diff --git a/src/tools/rust-analyzer/.cargo/config.toml b/src/tools/rust-analyzer/.cargo/config.toml index 070560dfbc316..0193a9566e2bf 100644 --- a/src/tools/rust-analyzer/.cargo/config.toml +++ b/src/tools/rust-analyzer/.cargo/config.toml @@ -4,6 +4,7 @@ tq = "test -- -q" qt = "tq" lint = "clippy --all-targets -- --cap-lints warn" codegen = "run --package xtask --bin xtask -- codegen" +dist = "run --package xtask --bin xtask -- dist" [target.x86_64-pc-windows-msvc] linker = "rust-lld" diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock index 3558c39bb32c5..57d43dad3fd80 100644 --- a/src/tools/rust-analyzer/Cargo.lock +++ b/src/tools/rust-analyzer/Cargo.lock @@ -328,6 +328,15 @@ dependencies = [ "dirs-sys", ] +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + [[package]] name = "dirs-sys" version = "0.4.1" @@ -503,6 +512,7 @@ dependencies = [ "hir-def", "hir-expand", "hir-ty", + "intern", "itertools", "once_cell", "rustc-hash", @@ -891,9 +901,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libloading" @@ -1665,6 +1675,7 @@ dependencies = [ "anyhow", "cfg", "crossbeam-channel", + "dirs", "dissimilar", "expect-test", "flycheck", diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml index ccc27e21333b5..583c7bbe33891 100644 --- a/src/tools/rust-analyzer/Cargo.toml +++ b/src/tools/rust-analyzer/Cargo.toml @@ -162,7 +162,11 @@ xshell = "0.2.5" dashmap = { version = "=5.5.3", features = ["raw-api"] } [workspace.lints.rust] -rust_2018_idioms = "warn" +bare_trait_objects = "warn" +elided_lifetimes_in_paths = "warn" +ellipsis_inclusive_range_patterns = "warn" +explicit_outlives_requirements = "warn" +unused_extern_crates = "warn" unused_lifetimes = "warn" unreachable_pub = "warn" semicolon_in_expressions_from_macros = "warn" diff --git a/src/tools/rust-analyzer/crates/base-db/src/change.rs b/src/tools/rust-analyzer/crates/base-db/src/change.rs index 927b2108a6ce8..0fd54e1211cd9 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/change.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/change.rs @@ -51,7 +51,7 @@ impl FileChange { } pub fn apply(self, db: &mut dyn SourceDatabaseExt) { - let _p = tracing::span!(tracing::Level::INFO, "FileChange::apply").entered(); + let _p = tracing::info_span!("FileChange::apply").entered(); if let Some(roots) = self.roots { for (idx, root) in roots.into_iter().enumerate() { let root_id = SourceRootId(idx as u32); diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs index b2c3f38ab4f8a..1d172ab9e40e3 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/input.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs @@ -412,7 +412,7 @@ impl CrateGraph { from: CrateId, dep: Dependency, ) -> Result<(), CyclicDependenciesError> { - let _p = tracing::span!(tracing::Level::INFO, "add_dep").entered(); + let _p = tracing::info_span!("add_dep").entered(); self.check_cycle_after_dependency(from, dep.crate_id)?; diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs index 2c13eed56c3e1..f5165ea8a7bb8 100644 --- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs +++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs @@ -85,7 +85,7 @@ fn toolchain_channel(db: &dyn SourceDatabase, krate: CrateId) -> Option Parse { - let _p = tracing::span!(tracing::Level::INFO, "parse", ?file_id).entered(); + let _p = tracing::info_span!("parse", ?file_id).entered(); let text = db.file_text(file_id); // FIXME: Edition based parsing SourceFile::parse(&text, span::Edition::CURRENT) @@ -187,7 +187,7 @@ impl FileLoader for FileLoaderDelegate<&'_ T> { } fn relevant_crates(&self, file_id: FileId) -> Arc<[CrateId]> { - let _p = tracing::span!(tracing::Level::INFO, "relevant_crates").entered(); + let _p = tracing::info_span!("relevant_crates").entered(); let source_root = self.0.file_source_root(file_id); self.0.source_root_crates(source_root) } diff --git a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs index afdc3e389b368..4584400e66f0c 100644 --- a/src/tools/rust-analyzer/crates/flycheck/src/lib.rs +++ b/src/tools/rust-analyzer/crates/flycheck/src/lib.rs @@ -304,7 +304,7 @@ impl FlycheckActor { Some(c) => c, None => continue, }; - let formatted_command = format!("{:?}", command); + let formatted_command = format!("{command:?}"); tracing::debug!(?command, "will restart flycheck"); let (sender, receiver) = unbounded(); @@ -318,8 +318,7 @@ impl FlycheckActor { } Err(error) => { self.report_progress(Progress::DidFailToRestart(format!( - "Failed to run the following command: {} error={}", - formatted_command, error + "Failed to run the following command: {formatted_command} error={error}" ))); self.status = FlycheckStatus::Finished; } @@ -331,7 +330,7 @@ impl FlycheckActor { // Watcher finished let command_handle = self.command_handle.take().unwrap(); self.command_receiver.take(); - let formatted_handle = format!("{:?}", command_handle); + let formatted_handle = format!("{command_handle:?}"); let res = command_handle.join(); if let Err(error) = &res { @@ -387,6 +386,7 @@ impl FlycheckActor { "did cancel flycheck" ); command_handle.cancel(); + self.command_receiver.take(); self.report_progress(Progress::DidCancel); self.status = FlycheckStatus::Finished; } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs index d9eeffd7983bf..184dab8367c16 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/attr.rs @@ -1,10 +1,5 @@ //! A higher level attributes based on TokenTree, with also some shortcuts. -pub mod builtin; - -#[cfg(test)] -mod tests; - use std::{borrow::Cow, hash::Hash, ops, slice::Iter as SliceIter}; use base_db::CrateId; @@ -75,7 +70,7 @@ impl Attrs { db: &dyn DefDatabase, v: VariantId, ) -> Arc> { - let _p = tracing::span!(tracing::Level::INFO, "fields_attrs_query").entered(); + let _p = tracing::info_span!("fields_attrs_query").entered(); // FIXME: There should be some proper form of mapping between item tree field ids and hir field ids let mut res = ArenaMap::default(); @@ -326,7 +321,7 @@ impl AttrsWithOwner { } pub(crate) fn attrs_query(db: &dyn DefDatabase, def: AttrDefId) -> Attrs { - let _p = tracing::span!(tracing::Level::INFO, "attrs_query").entered(); + let _p = tracing::info_span!("attrs_query").entered(); // FIXME: this should use `Trace` to avoid duplication in `source_map` below let raw_attrs = match def { AttrDefId::ModuleId(module) => { @@ -646,3 +641,55 @@ pub(crate) fn fields_attrs_source_map( Arc::new(res) } + +#[cfg(test)] +mod tests { + //! This module contains tests for doc-expression parsing. + //! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. + + use triomphe::Arc; + + use base_db::FileId; + use hir_expand::span_map::{RealSpanMap, SpanMap}; + use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode}; + use syntax::{ast, AstNode, TextRange}; + + use crate::attr::{DocAtom, DocExpr}; + + fn assert_parse_result(input: &str, expected: DocExpr) { + let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap(); + let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); + let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0)))); + let tt = syntax_node_to_token_tree( + tt.syntax(), + map.as_ref(), + map.span_for_range(TextRange::empty(0.into())), + DocCommentDesugarMode::ProcMacro, + ); + let cfg = DocExpr::parse(&tt); + assert_eq!(cfg, expected); + } + + #[test] + fn test_doc_expr_parser() { + assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); + + assert_parse_result( + r#"#![doc(alias = "foo")]"#, + DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), + ); + + assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); + assert_parse_result( + r#"#![doc(alias("foo", "bar", "baz"))]"#, + DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), + ); + + assert_parse_result( + r#" + #[doc(alias("Bar", "Qux"))] + struct Foo;"#, + DocExpr::Alias(["Bar".into(), "Qux".into()].into()), + ); + } +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs deleted file mode 100644 index 727f4429802cd..0000000000000 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/tests.rs +++ /dev/null @@ -1,48 +0,0 @@ -//! This module contains tests for doc-expression parsing. -//! Currently, it tests `#[doc(hidden)]` and `#[doc(alias)]`. - -use triomphe::Arc; - -use base_db::FileId; -use hir_expand::span_map::{RealSpanMap, SpanMap}; -use mbe::{syntax_node_to_token_tree, DocCommentDesugarMode}; -use syntax::{ast, AstNode, TextRange}; - -use crate::attr::{DocAtom, DocExpr}; - -fn assert_parse_result(input: &str, expected: DocExpr) { - let source_file = ast::SourceFile::parse(input, span::Edition::CURRENT).ok().unwrap(); - let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); - let map = SpanMap::RealSpanMap(Arc::new(RealSpanMap::absolute(FileId::from_raw(0)))); - let tt = syntax_node_to_token_tree( - tt.syntax(), - map.as_ref(), - map.span_for_range(TextRange::empty(0.into())), - DocCommentDesugarMode::ProcMacro, - ); - let cfg = DocExpr::parse(&tt); - assert_eq!(cfg, expected); -} - -#[test] -fn test_doc_expr_parser() { - assert_parse_result("#![doc(hidden)]", DocAtom::Flag("hidden".into()).into()); - - assert_parse_result( - r#"#![doc(alias = "foo")]"#, - DocAtom::KeyValue { key: "alias".into(), value: "foo".into() }.into(), - ); - - assert_parse_result(r#"#![doc(alias("foo"))]"#, DocExpr::Alias(["foo".into()].into())); - assert_parse_result( - r#"#![doc(alias("foo", "bar", "baz"))]"#, - DocExpr::Alias(["foo".into(), "bar".into(), "baz".into()].into()), - ); - - assert_parse_result( - r#" - #[doc(alias("Bar", "Qux"))] - struct Foo;"#, - DocExpr::Alias(["Bar".into(), "Qux".into()].into()), - ); -} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/body.rs index d2f4d7b7e56e9..ca4a3f5217cf3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body.rs @@ -124,7 +124,7 @@ impl Body { db: &dyn DefDatabase, def: DefWithBodyId, ) -> (Arc, Arc) { - let _p = tracing::span!(tracing::Level::INFO, "body_with_source_map_query").entered(); + let _p = tracing::info_span!("body_with_source_map_query").entered(); let mut params = None; let mut is_async_fn = false; @@ -395,6 +395,12 @@ impl BodySourceMap { self.expr_map.get(&src).copied() } + pub fn expansions( + &self, + ) -> impl Iterator>, &MacroFileId)> { + self.expansions.iter() + } + pub fn implicit_format_args( &self, node: InFile<&ast::FormatArgsExpr>, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs index c6d9ba6cfe459..faba9050fc4d4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs @@ -12,6 +12,7 @@ use intern::Interned; use rustc_hash::FxHashMap; use smallvec::SmallVec; use span::AstIdMap; +use stdx::never; use syntax::{ ast::{ self, ArrayExprKind, AstChildren, BlockExpr, HasArgList, HasAttrs, HasLoopBody, HasName, @@ -480,7 +481,8 @@ impl ExprCollector<'_> { } else if e.const_token().is_some() { Mutability::Shared } else { - unreachable!("parser only remaps to raw_token() if matching mutability token follows") + never!("parser only remaps to raw_token() if matching mutability token follows"); + Mutability::Shared } } else { Mutability::from_mutable(e.mut_token().is_some()) @@ -963,7 +965,7 @@ impl ExprCollector<'_> { .resolve_path( self.db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) @@ -1006,9 +1008,9 @@ impl ExprCollector<'_> { Some((mark, expansion)) => { // Keep collecting even with expansion errors so we can provide completions and // other services in incomplete macro expressions. - self.source_map - .expansions - .insert(macro_call_ptr, self.expander.current_file_id().macro_file().unwrap()); + if let Some(macro_file) = self.expander.current_file_id().macro_file() { + self.source_map.expansions.insert(macro_call_ptr, macro_file); + } let prev_ast_id_map = mem::replace( &mut self.ast_id_map, self.db.ast_id_map(self.expander.current_file_id()), diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs index cbb5ca887f49a..c48d16d053049 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs @@ -48,21 +48,30 @@ pub(super) fn print_body_hir(db: &dyn DefDatabase, body: &Body, owner: DefWithBo let mut p = Printer { db, body, buf: header, indent_level: 0, needs_indent: false }; if let DefWithBodyId::FunctionId(it) = owner { p.buf.push('('); - let params = &db.function_data(it).params; - let mut params = params.iter(); + let function_data = &db.function_data(it); + let (mut params, ret_type) = (function_data.params.iter(), &function_data.ret_type); if let Some(self_param) = body.self_param { p.print_binding(self_param); - p.buf.push(':'); + p.buf.push_str(": "); if let Some(ty) = params.next() { p.print_type_ref(ty); + p.buf.push_str(", "); } } body.params.iter().zip(params).for_each(|(¶m, ty)| { p.print_pat(param); - p.buf.push(':'); + p.buf.push_str(": "); p.print_type_ref(ty); + p.buf.push_str(", "); }); + // remove the last ", " in param list + if body.params.len() > 0 { + p.buf.truncate(p.buf.len() - 2); + } p.buf.push(')'); + // return type + p.buf.push_str(" -> "); + p.print_type_ref(ret_type); p.buf.push(' '); } p.print_expr(body.body_expr); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs index e8b26d537345c..0011d3a20c2a4 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs @@ -156,7 +156,7 @@ fn main() { ); expect![[r#" - fn main() { + fn main() -> () { let are = "are"; let count = 10; builtin#lang(Arguments::new_v1_formatted)( @@ -258,7 +258,7 @@ impl SsrError { assert_eq!(db.body_with_source_map(def).1.diagnostics(), &[]); expect![[r#" - fn main() { + fn main() -> () { _ = $crate::error::SsrError::new( builtin#lang(Arguments::new_v1_formatted)( &[ @@ -303,7 +303,7 @@ macro_rules! m { }; } -fn f() { +fn f(a: i32, b: u32) -> String { m!(); } "#, @@ -317,7 +317,7 @@ fn f() { } expect![[r#" - fn f() { + fn f(a: i32, b: u32) -> String { { $crate::panicking::panic_fmt( builtin#lang(Arguments::new_v1_formatted)( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs index 0b41984bdd898..106109eb18448 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/child_by_source.rs @@ -6,7 +6,7 @@ use either::Either; use hir_expand::{attrs::collect_attrs, HirFileId}; -use syntax::ast; +use syntax::{ast, AstPtr}; use crate::{ db::DefDatabase, @@ -38,7 +38,7 @@ impl ChildBySource for TraitId { data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); data.items.iter().for_each(|&(_, item)| { @@ -50,9 +50,10 @@ impl ChildBySource for TraitId { impl ChildBySource for ImplId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { let data = db.impl_data(*self); + // FIXME: Macro calls data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); data.items.iter().for_each(|&item| { @@ -80,7 +81,7 @@ impl ChildBySource for ItemScope { .for_each(|konst| insert_item_loc(db, res, file_id, konst, keys::CONST)); self.attr_macro_invocs().filter(|(id, _)| id.file_id == file_id).for_each( |(ast_id, call_id)| { - res[keys::ATTR_MACRO_CALL].insert(ast_id.to_node(db.upcast()), call_id); + res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db.upcast()), call_id); }, ); self.legacy_macros().for_each(|(_, ids)| { @@ -88,7 +89,7 @@ impl ChildBySource for ItemScope { if let MacroId::MacroRulesId(id) = id { let loc = id.lookup(db); if loc.id.file_id() == file_id { - res[keys::MACRO_RULES].insert(loc.source(db).value, id); + res[keys::MACRO_RULES].insert(loc.ast_ptr(db).value, id); } } }) @@ -100,12 +101,18 @@ impl ChildBySource for ItemScope { if let Some((_, Either::Left(attr))) = collect_attrs(&adt).nth(attr_id.ast_index()) { - res[keys::DERIVE_MACRO_CALL].insert(attr, (attr_id, call_id, calls.into())); + res[keys::DERIVE_MACRO_CALL] + .insert(AstPtr::new(&attr), (attr_id, call_id, calls.into())); } }); }, ); - + self.iter_macro_invoc().filter(|(id, _)| id.file_id == file_id).for_each( + |(ast_id, &call)| { + let ast = ast_id.to_ptr(db.upcast()); + res[keys::MACRO_CALL].insert(ast, call); + }, + ); fn add_module_def( db: &dyn DefDatabase, map: &mut DynMap, @@ -155,8 +162,8 @@ impl ChildBySource for VariantId { for (local_id, source) in arena_map.value.iter() { let id = FieldId { parent, local_id }; match source.clone() { - Either::Left(source) => res[keys::TUPLE_FIELD].insert(source, id), - Either::Right(source) => res[keys::RECORD_FIELD].insert(source, id), + Either::Left(source) => res[keys::TUPLE_FIELD].insert(AstPtr::new(&source), id), + Either::Right(source) => res[keys::RECORD_FIELD].insert(AstPtr::new(&source), id), } } } @@ -171,29 +178,30 @@ impl ChildBySource for EnumId { let tree = loc.id.item_tree(db); let ast_id_map = db.ast_id_map(loc.id.file_id()); - let root = db.parse_or_expand(loc.id.file_id()); db.enum_data(*self).variants.iter().for_each(|&(variant, _)| { - res[keys::ENUM_VARIANT].insert( - ast_id_map.get(tree[variant.lookup(db).id.value].ast_id).to_node(&root), - variant, - ); + res[keys::ENUM_VARIANT] + .insert(ast_id_map.get(tree[variant.lookup(db).id.value].ast_id), variant); }); } } impl ChildBySource for DefWithBodyId { fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) { - let body = db.body(*self); + let (body, sm) = db.body_with_source_map(*self); if let &DefWithBodyId::VariantId(v) = self { VariantId::EnumVariantId(v).child_by_source_to(db, res, file_id) } + sm.expansions().filter(|(ast, _)| ast.file_id == file_id).for_each(|(ast, &exp_id)| { + res[keys::MACRO_CALL].insert(ast.value, exp_id.macro_call_id); + }); + for (block, def_map) in body.blocks(db) { // All block expressions are merged into the same map, because they logically all add // inner items to the containing `DefWithBodyId`. def_map[DefMap::ROOT].scope.child_by_source_to(db, res, file_id); - res[keys::BLOCK].insert(block.lookup(db).ast_id.to_node(db.upcast()), block); + res[keys::BLOCK].insert(block.lookup(db).ast_id.to_ptr(db.upcast()), block); } } } @@ -220,13 +228,17 @@ impl ChildBySource for GenericDefId { { let id = TypeOrConstParamId { parent: *self, local_id }; match ast_param { - ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id), - ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id), + ast::TypeOrConstParam::Type(a) => { + res[keys::TYPE_PARAM].insert(AstPtr::new(&a), id) + } + ast::TypeOrConstParam::Const(a) => { + res[keys::CONST_PARAM].insert(AstPtr::new(&a), id) + } } } for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) { let id = LifetimeParamId { parent: *self, local_id }; - res[keys::LIFETIME_PARAM].insert(ast_param, id); + res[keys::LIFETIME_PARAM].insert(AstPtr::new(&ast_param), id); } } } @@ -246,7 +258,7 @@ fn insert_item_loc( { let loc = id.lookup(db); if loc.item_tree_id().file_id() == file_id { - res[key].insert(loc.source(db).value, id) + res[key].insert(loc.ast_ptr(db).value, id) } } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/data.rs b/src/tools/rust-analyzer/crates/hir-def/src/data.rs index 51a4dd6f42a85..43381636721b3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs @@ -340,7 +340,7 @@ impl ImplData { db: &dyn DefDatabase, id: ImplId, ) -> (Arc, DefDiagnostics) { - let _p = tracing::span!(tracing::Level::INFO, "impl_data_with_diagnostics_query").entered(); + let _p = tracing::info_span!("impl_data_with_diagnostics_query").entered(); let ItemLoc { container: module_id, id: tree_id } = id.lookup(db); let item_tree = tree_id.item_tree(db); @@ -628,7 +628,7 @@ impl<'a> AssocItemCollector<'a> { 'attrs: for attr in &*attrs { let ast_id = AstId::new(self.expander.current_file_id(), item.ast_id(item_tree).upcast()); - let ast_id_with_path = AstIdWithPath { path: (*attr.path).clone(), ast_id }; + let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id }; match self.def_map.resolve_attr_macro( self.db, @@ -642,7 +642,7 @@ impl<'a> AssocItemCollector<'a> { continue 'attrs; } let loc = self.db.lookup_intern_macro_call(call_id); - if let MacroDefKind::ProcMacro(exp, ..) = loc.def.kind { + if let MacroDefKind::ProcMacro(_, exp, _) = loc.def.kind { // If there's no expander for the proc macro (e.g. the // proc macro is ignored, or building the proc macro // crate failed), skip expansion like we would if it was @@ -719,12 +719,12 @@ impl<'a> AssocItemCollector<'a> { let MacroCall { ast_id, expand_to, ctxt, ref path } = item_tree[call]; let module = self.expander.module.local_id; - let resolver = |path| { + let resolver = |path: &_| { self.def_map .resolve_path( self.db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/db.rs b/src/tools/rust-analyzer/crates/hir-def/src/db.rs index 55ecabdc38e2c..61fed71218ee3 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs @@ -294,10 +294,10 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { let in_file = InFile::new(file_id, m); match expander { MacroExpander::Declarative => MacroDefKind::Declarative(in_file), - MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(it, in_file), - MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(it, in_file), - MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(it, in_file), - MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(it, in_file), + MacroExpander::BuiltIn(it) => MacroDefKind::BuiltIn(in_file, it), + MacroExpander::BuiltInAttr(it) => MacroDefKind::BuiltInAttr(in_file, it), + MacroExpander::BuiltInDerive(it) => MacroDefKind::BuiltInDerive(in_file, it), + MacroExpander::BuiltInEager(it) => MacroDefKind::BuiltInEager(in_file, it), } }; @@ -338,9 +338,9 @@ fn macro_def(db: &dyn DefDatabase, id: MacroId) -> MacroDefId { MacroDefId { krate: loc.container.krate, kind: MacroDefKind::ProcMacro( + InFile::new(loc.id.file_id(), makro.ast_id), loc.expander, loc.kind, - InFile::new(loc.id.file_id(), makro.ast_id), ), local_inner: false, allow_internal_unsafe: false, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs index f83ab1e1a0562..9d330a7bf1c00 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/dyn_map/keys.rs @@ -13,7 +13,7 @@ use crate::{ TraitId, TypeAliasId, TypeOrConstParamId, UnionId, UseId, }; -pub type Key = crate::dyn_map::Key>; +pub type Key = crate::dyn_map::Key, V, AstPtrPolicy>; pub const BLOCK: Key = Key::new(); pub const FUNCTION: Key = Key::new(); @@ -39,6 +39,7 @@ pub const LIFETIME_PARAM: Key = Key::new(); pub const MACRO_RULES: Key = Key::new(); pub const MACRO2: Key = Key::new(); pub const PROC_MACRO: Key = Key::new(); +pub const MACRO_CALL: Key = Key::new(); pub const ATTR_MACRO_CALL: Key = Key::new(); pub const DERIVE_MACRO_CALL: Key]>)> = Key::new(); @@ -54,18 +55,16 @@ pub struct AstPtrPolicy { } impl Policy for AstPtrPolicy { - type K = AST; + type K = AstPtr; type V = ID; - fn insert(map: &mut DynMap, key: AST, value: ID) { - let key = AstPtr::new(&key); + fn insert(map: &mut DynMap, key: AstPtr, value: ID) { map.map .entry::, ID>>() .or_insert_with(Default::default) .insert(key, value); } - fn get<'a>(map: &'a DynMap, key: &AST) -> Option<&'a ID> { - let key = AstPtr::new(key); - map.map.get::, ID>>()?.get(&key) + fn get<'a>(map: &'a DynMap, key: &AstPtr) -> Option<&'a ID> { + map.map.get::, ID>>()?.get(key) } fn is_empty(map: &DynMap) -> bool { map.map.get::, ID>>().map_or(true, |it| it.is_empty()) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs index 73ce942c5807a..dbf8e6b225c2a 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/expander.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/expander.rs @@ -56,7 +56,7 @@ impl Expander { &mut self, db: &dyn DefDatabase, macro_call: ast::MacroCall, - resolver: impl Fn(ModPath) -> Option, + resolver: impl Fn(&ModPath) -> Option, ) -> Result)>>, UnresolvedMacro> { // FIXME: within_limit should support this, instead of us having to extract the error let mut unresolved_macro_err = None; diff --git a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs index d9495d36c0d9f..58a1872ef2510 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/find_path.rs @@ -1,6 +1,6 @@ //! An algorithm to find a path to refer to a certain item. -use std::{cmp::Ordering, iter}; +use std::{cell::Cell, cmp::Ordering, iter}; use hir_expand::{ name::{known, AsName, Name}, @@ -23,15 +23,40 @@ pub fn find_path( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, - prefix_kind: PrefixKind, + mut prefix_kind: PrefixKind, ignore_local_imports: bool, - cfg: ImportPathConfig, + mut cfg: ImportPathConfig, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "find_path").entered(); - find_path_inner(FindPathCtx { db, prefix: prefix_kind, cfg, ignore_local_imports }, item, from) + let _p = tracing::info_span!("find_path").entered(); + + // - 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, iter::once(builtin.as_name()))); + } + + // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so + // default to plain paths. + if item.module(db).is_some_and(ModuleId::is_within_block) { + prefix_kind = PrefixKind::Plain; + } + cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate()); + + find_path_inner( + &FindPathCtx { + db, + prefix: prefix_kind, + cfg, + ignore_local_imports, + from, + from_def_map: &from.def_map(db), + fuel: Cell::new(FIND_PATH_FUEL), + }, + item, + MAX_PATH_LEN, + ) } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq)] enum Stability { Unstable, Stable, @@ -46,6 +71,7 @@ fn zip_stability(a: Stability, b: Stability) -> Stability { } const MAX_PATH_LEN: usize = 15; +const FIND_PATH_FUEL: usize = 10000; #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum PrefixKind { @@ -63,79 +89,54 @@ impl PrefixKind { #[inline] fn path_kind(self) -> PathKind { match self { - PrefixKind::BySelf => PathKind::Super(0), + PrefixKind::BySelf => PathKind::SELF, PrefixKind::Plain => PathKind::Plain, PrefixKind::ByCrate => PathKind::Crate, } } } -#[derive(Copy, Clone)] struct FindPathCtx<'db> { db: &'db dyn DefDatabase, prefix: PrefixKind, cfg: ImportPathConfig, ignore_local_imports: bool, + from: ModuleId, + from_def_map: &'db DefMap, + fuel: Cell, } /// 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 { - // - 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, iter::once(builtin.as_name()))); - } - - let def_map = from.def_map(ctx.db); - let crate_root = from.derive_crate_root(); +fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option { // - 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( - FindPathCtx { - cfg: ImportPathConfig { - prefer_no_std: ctx.cfg.prefer_no_std - || ctx.db.crate_supports_no_std(crate_root.krate), - ..ctx.cfg - }, - ..ctx - }, - &def_map, - &mut visited_modules, - from, - module_id, - MAX_PATH_LEN, - ) - .map(|(item, _)| item); + return find_path_for_module(ctx, &mut visited_modules, module_id, max_len) + .map(|(item, _)| item); } - let prefix = if item.module(ctx.db).is_some_and(|it| it.is_within_block()) { - PrefixKind::Plain - } else { - ctx.prefix - }; - let may_be_in_scope = match prefix { + let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => from.is_crate_root(), + PrefixKind::ByCrate => ctx.from.is_crate_root(), }; if may_be_in_scope { // - if the item is already in scope, return the name under which it is - let scope_name = find_in_scope(ctx.db, &def_map, from, item, ctx.ignore_local_imports); + let scope_name = + find_in_scope(ctx.db, ctx.from_def_map, ctx.from, item, ctx.ignore_local_imports); if let Some(scope_name) = scope_name { - return Some(ModPath::from_segments(prefix.path_kind(), iter::once(scope_name))); + return Some(ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name))); } } // - if the item is in the prelude, return the name from there - if let value @ Some(_) = - find_in_prelude(ctx.db, &crate_root.def_map(ctx.db), &def_map, item, from) - { - return value; + if let Some(value) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) { + return Some(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(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), from) + find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len) { path.push_segment(ctx.db.enum_variant_data(variant).name.clone()); return Some(path); @@ -147,53 +148,32 @@ fn find_path_inner(ctx: FindPathCtx<'_>, item: ItemInNs, from: ModuleId) -> Opti let mut visited_modules = FxHashSet::default(); - calculate_best_path( - FindPathCtx { - cfg: ImportPathConfig { - prefer_no_std: ctx.cfg.prefer_no_std - || ctx.db.crate_supports_no_std(crate_root.krate), - ..ctx.cfg - }, - ..ctx - }, - &def_map, - &mut visited_modules, - MAX_PATH_LEN, - item, - from, - ) - .map(|(item, _)| item) + calculate_best_path(ctx, &mut visited_modules, item, max_len).map(|(item, _)| item) } #[tracing::instrument(skip_all)] fn find_path_for_module( - ctx: FindPathCtx<'_>, - def_map: &DefMap, + ctx: &FindPathCtx<'_>, visited_modules: &mut FxHashSet, - from: ModuleId, module_id: ModuleId, max_len: usize, ) -> Option<(ModPath, Stability)> { - if max_len == 0 { - return None; - } - - let is_crate_root = module_id.as_crate_root(); - // - if the item is the crate root, return `crate` - if is_crate_root.is_some_and(|it| it == from.derive_crate_root()) { - return Some((ModPath::from_segments(PathKind::Crate, None), Stable)); - } + if let Some(crate_root) = module_id.as_crate_root() { + if crate_root == ctx.from.derive_crate_root() { + // - if the item is the crate root, return `crate` + return Some((ModPath::from_segments(PathKind::Crate, None), Stable)); + } + // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude - let root_def_map = from.derive_crate_root().def_map(ctx.db); - // - if the item is the crate root of a dependency crate, return the name from the extern prelude - if let Some(crate_root) = is_crate_root { + let root_def_map = ctx.from.derive_crate_root().def_map(ctx.db); // rev here so we prefer looking at renamed extern decls first for (name, (def_id, _extern_crate)) in root_def_map.extern_prelude().rev() { if crate_root != def_id { continue; } - let name_already_occupied_in_type_ns = def_map - .with_ancestor_maps(ctx.db, from.local_id, &mut |def_map, local_id| { + let name_already_occupied_in_type_ns = ctx + .from_def_map + .with_ancestor_maps(ctx.db, ctx.from.local_id, &mut |def_map, local_id| { def_map[local_id] .scope .type_(name) @@ -209,30 +189,30 @@ fn find_path_for_module( return Some((ModPath::from_segments(kind, iter::once(name.clone())), Stable)); } } - let prefix = if module_id.is_within_block() { PrefixKind::Plain } else { ctx.prefix }; - let may_be_in_scope = match prefix { + + let may_be_in_scope = match ctx.prefix { PrefixKind::Plain | PrefixKind::BySelf => true, - PrefixKind::ByCrate => from.is_crate_root(), + PrefixKind::ByCrate => ctx.from.is_crate_root(), }; if may_be_in_scope { let scope_name = find_in_scope( ctx.db, - def_map, - from, + ctx.from_def_map, + ctx.from, ItemInNs::Types(module_id.into()), ctx.ignore_local_imports, ); if let Some(scope_name) = scope_name { // - if the item is already in scope, return the name under which it is return Some(( - ModPath::from_segments(prefix.path_kind(), iter::once(scope_name)), + ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)), Stable, )); } } // - if the module can be referenced as self, super or crate, do that - if let Some(mod_path) = is_kw_kind_relative_to_from(def_map, module_id, from) { + if let Some(mod_path) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) { if ctx.prefix != PrefixKind::ByCrate || mod_path.kind == PathKind::Crate { return Some((mod_path, Stable)); } @@ -240,21 +220,13 @@ fn find_path_for_module( // - if the module is in the prelude, return it by that path if let Some(mod_path) = - find_in_prelude(ctx.db, &root_def_map, def_map, ItemInNs::Types(module_id.into()), from) + find_in_prelude(ctx.db, ctx.from_def_map, ItemInNs::Types(module_id.into()), ctx.from) { return Some((mod_path, Stable)); } - calculate_best_path( - ctx, - def_map, - visited_modules, - max_len, - ItemInNs::Types(module_id.into()), - from, - ) + calculate_best_path(ctx, visited_modules, ItemInNs::Types(module_id.into()), max_len) } -// FIXME: Do we still need this now that we record import origins, and hence aliases? fn find_in_scope( db: &dyn DefDatabase, def_map: &DefMap, @@ -274,13 +246,11 @@ fn find_in_scope( /// name doesn't clash in current scope. fn find_in_prelude( db: &dyn DefDatabase, - root_def_map: &DefMap, local_def_map: &DefMap, item: ItemInNs, from: ModuleId, ) -> Option { - let (prelude_module, _) = root_def_map.prelude()?; - // Preludes in block DefMaps are ignored, only the crate DefMap is searched + let (prelude_module, _) = local_def_map.prelude()?; let prelude_def_map = prelude_module.def_map(db); let prelude_scope = &prelude_def_map[prelude_module.local_id].scope; let (name, vis, _declared) = prelude_scope.name_of(item)?; @@ -319,7 +289,7 @@ fn is_kw_kind_relative_to_from( let from = from.local_id; if item == from { // - if the item is the module we're in, use `self` - Some(ModPath::from_segments(PathKind::Super(0), None)) + Some(ModPath::from_segments(PathKind::SELF, None)) } else if let Some(parent_id) = def_map[from].parent { if item == parent_id { // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly) @@ -337,60 +307,71 @@ fn is_kw_kind_relative_to_from( #[tracing::instrument(skip_all)] fn calculate_best_path( - ctx: FindPathCtx<'_>, - def_map: &DefMap, + ctx: &FindPathCtx<'_>, visited_modules: &mut FxHashSet, - max_len: usize, item: ItemInNs, - from: ModuleId, + max_len: usize, ) -> Option<(ModPath, Stability)> { if max_len <= 1 { + // recursive base case, we can't find a path prefix of length 0, one segment is occupied by + // the item's name itself. + return None; + } + let fuel = ctx.fuel.get(); + if fuel == 0 { + // we ran out of fuel, so we stop searching here + tracing::warn!( + "ran out of fuel while searching for a path for item {item:?} of krate {:?} from krate {:?}", + item.krate(ctx.db), + ctx.from.krate() + ); return None; } + ctx.fuel.set(fuel - 1); + let mut best_path = None; - let update_best_path = - |best_path: &mut Option<_>, new_path: (ModPath, Stability)| match best_path { + let mut best_path_len = max_len; + let mut process = |mut path: (ModPath, Stability), name, best_path_len: &mut _| { + path.0.push_segment(name); + let new_path = match best_path.take() { + Some(best_path) => select_best_path(best_path, path, ctx.cfg), + None => path, + }; + if new_path.1 == Stable { + *best_path_len = new_path.0.len(); + } + match &mut best_path { Some((old_path, old_stability)) => { *old_path = new_path.0; *old_stability = zip_stability(*old_stability, new_path.1); } - None => *best_path = Some(new_path), - }; - // Recursive case: - // - otherwise, look for modules containing (reexporting) it and import it from one of those - if item.krate(ctx.db) == Some(from.krate) { - let mut best_path_len = max_len; + None => best_path = Some(new_path), + } + }; + let db = ctx.db; + if item.krate(db) == Some(ctx.from.krate) { // 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(ctx.db, item, from) { + // FIXME: cache the `find_local_import_locations` output? + find_local_import_locations(db, item, ctx.from, ctx.from_def_map, |name, module_id| { if !visited_modules.insert(module_id) { - continue; + return; } - if let Some(mut path) = find_path_for_module( - ctx, - def_map, - visited_modules, - from, - module_id, - best_path_len - 1, - ) { - path.0.push_segment(name); - - let new_path = match best_path.take() { - Some(best_path) => select_best_path(best_path, path, ctx.cfg), - None => path, - }; - best_path_len = new_path.0.len(); - update_best_path(&mut best_path, new_path); + // we are looking for paths of length up to best_path_len, any longer will make it be + // less optimal. The -1 is due to us pushing name onto it afterwards. + if let Some(path) = + find_path_for_module(ctx, visited_modules, module_id, best_path_len - 1) + { + process(path, name.clone(), &mut best_path_len); } - } + }) } else { // Item was defined in some upstream crate. This means that it must be exported from one, // 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 &ctx.db.crate_graph()[from.krate].dependencies { - let import_map = ctx.db.import_map(dep.crate_id); + for dep in &db.crate_graph()[ctx.from.krate].dependencies { + let import_map = 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 { @@ -400,29 +381,18 @@ 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( - ctx, - def_map, - visited_modules, - from, - info.container, - max_len - 1, - ) else { + let path = + find_path_for_module(ctx, visited_modules, info.container, best_path_len - 1); + let Some((path, path_stability)) = path else { continue; }; cov_mark::hit!(partially_imported); - path.push_segment(info.name.clone()); - - let path_with_stab = ( + let path = ( path, zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }), ); - let new_path_with_stab = match best_path.take() { - Some(best_path) => select_best_path(best_path, path_with_stab, ctx.cfg), - None => path_with_stab, - }; - update_best_path(&mut best_path, new_path_with_stab); + process(path, info.name.clone(), &mut best_path_len); } } } @@ -430,7 +400,7 @@ fn calculate_best_path( } /// Select the best (most relevant) path between two paths. -/// This accounts for stability, path length whether std should be chosen over alloc/core paths as +/// This accounts for stability, path length whether, std should be chosen over alloc/core paths as /// well as ignoring prelude like paths or not. fn select_best_path( old_path @ (_, old_stability): (ModPath, Stability), @@ -496,36 +466,33 @@ fn select_best_path( } } -// FIXME: Remove allocations /// Finds locations in `from.krate` from which `item` can be imported by `from`. fn find_local_import_locations( db: &dyn DefDatabase, item: ItemInNs, from: ModuleId, -) -> Vec<(ModuleId, Name)> { - let _p = tracing::span!(tracing::Level::INFO, "find_local_import_locations").entered(); + def_map: &DefMap, + mut cb: impl FnMut(&Name, ModuleId), +) { + let _p = tracing::info_span!("find_local_import_locations").entered(); // `from` can import anything below `from` with visibility of at least `from`, and anything // above `from` with any visibility. That means we do not need to descend into private siblings // of `from` (and similar). - let def_map = from.def_map(db); - // Compute the initial worklist. We start with all direct child modules of `from` as well as all // of its (recursive) parent modules. - let data = &def_map[from.local_id]; - let mut worklist = - data.children.values().map(|child| def_map.module_id(*child)).collect::>(); - // FIXME: do we need to traverse out of block expressions here? - for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { - worklist.push(ancestor); - } + let mut worklist = def_map[from.local_id] + .children + .values() + .map(|child| def_map.module_id(*child)) + // FIXME: do we need to traverse out of block expressions here? + .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db))) + .collect::>(); + let mut seen: FxHashSet<_> = FxHashSet::default(); let def_map = def_map.crate_root().def_map(db); - let mut seen: FxHashSet<_> = FxHashSet::default(); - - let mut locations = Vec::new(); while let Some(module) = worklist.pop() { if !seen.insert(module) { continue; // already processed this module @@ -566,7 +533,7 @@ fn find_local_import_locations( // the item and we're a submodule of it, so can we. // Also this keeps the cached data smaller. if declared || is_pub_or_explicit { - locations.push((module, name.clone())); + cb(name, module); } } } @@ -578,8 +545,6 @@ fn find_local_import_locations( } } } - - locations } #[cfg(test)] @@ -633,15 +598,13 @@ mod tests { .into_iter() .cartesian_product([false, true]) { - let found_path = find_path_inner( - FindPathCtx { - db: &db, - prefix, - cfg: ImportPathConfig { prefer_no_std: false, prefer_prelude }, - ignore_local_imports, - }, + let found_path = find_path( + &db, resolved, module, + prefix, + ignore_local_imports, + ImportPathConfig { prefer_no_std: false, prefer_prelude }, ); format_to!( res, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs index 10a1d65bb9337..b9f8082391f15 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs @@ -11,7 +11,7 @@ use hir_expand::{ ExpandResult, }; use intern::Interned; -use la_arena::Arena; +use la_arena::{Arena, RawIdx}; use once_cell::unsync::Lazy; use stdx::impl_from; use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds}; @@ -28,6 +28,9 @@ use crate::{ LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, }; +const SELF_PARAM_ID_IN_SELF: la_arena::Idx = + LocalTypeOrConstParamId::from_raw(RawIdx::from_u32(0)); + /// Data about a generic type parameter (to a function, struct, impl, ...). #[derive(Clone, PartialEq, Eq, Debug, Hash)] pub struct TypeParamData { @@ -403,12 +406,12 @@ impl GenericParamsCollector { let (def_map, expander) = &mut **exp; let module = expander.module.local_id; - let resolver = |path| { + let resolver = |path: &_| { def_map .resolve_path( db, module, - &path, + path, crate::item_scope::BuiltinShadowMode::Other, Some(MacroSubNs::Bang), ) @@ -441,15 +444,18 @@ impl GenericParamsCollector { impl GenericParams { /// Number of Generic parameters (type_or_consts + lifetimes) + #[inline] pub fn len(&self) -> usize { self.type_or_consts.len() + self.lifetimes.len() } + #[inline] pub fn is_empty(&self) -> bool { self.len() == 0 } /// Iterator of type_or_consts field + #[inline] pub fn iter_type_or_consts( &self, ) -> impl DoubleEndedIterator { @@ -457,6 +463,7 @@ impl GenericParams { } /// Iterator of lifetimes field + #[inline] pub fn iter_lt( &self, ) -> impl DoubleEndedIterator { @@ -467,7 +474,7 @@ impl GenericParams { db: &dyn DefDatabase, def: GenericDefId, ) -> Interned { - let _p = tracing::span!(tracing::Level::INFO, "generic_params_query").entered(); + let _p = tracing::info_span!("generic_params_query").entered(); let krate = def.module(db).krate; let cfg_options = db.crate_graph(); @@ -605,17 +612,18 @@ impl GenericParams { }) } - pub fn find_trait_self_param(&self) -> Option { - self.type_or_consts.iter().find_map(|(id, p)| { - matches!( - p, - TypeOrConstParamData::TypeParamData(TypeParamData { - provenance: TypeParamProvenance::TraitSelf, - .. - }) - ) - .then(|| id) - }) + pub fn trait_self_param(&self) -> Option { + if self.type_or_consts.is_empty() { + return None; + } + matches!( + self.type_or_consts[SELF_PARAM_ID_IN_SELF], + TypeOrConstParamData::TypeParamData(TypeParamData { + provenance: TypeParamProvenance::TraitSelf, + .. + }) + ) + .then(|| SELF_PARAM_ID_IN_SELF) } pub fn find_lifetime_by_name( diff --git a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs index 2f7ebbfec13ae..fd6f4a3d089db 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs @@ -503,11 +503,11 @@ impl BindingAnnotation { #[derive(Debug, Clone, Eq, PartialEq)] pub enum BindingProblems { - /// https://doc.rust-lang.org/stable/error_codes/E0416.html + /// BoundMoreThanOnce, - /// https://doc.rust-lang.org/stable/error_codes/E0409.html + /// BoundInconsistently, - /// https://doc.rust-lang.org/stable/error_codes/E0408.html + /// NotBoundAcrossAll, } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs index 6e40293dbf8e6..2b2db21a9f41f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/import_map.rs @@ -73,7 +73,7 @@ impl ImportMap { } pub(crate) fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "import_map_query").entered(); + let _p = tracing::info_span!("import_map_query").entered(); let map = Self::collect_import_map(db, krate); @@ -124,7 +124,7 @@ impl ImportMap { } fn collect_import_map(db: &dyn DefDatabase, krate: CrateId) -> ImportMapIndex { - let _p = tracing::span!(tracing::Level::INFO, "collect_import_map").entered(); + let _p = tracing::info_span!("collect_import_map").entered(); let def_map = db.crate_def_map(krate); let mut map = FxIndexMap::default(); @@ -214,7 +214,7 @@ impl ImportMap { is_type_in_ns: bool, trait_import_info: &ImportInfo, ) { - let _p = tracing::span!(tracing::Level::INFO, "collect_trait_assoc_items").entered(); + let _p = tracing::info_span!("collect_trait_assoc_items").entered(); for &(ref assoc_item_name, item) in &db.trait_data(tr).items { let module_def_id = match item { AssocItemId::FunctionId(f) => ModuleDefId::from(f), @@ -396,7 +396,7 @@ pub fn search_dependencies( krate: CrateId, query: &Query, ) -> FxHashSet { - let _p = tracing::span!(tracing::Level::INFO, "search_dependencies", ?query).entered(); + let _p = tracing::info_span!("search_dependencies", ?query).entered(); let graph = db.crate_graph(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs index acda64c41fb24..c3b7a78301d27 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs @@ -99,7 +99,7 @@ pub struct ItemTree { impl ItemTree { pub(crate) fn file_item_tree_query(db: &dyn DefDatabase, file_id: HirFileId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "file_item_tree_query", ?file_id).entered(); + let _p = tracing::info_span!("file_item_tree_query", ?file_id).entered(); let syntax = db.parse_or_expand(file_id); @@ -242,11 +242,11 @@ impl ItemVisibilities { match &vis { RawVisibility::Public => RawVisibilityId::PUB, RawVisibility::Module(path, explicitiy) if path.segments().is_empty() => { - match (&path.kind, explicitiy) { - (PathKind::Super(0), VisibilityExplicitness::Explicit) => { + match (path.kind, explicitiy) { + (PathKind::SELF, VisibilityExplicitness::Explicit) => { RawVisibilityId::PRIV_EXPLICIT } - (PathKind::Super(0), VisibilityExplicitness::Implicit) => { + (PathKind::SELF, VisibilityExplicitness::Implicit) => { RawVisibilityId::PRIV_IMPLICIT } (PathKind::Crate, _) => RawVisibilityId::PUB_CRATE, @@ -586,11 +586,11 @@ impl Index for ItemTree { fn index(&self, index: RawVisibilityId) -> &Self::Output { static VIS_PUB: RawVisibility = RawVisibility::Public; static VIS_PRIV_IMPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), + ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit, ); static VIS_PRIV_EXPLICIT: RawVisibility = RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), + ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Explicit, ); static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module( @@ -928,7 +928,7 @@ impl UseTree { _ => None, } } - (Some(prefix), PathKind::Super(0)) if path.segments().is_empty() => { + (Some(prefix), PathKind::SELF) if path.segments().is_empty() => { // `some::path::self` == `some::path` Some((prefix, ImportKind::TypeOnly)) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs index 3a07c678428e4..6d7836d5ae899 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs @@ -91,7 +91,7 @@ impl LangItems { db: &dyn DefDatabase, krate: CrateId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "crate_lang_items_query").entered(); + let _p = tracing::info_span!("crate_lang_items_query").entered(); let mut lang_items = LangItems::default(); @@ -163,7 +163,7 @@ impl LangItems { start_crate: CrateId, item: LangItem, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "lang_item_query").entered(); + let _p = tracing::info_span!("lang_item_query").entered(); if let Some(target) = db.crate_lang_items(start_crate).and_then(|it| it.items.get(&item).copied()) { @@ -183,7 +183,7 @@ impl LangItems { ) where T: Into + Copy, { - let _p = tracing::span!(tracing::Level::INFO, "collect_lang_item").entered(); + let _p = tracing::info_span!("collect_lang_item").entered(); if let Some(lang_item) = lang_attr(db, item.into()) { self.items.entry(lang_item).or_insert_with(|| constructor(item)); } @@ -199,7 +199,7 @@ pub(crate) fn notable_traits_in_deps( db: &dyn DefDatabase, krate: CrateId, ) -> Arc<[Arc<[TraitId]>]> { - let _p = tracing::span!(tracing::Level::INFO, "notable_traits_in_deps", ?krate).entered(); + let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered(); let crate_graph = db.crate_graph(); Arc::from_iter( @@ -208,7 +208,7 @@ pub(crate) fn notable_traits_in_deps( } pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: CrateId) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "crate_notable_traits", ?krate).entered(); + let _p = tracing::info_span!("crate_notable_traits", ?krate).entered(); let mut traits = Vec::new(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs index 682d169adb11b..f6fe0c618a296 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs @@ -56,6 +56,7 @@ pub mod find_path; pub mod import_map; pub mod visibility; +use intern::Interned; pub use rustc_abi as layout; use triomphe::Arc; @@ -72,7 +73,7 @@ use std::{ use base_db::{ impl_intern_key, - salsa::{self, impl_intern_value_trivial}, + salsa::{self, InternValueTrivial}, CrateId, }; use hir_expand::{ @@ -90,7 +91,7 @@ use hir_expand::{ use item_tree::ExternBlock; use la_arena::Idx; use nameres::DefMap; -use span::{AstIdNode, Edition, FileAstId, FileId, SyntaxContextId}; +use span::{AstIdNode, Edition, FileAstId, SyntaxContextId}; use stdx::impl_from; use syntax::{ast, AstNode}; @@ -186,7 +187,7 @@ pub trait ItemTreeLoc { macro_rules! impl_intern { ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => { impl_intern_key!($id); - impl_intern_value_trivial!($loc); + impl InternValueTrivial for $loc {} impl_intern_lookup!(DefDatabase, $id, $loc, $intern, $lookup); }; } @@ -396,6 +397,23 @@ impl PartialEq for CrateRootModuleId { other.block.is_none() && other.local_id == DefMap::ROOT && self.krate == other.krate } } +impl PartialEq for ModuleId { + fn eq(&self, other: &CrateRootModuleId) -> bool { + other == self + } +} + +impl From for ModuleId { + fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { + ModuleId { krate, block: None, local_id: DefMap::ROOT } + } +} + +impl From for ModuleDefId { + fn from(value: CrateRootModuleId) -> Self { + ModuleDefId::ModuleId(value.into()) + } +} impl From for CrateRootModuleId { fn from(krate: CrateId) -> Self { @@ -472,6 +490,7 @@ impl ModuleId { self.block.is_some() } + /// Returns the [`CrateRootModuleId`] for this module if it is the crate root module. pub fn as_crate_root(&self) -> Option { if self.local_id == DefMap::ROOT && self.block.is_none() { Some(CrateRootModuleId { krate: self.krate }) @@ -480,33 +499,17 @@ impl ModuleId { } } + /// Returns the [`CrateRootModuleId`] for this module. pub fn derive_crate_root(&self) -> CrateRootModuleId { CrateRootModuleId { krate: self.krate } } + /// Whether this module represents the crate root module fn is_crate_root(&self) -> bool { self.local_id == DefMap::ROOT && self.block.is_none() } } -impl PartialEq for ModuleId { - fn eq(&self, other: &CrateRootModuleId) -> bool { - other == self - } -} - -impl From for ModuleId { - fn from(CrateRootModuleId { krate }: CrateRootModuleId) -> Self { - ModuleId { krate, block: None, local_id: DefMap::ROOT } - } -} - -impl From for ModuleDefId { - fn from(value: CrateRootModuleId) -> Self { - ModuleDefId::ModuleId(value.into()) - } -} - /// An ID of a module, **local** to a `DefMap`. pub type LocalModuleId = Idx; @@ -532,7 +535,7 @@ pub struct TypeOrConstParamId { pub parent: GenericDefId, pub local_id: LocalTypeOrConstParamId, } -impl_intern_value_trivial!(TypeOrConstParamId); +impl InternValueTrivial for TypeOrConstParamId {} /// A TypeOrConstParamId with an invariant that it actually belongs to a type #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -594,7 +597,7 @@ pub struct LifetimeParamId { pub local_id: LocalLifetimeParamId, } pub type LocalLifetimeParamId = Idx; -impl_intern_value_trivial!(LifetimeParamId); +impl InternValueTrivial for LifetimeParamId {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum ItemContainerId { @@ -920,6 +923,7 @@ pub enum GenericDefId { ImplId(ImplId), // enum variants cannot have generics themselves, but their parent enums // can, and this makes some code easier to write + // FIXME: Try to remove this as that will reduce the amount of query slots generated per enum? EnumVariantId(EnumVariantId), // consts can have type parameters from their parents (i.e. associated consts of traits) ConstId(ConstId), @@ -956,15 +960,14 @@ impl GenericDefId { match self { GenericDefId::FunctionId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TypeAliasId(it) => file_id_and_params_of_item_loc(db, it), - GenericDefId::ConstId(_) => (FileId::BOGUS.into(), None), GenericDefId::AdtId(AdtId::StructId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::AdtId(AdtId::UnionId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::AdtId(AdtId::EnumId(it)) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it), GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it), - // We won't be using this ID anyway - GenericDefId::EnumVariantId(_) => (FileId::BOGUS.into(), None), + GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None), + GenericDefId::EnumVariantId(it) => (it.lookup(db).id.file_id(), None), } } @@ -1368,7 +1371,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Option { self.as_call_id_with_errors(db, krate, resolver).ok()?.value } @@ -1377,7 +1380,7 @@ pub trait AsMacroCall { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result>, UnresolvedMacro>; } @@ -1386,7 +1389,7 @@ impl AsMacroCall for InFile<&ast::MacroCall> { &self, db: &dyn ExpandDatabase, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result>, UnresolvedMacro> { let expands_to = hir_expand::ExpandTo::from_call_site(self.value); let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); @@ -1406,7 +1409,8 @@ impl AsMacroCall for InFile<&ast::MacroCall> { macro_call_as_call_id_with_eager( db, - &AstIdWithPath::new(ast_id.file_id, ast_id.value, path), + ast_id, + &path, call_site.ctx, expands_to, krate, @@ -1420,11 +1424,15 @@ impl AsMacroCall for InFile<&ast::MacroCall> { #[derive(Clone, Debug, Eq, PartialEq)] struct AstIdWithPath { ast_id: AstId, - path: path::ModPath, + path: Interned, } impl AstIdWithPath { - fn new(file_id: HirFileId, ast_id: FileAstId, path: path::ModPath) -> AstIdWithPath { + fn new( + file_id: HirFileId, + ast_id: FileAstId, + path: Interned, + ) -> AstIdWithPath { AstIdWithPath { ast_id: AstId::new(file_id, ast_id), path } } } @@ -1435,30 +1443,39 @@ fn macro_call_as_call_id( call_site: SyntaxContextId, expand_to: ExpandTo, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option + Copy, + resolver: impl Fn(&path::ModPath) -> Option + Copy, ) -> Result, UnresolvedMacro> { - macro_call_as_call_id_with_eager(db, call, call_site, expand_to, krate, resolver, resolver) - .map(|res| res.value) + macro_call_as_call_id_with_eager( + db, + call.ast_id, + &call.path, + call_site, + expand_to, + krate, + resolver, + resolver, + ) + .map(|res| res.value) } fn macro_call_as_call_id_with_eager( db: &dyn ExpandDatabase, - call: &AstIdWithPath, + ast_id: AstId, + path: &path::ModPath, call_site: SyntaxContextId, expand_to: ExpandTo, krate: CrateId, - resolver: impl FnOnce(path::ModPath) -> Option, - eager_resolver: impl Fn(path::ModPath) -> Option, + resolver: impl FnOnce(&path::ModPath) -> Option, + eager_resolver: impl Fn(&path::ModPath) -> Option, ) -> Result>, UnresolvedMacro> { - let def = - resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?; + let def = resolver(path).ok_or_else(|| UnresolvedMacro { path: path.clone() })?; let res = match def.kind { MacroDefKind::BuiltInEager(..) => expand_eager_macro_input( db, krate, - &call.ast_id.to_node(db), - call.ast_id, + &ast_id.to_node(db), + ast_id, def, call_site, &|path| eager_resolver(path).filter(MacroDefId::is_fn_like), @@ -1467,12 +1484,12 @@ fn macro_call_as_call_id_with_eager( value: Some(def.make_call( db, krate, - MacroCallKind::FnLike { ast_id: call.ast_id, expand_to, eager: None }, + MacroCallKind::FnLike { ast_id, expand_to, eager: None }, call_site, )), err: None, }, - _ => return Err(UnresolvedMacro { path: call.path.clone() }), + _ => return Err(UnresolvedMacro { path: path.clone() }), }; Ok(res) } diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs index c5c26e26bc0e7..4058159cefefe 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs @@ -1883,3 +1883,41 @@ fn test() { "#]], ); } + +#[test] +fn test_pat_fragment_eof_17441() { + check( + r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? ) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn f() { + matches!(0, 10..); + matches!(0, 10.. if true); +} + "#, + expect![[r#" +macro_rules! matches { + ($expression:expr, $pattern:pat $(if $guard:expr)? ) => { + match $expression { + $pattern $(if $guard)? => true, + _ => false + } + }; +} +fn f() { + match 0 { + 10.. =>true , _=>false + }; + match 0 { + 10..if true =>true , _=>false + }; +} + "#]], + ); +} diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs index 8904aca9f2849..dc964b3c9a8df 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs @@ -96,7 +96,7 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream let res = macro_call .as_call_id_with_errors(&db, krate, |path| { resolver - .resolve_path_as_macro(&db, &path, Some(MacroSubNs::Bang)) + .resolve_path_as_macro(&db, path, Some(MacroSubNs::Bang)) .map(|(it, _)| db.macro_def(it)) }) .unwrap(); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs index a3eab22fc49c4..162b6429c341f 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs @@ -16,8 +16,8 @@ //! //! This happens in the `raw` module, which parses a single source file into a //! set of top-level items. Nested imports are desugared to flat imports in this -//! phase. Macro calls are represented as a triple of (Path, Option, -//! TokenTree). +//! phase. Macro calls are represented as a triple of `(Path, Option, +//! TokenTree)`. //! //! ## Collecting Modules //! @@ -333,7 +333,7 @@ impl DefMap { let crate_graph = db.crate_graph(); let krate = &crate_graph[crate_id]; let name = krate.display_name.as_deref().unwrap_or_default(); - let _p = tracing::span!(tracing::Level::INFO, "crate_def_map_query", ?name).entered(); + let _p = tracing::info_span!("crate_def_map_query", ?name).entered(); let module_data = ModuleData::new( ModuleOrigin::CrateRoot { definition: krate.root_file_id }, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs index 3cb0666edf9c3..f842027d642a6 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs @@ -3,6 +3,7 @@ use base_db::CrateId; use hir_expand::{ attrs::{Attr, AttrId, AttrInput}, + inert_attr_macro::find_builtin_attr_idx, MacroCallId, MacroCallKind, MacroDefId, }; use span::SyntaxContextId; @@ -10,7 +11,6 @@ use syntax::{ast, SmolStr}; use triomphe::Arc; use crate::{ - attr::builtin::find_builtin_attr_idx, db::DefDatabase, item_scope::BuiltinShadowMode, nameres::path_resolution::ResolveMode, @@ -59,7 +59,7 @@ impl DefMap { return Ok(ResolvedAttr::Other); } } - None => return Err(UnresolvedMacro { path: ast_id.path }), + None => return Err(UnresolvedMacro { path: ast_id.path.as_ref().clone() }), }; Ok(ResolvedAttr::Macro(attr_macro_as_call_id( @@ -89,9 +89,12 @@ impl DefMap { } if segments.len() == 1 { - let mut registered = self.data.registered_attrs.iter().map(SmolStr::as_str); - let is_inert = find_builtin_attr_idx(&name).is_some() || registered.any(pred); - return is_inert; + if find_builtin_attr_idx(&name).is_some() { + return true; + } + if self.data.registered_attrs.iter().map(SmolStr::as_str).any(pred) { + return true; + } } } false @@ -134,12 +137,12 @@ pub(super) fn derive_macro_as_call_id( derive_pos: u32, call_site: SyntaxContextId, krate: CrateId, - resolver: impl Fn(path::ModPath) -> Option<(MacroId, MacroDefId)>, + resolver: impl Fn(&path::ModPath) -> Option<(MacroId, MacroDefId)>, derive_macro_id: MacroCallId, ) -> Result<(MacroId, MacroDefId, MacroCallId), UnresolvedMacro> { - let (macro_id, def_id) = resolver(item_attr.path.clone()) + let (macro_id, def_id) = resolver(&item_attr.path) .filter(|(_, def_id)| def_id.is_derive()) - .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?; + .ok_or_else(|| UnresolvedMacro { path: item_attr.path.as_ref().clone() })?; let call_id = def_id.make_call( db.upcast(), krate, diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs index 587997c47361a..6d2eb71549e70 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs @@ -10,18 +10,19 @@ use cfg::{CfgExpr, CfgOptions}; use either::Either; use hir_expand::{ attrs::{Attr, AttrId}, - builtin_attr_macro::{find_builtin_attr, BuiltinAttrExpander}, + builtin_attr_macro::find_builtin_attr, builtin_derive_macro::find_builtin_derive, builtin_fn_macro::find_builtin_macro, name::{name, AsName, Name}, proc_macro::CustomProcMacroExpander, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, }; +use intern::Interned; use itertools::{izip, Itertools}; use la_arena::Idx; use limit::Limit; use rustc_hash::{FxHashMap, FxHashSet}; -use span::{Edition, ErasedFileAstId, FileAstId, Span, SyntaxContextId}; +use span::{Edition, ErasedFileAstId, FileAstId, SyntaxContextId}; use syntax::ast; use triomphe::Arc; @@ -75,36 +76,23 @@ pub(super) fn collect_defs(db: &dyn DefDatabase, def_map: DefMap, tree_id: TreeI let proc_macros = if krate.is_proc_macro { match db.proc_macros().get(&def_map.krate) { - Some(Ok(proc_macros)) => { - Ok(proc_macros - .iter() - .enumerate() - .map(|(idx, it)| { - // FIXME: a hacky way to create a Name from string. - let name = tt::Ident { - text: it.name.clone(), - span: Span { - range: syntax::TextRange::empty(syntax::TextSize::new(0)), - anchor: span::SpanAnchor { - file_id: FileId::BOGUS, - ast_id: span::ROOT_ERASED_FILE_AST_ID, - }, - ctx: SyntaxContextId::ROOT, - }, - }; - ( - name.as_name(), - if it.disabled { - CustomProcMacroExpander::disabled() - } else { - CustomProcMacroExpander::new( - hir_expand::proc_macro::ProcMacroId::new(idx as u32), - ) - }, - ) - }) - .collect()) - } + Some(Ok(proc_macros)) => Ok(proc_macros + .iter() + .enumerate() + .map(|(idx, it)| { + let name = Name::new_text_dont_use(it.name.clone()); + ( + name, + if it.disabled { + CustomProcMacroExpander::disabled() + } else { + CustomProcMacroExpander::new(hir_expand::proc_macro::ProcMacroId::new( + idx as u32, + )) + }, + ) + }) + .collect()), Some(Err(e)) => Err(e.clone().into_boxed_str()), None => Err("No proc-macros present for crate".to_owned().into_boxed_str()), } @@ -270,12 +258,13 @@ struct DefCollector<'a> { /// /// This also stores the attributes to skip when we resolve derive helpers and non-macro /// non-builtin attributes in general. + // FIXME: There has to be a better way to do this skip_attrs: FxHashMap, AttrId>, } impl DefCollector<'_> { fn seed_with_top_level(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "seed_with_top_level").entered(); + let _p = tracing::info_span!("seed_with_top_level").entered(); let crate_graph = self.db.crate_graph(); let file_id = crate_graph[self.def_map.krate].root_file_id; @@ -410,17 +399,17 @@ impl DefCollector<'_> { } fn resolution_loop(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::resolution_loop").entered(); + let _p = tracing::info_span!("DefCollector::resolution_loop").entered(); // main name resolution fixed-point loop. let mut i = 0; 'resolve_attr: loop { - let _p = tracing::span!(tracing::Level::INFO, "resolve_macros loop").entered(); + let _p = tracing::info_span!("resolve_macros loop").entered(); 'resolve_macros: loop { self.db.unwind_if_cancelled(); { - let _p = tracing::span!(tracing::Level::INFO, "resolve_imports loop").entered(); + let _p = tracing::info_span!("resolve_imports loop").entered(); 'resolve_imports: loop { if self.resolve_imports() == ReachedFixedPoint::Yes { @@ -446,7 +435,7 @@ impl DefCollector<'_> { } fn collect(&mut self) { - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::collect").entered(); + let _p = tracing::info_span!("DefCollector::collect").entered(); self.resolution_loop(); @@ -794,7 +783,7 @@ impl DefCollector<'_> { } fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialResolvedImport { - let _p = tracing::span!(tracing::Level::INFO, "resolve_import", import_path = %import.path.display(self.db.upcast())) + let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db.upcast())) .entered(); tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition); match import.source { @@ -856,7 +845,7 @@ impl DefCollector<'_> { } fn record_resolved_import(&mut self, directive: &ImportDirective) { - let _p = tracing::span!(tracing::Level::INFO, "record_resolved_import").entered(); + let _p = tracing::info_span!("record_resolved_import").entered(); let module_id = directive.module_id; let import = &directive.import; @@ -1136,18 +1125,18 @@ impl DefCollector<'_> { MacroSubNs::Attr } }; - let resolver = |path| { + let resolver = |path: &_| { let resolved_res = self.def_map.resolve_path_fp_with_macro( self.db, ResolveMode::Other, directive.module_id, - &path, + path, BuiltinShadowMode::Module, Some(subns), ); resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it))) }; - let resolver_def_id = |path| resolver(path).map(|(_, it)| it); + let resolver_def_id = |path: &_| resolver(path).map(|(_, it)| it); match &directive.kind { MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => { @@ -1250,22 +1239,28 @@ impl DefCollector<'_> { } } - let def = match resolver_def_id(path.clone()) { + let def = match resolver_def_id(path) { Some(def) if def.is_attribute() => def, _ => return Resolved::No, }; - let call_id = - attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def); - if let MacroDefId { - kind: - MacroDefKind::BuiltInAttr( - BuiltinAttrExpander::Derive | BuiltinAttrExpander::DeriveConst, - _, - ), - .. - } = def - { + // Skip #[test]/#[bench] expansion, which would merely result in more memory usage + // due to duplicating functions into macro expansions + if matches!( + def.kind, + MacroDefKind::BuiltInAttr(_, expander) + if expander.is_test() || expander.is_bench() + ) { + return recollect_without(self); + } + + let call_id = || { + attr_macro_as_call_id(self.db, file_ast_id, attr, self.def_map.krate, def) + }; + if matches!(def, + MacroDefId { kind: MacroDefKind::BuiltInAttr(_, exp), .. } + if exp.is_derive() + ) { // Resolved to `#[derive]`, we don't actually expand this attribute like // normal (as that would just be an identity expansion with extra output) // Instead we treat derive attributes special and apply them separately. @@ -1290,9 +1285,14 @@ impl DefCollector<'_> { match attr.parse_path_comma_token_tree(self.db.upcast()) { Some(derive_macros) => { + let call_id = call_id(); let mut len = 0; for (idx, (path, call_site)) in derive_macros.enumerate() { - let ast_id = AstIdWithPath::new(file_id, ast_id.value, path); + let ast_id = AstIdWithPath::new( + file_id, + ast_id.value, + Interned::new(path), + ); self.unresolved_macros.push(MacroDirective { module_id: directive.module_id, depth: directive.depth + 1, @@ -1312,13 +1312,6 @@ impl DefCollector<'_> { // This is just a trick to be able to resolve the input to derives // as proper paths in `Semantics`. // Check the comment in [`builtin_attr_macro`]. - let call_id = attr_macro_as_call_id( - self.db, - file_ast_id, - attr, - self.def_map.krate, - def, - ); self.def_map.modules[directive.module_id] .scope .init_derive_attribute(ast_id, attr.id, call_id, len + 1); @@ -1336,17 +1329,8 @@ impl DefCollector<'_> { return recollect_without(self); } - // Skip #[test]/#[bench] expansion, which would merely result in more memory usage - // due to duplicating functions into macro expansions - if matches!( - def.kind, - MacroDefKind::BuiltInAttr(expander, _) - if expander.is_test() || expander.is_bench() - ) { - return recollect_without(self); - } - - if let MacroDefKind::ProcMacro(exp, ..) = def.kind { + let call_id = call_id(); + if let MacroDefKind::ProcMacro(_, exp, _) = def.kind { // If proc attribute macro expansion is disabled, skip expanding it here if !self.db.expand_proc_attr_macros() { self.def_map.diagnostics.push(DefDiagnostic::unresolved_proc_macro( @@ -1430,7 +1414,7 @@ impl DefCollector<'_> { fn finish(mut self) -> DefMap { // Emit diagnostics for all remaining unexpanded macros. - let _p = tracing::span!(tracing::Level::INFO, "DefCollector::finish").entered(); + let _p = tracing::info_span!("DefCollector::finish").entered(); for directive in &self.unresolved_macros { match &directive.kind { @@ -1447,7 +1431,7 @@ impl DefCollector<'_> { self.db, ResolveMode::Other, directive.module_id, - &path, + path, BuiltinShadowMode::Module, Some(MacroSubNs::Bang), ); @@ -1481,7 +1465,7 @@ impl DefCollector<'_> { derive_index: *derive_pos as u32, derive_macro_id: *derive_macro_id, }, - ast_id.path.clone(), + ast_id.path.as_ref().clone(), )); } // These are diagnosed by `reseed_with_unresolved_attribute`, as that function consumes them @@ -2116,7 +2100,7 @@ impl ModCollector<'_, '_> { let ast_id = AstIdWithPath::new( self.file_id(), mod_item.ast_id(self.item_tree), - attr.path.as_ref().clone(), + attr.path.clone(), ); self.def_collector.unresolved_macros.push(MacroDirective { module_id: self.module_id, @@ -2162,19 +2146,7 @@ impl ModCollector<'_, '_> { let name; let name = match attrs.by_key("rustc_builtin_macro").string_value() { Some(it) => { - // FIXME: a hacky way to create a Name from string. - name = tt::Ident { - text: it.into(), - span: Span { - range: syntax::TextRange::empty(syntax::TextSize::new(0)), - anchor: span::SpanAnchor { - file_id: FileId::BOGUS, - ast_id: span::ROOT_ERASED_FILE_AST_ID, - }, - ctx: SyntaxContextId::ROOT, - }, - } - .as_name(); + name = Name::new_text_dont_use(it.into()); &name } None => { @@ -2310,7 +2282,7 @@ impl ModCollector<'_, '_> { &MacroCall { ref path, ast_id, expand_to, ctxt }: &MacroCall, container: ItemContainerId, ) { - let ast_id = AstIdWithPath::new(self.file_id(), ast_id, ModPath::clone(path)); + let ast_id = AstIdWithPath::new(self.file_id(), ast_id, path.clone()); let db = self.def_collector.db; // FIXME: Immediately expanding in "Case 1" is insufficient since "Case 2" may also define @@ -2320,7 +2292,8 @@ impl ModCollector<'_, '_> { // Case 1: try to resolve macro calls with single-segment name and expand macro_rules if let Ok(res) = macro_call_as_call_id_with_eager( db.upcast(), - &ast_id, + ast_id.ast_id, + &ast_id.path, ctxt, expand_to, self.def_collector.def_map.krate, @@ -2347,7 +2320,7 @@ impl ModCollector<'_, '_> { db, ResolveMode::Other, self.module_id, - &path, + path, BuiltinShadowMode::Module, Some(MacroSubNs::Bang), ); diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs index d621f3a360a96..e797d19223ed2 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/path_resolution.rs @@ -283,7 +283,7 @@ impl DefMap { // If we have a different `DefMap` from `self` (the original `DefMap` we started // with), resolve the remaining path segments in that `DefMap`. let path = - ModPath::from_segments(PathKind::Super(0), path.segments().iter().cloned()); + ModPath::from_segments(PathKind::SELF, path.segments().iter().cloned()); return def_map.resolve_path_fp_with_macro( db, mode, @@ -333,7 +333,7 @@ impl DefMap { ModuleDefId::ModuleId(module) => { if module.krate != self.krate { let path = ModPath::from_segments( - PathKind::Super(0), + PathKind::SELF, path.segments()[i..].iter().cloned(), ); tracing::debug!("resolving {:?} in other crate", path); @@ -493,7 +493,12 @@ impl DefMap { ) }) }; - let prelude = || self.resolve_in_prelude(db, name); + let prelude = || { + if self.block.is_some() && module == DefMap::ROOT { + return PerNs::none(); + } + self.resolve_in_prelude(db, name) + }; from_legacy_macro .or(from_scope_or_builtin) diff --git a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs index 6af5261411168..2b555b3998a79 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/path/lower.rs @@ -122,7 +122,7 @@ pub(super) fn lower_path(ctx: &LowerCtx<'_>, mut path: ast::Path) -> Option, mut path: ast::Path) -> Option bool) -> PerNs { - let _p = tracing::span!(tracing::Level::INFO, "PerNs::filter_visibility").entered(); + let _p = tracing::info_span!("PerNs::filter_visibility").entered(); PerNs { types: self.types.filter(|&(_, v, _)| f(v)), values: self.values.filter(|&(_, v, _)| f(v)), @@ -119,7 +119,7 @@ impl PerNs { } pub fn iter_items(self) -> impl Iterator)> { - let _p = tracing::span!(tracing::Level::INFO, "PerNs::iter_items").entered(); + let _p = tracing::info_span!("PerNs::iter_items").entered(); self.types .map(|it| (ItemInNs::Types(it.0), it.2)) .into_iter() diff --git a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs index d3135bba9656f..d08e063976a38 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/pretty.rs @@ -57,7 +57,7 @@ pub(crate) fn print_path(db: &dyn DefDatabase, path: &Path, buf: &mut dyn Write) } None => match path.kind() { PathKind::Plain => {} - PathKind::Super(0) => write!(buf, "self")?, + &PathKind::SELF => write!(buf, "self")?, PathKind::Super(n) => { for i in 0..*n { if i == 0 { diff --git a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs index 1ef8fa772a11c..e08718fc83661 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs +++ b/src/tools/rust-analyzer/crates/hir-def/src/visibility.rs @@ -27,10 +27,7 @@ pub enum RawVisibility { impl RawVisibility { pub(crate) const fn private() -> RawVisibility { - RawVisibility::Module( - ModPath::from_kind(PathKind::Super(0)), - VisibilityExplicitness::Implicit, - ) + RawVisibility::Module(ModPath::from_kind(PathKind::SELF), VisibilityExplicitness::Implicit) } pub(crate) fn from_ast( @@ -60,7 +57,7 @@ impl RawVisibility { } ast::VisibilityKind::PubCrate => ModPath::from_kind(PathKind::Crate), ast::VisibilityKind::PubSuper => ModPath::from_kind(PathKind::Super(1)), - ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::Super(0)), + ast::VisibilityKind::PubSelf => ModPath::from_kind(PathKind::SELF), ast::VisibilityKind::Pub => return RawVisibility::Public, }; RawVisibility::Module(path, VisibilityExplicitness::Explicit) diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs index 85ec02ae07313..db0feb055e198 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs @@ -54,7 +54,7 @@ impl RawAttrs { let span = span_map.span_for_range(comment.syntax().text_range()); Attr { id, - input: Some(Interned::new(AttrInput::Literal(tt::Literal { + input: Some(Box::new(AttrInput::Literal(tt::Literal { text: SmolStr::new(format_smolstr!("\"{}\"", Self::escape_chars(doc))), span, }))), @@ -199,7 +199,7 @@ impl AttrId { pub struct Attr { pub id: AttrId, pub path: Interned, - pub input: Option>, + pub input: Option>, pub ctxt: SyntaxContextId, } @@ -234,7 +234,7 @@ impl Attr { })?); let span = span_map.span_for_range(range); let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { - Some(Interned::new(AttrInput::Literal(tt::Literal { + Some(Box::new(AttrInput::Literal(tt::Literal { text: lit.token().text().into(), span, }))) @@ -245,7 +245,7 @@ impl Attr { span, DocCommentDesugarMode::ProcMacro, ); - Some(Interned::new(AttrInput::TokenTree(Box::new(tree)))) + Some(Box::new(AttrInput::TokenTree(Box::new(tree)))) } else { None }; @@ -281,12 +281,12 @@ impl Attr { let input = match input.first() { Some(tt::TokenTree::Subtree(tree)) => { - Some(Interned::new(AttrInput::TokenTree(Box::new(tree.clone())))) + Some(Box::new(AttrInput::TokenTree(Box::new(tree.clone())))) } Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. }))) => { let input = match input.get(1) { Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) => { - Some(Interned::new(AttrInput::Literal(lit.clone()))) + Some(Box::new(AttrInput::Literal(lit.clone()))) } _ => None, }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs index 9ff29b484d32d..2e115f479327e 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_attr_macro.rs @@ -52,8 +52,6 @@ impl BuiltinAttrExpander { register_builtin! { (bench, Bench) => dummy_attr_expand, - (cfg, Cfg) => dummy_attr_expand, - (cfg_attr, CfgAttr) => dummy_attr_expand, (cfg_accessible, CfgAccessible) => dummy_attr_expand, (cfg_eval, CfgEval) => dummy_attr_expand, (derive, Derive) => derive_expand, diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs index ba96ab6cc2f06..02fd431e4e7ec 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin_fn_macro.rs @@ -67,6 +67,10 @@ impl BuiltinFnLikeExpander { let span = span_with_def_site_ctxt(db, span, id); self.expander()(db, id, tt, span) } + + pub fn is_asm(&self) -> bool { + matches!(self, Self::Asm | Self::GlobalAsm) + } } impl EagerExpander { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs index 9dd44262ba954..55ae19068f9c6 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/cfg_process.rs @@ -189,8 +189,8 @@ pub(crate) fn process_cfg_attrs( // FIXME: #[cfg_eval] is not implemented. But it is not stable yet let is_derive = match loc.def.kind { MacroDefKind::BuiltInDerive(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) => true, - MacroDefKind::BuiltInAttr(expander, _) => expander.is_derive(), + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) => true, + MacroDefKind::BuiltInAttr(_, expander) => expander.is_derive(), _ => false, }; if !is_derive { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs index 12421bbe70263..ad25a1168c4d5 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/db.rs @@ -146,13 +146,11 @@ pub fn expand_speculative( token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { let loc = db.lookup_intern_macro_call(actual_macro_call); + let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind); - // FIXME: This BOGUS here is dangerous once the proc-macro server can call back into the database! - let span_map = RealSpanMap::absolute(FileId::BOGUS); + let span_map = RealSpanMap::absolute(span.anchor.file_id); let span_map = SpanMapRef::RealSpanMap(&span_map); - let (_, _, span) = db.macro_arg_considering_derives(actual_macro_call, &loc.kind); - // Build the subtree and token mapping for the speculative args let (mut tt, undo_info) = match loc.kind { MacroCallKind::FnLike { .. } => ( @@ -252,7 +250,7 @@ pub fn expand_speculative( // Otherwise the expand query will fetch the non speculative attribute args and pass those instead. let mut speculative_expansion = match loc.def.kind { - MacroDefKind::ProcMacro(expander, _, ast) => { + MacroDefKind::ProcMacro(ast, expander, _) => { let span = db.proc_macro_span(ast); tt.delimiter = tt::Delimiter::invisible_spanned(span); expander.expand( @@ -266,22 +264,22 @@ pub fn expand_speculative( span_with_mixed_site_ctxt(db, span, actual_macro_call), ) } - MacroDefKind::BuiltInAttr(BuiltinAttrExpander::Derive, _) => { + MacroDefKind::BuiltInAttr(_, it) if it.is_derive() => { pseudo_derive_attr_expansion(&tt, attr_arg.as_ref()?, span) } MacroDefKind::Declarative(it) => db .decl_macro_expander(loc.krate, it) .expand_unhygienic(db, tt, loc.def.krate, span, loc.def.edition), - MacroDefKind::BuiltIn(it, _) => { + MacroDefKind::BuiltIn(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInDerive(it, ..) => { + MacroDefKind::BuiltInDerive(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInEager(it, _) => { + MacroDefKind::BuiltInEager(_, it) => { it.expand(db, actual_macro_call, &tt, span).map_err(Into::into) } - MacroDefKind::BuiltInAttr(it, _) => it.expand(db, actual_macro_call, &tt, span), + MacroDefKind::BuiltInAttr(_, it) => it.expand(db, actual_macro_call, &tt, span), }; let expand_to = loc.expand_to(); @@ -334,7 +332,7 @@ fn parse_macro_expansion( db: &dyn ExpandDatabase, macro_file: MacroFileId, ) -> ExpandResult<(Parse, Arc)> { - let _p = tracing::span!(tracing::Level::INFO, "parse_macro_expansion").entered(); + let _p = tracing::info_span!("parse_macro_expansion").entered(); let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); let edition = loc.def.edition; let expand_to = loc.expand_to(); @@ -493,7 +491,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult { .map_or_else(|| node.syntax().text_range(), |it| it.syntax().text_range()), ); // If derive attribute we need to censor the derive input - if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) + if matches!(loc.def.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()) && ast::Adt::can_cast(node.syntax().kind()) { let adt = ast::Adt::cast(node.syntax().clone()).unwrap(); @@ -569,11 +567,11 @@ impl TokenExpander { MacroDefKind::Declarative(ast_id) => { TokenExpander::DeclarativeMacro(db.decl_macro_expander(id.krate, ast_id)) } - MacroDefKind::BuiltIn(expander, _) => TokenExpander::BuiltIn(expander), - MacroDefKind::BuiltInAttr(expander, _) => TokenExpander::BuiltInAttr(expander), - MacroDefKind::BuiltInDerive(expander, _) => TokenExpander::BuiltInDerive(expander), - MacroDefKind::BuiltInEager(expander, ..) => TokenExpander::BuiltInEager(expander), - MacroDefKind::ProcMacro(expander, ..) => TokenExpander::ProcMacro(expander), + MacroDefKind::BuiltIn(_, expander) => TokenExpander::BuiltIn(expander), + MacroDefKind::BuiltInAttr(_, expander) => TokenExpander::BuiltInAttr(expander), + MacroDefKind::BuiltInDerive(_, expander) => TokenExpander::BuiltInDerive(expander), + MacroDefKind::BuiltInEager(_, expander) => TokenExpander::BuiltInEager(expander), + MacroDefKind::ProcMacro(_, expander, _) => TokenExpander::ProcMacro(expander), } } } @@ -588,7 +586,7 @@ fn macro_expand( macro_call_id: MacroCallId, loc: MacroCallLoc, ) -> ExpandResult<(CowArc, MatchedArmIndex)> { - let _p = tracing::span!(tracing::Level::INFO, "macro_expand").entered(); + let _p = tracing::info_span!("macro_expand").entered(); let (ExpandResult { value: (tt, matched_arm), err }, span) = match loc.def.kind { MacroDefKind::ProcMacro(..) => { @@ -604,13 +602,13 @@ fn macro_expand( MacroDefKind::Declarative(id) => db .decl_macro_expander(loc.def.krate, id) .expand(db, arg.clone(), macro_call_id, span), - MacroDefKind::BuiltIn(it, _) => { + MacroDefKind::BuiltIn(_, it) => { it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) } - MacroDefKind::BuiltInDerive(it, _) => { + MacroDefKind::BuiltInDerive(_, it) => { it.expand(db, macro_call_id, arg, span).map_err(Into::into).zip_val(None) } - MacroDefKind::BuiltInEager(it, _) => { + MacroDefKind::BuiltInEager(_, it) => { // This might look a bit odd, but we do not expand the inputs to eager macros here. // Eager macros inputs are expanded, well, eagerly when we collect the macro calls. // That kind of expansion uses the ast id map of an eager macros input though which goes through @@ -634,12 +632,12 @@ fn macro_expand( } res.zip_val(None) } - MacroDefKind::BuiltInAttr(it, _) => { + MacroDefKind::BuiltInAttr(_, it) => { let mut res = it.expand(db, macro_call_id, arg, span); fixup::reverse_fixups(&mut res.value, &undo_info); res.zip_val(None) } - _ => unreachable!(), + MacroDefKind::ProcMacro(_, _, _) => unreachable!(), }; (ExpandResult { value: res.value, err: res.err }, span) } @@ -678,8 +676,8 @@ fn expand_proc_macro(db: &dyn ExpandDatabase, id: MacroCallId) -> ExpandResult (expander, ast), + let (ast, expander) = match loc.def.kind { + MacroDefKind::ProcMacro(ast, expander, _) => (ast, expander), _ => unreachable!(), }; diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs index 64e04bc08f525..3e0d2dfa6c173 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/eager.rs @@ -39,7 +39,7 @@ pub fn expand_eager_macro_input( ast_id: AstId, def: MacroDefId, call_site: SyntaxContextId, - resolver: &dyn Fn(ModPath) -> Option, + resolver: &dyn Fn(&ModPath) -> Option, ) -> ExpandResult> { let expand_to = ExpandTo::from_call_site(macro_call); @@ -138,7 +138,7 @@ fn eager_macro_recur( curr: InFile, krate: CrateId, call_site: SyntaxContextId, - macro_resolver: &dyn Fn(ModPath) -> Option, + macro_resolver: &dyn Fn(&ModPath) -> Option, ) -> ExpandResult> { let original = curr.value.clone_for_update(); @@ -172,7 +172,7 @@ fn eager_macro_recur( let def = match call.path().and_then(|path| { ModPath::from_src(db, path, &mut |range| span_map.span_at(range.start()).ctx) }) { - Some(path) => match macro_resolver(path.clone()) { + Some(path) => match macro_resolver(&path) { Some(def) => def, None => { error = diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs index 1ba85c5c7eac0..743fac50f4e1d 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/files.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/files.rs @@ -1,6 +1,4 @@ //! Things to wrap other things in file ids. -use std::iter; - use either::Either; use span::{ AstIdNode, ErasedFileAstId, FileAstId, FileId, FileRange, HirFileId, HirFileIdRepr, @@ -150,27 +148,16 @@ impl InFileWrapper { } } +impl InFileWrapper { + // unfortunately `syntax` collides with the impl above, because `&_` is fundamental + pub fn syntax_ref(&self) -> InFileWrapper { + self.with_value(self.value.syntax()) + } +} + // region:specific impls impl InFile<&SyntaxNode> { - /// Traverse up macro calls and skips the macro invocation node - pub fn ancestors_with_macros( - self, - db: &dyn db::ExpandDatabase, - ) -> impl Iterator> + '_ { - let succ = move |node: &InFile| match node.value.parent() { - Some(parent) => Some(node.with_value(parent)), - None => db - .lookup_intern_macro_call(node.file_id.macro_file()?.macro_call_id) - .to_node_item(db) - .syntax() - .cloned() - .map(|node| node.parent()) - .transpose(), - }; - iter::successors(succ(&self.cloned()), succ) - } - /// Falls back to the macro call range if the node cannot be mapped up fully. /// /// For attributes and derives, this will point back to the attribute only. diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs index 9ec2a83162a62..9fdf4aa4f7cc7 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs @@ -4,7 +4,10 @@ use mbe::DocCommentDesugarMode; use rustc_hash::{FxHashMap, FxHashSet}; use smallvec::SmallVec; -use span::{ErasedFileAstId, Span, SpanAnchor, FIXUP_ERASED_FILE_AST_ID_MARKER}; +use span::{ + ErasedFileAstId, Span, SpanAnchor, SyntaxContextId, FIXUP_ERASED_FILE_AST_ID_MARKER, + ROOT_ERASED_FILE_AST_ID, +}; use stdx::never; use syntax::{ ast::{self, AstNode, HasLoopBody}, @@ -88,7 +91,6 @@ pub(crate) fn fixup_syntax( preorder.skip_subtree(); continue; } - // In some other situations, we can fix things by just appending some tokens. match_ast! { match node { @@ -273,6 +275,62 @@ pub(crate) fn fixup_syntax( ]); } }, + ast::RecordExprField(it) => { + if let Some(colon) = it.colon_token() { + if it.name_ref().is_some() && it.expr().is_none() { + append.insert(colon.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + } + }, + ast::Path(it) => { + if let Some(colon) = it.coloncolon_token() { + if it.segment().is_none() { + append.insert(colon.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + } + }, + ast::ArgList(it) => { + if it.r_paren_token().is_none() { + append.insert(node.into(), vec![ + Leaf::Punct(Punct { + span: fake_span(node_range), + char: ')', + spacing: Spacing::Alone + }) + ]); + } + }, + ast::ArgList(it) => { + if it.r_paren_token().is_none() { + append.insert(node.into(), vec![ + Leaf::Punct(Punct { + span: fake_span(node_range), + char: ')', + spacing: Spacing::Alone + }) + ]); + } + }, + ast::ClosureExpr(it) => { + if it.body().is_none() { + append.insert(node.into(), vec![ + Leaf::Ident(Ident { + text: "__ra_fixup".into(), + span: fake_span(node_range) + }) + ]); + } + }, _ => (), } } @@ -307,8 +365,13 @@ pub(crate) fn reverse_fixups(tt: &mut Subtree, undo_info: &SyntaxFixupUndoInfo) tt.delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID || tt.delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID ) { - tt.delimiter.close = Span::DUMMY; - tt.delimiter.open = Span::DUMMY; + let span = |file_id| Span { + range: TextRange::empty(TextSize::new(0)), + anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID }, + ctx: SyntaxContextId::ROOT, + }; + tt.delimiter.open = span(tt.delimiter.open.anchor.file_id); + tt.delimiter.close = span(tt.delimiter.close.anchor.file_id); } reverse_fixups_(tt, undo_info); } @@ -751,4 +814,84 @@ fn foo () {loop { }} "#]], ) } + + #[test] + fn fixup_path() { + check( + r#" +fn foo() { + path:: +} +"#, + expect![[r#" +fn foo () {path :: __ra_fixup} +"#]], + ) + } + + #[test] + fn fixup_record_ctor_field() { + check( + r#" +fn foo() { + R { f: } +} +"#, + expect![[r#" +fn foo () {R {f : __ra_fixup}} +"#]], + ) + } + + #[test] + fn no_fixup_record_ctor_field() { + check( + r#" +fn foo() { + R { f: a } +} +"#, + expect![[r#" +fn foo () {R {f : a}} +"#]], + ) + } + + #[test] + fn fixup_arg_list() { + check( + r#" +fn foo() { + foo(a +} +"#, + expect![[r#" +fn foo () { foo ( a ) } +"#]], + ); + check( + r#" +fn foo() { + bar.foo(a +} +"#, + expect![[r#" +fn foo () { bar . foo ( a ) } +"#]], + ); + } + + #[test] + fn fixup_closure() { + check( + r#" +fn foo() { + || +} +"#, + expect![[r#" +fn foo () {|| __ra_fixup} +"#]], + ); + } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs index 097e760c70ab0..cc02332207d6c 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/hygiene.rs @@ -4,7 +4,7 @@ //! Expansion, and Definition Contexts,” *Journal of Functional Programming* 22, no. 2 //! (March 1, 2012): 181–216, . //! -//! Also see https://rustc-dev-guide.rust-lang.org/macro-expansion.html#hygiene-and-hierarchies +//! Also see //! //! # The Expansion Order Hierarchy //! diff --git a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs similarity index 99% rename from src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs rename to src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs index f4564c94bb594..35fd85bf45182 100644 --- a/src/tools/rust-analyzer/crates/hir-def/src/attr/builtin.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/inert_attr_macro.rs @@ -36,11 +36,6 @@ pub fn find_builtin_attr_idx(name: &str) -> Option { .copied() } -// impl AttributeTemplate { -// const DEFAULT: AttributeTemplate = -// AttributeTemplate { word: false, list: None, name_value_str: None }; -// } - /// A convenience macro for constructing attribute templates. /// E.g., `template!(Word, List: "description")` means that the attribute /// supports forms `#[attr]` and `#[attr(description)]`. @@ -628,6 +623,10 @@ pub const INERT_ATTRIBUTES: &[BuiltinAttribute] = &[ rustc_safe_intrinsic, Normal, template!(Word), WarnFollowing, "the `#[rustc_safe_intrinsic]` attribute is used internally to mark intrinsics as safe" ), + rustc_attr!( + rustc_deprecated_safe_2024, Normal, template!(Word), WarnFollowing, + "the `#[rustc_safe_intrinsic]` marks functions as unsafe in Rust 2024", + ), // ========================================================================== // Internal attributes, Testing: diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs index 83e92565f4d8f..a7150cf308742 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/lib.rs @@ -16,6 +16,7 @@ pub mod declarative; pub mod eager; pub mod files; pub mod hygiene; +pub mod inert_attr_macro; pub mod mod_path; pub mod name; pub mod proc_macro; @@ -30,7 +31,7 @@ use triomphe::Arc; use std::{fmt, hash::Hash}; -use base_db::{salsa::impl_intern_value_trivial, CrateId, FileId}; +use base_db::{salsa::InternValueTrivial, CrateId, FileId}; use either::Either; use span::{ Edition, ErasedFileAstId, FileAstId, FileRange, HirFileIdRepr, Span, SpanAnchor, @@ -46,7 +47,7 @@ use crate::{ builtin_attr_macro::BuiltinAttrExpander, builtin_derive_macro::BuiltinDeriveExpander, builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, - db::{ExpandDatabase, TokenExpander}, + db::ExpandDatabase, mod_path::ModPath, proc_macro::{CustomProcMacroExpander, ProcMacroKind}, span_map::{ExpansionSpanMap, SpanMap}, @@ -172,7 +173,7 @@ pub struct MacroCallLoc { pub kind: MacroCallKind, pub ctxt: SyntaxContextId, } -impl_intern_value_trivial!(MacroCallLoc); +impl InternValueTrivial for MacroCallLoc {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct MacroDefId { @@ -186,11 +187,11 @@ pub struct MacroDefId { #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum MacroDefKind { Declarative(AstId), - BuiltIn(BuiltinFnLikeExpander, AstId), - BuiltInAttr(BuiltinAttrExpander, AstId), - BuiltInDerive(BuiltinDeriveExpander, AstId), - BuiltInEager(EagerExpander, AstId), - ProcMacro(CustomProcMacroExpander, ProcMacroKind, AstId), + BuiltIn(AstId, BuiltinFnLikeExpander), + BuiltInAttr(AstId, BuiltinAttrExpander), + BuiltInDerive(AstId, BuiltinDeriveExpander), + BuiltInEager(AstId, EagerExpander), + ProcMacro(AstId, CustomProcMacroExpander, ProcMacroKind), } #[derive(Debug, Clone, PartialEq, Eq, Hash)] @@ -252,9 +253,6 @@ pub trait HirFileIdExt { /// If this is a macro call, returns the syntax node of the very first macro call this file resides in. fn original_call_node(self, db: &dyn ExpandDatabase) -> Option>; - /// Return expansion information if it is a macro-expansion file - fn expansion_info(self, db: &dyn ExpandDatabase) -> Option; - fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option>; } @@ -308,11 +306,6 @@ impl HirFileIdExt for HirFileId { } } - /// Return expansion information if it is a macro-expansion file - fn expansion_info(self, db: &dyn ExpandDatabase) -> Option { - Some(ExpansionInfo::new(db, self.macro_file()?)) - } - fn as_builtin_derive_attr_node(&self, db: &dyn ExpandDatabase) -> Option> { let macro_file = self.macro_file()?; let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); @@ -379,7 +372,7 @@ impl MacroFileIdExt for MacroFileId { fn is_custom_derive(&self, db: &dyn ExpandDatabase) -> bool { matches!( db.lookup_intern_macro_call(self.macro_call_id).def.kind, - MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) ) } @@ -416,8 +409,10 @@ impl MacroFileIdExt for MacroFileId { } fn is_attr_macro(&self, db: &dyn ExpandDatabase) -> bool { - let loc = db.lookup_intern_macro_call(self.macro_call_id); - matches!(loc.kind, MacroCallKind::Attr { .. }) + matches!( + db.lookup_intern_macro_call(self.macro_call_id).def.kind, + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) + ) } fn is_derive_attr_pseudo_expansion(&self, db: &dyn ExpandDatabase) -> bool { @@ -440,13 +435,13 @@ impl MacroDefId { pub fn definition_range(&self, db: &dyn ExpandDatabase) -> InFile { match self.kind { MacroDefKind::Declarative(id) - | MacroDefKind::BuiltIn(_, id) - | MacroDefKind::BuiltInAttr(_, id) - | MacroDefKind::BuiltInDerive(_, id) - | MacroDefKind::BuiltInEager(_, id) => { + | MacroDefKind::BuiltIn(id, _) + | MacroDefKind::BuiltInAttr(id, _) + | MacroDefKind::BuiltInDerive(id, _) + | MacroDefKind::BuiltInEager(id, _) => { id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) } - MacroDefKind::ProcMacro(_, _, id) => { + MacroDefKind::ProcMacro(id, _, _) => { id.with_value(db.ast_id_map(id.file_id).get(id.value).text_range()) } } @@ -454,12 +449,12 @@ impl MacroDefId { pub fn ast_id(&self) -> Either, AstId> { match self.kind { - MacroDefKind::ProcMacro(.., id) => Either::Right(id), + MacroDefKind::ProcMacro(id, ..) => Either::Right(id), MacroDefKind::Declarative(id) - | MacroDefKind::BuiltIn(_, id) - | MacroDefKind::BuiltInAttr(_, id) - | MacroDefKind::BuiltInDerive(_, id) - | MacroDefKind::BuiltInEager(_, id) => Either::Left(id), + | MacroDefKind::BuiltIn(id, _) + | MacroDefKind::BuiltInAttr(id, _) + | MacroDefKind::BuiltInDerive(id, _) + | MacroDefKind::BuiltInEager(id, _) => Either::Left(id), } } @@ -470,7 +465,7 @@ impl MacroDefId { pub fn is_attribute(&self) -> bool { matches!( self.kind, - MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, ProcMacroKind::Attr, _) + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) ) } @@ -478,7 +473,7 @@ impl MacroDefId { matches!( self.kind, MacroDefKind::BuiltInDerive(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::CustomDerive, _) + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::CustomDerive) ) } @@ -486,26 +481,26 @@ impl MacroDefId { matches!( self.kind, MacroDefKind::BuiltIn(..) - | MacroDefKind::ProcMacro(_, ProcMacroKind::Bang, _) + | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Bang) | MacroDefKind::BuiltInEager(..) | MacroDefKind::Declarative(..) ) } pub fn is_attribute_derive(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInAttr(expander, ..) if expander.is_derive()) + matches!(self.kind, MacroDefKind::BuiltInAttr(_, expander) if expander.is_derive()) } pub fn is_include(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include()) } pub fn is_include_like(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_include_like()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_include_like()) } pub fn is_env_or_option_env(&self) -> bool { - matches!(self.kind, MacroDefKind::BuiltInEager(expander, ..) if expander.is_env_or_option_env()) + matches!(self.kind, MacroDefKind::BuiltInEager(_, expander) if expander.is_env_or_option_env()) } } @@ -702,16 +697,12 @@ impl MacroCallKind { // simpler function calls if the map is only used once #[derive(Clone, Debug, PartialEq, Eq)] pub struct ExpansionInfo { - pub expanded: InMacroFile, + expanded: InMacroFile, /// The argument TokenTree or item for attributes arg: InFile>, - /// The `macro_rules!` or attribute input. - attr_input_or_mac_def: Option>, - - macro_def: TokenExpander, - macro_arg: Arc, - pub exp_map: Arc, + exp_map: Arc, arg_map: SpanMap, + loc: MacroCallLoc, } impl ExpansionInfo { @@ -719,14 +710,21 @@ impl ExpansionInfo { self.expanded.clone() } - pub fn call_node(&self) -> Option> { - Some(self.arg.with_value(self.arg.value.as_ref()?.parent()?)) + pub fn arg(&self) -> InFile> { + self.arg.as_ref().map(|it| it.as_ref()) } pub fn call_file(&self) -> HirFileId { self.arg.file_id } + pub fn is_attr(&self) -> bool { + matches!( + self.loc.def.kind, + MacroDefKind::BuiltInAttr(..) | MacroDefKind::ProcMacro(_, _, ProcMacroKind::Attr) + ) + } + /// Maps the passed in file range down into a macro expansion if it is the input to a macro call. /// /// Note this does a linear search through the entire backing vector of the spanmap. @@ -811,49 +809,16 @@ impl ExpansionInfo { } pub fn new(db: &dyn ExpandDatabase, macro_file: MacroFileId) -> ExpansionInfo { - let loc: MacroCallLoc = db.lookup_intern_macro_call(macro_file.macro_call_id); + let _p = tracing::info_span!("ExpansionInfo::new").entered(); + let loc = db.lookup_intern_macro_call(macro_file.macro_call_id); let arg_tt = loc.kind.arg(db); let arg_map = db.span_map(arg_tt.file_id); - let macro_def = db.macro_expander(loc.def); let (parse, exp_map) = db.parse_macro_expansion(macro_file).value; let expanded = InMacroFile { file_id: macro_file, value: parse.syntax_node() }; - let (macro_arg, _, _) = - db.macro_arg_considering_derives(macro_file.macro_call_id, &loc.kind); - - let def = loc.def.ast_id().left().and_then(|id| { - let def_tt = match id.to_node(db) { - ast::Macro::MacroRules(mac) => mac.token_tree()?, - ast::Macro::MacroDef(_) if matches!(macro_def, TokenExpander::BuiltInAttr(_)) => { - return None - } - ast::Macro::MacroDef(mac) => mac.body()?, - }; - Some(InFile::new(id.file_id, def_tt)) - }); - let attr_input_or_mac_def = def.or_else(|| match loc.kind { - MacroCallKind::Attr { ast_id, invoc_attr_index, .. } => { - // FIXME: handle `cfg_attr` - let tt = collect_attrs(&ast_id.to_node(db)) - .nth(invoc_attr_index.ast_index()) - .and_then(|x| Either::left(x.1))? - .token_tree()?; - Some(InFile::new(ast_id.file_id, tt)) - } - _ => None, - }); - - ExpansionInfo { - expanded, - arg: arg_tt, - attr_input_or_mac_def, - macro_arg, - macro_def, - exp_map, - arg_map, - } + ExpansionInfo { expanded, loc, arg: arg_tt, exp_map, arg_map } } } diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs index 46f8c2b9d8c4c..12fdf88a2a873 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs @@ -44,6 +44,10 @@ pub enum PathKind { DollarCrate(CrateId), } +impl PathKind { + pub const SELF: PathKind = PathKind::Super(0); +} + impl ModPath { pub fn from_src( db: &dyn ExpandDatabase, @@ -96,7 +100,7 @@ impl ModPath { pub fn textual_len(&self) -> usize { let base = match self.kind { PathKind::Plain => 0, - PathKind::Super(0) => "self".len(), + PathKind::SELF => "self".len(), PathKind::Super(i) => "super".len() * i as usize, PathKind::Crate => "crate".len(), PathKind::Abs => 0, @@ -113,7 +117,7 @@ impl ModPath { } pub fn is_self(&self) -> bool { - self.kind == PathKind::Super(0) && self.segments.is_empty() + self.kind == PathKind::SELF && self.segments.is_empty() } #[allow(non_snake_case)] @@ -193,7 +197,7 @@ fn display_fmt_path( }; match path.kind { PathKind::Plain => {} - PathKind::Super(0) => add_segment("self")?, + PathKind::SELF => add_segment("self")?, PathKind::Super(n) => { for _ in 0..n { add_segment("super")?; @@ -316,7 +320,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: &[tt::TokenTree]) -> Option { resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate) } - tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::Super(0), + tt::Leaf::Ident(tt::Ident { text, .. }) if text == "self" => PathKind::SELF, tt::Leaf::Ident(tt::Ident { text, .. }) if text == "super" => { let mut deg = 1; while let Some(tt::Leaf::Ident(tt::Ident { text, .. })) = leaves.next() { diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs index a31a111c91174..8f1e32321e147 100644 --- a/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs +++ b/src/tools/rust-analyzer/crates/hir-expand/src/quote.rs @@ -231,7 +231,7 @@ mod tests { const DUMMY: tt::Span = tt::Span { range: TextRange::empty(TextSize::new(0)), - anchor: SpanAnchor { file_id: FileId::BOGUS, ast_id: ROOT_ERASED_FILE_AST_ID }, + anchor: SpanAnchor { file_id: FileId::from_raw(0xe4e4e), ast_id: ROOT_ERASED_FILE_AST_ID }, ctx: SyntaxContextId::ROOT, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs index e2446c34254a4..b706cef0b3a28 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs @@ -143,7 +143,7 @@ pub(crate) fn deref_by_trait( table @ &mut InferenceTable { db, .. }: &mut InferenceTable<'_>, ty: Ty, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "deref_by_trait").entered(); + let _p = tracing::info_span!("deref_by_trait").entered(); if table.resolve_ty_shallow(&ty).inference_var(Interner).is_some() { // don't try to deref unknown variables return None; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs index 41acd3555eb93..52411f94ad03a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/builder.rs @@ -14,10 +14,10 @@ use hir_def::{ use smallvec::SmallVec; use crate::{ - consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, - infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, - Binders, BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, - Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind, + consteval::unknown_const_as_generic, db::HirDatabase, error_lifetime, generics::generics, + infer::unify::InferenceTable, primitive, to_assoc_type_id, to_chalk_trait_id, Binders, + BoundVar, CallableSig, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, + TraitRef, Ty, TyDefId, TyExt, TyKind, }; #[derive(Debug, Clone, PartialEq, Eq)] @@ -246,6 +246,7 @@ impl TyBuilder<()> { /// - yield type of coroutine ([`Coroutine::Yield`](std::ops::Coroutine::Yield)) /// - return type of coroutine ([`Coroutine::Return`](std::ops::Coroutine::Return)) /// - generic parameters in scope on `parent` + /// /// in this order. /// /// This method prepopulates the builder with placeholder substitution of `parent`, so you diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs index 84ac8740ecd54..debae1fe12352 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs @@ -20,13 +20,14 @@ use hir_expand::name::name; use crate::{ db::{HirDatabase, InternedCoroutine}, display::HirDisplay, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders, - make_single_type_binders, + from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + generics::generics, + make_binders, make_single_type_binders, mapping::{from_chalk, ToChalk, TypeAliasAsValue}, method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, to_assoc_type_id, to_chalk_trait_id, traits::ChalkContext, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause, @@ -603,7 +604,6 @@ pub(crate) fn associated_ty_data_query( // Lower bounds -- we could/should maybe move this to a separate query in `lower` let type_alias_data = db.type_alias_data(type_alias); let generic_params = generics(db.upcast(), type_alias.into()); - // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); let ctx = crate::TyLoweringContext::new(db, &resolver, type_alias.into()) .with_type_param_mode(crate::lower::ParamLoweringMode::Variable); @@ -806,7 +806,7 @@ pub(crate) fn impl_datum_query( krate: CrateId, impl_id: ImplId, ) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "impl_datum_query").entered(); + let _p = tracing::info_span!("impl_datum_query").entered(); debug!("impl_datum {:?}", impl_id); let impl_: hir_def::ImplId = from_chalk(db, impl_id); impl_def_datum(db, krate, impl_id, impl_) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs index d99ef6679e51f..4279c756519c0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_ext.rs @@ -12,12 +12,10 @@ use hir_def::{ }; use crate::{ - db::HirDatabase, - from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx, - to_chalk_trait_id, - utils::{generics, ClosureSubst}, - AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, - ClosureId, DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, + db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, + from_placeholder_idx, generics::generics, to_chalk_trait_id, utils::ClosureSubst, AdtId, + AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, ClosureId, + DynTy, FnPointer, ImplTraitId, InEnvironment, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause, Substitution, TraitRef, Ty, TyBuilder, TyKind, TypeFlags, WhereClause, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs index f09277a92e669..8b6cde975f63e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs @@ -15,10 +15,9 @@ use stdx::never; use triomphe::Arc; use crate::{ - db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode, - mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData, - ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, - TyBuilder, + db::HirDatabase, generics::Generics, infer::InferenceContext, lower::ParamLoweringMode, + mir::monomorphize_mir_body_bad, to_placeholder_idx, Const, ConstData, ConstScalar, ConstValue, + GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty, TyBuilder, }; use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError}; @@ -72,12 +71,12 @@ impl From for ConstEvalError { } } -pub(crate) fn path_to_const( +pub(crate) fn path_to_const<'g>( db: &dyn HirDatabase, resolver: &Resolver, path: &Path, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, expected_ty: Ty, ) -> Option { @@ -90,7 +89,7 @@ pub(crate) fn path_to_const( } ParamLoweringMode::Variable => { let args = args(); - match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) { + match args.and_then(|args| args.type_or_const_param_idx(p.into())) { Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)), None => { never!( diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs index d1ffd5046c3f3..1b4584a18d76d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs @@ -73,7 +73,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { Ok(t) => t, Err(e) => { let err = pretty_print_err(e, db); - panic!("Error in evaluating goal: {}", err); + panic!("Error in evaluating goal: {err}"); } }; match &r.data(Interner).value { @@ -81,7 +81,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { ConstScalar::Bytes(b, mm) => { check(b, mm); } - x => panic!("Expected number but found {:?}", x), + x => panic!("Expected number but found {x:?}"), }, _ => panic!("result of const eval wasn't a concrete const"), } @@ -89,7 +89,7 @@ fn check_answer(ra_fixture: &str, check: impl FnOnce(&[u8], &MemoryMap)) { fn pretty_print_err(e: ConstEvalError, db: TestDB) -> String { let mut err = String::new(); - let span_formatter = |file, range| format!("{:?} {:?}", file, range); + let span_formatter = |file, range| format!("{file:?} {range:?}"); match e { ConstEvalError::MirLowerError(e) => e.pretty_print(&mut err, &db, span_formatter), ConstEvalError::MirEvalError(e) => e.pretty_print(&mut err, &db, span_formatter), diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs index 90bf46b5056cc..e951048021de7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/db.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/db.rs @@ -5,7 +5,7 @@ use std::sync; use base_db::{ impl_intern_key, - salsa::{self, impl_intern_value_trivial}, + salsa::{self, InternValueTrivial}, CrateId, Upcast, }; use hir_def::{ @@ -21,11 +21,12 @@ use crate::{ chalk_db, consteval::ConstEvalError, layout::{Layout, LayoutError}, + lower::{GenericDefaults, GenericPredicates}, method_resolution::{InherentImpls, TraitImpls, TyFingerprint}, mir::{BorrowckResult, MirBody, MirLowerError}, - Binders, CallableDefId, ClosureId, Const, FnDefId, GenericArg, ImplTraitId, ImplTraits, - InferenceResult, Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, - TraitRef, Ty, TyDefId, ValueTyDefId, + Binders, CallableDefId, ClosureId, Const, FnDefId, ImplTraitId, ImplTraits, InferenceResult, + Interner, PolyFnSig, QuantifiedWhereClause, Substitution, TraitEnvironment, TraitRef, Ty, + TyDefId, ValueTyDefId, }; use hir_expand::name::Name; @@ -147,7 +148,7 @@ pub trait HirDatabase: DefDatabase + Upcast { ) -> Arc<[Binders]>; #[salsa::invoke(crate::lower::generic_predicates_query)] - fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders]>; + fn generic_predicates(&self, def: GenericDefId) -> GenericPredicates; #[salsa::invoke(crate::lower::trait_environment_for_body_query)] #[salsa::transparent] @@ -158,7 +159,7 @@ pub trait HirDatabase: DefDatabase + Upcast { #[salsa::invoke(crate::lower::generic_defaults_query)] #[salsa::cycle(crate::lower::generic_defaults_recover)] - fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders]>; + fn generic_defaults(&self, def: GenericDefId) -> GenericDefaults; #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)] fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc; @@ -298,7 +299,8 @@ impl_intern_key!(InternedClosureId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedClosure(pub DefWithBodyId, pub ExprId); -impl_intern_value_trivial!(InternedClosure); + +impl InternValueTrivial for InternedClosure {} #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedCoroutineId(salsa::InternId); @@ -306,7 +308,7 @@ impl_intern_key!(InternedCoroutineId); #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub struct InternedCoroutine(pub DefWithBodyId, pub ExprId); -impl_intern_value_trivial!(InternedCoroutine); +impl InternValueTrivial for InternedCoroutine {} /// This exists just for Chalk, because Chalk just has a single `FnDefId` where /// we have different IDs for struct and enum variant constructors. diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs index ecbb1d4c60e5f..15ecf9aafcfc9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs @@ -43,7 +43,7 @@ mod allow { } pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec { - let _p = tracing::span!(tracing::Level::INFO, "incorrect_case").entered(); + let _p = tracing::info_span!("incorrect_case").entered(); let mut validator = DeclValidator::new(db); validator.validate_item(owner); validator.sink diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs index a5a42c52af04a..ce3fa53f7ad62 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs @@ -65,8 +65,7 @@ impl BodyValidationDiagnostic { owner: DefWithBodyId, validate_lints: bool, ) -> Vec { - let _p = - tracing::span!(tracing::Level::INFO, "BodyValidationDiagnostic::collect").entered(); + let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered(); let infer = db.infer(owner); let body = db.body(owner); let mut validator = diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs index 081b4d83a86fd..22aa5c69bb03d 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/unsafe_check.rs @@ -13,7 +13,7 @@ use crate::{ }; pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec { - let _p = tracing::span!(tracing::Level::INFO, "missing_unsafe").entered(); + let _p = tracing::info_span!("missing_unsafe").entered(); let mut res = Vec::new(); let is_unsafe = match def { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs index 241690d00896d..66b5398b88ebb 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs @@ -4,7 +4,7 @@ use std::{ fmt::{self, Debug}, - mem::size_of, + mem::{self, size_of}, }; use base_db::CrateId; @@ -36,12 +36,13 @@ use crate::{ consteval::try_const_usize, db::{HirDatabase, InternedClosure}, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, + generics::generics, layout::Layout, lt_from_placeholder_idx, mapping::from_chalk, mir::pad16, primitive, to_assoc_type_id, - utils::{self, detect_variant_from_bytes, generics, ClosureSubst}, + utils::{self, detect_variant_from_bytes, ClosureSubst}, AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, ConcreteConst, Const, ConstScalar, ConstValue, DomainGoal, FnAbi, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, @@ -74,6 +75,8 @@ pub struct HirFormatter<'a> { /// When rendering something that has a concept of "children" (like fields in a struct), this limits /// how many should be rendered. pub entity_limit: Option, + /// When rendering functions, whether to show the constraint from the container + show_container_bounds: bool, omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, @@ -101,6 +104,7 @@ pub trait HirDisplay { omit_verbose_types: bool, display_target: DisplayTarget, closure_style: ClosureStyle, + show_container_bounds: bool, ) -> HirDisplayWrapper<'a, Self> where Self: Sized, @@ -117,6 +121,7 @@ pub trait HirDisplay { omit_verbose_types, display_target, closure_style, + show_container_bounds, } } @@ -134,6 +139,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -155,6 +161,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -176,6 +183,7 @@ pub trait HirDisplay { omit_verbose_types: true, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Diagnostics, + show_container_bounds: false, } } @@ -198,6 +206,7 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::SourceCode { module_id, allow_opaque }, + show_container_bounds: false, }) { Ok(()) => {} Err(HirDisplayError::FmtError) => panic!("Writing to String can't fail!"), @@ -219,6 +228,29 @@ pub trait HirDisplay { omit_verbose_types: false, closure_style: ClosureStyle::ImplFn, display_target: DisplayTarget::Test, + show_container_bounds: false, + } + } + + /// Returns a String representation of `self` that shows the constraint from + /// the container for functions + fn display_with_container_bounds<'a>( + &'a self, + db: &'a dyn HirDatabase, + show_container_bounds: bool, + ) -> HirDisplayWrapper<'a, Self> + where + Self: Sized, + { + HirDisplayWrapper { + db, + t: self, + max_size: None, + limited_size: None, + omit_verbose_types: false, + closure_style: ClosureStyle::ImplFn, + display_target: DisplayTarget::Diagnostics, + show_container_bounds, } } } @@ -277,6 +309,10 @@ impl HirFormatter<'_> { pub fn omit_verbose_types(&self) -> bool { self.omit_verbose_types } + + pub fn show_container_bounds(&self) -> bool { + self.show_container_bounds + } } #[derive(Clone, Copy)] @@ -336,6 +372,7 @@ pub struct HirDisplayWrapper<'a, T> { omit_verbose_types: bool, closure_style: ClosureStyle, display_target: DisplayTarget, + show_container_bounds: bool, } #[derive(Debug, PartialEq, Eq, Clone, Copy)] @@ -365,6 +402,7 @@ impl HirDisplayWrapper<'_, T> { omit_verbose_types: self.omit_verbose_types, display_target: self.display_target, closure_style: self.closure_style, + show_container_bounds: self.show_container_bounds, }) } @@ -423,7 +461,7 @@ impl HirDisplay for ProjectionTy { let proj_params_count = self.substitution.len(Interner) - trait_ref.substitution.len(Interner); let proj_params = &self.substitution.as_slice(Interner)[..proj_params_count]; - hir_fmt_generics(f, proj_params, None) + hir_fmt_generics(f, proj_params, None, None) } } @@ -456,7 +494,7 @@ impl HirDisplay for Const { ConstValue::Placeholder(idx) => { let id = from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?; Ok(()) } @@ -468,6 +506,7 @@ impl HirDisplay for Const { f, parameters.as_slice(Interner), c.generic_def(f.db.upcast()), + None, )?; Ok(()) } @@ -670,7 +709,7 @@ fn render_const_scalar( TyKind::FnDef(..) => ty.hir_fmt(f), TyKind::Function(_) | TyKind::Raw(_, _) => { let it = u128::from_le_bytes(pad16(b, false)); - write!(f, "{:#X} as ", it)?; + write!(f, "{it:#X} as ")?; ty.hir_fmt(f) } TyKind::Array(ty, len) => { @@ -950,7 +989,7 @@ impl HirDisplay for Ty { if parameters.len(Interner) > 0 { let generics = generics(db.upcast(), def.into()); - let (parent_len, self_, type_, const_, impl_, lifetime) = + let (parent_len, self_param, type_, const_, impl_, lifetime) = generics.provenance_split(); let parameters = parameters.as_slice(Interner); // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? @@ -958,7 +997,7 @@ impl HirDisplay for Ty { // `parameters` are in the order of fn's params (including impl traits), fn's lifetimes // parent's params (those from enclosing impl or trait, if any). let (fn_params, other) = - parameters.split_at(self_ + type_ + const_ + lifetime); + parameters.split_at(self_param as usize + type_ + const_ + lifetime); let (_impl, parent_params) = other.split_at(impl_); debug_assert_eq!(parent_params.len(), parent_len); @@ -967,11 +1006,11 @@ impl HirDisplay for Ty { let fn_params = generic_args_sans_defaults(f, Some(def.into()), fn_params); write!(f, "<")?; - hir_fmt_generic_arguments(f, parent_params)?; + hir_fmt_generic_arguments(f, parent_params, None)?; if !parent_params.is_empty() && !fn_params.is_empty() { write!(f, ", ")?; } - hir_fmt_generic_arguments(f, fn_params)?; + hir_fmt_generic_arguments(f, fn_params, None)?; write!(f, ">")?; } } @@ -1016,7 +1055,7 @@ impl HirDisplay for Ty { let generic_def = self.as_generic_def(db); - hir_fmt_generics(f, parameters.as_slice(Interner), generic_def)?; + hir_fmt_generics(f, parameters.as_slice(Interner), generic_def, None)?; } TyKind::AssociatedType(assoc_type_id, parameters) => { let type_alias = from_assoc_type_id(*assoc_type_id); @@ -1039,7 +1078,7 @@ impl HirDisplay for Ty { f.end_location_link(); // Note that the generic args for the associated type come before those for the // trait (including the self type). - hir_fmt_generics(f, parameters.as_slice(Interner), None) + hir_fmt_generics(f, parameters.as_slice(Interner), None, None) } else { let projection_ty = ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), @@ -1141,7 +1180,7 @@ impl HirDisplay for Ty { } ClosureStyle::ClosureWithSubst => { write!(f, "{{closure#{:?}}}", id.0.as_u32())?; - return hir_fmt_generics(f, substs.as_slice(Interner), None); + return hir_fmt_generics(f, substs.as_slice(Interner), None, None); } _ => (), } @@ -1177,7 +1216,7 @@ impl HirDisplay for Ty { TyKind::Placeholder(idx) => { let id = from_placeholder_idx(db, *idx); let generics = generics(db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; match param_data { TypeOrConstParamData::TypeParamData(p) => match p.provenance { TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => { @@ -1329,6 +1368,7 @@ fn hir_fmt_generics( f: &mut HirFormatter<'_>, parameters: &[GenericArg], generic_def: Option, + self_: Option<&Ty>, ) -> Result<(), HirDisplayError> { if parameters.is_empty() { return Ok(()); @@ -1348,7 +1388,7 @@ fn hir_fmt_generics( }); if !parameters_to_write.is_empty() && !only_err_lifetimes { write!(f, "<")?; - hir_fmt_generic_arguments(f, parameters_to_write)?; + hir_fmt_generic_arguments(f, parameters_to_write, self_)?; write!(f, ">")?; } @@ -1411,6 +1451,7 @@ fn generic_args_sans_defaults<'ga>( fn hir_fmt_generic_arguments( f: &mut HirFormatter<'_>, parameters: &[GenericArg], + self_: Option<&Ty>, ) -> Result<(), HirDisplayError> { let mut first = true; let lifetime_offset = parameters.iter().position(|arg| arg.lifetime(Interner).is_some()); @@ -1432,11 +1473,13 @@ fn hir_fmt_generic_arguments( continue; } - if !first { + if !mem::take(&mut first) { write!(f, ", ")?; } - first = false; - generic_arg.hir_fmt(f)?; + match self_ { + self_ @ Some(_) if generic_arg.ty(Interner) == self_ => write!(f, "Self")?, + _ => generic_arg.hir_fmt(f)?, + } } Ok(()) } @@ -1559,12 +1602,16 @@ fn write_bounds_like_dyn_trait( write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); if is_fn_trait { - if let [_self, params @ ..] = trait_ref.substitution.as_slice(Interner) { + if let [self_, params @ ..] = trait_ref.substitution.as_slice(Interner) { if let Some(args) = params.first().and_then(|it| it.assert_ty_ref(Interner).as_tuple()) { write!(f, "(")?; - hir_fmt_generic_arguments(f, args.as_slice(Interner))?; + hir_fmt_generic_arguments( + f, + args.as_slice(Interner), + self_.ty(Interner), + )?; write!(f, ")")?; } } @@ -1574,10 +1621,10 @@ fn write_bounds_like_dyn_trait( Some(trait_.into()), trait_ref.substitution.as_slice(Interner), ); - if let [_self, params @ ..] = params { + if let [self_, params @ ..] = params { if !params.is_empty() { write!(f, "<")?; - hir_fmt_generic_arguments(f, params)?; + hir_fmt_generic_arguments(f, params, self_.ty(Interner))?; // there might be assoc type bindings, so we leave the angle brackets open angle_open = true; } @@ -1635,6 +1682,7 @@ fn write_bounds_like_dyn_trait( hir_fmt_generic_arguments( f, &proj.substitution.as_slice(Interner)[..proj_arg_count], + None, )?; write!(f, ">")?; } @@ -1691,7 +1739,8 @@ fn fmt_trait_ref( f.start_location_link(trait_.into()); write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast()))?; f.end_location_link(); - hir_fmt_generics(f, &tr.substitution.as_slice(Interner)[1..], None) + let substs = tr.substitution.as_slice(Interner); + hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner)) } impl HirDisplay for TraitRef { @@ -1749,7 +1798,7 @@ impl HirDisplay for LifetimeData { LifetimeData::Placeholder(idx) => { let id = lt_from_placeholder_idx(f.db, *idx); let generics = generics(f.db.upcast(), id.parent); - let param_data = &generics.params[id.local_id]; + let param_data = &generics[id.local_id]; write!(f, "{}", param_data.name.display(f.db.upcast()))?; Ok(()) } @@ -1943,7 +1992,7 @@ impl HirDisplay for Path { (_, PathKind::Plain) => {} (_, PathKind::Abs) => {} (_, PathKind::Crate) => write!(f, "crate")?, - (_, PathKind::Super(0)) => write!(f, "self")?, + (_, &PathKind::SELF) => write!(f, "self")?, (_, PathKind::Super(n)) => { for i in 0..*n { if i > 0 { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs new file mode 100644 index 0000000000000..ea10e6881e7fb --- /dev/null +++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs @@ -0,0 +1,263 @@ +//! Utilities for working with generics. +//! +//! The layout for generics as expected by chalk are as follows: +//! - Optional Self parameter +//! - Type or Const parameters +//! - Lifetime parameters +//! - Parent parameters +//! +//! where parent follows the same scheme. +use std::ops; + +use chalk_ir::{cast::Cast as _, BoundVar, DebruijnIndex}; +use hir_def::{ + db::DefDatabase, + generics::{ + GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, + TypeParamProvenance, + }, + ConstParamId, GenericDefId, GenericParamId, ItemContainerId, LifetimeParamId, + LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId, +}; +use intern::Interned; + +use crate::{db::HirDatabase, lt_to_placeholder_idx, to_placeholder_idx, Interner, Substitution}; + +pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { + let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); + Generics { def, params: db.generic_params(def), parent_generics } +} +#[derive(Clone, Debug)] +pub(crate) struct Generics { + def: GenericDefId, + params: Interned, + parent_generics: Option>, +} + +impl ops::Index for Generics +where + GenericParams: ops::Index, +{ + type Output = >::Output; + fn index(&self, index: T) -> &Self::Output { + &self.params[index] + } +} + +impl Generics { + pub(crate) fn def(&self) -> GenericDefId { + self.def + } + + pub(crate) fn iter_id(&self) -> impl Iterator + '_ { + self.iter_self_id().chain(self.iter_parent_id()) + } + + pub(crate) fn iter_self_id(&self) -> impl Iterator + '_ { + self.iter_self().map(|(id, _)| id) + } + + fn iter_parent_id(&self) -> impl Iterator + '_ { + self.iter_parent().map(|(id, _)| id) + } + + pub(crate) fn iter_self_type_or_consts( + &self, + ) -> impl DoubleEndedIterator { + self.params.iter_type_or_consts() + } + + /// Iterate over the params followed by the parent params. + pub(crate) fn iter( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.iter_self().chain(self.iter_parent()) + } + + /// Iterate over the params without parent params. + pub(crate) fn iter_self( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.params + .iter_type_or_consts() + .map(from_toc_id(self)) + .chain(self.params.iter_lt().map(from_lt_id(self))) + } + + /// Iterator over types and const params of parent. + fn iter_parent( + &self, + ) -> impl DoubleEndedIterator)> + '_ { + self.parent_generics().into_iter().flat_map(|it| { + let lt_iter = it.params.iter_lt().map(from_lt_id(it)); + it.params.iter_type_or_consts().map(from_toc_id(it)).chain(lt_iter) + }) + } + + /// Returns total number of generic parameters in scope, including those from parent. + pub(crate) fn len(&self) -> usize { + let parent = self.parent_generics().map_or(0, Generics::len); + let child = self.params.len(); + parent + child + } + + /// Returns numbers of generic parameters excluding those from parent. + pub(crate) fn len_self(&self) -> usize { + self.params.len() + } + + /// (parent total, self param, type params, const params, impl trait list, lifetimes) + pub(crate) fn provenance_split(&self) -> (usize, bool, usize, usize, usize, usize) { + let mut self_param = false; + let mut type_params = 0; + let mut impl_trait_params = 0; + let mut const_params = 0; + self.params.iter_type_or_consts().for_each(|(_, data)| match data { + TypeOrConstParamData::TypeParamData(p) => match p.provenance { + TypeParamProvenance::TypeParamList => type_params += 1, + TypeParamProvenance::TraitSelf => self_param |= true, + TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, + }, + TypeOrConstParamData::ConstParamData(_) => const_params += 1, + }); + + let lifetime_params = self.params.iter_lt().count(); + + let parent_len = self.parent_generics().map_or(0, Generics::len); + (parent_len, self_param, type_params, const_params, impl_trait_params, lifetime_params) + } + + pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { + self.find_type_or_const_param(param) + } + + fn find_type_or_const_param(&self, param: TypeOrConstParamId) -> Option { + if param.parent == self.def { + let idx = param.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.type_or_consts.len()); + Some(idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(param.parent)); + self.parent_generics() + .and_then(|g| g.find_type_or_const_param(param)) + // Remember that parent parameters come after parameters for self. + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option { + self.find_lifetime(lifetime) + } + + fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option { + if lifetime.parent == self.def { + let idx = lifetime.local_id.into_raw().into_u32() as usize; + debug_assert!(idx <= self.params.lifetimes.len()); + Some(self.params.type_or_consts.len() + idx) + } else { + debug_assert_eq!(self.parent_generics().map(|it| it.def), Some(lifetime.parent)); + self.parent_generics() + .and_then(|g| g.find_lifetime(lifetime)) + .map(|idx| self.len_self() + idx) + } + } + + pub(crate) fn parent_generics(&self) -> Option<&Generics> { + self.parent_generics.as_deref() + } + + pub(crate) fn parent_or_self(&self) -> &Generics { + self.parent_generics.as_deref().unwrap_or(self) + } + + /// Returns a Substitution that replaces each parameter by a bound variable. + pub(crate) fn bound_vars_subst( + &self, + db: &dyn HirDatabase, + debruijn: DebruijnIndex, + ) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().enumerate().map(|(idx, id)| match id { + GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::TypeParamId(_) => { + BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) + } + GenericParamId::LifetimeParamId(_) => { + BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) + } + }), + ) + } + + /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). + pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { + Substitution::from_iter( + Interner, + self.iter_id().map(|id| match id { + GenericParamId::TypeParamId(id) => { + to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) + } + GenericParamId::ConstParamId(id) => to_placeholder_idx(db, id.into()) + .to_const(Interner, db.const_param_ty(id)) + .cast(Interner), + GenericParamId::LifetimeParamId(id) => { + lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) + } + }), + ) + } +} + +fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { + let container = match def { + GenericDefId::FunctionId(it) => it.lookup(db).container, + GenericDefId::TypeAliasId(it) => it.lookup(db).container, + GenericDefId::ConstId(it) => it.lookup(db).container, + GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), + GenericDefId::AdtId(_) + | GenericDefId::TraitId(_) + | GenericDefId::ImplId(_) + | GenericDefId::TraitAliasId(_) => return None, + }; + + match container { + ItemContainerId::ImplId(it) => Some(it.into()), + ItemContainerId::TraitId(it) => Some(it.into()), + ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, + } +} + +fn from_toc_id<'a>( + it: &'a Generics, +) -> impl Fn( + (LocalTypeOrConstParamId, &'a TypeOrConstParamData), +) -> (GenericParamId, GenericParamDataRef<'a>) { + move |(local_id, p): (_, _)| { + let id = TypeOrConstParamId { parent: it.def, local_id }; + match p { + TypeOrConstParamData::TypeParamData(p) => ( + GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), + GenericParamDataRef::TypeParamData(p), + ), + TypeOrConstParamData::ConstParamData(p) => ( + GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), + GenericParamDataRef::ConstParamData(p), + ), + } + } +} + +fn from_lt_id<'a>( + it: &'a Generics, +) -> impl Fn((LocalLifetimeParamId, &'a LifetimeParamData)) -> (GenericParamId, GenericParamDataRef<'a>) +{ + move |(local_id, p): (_, _)| { + ( + GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), + GenericParamDataRef::LifetimeParamData(p), + ) + } +} diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs index 6f2f70dd40a78..96431ba4ce9a7 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs @@ -49,6 +49,7 @@ use hir_def::{ use hir_expand::name::{name, Name}; use indexmap::IndexSet; use la_arena::{ArenaMap, Entry}; +use once_cell::unsync::OnceCell; use rustc_hash::{FxHashMap, FxHashSet}; use stdx::{always, never}; use triomphe::Arc; @@ -56,14 +57,15 @@ use triomphe::Arc; use crate::{ db::HirDatabase, error_lifetime, fold_tys, + generics::Generics, infer::{coerce::CoerceMany, unify::InferenceTable}, lower::ImplTraitLoweringMode, to_assoc_type_id, traits::FnTrait, - utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, + utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder}, AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId, - ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution, - TraitEnvironment, Ty, TyBuilder, TyExt, + ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ParamLoweringMode, ProjectionTy, + Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, }; // This lint has a false positive here. See the link below for details. @@ -79,7 +81,7 @@ pub(crate) use closure::{CaptureKind, CapturedItem, CapturedItemWithoutTy}; /// The entry point of type inference. pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc { - let _p = tracing::span!(tracing::Level::INFO, "infer_query").entered(); + let _p = tracing::info_span!("infer_query").entered(); let resolver = def.resolver(db.upcast()); let body = db.body(def); let mut ctx = InferenceContext::new(db, def, &body, resolver); @@ -526,6 +528,7 @@ pub(crate) struct InferenceContext<'a> { pub(crate) owner: DefWithBodyId, pub(crate) body: &'a Body, pub(crate) resolver: Resolver, + generics: OnceCell>, table: unify::InferenceTable<'a>, /// The traits in scope, disregarding block modules. This is used for caching purposes. traits_in_scope: FxHashSet, @@ -611,6 +614,7 @@ impl<'a> InferenceContext<'a> { ) -> Self { let trait_env = db.trait_environment_for_body(owner); InferenceContext { + generics: OnceCell::new(), result: InferenceResult::default(), table: unify::InferenceTable::new(db, trait_env), tuple_field_accesses_rev: Default::default(), @@ -632,8 +636,14 @@ impl<'a> InferenceContext<'a> { } } - pub(crate) fn generics(&self) -> Option { - Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?)) + pub(crate) fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| { + self.resolver + .generic_def() + .map(|def| crate::generics::generics(self.db.upcast(), def)) + }) + .as_ref() } // FIXME: This function should be private in module. It is currently only used in the consteval, since we need @@ -781,7 +791,8 @@ impl<'a> InferenceContext<'a> { fn collect_fn(&mut self, func: FunctionId) { let data = self.db.function_data(func); - let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, func.into()) + let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder) .with_impl_trait_mode(ImplTraitLoweringMode::Param); let mut param_tys = data.params.iter().map(|type_ref| ctx.lower_ty(type_ref)).collect::>(); @@ -816,6 +827,7 @@ impl<'a> InferenceContext<'a> { let return_ty = &*data.ret_type; let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver, self.owner.into()) + .with_type_param_mode(ParamLoweringMode::Placeholder) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque); let return_ty = ctx.lower_ty(return_ty); let return_ty = self.insert_type_vars(return_ty); @@ -1263,7 +1275,7 @@ impl<'a> InferenceContext<'a> { forbid_unresolved_segments((ty, Some(var.into())), unresolved) } TypeNs::SelfType(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let mut ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs index a25498eff3339..b7c7b6654536a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs @@ -22,11 +22,13 @@ use stdx::never; use crate::{ db::{HirDatabase, InternedClosure}, - error_lifetime, from_chalk_trait_id, from_placeholder_idx, make_binders, + error_lifetime, from_chalk_trait_id, from_placeholder_idx, + generics::Generics, + make_binders, mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem}, to_chalk_trait_id, traits::FnTrait, - utils::{self, elaborate_clause_supertraits, Generics}, + utils::{self, elaborate_clause_supertraits}, Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy, DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty, TyExt, WhereClause, @@ -337,7 +339,7 @@ impl CapturedItemWithoutTy { fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders { struct Filler<'a> { db: &'a dyn HirDatabase, - generics: Generics, + generics: &'a Generics, } impl FallibleTypeFolder for Filler<'_> { type Error = (); @@ -380,7 +382,7 @@ impl CapturedItemWithoutTy { }; let filler = &mut Filler { db: ctx.db, generics }; let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty); - make_binders(ctx.db, &filler.generics, result) + make_binders(ctx.db, filler.generics, result) } } } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs index 4c12786362f03..95f28531acfed 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs @@ -24,6 +24,7 @@ use crate::{ consteval, db::{InternedClosure, InternedCoroutine}, error_lifetime, + generics::{generics, Generics}, infer::{ coerce::{CoerceMany, CoercionCause}, find_continuable, @@ -39,7 +40,6 @@ use crate::{ primitive::{self, UintTy}, static_lifetime, to_chalk_trait_id, traits::FnTrait, - utils::{generics, Generics}, Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, FnAbi, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind, @@ -1830,13 +1830,13 @@ impl InferenceContext<'_> { ) -> Substitution { let ( parent_params, - self_params, + has_self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); - assert_eq!(self_params, 0); // method shouldn't have another Self param + assert!(!has_self_param); // method shouldn't have another Self param let total_len = parent_params + type_params + const_params + impl_trait_params + lifetime_params; let mut substs = Vec::with_capacity(total_len); @@ -1844,13 +1844,11 @@ impl InferenceContext<'_> { // handle provided arguments if let Some(generic_args) = generic_args { // if args are provided, it should be all of them, but we can't rely on that - for (arg, kind_id) in generic_args - .args - .iter() - .take(type_params + const_params + lifetime_params) - .zip(def_generics.iter_id()) + let self_params = type_params + const_params + lifetime_params; + for (arg, kind_id) in + generic_args.args.iter().zip(def_generics.iter_self_id()).take(self_params) { - if let Some(g) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, kind_id, arg, @@ -1869,9 +1867,8 @@ impl InferenceContext<'_> { ) }, |this, lt_ref| this.make_lifetime(lt_ref), - ) { - substs.push(g); - } + ); + substs.push(arg); } }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs index 9a1835b625b3c..d876008cd581e 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/path.rs @@ -12,11 +12,10 @@ use stdx::never; use crate::{ builder::ParamKind, consteval, error_lifetime, + generics::generics, method_resolution::{self, VisibleFromModule}, - to_chalk_trait_id, - utils::generics, - InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder, TyExt, - TyKind, ValueTyDefId, + to_chalk_trait_id, InferenceDiagnostic, Interner, Substitution, TraitRef, TraitRefExt, Ty, + TyBuilder, TyExt, TyKind, ValueTyDefId, }; use super::{ExprOrPatId, InferenceContext}; @@ -64,7 +63,7 @@ impl InferenceContext<'_> { it.into() } ValueNs::ImplSelf(impl_id) => { - let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); + let generics = crate::generics::generics(self.db.upcast(), impl_id.into()); let substs = generics.placeholder_subst(self.db); let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs); if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs index 36e3a458898da..ed4d55d203773 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/unify.rs @@ -613,8 +613,7 @@ impl<'a> InferenceTable<'a> { } pub(crate) fn resolve_obligations_as_possible(&mut self) { - let _span = - tracing::span!(tracing::Level::INFO, "resolve_obligations_as_possible").entered(); + let _span = tracing::info_span!("resolve_obligations_as_possible").entered(); let mut changed = true; let mut obligations = mem::take(&mut self.resolve_obligations_buffer); while mem::take(&mut changed) { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs index 7546369d8d47a..f5fb2ffd78175 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs @@ -15,7 +15,7 @@ use crate::{ // FIXME: Turn this into a query, it can be quite slow /// Checks whether a type is visibly uninhabited from a particular module. pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool { - let _p = tracing::span!(tracing::Level::INFO, "is_ty_uninhabited_from", ?ty).entered(); + let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST); @@ -30,7 +30,7 @@ pub(crate) fn is_enum_variant_uninhabited_from( subst: &Substitution, target_mod: ModuleId, ) -> bool { - let _p = tracing::span!(tracing::Level::INFO, "is_enum_variant_uninhabited_from").entered(); + let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered(); let mut uninhabited_from = UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs index 26a839f0e9fae..5e33e1285ee55 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs @@ -22,6 +22,7 @@ extern crate ra_ap_rustc_pattern_analysis as rustc_pattern_analysis; mod builder; mod chalk_db; mod chalk_ext; +mod generics; mod infer; mod inhabitedness; mod interner; @@ -52,7 +53,7 @@ use std::{ hash::{BuildHasherDefault, Hash}, }; -use base_db::salsa::impl_intern_value_trivial; +use base_db::salsa::InternValueTrivial; use chalk_ir::{ fold::{Shift, TypeFoldable}, interner::HasInterner, @@ -67,11 +68,10 @@ use rustc_hash::{FxHashMap, FxHashSet}; use syntax::ast::{make, ConstArg}; use traits::FnTrait; use triomphe::Arc; -use utils::Generics; use crate::{ - consteval::unknown_const, db::HirDatabase, display::HirDisplay, infer::unify::InferenceTable, - utils::generics, + consteval::unknown_const, db::HirDatabase, display::HirDisplay, generics::Generics, + infer::unify::InferenceTable, }; pub use autoderef::autoderef; @@ -289,7 +289,7 @@ impl Hash for ConstScalar { /// Return an index of a parameter in the generic type parameter list by it's id. pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option { - generics(db.upcast(), id.parent).type_or_const_param_idx(id) + generics::generics(db.upcast(), id.parent).type_or_const_param_idx(id) } pub(crate) fn wrap_empty_binders(value: T) -> Binders @@ -330,18 +330,15 @@ pub(crate) fn make_single_type_binders>( ) } -pub(crate) fn make_binders_with_count>( +pub(crate) fn make_binders>( db: &dyn HirDatabase, - count: usize, generics: &Generics, value: T, ) -> Binders { - let it = generics.iter_id().take(count); - Binders::new( VariableKinds::from_iter( Interner, - it.map(|x| match x { + generics.iter_id().map(|x| match x { hir_def::GenericParamId::ConstParamId(id) => { chalk_ir::VariableKind::Const(db.const_param_ty(id)) } @@ -355,14 +352,6 @@ pub(crate) fn make_binders_with_count>( ) } -pub(crate) fn make_binders>( - db: &dyn HirDatabase, - generics: &Generics, - value: T, -) -> Binders { - make_binders_with_count(db, usize::MAX, generics, value) -} - // FIXME: get rid of this, just replace it by FnPointer /// A function signature as seen by type inference: Several parameter types and /// one return type. @@ -524,14 +513,16 @@ pub type PolyFnSig = Binders; impl CallableSig { pub fn from_params_and_return( - mut params: Vec, + params: impl ExactSizeIterator, ret: Ty, is_varargs: bool, safety: Safety, abi: FnAbi, ) -> CallableSig { - params.push(ret); - CallableSig { params_and_return: params.into(), is_varargs, safety, abi } + let mut params_and_return = Vec::with_capacity(params.len() + 1); + params_and_return.extend(params); + params_and_return.push(ret); + CallableSig { params_and_return: params_and_return.into(), is_varargs, safety, abi } } pub fn from_def(db: &dyn HirDatabase, def: FnDefId, substs: &Substitution) -> CallableSig { @@ -606,7 +597,7 @@ pub enum ImplTraitId { AssociatedTypeImplTrait(hir_def::TypeAliasId, ImplTraitIdx), AsyncBlockTypeImplTrait(hir_def::DefWithBodyId, ExprId), } -impl_intern_value_trivial!(ImplTraitId); +impl InternValueTrivial for ImplTraitId {} #[derive(PartialEq, Eq, Debug, Hash)] pub struct ImplTraits { @@ -946,8 +937,7 @@ pub fn callable_sig_from_fn_trait( .as_tuple()? .iter(Interner) .map(|it| it.assert_ty_ref(Interner)) - .cloned() - .collect(); + .cloned(); return Some(( fn_x, diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs index 04ace38202191..96f545415e237 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs @@ -8,10 +8,11 @@ use std::{ cell::{Cell, RefCell, RefMut}, iter, + ops::{self, Not as _}, }; use base_db::{ - salsa::{impl_intern_value_trivial, Cycle}, + salsa::{Cycle, InternValueTrivial}, CrateId, }; use chalk_ir::{ @@ -45,7 +46,9 @@ use hir_def::{ use hir_expand::{name::Name, ExpandResult}; use intern::Interned; use la_arena::{Arena, ArenaMap}; +use once_cell::unsync::OnceCell; use rustc_hash::FxHashSet; +use rustc_pattern_analysis::Captures; use smallvec::SmallVec; use stdx::{impl_from, never}; use syntax::ast; @@ -58,12 +61,13 @@ use crate::{ unknown_const_as_generic, }, db::HirDatabase, - error_lifetime, make_binders, + error_lifetime, + generics::{generics, Generics}, + make_binders, mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk}, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, utils::{ - self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics, - Generics, InTypeConstIdMetadata, + all_super_trait_refs, associated_type_by_name_including_super_traits, InTypeConstIdMetadata, }, AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy, FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime, @@ -121,6 +125,7 @@ impl ImplTraitLoweringState { pub struct TyLoweringContext<'a> { pub db: &'a dyn HirDatabase, resolver: &'a Resolver, + generics: OnceCell>, in_binders: DebruijnIndex, // FIXME: Should not be an `Option` but `Resolver` currently does not return owners in all cases // where expected @@ -152,6 +157,7 @@ impl<'a> TyLoweringContext<'a> { Self { db, resolver, + generics: OnceCell::new(), owner, in_binders, impl_trait_mode, @@ -174,6 +180,7 @@ impl<'a> TyLoweringContext<'a> { impl_trait_mode, expander: RefCell::new(expander), unsized_types: RefCell::new(unsized_types), + generics: self.generics.clone(), ..*self }; let result = f(&new_ctx); @@ -245,8 +252,10 @@ impl<'a> TyLoweringContext<'a> { ) } - fn generics(&self) -> Option { - Some(generics(self.db.upcast(), self.resolver.generic_def()?)) + fn generics(&self) -> Option<&Generics> { + self.generics + .get_or_init(|| self.resolver.generic_def().map(|def| generics(self.db.upcast(), def))) + .as_ref() } pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option) { @@ -374,7 +383,7 @@ impl<'a> TyLoweringContext<'a> { counter.set(idx + count_impl_traits(type_ref) as u16); let ( _parent_params, - self_params, + self_param, type_params, const_params, _impl_trait_params, @@ -385,7 +394,7 @@ impl<'a> TyLoweringContext<'a> { .provenance_split(); TyKind::BoundVar(BoundVar::new( self.in_binders, - idx as usize + self_params + type_params + const_params, + idx as usize + self_param as usize + type_params + const_params, )) .intern(Interner) } @@ -416,9 +425,9 @@ impl<'a> TyLoweringContext<'a> { }; let ty = { let macro_call = macro_call.to_node(self.db.upcast()); - let resolver = |path| { + let resolver = |path: &_| { self.resolver - .resolve_path_as_macro(self.db.upcast(), &path, Some(MacroSubNs::Bang)) + .resolve_path_as_macro(self.db.upcast(), path, Some(MacroSubNs::Bang)) .map(|(it, _)| it) }; match expander.enter_expand::(self.db.upcast(), macro_call, resolver) @@ -705,7 +714,8 @@ impl<'a> TyLoweringContext<'a> { None, ); - let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self(); + let len_self = + crate::generics::generics(self.db.upcast(), associated_ty.into()).len_self(); let substs = Substitution::from_iter( Interner, @@ -815,14 +825,14 @@ impl<'a> TyLoweringContext<'a> { let def_generics = generics(self.db.upcast(), def); let ( parent_params, - self_params, + self_param, type_params, const_params, impl_trait_params, lifetime_params, ) = def_generics.provenance_split(); let item_len = - self_params + type_params + const_params + impl_trait_params + lifetime_params; + self_param as usize + type_params + const_params + impl_trait_params + lifetime_params; let total_len = parent_params + item_len; let ty_error = TyKind::Error.intern(Interner).cast(Interner); @@ -830,18 +840,16 @@ impl<'a> TyLoweringContext<'a> { let mut def_generic_iter = def_generics.iter_id(); let fill_self_params = || { - for x in explicit_self_ty - .into_iter() - .map(|x| x.cast(Interner)) - .chain(iter::repeat(ty_error.clone())) - .take(self_params) - { + if self_param { + let self_ty = + explicit_self_ty.map(|x| x.cast(Interner)).unwrap_or_else(|| ty_error.clone()); + if let Some(id) = def_generic_iter.next() { assert!(matches!( id, GenericParamId::TypeParamId(_) | GenericParamId::LifetimeParamId(_) )); - substs.push(x); + substs.push(self_ty); } } }; @@ -852,11 +860,11 @@ impl<'a> TyLoweringContext<'a> { fill_self_params(); } let expected_num = if generic_args.has_self_type { - self_params + type_params + const_params + self_param as usize + type_params + const_params } else { type_params + const_params }; - let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 }; + let skip = if generic_args.has_self_type && !self_param { 1 } else { 0 }; // if args are provided, it should be all of them, but we can't rely on that for arg in generic_args .args @@ -866,7 +874,7 @@ impl<'a> TyLoweringContext<'a> { .take(expected_num) { if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -874,13 +882,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // we just filtered them out - never!("Unexpected lifetime argument"); - } + ); + had_explicit_args = true; + substs.push(arg); } } @@ -893,7 +897,7 @@ impl<'a> TyLoweringContext<'a> { // Taking into the fact that def_generic_iter will always have lifetimes at the end // Should have some test cases tho to test this behaviour more properly if let Some(id) = def_generic_iter.next() { - if let Some(x) = generic_arg_to_chalk( + let arg = generic_arg_to_chalk( self.db, id, arg, @@ -901,13 +905,9 @@ impl<'a> TyLoweringContext<'a> { |_, type_ref| self.lower_ty(type_ref), |_, const_ref, ty| self.lower_const(const_ref, ty), |_, lifetime_ref| self.lower_lifetime(lifetime_ref), - ) { - had_explicit_args = true; - substs.push(x); - } else { - // Never return a None explicitly - never!("Unexpected None by generic_arg_to_chalk"); - } + ); + had_explicit_args = true; + substs.push(arg); } } } else { @@ -1176,7 +1176,7 @@ impl<'a> TyLoweringContext<'a> { let ty = if let Some(target_param_idx) = target_param_idx { let mut counter = 0; let generics = self.generics().expect("generics in scope"); - for (idx, data) in generics.params.type_or_consts.iter() { + for (idx, data) in generics.iter_self_type_or_consts() { // Count the number of `impl Trait` things that appear before // the target of our `bound`. // Our counter within `impl_trait_mode` should be that number @@ -1478,7 +1478,7 @@ fn named_associated_type_shorthand_candidates( // Handle `Self::Type` referring to own associated type in trait definitions if let GenericDefId::TraitId(trait_id) = param_id.parent() { let trait_generics = generics(db.upcast(), trait_id.into()); - if trait_generics.params[param_id.local_id()].is_trait_self() { + if trait_generics[param_id.local_id()].is_trait_self() { let def_generics = generics(db.upcast(), def); let starting_idx = match def { GenericDefId::TraitId(_) => 0, @@ -1596,14 +1596,20 @@ pub(crate) fn generic_predicates_for_param_query( .collect(); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver) - { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_predicates) = implicitly_sized_clauses( + db, + param_id.parent, + &explicitly_unsized_tys, + &subst, + &resolver, + ) { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + }; } predicates.into() } @@ -1666,14 +1672,17 @@ pub(crate) fn trait_environment_query( } let subst = generics(db.upcast(), def).placeholder_subst(db); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_clauses) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - clauses.extend( - implicitly_sized_clauses - .map(|pred| pred.cast::(Interner).into_from_env_clause(Interner)), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_clauses) = + implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) + { + clauses.extend( + implicitly_sized_clauses.map(|pred| { + pred.cast::(Interner).into_from_env_clause(Interner) + }), + ); + }; } let env = chalk_ir::Environment::new(Interner).add_clauses(Interner, clauses); @@ -1681,20 +1690,32 @@ pub(crate) fn trait_environment_query( TraitEnvironment::new(resolver.krate(), None, traits_in_scope.into_boxed_slice(), env) } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericPredicates(Option]>>); + +impl ops::Deref for GenericPredicates { + type Target = [Binders]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + /// Resolve the where clause(s) of an item with generics. pub(crate) fn generic_predicates_query( db: &dyn HirDatabase, def: GenericDefId, -) -> Arc<[Binders]> { +) -> GenericPredicates { let resolver = def.resolver(db.upcast()); - let ctx = if let GenericDefId::FunctionId(_) = def { - TyLoweringContext::new(db, &resolver, def.into()) - .with_impl_trait_mode(ImplTraitLoweringMode::Variable) - .with_type_param_mode(ParamLoweringMode::Variable) - } else { - TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable) + let (impl_trait_lowering, param_lowering) = match def { + GenericDefId::FunctionId(_) => { + (ImplTraitLoweringMode::Variable, ParamLoweringMode::Variable) + } + _ => (ImplTraitLoweringMode::Disallowed, ParamLoweringMode::Variable), }; + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(impl_trait_lowering) + .with_type_param_mode(param_lowering); let generics = generics(db.upcast(), def); let mut predicates = resolver @@ -1705,27 +1726,29 @@ pub(crate) fn generic_predicates_query( .collect::>(); let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST); - let explicitly_unsized_tys = ctx.unsized_types.into_inner(); - if let Some(implicitly_sized_predicates) = - implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) - { - predicates.extend( - implicitly_sized_predicates - .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), - ); + if !subst.is_empty(Interner) { + let explicitly_unsized_tys = ctx.unsized_types.into_inner(); + if let Some(implicitly_sized_predicates) = + implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver) + { + predicates.extend( + implicitly_sized_predicates + .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p))), + ); + }; } - predicates.into() + GenericPredicates(predicates.is_empty().not().then(|| predicates.into())) } /// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound. /// Exception is Self of a trait def. -fn implicitly_sized_clauses<'a>( +fn implicitly_sized_clauses<'a, 'subst: 'a>( db: &dyn HirDatabase, def: GenericDefId, explicitly_unsized_tys: &'a FxHashSet, - substitution: &'a Substitution, + substitution: &'subst Substitution, resolver: &Resolver, -) -> Option + 'a> { +) -> Option + Captures<'a> + Captures<'subst>> { let is_trait_def = matches!(def, GenericDefId::TraitId(..)); let generic_args = &substitution.as_slice(Interner)[is_trait_def as usize..]; let sized_trait = db @@ -1746,71 +1769,84 @@ fn implicitly_sized_clauses<'a>( }) } +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct GenericDefaults(Option]>>); + +impl ops::Deref for GenericDefaults { + type Target = [Binders]; + + fn deref(&self) -> &Self::Target { + self.0.as_deref().unwrap_or(&[]) + } +} + /// Resolve the default type params from generics -pub(crate) fn generic_defaults_query( - db: &dyn HirDatabase, - def: GenericDefId, -) -> Arc<[Binders]> { - let resolver = def.resolver(db.upcast()); - let ctx = TyLoweringContext::new(db, &resolver, def.into()) - .with_type_param_mode(ParamLoweringMode::Variable); +pub(crate) fn generic_defaults_query(db: &dyn HirDatabase, def: GenericDefId) -> GenericDefaults { let generic_params = generics(db.upcast(), def); + if generic_params.len() == 0 { + return GenericDefaults(None); + } + let resolver = def.resolver(db.upcast()); let parent_start_idx = generic_params.len_self(); - let defaults = Arc::from_iter(generic_params.iter().enumerate().map(|(idx, (id, p))| { - match p { - GenericParamDataRef::TypeParamData(p) => { - let mut ty = - p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t)); - // Each default can only refer to previous parameters. - // Type variable default referring to parameter coming - // after it is forbidden (FIXME: report diagnostic) - ty = fallback_bound_vars(ty, idx, parent_start_idx); - crate::make_binders(db, &generic_params, ty.cast(Interner)) - } - GenericParamDataRef::ConstParamData(p) => { - let GenericParamId::ConstParamId(id) = id else { - unreachable!("Unexpected lifetime or type argument") - }; + let ctx = TyLoweringContext::new(db, &resolver, def.into()) + .with_impl_trait_mode(ImplTraitLoweringMode::Disallowed) + .with_type_param_mode(ParamLoweringMode::Variable); + GenericDefaults(Some(Arc::from_iter(generic_params.iter().enumerate().map( + |(idx, (id, p))| { + match p { + GenericParamDataRef::TypeParamData(p) => { + let ty = p.default.as_ref().map_or(TyKind::Error.intern(Interner), |ty| { + // Each default can only refer to previous parameters. + // Type variable default referring to parameter coming + // after it is forbidden (FIXME: report diagnostic) + fallback_bound_vars(ctx.lower_ty(ty), idx, parent_start_idx) + }); + crate::make_binders(db, &generic_params, ty.cast(Interner)) + } + GenericParamDataRef::ConstParamData(p) => { + let GenericParamId::ConstParamId(id) = id else { + unreachable!("Unexpected lifetime or type argument") + }; - let mut val = p.default.as_ref().map_or_else( - || unknown_const_as_generic(db.const_param_ty(id)), - |c| { - let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); - c.cast(Interner) - }, - ); - // Each default can only refer to previous parameters, see above. - val = fallback_bound_vars(val, idx, parent_start_idx); - make_binders(db, &generic_params, val) - } - GenericParamDataRef::LifetimeParamData(_) => { - make_binders(db, &generic_params, error_lifetime().cast(Interner)) + let mut val = p.default.as_ref().map_or_else( + || unknown_const_as_generic(db.const_param_ty(id)), + |c| { + let c = ctx.lower_const(c, ctx.lower_ty(&p.ty)); + c.cast(Interner) + }, + ); + // Each default can only refer to previous parameters, see above. + val = fallback_bound_vars(val, idx, parent_start_idx); + make_binders(db, &generic_params, val) + } + GenericParamDataRef::LifetimeParamData(_) => { + make_binders(db, &generic_params, error_lifetime().cast(Interner)) + } } - } - })); - - defaults + }, + )))) } pub(crate) fn generic_defaults_recover( db: &dyn HirDatabase, _cycle: &Cycle, def: &GenericDefId, -) -> Arc<[Binders]> { +) -> GenericDefaults { let generic_params = generics(db.upcast(), *def); + if generic_params.len() == 0 { + return GenericDefaults(None); + } // FIXME: this code is not covered in tests. // we still need one default per parameter - let defaults = Arc::from_iter(generic_params.iter_id().map(|id| { + GenericDefaults(Some(Arc::from_iter(generic_params.iter_id().map(|id| { let val = match id { GenericParamId::TypeParamId(_) => TyKind::Error.intern(Interner).cast(Interner), GenericParamId::ConstParamId(id) => unknown_const_as_generic(db.const_param_ty(id)), GenericParamId::LifetimeParamId(_) => error_lifetime().cast(Interner), }; crate::make_binders(db, &generic_params, val) - })); - - defaults + })))) } fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { @@ -1819,7 +1855,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig { let ctx_params = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Variable) .with_type_param_mode(ParamLoweringMode::Variable); - let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::>(); + let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)); let ctx_ret = TyLoweringContext::new(db, &resolver, def.into()) .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) .with_type_param_mode(ParamLoweringMode::Variable); @@ -1873,7 +1909,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, AdtId::from(def).into()) .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders(); Binders::new( binders, @@ -1905,7 +1941,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) let resolver = def.resolver(db.upcast()); let ctx = TyLoweringContext::new(db, &resolver, DefWithBodyId::VariantId(def).into()) .with_type_param_mode(ParamLoweringMode::Variable); - let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::>(); + let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)); let (ret, binders) = type_for_adt(db, def.lookup(db.upcast()).parent.into()).into_value_and_skipped_binders(); Binders::new( @@ -1965,7 +2001,9 @@ pub enum CallableDefId { StructId(StructId), EnumVariantId(EnumVariantId), } -impl_intern_value_trivial!(CallableDefId); + +impl InternValueTrivial for CallableDefId {} + impl_from!(FunctionId, StructId, EnumVariantId for CallableDefId); impl From for ModuleDefId { fn from(def: CallableDefId) -> ModuleDefId { @@ -2166,7 +2204,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut /// Checks if the provided generic arg matches its expected kind, then lower them via /// provided closures. Use unknown if there was kind mismatch. /// -/// Returns `Some` of the lowered generic arg. `None` if the provided arg is a lifetime. pub(crate) fn generic_arg_to_chalk<'a, T>( db: &dyn HirDatabase, kind_id: GenericParamId, @@ -2175,7 +2212,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a, for_const: impl FnOnce(&mut T, &ConstRef, Ty) -> Const + 'a, for_lifetime: impl FnOnce(&mut T, &LifetimeRef) -> Lifetime + 'a, -) -> Option { +) -> crate::GenericArg { let kind = match kind_id { GenericParamId::TypeParamId(_) => ParamKind::Type, GenericParamId::ConstParamId(id) => { @@ -2184,7 +2221,7 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( } GenericParamId::LifetimeParamId(_) => ParamKind::Lifetime, }; - Some(match (arg, kind) { + match (arg, kind) { (GenericArg::Type(type_ref), ParamKind::Type) => for_type(this, type_ref).cast(Interner), (GenericArg::Const(c), ParamKind::Const(c_ty)) => for_const(this, c, c_ty).cast(Interner), (GenericArg::Lifetime(lifetime_ref), ParamKind::Lifetime) => { @@ -2197,11 +2234,12 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( // as types. Maybe here is not the best place to do it, but // it works. if let TypeRef::Path(p) = t { - let p = p.mod_path()?; - if p.kind == PathKind::Plain { - if let [n] = p.segments() { - let c = ConstRef::Path(n.clone()); - return Some(for_const(this, &c, c_ty).cast(Interner)); + if let Some(p) = p.mod_path() { + if p.kind == PathKind::Plain { + if let [n] = p.segments() { + let c = ConstRef::Path(n.clone()); + return for_const(this, &c, c_ty).cast(Interner); + } } } } @@ -2210,17 +2248,17 @@ pub(crate) fn generic_arg_to_chalk<'a, T>( (GenericArg::Lifetime(_), ParamKind::Const(c_ty)) => unknown_const_as_generic(c_ty), (GenericArg::Type(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), (GenericArg::Const(_), ParamKind::Lifetime) => error_lifetime().cast(Interner), - }) + } } -pub(crate) fn const_or_path_to_chalk( +pub(crate) fn const_or_path_to_chalk<'g>( db: &dyn HirDatabase, resolver: &Resolver, owner: TypeOwnerId, expected_ty: Ty, value: &ConstRef, mode: ParamLoweringMode, - args: impl FnOnce() -> Option, + args: impl FnOnce() -> Option<&'g Generics>, debruijn: DebruijnIndex, ) -> Const { match value { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs index cb56a6f0bfe7d..5ce124d6d27fa 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs @@ -144,8 +144,7 @@ pub struct TraitImpls { impl TraitImpls { pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = - tracing::span!(tracing::Level::INFO, "trait_impls_in_crate_query", ?krate).entered(); + let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered(); let mut impls = FxHashMap::default(); Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate)); @@ -157,7 +156,7 @@ impl TraitImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "trait_impls_in_block_query").entered(); + let _p = tracing::info_span!("trait_impls_in_block_query").entered(); let mut impls = FxHashMap::default(); Self::collect_def_map(db, &mut impls, &db.block_def_map(block)); @@ -173,8 +172,7 @@ impl TraitImpls { db: &dyn HirDatabase, krate: CrateId, ) -> Arc<[Arc]> { - let _p = - tracing::span!(tracing::Level::INFO, "trait_impls_in_deps_query", ?krate).entered(); + let _p = tracing::info_span!("trait_impls_in_deps_query", ?krate).entered(); let crate_graph = db.crate_graph(); Arc::from_iter( @@ -280,8 +278,7 @@ pub struct InherentImpls { impl InherentImpls { pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc { - let _p = - tracing::span!(tracing::Level::INFO, "inherent_impls_in_crate_query", ?krate).entered(); + let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered(); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let crate_def_map = db.crate_def_map(krate); @@ -295,7 +292,7 @@ impl InherentImpls { db: &dyn HirDatabase, block: BlockId, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "inherent_impls_in_block_query").entered(); + let _p = tracing::info_span!("inherent_impls_in_block_query").entered(); let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() }; let block_def_map = db.block_def_map(block); @@ -368,7 +365,7 @@ pub(crate) fn incoherent_inherent_impl_crates( krate: CrateId, fp: TyFingerprint, ) -> SmallVec<[CrateId; 2]> { - let _p = tracing::span!(tracing::Level::INFO, "incoherent_inherent_impl_crates").entered(); + let _p = tracing::info_span!("incoherent_inherent_impl_crates").entered(); let mut res = SmallVec::new(); let crate_graph = db.crate_graph(); @@ -937,8 +934,7 @@ pub fn iterate_method_candidates_dyn( mode: LookupMode, callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId, bool) -> ControlFlow<()>, ) -> ControlFlow<()> { - let _p = tracing::span!( - tracing::Level::INFO, + let _p = tracing::info_span!( "iterate_method_candidates_dyn", ?mode, ?name, @@ -1504,7 +1500,7 @@ fn is_valid_impl_fn_candidate( } } table.run_in_snapshot(|table| { - let _p = tracing::span!(tracing::Level::INFO, "subst_for_def").entered(); + let _p = tracing::info_span!("subst_for_def").entered(); let impl_subst = TyBuilder::subst_for_def(db, impl_id, None).fill_with_inference_vars(table).build(); let expect_self_ty = db.impl_self_ty(impl_id).substitute(Interner, &impl_subst); @@ -1512,7 +1508,7 @@ fn is_valid_impl_fn_candidate( check_that!(table.unify(&expect_self_ty, self_ty)); if let Some(receiver_ty) = receiver_ty { - let _p = tracing::span!(tracing::Level::INFO, "check_receiver_ty").entered(); + let _p = tracing::info_span!("check_receiver_ty").entered(); check_that!(data.has_self_param()); let fn_subst = TyBuilder::subst_for_def(db, fn_id, Some(impl_subst.clone())) diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs index d513355037710..2e106877cbc20 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs @@ -898,20 +898,19 @@ pub enum Rvalue { Cast(CastKind, Operand, Ty), // FIXME link to `pointer::offset` when it hits stable. - /// * `Offset` has the same semantics as `pointer::offset`, except that the second - /// parameter may be a `usize` as well. - /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, - /// raw pointers, or function pointers and return a `bool`. The types of the operands must be - /// matching, up to the usual caveat of the lifetimes in function pointers. - /// * Left and right shift operations accept signed or unsigned integers not necessarily of the - /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is - /// truncated as needed. - /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching - /// types and return a value of that type. - /// * The remaining operations accept signed integers, unsigned integers, or floats with - /// matching types and return a value of that type. + // /// * `Offset` has the same semantics as `pointer::offset`, except that the second + // /// parameter may be a `usize` as well. + // /// * The comparison operations accept `bool`s, `char`s, signed or unsigned integers, floats, + // /// raw pointers, or function pointers and return a `bool`. The types of the operands must be + // /// matching, up to the usual caveat of the lifetimes in function pointers. + // /// * Left and right shift operations accept signed or unsigned integers not necessarily of the + // /// same type and return a value of the same type as their LHS. Like in Rust, the RHS is + // /// truncated as needed. + // /// * The `Bit*` operations accept signed integers, unsigned integers, or bools with matching + // /// types and return a value of that type. + // /// * The remaining operations accept signed integers, unsigned integers, or floats with + // /// matching types and return a value of that type. //BinaryOp(BinOp, Box<(Operand, Operand)>), - /// Same as `BinaryOp`, but yields `(T, bool)` with a `bool` indicating an error condition. /// /// When overflow checking is disabled and we are generating run-time code, the error condition diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs index 8b6936f8bc0fc..878d584a4efa0 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs @@ -91,7 +91,7 @@ pub fn borrowck_query( db: &dyn HirDatabase, def: DefWithBodyId, ) -> Result, MirLowerError> { - let _p = tracing::span!(tracing::Level::INFO, "borrowck_query").entered(); + let _p = tracing::info_span!("borrowck_query").entered(); let mut res = vec![]; all_mir_bodies(db, def, |body| { res.push(BorrowckResult { diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs index 2de1aa30c9660..4ee96a66a3961 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs @@ -363,7 +363,7 @@ impl MirEvalError { )?; } Either::Right(closure) => { - writeln!(f, "In {:?}", closure)?; + writeln!(f, "In {closure:?}")?; } } let source_map = db.body_with_source_map(*def).1; @@ -424,7 +424,7 @@ impl MirEvalError { | MirEvalError::StackOverflow | MirEvalError::CoerceUnsizedError(_) | MirEvalError::InternalError(_) - | MirEvalError::InvalidVTableId(_) => writeln!(f, "{:?}", err)?, + | MirEvalError::InvalidVTableId(_) => writeln!(f, "{err:?}")?, } Ok(()) } diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs index 4abbda56cbb4d..c3b35cd553da9 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/tests.rs @@ -77,7 +77,7 @@ fn check_panic(ra_fixture: &str, expected_panic: &str) { let (db, file_ids) = TestDB::with_many_files(ra_fixture); let file_id = *file_ids.last().unwrap(); let e = eval_main(&db, file_id).unwrap_err(); - assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {:?}", e)), expected_panic); + assert_eq!(e.is_panic().unwrap_or_else(|| panic!("unexpected error: {e:?}")), expected_panic); } #[test] diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs index 151f65cfbb8e6..09302846f1b3a 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs @@ -28,6 +28,7 @@ use crate::{ db::{HirDatabase, InternedClosure}, display::HirDisplay, error_lifetime, + generics::generics, infer::{CaptureKind, CapturedItem, TypeMismatch}, inhabitedness::is_ty_uninhabited_from, layout::LayoutError, @@ -42,7 +43,7 @@ use crate::{ }, static_lifetime, traits::FnTrait, - utils::{generics, ClosureSubst}, + utils::ClosureSubst, Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt, }; @@ -213,7 +214,7 @@ impl MirLowerError { | MirLowerError::LangItemNotFound(_) | MirLowerError::MutatingRvalue | MirLowerError::UnresolvedLabel - | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{:?}", self)?, + | MirLowerError::UnresolvedUpvar(_) => writeln!(f, "{self:?}")?, } Ok(()) } @@ -2133,7 +2134,7 @@ pub fn mir_body_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Result format!("in type const {it:?}"), }; - let _p = tracing::span!(tracing::Level::INFO, "mir_body_query", ?detail).entered(); + let _p = tracing::info_span!("mir_body_query", ?detail).entered(); let body = db.body(def); let infer = db.infer(def); let mut result = lower_to_mir(db, def, &body, &infer, body.body_expr)?; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs index a384c9306eee2..43afa61504839 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/monomorphization.rs @@ -21,8 +21,8 @@ use crate::{ consteval::{intern_const_scalar, unknown_const}, db::{HirDatabase, InternedClosure}, from_placeholder_idx, + generics::{generics, Generics}, infer::normalize, - utils::{generics, Generics}, ClosureId, Const, Interner, ProjectionTy, Substitution, TraitEnvironment, Ty, TyKind, }; diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs index 02f2cd761599a..4283a94657b9f 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs @@ -108,7 +108,7 @@ pub(crate) fn trait_solve_query( GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(_))) => "alias_eq".to_owned(), _ => "??".to_owned(), }; - let _p = tracing::span!(tracing::Level::INFO, "trait_solve_query", ?detail).entered(); + let _p = tracing::info_span!("trait_solve_query", ?detail).entered(); tracing::info!("trait_solve_query({:?})", goal.value.goal); if let GoalData::DomainGoal(DomainGoal::Holds(WhereClause::AliasEq(AliasEq { @@ -140,7 +140,7 @@ fn solve( block: Option, goal: &chalk_ir::UCanonical>>, ) -> Option> { - let _p = tracing::span!(tracing::Level::INFO, "solve", ?krate, ?block).entered(); + let _p = tracing::info_span!("solve", ?krate, ?block).entered(); let context = ChalkContext { db, krate, block }; tracing::debug!("solve goal: {:?}", goal); let mut solver = create_chalk_solver(); diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs index 42c7a84032830..969999cdb8445 100644 --- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs +++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs @@ -5,25 +5,19 @@ use std::{hash::Hash, iter}; use base_db::CrateId; use chalk_ir::{ - cast::Cast, fold::{FallibleTypeFolder, Shift}, - BoundVar, DebruijnIndex, + DebruijnIndex, }; use hir_def::{ db::DefDatabase, - generics::{ - GenericParamDataRef, GenericParams, LifetimeParamData, TypeOrConstParamData, - TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, - }, + generics::{WherePredicate, WherePredicateTypeTarget}, lang_item::LangItem, resolver::{HasResolver, TypeNs}, type_ref::{TraitBoundModifier, TypeRef}, - ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId, GenericParamId, ItemContainerId, - LifetimeParamId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, TypeOrConstParamId, - TypeParamId, + EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId, + TypeOrConstParamId, }; use hir_expand::name::Name; -use intern::Interned; use rustc_abi::TargetDataLayout; use rustc_hash::FxHashSet; use smallvec::{smallvec, SmallVec}; @@ -161,7 +155,7 @@ impl Iterator for ClauseElaborator<'_> { fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(TraitId)) { let resolver = trait_.resolver(db); let generic_params = db.generic_params(trait_.into()); - let trait_self = generic_params.find_trait_self_param(); + let trait_self = generic_params.trait_self_param(); generic_params .where_predicates .iter() @@ -194,7 +188,7 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId, cb: impl FnMut(Tra fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef, cb: impl FnMut(TraitRef)) { let generic_params = db.generic_params(trait_ref.hir_trait_id().into()); - let trait_self = match generic_params.find_trait_self_param() { + let trait_self = match generic_params.trait_self_param() { Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p }, None => return, }; @@ -226,11 +220,6 @@ pub(super) fn associated_type_by_name_including_super_traits( }) } -pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { - let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); - Generics { def, params: db.generic_params(def), parent_generics } -} - /// It is a bit different from the rustc equivalent. Currently it stores: /// - 0: the function signature, encoded as a function pointer type /// - 1..n: generics of the parent @@ -262,278 +251,14 @@ impl<'a> ClosureSubst<'a> { } } -#[derive(Clone, Debug)] -pub(crate) struct Generics { - def: GenericDefId, - pub(crate) params: Interned, - parent_generics: Option>, -} - -impl Generics { - pub(crate) fn iter_id(&self) -> impl Iterator + '_ { - self.iter().map(|(id, _)| id) - } - - pub(crate) fn def(&self) -> GenericDefId { - self.def - } - - /// Iterator over types and const params of self, then parent. - pub(crate) fn iter<'a>( - &'a self, - ) -> impl DoubleEndedIterator)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - let lt_iter = self.params.iter_lt().map(from_lt_id(self)); - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(lt_iter) - .chain(self.iter_parent()) - } - - /// Iterate over types and const params without parent params. - pub(crate) fn iter_self<'a>( - &'a self, - ) -> impl DoubleEndedIterator)> + 'a { - let from_toc_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a TypeOrConstParamData)| { - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - } - }; - - let from_lt_id = |it: &'a Generics| { - move |(local_id, p): (_, &'a LifetimeParamData)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - } - }; - - self.params - .iter_type_or_consts() - .map(from_toc_id(self)) - .chain(self.params.iter_lt().map(from_lt_id(self))) - } - - /// Iterator over types and const params of parent. - pub(crate) fn iter_parent( - &self, - ) -> impl DoubleEndedIterator)> + '_ { - self.parent_generics().into_iter().flat_map(|it| { - let from_toc_id = move |(local_id, p)| { - let p: &_ = p; - let id = TypeOrConstParamId { parent: it.def, local_id }; - match p { - TypeOrConstParamData::TypeParamData(p) => ( - GenericParamId::TypeParamId(TypeParamId::from_unchecked(id)), - GenericParamDataRef::TypeParamData(p), - ), - TypeOrConstParamData::ConstParamData(p) => ( - GenericParamId::ConstParamId(ConstParamId::from_unchecked(id)), - GenericParamDataRef::ConstParamData(p), - ), - } - }; - - let from_lt_id = move |(local_id, p): (_, _)| { - ( - GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }), - GenericParamDataRef::LifetimeParamData(p), - ) - }; - let lt_iter = it.params.iter_lt().map(from_lt_id); - it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter) - }) - } - - /// Returns total number of generic parameters in scope, including those from parent. - pub(crate) fn len(&self) -> usize { - let parent = self.parent_generics().map_or(0, Generics::len); - let child = self.params.len(); - parent + child - } - - /// Returns numbers of generic parameters and lifetimes excluding those from parent. - pub(crate) fn len_self(&self) -> usize { - self.params.len() - } - - /// Returns number of generic parameter excluding those from parent - fn len_type_and_const_params(&self) -> usize { - self.params.type_or_consts.len() - } - - /// (parent total, self param, type params, const params, impl trait list, lifetimes) - pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize, usize) { - let mut self_params = 0; - let mut type_params = 0; - let mut impl_trait_params = 0; - let mut const_params = 0; - let mut lifetime_params = 0; - self.params.iter_type_or_consts().for_each(|(_, data)| match data { - TypeOrConstParamData::TypeParamData(p) => match p.provenance { - TypeParamProvenance::TypeParamList => type_params += 1, - TypeParamProvenance::TraitSelf => self_params += 1, - TypeParamProvenance::ArgumentImplTrait => impl_trait_params += 1, - }, - TypeOrConstParamData::ConstParamData(_) => const_params += 1, - }); - - self.params.iter_lt().for_each(|(_, _)| lifetime_params += 1); - - let parent_len = self.parent_generics().map_or(0, Generics::len); - (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params) - } - - pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option { - Some(self.find_type_or_const_param(param)?.0) - } - - fn find_type_or_const_param( - &self, - param: TypeOrConstParamId, - ) -> Option<(usize, &TypeOrConstParamData)> { - if param.parent == self.def { - let idx = param.local_id.into_raw().into_u32() as usize; - if idx >= self.params.type_or_consts.len() { - return None; - } - Some((idx, &self.params.type_or_consts[param.local_id])) - } else { - self.parent_generics() - .and_then(|g| g.find_type_or_const_param(param)) - // Remember that parent parameters come after parameters for self. - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn lifetime_idx(&self, lifetime: LifetimeParamId) -> Option { - Some(self.find_lifetime(lifetime)?.0) - } - - fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> { - if lifetime.parent == self.def { - let idx = lifetime.local_id.into_raw().into_u32() as usize; - if idx >= self.params.lifetimes.len() { - return None; - } - Some(( - self.len_type_and_const_params() + idx, - &self.params.lifetimes[lifetime.local_id], - )) - } else { - self.parent_generics() - .and_then(|g| g.find_lifetime(lifetime)) - .map(|(idx, data)| (self.len_self() + idx, data)) - } - } - - pub(crate) fn parent_generics(&self) -> Option<&Generics> { - self.parent_generics.as_deref() - } - - pub(crate) fn parent_or_self(&self) -> &Generics { - self.parent_generics.as_deref().unwrap_or(self) - } - - /// Returns a Substitution that replaces each parameter by a bound variable. - pub(crate) fn bound_vars_subst( - &self, - db: &dyn HirDatabase, - debruijn: DebruijnIndex, - ) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().enumerate().map(|(idx, id)| match id { - GenericParamId::ConstParamId(id) => BoundVar::new(debruijn, idx) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::TypeParamId(_) => { - BoundVar::new(debruijn, idx).to_ty(Interner).cast(Interner) - } - GenericParamId::LifetimeParamId(_) => { - BoundVar::new(debruijn, idx).to_lifetime(Interner).cast(Interner) - } - }), - ) - } - - /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`). - pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution { - Substitution::from_iter( - Interner, - self.iter_id().map(|id| match id { - GenericParamId::TypeParamId(id) => { - crate::to_placeholder_idx(db, id.into()).to_ty(Interner).cast(Interner) - } - GenericParamId::ConstParamId(id) => crate::to_placeholder_idx(db, id.into()) - .to_const(Interner, db.const_param_ty(id)) - .cast(Interner), - GenericParamId::LifetimeParamId(id) => { - crate::lt_to_placeholder_idx(db, id).to_lifetime(Interner).cast(Interner) - } - }), - ) - } -} - -fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option { - let container = match def { - GenericDefId::FunctionId(it) => it.lookup(db).container, - GenericDefId::TypeAliasId(it) => it.lookup(db).container, - GenericDefId::ConstId(it) => it.lookup(db).container, - GenericDefId::EnumVariantId(it) => return Some(it.lookup(db).parent.into()), - GenericDefId::AdtId(_) - | GenericDefId::TraitId(_) - | GenericDefId::ImplId(_) - | GenericDefId::TraitAliasId(_) => return None, - }; - - match container { - ItemContainerId::ImplId(it) => Some(it.into()), - ItemContainerId::TraitId(it) => Some(it.into()), - ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => None, - } -} - pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool { let data = db.function_data(func); if data.has_unsafe_kw() { + // Functions that are `#[rustc_deprecated_safe_2024]` are safe to call before 2024. + if db.attrs(func.into()).by_key("rustc_deprecated_safe_2024").exists() { + // FIXME: Properly check the caller span and mark it as unsafe after 2024. + return false; + } return true; } diff --git a/src/tools/rust-analyzer/crates/hir/Cargo.toml b/src/tools/rust-analyzer/crates/hir/Cargo.toml index 6d7ecd1e50b6c..edf26a07a7442 100644 --- a/src/tools/rust-analyzer/crates/hir/Cargo.toml +++ b/src/tools/rust-analyzer/crates/hir/Cargo.toml @@ -27,6 +27,7 @@ cfg.workspace = true hir-def.workspace = true hir-expand.workspace = true hir-ty.workspace = true +intern.workspace = true stdx.workspace = true syntax.workspace = true tt.workspace = true diff --git a/src/tools/rust-analyzer/crates/hir/src/attrs.rs b/src/tools/rust-analyzer/crates/hir/src/attrs.rs index c7502890ef41e..7b3ff7b06458b 100644 --- a/src/tools/rust-analyzer/crates/hir/src/attrs.rs +++ b/src/tools/rust-analyzer/crates/hir/src/attrs.rs @@ -307,7 +307,7 @@ fn doc_modpath_from_str(link: &str) -> Option { let kind = match parts.next()? { "" => PathKind::Abs, "crate" => PathKind::Crate, - "self" => PathKind::Super(0), + "self" => PathKind::SELF, "super" => { let mut deg = 1; for segment in parts.by_ref() { diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs index c276e87786dde..79069ed66bf03 100644 --- a/src/tools/rust-analyzer/crates/hir/src/display.rs +++ b/src/tools/rust-analyzer/crates/hir/src/display.rs @@ -3,7 +3,8 @@ use either::Either; use hir_def::{ data::adt::{StructKind, VariantData}, generics::{ - TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, + GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate, + WherePredicateTypeTarget, }, lang_item::LangItem, type_ref::{TypeBound, TypeRef}, @@ -16,10 +17,12 @@ use hir_ty::{ }, AliasEq, AliasTy, Interner, ProjectionTyExt, TraitRefExt, TyKind, WhereClause, }; +use intern::Interned; +use itertools::Itertools; use crate::{ Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl, - Field, Function, GenericParam, HasCrate, HasVisibility, LifetimeParam, Macro, Module, + Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module, SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias, TypeOrConstParam, TypeParam, Union, Variant, }; @@ -30,12 +33,42 @@ impl HirDisplay for Function { let data = db.function_data(self.id); let container = self.as_assoc_item(db).map(|it| it.container(db)); let mut module = self.module(db); + + // Write container (trait or impl) + let container_params = match container { + Some(AssocItemContainer::Trait(trait_)) => { + let params = f.db.generic_params(trait_.id.into()); + if f.show_container_bounds() && !params.is_empty() { + write_trait_header(&trait_, f)?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None + } + } + Some(AssocItemContainer::Impl(impl_)) => { + let params = f.db.generic_params(impl_.id.into()); + if f.show_container_bounds() && !params.is_empty() { + write_impl_header(&impl_, f)?; + f.write_char('\n')?; + has_disaplayable_predicates(¶ms).then_some(params) + } else { + None + } + } + None => None, + }; + + // Write signature of the function + + // Block-local impls are "hoisted" to the nearest (non-block) module. if let Some(AssocItemContainer::Impl(_)) = container { - // Block-local impls are "hoisted" to the nearest (non-block) module. module = module.nearest_non_block_module(db); } let module_id = module.id; + write_visibility(module_id, self.visibility(db), f)?; + if data.has_default_kw() { f.write_str("default ")?; } @@ -116,12 +149,41 @@ impl HirDisplay for Function { } } - write_where_clause(GenericDefId::FunctionId(self.id), f)?; - + // Write where clauses + let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?; + if let Some(container_params) = container_params { + if !has_written_where { + f.write_str("\nwhere")?; + } + let container_name = match container.unwrap() { + AssocItemContainer::Trait(_) => "trait", + AssocItemContainer::Impl(_) => "impl", + }; + write!(f, "\n // Bounds from {container_name}:",)?; + write_where_predicates(&container_params, f)?; + } Ok(()) } } +fn write_impl_header(impl_: &Impl, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + let db = f.db; + + f.write_str("impl")?; + let def_id = GenericDefId::ImplId(impl_.id); + write_generic_params(def_id, f)?; + + if let Some(trait_) = impl_.trait_(db) { + let trait_data = db.trait_data(trait_.id); + write!(f, " {} for", trait_data.name.display(db.upcast()))?; + } + + f.write_char(' ')?; + impl_.self_ty(db).hir_fmt(f)?; + + Ok(()) +} + impl HirDisplay for SelfParam { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { let data = f.db.function_data(self.func); @@ -188,7 +250,7 @@ impl HirDisplay for Struct { StructKind::Record => { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } } StructKind::Unit => _ = write_where_clause(def_id, f)?, @@ -208,7 +270,7 @@ impl HirDisplay for Enum { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_variants(&self.variants(f.db), has_where_clause, limit, f)?; + write_variants(&self.variants(f.db), has_where_clause, limit, f)?; } Ok(()) @@ -225,13 +287,13 @@ impl HirDisplay for Union { let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; + write_fields(&self.fields(f.db), has_where_clause, limit, false, f)?; } Ok(()) } } -fn display_fields( +fn write_fields( fields: &[Field], has_where_clause: bool, limit: usize, @@ -242,11 +304,7 @@ fn display_fields( let (indent, separator) = if in_line { ("", ' ') } else { (" ", '\n') }; f.write_char(if !has_where_clause { ' ' } else { separator })?; if count == 0 { - if fields.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + f.write_str(if fields.is_empty() { "{}" } else { "{ /* … */ }" })?; } else { f.write_char('{')?; @@ -255,14 +313,11 @@ fn display_fields( for field in &fields[..count] { f.write_str(indent)?; field.hir_fmt(f)?; - f.write_char(',')?; - f.write_char(separator)?; + write!(f, ",{separator}")?; } if fields.len() > count { - f.write_str(indent)?; - f.write_str("/* … */")?; - f.write_char(separator)?; + write!(f, "{indent}/* … */{separator}")?; } } @@ -272,7 +327,7 @@ fn display_fields( Ok(()) } -fn display_variants( +fn write_variants( variants: &[Variant], has_where_clause: bool, limit: usize, @@ -281,30 +336,22 @@ fn display_variants( let count = variants.len().min(limit); f.write_char(if !has_where_clause { ' ' } else { '\n' })?; if count == 0 { - if variants.is_empty() { - f.write_str("{}")?; - } else { - f.write_str("{ /* … */ }")?; - } + let variants = if variants.is_empty() { "{}" } else { "{ /* … */ }" }; + f.write_str(variants)?; } else { f.write_str("{\n")?; for variant in &variants[..count] { - f.write_str(" ")?; - write!(f, "{}", variant.name(f.db).display(f.db.upcast()))?; + write!(f, " {}", variant.name(f.db).display(f.db.upcast()))?; match variant.kind(f.db) { StructKind::Tuple => { - if variant.fields(f.db).is_empty() { - f.write_str("()")?; - } else { - f.write_str("( /* … */ )")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { "()" } else { "( /* … */ )" }; + f.write_str(fields_str)?; } StructKind::Record => { - if variant.fields(f.db).is_empty() { - f.write_str(" {}")?; - } else { - f.write_str(" { /* … */ }")?; - } + let fields_str = + if variant.fields(f.db).is_empty() { " {}" } else { " { /* … */ }" }; + f.write_str(fields_str)?; } StructKind::Unit => {} } @@ -357,7 +404,7 @@ impl HirDisplay for Variant { } VariantData::Record(_) => { if let Some(limit) = f.entity_limit { - display_fields(&self.fields(f.db), false, limit, true, f)?; + write_fields(&self.fields(f.db), false, limit, true, f)?; } } } @@ -554,102 +601,96 @@ fn write_where_clause( f: &mut HirFormatter<'_>, ) -> Result { let params = f.db.generic_params(def); + if !has_disaplayable_predicates(¶ms) { + return Ok(false); + } - // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. - let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target { - WherePredicateTypeTarget::TypeRef(_) => false, - WherePredicateTypeTarget::TypeOrConstParam(id) => { - params.type_or_consts[*id].name().is_none() - } - }; + f.write_str("\nwhere")?; + write_where_predicates(¶ms, f)?; - let has_displayable_predicate = params - .where_predicates - .iter() - .any(|pred| { - !matches!(pred, WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target)) - }); + Ok(true) +} - if !has_displayable_predicate { - return Ok(false); - } +fn has_disaplayable_predicates(params: &Interned) -> bool { + params.where_predicates.iter().any(|pred| { + !matches!( + pred, + WherePredicate::TypeBound { target: WherePredicateTypeTarget::TypeOrConstParam(id), .. } + if params.type_or_consts[*id].name().is_none() + ) + }) +} + +fn write_where_predicates( + params: &Interned, + f: &mut HirFormatter<'_>, +) -> Result<(), HirDisplayError> { + use WherePredicate::*; + + // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`. + let is_unnamed_type_target = + |params: &Interned, target: &WherePredicateTypeTarget| { + matches!(target, + WherePredicateTypeTarget::TypeOrConstParam(id) if params.type_or_consts[*id].name().is_none() + ) + }; let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter<'_>| match target { WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f), - WherePredicateTypeTarget::TypeOrConstParam(id) => { - match ¶ms.type_or_consts[*id].name() { - Some(name) => write!(f, "{}", name.display(f.db.upcast())), - None => f.write_str("{unnamed}"), - } - } + WherePredicateTypeTarget::TypeOrConstParam(id) => match params.type_or_consts[*id].name() { + Some(name) => write!(f, "{}", name.display(f.db.upcast())), + None => f.write_str("{unnamed}"), + }, }; - f.write_str("\nwhere")?; - - for (pred_idx, pred) in params.where_predicates.iter().enumerate() { - let prev_pred = - if pred_idx == 0 { None } else { Some(¶ms.where_predicates[pred_idx - 1]) }; + let check_same_target = |pred1: &WherePredicate, pred2: &WherePredicate| match (pred1, pred2) { + (TypeBound { target: t1, .. }, TypeBound { target: t2, .. }) => t1 == t2, + (Lifetime { target: t1, .. }, Lifetime { target: t2, .. }) => t1 == t2, + ( + ForLifetime { lifetimes: l1, target: t1, .. }, + ForLifetime { lifetimes: l2, target: t2, .. }, + ) => l1 == l2 && t1 == t2, + _ => false, + }; - let new_predicate = |f: &mut HirFormatter<'_>| { - f.write_str(if pred_idx == 0 { "\n " } else { ",\n " }) - }; + let mut iter = params.where_predicates.iter().peekable(); + while let Some(pred) = iter.next() { + if matches!(pred, TypeBound { target, .. } if is_unnamed_type_target(params, target)) { + continue; + } + f.write_str("\n ")?; match pred { - WherePredicate::TypeBound { target, .. } if is_unnamed_type_target(target) => {} - WherePredicate::TypeBound { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::TypeBound { target: target_, .. }) if target_ == target) - { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - write_target(target, f)?; - f.write_str(": ")?; - } + TypeBound { target, bound } => { + write_target(target, f)?; + f.write_str(": ")?; bound.hir_fmt(f)?; } - WherePredicate::Lifetime { target, bound } => { - if matches!(prev_pred, Some(WherePredicate::Lifetime { target: target_, .. }) if target_ == target) - { - write!(f, " + {}", bound.name.display(f.db.upcast()))?; - } else { - new_predicate(f)?; - write!( - f, - "{}: {}", - target.name.display(f.db.upcast()), - bound.name.display(f.db.upcast()) - )?; - } + Lifetime { target, bound } => { + let target = target.name.display(f.db.upcast()); + let bound = bound.name.display(f.db.upcast()); + write!(f, "{target}: {bound}")?; } - WherePredicate::ForLifetime { lifetimes, target, bound } => { - if matches!( - prev_pred, - Some(WherePredicate::ForLifetime { lifetimes: lifetimes_, target: target_, .. }) - if lifetimes_ == lifetimes && target_ == target, - ) { - f.write_str(" + ")?; - } else { - new_predicate(f)?; - f.write_str("for<")?; - for (idx, lifetime) in lifetimes.iter().enumerate() { - if idx != 0 { - f.write_str(", ")?; - } - write!(f, "{}", lifetime.display(f.db.upcast()))?; - } - f.write_str("> ")?; - write_target(target, f)?; - f.write_str(": ")?; - } + ForLifetime { lifetimes, target, bound } => { + let lifetimes = lifetimes.iter().map(|it| it.display(f.db.upcast())).join(", "); + write!(f, "for<{lifetimes}> ")?; + write_target(target, f)?; + f.write_str(": ")?; bound.hir_fmt(f)?; } } - } - // End of final predicate. There must be at least one predicate here. - f.write_char(',')?; + while let Some(nxt) = iter.next_if(|nxt| check_same_target(pred, nxt)) { + f.write_str(" + ")?; + match nxt { + TypeBound { bound, .. } | ForLifetime { bound, .. } => bound.hir_fmt(f)?, + Lifetime { bound, .. } => write!(f, "{}", bound.name.display(f.db.upcast()))?, + } + } + f.write_str(",")?; + } - Ok(true) + Ok(()) } impl HirDisplay for Const { @@ -689,17 +730,8 @@ impl HirDisplay for Static { impl HirDisplay for Trait { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { - write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; - let data = f.db.trait_data(self.id); - if data.is_unsafe { - f.write_str("unsafe ")?; - } - if data.is_auto { - f.write_str("auto ")?; - } - write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_trait_header(self, f)?; let def_id = GenericDefId::TraitId(self.id); - write_generic_params(def_id, f)?; let has_where_clause = write_where_clause(def_id, f)?; if let Some(limit) = f.entity_limit { @@ -735,6 +767,20 @@ impl HirDisplay for Trait { } } +fn write_trait_header(trait_: &Trait, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { + write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?; + let data = f.db.trait_data(trait_.id); + if data.is_unsafe { + f.write_str("unsafe ")?; + } + if data.is_auto { + f.write_str("auto ")?; + } + write!(f, "trait {}", data.name.display(f.db.upcast()))?; + write_generic_params(GenericDefId::TraitId(trait_.id), f)?; + Ok(()) +} + impl HirDisplay for TraitAlias { fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> { write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; diff --git a/src/tools/rust-analyzer/crates/hir/src/has_source.rs b/src/tools/rust-analyzer/crates/hir/src/has_source.rs index 7cdcdd76d1851..929c8b3c09e37 100644 --- a/src/tools/rust-analyzer/crates/hir/src/has_source.rs +++ b/src/tools/rust-analyzer/crates/hir/src/has_source.rs @@ -8,13 +8,14 @@ use hir_def::{ Lookup, MacroId, VariantId, }; use hir_expand::{HirFileId, InFile}; +use hir_ty::{db::InternedClosure, CallableDefId}; use syntax::ast; use tt::TextRange; use crate::{ - db::HirDatabase, Adt, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, - LifetimeParam, LocalSource, Macro, Module, Static, Struct, Trait, TraitAlias, TypeAlias, - TypeOrConstParam, Union, Variant, + db::HirDatabase, Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl, + Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static, Struct, Trait, + TraitAlias, TypeAlias, TypeOrConstParam, Union, Variant, }; pub trait HasSource { @@ -25,7 +26,7 @@ pub trait HasSource { /// /// The current some implementations can return `InFile` instead of `Option`. /// But we made this method `Option` to support rlib in the future - /// by https://github.com/rust-lang/rust-analyzer/issues/6913 + /// by fn source(self, db: &dyn HirDatabase) -> Option>; } @@ -202,7 +203,7 @@ impl HasSource for TypeOrConstParam { type Ast = Either; fn source(self, db: &dyn HirDatabase) -> Option> { let child_source = self.id.parent.child_source(db.upcast()); - Some(child_source.map(|it| it[self.id.local_id].clone())) + child_source.map(|it| it.get(self.id.local_id).cloned()).transpose() } } @@ -210,7 +211,7 @@ impl HasSource for LifetimeParam { type Ast = ast::LifetimeParam; fn source(self, db: &dyn HirDatabase) -> Option> { let child_source = self.id.parent.child_source(db.upcast()); - Some(child_source.map(|it| it[self.id.local_id].clone())) + child_source.map(|it| it.get(self.id.local_id).cloned()).transpose() } } @@ -222,6 +223,68 @@ impl HasSource for LocalSource { } } +impl HasSource for Param { + type Ast = Either; + + fn source(self, db: &dyn HirDatabase) -> Option> { + match self.func { + Callee::Def(CallableDefId::FunctionId(func)) => { + let InFile { file_id, value } = Function { id: func }.source(db)?; + let params = value.param_list()?; + if let Some(self_param) = params.self_param() { + if let Some(idx) = self.idx.checked_sub(1) { + params.params().nth(idx).map(Either::Right) + } else { + Some(Either::Left(self_param)) + } + } else { + params.params().nth(self.idx).map(Either::Right) + } + .map(|value| InFile { file_id, value }) + } + Callee::Closure(closure, _) => { + let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into()); + let (_, source_map) = db.body_with_source_map(owner); + let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; + let root = db.parse_or_expand(file_id); + match value.to_node(&root) { + ast::Expr::ClosureExpr(it) => it + .param_list()? + .params() + .nth(self.idx) + .map(Either::Right) + .map(|value| InFile { file_id: ast.file_id, value }), + _ => None, + } + } + _ => None, + } + } +} + +impl HasSource for SelfParam { + type Ast = ast::SelfParam; + + fn source(self, db: &dyn HirDatabase) -> Option> { + let InFile { file_id, value } = Function::from(self.func).source(db)?; + value + .param_list() + .and_then(|params| params.self_param()) + .map(|value| InFile { file_id, value }) + } +} + +impl HasSource for Label { + type Ast = ast::Label; + + fn source(self, db: &dyn HirDatabase) -> Option> { + let (_body, source_map) = db.body_with_source_map(self.parent); + let src = source_map.label_syntax(self.label_id); + let root = src.file_syntax(db.upcast()); + Some(src.map(|ast| ast.to_node(&root))) + } +} + impl HasSource for ExternCrateDecl { type Ast = ast::ExternCrate; diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs index 777be711a5e6e..c1fe8a8b316fe 100644 --- a/src/tools/rust-analyzer/crates/hir/src/lib.rs +++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs @@ -64,7 +64,6 @@ use hir_expand::{ use hir_ty::{ all_super_traits, autoderef, check_orphan_rules, consteval::{try_const_usize, unknown_const_as_generic, ConstExt}, - db::InternedClosure, diagnostics::BodyValidationDiagnostic, error_lifetime, known_const_to_ast, layout::{Layout as TyLayout, RustcEnumVariantIdx, RustcFieldIdx, TagEncoding}, @@ -113,7 +112,7 @@ pub use hir_ty::method_resolution::TyFingerprint; pub use { cfg::{CfgAtom, CfgExpr, CfgOptions}, hir_def::{ - attr::{builtin::AttributeTemplate, AttrSourceMap, Attrs, AttrsWithOwner}, + attr::{AttrSourceMap, Attrs, AttrsWithOwner}, data::adt::StructKind, find_path::PrefixKind, import_map, @@ -132,6 +131,7 @@ pub use { attrs::{Attr, AttrId}, change::ChangeWithProcMacros, hygiene::{marks_rev, SyntaxContextExt}, + inert_attr_macro::AttributeTemplate, name::{known, Name}, proc_macro::ProcMacros, tt, ExpandResult, HirFileId, HirFileIdExt, InFile, InMacroFile, InRealFile, MacroFileId, @@ -242,7 +242,7 @@ impl Crate { db: &dyn DefDatabase, query: import_map::Query, ) -> impl Iterator> { - let _p = tracing::span!(tracing::Level::INFO, "query_external_importables").entered(); + let _p = tracing::info_span!("query_external_importables").entered(); import_map::search_dependencies(db, self.into(), &query).into_iter().map(|item| { match ItemInNs::from(item) { ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id), @@ -551,8 +551,7 @@ impl Module { acc: &mut Vec, style_lints: bool, ) { - let _p = tracing::span!(tracing::Level::INFO, "Module::diagnostics", name = ?self.name(db)) - .entered(); + let _p = tracing::info_span!("Module::diagnostics", name = ?self.name(db)).entered(); let def_map = self.id.def_map(db.upcast()); for diag in def_map.diagnostics() { if diag.in_module != self.id.local_id { @@ -1099,6 +1098,35 @@ pub enum FieldSource { Pos(ast::TupleField), } +impl AstNode for FieldSource { + fn can_cast(kind: syntax::SyntaxKind) -> bool + where + Self: Sized, + { + ast::RecordField::can_cast(kind) || ast::TupleField::can_cast(kind) + } + + fn cast(syntax: SyntaxNode) -> Option + where + Self: Sized, + { + if ast::RecordField::can_cast(syntax.kind()) { + ::cast(syntax).map(FieldSource::Named) + } else if ast::TupleField::can_cast(syntax.kind()) { + ::cast(syntax).map(FieldSource::Pos) + } else { + None + } + } + + fn syntax(&self) -> &SyntaxNode { + match self { + FieldSource::Named(it) => it.syntax(), + FieldSource::Pos(it) => it.syntax(), + } + } +} + impl Field { pub fn name(&self, db: &dyn HirDatabase) -> Name { self.parent.variant_data(db).fields()[self.id].name.clone() @@ -1884,6 +1912,14 @@ impl Function { Type::from_value_def(db, self.id) } + pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type { + let resolver = self.id.resolver(db.upcast()); + let substs = TyBuilder::placeholder_subst(db, self.id); + let callable_sig = db.callable_item_signature(self.id.into()).substitute(Interner, &substs); + let ty = TyKind::Function(callable_sig.to_fn_ptr()).intern(Interner); + Type::new_with_resolver_inner(db, &resolver, ty) + } + /// Get this function's return type pub fn ret_type(self, db: &dyn HirDatabase) -> Type { let resolver = self.id.resolver(db.upcast()); @@ -2208,47 +2244,9 @@ impl Param { } } - pub fn pattern_source(&self, db: &dyn HirDatabase) -> Option { + pub fn pattern_source(self, db: &dyn HirDatabase) -> Option { self.source(db).and_then(|p| p.value.right()?.pat()) } - - pub fn source( - &self, - db: &dyn HirDatabase, - ) -> Option>> { - match self.func { - Callee::Def(CallableDefId::FunctionId(func)) => { - let InFile { file_id, value } = Function { id: func }.source(db)?; - let params = value.param_list()?; - if let Some(self_param) = params.self_param() { - if let Some(idx) = self.idx.checked_sub(1) { - params.params().nth(idx).map(Either::Right) - } else { - Some(Either::Left(self_param)) - } - } else { - params.params().nth(self.idx).map(Either::Right) - } - .map(|value| InFile { file_id, value }) - } - Callee::Closure(closure, _) => { - let InternedClosure(owner, expr_id) = db.lookup_intern_closure(closure.into()); - let (_, source_map) = db.body_with_source_map(owner); - let ast @ InFile { file_id, value } = source_map.expr_syntax(expr_id).ok()?; - let root = db.parse_or_expand(file_id); - match value.to_node(&root) { - ast::Expr::ClosureExpr(it) => it - .param_list()? - .params() - .nth(self.idx) - .map(Either::Right) - .map(|value| InFile { file_id: ast.file_id, value }), - _ => None, - } - } - _ => None, - } - } } #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] @@ -2272,14 +2270,6 @@ impl SelfParam { .unwrap_or(Access::Owned) } - pub fn source(&self, db: &dyn HirDatabase) -> Option> { - let InFile { file_id, value } = Function::from(self.func).source(db)?; - value - .param_list() - .and_then(|params| params.self_param()) - .map(|value| InFile { file_id, value }) - } - pub fn parent_fn(&self) -> Function { Function::from(self.func) } @@ -2414,9 +2404,9 @@ impl Const { let value_signed = i128::from_le_bytes(mir::pad16(b, matches!(s, Scalar::Int(_)))); if value >= 10 { - return Ok(format!("{} ({:#X})", value_signed, value)); + return Ok(format!("{value_signed} ({value:#X})")); } else { - return Ok(format!("{}", value_signed)); + return Ok(format!("{value_signed}")); } } } @@ -2746,6 +2736,12 @@ impl Macro { } } + pub fn is_asm_or_global_asm(&self, db: &dyn HirDatabase) -> bool { + matches!(self.id, MacroId::Macro2Id(it) if { + matches!(it.lookup(db.upcast()).expander, MacroExpander::BuiltIn(m) if m.is_asm()) + }) + } + pub fn is_attr(&self, db: &dyn HirDatabase) -> bool { matches!(self.kind(db), MacroKind::Attr) } @@ -2788,6 +2784,7 @@ impl From for ItemInNs { ModuleDef::Static(_) | ModuleDef::Const(_) | ModuleDef::Function(_) => { ItemInNs::Values(module_def) } + ModuleDef::Macro(it) => ItemInNs::Macros(it), _ => ItemInNs::Types(module_def), } } @@ -3381,7 +3378,7 @@ impl BuiltinAttr { } fn builtin(name: &str) -> Option { - hir_def::attr::builtin::find_builtin_attr_idx(name) + hir_expand::inert_attr_macro::find_builtin_attr_idx(name) .map(|idx| BuiltinAttr { krate: None, idx: idx as u32 }) } @@ -3389,14 +3386,18 @@ impl BuiltinAttr { // FIXME: Return a `Name` here match self.krate { Some(krate) => db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(), - None => SmolStr::new(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].name), + None => { + SmolStr::new(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name) + } } } pub fn template(&self, _: &dyn HirDatabase) -> Option { match self.krate { Some(_) => None, - None => Some(hir_def::attr::builtin::INERT_ATTRIBUTES[self.idx as usize].template), + None => { + Some(hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].template) + } } } } @@ -3440,13 +3441,6 @@ impl Label { let body = db.body(self.parent); body[self.label_id].name.clone() } - - pub fn source(self, db: &dyn HirDatabase) -> InFile { - let (_body, source_map) = db.body_with_source_map(self.parent); - let src = source_map.label_syntax(self.label_id); - let root = src.file_syntax(db.upcast()); - src.map(|ast| ast.to_node(&root)) - } } #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -4612,8 +4606,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(Function) -> Option, ) -> Option { - let _p = - tracing::span!(tracing::Level::INFO, "iterate_method_candidates_with_traits").entered(); + let _p = tracing::info_span!("iterate_method_candidates_with_traits").entered(); let mut slot = None; self.iterate_method_candidates_dyn( @@ -4662,8 +4655,7 @@ impl Type { name: Option<&Name>, callback: &mut dyn FnMut(AssocItemId) -> ControlFlow<()>, ) { - let _p = tracing::span!( - tracing::Level::INFO, + let _p = tracing::info_span!( "iterate_method_candidates_dyn", with_local_impls = traits_in_scope.len(), traits_in_scope = traits_in_scope.len(), @@ -4701,7 +4693,7 @@ impl Type { name: Option<&Name>, mut callback: impl FnMut(AssocItem) -> Option, ) -> Option { - let _p = tracing::span!(tracing::Level::INFO, "iterate_path_candidates").entered(); + let _p = tracing::info_span!("iterate_path_candidates").entered(); let mut slot = None; self.iterate_path_candidates_dyn( db, @@ -4768,7 +4760,7 @@ impl Type { &'a self, db: &'a dyn HirDatabase, ) -> impl Iterator + 'a { - let _p = tracing::span!(tracing::Level::INFO, "applicable_inherent_traits").entered(); + let _p = tracing::info_span!("applicable_inherent_traits").entered(); self.autoderef_(db) .filter_map(|ty| ty.dyn_trait()) .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id)) @@ -4776,7 +4768,7 @@ impl Type { } pub fn env_traits<'a>(&'a self, db: &'a dyn HirDatabase) -> impl Iterator + 'a { - let _p = tracing::span!(tracing::Level::INFO, "env_traits").entered(); + let _p = tracing::info_span!("env_traits").entered(); self.autoderef_(db) .filter(|ty| matches!(ty.kind(Interner), TyKind::Placeholder(_))) .flat_map(|ty| { diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs index 43de2a6ee7dc8..f6c88edbff74c 100644 --- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs +++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs @@ -19,7 +19,11 @@ use hir_def::{ AsMacroCall, DefWithBodyId, FunctionId, MacroId, TraitId, VariantId, }; use hir_expand::{ - attrs::collect_attrs, db::ExpandDatabase, files::InRealFile, name::AsName, ExpansionInfo, + attrs::collect_attrs, + builtin_fn_macro::{BuiltinFnLikeExpander, EagerExpander}, + db::ExpandDatabase, + files::InRealFile, + name::AsName, InMacroFile, MacroCallId, MacroFileId, MacroFileIdExt, }; use itertools::Itertools; @@ -132,9 +136,6 @@ pub struct SemanticsImpl<'db> { s2d_cache: RefCell, /// Rootnode to HirFileId cache root_to_file_cache: RefCell>, - // These 2 caches are mainly useful for semantic highlighting as nothing else descends a lot of tokens - // So we might wanna move them out into something specific for semantic highlighting - expansion_info_cache: RefCell>, /// MacroCall to its expansion's MacroFileId cache macro_call_cache: RefCell, MacroFileId>>, } @@ -295,7 +296,6 @@ impl<'db> SemanticsImpl<'db> { db, s2d_cache: Default::default(), root_to_file_cache: Default::default(), - expansion_info_cache: Default::default(), macro_call_cache: Default::default(), } } @@ -314,7 +314,58 @@ impl<'db> SemanticsImpl<'db> { pub fn expand(&self, macro_call: &ast::MacroCall) -> Option { let sa = self.analyze_no_infer(macro_call.syntax())?; - let file_id = sa.expand(self.db, InFile::new(sa.file_id, macro_call))?; + + let macro_call = InFile::new(sa.file_id, macro_call); + let file_id = if let Some(call) = + ::to_def(self, macro_call) + { + call.as_macro_file() + } else { + sa.expand(self.db, macro_call)? + }; + + let node = self.parse_or_expand(file_id.into()); + Some(node) + } + + /// Expands the macro if it isn't one of the built-in ones that expand to custom syntax or dummy + /// expansions. + pub fn expand_allowed_builtins(&self, macro_call: &ast::MacroCall) -> Option { + let sa = self.analyze_no_infer(macro_call.syntax())?; + + let macro_call = InFile::new(sa.file_id, macro_call); + let file_id = if let Some(call) = + ::to_def(self, macro_call) + { + call.as_macro_file() + } else { + sa.expand(self.db, macro_call)? + }; + let macro_call = self.db.lookup_intern_macro_call(file_id.macro_call_id); + + let skip = matches!( + macro_call.def.kind, + hir_expand::MacroDefKind::BuiltIn( + _, + BuiltinFnLikeExpander::Column + | BuiltinFnLikeExpander::File + | BuiltinFnLikeExpander::ModulePath + | BuiltinFnLikeExpander::Asm + | BuiltinFnLikeExpander::LlvmAsm + | BuiltinFnLikeExpander::GlobalAsm + | BuiltinFnLikeExpander::LogSyntax + | BuiltinFnLikeExpander::TraceMacros + | BuiltinFnLikeExpander::FormatArgs + | BuiltinFnLikeExpander::FormatArgsNl + | BuiltinFnLikeExpander::ConstFormatArgs, + ) | hir_expand::MacroDefKind::BuiltInEager(_, EagerExpander::CompileError) + ); + if skip { + // these macros expand to custom builtin syntax and/or dummy things, no point in + // showing these to the user + return None; + } + let node = self.parse_or_expand(file_id.into()); Some(node) } @@ -322,7 +373,7 @@ impl<'db> SemanticsImpl<'db> { /// If `item` has an attribute macro attached to it, expands it. pub fn expand_attr_macro(&self, item: &ast::Item) -> Option { let src = self.wrap_node_infile(item.clone()); - let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src))?; + let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?; Some(self.parse_or_expand(macro_call_id.as_file())) } @@ -341,9 +392,7 @@ impl<'db> SemanticsImpl<'db> { Some( calls .into_iter() - .map(|call| { - macro_call_to_macro_id(ctx, self.db.upcast(), call?).map(|id| Macro { id }) - }) + .map(|call| macro_call_to_macro_id(ctx, call?).map(|id| Macro { id })) .collect(), ) }) @@ -403,7 +452,7 @@ impl<'db> SemanticsImpl<'db> { pub fn is_attr_macro_call(&self, item: &ast::Item) -> bool { let file_id = self.find_file(item.syntax()).file_id; - let src = InFile::new(file_id, item.clone()); + let src = InFile::new(file_id, item); self.with_ctx(|ctx| ctx.item_to_macro_call(src).is_some()) } @@ -420,7 +469,7 @@ impl<'db> SemanticsImpl<'db> { let macro_call = InFile::new(file_id, actual_macro_call); let krate = resolver.krate(); let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { - resolver.resolve_path_as_macro_def(self.db.upcast(), &path, Some(MacroSubNs::Bang)) + resolver.resolve_path_as_macro_def(self.db.upcast(), path, Some(MacroSubNs::Bang)) })?; hir_expand::db::expand_speculative( self.db.upcast(), @@ -453,7 +502,7 @@ impl<'db> SemanticsImpl<'db> { token_to_map: SyntaxToken, ) -> Option<(SyntaxNode, SyntaxToken)> { let macro_call = self.wrap_node_infile(actual_macro_call.clone()); - let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call))?; + let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(macro_call.as_ref()))?; hir_expand::db::expand_speculative( self.db.upcast(), macro_call_id, @@ -705,8 +754,6 @@ impl<'db> SemanticsImpl<'db> { let parent = token.parent()?; let file_id = self.find_file(&parent).file_id.file_id()?; - let mut cache = self.expansion_info_cache.borrow_mut(); - // iterate related crates and find all include! invocations that include_file_id matches for (invoc, _) in self .db @@ -716,18 +763,32 @@ impl<'db> SemanticsImpl<'db> { .filter(|&(_, include_file_id)| include_file_id == file_id) { let macro_file = invoc.as_macro_file(); - let expansion_info = cache.entry(macro_file).or_insert_with(|| { - let exp_info = macro_file.expansion_info(self.db.upcast()); - - let InMacroFile { file_id, value } = exp_info.expanded(); - self.cache(value, file_id.into()); + let expansion_info = { + self.with_ctx(|ctx| { + ctx.cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| { + let exp_info = macro_file.expansion_info(self.db.upcast()); + + let InMacroFile { file_id, value } = exp_info.expanded(); + if let InFile { file_id, value: Some(value) } = exp_info.arg() { + self.cache(value.ancestors().last().unwrap(), file_id); + } + self.cache(value, file_id.into()); - exp_info - }); + exp_info + }) + .clone() + }) + }; // FIXME: uncached parse // Create the source analyzer for the macro call scope - let Some(sa) = self.analyze_no_infer(&self.parse_or_expand(expansion_info.call_file())) + let Some(sa) = expansion_info + .arg() + .value + .and_then(|it| self.analyze_no_infer(&it.ancestors().last().unwrap())) else { continue; }; @@ -758,7 +819,7 @@ impl<'db> SemanticsImpl<'db> { mut token: SyntaxToken, f: &mut dyn FnMut(InFile) -> ControlFlow<()>, ) { - let _p = tracing::span!(tracing::Level::INFO, "descend_into_macros_impl").entered(); + let _p = tracing::info_span!("descend_into_macros_impl").entered(); let (sa, span, file_id) = match token.parent().and_then(|parent| self.analyze_no_infer(&parent)) { Some(sa) => match sa.file_id.file_id() { @@ -785,23 +846,28 @@ impl<'db> SemanticsImpl<'db> { } }; - let mut cache = self.expansion_info_cache.borrow_mut(); - let mut mcache = self.macro_call_cache.borrow_mut(); + let mut m_cache = self.macro_call_cache.borrow_mut(); let def_map = sa.resolver.def_map(); let mut stack: Vec<(_, SmallVec<[_; 2]>)> = vec![(file_id, smallvec![token])]; - let mut process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { - let exp_info = cache.entry(macro_file).or_insert_with(|| { - let exp_info = macro_file.expansion_info(self.db.upcast()); - - let InMacroFile { file_id, value } = exp_info.expanded(); - self.cache(value, file_id.into()); - - exp_info - }); - - let InMacroFile { file_id, value: mapped_tokens } = exp_info.map_range_down(span)?; - let mapped_tokens: SmallVec<[_; 2]> = mapped_tokens.collect(); + let process_expansion_for_token = |stack: &mut Vec<_>, macro_file| { + let InMacroFile { file_id, value: mapped_tokens } = self.with_ctx(|ctx| { + Some( + ctx.cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| { + let exp_info = macro_file.expansion_info(self.db.upcast()); + + let InMacroFile { file_id, value } = exp_info.expanded(); + self.cache(value, file_id.into()); + + exp_info + }) + .map_range_down(span)? + .map(SmallVec::<[_; 2]>::from_iter), + ) + })?; // we have found a mapping for the token if the vec is non-empty let res = mapped_tokens.is_empty().not().then_some(()); @@ -818,10 +884,7 @@ impl<'db> SemanticsImpl<'db> { token.parent_ancestors().filter_map(ast::Item::cast).find_map(|item| { // Don't force populate the dyn cache for items that don't have an attribute anyways item.attrs().next()?; - Some(( - ctx.item_to_macro_call(InFile::new(file_id, item.clone()))?, - item, - )) + Some((ctx.item_to_macro_call(InFile::new(file_id, &item))?, item)) }) }); if let Some((call_id, item)) = containing_attribute_macro_call { @@ -874,13 +937,20 @@ impl<'db> SemanticsImpl<'db> { return None; } let macro_call = tt.syntax().parent().and_then(ast::MacroCall::cast)?; - let mcall: hir_expand::files::InFileWrapper = - InFile::new(file_id, macro_call); - let file_id = match mcache.get(&mcall) { + let mcall = InFile::new(file_id, macro_call); + let file_id = match m_cache.get(&mcall) { Some(&it) => it, None => { - let it = sa.expand(self.db, mcall.as_ref())?; - mcache.insert(mcall, it); + let it = if let Some(call) = + ::to_def( + self, + mcall.as_ref(), + ) { + call.as_macro_file() + } else { + sa.expand(self.db, mcall.as_ref())? + }; + m_cache.insert(mcall, it); it } }; @@ -953,6 +1023,13 @@ impl<'db> SemanticsImpl<'db> { let helpers = def_map.derive_helpers_in_scope(InFile::new(file_id, id))?; + if !helpers.is_empty() { + let text_range = attr.syntax().text_range(); + // remove any other token in this macro input, all their mappings are the + // same as this + tokens.retain(|t| !text_range.contains_range(t.text_range())); + } + let mut res = None; for (.., derive) in helpers.iter().filter(|(helper, ..)| *helper == attr_name) @@ -1056,16 +1133,20 @@ impl<'db> SemanticsImpl<'db> { node: SyntaxNode, ) -> impl Iterator + Clone + '_ { let node = self.find_file(&node); - let db = self.db.upcast(); iter::successors(Some(node.cloned()), move |&InFile { file_id, ref value }| { match value.parent() { Some(parent) => Some(InFile::new(file_id, parent)), None => { - let call_node = file_id.macro_file()?.call_node(db); - // cache the node - // FIXME: uncached parse - self.parse_or_expand(call_node.file_id); - Some(call_node) + let macro_file = file_id.macro_file()?; + + self.with_ctx(|ctx| { + let expansion_info = ctx + .cache + .expansion_info_cache + .entry(macro_file) + .or_insert_with(|| macro_file.expansion_info(self.db.upcast())); + expansion_info.arg().map(|node| node?.parent()).transpose() + }) } } }) @@ -1090,7 +1171,7 @@ impl<'db> SemanticsImpl<'db> { .find(|tp| tp.lifetime().as_ref().map(|lt| lt.text()).as_ref() == Some(&text)) })?; let src = self.wrap_node_infile(lifetime_param); - ToDef::to_def(self, src) + ToDef::to_def(self, src.as_ref()) } pub fn resolve_label(&self, lifetime: &ast::Lifetime) -> Option