diff --git a/src/tools/rust-analyzer/.git-blame-ignore-revs b/src/tools/rust-analyzer/.git-blame-ignore-revs
index 2ccdc8c042563..651502965ef7a 100644
--- a/src/tools/rust-analyzer/.git-blame-ignore-revs
+++ b/src/tools/rust-analyzer/.git-blame-ignore-revs
@@ -14,3 +14,4 @@ f247090558c9ba3c551566eae5882b7ca865225f
b2f6fd4f961fc7e4fbfdb80cae2e6065f8436f15
c48062fe2ab9a2d913d1985a6b0aec4bf936bfc1
f532576ac53ddcc666bc8d59e0b6437065e2f599
+4704881b641884de50645637108b6b6f5b68aaf9
diff --git a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
index 5258d9ddd3ad0..e4fa94643ba19 100644
--- a/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/autopublish.yaml
@@ -11,6 +11,7 @@ on:
jobs:
publish:
+ if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event.action == 'workflow_dispatch' }}
name: publish
runs-on: ubuntu-latest
steps:
diff --git a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
index f1533bf26e52b..5023a634fde42 100644
--- a/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/publish-libs.yaml
@@ -9,6 +9,7 @@ on:
jobs:
publish-libs:
+ if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event.action == 'workflow_dispatch' }}
name: publish
runs-on: ubuntu-latest
steps:
diff --git a/src/tools/rust-analyzer/.github/workflows/release.yaml b/src/tools/rust-analyzer/.github/workflows/release.yaml
index 39ac652de0f86..3f1c8b2a9c1ce 100644
--- a/src/tools/rust-analyzer/.github/workflows/release.yaml
+++ b/src/tools/rust-analyzer/.github/workflows/release.yaml
@@ -22,6 +22,7 @@ env:
jobs:
dist:
+ if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event.action == 'workflow_dispatch' }}
strategy:
matrix:
include:
@@ -138,6 +139,7 @@ jobs:
path: ./dist
dist-x86_64-unknown-linux-musl:
+ if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event.action == 'workflow_dispatch' }}
name: dist (x86_64-unknown-linux-musl)
runs-on: ubuntu-latest
env:
@@ -183,6 +185,7 @@ jobs:
path: ./dist
publish:
+ if: ${{ github.repository == 'rust-lang/rust-analyzer' || github.event.action == 'workflow_dispatch' }}
name: publish
runs-on: ubuntu-latest
needs: ["dist", "dist-x86_64-unknown-linux-musl"]
@@ -257,24 +260,24 @@ jobs:
working-directory: ./editors/code
- name: Publish Extension (Code Marketplace, release)
- if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
+ if: github.ref == 'refs/heads/release' && github.repository == 'rust-lang/rust-analyzer'
working-directory: ./editors/code
# token from https://dev.azure.com/rust-analyzer/
run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
- name: Publish Extension (OpenVSX, release)
- if: github.ref == 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
+ if: github.ref == 'refs/heads/release' && github.repository == 'rust-lang/rust-analyzer'
working-directory: ./editors/code
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
timeout-minutes: 2
- name: Publish Extension (Code Marketplace, nightly)
- if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
+ if: github.ref != 'refs/heads/release' && github.repository == 'rust-lang/rust-analyzer'
working-directory: ./editors/code
run: npx vsce publish --pat ${{ secrets.MARKETPLACE_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix --pre-release
- name: Publish Extension (OpenVSX, nightly)
- if: github.ref != 'refs/heads/release' && (github.repository == 'rust-analyzer/rust-analyzer' || github.repository == 'rust-lang/rust-analyzer')
+ if: github.ref != 'refs/heads/release' && github.repository == 'rust-lang/rust-analyzer'
working-directory: ./editors/code
run: npx ovsx publish --pat ${{ secrets.OPENVSX_TOKEN }} --packagePath ../../dist/rust-analyzer-*.vsix
timeout-minutes: 2
diff --git a/src/tools/rust-analyzer/.gitignore b/src/tools/rust-analyzer/.gitignore
index c4470a45078a2..7192e685e29bf 100644
--- a/src/tools/rust-analyzer/.gitignore
+++ b/src/tools/rust-analyzer/.gitignore
@@ -6,10 +6,11 @@ target/
*.log
*.iml
.vscode/settings.json
-generated_assists.adoc
-generated_features.adoc
-generated_diagnostic.adoc
.DS_Store
/out/
/dump.lsif
.envrc
+docs/book/book
+docs/book/src/assists_generated.md
+docs/book/src/diagnostics_generated.md
+docs/book/src/features_generated.md
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index 2dfca7c4803e2..98268d8f84449 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -1408,9 +1408,9 @@ dependencies = [
[[package]]
name = "proc-macro2"
-version = "1.0.86"
+version = "1.0.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77"
+checksum = "60946a68e5f9d28b0dc1c21bb8a97ee7d018a8b322fa57838ba31cc878e22d99"
dependencies = [
"unicode-ident",
]
@@ -1514,9 +1514,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_abi"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d5246e9e1f450333a990877eabbc36fe0567e7cedd56d5365db319e14079cf2a"
+checksum = "2fa4333df7b71217edb44a36702cafd2bcfc9850677bdf78b32c9f2c98e5df40"
dependencies = [
"bitflags 2.7.0",
"ra-ap-rustc_index",
@@ -1525,9 +1525,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "59fd8e4f5b34c434ec111efb0e0614954db048b9307d3b2e4cc3c915da9d2160"
+checksum = "d200275ff3d952cc11108f4dc6a692473659758623d63f2bdcea6104a7f1cec8"
dependencies = [
"ra-ap-rustc_index_macros",
"smallvec",
@@ -1535,9 +1535,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_index_macros"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2d34973fe081392bd1edb022e865e9952fcaa093f9cdae183edce64472e5e889"
+checksum = "06eb63df8c1ce2dcb07647305bed811c9c5ebd157def01a81c1b9479b8592b3b"
dependencies = [
"proc-macro2",
"quote",
@@ -1546,19 +1546,20 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_lexer"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "52fa42c582e21b35e8f61a5afe3c63a9c722d995826762eb19b18beeccf5157f"
+checksum = "b7a4d402b2f85650e8c1f78e2e2defc241b03948d6e30d9f5254c9b82755cc4d"
dependencies = [
+ "memchr",
"unicode-properties",
"unicode-xid",
]
[[package]]
name = "ra-ap-rustc_parse_format"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "740383328d7033393e5385f4a6073b880d5811b0fc0fd2559e481f905940f2f8"
+checksum = "a23a382dbe392beb26360c1a8ce9193155ef74eeac59bcda0fa0a233e047323a"
dependencies = [
"ra-ap-rustc_index",
"ra-ap-rustc_lexer",
@@ -1566,9 +1567,9 @@ dependencies = [
[[package]]
name = "ra-ap-rustc_pattern_analysis"
-version = "0.91.0"
+version = "0.94.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c39f544728f32cebffb1a8b92ba3c1f3dcb4144081438d192137ed197d479a9d"
+checksum = "d746955d67f315ab79767f1d0bbc17fee4f0970d4a00b9ad76bf09cc7d3cd17e"
dependencies = [
"ra-ap-rustc_index",
"rustc-hash 2.0.0",
@@ -2001,9 +2002,9 @@ dependencies = [
[[package]]
name = "tenthash"
-version = "0.4.0"
+version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d67f9f3cf70e0852941d7bc3cb884b49b24b8ee956baf91ad0abae31f5ef11fb"
+checksum = "2d092d622df8bb64e5de8dc86a3667702d5f1e0fe2f0604c6035540703c8cd1e"
[[package]]
name = "test-fixture"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index c42ae171d8668..44c628e8294d1 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -87,11 +87,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
vfs = { path = "./crates/vfs", version = "0.0.0" }
edition = { path = "./crates/edition", version = "0.0.0" }
-ra-ap-rustc_lexer = { version = "0.91", default-features = false }
-ra-ap-rustc_parse_format = { version = "0.91", default-features = false }
-ra-ap-rustc_index = { version = "0.91", default-features = false }
-ra-ap-rustc_abi = { version = "0.91", default-features = false }
-ra-ap-rustc_pattern_analysis = { version = "0.91", default-features = false }
+ra-ap-rustc_lexer = { version = "0.94", default-features = false }
+ra-ap-rustc_parse_format = { version = "0.94", default-features = false }
+ra-ap-rustc_index = { version = "0.94", default-features = false }
+ra-ap-rustc_abi = { version = "0.94", default-features = false }
+ra-ap-rustc_pattern_analysis = { version = "0.94", default-features = false }
# local crates that aren't published to crates.io. These should not have versions.
diff --git a/src/tools/rust-analyzer/PRIVACY.md b/src/tools/rust-analyzer/PRIVACY.md
index 89e252be731d0..ef9c2437ab7d3 100644
--- a/src/tools/rust-analyzer/PRIVACY.md
+++ b/src/tools/rust-analyzer/PRIVACY.md
@@ -1 +1 @@
-See the [Privacy](https://rust-analyzer.github.io/manual.html#privacy) section of the user manual.
+See the [Privacy](https://rust-analyzer.github.io/book/privacy.html) section of the user manual.
diff --git a/src/tools/rust-analyzer/README.md b/src/tools/rust-analyzer/README.md
index 552f71f151847..56883723c93e0 100644
--- a/src/tools/rust-analyzer/README.md
+++ b/src/tools/rust-analyzer/README.md
@@ -1,6 +1,6 @@
@@ -9,7 +9,7 @@ It is a part of a larger rls-2.0 effort to create excellent IDE support for Rust
## Quick Start
-https://rust-analyzer.github.io/manual.html#installation
+https://rust-analyzer.github.io/book/installation.html
## Documentation
@@ -18,12 +18,13 @@ if you are just curious about how things work under the hood, check the [./docs/
folder.
If you want to **use** rust-analyzer's language server with your editor of
-choice, check [the manual](https://rust-analyzer.github.io/manual.html) folder.
+choice, check [the manual](https://rust-analyzer.github.io/book/).
It also contains some tips & tricks to help you be more productive when using rust-analyzer.
## Security and Privacy
-See the corresponding sections of [the manual](https://rust-analyzer.github.io/manual.html#security).
+See the [security](https://rust-analyzer.github.io/book/security.html) and
+[privacy](https://rust-analyzer.github.io/book/privacy.html) sections of the manual.
## Communication
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 a0fc8c31eaf62..c2cea07190586 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -129,9 +129,9 @@ impl fmt::Display for CrateName {
}
impl ops::Deref for CrateName {
- type Target = str;
- fn deref(&self) -> &str {
- self.0.as_str()
+ type Target = Symbol;
+ fn deref(&self) -> &Symbol {
+ &self.0
}
}
@@ -230,8 +230,8 @@ impl fmt::Display for CrateDisplayName {
}
impl ops::Deref for CrateDisplayName {
- type Target = str;
- fn deref(&self) -> &str {
+ type Target = Symbol;
+ fn deref(&self) -> &Symbol {
&self.crate_name
}
}
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 12f5f6ad79abe..c5bbd4edba9e4 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/data.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/data.rs
@@ -95,10 +95,14 @@ impl FunctionData {
.map(Box::new);
let rustc_allow_incoherent_impl = attrs.by_key(&sym::rustc_allow_incoherent_impl).exists();
if flags.contains(FnFlags::HAS_UNSAFE_KW)
- && !crate_graph[krate].edition.at_least_2024()
&& attrs.by_key(&sym::rustc_deprecated_safe_2024).exists()
{
flags.remove(FnFlags::HAS_UNSAFE_KW);
+ flags.insert(FnFlags::DEPRECATED_SAFE_2024);
+ }
+
+ if attrs.by_key(&sym::target_feature).exists() {
+ flags.insert(FnFlags::HAS_TARGET_FEATURE);
}
Arc::new(FunctionData {
@@ -148,6 +152,10 @@ impl FunctionData {
self.flags.contains(FnFlags::HAS_UNSAFE_KW)
}
+ pub fn is_deprecated_safe_2024(&self) -> bool {
+ self.flags.contains(FnFlags::DEPRECATED_SAFE_2024)
+ }
+
pub fn is_safe(&self) -> bool {
self.flags.contains(FnFlags::HAS_SAFE_KW)
}
@@ -155,6 +163,10 @@ impl FunctionData {
pub fn is_varargs(&self) -> bool {
self.flags.contains(FnFlags::IS_VARARGS)
}
+
+ pub fn has_target_feature(&self) -> bool {
+ self.flags.contains(FnFlags::HAS_TARGET_FEATURE)
+ }
}
fn parse_rustc_legacy_const_generics(tt: &crate::tt::TopSubtree) -> Box<[u32]> {
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 bf6cc1dcadec5..598a850898bb6 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/db.rs
@@ -10,12 +10,12 @@ use triomphe::Arc;
use crate::{
attr::{Attrs, AttrsWithOwner},
- body::{scope::ExprScopes, Body, BodySourceMap},
data::{
adt::{EnumData, EnumVariantData, StructData, VariantData},
ConstData, ExternCrateDeclData, FunctionData, ImplData, Macro2Data, MacroRulesData,
ProcMacroData, StaticData, TraitAliasData, TraitData, TypeAliasData,
},
+ expr_store::{scope::ExprScopes, Body, BodySourceMap},
generics::GenericParams,
import_map::ImportMap,
item_tree::{AttrOwner, ItemTree, ItemTreeSourceMaps},
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
similarity index 72%
rename from src/tools/rust-analyzer/crates/hir-def/src/body.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
index de43924930632..9df6eaade757a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store.rs
@@ -1,18 +1,19 @@
-//! Defines `Body`: a lowered representation of bodies of functions, statics and
+//! Defines `ExpressionStore`: a lowered representation of functions, statics and
//! consts.
+mod body;
mod lower;
mod pretty;
pub mod scope;
+
#[cfg(test)]
mod tests;
use std::ops::{Deref, Index};
-use base_db::CrateId;
use cfg::{CfgExpr, CfgOptions};
use either::Either;
use hir_expand::{name::Name, ExpandError, InFile};
-use la_arena::{Arena, ArenaMap, Idx, RawIdx};
+use la_arena::{Arena, ArenaMap};
use rustc_hash::FxHashMap;
use smallvec::SmallVec;
use span::{Edition, MacroFileId, SyntaxContextData};
@@ -22,19 +23,18 @@ use tt::TextRange;
use crate::{
db::DefDatabase,
- expander::Expander,
hir::{
- dummy_expr_id, Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label,
- LabelId, Pat, PatId, RecordFieldPat, Statement,
+ Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
+ PatId, RecordFieldPat, Statement,
},
- item_tree::AttrOwner,
nameres::DefMap,
path::{ModPath, Path},
- src::HasSource,
type_ref::{TypeRef, TypeRefId, TypesMap, TypesSourceMap},
- BlockId, DefWithBodyId, HasModule, Lookup, SyntheticSyntax,
+ BlockId, DefWithBodyId, Lookup, SyntheticSyntax,
};
+pub use self::body::{Body, BodySourceMap};
+
/// A wrapper around [`span::SyntaxContextId`] that is intended only for comparisons.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub struct HygieneId(span::SyntaxContextId);
@@ -58,9 +58,29 @@ impl HygieneId {
}
}
-/// The body of an item (function, const etc.).
+pub type ExprPtr = AstPtr;
+pub type ExprSource = InFile;
+
+pub type PatPtr = AstPtr;
+pub type PatSource = InFile;
+
+pub type LabelPtr = AstPtr;
+pub type LabelSource = InFile;
+
+pub type FieldPtr = AstPtr;
+pub type FieldSource = InFile;
+
+pub type PatFieldPtr = AstPtr>;
+pub type PatFieldSource = InFile;
+
+pub type ExprOrPatPtr = AstPtr>;
+pub type ExprOrPatSource = InFile;
+
+pub type SelfParamPtr = AstPtr;
+pub type MacroCallPtr = AstPtr;
+
#[derive(Debug, Eq, PartialEq)]
-pub struct Body {
+pub struct ExpressionStore {
pub exprs: Arena,
pub pats: Arena,
pub bindings: Arena,
@@ -68,19 +88,9 @@ pub struct Body {
/// Id of the closure/coroutine that owns the corresponding binding. If a binding is owned by the
/// top level expression, it will not be listed in here.
pub binding_owners: FxHashMap,
- /// The patterns for the function's parameters. While the parameter types are
- /// part of the function signature, the patterns are not (they don't change
- /// the external type of the function).
- ///
- /// If this `Body` is for the body of a constant, this will just be
- /// empty.
- pub params: Box<[PatId]>,
- pub self_param: Option,
- /// The `ExprId` of the actual body expression.
- pub body_expr: ExprId,
pub types: TypesMap,
- /// Block expressions in this body that may contain inner items.
- block_scopes: Vec,
+ /// Block expressions in this store that may contain inner items.
+ block_scopes: Box<[BlockId]>,
/// A map from binding to its hygiene ID.
///
@@ -92,44 +102,13 @@ pub struct Body {
binding_hygiene: FxHashMap,
/// A map from an variable usages to their hygiene ID.
///
- /// Expressions that can be recorded here are single segment path, although not all single segments path refer
+ /// Expressions (and destructuing patterns) that can be recorded here are single segment path, although not all single segments path refer
/// to variables and have hygiene (some refer to items, we don't know at this stage).
- expr_hygiene: FxHashMap,
- /// A map from a destructuring assignment possible variable usages to their hygiene ID.
- pat_hygiene: FxHashMap,
+ ident_hygiene: FxHashMap,
}
-pub type ExprPtr = AstPtr;
-pub type ExprSource = InFile;
-
-pub type PatPtr = AstPtr;
-pub type PatSource = InFile;
-
-pub type LabelPtr = AstPtr;
-pub type LabelSource = InFile;
-
-pub type FieldPtr = AstPtr;
-pub type FieldSource = InFile;
-
-pub type PatFieldPtr = AstPtr>;
-pub type PatFieldSource = InFile;
-
-pub type ExprOrPatPtr = AstPtr>;
-pub type ExprOrPatSource = InFile;
-
-/// An item body together with the mapping from syntax nodes to HIR expression
-/// IDs. This is needed to go from e.g. a position in a file to the HIR
-/// expression containing it; but for type inference etc., we want to operate on
-/// a structure that is agnostic to the actual positions of expressions in the
-/// file, so that we don't recompute types whenever some whitespace is typed.
-///
-/// One complication here is that, due to macro expansion, a single `Body` might
-/// be spread across several files. So, for each ExprId and PatId, we record
-/// both the HirFileId and the position inside the file. However, we only store
-/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
-/// this properly for macros.
-#[derive(Default, Debug, Eq, PartialEq)]
-pub struct BodySourceMap {
+#[derive(Debug, Eq, PartialEq, Default)]
+pub struct ExpressionStoreSourceMap {
// AST expressions can create patterns in destructuring assignments. Therefore, `ExprSource` can also map
// to `PatId`, and `PatId` can also map to `ExprSource` (the other way around is unaffected).
expr_map: FxHashMap,
@@ -141,7 +120,6 @@ pub struct BodySourceMap {
label_map: FxHashMap,
label_map_back: ArenaMap,
- self_param: Option>>,
binding_definitions: FxHashMap>,
/// We don't create explicit nodes for record fields (`S { record_field: 92 }`).
@@ -153,11 +131,25 @@ pub struct BodySourceMap {
template_map: Option>,
- expansions: FxHashMap>, MacroFileId>,
+ expansions: FxHashMap, MacroFileId>,
- /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
+ /// Diagnostics accumulated during lowering. These contain `AstPtr`s and so are stored in
/// the source map (since they're just as volatile).
- diagnostics: Vec,
+ diagnostics: Vec,
+}
+
+/// The body of an item (function, const etc.).
+#[derive(Debug, Eq, PartialEq, Default)]
+pub struct ExpressionStoreBuilder {
+ pub exprs: Arena,
+ pub pats: Arena,
+ pub bindings: Arena,
+ pub labels: Arena,
+ pub binding_owners: FxHashMap,
+ pub types: TypesMap,
+ block_scopes: Vec,
+ binding_hygiene: FxHashMap,
+ ident_hygiene: FxHashMap,
}
#[derive(Default, Debug, Eq, PartialEq)]
@@ -171,166 +163,62 @@ struct FormatTemplate {
/// The value stored for each capture is its template literal and offset inside it. The template literal
/// is from the `format_args[_nl]!()` macro and so needs to be mapped up once to go to the user-written
/// template.
- implicit_capture_to_source: FxHashMap, TextRange)>>,
+ implicit_capture_to_source: FxHashMap>,
}
#[derive(Debug, Eq, PartialEq)]
-pub enum BodyDiagnostic {
+pub enum ExpressionStoreDiagnostics {
InactiveCode { node: InFile, cfg: CfgExpr, opts: CfgOptions },
- MacroError { node: InFile>, err: ExpandError },
- UnresolvedMacroCall { node: InFile>, path: ModPath },
+ MacroError { node: InFile, err: ExpandError },
+ UnresolvedMacroCall { node: InFile, path: ModPath },
UnreachableLabel { node: InFile>, name: Name },
AwaitOutsideOfAsync { node: InFile>, location: String },
UndeclaredLabel { node: InFile>, name: Name },
}
-impl Body {
- pub(crate) fn body_with_source_map_query(
- db: &dyn DefDatabase,
- def: DefWithBodyId,
- ) -> (Arc, Arc) {
- let _p = tracing::info_span!("body_with_source_map_query").entered();
- let mut params = None;
-
- let mut is_async_fn = false;
- let InFile { file_id, value: body } = {
- match def {
- DefWithBodyId::FunctionId(f) => {
- let data = db.function_data(f);
- let f = f.lookup(db);
- let src = f.source(db);
- params = src.value.param_list().map(move |param_list| {
- let item_tree = f.id.item_tree(db);
- let func = &item_tree[f.id.value];
- let krate = f.container.module(db).krate;
- let crate_graph = db.crate_graph();
- (
- param_list,
- (0..func.params.len()).map(move |idx| {
- item_tree
- .attrs(
- db,
- krate,
- AttrOwner::Param(
- f.id.value,
- Idx::from_raw(RawIdx::from(idx as u32)),
- ),
- )
- .is_cfg_enabled(&crate_graph[krate].cfg_options)
- }),
- )
- });
- is_async_fn = data.is_async();
- src.map(|it| it.body().map(ast::Expr::from))
- }
- DefWithBodyId::ConstId(c) => {
- let c = c.lookup(db);
- let src = c.source(db);
- src.map(|it| it.body())
- }
- DefWithBodyId::StaticId(s) => {
- let s = s.lookup(db);
- let src = s.source(db);
- src.map(|it| it.body())
- }
- DefWithBodyId::VariantId(v) => {
- let s = v.lookup(db);
- let src = s.source(db);
- src.map(|it| it.expr())
- }
- DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()),
- }
- };
- let module = def.module(db);
- let expander = Expander::new(db, file_id, module);
- let (mut body, mut source_map) =
- Body::new(db, def, expander, params, body, module.krate, is_async_fn);
- body.shrink_to_fit();
- source_map.shrink_to_fit();
-
- (Arc::new(body), Arc::new(source_map))
- }
-
- pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc {
- db.body_with_source_map(def).0
- }
-
- /// Returns an iterator over all block expressions in this body that define inner items.
- pub fn blocks<'a>(
- &'a self,
- db: &'a dyn DefDatabase,
- ) -> impl Iterator- )> + 'a {
- self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
- }
-
- pub fn pretty_print(
- &self,
- db: &dyn DefDatabase,
- owner: DefWithBodyId,
- edition: Edition,
- ) -> String {
- pretty::print_body_hir(db, self, owner, edition)
- }
-
- pub fn pretty_print_expr(
- &self,
- db: &dyn DefDatabase,
- owner: DefWithBodyId,
- expr: ExprId,
- edition: Edition,
- ) -> String {
- pretty::print_expr_hir(db, self, owner, expr, edition)
- }
-
- pub fn pretty_print_pat(
- &self,
- db: &dyn DefDatabase,
- owner: DefWithBodyId,
- pat: PatId,
- oneline: bool,
- edition: Edition,
- ) -> String {
- pretty::print_pat_hir(db, self, owner, pat, oneline, edition)
- }
-
- fn new(
- db: &dyn DefDatabase,
- owner: DefWithBodyId,
- expander: Expander,
- params: Option<(ast::ParamList, impl Iterator
- )>,
- body: Option
,
- krate: CrateId,
- is_async_fn: bool,
- ) -> (Body, BodySourceMap) {
- lower::lower(db, owner, expander, params, body, krate, is_async_fn)
- }
-
- fn shrink_to_fit(&mut self) {
+impl ExpressionStoreBuilder {
+ fn finish(self) -> ExpressionStore {
let Self {
- body_expr: _,
- params: _,
- self_param: _,
block_scopes,
- exprs,
- labels,
- pats,
- bindings,
- binding_owners,
- binding_hygiene,
- expr_hygiene,
- pat_hygiene,
- types,
+ mut exprs,
+ mut labels,
+ mut pats,
+ mut bindings,
+ mut binding_owners,
+ mut binding_hygiene,
+ mut ident_hygiene,
+ mut types,
} = self;
- block_scopes.shrink_to_fit();
exprs.shrink_to_fit();
labels.shrink_to_fit();
pats.shrink_to_fit();
bindings.shrink_to_fit();
binding_owners.shrink_to_fit();
binding_hygiene.shrink_to_fit();
- expr_hygiene.shrink_to_fit();
- pat_hygiene.shrink_to_fit();
+ ident_hygiene.shrink_to_fit();
types.shrink_to_fit();
+
+ ExpressionStore {
+ exprs,
+ pats,
+ bindings,
+ labels,
+ binding_owners,
+ types,
+ block_scopes: block_scopes.into_boxed_slice(),
+ binding_hygiene,
+ ident_hygiene,
+ }
+ }
+}
+
+impl ExpressionStore {
+ /// Returns an iterator over all block expressions in this store that define inner items.
+ pub fn blocks<'a>(
+ &'a self,
+ db: &'a dyn DefDatabase,
+ ) -> impl Iterator- )> + 'a {
+ self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
}
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
@@ -658,11 +546,11 @@ impl Body {
}
pub fn expr_path_hygiene(&self, expr: ExprId) -> HygieneId {
- self.expr_hygiene.get(&expr).copied().unwrap_or(HygieneId::ROOT)
+ self.ident_hygiene.get(&expr.into()).copied().unwrap_or(HygieneId::ROOT)
}
pub fn pat_path_hygiene(&self, pat: PatId) -> HygieneId {
- self.pat_hygiene.get(&pat).copied().unwrap_or(HygieneId::ROOT)
+ self.ident_hygiene.get(&pat.into()).copied().unwrap_or(HygieneId::ROOT)
}
pub fn expr_or_pat_path_hygiene(&self, id: ExprOrPatId) -> HygieneId {
@@ -673,27 +561,7 @@ impl Body {
}
}
-impl Default for Body {
- fn default() -> Self {
- Self {
- body_expr: dummy_expr_id(),
- exprs: Default::default(),
- pats: Default::default(),
- bindings: Default::default(),
- labels: Default::default(),
- params: Default::default(),
- block_scopes: Default::default(),
- binding_owners: Default::default(),
- self_param: Default::default(),
- binding_hygiene: Default::default(),
- expr_hygiene: Default::default(),
- pat_hygiene: Default::default(),
- types: Default::default(),
- }
- }
-}
-
-impl Index
for Body {
+impl Index for ExpressionStore {
type Output = Expr;
fn index(&self, expr: ExprId) -> &Expr {
@@ -701,7 +569,7 @@ impl Index for Body {
}
}
-impl Index for Body {
+impl Index for ExpressionStore {
type Output = Pat;
fn index(&self, pat: PatId) -> &Pat {
@@ -709,7 +577,7 @@ impl Index for Body {
}
}
-impl Index for Body {
+impl Index for ExpressionStore {
type Output = Label;
fn index(&self, label: LabelId) -> &Label {
@@ -717,7 +585,7 @@ impl Index for Body {
}
}
-impl Index for Body {
+impl Index for ExpressionStore {
type Output = Binding;
fn index(&self, b: BindingId) -> &Binding {
@@ -725,7 +593,7 @@ impl Index for Body {
}
}
-impl Index for Body {
+impl Index for ExpressionStore {
type Output = TypeRef;
fn index(&self, b: TypeRefId) -> &TypeRef {
@@ -735,7 +603,7 @@ impl Index for Body {
// FIXME: Change `node_` prefix to something more reasonable.
// Perhaps `expr_syntax` and `expr_id`?
-impl BodySourceMap {
+impl ExpressionStoreSourceMap {
pub fn expr_or_pat_syntax(&self, id: ExprOrPatId) -> Result {
match id {
ExprOrPatId::ExprId(id) => self.expr_syntax(id).map(|it| it.map(AstPtr::wrap_left)),
@@ -757,9 +625,7 @@ impl BodySourceMap {
self.expansions.get(&src).cloned()
}
- pub fn macro_calls(
- &self,
- ) -> impl Iterator- >, MacroFileId)> + '_ {
+ pub fn macro_calls(&self) -> impl Iterator
- , MacroFileId)> + '_ {
self.expansions.iter().map(|(&a, &b)| (a, b))
}
@@ -767,10 +633,6 @@ impl BodySourceMap {
self.pat_map_back.get(pat).cloned().ok_or(SyntheticSyntax)
}
- pub fn self_param_syntax(&self) -> Option
>> {
- self.self_param
- }
-
pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option {
self.pat_map.get(&node.map(AstPtr::new)).cloned()
}
@@ -801,9 +663,7 @@ impl BodySourceMap {
self.expr_map.get(&src).copied()
}
- pub fn expansions(
- &self,
- ) -> impl Iterator- >, &MacroFileId)> {
+ pub fn expansions(&self) -> impl Iterator
- , &MacroFileId)> {
self.expansions.iter()
}
@@ -823,7 +683,7 @@ impl BodySourceMap {
pub fn format_args_implicit_capture(
&self,
capture_expr: ExprId,
- ) -> Option
, TextRange)>> {
+ ) -> Option> {
self.template_map.as_ref()?.implicit_capture_to_source.get(&capture_expr).copied()
}
@@ -837,14 +697,13 @@ impl BodySourceMap {
.zip(self.template_map.as_ref()?.asm_to_captures.get(&expr).map(std::ops::Deref::deref))
}
- /// Get a reference to the body source map's diagnostics.
- pub fn diagnostics(&self) -> &[BodyDiagnostic] {
+ /// Get a reference to the source map's diagnostics.
+ pub fn diagnostics(&self) -> &[ExpressionStoreDiagnostics] {
&self.diagnostics
}
fn shrink_to_fit(&mut self) {
let Self {
- self_param: _,
expr_map,
expr_map_back,
pat_map,
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs
new file mode 100644
index 0000000000000..a55fec4f8b1e1
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/body.rs
@@ -0,0 +1,175 @@
+//! Defines `Body`: a lowered representation of functions, statics and
+//! consts.
+use std::ops;
+
+use hir_expand::{InFile, Lookup};
+use la_arena::{Idx, RawIdx};
+use span::Edition;
+use syntax::ast;
+use triomphe::Arc;
+
+use crate::{
+ db::DefDatabase,
+ expander::Expander,
+ expr_store::{lower, pretty, ExpressionStore, ExpressionStoreSourceMap, SelfParamPtr},
+ hir::{BindingId, ExprId, PatId},
+ item_tree::AttrOwner,
+ src::HasSource,
+ DefWithBodyId, HasModule,
+};
+
+/// The body of an item (function, const etc.).
+#[derive(Debug, Eq, PartialEq)]
+pub struct Body {
+ pub store: ExpressionStore,
+ /// The patterns for the function's parameters. While the parameter types are
+ /// part of the function signature, the patterns are not (they don't change
+ /// the external type of the function).
+ ///
+ /// If this `Body` is for the body of a constant, this will just be
+ /// empty.
+ pub params: Box<[PatId]>,
+ pub self_param: Option,
+ /// The `ExprId` of the actual body expression.
+ pub body_expr: ExprId,
+}
+
+impl ops::Deref for Body {
+ type Target = ExpressionStore;
+
+ fn deref(&self) -> &Self::Target {
+ &self.store
+ }
+}
+
+/// An item body together with the mapping from syntax nodes to HIR expression
+/// IDs. This is needed to go from e.g. a position in a file to the HIR
+/// expression containing it; but for type inference etc., we want to operate on
+/// a structure that is agnostic to the actual positions of expressions in the
+/// file, so that we don't recompute types whenever some whitespace is typed.
+///
+/// One complication here is that, due to macro expansion, a single `Body` might
+/// be spread across several files. So, for each ExprId and PatId, we record
+/// both the HirFileId and the position inside the file. However, we only store
+/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
+/// this properly for macros.
+#[derive(Default, Debug, Eq, PartialEq)]
+pub struct BodySourceMap {
+ pub self_param: Option>,
+ pub store: ExpressionStoreSourceMap,
+}
+
+impl ops::Deref for BodySourceMap {
+ type Target = ExpressionStoreSourceMap;
+
+ fn deref(&self) -> &Self::Target {
+ &self.store
+ }
+}
+
+impl Body {
+ pub(crate) fn body_with_source_map_query(
+ db: &dyn DefDatabase,
+ def: DefWithBodyId,
+ ) -> (Arc, Arc) {
+ let _p = tracing::info_span!("body_with_source_map_query").entered();
+ let mut params = None;
+
+ let mut is_async_fn = false;
+ let InFile { file_id, value: body } = {
+ match def {
+ DefWithBodyId::FunctionId(f) => {
+ let data = db.function_data(f);
+ let f = f.lookup(db);
+ let src = f.source(db);
+ params = src.value.param_list().map(move |param_list| {
+ let item_tree = f.id.item_tree(db);
+ let func = &item_tree[f.id.value];
+ let krate = f.container.module(db).krate;
+ let crate_graph = db.crate_graph();
+ (
+ param_list,
+ (0..func.params.len()).map(move |idx| {
+ item_tree
+ .attrs(
+ db,
+ krate,
+ AttrOwner::Param(
+ f.id.value,
+ Idx::from_raw(RawIdx::from(idx as u32)),
+ ),
+ )
+ .is_cfg_enabled(&crate_graph[krate].cfg_options)
+ }),
+ )
+ });
+ is_async_fn = data.is_async();
+ src.map(|it| it.body().map(ast::Expr::from))
+ }
+ DefWithBodyId::ConstId(c) => {
+ let c = c.lookup(db);
+ let src = c.source(db);
+ src.map(|it| it.body())
+ }
+ DefWithBodyId::StaticId(s) => {
+ let s = s.lookup(db);
+ let src = s.source(db);
+ src.map(|it| it.body())
+ }
+ DefWithBodyId::VariantId(v) => {
+ let s = v.lookup(db);
+ let src = s.source(db);
+ src.map(|it| it.expr())
+ }
+ DefWithBodyId::InTypeConstId(c) => c.lookup(db).id.map(|_| c.source(db).expr()),
+ }
+ };
+ let module = def.module(db);
+ let expander = Expander::new(db, file_id, module);
+ let (body, mut source_map) =
+ lower::lower_body(db, def, expander, params, body, module.krate, is_async_fn);
+ source_map.store.shrink_to_fit();
+
+ (Arc::new(body), Arc::new(source_map))
+ }
+
+ pub(crate) fn body_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc {
+ db.body_with_source_map(def).0
+ }
+
+ pub fn pretty_print(
+ &self,
+ db: &dyn DefDatabase,
+ owner: DefWithBodyId,
+ edition: Edition,
+ ) -> String {
+ pretty::print_body_hir(db, self, owner, edition)
+ }
+
+ pub fn pretty_print_expr(
+ &self,
+ db: &dyn DefDatabase,
+ owner: DefWithBodyId,
+ expr: ExprId,
+ edition: Edition,
+ ) -> String {
+ pretty::print_expr_hir(db, self, owner, expr, edition)
+ }
+
+ pub fn pretty_print_pat(
+ &self,
+ db: &dyn DefDatabase,
+ owner: DefWithBodyId,
+ pat: PatId,
+ oneline: bool,
+ edition: Edition,
+ ) -> String {
+ pretty::print_pat_hir(db, self, owner, pat, oneline, edition)
+ }
+}
+
+impl BodySourceMap {
+ pub fn self_param_syntax(&self) -> Option> {
+ self.self_param
+ }
+}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
similarity index 90%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
index 16c7b5ca00a07..88f770da02a4e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower.rs
@@ -29,11 +29,14 @@ use triomphe::Arc;
use crate::{
attr::Attrs,
- body::{Body, BodyDiagnostic, BodySourceMap, ExprPtr, HygieneId, LabelPtr, PatPtr},
builtin_type::BuiltinUint,
data::adt::StructKind,
db::DefDatabase,
expander::Expander,
+ expr_store::{
+ Body, BodySourceMap, ExprPtr, ExpressionStore, ExpressionStoreBuilder,
+ ExpressionStoreDiagnostics, ExpressionStoreSourceMap, HygieneId, LabelPtr, PatPtr,
+ },
hir::{
format_args::{
self, FormatAlignment, FormatArgs, FormatArgsPiece, FormatArgument, FormatArgumentKind,
@@ -55,11 +58,11 @@ use crate::{
type FxIndexSet = indexmap::IndexSet>;
-pub(super) fn lower(
+pub(super) fn lower_body(
db: &dyn DefDatabase,
owner: DefWithBodyId,
expander: Expander,
- params: Option<(ast::ParamList, impl Iterator- )>,
+ parameters: Option<(ast::ParamList, impl Iterator
- )>,
body: Option
,
krate: CrateId,
is_async_fn: bool,
@@ -75,35 +78,146 @@ pub(super) fn lower(
};
Arc::clone(span_map)
});
- ExprCollector {
- db,
- owner,
- krate,
- def_map: expander.module.def_map(db),
- source_map: BodySourceMap::default(),
- ast_id_map: db.ast_id_map(expander.current_file_id()),
- body: Body::default(),
- expander,
- current_try_block_label: None,
- is_lowering_coroutine: false,
- label_ribs: Vec::new(),
- current_binding_owner: None,
- awaitable_context: None,
- current_span_map: span_map,
- current_block_legacy_macro_defs_count: FxHashMap::default(),
- }
- .collect(params, body, is_async_fn)
+
+ let mut self_param = None;
+ let mut source_map_self_param = None;
+ let mut params = vec![];
+ let mut collector = ExprCollector::new(db, owner, expander, krate, span_map);
+
+ let skip_body = match owner {
+ DefWithBodyId::FunctionId(it) => db.attrs(it.into()),
+ DefWithBodyId::StaticId(it) => db.attrs(it.into()),
+ DefWithBodyId::ConstId(it) => db.attrs(it.into()),
+ DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY,
+ DefWithBodyId::VariantId(it) => db.attrs(it.into()),
+ }
+ .rust_analyzer_tool()
+ .any(|attr| *attr.path() == tool_path![skip]);
+ // If #[rust_analyzer::skip] annotated, only construct enough information for the signature
+ // and skip the body.
+ if skip_body {
+ if let Some((param_list, mut attr_enabled)) = parameters {
+ if let Some(self_param_syn) =
+ param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+ {
+ let is_mutable =
+ self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
+ let binding_id: la_arena::Idx = collector.alloc_binding(
+ Name::new_symbol_root(sym::self_.clone()),
+ BindingAnnotation::new(is_mutable, false),
+ );
+ self_param = Some(binding_id);
+ source_map_self_param =
+ Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
+ }
+ params = param_list
+ .params()
+ .zip(attr_enabled)
+ .filter(|(_, enabled)| *enabled)
+ .map(|_| collector.missing_pat())
+ .collect();
+ };
+ let body_expr = collector.missing_expr();
+ return (
+ Body {
+ store: collector.store.finish(),
+ params: params.into_boxed_slice(),
+ self_param,
+ body_expr,
+ },
+ BodySourceMap { self_param: source_map_self_param, store: collector.source_map },
+ );
+ }
+
+ if let Some((param_list, mut attr_enabled)) = parameters {
+ if let Some(self_param_syn) =
+ param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
+ {
+ let is_mutable =
+ self_param_syn.mut_token().is_some() && self_param_syn.amp_token().is_none();
+ let binding_id: la_arena::Idx = collector.alloc_binding(
+ Name::new_symbol_root(sym::self_.clone()),
+ BindingAnnotation::new(is_mutable, false),
+ );
+ let hygiene = self_param_syn
+ .name()
+ .map(|name| collector.hygiene_id_for(name.syntax().text_range().start()))
+ .unwrap_or(HygieneId::ROOT);
+ if !hygiene.is_root() {
+ collector.store.binding_hygiene.insert(binding_id, hygiene);
+ }
+ self_param = Some(binding_id);
+ source_map_self_param = Some(collector.expander.in_file(AstPtr::new(&self_param_syn)));
+ }
+
+ for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled) {
+ let param_pat = collector.collect_pat_top(param.pat());
+ params.push(param_pat);
+ }
+ };
+
+ let body_expr = collector.collect(
+ body,
+ if is_async_fn {
+ Awaitable::Yes
+ } else {
+ match owner {
+ DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),
+ DefWithBodyId::StaticId(..) => Awaitable::No("static"),
+ DefWithBodyId::ConstId(..) | DefWithBodyId::InTypeConstId(..) => {
+ Awaitable::No("constant")
+ }
+ DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
+ }
+ },
+ );
+
+ (
+ Body {
+ store: collector.store.finish(),
+ params: params.into_boxed_slice(),
+ self_param,
+ body_expr,
+ },
+ BodySourceMap { self_param: source_map_self_param, store: collector.source_map },
+ )
}
+#[allow(dead_code)]
+pub(super) fn lower(
+ db: &dyn DefDatabase,
+ owner: ExprStoreOwnerId,
+ expander: Expander,
+ body: Option,
+ krate: CrateId,
+) -> (ExpressionStore, ExpressionStoreSourceMap) {
+ // We cannot leave the root span map empty and let any identifier from it be treated as root,
+ // because when inside nested macros `SyntaxContextId`s from the outer macro will be interleaved
+ // with the inner macro, and that will cause confusion because they won't be the same as `ROOT`
+ // even though they should be the same. Also, when the body comes from multiple expansions, their
+ // hygiene is different.
+ let span_map = expander.current_file_id().macro_file().map(|_| {
+ let SpanMap::ExpansionSpanMap(span_map) = expander.span_map(db) else {
+ panic!("in a macro file there should be `ExpansionSpanMap`");
+ };
+ Arc::clone(span_map)
+ });
+ let mut expr_collector = ExprCollector::new(db, owner, expander, krate, span_map);
+ expr_collector.collect(body, Awaitable::No("?"));
+ (expr_collector.store.finish(), expr_collector.source_map)
+}
+
+type ExprStoreOwnerId = DefWithBodyId;
+
struct ExprCollector<'a> {
db: &'a dyn DefDatabase,
expander: Expander,
- owner: DefWithBodyId,
+ owner: ExprStoreOwnerId,
def_map: Arc,
ast_id_map: Arc,
krate: CrateId,
- body: Body,
- source_map: BodySourceMap,
+ store: ExpressionStoreBuilder,
+ source_map: ExpressionStoreSourceMap,
is_lowering_coroutine: bool,
@@ -157,6 +271,7 @@ impl RibKind {
}
}
+#[derive(PartialEq, Eq, Debug, Copy, Clone)]
enum Awaitable {
Yes,
No(&'static str),
@@ -180,12 +295,12 @@ impl BindingList {
let id = *self.map.entry((name, hygiene)).or_insert_with_key(|(name, _)| {
let id = ec.alloc_binding(name.clone(), mode);
if !hygiene.is_root() {
- ec.body.binding_hygiene.insert(id, hygiene);
+ ec.store.binding_hygiene.insert(id, hygiene);
}
id
});
- if ec.body.bindings[id].mode != mode {
- ec.body.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
+ if ec.store.bindings[id].mode != mode {
+ ec.store.bindings[id].problems = Some(BindingProblems::BoundInconsistently);
}
self.check_is_used(ec, id);
id
@@ -195,11 +310,11 @@ impl BindingList {
match self.is_used.get(&id) {
None => {
if self.reject_new {
- ec.body.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);
+ ec.store.bindings[id].problems = Some(BindingProblems::NotBoundAcrossAll);
}
}
Some(true) => {
- ec.body.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);
+ ec.store.bindings[id].problems = Some(BindingProblems::BoundMoreThanOnce);
}
Some(false) => {}
}
@@ -208,93 +323,37 @@ impl BindingList {
}
impl ExprCollector<'_> {
- fn collect(
- mut self,
- param_list: Option<(ast::ParamList, impl Iterator- )>,
- body: Option
,
- is_async_fn: bool,
- ) -> (Body, BodySourceMap) {
- let skip_body = match self.owner {
- DefWithBodyId::FunctionId(it) => self.db.attrs(it.into()),
- DefWithBodyId::StaticId(it) => self.db.attrs(it.into()),
- DefWithBodyId::ConstId(it) => self.db.attrs(it.into()),
- DefWithBodyId::InTypeConstId(_) => Attrs::EMPTY,
- DefWithBodyId::VariantId(it) => self.db.attrs(it.into()),
+ fn new(
+ db: &dyn DefDatabase,
+ owner: ExprStoreOwnerId,
+ expander: Expander,
+ krate: CrateId,
+ span_map: Option>,
+ ) -> ExprCollector<'_> {
+ ExprCollector {
+ db,
+ owner,
+ krate,
+ def_map: expander.module.def_map(db),
+ source_map: ExpressionStoreSourceMap::default(),
+ ast_id_map: db.ast_id_map(expander.current_file_id()),
+ store: ExpressionStoreBuilder::default(),
+ expander,
+ current_try_block_label: None,
+ is_lowering_coroutine: false,
+ label_ribs: Vec::new(),
+ current_binding_owner: None,
+ awaitable_context: None,
+ current_span_map: span_map,
+ current_block_legacy_macro_defs_count: FxHashMap::default(),
}
- .rust_analyzer_tool()
- .any(|attr| *attr.path() == tool_path![skip]);
- // If #[rust_analyzer::skip] annotated, only construct enough information for the signature
- // and skip the body.
- if skip_body {
- self.body.body_expr = self.missing_expr();
- if let Some((param_list, mut attr_enabled)) = param_list {
- if let Some(self_param) =
- param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
- {
- let is_mutable =
- self_param.mut_token().is_some() && self_param.amp_token().is_none();
- let binding_id: la_arena::Idx = self.alloc_binding(
- Name::new_symbol_root(sym::self_.clone()),
- BindingAnnotation::new(is_mutable, false),
- );
- self.body.self_param = Some(binding_id);
- self.source_map.self_param =
- Some(self.expander.in_file(AstPtr::new(&self_param)));
- }
- self.body.params = param_list
- .params()
- .zip(attr_enabled)
- .filter(|(_, enabled)| *enabled)
- .map(|_| self.missing_pat())
- .collect();
- };
- return (self.body, self.source_map);
- }
-
- self.awaitable_context.replace(if is_async_fn {
- Awaitable::Yes
- } else {
- match self.owner {
- DefWithBodyId::FunctionId(..) => Awaitable::No("non-async function"),
- DefWithBodyId::StaticId(..) => Awaitable::No("static"),
- DefWithBodyId::ConstId(..) | DefWithBodyId::InTypeConstId(..) => {
- Awaitable::No("constant")
- }
- DefWithBodyId::VariantId(..) => Awaitable::No("enum variant"),
- }
- });
- if let Some((param_list, mut attr_enabled)) = param_list {
- let mut params = vec![];
- if let Some(self_param) =
- param_list.self_param().filter(|_| attr_enabled.next().unwrap_or(false))
- {
- let is_mutable =
- self_param.mut_token().is_some() && self_param.amp_token().is_none();
- let binding_id: la_arena::Idx = self.alloc_binding(
- Name::new_symbol_root(sym::self_.clone()),
- BindingAnnotation::new(is_mutable, false),
- );
- let hygiene = self_param
- .name()
- .map(|name| self.hygiene_id_for(name.syntax().text_range().start()))
- .unwrap_or(HygieneId::ROOT);
- if !hygiene.is_root() {
- self.body.binding_hygiene.insert(binding_id, hygiene);
- }
- self.body.self_param = Some(binding_id);
- self.source_map.self_param = Some(self.expander.in_file(AstPtr::new(&self_param)));
- }
+ }
- for (param, _) in param_list.params().zip(attr_enabled).filter(|(_, enabled)| *enabled)
- {
- let param_pat = self.collect_pat_top(param.pat());
- params.push(param_pat);
- }
- self.body.params = params.into_boxed_slice();
- };
- self.body.body_expr = self.with_label_rib(RibKind::Closure, |this| {
- if is_async_fn {
- match body {
+ fn collect(&mut self, expr: Option, awaitable: Awaitable) -> ExprId {
+ self.awaitable_context.replace(awaitable);
+ self.with_label_rib(RibKind::Closure, |this| {
+ if awaitable == Awaitable::Yes {
+ match expr {
Some(e) => {
let syntax_ptr = AstPtr::new(&e);
let expr = this.collect_expr(e);
@@ -306,15 +365,13 @@ impl ExprCollector<'_> {
None => this.missing_expr(),
}
} else {
- this.collect_expr_opt(body)
+ this.collect_expr_opt(expr)
}
- });
-
- (self.body, self.source_map)
+ })
}
fn ctx(&mut self) -> LowerCtx<'_> {
- self.expander.ctx(self.db, &mut self.body.types, &mut self.source_map.types)
+ self.expander.ctx(self.db, &mut self.store.types, &mut self.source_map.types)
}
fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -390,7 +447,7 @@ impl ExprCollector<'_> {
parent: this.owner,
root: inner_expr,
});
- this.body.exprs[result_expr_id] = Expr::Const(it);
+ this.store.exprs[result_expr_id] = Expr::Const(it);
this.current_binding_owner = prev_binding_owner;
result_expr_id
})
@@ -480,7 +537,7 @@ impl ExprCollector<'_> {
.unwrap_or((Expr::Missing, HygieneId::ROOT));
let expr_id = self.alloc_expr(path, syntax_ptr);
if !hygiene.is_root() {
- self.body.expr_hygiene.insert(expr_id, hygiene);
+ self.store.ident_hygiene.insert(expr_id.into(), hygiene);
}
expr_id
}
@@ -562,10 +619,12 @@ impl ExprCollector<'_> {
ast::Expr::AwaitExpr(e) => {
let expr = self.collect_expr_opt(e.expr());
if let Awaitable::No(location) = self.is_lowering_awaitable_block() {
- self.source_map.diagnostics.push(BodyDiagnostic::AwaitOutsideOfAsync {
- node: InFile::new(self.expander.current_file_id(), AstPtr::new(&e)),
- location: location.to_string(),
- });
+ self.source_map.diagnostics.push(
+ ExpressionStoreDiagnostics::AwaitOutsideOfAsync {
+ node: InFile::new(self.expander.current_file_id(), AstPtr::new(&e)),
+ location: location.to_string(),
+ },
+ );
}
self.alloc_expr(Expr::Await { expr }, syntax_ptr)
}
@@ -646,7 +705,7 @@ impl ExprCollector<'_> {
this.is_lowering_coroutine = prev_is_lowering_coroutine;
this.current_binding_owner = prev_binding_owner;
this.current_try_block_label = prev_try_block_label;
- this.body.exprs[result_expr_id] = Expr::Closure {
+ this.store.exprs[result_expr_id] = Expr::Closure {
args: args.into(),
arg_types: arg_types.into(),
ret_type,
@@ -752,7 +811,7 @@ impl ExprCollector<'_> {
}
fn parse_path(&mut self, path: ast::Path) -> Option {
- self.expander.parse_path(self.db, path, &mut self.body.types, &mut self.source_map.types)
+ self.expander.parse_path(self.db, path, &mut self.store.types, &mut self.source_map.types)
}
fn collect_expr_path(&mut self, e: ast::PathExpr) -> Option<(Path, HygieneId)> {
@@ -781,7 +840,7 @@ impl ExprCollector<'_> {
let src = self.expander.in_file(AstPtr::new(&expr).wrap_left());
let expr = self.collect_expr(expr);
// Do not use `alloc_pat_from_expr()` here, it will override the entry in `expr_map`.
- let id = self.body.pats.alloc(Pat::Expr(expr));
+ let id = self.store.pats.alloc(Pat::Expr(expr));
self.source_map.pat_map_back.insert(id, src);
id
})
@@ -835,7 +894,7 @@ impl ExprCollector<'_> {
.unwrap_or((Pat::Missing, HygieneId::ROOT));
let pat_id = self.alloc_pat_from_expr(path, syntax_ptr);
if !hygiene.is_root() {
- self.body.pat_hygiene.insert(pat_id, hygiene);
+ self.store.ident_hygiene.insert(pat_id.into(), hygiene);
}
pat_id
}
@@ -967,7 +1026,7 @@ impl ExprCollector<'_> {
) -> ExprId {
let (id, prev_owner) = self.initialize_binding_owner(syntax_ptr);
let tmp = job(self);
- self.body.exprs[id] = mem::replace(&mut self.body.exprs[tmp], Expr::Missing);
+ self.store.exprs[id] = mem::replace(&mut self.store.exprs[tmp], Expr::Missing);
self.current_binding_owner = prev_owner;
id
}
@@ -979,8 +1038,9 @@ impl ExprCollector<'_> {
let Some(try_from_output) = self.lang_path(LangItem::TryTraitFromOutput) else {
return self.collect_block(e);
};
- let label = self
- .alloc_label_desugared(Label { name: Name::generate_new_name(self.body.labels.len()) });
+ let label = self.alloc_label_desugared(Label {
+ name: Name::generate_new_name(self.store.labels.len()),
+ });
let old_label = self.current_try_block_label.replace(label);
let ptr = AstPtr::new(&e).upcast();
@@ -1006,7 +1066,7 @@ impl ExprCollector<'_> {
)
}
};
- let Expr::Block { tail, .. } = &mut self.body.exprs[expr_id] else {
+ let Expr::Block { tail, .. } = &mut self.store.exprs[expr_id] else {
unreachable!("block was lowered to non-block");
};
*tail = Some(next_tail);
@@ -1112,7 +1172,7 @@ impl ExprCollector<'_> {
this.collect_expr_opt(e.loop_body().map(|it| it.into()))
}),
};
- let iter_name = Name::generate_new_name(self.body.exprs.len());
+ let iter_name = Name::generate_new_name(self.store.exprs.len());
let iter_expr = self.alloc_expr(Expr::Path(Path::from(iter_name.clone())), syntax_ptr);
let iter_expr_mut = self.alloc_expr(
Expr::Ref { expr: iter_expr, rawness: Rawness::Ref, mutability: Mutability::Mut },
@@ -1177,7 +1237,7 @@ impl ExprCollector<'_> {
let try_branch = self.alloc_expr(Expr::Path(try_branch), syntax_ptr);
let expr = self
.alloc_expr(Expr::Call { callee: try_branch, args: Box::new([operand]) }, syntax_ptr);
- let continue_name = Name::generate_new_name(self.body.bindings.len());
+ let continue_name = Name::generate_new_name(self.store.bindings.len());
let continue_binding =
self.alloc_binding(continue_name.clone(), BindingAnnotation::Unannotated);
let continue_bpat =
@@ -1192,7 +1252,7 @@ impl ExprCollector<'_> {
guard: None,
expr: self.alloc_expr(Expr::Path(Path::from(continue_name)), syntax_ptr),
};
- let break_name = Name::generate_new_name(self.body.bindings.len());
+ let break_name = Name::generate_new_name(self.store.bindings.len());
let break_binding = self.alloc_binding(break_name.clone(), BindingAnnotation::Unannotated);
let break_bpat = self.alloc_pat_desugared(Pat::Bind { id: break_binding, subpat: None });
self.add_definition_to_binding(break_binding, break_bpat);
@@ -1261,17 +1321,19 @@ impl ExprCollector<'_> {
Ok(res) => res,
Err(UnresolvedMacro { path }) => {
if record_diagnostics {
- self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall {
- node: InFile::new(outer_file, syntax_ptr),
- path,
- });
+ self.source_map.diagnostics.push(
+ ExpressionStoreDiagnostics::UnresolvedMacroCall {
+ node: InFile::new(outer_file, syntax_ptr),
+ path,
+ },
+ );
}
return collector(self, None);
}
};
if record_diagnostics {
if let Some(err) = res.err {
- self.source_map.diagnostics.push(BodyDiagnostic::MacroError {
+ self.source_map.diagnostics.push(ExpressionStoreDiagnostics::MacroError {
node: InFile::new(outer_file, syntax_ptr),
err,
});
@@ -1464,7 +1526,7 @@ impl ExprCollector<'_> {
let (module, def_map) =
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
Some((def_map, block_id)) => {
- self.body.block_scopes.push(block_id);
+ self.store.block_scopes.push(block_id);
(def_map.module_id(DefMap::ROOT), def_map)
}
None => (self.expander.module, self.def_map.clone()),
@@ -1621,7 +1683,7 @@ impl ExprCollector<'_> {
pats.push(self.collect_pat(rest, binding_list));
for (&id, &is_used) in binding_list.is_used.iter() {
if !is_used {
- self.body.bindings[id].problems =
+ self.store.bindings[id].problems =
Some(BindingProblems::NotBoundAcrossAll);
}
}
@@ -1825,7 +1887,7 @@ impl ExprCollector<'_> {
return Some(());
}
- self.source_map.diagnostics.push(BodyDiagnostic::InactiveCode {
+ self.source_map.diagnostics.push(ExpressionStoreDiagnostics::InactiveCode {
node: self.expander.in_file(SyntaxNodePtr::new(owner.syntax())),
cfg,
opts: self.expander.cfg_options().clone(),
@@ -1853,7 +1915,7 @@ impl ExprCollector<'_> {
fn resolve_label(
&self,
lifetime: Option,
- ) -> Result, BodyDiagnostic> {
+ ) -> Result , ExpressionStoreDiagnostics> {
let Some(lifetime) = lifetime else { return Ok(None) };
let (mut hygiene_id, mut hygiene_info) = match &self.current_span_map {
None => (HygieneId::ROOT, None),
@@ -1877,7 +1939,7 @@ impl ExprCollector<'_> {
return if self.is_label_valid_from_rib(rib_idx) {
Ok(Some(*id))
} else {
- Err(BodyDiagnostic::UnreachableLabel {
+ Err(ExpressionStoreDiagnostics::UnreachableLabel {
name,
node: self.expander.in_file(AstPtr::new(&lifetime)),
})
@@ -1903,7 +1965,7 @@ impl ExprCollector<'_> {
}
}
- Err(BodyDiagnostic::UndeclaredLabel {
+ Err(ExpressionStoreDiagnostics::UndeclaredLabel {
name,
node: self.expander.in_file(AstPtr::new(&lifetime)),
})
@@ -1934,7 +1996,7 @@ impl ExprCollector<'_> {
f: impl FnOnce(&mut Self) -> T,
) -> T {
self.label_ribs.push(LabelRib::new(RibKind::Normal(
- self.body[label].name.clone(),
+ self.store.labels[label].name.clone(),
label,
hygiene,
)));
@@ -2023,7 +2085,7 @@ impl ExprCollector<'_> {
);
}
if !hygiene.is_root() {
- self.body.expr_hygiene.insert(expr_id, hygiene);
+ self.store.ident_hygiene.insert(expr_id.into(), hygiene);
}
expr_id
},
@@ -2171,17 +2233,27 @@ impl ExprCollector<'_> {
let unsafe_arg_new = self.alloc_expr_desugared(Expr::Path(unsafe_arg_new));
let unsafe_arg_new =
self.alloc_expr_desugared(Expr::Call { callee: unsafe_arg_new, args: Box::default() });
- let unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
+ let mut unsafe_arg_new = self.alloc_expr_desugared(Expr::Unsafe {
id: None,
- // We collect the unused expressions here so that we still infer them instead of
- // dropping them out of the expression tree
- statements: fmt
- .orphans
- .into_iter()
- .map(|expr| Statement::Expr { expr, has_semi: true })
- .collect(),
+ statements: Box::new([]),
tail: Some(unsafe_arg_new),
});
+ if !fmt.orphans.is_empty() {
+ unsafe_arg_new = self.alloc_expr_desugared(Expr::Block {
+ id: None,
+ // We collect the unused expressions here so that we still infer them instead of
+ // dropping them out of the expression tree. We cannot store them in the `Unsafe`
+ // block because then unsafe blocks within them will get a false "unused unsafe"
+ // diagnostic (rustc has a notion of builtin unsafe blocks, but we don't).
+ statements: fmt
+ .orphans
+ .into_iter()
+ .map(|expr| Statement::Expr { expr, has_semi: true })
+ .collect(),
+ tail: Some(unsafe_arg_new),
+ label: None,
+ });
+ }
let idx = self.alloc_expr(
Expr::Call {
@@ -2417,7 +2489,7 @@ fn pat_literal_to_hir(lit: &ast::LiteralPat) -> Option<(Literal, ast::Literal)>
impl ExprCollector<'_> {
fn alloc_expr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.in_file(ptr);
- let id = self.body.exprs.alloc(expr);
+ let id = self.store.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
self.source_map.expr_map.insert(src, id.into());
id
@@ -2425,11 +2497,11 @@ impl ExprCollector<'_> {
// FIXME: desugared exprs don't have ptr, that's wrong and should be fixed.
// Migrate to alloc_expr_desugared_with_ptr and then rename back
fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
- self.body.exprs.alloc(expr)
+ self.store.exprs.alloc(expr)
}
fn alloc_expr_desugared_with_ptr(&mut self, expr: Expr, ptr: ExprPtr) -> ExprId {
let src = self.expander.in_file(ptr);
- let id = self.body.exprs.alloc(expr);
+ let id = self.store.exprs.alloc(expr);
self.source_map.expr_map_back.insert(id, src);
// We intentionally don't fill this as it could overwrite a non-desugared entry
// self.source_map.expr_map.insert(src, id);
@@ -2440,45 +2512,45 @@ impl ExprCollector<'_> {
}
fn alloc_binding(&mut self, name: Name, mode: BindingAnnotation) -> BindingId {
- let binding = self.body.bindings.alloc(Binding { name, mode, problems: None });
+ let binding = self.store.bindings.alloc(Binding { name, mode, problems: None });
if let Some(owner) = self.current_binding_owner {
- self.body.binding_owners.insert(binding, owner);
+ self.store.binding_owners.insert(binding, owner);
}
binding
}
fn alloc_pat_from_expr(&mut self, pat: Pat, ptr: ExprPtr) -> PatId {
let src = self.expander.in_file(ptr);
- let id = self.body.pats.alloc(pat);
+ let id = self.store.pats.alloc(pat);
self.source_map.expr_map.insert(src, id.into());
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_left));
id
}
fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
let src = self.expander.in_file(ptr);
- let id = self.body.pats.alloc(pat);
+ let id = self.store.pats.alloc(pat);
self.source_map.pat_map_back.insert(id, src.map(AstPtr::wrap_right));
self.source_map.pat_map.insert(src, id);
id
}
// FIXME: desugared pats don't have ptr, that's wrong and should be fixed somehow.
fn alloc_pat_desugared(&mut self, pat: Pat) -> PatId {
- self.body.pats.alloc(pat)
+ self.store.pats.alloc(pat)
}
fn missing_pat(&mut self) -> PatId {
- self.body.pats.alloc(Pat::Missing)
+ self.store.pats.alloc(Pat::Missing)
}
fn alloc_label(&mut self, label: Label, ptr: LabelPtr) -> LabelId {
let src = self.expander.in_file(ptr);
- let id = self.body.labels.alloc(label);
+ let id = self.store.labels.alloc(label);
self.source_map.label_map_back.insert(id, src);
self.source_map.label_map.insert(src, id);
id
}
// FIXME: desugared labels don't have ptr, that's wrong and should be fixed somehow.
fn alloc_label_desugared(&mut self, label: Label) -> LabelId {
- self.body.labels.alloc(label)
+ self.store.labels.alloc(label)
}
fn is_lowering_awaitable_block(&self) -> &Awaitable {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
similarity index 99%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
index 994ba2aa069d3..032c18688ea71 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/lower/asm.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/asm.rs
@@ -9,7 +9,7 @@ use syntax::{
use tt::TextRange;
use crate::{
- body::lower::{ExprCollector, FxIndexSet},
+ expr_store::lower::{ExprCollector, FxIndexSet},
hir::{AsmOperand, AsmOptions, Expr, ExprId, InlineAsm, InlineAsmRegOrRegClass},
};
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
similarity index 95%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
index 52b91b522a412..6a0b1e5197905 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/pretty.rs
@@ -60,7 +60,7 @@ pub(super) fn print_body_hir(
let mut p = Printer {
db,
- body,
+ store: body,
buf: header,
indent_level: 0,
line_format: LineFormat::Newline,
@@ -103,14 +103,14 @@ pub(super) fn print_body_hir(
pub(super) fn print_expr_hir(
db: &dyn DefDatabase,
- body: &Body,
+ store: &ExpressionStore,
_owner: DefWithBodyId,
expr: ExprId,
edition: Edition,
) -> String {
let mut p = Printer {
db,
- body,
+ store,
buf: String::new(),
indent_level: 0,
line_format: LineFormat::Newline,
@@ -122,7 +122,7 @@ pub(super) fn print_expr_hir(
pub(super) fn print_pat_hir(
db: &dyn DefDatabase,
- body: &Body,
+ store: &ExpressionStore,
_owner: DefWithBodyId,
pat: PatId,
oneline: bool,
@@ -130,7 +130,7 @@ pub(super) fn print_pat_hir(
) -> String {
let mut p = Printer {
db,
- body,
+ store,
buf: String::new(),
indent_level: 0,
line_format: if oneline { LineFormat::Oneline } else { LineFormat::Newline },
@@ -157,7 +157,7 @@ macro_rules! wln {
struct Printer<'a> {
db: &'a dyn DefDatabase,
- body: &'a Body,
+ store: &'a ExpressionStore,
buf: String,
indent_level: usize,
line_format: LineFormat,
@@ -233,7 +233,7 @@ impl Printer<'_> {
}
fn print_expr(&mut self, expr: ExprId) {
- let expr = &self.body[expr];
+ let expr = &self.store[expr];
match expr {
Expr::Missing => w!(self, "�"),
@@ -241,7 +241,7 @@ impl Printer<'_> {
Expr::InlineAsm(_) => w!(self, "builtin#asm(_)"),
Expr::OffsetOf(offset_of) => {
w!(self, "builtin#offset_of(");
- self.print_type_ref(offset_of.container, &self.body.types);
+ self.print_type_ref(offset_of.container, &self.store.types);
let edition = self.edition;
w!(
self,
@@ -271,7 +271,7 @@ impl Printer<'_> {
}
Expr::Loop { body, label } => {
if let Some(lbl) = label {
- w!(self, "{}: ", self.body[*lbl].name.display(self.db.upcast(), self.edition));
+ w!(self, "{}: ", self.store[*lbl].name.display(self.db.upcast(), self.edition));
}
w!(self, "loop ");
self.print_expr(*body);
@@ -295,7 +295,7 @@ impl Printer<'_> {
if let Some(args) = generic_args {
w!(self, "::<");
let edition = self.edition;
- print_generic_args(self.db, args, &self.body.types, self, edition).unwrap();
+ print_generic_args(self.db, args, &self.store.types, self, edition).unwrap();
w!(self, ">");
}
w!(self, "(");
@@ -330,13 +330,13 @@ impl Printer<'_> {
Expr::Continue { label } => {
w!(self, "continue");
if let Some(lbl) = label {
- w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
+ w!(self, " {}", self.store[*lbl].name.display(self.db.upcast(), self.edition));
}
}
Expr::Break { expr, label } => {
w!(self, "break");
if let Some(lbl) = label {
- w!(self, " {}", self.body[*lbl].name.display(self.db.upcast(), self.edition));
+ w!(self, " {}", self.store[*lbl].name.display(self.db.upcast(), self.edition));
}
if let Some(expr) = expr {
self.whitespace();
@@ -404,7 +404,7 @@ impl Printer<'_> {
Expr::Cast { expr, type_ref } => {
self.print_expr(*expr);
w!(self, " as ");
- self.print_type_ref(*type_ref, &self.body.types);
+ self.print_type_ref(*type_ref, &self.store.types);
}
Expr::Ref { expr, rawness, mutability } => {
w!(self, "&");
@@ -492,13 +492,13 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = ty {
w!(self, ": ");
- self.print_type_ref(*ty, &self.body.types);
+ self.print_type_ref(*ty, &self.store.types);
}
}
w!(self, "|");
if let Some(ret_ty) = ret_type {
w!(self, " -> ");
- self.print_type_ref(*ret_ty, &self.body.types);
+ self.print_type_ref(*ret_ty, &self.store.types);
}
self.whitespace();
self.print_expr(*body);
@@ -534,7 +534,7 @@ impl Printer<'_> {
Expr::Literal(lit) => self.print_literal(lit),
Expr::Block { id: _, statements, tail, label } => {
let label = label.map(|lbl| {
- format!("{}: ", self.body[lbl].name.display(self.db.upcast(), self.edition))
+ format!("{}: ", self.store[lbl].name.display(self.db.upcast(), self.edition))
});
self.print_block(label.as_deref(), statements, tail);
}
@@ -581,7 +581,7 @@ impl Printer<'_> {
}
fn print_pat(&mut self, pat: PatId) {
- let pat = &self.body[pat];
+ let pat = &self.store[pat];
match pat {
Pat::Missing => w!(self, "�"),
@@ -623,9 +623,9 @@ impl Printer<'_> {
let field_name = arg.name.display(self.db.upcast(), edition).to_string();
let mut same_name = false;
- if let Pat::Bind { id, subpat: None } = &self.body[arg.pat] {
+ if let Pat::Bind { id, subpat: None } = &self.store[arg.pat] {
if let Binding { name, mode: BindingAnnotation::Unannotated, .. } =
- &self.body.bindings[*id]
+ &self.store.bindings[*id]
{
if name.as_str() == field_name {
same_name = true;
@@ -734,7 +734,7 @@ impl Printer<'_> {
self.print_pat(*pat);
if let Some(ty) = type_ref {
w!(self, ": ");
- self.print_type_ref(*ty, &self.body.types);
+ self.print_type_ref(*ty, &self.store.types);
}
if let Some(init) = initializer {
w!(self, " = ");
@@ -799,11 +799,11 @@ impl Printer<'_> {
fn print_path(&mut self, path: &Path) {
let edition = self.edition;
- print_path(self.db, path, &self.body.types, self, edition).unwrap();
+ print_path(self.db, path, &self.store.types, self, edition).unwrap();
}
fn print_binding(&mut self, id: BindingId) {
- let Binding { name, mode, .. } = &self.body.bindings[id];
+ let Binding { name, mode, .. } = &self.store.bindings[id];
let mode = match mode {
BindingAnnotation::Unannotated => "",
BindingAnnotation::Mutable => "mut ",
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
similarity index 90%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
index 08af470b9654a..859a706177aab 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/scope.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/scope.rs
@@ -4,8 +4,8 @@ use la_arena::{Arena, ArenaMap, Idx, IdxRange, RawIdx};
use triomphe::Arc;
use crate::{
- body::{Body, HygieneId},
db::DefDatabase,
+ expr_store::{Body, ExpressionStore, HygieneId},
hir::{Binding, BindingId, Expr, ExprId, Item, LabelId, Pat, PatId, Statement},
BlockId, ConstBlockId, DefWithBodyId,
};
@@ -53,7 +53,7 @@ pub struct ScopeData {
impl ExprScopes {
pub(crate) fn expr_scopes_query(db: &dyn DefDatabase, def: DefWithBodyId) -> Arc {
let body = db.body(def);
- let mut scopes = ExprScopes::new(&body, |const_block| {
+ let mut scopes = ExprScopes::new_body(&body, |const_block| {
db.lookup_intern_anonymous_const(const_block).root
});
scopes.shrink_to_fit();
@@ -104,7 +104,7 @@ fn empty_entries(idx: usize) -> IdxRange {
}
impl ExprScopes {
- fn new(
+ fn new_body(
body: &Body,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
) -> ExprScopes {
@@ -179,28 +179,28 @@ impl ExprScopes {
fn add_bindings(
&mut self,
- body: &Body,
+ store: &ExpressionStore,
scope: ScopeId,
binding: BindingId,
hygiene: HygieneId,
) {
- let Binding { name, .. } = &body.bindings[binding];
+ let Binding { name, .. } = &store.bindings[binding];
let entry = self.scope_entries.alloc(ScopeEntry { name: name.clone(), binding, hygiene });
self.scopes[scope].entries =
IdxRange::new_inclusive(self.scopes[scope].entries.start()..=entry);
}
- fn add_pat_bindings(&mut self, body: &Body, scope: ScopeId, pat: PatId) {
- let pattern = &body[pat];
+ fn add_pat_bindings(&mut self, store: &ExpressionStore, scope: ScopeId, pat: PatId) {
+ let pattern = &store[pat];
if let Pat::Bind { id, .. } = *pattern {
- self.add_bindings(body, scope, id, body.binding_hygiene(id));
+ self.add_bindings(store, scope, id, store.binding_hygiene(id));
}
- pattern.walk_child_pats(|pat| self.add_pat_bindings(body, scope, pat));
+ pattern.walk_child_pats(|pat| self.add_pat_bindings(store, scope, pat));
}
- fn add_params_bindings(&mut self, body: &Body, scope: ScopeId, params: &[PatId]) {
- params.iter().for_each(|pat| self.add_pat_bindings(body, scope, *pat));
+ fn add_params_bindings(&mut self, store: &ExpressionStore, scope: ScopeId, params: &[PatId]) {
+ params.iter().for_each(|pat| self.add_pat_bindings(store, scope, *pat));
}
fn set_scope(&mut self, node: ExprId, scope: ScopeId) {
@@ -218,7 +218,7 @@ impl ExprScopes {
fn compute_block_scopes(
statements: &[Statement],
tail: Option,
- body: &Body,
+ store: &ExpressionStore,
scopes: &mut ExprScopes,
scope: &mut ScopeId,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
@@ -227,17 +227,17 @@ fn compute_block_scopes(
match stmt {
Statement::Let { pat, initializer, else_branch, .. } => {
if let Some(expr) = initializer {
- compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
+ compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
}
if let Some(expr) = else_branch {
- compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
+ compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
}
*scope = scopes.new_scope(*scope);
- scopes.add_pat_bindings(body, *scope, *pat);
+ scopes.add_pat_bindings(store, *scope, *pat);
}
Statement::Expr { expr, .. } => {
- compute_expr_scopes(*expr, body, scopes, scope, resolve_const_block);
+ compute_expr_scopes(*expr, store, scopes, scope, resolve_const_block);
}
Statement::Item(Item::MacroDef(macro_id)) => {
*scope = scopes.new_macro_def_scope(*scope, macro_id.clone());
@@ -246,32 +246,32 @@ fn compute_block_scopes(
}
}
if let Some(expr) = tail {
- compute_expr_scopes(expr, body, scopes, scope, resolve_const_block);
+ compute_expr_scopes(expr, store, scopes, scope, resolve_const_block);
}
}
fn compute_expr_scopes(
expr: ExprId,
- body: &Body,
+ store: &ExpressionStore,
scopes: &mut ExprScopes,
scope: &mut ScopeId,
resolve_const_block: impl (Fn(ConstBlockId) -> ExprId) + Copy,
) {
let make_label =
- |label: &Option| label.map(|label| (label, body.labels[label].name.clone()));
+ |label: &Option| label.map(|label| (label, store.labels[label].name.clone()));
let compute_expr_scopes = |scopes: &mut ExprScopes, expr: ExprId, scope: &mut ScopeId| {
- compute_expr_scopes(expr, body, scopes, scope, resolve_const_block)
+ compute_expr_scopes(expr, store, scopes, scope, resolve_const_block)
};
scopes.set_scope(expr, *scope);
- match &body[expr] {
+ match &store[expr] {
Expr::Block { statements, tail, id, label } => {
let mut scope = scopes.new_block_scope(*scope, *id, make_label(label));
// Overwrite the old scope for the block expr, so that every block scope can be found
// via the block itself (important for blocks that only contain items, no expressions).
scopes.set_scope(expr, scope);
- compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
+ compute_block_scopes(statements, *tail, store, scopes, &mut scope, resolve_const_block);
}
Expr::Const(id) => {
let mut scope = scopes.root_scope();
@@ -282,7 +282,7 @@ fn compute_expr_scopes(
// Overwrite the old scope for the block expr, so that every block scope can be found
// via the block itself (important for blocks that only contain items, no expressions).
scopes.set_scope(expr, scope);
- compute_block_scopes(statements, *tail, body, scopes, &mut scope, resolve_const_block);
+ compute_block_scopes(statements, *tail, store, scopes, &mut scope, resolve_const_block);
}
Expr::Loop { body: body_expr, label } => {
let mut scope = scopes.new_labeled_scope(*scope, make_label(label));
@@ -290,14 +290,14 @@ fn compute_expr_scopes(
}
Expr::Closure { args, body: body_expr, .. } => {
let mut scope = scopes.new_scope(*scope);
- scopes.add_params_bindings(body, scope, args);
+ scopes.add_params_bindings(store, scope, args);
compute_expr_scopes(scopes, *body_expr, &mut scope);
}
Expr::Match { expr, arms } => {
compute_expr_scopes(scopes, *expr, scope);
for arm in arms.iter() {
let mut scope = scopes.new_scope(*scope);
- scopes.add_pat_bindings(body, scope, arm.pat);
+ scopes.add_pat_bindings(store, scope, arm.pat);
if let Some(guard) = arm.guard {
scope = scopes.new_scope(scope);
compute_expr_scopes(scopes, guard, &mut scope);
@@ -316,9 +316,9 @@ fn compute_expr_scopes(
&Expr::Let { pat, expr } => {
compute_expr_scopes(scopes, expr, scope);
*scope = scopes.new_scope(*scope);
- scopes.add_pat_bindings(body, *scope, pat);
+ scopes.add_pat_bindings(store, *scope, pat);
}
- _ => body.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
+ _ => store.walk_child_exprs(expr, |e| compute_expr_scopes(scopes, e, scope)),
};
}
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
similarity index 99%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
index edc7c4c1f211b..9bf1ddb479380 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/body/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests.rs
@@ -1,6 +1,7 @@
mod block;
use expect_test::{expect, Expect};
+use la_arena::RawIdx;
use test_fixture::WithFixture;
use crate::{test_db::TestDB, ModuleDefId};
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs b/src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/block.rs
similarity index 100%
rename from src/tools/rust-analyzer/crates/hir-def/src/body/tests/block.rs
rename to src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/block.rs
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 7b3f1d06d21b6..e2b36da79b232 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/generics.rs
@@ -433,7 +433,7 @@ impl GenericParams {
GenericDefId::TraitAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::TypeAliasId(id) => id_to_generics(db, id, enabled_params),
GenericDefId::ImplId(id) => id_to_generics(db, id, enabled_params),
- GenericDefId::ConstId(_) => (
+ GenericDefId::ConstId(_) | GenericDefId::StaticId(_) => (
Arc::new(GenericParams {
type_or_consts: Default::default(),
lifetimes: Default::default(),
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 8596346943022..0dcddf162b2fa 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/hir.rs
@@ -19,7 +19,7 @@ use std::fmt;
use hir_expand::{name::Name, MacroDefId};
use intern::Symbol;
-use la_arena::{Idx, RawIdx};
+use la_arena::Idx;
use rustc_apfloat::ieee::{Half as f16, Quad as f128};
use syntax::ast;
use type_ref::TypeRefId;
@@ -37,13 +37,10 @@ pub type BindingId = Idx;
pub type ExprId = Idx;
-/// FIXME: this is a hacky function which should be removed
-pub(crate) fn dummy_expr_id() -> ExprId {
- ExprId::from_raw(RawIdx::from(u32::MAX))
-}
-
pub type PatId = Idx;
+// FIXME: Encode this as a single u32, we won't ever reach all 32 bits especially given these counts
+// are local to the body.
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum ExprOrPatId {
ExprId(ExprId),
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 34635997bdff3..6137bd34d64a0 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
@@ -519,7 +519,7 @@ mod tests {
crate_graph[krate]
.display_name
.as_ref()
- .is_some_and(|it| &**it.crate_name() == crate_name)
+ .is_some_and(|it| it.crate_name().as_str() == crate_name)
})
.expect("could not find crate");
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 b5bf2feb82a20..8d5b3eeb28e10 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
@@ -937,7 +937,7 @@ pub struct Param {
bitflags::bitflags! {
#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
- pub(crate) struct FnFlags: u8 {
+ pub(crate) struct FnFlags: u16 {
const HAS_SELF_PARAM = 1 << 0;
const HAS_BODY = 1 << 1;
const HAS_DEFAULT_KW = 1 << 2;
@@ -946,6 +946,12 @@ bitflags::bitflags! {
const HAS_UNSAFE_KW = 1 << 5;
const IS_VARARGS = 1 << 6;
const HAS_SAFE_KW = 1 << 7;
+ /// The `#[target_feature]` attribute is necessary to check safety (with RFC 2396),
+ /// but keeping it for all functions will consume a lot of memory when there are
+ /// only very few functions with it. So we only encode its existence here, and lookup
+ /// it if needed.
+ const HAS_TARGET_FEATURE = 1 << 8;
+ const DEPRECATED_SAFE_2024 = 1 << 9;
}
}
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 38733577d1c86..59f51db9f7401 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
@@ -502,4 +502,5 @@ language_item_table! {
String, sym::String, string, Target::Struct, GenericRequirement::None;
CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
+ Ordering, sym::Ordering, ordering, Target::Enum, GenericRequirement::None;
}
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 c78818c642ceb..c8efd9043203b 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lib.rs
@@ -42,7 +42,7 @@ pub mod lang_item;
pub mod hir;
pub use self::hir::type_ref;
-pub mod body;
+pub mod expr_store;
pub mod resolver;
pub mod nameres;
@@ -693,6 +693,7 @@ impl TypeOwnerId {
Some(match self {
TypeOwnerId::FunctionId(it) => GenericDefId::FunctionId(it),
TypeOwnerId::ConstId(it) => GenericDefId::ConstId(it),
+ TypeOwnerId::StaticId(it) => GenericDefId::StaticId(it),
TypeOwnerId::AdtId(it) => GenericDefId::AdtId(it),
TypeOwnerId::TraitId(it) => GenericDefId::TraitId(it),
TypeOwnerId::TraitAliasId(it) => GenericDefId::TraitAliasId(it),
@@ -701,7 +702,7 @@ impl TypeOwnerId {
TypeOwnerId::EnumVariantId(it) => {
GenericDefId::AdtId(AdtId::EnumId(it.lookup(db).parent))
}
- TypeOwnerId::InTypeConstId(_) | TypeOwnerId::StaticId(_) => return None,
+ TypeOwnerId::InTypeConstId(_) => return None,
})
}
}
@@ -743,6 +744,7 @@ impl From for TypeOwnerId {
GenericDefId::TypeAliasId(it) => it.into(),
GenericDefId::ImplId(it) => it.into(),
GenericDefId::ConstId(it) => it.into(),
+ GenericDefId::StaticId(it) => it.into(),
}
}
}
@@ -851,7 +853,7 @@ impl GeneralConstId {
pub fn generic_def(self, db: &dyn DefDatabase) -> Option {
match self {
GeneralConstId::ConstId(it) => Some(it.into()),
- GeneralConstId::StaticId(_) => None,
+ GeneralConstId::StaticId(it) => Some(it.into()),
GeneralConstId::ConstBlockId(it) => it.lookup(db).parent.as_generic_def_id(db),
GeneralConstId::InTypeConstId(it) => it.lookup(db).owner.as_generic_def_id(db),
}
@@ -897,7 +899,7 @@ impl DefWithBodyId {
pub fn as_generic_def_id(self, db: &dyn DefDatabase) -> Option {
match self {
DefWithBodyId::FunctionId(f) => Some(f.into()),
- DefWithBodyId::StaticId(_) => None,
+ DefWithBodyId::StaticId(s) => Some(s.into()),
DefWithBodyId::ConstId(c) => Some(c.into()),
DefWithBodyId::VariantId(c) => Some(c.lookup(db).parent.into()),
// FIXME: stable rust doesn't allow generics in constants, but we should
@@ -922,23 +924,28 @@ impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub enum GenericDefId {
- FunctionId(FunctionId),
AdtId(AdtId),
- TraitId(TraitId),
- TraitAliasId(TraitAliasId),
- TypeAliasId(TypeAliasId),
- ImplId(ImplId),
// consts can have type parameters from their parents (i.e. associated consts of traits)
ConstId(ConstId),
+ FunctionId(FunctionId),
+ ImplId(ImplId),
+ // can't actually have generics currently, but they might in the future
+ // More importantly, this completes the set of items that contain type references
+ // which is to be used by the signature expression store in the future.
+ StaticId(StaticId),
+ TraitAliasId(TraitAliasId),
+ TraitId(TraitId),
+ TypeAliasId(TypeAliasId),
}
impl_from!(
- FunctionId,
AdtId(StructId, EnumId, UnionId),
- TraitId,
- TraitAliasId,
- TypeAliasId,
+ ConstId,
+ FunctionId,
ImplId,
- ConstId
+ StaticId,
+ TraitAliasId,
+ TraitId,
+ TypeAliasId
for GenericDefId
);
@@ -969,6 +976,7 @@ impl GenericDefId {
GenericDefId::TraitAliasId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::ImplId(it) => file_id_and_params_of_item_loc(db, it),
GenericDefId::ConstId(it) => (it.lookup(db).id.file_id(), None),
+ GenericDefId::StaticId(it) => (it.lookup(db).id.file_id(), None),
}
}
@@ -1350,6 +1358,7 @@ impl HasModule for GenericDefId {
GenericDefId::TypeAliasId(it) => it.module(db),
GenericDefId::ImplId(it) => it.module(db),
GenericDefId::ConstId(it) => it.module(db),
+ GenericDefId::StaticId(it) => it.module(db),
}
}
}
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 39d383f0159b1..3b6e3c5916e32 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -337,7 +337,7 @@ impl DefMap {
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: CrateId) -> Arc {
let crate_graph = db.crate_graph();
let krate = &crate_graph[crate_id];
- let name = krate.display_name.as_deref().unwrap_or_default();
+ let name = krate.display_name.as_deref().map(Symbol::as_str).unwrap_or_default();
let _p = tracing::info_span!("crate_def_map_query", ?name).entered();
let module_data = ModuleData::new(
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
index 8c556d8a8c3f4..7e13ae2f7a1be 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/resolver.rs
@@ -10,13 +10,13 @@ use smallvec::{smallvec, SmallVec};
use triomphe::Arc;
use crate::{
- body::{
- scope::{ExprScopes, ScopeId},
- HygieneId,
- },
builtin_type::BuiltinType,
data::ExternCrateDeclData,
db::DefDatabase,
+ expr_store::{
+ scope::{ExprScopes, ScopeId},
+ HygieneId,
+ },
generics::{GenericParams, TypeOrConstParamData},
hir::{BindingId, ExprId, LabelId},
item_scope::{BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, BUILTIN_SCOPE},
@@ -1264,6 +1264,7 @@ impl HasResolver for GenericDefId {
GenericDefId::TypeAliasId(inner) => inner.resolver(db),
GenericDefId::ImplId(inner) => inner.resolver(db),
GenericDefId::ConstId(inner) => inner.resolver(db),
+ GenericDefId::StaticId(inner) => inner.resolver(db),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
index 848870c3a3844..21e5fb5ef9e1c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/name.rs
@@ -262,6 +262,6 @@ impl AsName for ast::FieldKind {
impl AsName for base_db::Dependency {
fn as_name(&self) -> Name {
- Name::new_root(&self.name)
+ Name::new_symbol_root((*self.name).clone())
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
index 6ff7831fd81a2..c744fbce77b7c 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/prettify_macro_expansion_.rs
@@ -41,9 +41,9 @@ pub fn prettify_macro_expansion(
} else if let Some(dep) =
target_crate.dependencies.iter().find(|dep| dep.crate_id == macro_def_crate)
{
- make::tokens::ident(&dep.name)
+ make::tokens::ident(dep.name.as_str())
} else if let Some(crate_name) = &crate_graph[macro_def_crate].display_name {
- make::tokens::ident(crate_name.crate_name())
+ make::tokens::ident(crate_name.crate_name().as_str())
} else {
return dollar_crate.clone();
}
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 62feca5f8cbbf..e0e366f450198 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/autoderef.rs
@@ -194,7 +194,11 @@ pub(crate) fn deref_by_trait(
}
let trait_id = || {
- if use_receiver_trait {
+ // FIXME: Remove the `false` once `Receiver` needs to be stabilized, doing so will
+ // effectively bump the MSRV of rust-analyzer to 1.84 due to 1.83 and below lacking the
+ // blanked impl on `Deref`.
+ #[expect(clippy::overly_complex_bool_expr)]
+ if use_receiver_trait && false {
if let Some(receiver) =
db.lang_item(table.trait_env.krate, LangItem::Receiver).and_then(|l| l.as_trait())
{
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 142766c039b5c..7839589994b2f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/consteval.rs
@@ -3,7 +3,7 @@
use base_db::{ra_salsa::Cycle, CrateId};
use chalk_ir::{cast::Cast, BoundVar, DebruijnIndex};
use hir_def::{
- body::{Body, HygieneId},
+ expr_store::{Body, HygieneId},
hir::{Expr, ExprId},
path::Path,
resolver::{Resolver, ValueNs},
@@ -124,6 +124,7 @@ pub(crate) fn path_to_const<'g>(
ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
expected_ty,
)),
+ // FIXME: With feature(adt_const_params), we also need to consider other things here, e.g. struct constructors.
_ => None,
}
}
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 7f9f0c0de197b..0b5f1319243f6 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
@@ -36,7 +36,7 @@ use crate::{
};
pub(crate) use hir_def::{
- body::Body,
+ expr_store::Body,
hir::{Expr, ExprId, MatchArm, Pat, PatId, Statement},
LocalFieldId, VariantId,
};
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
index c5d8c9566155d..b0f9fc53e29ee 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check.rs
@@ -11,7 +11,8 @@ pub(crate) mod pat_analysis;
use chalk_ir::Mutability;
use hir_def::{
- body::Body, data::adt::VariantData, hir::PatId, AdtId, EnumVariantId, LocalFieldId, VariantId,
+ data::adt::VariantData, expr_store::Body, hir::PatId, AdtId, EnumVariantId, LocalFieldId,
+ VariantId,
};
use hir_expand::name::Name;
use span::Edition;
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 6bba83fac9886..ac849b0762d7f 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
@@ -5,28 +5,31 @@ use std::mem;
use either::Either;
use hir_def::{
- body::Body,
+ expr_store::Body,
hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
path::Path,
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
type_ref::Rawness,
- AdtId, DefWithBodyId, FieldId, VariantId,
+ AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
};
+use span::Edition;
use crate::{
- db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TyExt, TyKind,
+ db::HirDatabase, utils::is_fn_unsafe_to_call, InferenceResult, Interner, TargetFeatures, TyExt,
+ TyKind,
};
-/// Returns `(unsafe_exprs, fn_is_unsafe)`.
-///
-/// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
-pub fn missing_unsafe(
- db: &dyn HirDatabase,
- def: DefWithBodyId,
-) -> (Vec<(ExprOrPatId, UnsafetyReason)>, bool) {
+#[derive(Debug, Default)]
+pub struct MissingUnsafeResult {
+ pub unsafe_exprs: Vec<(ExprOrPatId, UnsafetyReason)>,
+ /// If `fn_is_unsafe` is false, `unsafe_exprs` are hard errors. If true, they're `unsafe_op_in_unsafe_fn`.
+ pub fn_is_unsafe: bool,
+ pub deprecated_safe_calls: Vec,
+}
+
+pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> MissingUnsafeResult {
let _p = tracing::info_span!("missing_unsafe").entered();
- let mut res = Vec::new();
let is_unsafe = match def {
DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
DefWithBodyId::StaticId(_)
@@ -35,11 +38,19 @@ pub fn missing_unsafe(
| DefWithBodyId::InTypeConstId(_) => false,
};
+ let mut res = MissingUnsafeResult { fn_is_unsafe: is_unsafe, ..MissingUnsafeResult::default() };
let body = db.body(def);
let infer = db.infer(def);
- let mut callback = |node, inside_unsafe_block, reason| {
- if inside_unsafe_block == InsideUnsafeBlock::No {
- res.push((node, reason));
+ let mut callback = |diag| match diag {
+ UnsafeDiagnostic::UnsafeOperation { node, inside_unsafe_block, reason } => {
+ if inside_unsafe_block == InsideUnsafeBlock::No {
+ res.unsafe_exprs.push((node, reason));
+ }
+ }
+ UnsafeDiagnostic::DeprecatedSafe2024 { node, inside_unsafe_block } => {
+ if inside_unsafe_block == InsideUnsafeBlock::No {
+ res.deprecated_safe_calls.push(node)
+ }
}
};
let mut visitor = UnsafeVisitor::new(db, &infer, &body, def, &mut callback);
@@ -54,7 +65,7 @@ pub fn missing_unsafe(
}
}
- (res, is_unsafe)
+ res
}
#[derive(Debug, Clone, Copy)]
@@ -73,15 +84,31 @@ pub enum InsideUnsafeBlock {
Yes,
}
+#[derive(Debug)]
+enum UnsafeDiagnostic {
+ UnsafeOperation {
+ node: ExprOrPatId,
+ inside_unsafe_block: InsideUnsafeBlock,
+ reason: UnsafetyReason,
+ },
+ /// A lint.
+ DeprecatedSafe2024 { node: ExprId, inside_unsafe_block: InsideUnsafeBlock },
+}
+
pub fn unsafe_expressions(
db: &dyn HirDatabase,
infer: &InferenceResult,
def: DefWithBodyId,
body: &Body,
current: ExprId,
- unsafe_expr_cb: &mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason),
+ callback: &mut dyn FnMut(InsideUnsafeBlock),
) {
- let mut visitor = UnsafeVisitor::new(db, infer, body, def, unsafe_expr_cb);
+ let mut visitor_callback = |diag| {
+ if let UnsafeDiagnostic::UnsafeOperation { inside_unsafe_block, .. } = diag {
+ callback(inside_unsafe_block);
+ }
+ };
+ let mut visitor = UnsafeVisitor::new(db, infer, body, def, &mut visitor_callback);
_ = visitor.resolver.update_to_inner_scope(db.upcast(), def, current);
visitor.walk_expr(current);
}
@@ -95,7 +122,10 @@ struct UnsafeVisitor<'a> {
inside_unsafe_block: InsideUnsafeBlock,
inside_assignment: bool,
inside_union_destructure: bool,
- unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason),
+ callback: &'a mut dyn FnMut(UnsafeDiagnostic),
+ def_target_features: TargetFeatures,
+ // FIXME: This needs to be the edition of the span of each call.
+ edition: Edition,
}
impl<'a> UnsafeVisitor<'a> {
@@ -104,9 +134,14 @@ impl<'a> UnsafeVisitor<'a> {
infer: &'a InferenceResult,
body: &'a Body,
def: DefWithBodyId,
- unsafe_expr_cb: &'a mut dyn FnMut(ExprOrPatId, InsideUnsafeBlock, UnsafetyReason),
+ unsafe_expr_cb: &'a mut dyn FnMut(UnsafeDiagnostic),
) -> Self {
let resolver = def.resolver(db.upcast());
+ let def_target_features = match def {
+ DefWithBodyId::FunctionId(func) => TargetFeatures::from_attrs(&db.attrs(func.into())),
+ _ => TargetFeatures::default(),
+ };
+ let edition = db.crate_graph()[resolver.module().krate()].edition;
Self {
db,
infer,
@@ -116,12 +151,34 @@ impl<'a> UnsafeVisitor<'a> {
inside_unsafe_block: InsideUnsafeBlock::No,
inside_assignment: false,
inside_union_destructure: false,
- unsafe_expr_cb,
+ callback: unsafe_expr_cb,
+ def_target_features,
+ edition,
}
}
- fn call_cb(&mut self, node: ExprOrPatId, reason: UnsafetyReason) {
- (self.unsafe_expr_cb)(node, self.inside_unsafe_block, reason);
+ fn on_unsafe_op(&mut self, node: ExprOrPatId, reason: UnsafetyReason) {
+ (self.callback)(UnsafeDiagnostic::UnsafeOperation {
+ node,
+ inside_unsafe_block: self.inside_unsafe_block,
+ reason,
+ });
+ }
+
+ fn check_call(&mut self, node: ExprId, func: FunctionId) {
+ let unsafety = is_fn_unsafe_to_call(self.db, func, &self.def_target_features, self.edition);
+ match unsafety {
+ crate::utils::Unsafety::Safe => {}
+ crate::utils::Unsafety::Unsafe => {
+ self.on_unsafe_op(node.into(), UnsafetyReason::UnsafeFnCall)
+ }
+ crate::utils::Unsafety::DeprecatedSafe2024 => {
+ (self.callback)(UnsafeDiagnostic::DeprecatedSafe2024 {
+ node,
+ inside_unsafe_block: self.inside_unsafe_block,
+ })
+ }
+ }
}
fn walk_pats_top(&mut self, pats: impl Iterator- , parent_expr: ExprId) {
@@ -146,7 +203,9 @@ impl<'a> UnsafeVisitor<'a> {
| Pat::Ref { .. }
| Pat::Box { .. }
| Pat::Expr(..)
- | Pat::ConstBlock(..) => self.call_cb(current.into(), UnsafetyReason::UnionField),
+ | Pat::ConstBlock(..) => {
+ self.on_unsafe_op(current.into(), UnsafetyReason::UnionField)
+ }
// `Or` only wraps other patterns, and `Missing`/`Wild` do not constitute a read.
Pat::Missing | Pat::Wild | Pat::Or(_) => {}
}
@@ -180,9 +239,13 @@ impl<'a> UnsafeVisitor<'a> {
let inside_assignment = mem::replace(&mut self.inside_assignment, false);
match expr {
&Expr::Call { callee, .. } => {
- if let Some(func) = self.infer[callee].as_fn_def(self.db) {
- if is_fn_unsafe_to_call(self.db, func) {
- self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall);
+ let callee = &self.infer[callee];
+ if let Some(func) = callee.as_fn_def(self.db) {
+ self.check_call(current, func);
+ }
+ if let TyKind::Function(fn_ptr) = callee.kind(Interner) {
+ if fn_ptr.sig.safety == chalk_ir::Safety::Unsafe {
+ self.on_unsafe_op(current.into(), UnsafetyReason::UnsafeFnCall);
}
}
}
@@ -209,18 +272,13 @@ impl<'a> UnsafeVisitor<'a> {
}
}
Expr::MethodCall { .. } => {
- if self
- .infer
- .method_resolution(current)
- .map(|(func, _)| is_fn_unsafe_to_call(self.db, func))
- .unwrap_or(false)
- {
- self.call_cb(current.into(), UnsafetyReason::UnsafeFnCall);
+ if let Some((func, _)) = self.infer.method_resolution(current) {
+ self.check_call(current, func);
}
}
Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
if let TyKind::Raw(..) = &self.infer[*expr].kind(Interner) {
- self.call_cb(current.into(), UnsafetyReason::RawPtrDeref);
+ self.on_unsafe_op(current.into(), UnsafetyReason::RawPtrDeref);
}
}
Expr::Unsafe { .. } => {
@@ -235,7 +293,7 @@ impl<'a> UnsafeVisitor<'a> {
self.walk_pats_top(std::iter::once(target), current);
self.inside_assignment = old_inside_assignment;
}
- Expr::InlineAsm(_) => self.call_cb(current.into(), UnsafetyReason::InlineAsm),
+ Expr::InlineAsm(_) => self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm),
// rustc allows union assignment to propagate through field accesses and casts.
Expr::Cast { .. } => self.inside_assignment = inside_assignment,
Expr::Field { .. } => {
@@ -244,7 +302,7 @@ impl<'a> UnsafeVisitor<'a> {
if let Some(Either::Left(FieldId { parent: VariantId::UnionId(_), .. })) =
self.infer.field_resolution(current)
{
- self.call_cb(current.into(), UnsafetyReason::UnionField);
+ self.on_unsafe_op(current.into(), UnsafetyReason::UnionField);
}
}
}
@@ -279,9 +337,9 @@ impl<'a> UnsafeVisitor<'a> {
if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id), _)) = value_or_partial {
let static_data = self.db.static_data(id);
if static_data.mutable {
- self.call_cb(node, UnsafetyReason::MutableStatic);
+ self.on_unsafe_op(node, UnsafetyReason::MutableStatic);
} else if static_data.is_extern && !static_data.has_safe_kw {
- self.call_cb(node, UnsafetyReason::ExternStatic);
+ self.on_unsafe_op(node, UnsafetyReason::ExternStatic);
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
index abbf2a4f2efd4..18cf6e5ce36ef 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/generics.rs
@@ -262,7 +262,8 @@ fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option
it.lookup(db).container,
GenericDefId::TypeAliasId(it) => it.lookup(db).container,
GenericDefId::ConstId(it) => it.lookup(db).container,
- GenericDefId::AdtId(_)
+ GenericDefId::StaticId(_)
+ | GenericDefId::AdtId(_)
| GenericDefId::TraitId(_)
| GenericDefId::ImplId(_)
| GenericDefId::TraitAliasId(_) => return None,
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 25bb3a76de2c5..617ebba8811e2 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer.rs
@@ -34,9 +34,9 @@ use chalk_ir::{
};
use either::Either;
use hir_def::{
- body::{Body, HygieneId},
builtin_type::{BuiltinInt, BuiltinType, BuiltinUint},
data::{ConstData, StaticData},
+ expr_store::{Body, HygieneId},
hir::{BindingAnnotation, BindingId, ExprId, ExprOrPatId, LabelId, PatId},
lang_item::{LangItem, LangItemTarget},
layout::Integer,
@@ -466,6 +466,9 @@ pub struct InferenceResult {
pub type_of_for_iterator: FxHashMap,
type_mismatches: FxHashMap,
/// Whether there are any type-mismatching errors in the result.
+ // FIXME: This isn't as useful as initially thought due to us falling back placeholders to
+ // `TyKind::Error`.
+ // Which will then mark this field.
pub(crate) has_errors: bool,
/// Interned common types to return references to.
// FIXME: Move this into `InferenceContext`
@@ -943,7 +946,7 @@ impl<'a> InferenceContext<'a> {
let ty = self.insert_type_vars(ty);
let ty = self.normalize_associated_types_in(ty);
- self.infer_top_pat(*pat, &ty);
+ self.infer_top_pat(*pat, &ty, None);
if ty
.data(Interner)
.flags
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
index 21d0be6ed5f76..eb193686e967f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/cast.rs
@@ -374,6 +374,7 @@ enum PointerKind {
fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result, ()> {
let ty = table.resolve_ty_shallow(ty);
+ let ty = table.normalize_associated_types_in(ty);
if table.is_sized(&ty) {
return Ok(Some(PointerKind::Thin));
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
index 032dc37899dea..b85378531ad65 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/diagnostics.rs
@@ -5,7 +5,7 @@
use std::cell::RefCell;
use std::ops::{Deref, DerefMut};
-use hir_def::body::HygieneId;
+use hir_def::expr_store::HygieneId;
use hir_def::hir::ExprOrPatId;
use hir_def::path::{Path, PathSegment, PathSegments};
use hir_def::resolver::{ResolveValueResult, Resolver, TypeNs};
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 b951443897cb0..86e5afdb50923 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
@@ -43,9 +43,9 @@ use crate::{
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
- Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, FnAbi, FnPointer,
- FnSig, FnSubst, Interner, Rawness, Scalar, Substitution, TraitEnvironment, TraitRef, Ty,
- TyBuilder, TyExt, TyKind,
+ Adjust, Adjustment, AdtId, AutoBorrow, Binders, CallableDefId, CallableSig, DeclContext,
+ DeclOrigin, FnAbi, FnPointer, FnSig, FnSubst, Interner, Rawness, Scalar, Substitution,
+ TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};
use super::{
@@ -334,7 +334,11 @@ impl InferenceContext<'_> {
ExprIsRead::No
};
let input_ty = self.infer_expr(expr, &Expectation::none(), child_is_read);
- self.infer_top_pat(pat, &input_ty);
+ self.infer_top_pat(
+ pat,
+ &input_ty,
+ Some(DeclContext { origin: DeclOrigin::LetExpr }),
+ );
self.result.standard_types.bool_.clone()
}
Expr::Block { statements, tail, label, id } => {
@@ -461,7 +465,7 @@ impl InferenceContext<'_> {
// Now go through the argument patterns
for (arg_pat, arg_ty) in args.iter().zip(&sig_tys) {
- self.infer_top_pat(*arg_pat, arg_ty);
+ self.infer_top_pat(*arg_pat, arg_ty, None);
}
// FIXME: lift these out into a struct
@@ -582,7 +586,7 @@ impl InferenceContext<'_> {
let mut all_arms_diverge = Diverges::Always;
for arm in arms.iter() {
let input_ty = self.resolve_ty_shallow(&input_ty);
- self.infer_top_pat(arm.pat, &input_ty);
+ self.infer_top_pat(arm.pat, &input_ty, None);
}
let expected = expected.adjust_for_branches(&mut self.table);
@@ -927,7 +931,7 @@ impl InferenceContext<'_> {
let resolver_guard =
self.resolver.update_to_inner_scope(self.db.upcast(), self.owner, tgt_expr);
self.inside_assignment = true;
- self.infer_top_pat(target, &rhs_ty);
+ self.infer_top_pat(target, &rhs_ty, None);
self.inside_assignment = false;
self.resolver.reset_to_guard(resolver_guard);
}
@@ -1632,8 +1636,11 @@ impl InferenceContext<'_> {
decl_ty
};
- this.infer_top_pat(*pat, &ty);
+ let decl = DeclContext {
+ origin: DeclOrigin::LocalDecl { has_else: else_branch.is_some() },
+ };
+ this.infer_top_pat(*pat, &ty, Some(decl));
if let Some(expr) = else_branch {
let previous_diverges =
mem::replace(&mut this.diverges, Diverges::Maybe);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
index 00398f019da52..5ff22bea34dea 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/pat.rs
@@ -3,23 +3,24 @@
use std::iter::repeat_with;
use hir_def::{
- body::Body,
+ expr_store::Body,
hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, Literal, Pat, PatId},
path::Path,
+ HasModule,
};
use hir_expand::name::Name;
use stdx::TupleExt;
use crate::{
- consteval::{try_const_usize, usize_const},
+ consteval::{self, try_const_usize, usize_const},
infer::{
coerce::CoerceNever, expr::ExprIsRead, BindingMode, Expectation, InferenceContext,
TypeMismatch,
},
lower::lower_to_chalk_mutability,
primitive::UintTy,
- static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
- TyBuilder, TyExt, TyKind,
+ static_lifetime, DeclContext, DeclOrigin, InferenceDiagnostic, Interner, Mutability, Scalar,
+ Substitution, Ty, TyBuilder, TyExt, TyKind,
};
impl InferenceContext<'_> {
@@ -34,6 +35,7 @@ impl InferenceContext<'_> {
id: PatId,
ellipsis: Option,
subs: &[PatId],
+ decl: Option,
) -> Ty {
let (ty, def) = self.resolve_variant(id.into(), path, true);
let var_data = def.map(|it| it.variant_data(self.db.upcast()));
@@ -92,13 +94,13 @@ impl InferenceContext<'_> {
}
};
- self.infer_pat(subpat, &expected_ty, default_bm);
+ self.infer_pat(subpat, &expected_ty, default_bm, decl);
}
}
None => {
let err_ty = self.err_ty();
for &inner in subs {
- self.infer_pat(inner, &err_ty, default_bm);
+ self.infer_pat(inner, &err_ty, default_bm, decl);
}
}
}
@@ -114,6 +116,7 @@ impl InferenceContext<'_> {
default_bm: BindingMode,
id: PatId,
subs: impl ExactSizeIterator- ,
+ decl: Option
,
) -> Ty {
let (ty, def) = self.resolve_variant(id.into(), path, false);
if let Some(variant) = def {
@@ -162,13 +165,13 @@ impl InferenceContext<'_> {
}
};
- self.infer_pat(inner, &expected_ty, default_bm);
+ self.infer_pat(inner, &expected_ty, default_bm, decl);
}
}
None => {
let err_ty = self.err_ty();
for (_, inner) in subs {
- self.infer_pat(inner, &err_ty, default_bm);
+ self.infer_pat(inner, &err_ty, default_bm, decl);
}
}
}
@@ -185,6 +188,7 @@ impl InferenceContext<'_> {
default_bm: BindingMode,
ellipsis: Option,
subs: &[PatId],
+ decl: Option,
) -> Ty {
let expected = self.resolve_ty_shallow(expected);
let expectations = match expected.as_tuple() {
@@ -209,12 +213,12 @@ impl InferenceContext<'_> {
// Process pre
for (ty, pat) in inner_tys.iter_mut().zip(pre) {
- *ty = self.infer_pat(*pat, ty, default_bm);
+ *ty = self.infer_pat(*pat, ty, default_bm, decl);
}
// Process post
for (ty, pat) in inner_tys.iter_mut().skip(pre.len() + n_uncovered_patterns).zip(post) {
- *ty = self.infer_pat(*pat, ty, default_bm);
+ *ty = self.infer_pat(*pat, ty, default_bm, decl);
}
TyKind::Tuple(inner_tys.len(), Substitution::from_iter(Interner, inner_tys))
@@ -223,11 +227,17 @@ impl InferenceContext<'_> {
/// The resolver needs to be updated to the surrounding expression when inside assignment
/// (because there, `Pat::Path` can refer to a variable).
- pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty) {
- self.infer_pat(pat, expected, BindingMode::default());
+ pub(super) fn infer_top_pat(&mut self, pat: PatId, expected: &Ty, decl: Option) {
+ self.infer_pat(pat, expected, BindingMode::default(), decl);
}
- fn infer_pat(&mut self, pat: PatId, expected: &Ty, mut default_bm: BindingMode) -> Ty {
+ fn infer_pat(
+ &mut self,
+ pat: PatId,
+ expected: &Ty,
+ mut default_bm: BindingMode,
+ decl: Option,
+ ) -> Ty {
let mut expected = self.resolve_ty_shallow(expected);
if matches!(&self.body[pat], Pat::Ref { .. }) || self.inside_assignment {
@@ -261,11 +271,11 @@ impl InferenceContext<'_> {
let ty = match &self.body[pat] {
Pat::Tuple { args, ellipsis } => {
- self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args)
+ self.infer_tuple_pat_like(&expected, default_bm, *ellipsis, args, decl)
}
Pat::Or(pats) => {
for pat in pats.iter() {
- self.infer_pat(*pat, &expected, default_bm);
+ self.infer_pat(*pat, &expected, default_bm, decl);
}
expected.clone()
}
@@ -274,6 +284,7 @@ impl InferenceContext<'_> {
lower_to_chalk_mutability(mutability),
&expected,
default_bm,
+ decl,
),
Pat::TupleStruct { path: p, args: subpats, ellipsis } => self
.infer_tuple_struct_pat_like(
@@ -283,10 +294,11 @@ impl InferenceContext<'_> {
pat,
*ellipsis,
subpats,
+ decl,
),
Pat::Record { path: p, args: fields, ellipsis: _ } => {
let subs = fields.iter().map(|f| (f.name.clone(), f.pat));
- self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs)
+ self.infer_record_pat_like(p.as_deref(), &expected, default_bm, pat, subs, decl)
}
Pat::Path(path) => {
let ty = self.infer_path(path, pat.into()).unwrap_or_else(|| self.err_ty());
@@ -319,10 +331,10 @@ impl InferenceContext<'_> {
}
}
Pat::Bind { id, subpat } => {
- return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected);
+ return self.infer_bind_pat(pat, *id, default_bm, *subpat, &expected, decl);
}
Pat::Slice { prefix, slice, suffix } => {
- self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm)
+ self.infer_slice_pat(&expected, prefix, slice, suffix, default_bm, decl)
}
Pat::Wild => expected.clone(),
Pat::Range { .. } => {
@@ -345,7 +357,7 @@ impl InferenceContext<'_> {
_ => (self.result.standard_types.unknown.clone(), None),
};
- let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm);
+ let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm, decl);
let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty);
if let Some(alloc_ty) = alloc_ty {
@@ -420,6 +432,7 @@ impl InferenceContext<'_> {
mutability: Mutability,
expected: &Ty,
default_bm: BindingMode,
+ decl: Option,
) -> Ty {
let (expectation_type, expectation_lt) = match expected.as_reference() {
Some((inner_ty, lifetime, _exp_mut)) => (inner_ty.clone(), lifetime.clone()),
@@ -433,7 +446,7 @@ impl InferenceContext<'_> {
(inner_ty, inner_lt)
}
};
- let subty = self.infer_pat(inner_pat, &expectation_type, default_bm);
+ let subty = self.infer_pat(inner_pat, &expectation_type, default_bm, decl);
TyKind::Ref(mutability, expectation_lt, subty).intern(Interner)
}
@@ -444,6 +457,7 @@ impl InferenceContext<'_> {
default_bm: BindingMode,
subpat: Option,
expected: &Ty,
+ decl: Option,
) -> Ty {
let Binding { mode, .. } = self.body.bindings[binding];
let mode = if mode == BindingAnnotation::Unannotated {
@@ -454,7 +468,7 @@ impl InferenceContext<'_> {
self.result.binding_modes.insert(pat, mode);
let inner_ty = match subpat {
- Some(subpat) => self.infer_pat(subpat, expected, default_bm),
+ Some(subpat) => self.infer_pat(subpat, expected, default_bm, decl),
None => expected.clone(),
};
let inner_ty = self.insert_type_vars_shallow(inner_ty);
@@ -478,14 +492,28 @@ impl InferenceContext<'_> {
slice: &Option,
suffix: &[PatId],
default_bm: BindingMode,
+ decl: Option,
) -> Ty {
+ let expected = self.resolve_ty_shallow(expected);
+
+ // If `expected` is an infer ty, we try to equate it to an array if the given pattern
+ // allows it. See issue #16609
+ if self.pat_is_irrefutable(decl) && expected.is_ty_var() {
+ if let Some(resolved_array_ty) =
+ self.try_resolve_slice_ty_to_array_ty(prefix, suffix, slice)
+ {
+ self.unify(&expected, &resolved_array_ty);
+ }
+ }
+
+ let expected = self.resolve_ty_shallow(&expected);
let elem_ty = match expected.kind(Interner) {
TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
_ => self.err_ty(),
};
for &pat_id in prefix.iter().chain(suffix.iter()) {
- self.infer_pat(pat_id, &elem_ty, default_bm);
+ self.infer_pat(pat_id, &elem_ty, default_bm, decl);
}
if let &Some(slice_pat_id) = slice {
@@ -499,7 +527,7 @@ impl InferenceContext<'_> {
_ => TyKind::Slice(elem_ty.clone()),
}
.intern(Interner);
- self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm);
+ self.infer_pat(slice_pat_id, &rest_pat_ty, default_bm, decl);
}
match expected.kind(Interner) {
@@ -528,7 +556,7 @@ impl InferenceContext<'_> {
self.infer_expr(expr, &Expectation::has_type(expected.clone()), ExprIsRead::Yes)
}
- fn is_non_ref_pat(&mut self, body: &hir_def::body::Body, pat: PatId) -> bool {
+ fn is_non_ref_pat(&mut self, body: &hir_def::expr_store::Body, pat: PatId) -> bool {
match &body[pat] {
Pat::Tuple { .. }
| Pat::TupleStruct { .. }
@@ -553,6 +581,59 @@ impl InferenceContext<'_> {
| Pat::Expr(_) => false,
}
}
+
+ fn try_resolve_slice_ty_to_array_ty(
+ &mut self,
+ before: &[PatId],
+ suffix: &[PatId],
+ slice: &Option,
+ ) -> Option {
+ if !slice.is_none() {
+ return None;
+ }
+
+ let len = before.len() + suffix.len();
+ let size =
+ consteval::usize_const(self.db, Some(len as u128), self.owner.krate(self.db.upcast()));
+
+ let elem_ty = self.table.new_type_var();
+ let array_ty = TyKind::Array(elem_ty.clone(), size).intern(Interner);
+ Some(array_ty)
+ }
+
+ /// Used to determine whether we can infer the expected type in the slice pattern to be of type array.
+ /// This is only possible if we're in an irrefutable pattern. If we were to allow this in refutable
+ /// patterns we wouldn't e.g. report ambiguity in the following situation:
+ ///
+ /// ```ignore(rust)
+ /// struct Zeroes;
+ /// const ARR: [usize; 2] = [0; 2];
+ /// const ARR2: [usize; 2] = [2; 2];
+ ///
+ /// impl Into<&'static [usize; 2]> for Zeroes {
+ /// fn into(self) -> &'static [usize; 2] {
+ /// &ARR
+ /// }
+ /// }
+ ///
+ /// impl Into<&'static [usize]> for Zeroes {
+ /// fn into(self) -> &'static [usize] {
+ /// &ARR2
+ /// }
+ /// }
+ ///
+ /// fn main() {
+ /// let &[a, b]: &[usize] = Zeroes.into() else {
+ /// ..
+ /// };
+ /// }
+ /// ```
+ ///
+ /// If we're in an irrefutable pattern we prefer the array impl candidate given that
+ /// the slice impl candidate would be rejected anyway (if no ambiguity existed).
+ fn pat_is_irrefutable(&self, decl_ctxt: Option) -> bool {
+ matches!(decl_ctxt, Some(DeclContext { origin: DeclOrigin::LocalDecl { has_else: false } }))
+ }
}
pub(super) fn contains_explicit_ref_binding(body: &Body, pat_id: PatId) -> bool {
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 73bcefaf2a9d6..36ec60a7a2f69 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
@@ -86,10 +86,9 @@ impl InferenceContext<'_> {
}
};
- let generic_def_id = value_def.to_generic_def_id(self.db);
- let Some(generic_def) = generic_def_id else {
- // `value_def` is the kind of item that can never be generic (i.e. statics, at least
- // currently). We can just skip the binders to get its type.
+ let generic_def = value_def.to_generic_def_id(self.db);
+ if let GenericDefId::StaticId(_) = generic_def {
+ // `Static` is the kind of item that can never be generic currently. We can just skip the binders to get its type.
let (ty, binders) = self.db.value_ty(value_def)?.into_value_and_skipped_binders();
stdx::always!(binders.is_empty(Interner), "non-empty binders for non-generic def",);
return Some(ValuePathResolution::NonGeneric(ty));
@@ -122,7 +121,7 @@ impl InferenceContext<'_> {
}
let parent_substs = self_subst.or_else(|| {
- let generics = generics(self.db.upcast(), generic_def_id?);
+ let generics = generics(self.db.upcast(), generic_def);
let parent_params_len = generics.parent_generics()?.len();
let parent_args = &substs[substs.len() - parent_params_len..];
Some(Substitution::from_iter(Interner, parent_args))
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 3c18ea9281655..55d81875a2be4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lib.rs
@@ -100,7 +100,9 @@ pub use mapping::{
};
pub use method_resolution::check_orphan_rules;
pub use traits::TraitEnvironment;
-pub use utils::{all_super_traits, direct_super_traits, is_fn_unsafe_to_call};
+pub use utils::{
+ all_super_traits, direct_super_traits, is_fn_unsafe_to_call, TargetFeatures, Unsafety,
+};
pub use variance::Variance;
pub use chalk_ir::{
@@ -1047,3 +1049,20 @@ pub fn known_const_to_ast(
}
Some(make::expr_const_value(konst.display(db, edition).to_string().as_str()))
}
+
+#[derive(Debug, Copy, Clone)]
+pub(crate) enum DeclOrigin {
+ LetExpr,
+ /// from `let x = ..`
+ LocalDecl {
+ has_else: bool,
+ },
+}
+
+/// Provides context for checking patterns in declarations. More specifically this
+/// allows us to infer array types if the pattern is irrefutable and allows us to infer
+/// the size of the array. See issue rust-lang/rust#76342.
+#[derive(Debug, Copy, Clone)]
+pub(crate) struct DeclContext {
+ pub(crate) origin: DeclOrigin,
+}
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 432b8f4d94eac..db13e1fd35437 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/lower.rs
@@ -23,10 +23,10 @@ use chalk_ir::{
use either::Either;
use hir_def::{
- body::HygieneId,
builtin_type::BuiltinType,
data::{adt::StructKind, TraitFlags},
expander::Expander,
+ expr_store::HygieneId,
generics::{
GenericParamDataRef, TypeOrConstParamData, TypeParamProvenance, WherePredicate,
WherePredicateTypeTarget,
@@ -2471,14 +2471,14 @@ pub enum ValueTyDefId {
impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for ValueTyDefId);
impl ValueTyDefId {
- pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> Option {
+ pub(crate) fn to_generic_def_id(self, db: &dyn HirDatabase) -> GenericDefId {
match self {
- Self::FunctionId(id) => Some(id.into()),
- Self::StructId(id) => Some(id.into()),
- Self::UnionId(id) => Some(id.into()),
- Self::EnumVariantId(var) => Some(var.lookup(db.upcast()).parent.into()),
- Self::ConstId(id) => Some(id.into()),
- Self::StaticId(_) => None,
+ Self::FunctionId(id) => id.into(),
+ Self::StructId(id) => id.into(),
+ Self::UnionId(id) => id.into(),
+ Self::EnumVariantId(var) => var.lookup(db.upcast()).parent.into(),
+ Self::ConstId(id) => id.into(),
+ Self::StaticId(id) => id.into(),
}
}
}
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 1cea67ee96419..db94351dcc995 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
@@ -4,6 +4,7 @@
//! and the corresponding code mostly in rustc_hir_analysis/check/method/probe.rs.
use std::ops::ControlFlow;
+use arrayvec::ArrayVec;
use base_db::CrateId;
use chalk_ir::{cast::Cast, UniverseIndex, WithKind};
use hir_def::{
@@ -732,15 +733,27 @@ fn lookup_impl_assoc_item_for_trait_ref(
let self_ty = trait_ref.self_type_parameter(Interner);
let self_ty_fp = TyFingerprint::for_trait_impl(&self_ty)?;
let impls = db.trait_impls_in_deps(env.krate);
- let self_impls = match self_ty.kind(Interner) {
- TyKind::Adt(id, _) => {
- id.0.module(db.upcast()).containing_block().and_then(|it| db.trait_impls_in_block(it))
+
+ let trait_module = hir_trait_id.module(db.upcast());
+ let type_module = match self_ty_fp {
+ TyFingerprint::Adt(adt_id) => Some(adt_id.module(db.upcast())),
+ TyFingerprint::ForeignType(type_id) => {
+ Some(from_foreign_def_id(type_id).module(db.upcast()))
}
+ TyFingerprint::Dyn(trait_id) => Some(trait_id.module(db.upcast())),
_ => None,
};
+
+ let def_blocks: ArrayVec<_, 2> =
+ [trait_module.containing_block(), type_module.and_then(|it| it.containing_block())]
+ .into_iter()
+ .flatten()
+ .filter_map(|block_id| db.trait_impls_in_block(block_id))
+ .collect();
+
let impls = impls
.iter()
- .chain(self_impls.as_ref())
+ .chain(&def_blocks)
.flat_map(|impls| impls.for_trait_and_self_ty(hir_trait_id, self_ty_fp));
let table = InferenceTable::new(db, env);
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 59c583afb2a85..84d8950b1aa2f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir.rs
@@ -16,7 +16,7 @@ use base_db::CrateId;
use chalk_ir::Mutability;
use either::Either;
use hir_def::{
- body::Body,
+ expr_store::Body,
hir::{BindingAnnotation, BindingId, Expr, ExprId, Ordering, PatId},
DefWithBodyId, FieldId, StaticId, TupleFieldId, UnionId, VariantId,
};
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 dcae6877ba807..6b20522cf34c4 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
@@ -6,9 +6,9 @@ use base_db::CrateId;
use chalk_ir::{cast::Cast, Mutability};
use either::Either;
use hir_def::{
- body::HygieneId,
builtin_type::BuiltinType,
data::adt::{StructFlags, VariantData},
+ expr_store::HygieneId,
lang_item::LangItem,
layout::{TagEncoding, Variants},
resolver::{HasResolver, TypeNs, ValueNs},
@@ -1644,14 +1644,15 @@ impl Evaluator<'_> {
Variants::Multiple { tag, tag_encoding, variants, .. } => {
let size = tag.size(&*self.target_data_layout).bytes_usize();
let offset = layout.fields.offset(0).bytes_usize(); // The only field on enum variants is the tag field
+ let is_signed = tag.is_signed();
match tag_encoding {
TagEncoding::Direct => {
let tag = &bytes[offset..offset + size];
- Ok(i128::from_le_bytes(pad16(tag, false)))
+ Ok(i128::from_le_bytes(pad16(tag, is_signed)))
}
TagEncoding::Niche { untagged_variant, niche_start, .. } => {
let tag = &bytes[offset..offset + size];
- let candidate_tag = i128::from_le_bytes(pad16(tag, false))
+ let candidate_tag = i128::from_le_bytes(pad16(tag, is_signed))
.wrapping_sub(*niche_start as i128)
as usize;
let idx = variants
@@ -2943,10 +2944,10 @@ pub fn render_const_using_debug_impl(
// a3 = ::core::fmt::Arguments::new_v1(a1, a2)
// FIXME: similarly, we should call function here, not directly working with memory.
let a3 = evaluator.heap_allocate(evaluator.ptr_size() * 6, evaluator.ptr_size())?;
- evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a1.to_bytes())?;
+ evaluator.write_memory(a3, &a1.to_bytes())?;
+ evaluator.write_memory(a3.offset(evaluator.ptr_size()), &[1])?;
+ evaluator.write_memory(a3.offset(2 * evaluator.ptr_size()), &a2.to_bytes())?;
evaluator.write_memory(a3.offset(3 * evaluator.ptr_size()), &[1])?;
- evaluator.write_memory(a3.offset(4 * evaluator.ptr_size()), &a2.to_bytes())?;
- evaluator.write_memory(a3.offset(5 * evaluator.ptr_size()), &[1])?;
let Some(ValueNs::FunctionId(format_fn)) = resolver.resolve_path_in_value_ns_fully(
db.upcast(),
&hir_def::path::Path::from_known_path_with_no_generic(path![std::fmt::format]),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 0a78f4a5b24b7..38b189a517f2e 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -1,11 +1,12 @@
//! Interpret intrinsics, lang items and `extern "C"` wellknown functions which their implementation
//! is not available.
//!
-use std::cmp;
+use std::cmp::{self, Ordering};
use chalk_ir::TyKind;
use hir_def::{
builtin_type::{BuiltinInt, BuiltinUint},
+ lang_item::LangItemTarget,
resolver::HasResolver,
};
use hir_expand::name::Name;
@@ -1317,6 +1318,82 @@ impl Evaluator<'_> {
self.write_memory_using_ref(dst, size)?.fill(val);
Ok(())
}
+ "ptr_metadata" => {
+ let [ptr] = args else {
+ return Err(MirEvalError::InternalError(
+ "ptr_metadata args are not provided".into(),
+ ));
+ };
+ let arg = ptr.interval.get(self)?.to_owned();
+ let metadata = &arg[self.ptr_size()..];
+ destination.write_from_bytes(self, metadata)?;
+ Ok(())
+ }
+ "three_way_compare" => {
+ let [lhs, rhs] = args else {
+ return Err(MirEvalError::InternalError(
+ "three_way_compare args are not provided".into(),
+ ));
+ };
+ let Some(ty) =
+ generic_args.as_slice(Interner).first().and_then(|it| it.ty(Interner))
+ else {
+ return Err(MirEvalError::InternalError(
+ "three_way_compare generic arg is not provided".into(),
+ ));
+ };
+ let signed = match ty.as_builtin().unwrap() {
+ BuiltinType::Int(_) => true,
+ BuiltinType::Uint(_) => false,
+ _ => {
+ return Err(MirEvalError::InternalError(
+ "three_way_compare expects an integral type".into(),
+ ))
+ }
+ };
+ let rhs = rhs.get(self)?;
+ let lhs = lhs.get(self)?;
+ let mut result = Ordering::Equal;
+ for (l, r) in lhs.iter().zip(rhs).rev() {
+ let it = l.cmp(r);
+ if it != Ordering::Equal {
+ result = it;
+ break;
+ }
+ }
+ if signed {
+ if let Some((&l, &r)) = lhs.iter().zip(rhs).next_back() {
+ if l != r {
+ result = (l as i8).cmp(&(r as i8));
+ }
+ }
+ }
+ if let Some(LangItemTarget::EnumId(e)) =
+ self.db.lang_item(self.crate_id, LangItem::Ordering)
+ {
+ let ty = self.db.ty(e.into());
+ let r = self
+ .compute_discriminant(ty.skip_binders().clone(), &[result as i8 as u8])?;
+ destination.write_from_bytes(self, &r.to_le_bytes()[0..destination.size])?;
+ Ok(())
+ } else {
+ Err(MirEvalError::InternalError("Ordering enum not found".into()))
+ }
+ }
+ "aggregate_raw_ptr" => {
+ let [data, meta] = args else {
+ return Err(MirEvalError::InternalError(
+ "aggregate_raw_ptr args are not provided".into(),
+ ));
+ };
+ destination.write_from_interval(self, data.interval)?;
+ Interval {
+ addr: destination.addr.offset(data.interval.size),
+ size: destination.size - data.interval.size,
+ }
+ .write_from_interval(self, meta.interval)?;
+ Ok(())
+ }
_ if needs_override => not_supported!("intrinsic {name} is not implemented"),
_ => return Ok(false),
}
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 1d1044df6e964..549450e9bebd7 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
@@ -5,8 +5,8 @@ use std::{fmt::Write, iter, mem};
use base_db::ra_salsa::Cycle;
use chalk_ir::{BoundVar, ConstData, DebruijnIndex, TyKind};
use hir_def::{
- body::{Body, HygieneId},
data::adt::{StructKind, VariantData},
+ expr_store::{Body, HygieneId},
hir::{
ArithOp, Array, BinaryOp, BindingAnnotation, BindingId, ExprId, LabelId, Literal,
LiteralOrConst, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField,
@@ -2156,7 +2156,7 @@ pub fn lower_to_mir(
// need to take this input explicitly.
root_expr: ExprId,
) -> Result {
- if infer.has_errors {
+ if infer.type_mismatches().next().is_some() {
return Err(MirLowerError::HasErrors);
}
let mut ctx = MirLowerCtx::new(db, owner, body, infer);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
index 06765a104cbb4..2a26101ac439f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/pretty.rs
@@ -6,7 +6,7 @@ use std::{
};
use either::Either;
-use hir_def::{body::Body, hir::BindingId};
+use hir_def::{expr_store::Body, hir::BindingId};
use hir_expand::{name::Name, Lookup};
use la_arena::ArenaMap;
use span::Edition;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
index 00da9b251768e..69ec35f406df4 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests.rs
@@ -18,8 +18,8 @@ use std::sync::LazyLock;
use base_db::SourceDatabaseFileInputExt as _;
use expect_test::Expect;
use hir_def::{
- body::{Body, BodySourceMap},
db::DefDatabase,
+ expr_store::{Body, BodySourceMap},
hir::{ExprId, Pat, PatId},
item_scope::ItemScope,
nameres::DefMap,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
index 8866de22dfb99..e5f791ea6ffcd 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/method_resolution.rs
@@ -2163,9 +2163,9 @@ impl Receiver for Bar {
fn main() {
let bar = Bar;
let _v1 = bar.foo1();
- //^^^ type: i32
+ //^^^ type: {unknown}
let _v2 = bar.foo2();
- //^^^ type: bool
+ //^^^ type: {unknown}
}
"#,
);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
index 1563660457050..50a1ecd006d8f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs
@@ -3814,3 +3814,50 @@ async fn foo(a: (), b: i32) -> u32 {
"#,
);
}
+
+#[test]
+fn irrefutable_slices() {
+ check_infer(
+ r#"
+//- minicore: from
+struct A;
+
+impl From for [u8; 2] {
+ fn from(a: A) -> Self {
+ [0; 2]
+ }
+}
+impl From for [u8; 3] {
+ fn from(a: A) -> Self {
+ [0; 3]
+ }
+}
+
+
+fn main() {
+ let a = A;
+ let [b, c] = a.into();
+}
+"#,
+ expect![[r#"
+ 50..51 'a': A
+ 64..86 '{ ... }': [u8; 2]
+ 74..80 '[0; 2]': [u8; 2]
+ 75..76 '0': u8
+ 78..79 '2': usize
+ 128..129 'a': A
+ 142..164 '{ ... }': [u8; 3]
+ 152..158 '[0; 3]': [u8; 3]
+ 153..154 '0': u8
+ 156..157 '3': usize
+ 179..224 '{ ...o(); }': ()
+ 189..190 'a': A
+ 193..194 'A': A
+ 204..210 '[b, c]': [u8; 2]
+ 205..206 'b': u8
+ 208..209 'c': u8
+ 213..214 'a': A
+ 213..221 'a.into()': [u8; 2]
+ "#]],
+ );
+}
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 bf7892f69bd38..c131e97bc4cbe 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/utils.rs
@@ -9,19 +9,22 @@ use chalk_ir::{
DebruijnIndex,
};
use hir_def::{
+ attr::Attrs,
db::DefDatabase,
generics::{WherePredicate, WherePredicateTypeTarget},
lang_item::LangItem,
resolver::{HasResolver, TypeNs},
+ tt,
type_ref::{TraitBoundModifier, TypeRef},
EnumId, EnumVariantId, FunctionId, Lookup, OpaqueInternableThing, TraitId, TypeAliasId,
TypeOrConstParamId,
};
use hir_expand::name::Name;
-use intern::sym;
+use intern::{sym, Symbol};
use rustc_abi::TargetDataLayout;
use rustc_hash::FxHashSet;
use smallvec::{smallvec, SmallVec};
+use span::Edition;
use stdx::never;
use crate::{
@@ -264,10 +267,65 @@ impl<'a> ClosureSubst<'a> {
}
}
-pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
+#[derive(Debug, Default)]
+pub struct TargetFeatures {
+ enabled: FxHashSet,
+}
+
+impl TargetFeatures {
+ pub fn from_attrs(attrs: &Attrs) -> Self {
+ let enabled = attrs
+ .by_key(&sym::target_feature)
+ .tt_values()
+ .filter_map(|tt| {
+ match tt.token_trees().flat_tokens() {
+ [
+ tt::TokenTree::Leaf(tt::Leaf::Ident(enable_ident)),
+ tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '=', .. })),
+ tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { kind: tt::LitKind::Str, symbol: features, .. })),
+ ] if enable_ident.sym == sym::enable => Some(features),
+ _ => None,
+ }
+ })
+ .flat_map(|features| features.as_str().split(',').map(Symbol::intern))
+ .collect();
+ Self { enabled }
+ }
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Unsafety {
+ Safe,
+ Unsafe,
+ /// A lint.
+ DeprecatedSafe2024,
+}
+
+pub fn is_fn_unsafe_to_call(
+ db: &dyn HirDatabase,
+ func: FunctionId,
+ caller_target_features: &TargetFeatures,
+ call_edition: Edition,
+) -> Unsafety {
let data = db.function_data(func);
if data.is_unsafe() {
- return true;
+ return Unsafety::Unsafe;
+ }
+
+ if data.has_target_feature() {
+ // RFC 2396 .
+ let callee_target_features = TargetFeatures::from_attrs(&db.attrs(func.into()));
+ if !caller_target_features.enabled.is_superset(&callee_target_features.enabled) {
+ return Unsafety::Unsafe;
+ }
+ }
+
+ if data.is_deprecated_safe_2024() {
+ if call_edition.at_least_2024() {
+ return Unsafety::Unsafe;
+ } else {
+ return Unsafety::DeprecatedSafe2024;
+ }
}
let loc = func.lookup(db.upcast());
@@ -279,14 +337,22 @@ pub fn is_fn_unsafe_to_call(db: &dyn HirDatabase, func: FunctionId) -> bool {
if is_intrinsic_block {
// legacy intrinsics
// extern "rust-intrinsic" intrinsics are unsafe unless they have the rustc_safe_intrinsic attribute
- !db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists()
+ if db.attrs(func.into()).by_key(&sym::rustc_safe_intrinsic).exists() {
+ Unsafety::Safe
+ } else {
+ Unsafety::Unsafe
+ }
} else {
// Function in an `extern` block are always unsafe to call, except when
// it is marked as `safe`.
- !data.is_safe()
+ if data.is_safe() {
+ Unsafety::Safe
+ } else {
+ Unsafety::Unsafe
+ }
}
}
- _ => false,
+ _ => Unsafety::Safe,
}
}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
index afd163fbd96c9..3a22158ce6f1d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/variance.rs
@@ -1028,6 +1028,7 @@ struct FixedPoint(&'static FixedPoint<(), T, U>, V);
}
GenericDefId::ImplId(_) => return None,
GenericDefId::ConstId(_) => return None,
+ GenericDefId::StaticId(_) => return None,
},
))
})
diff --git a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
index fc77d1889c88e..64e982c42d7f6 100644
--- a/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/diagnostics.rs
@@ -271,11 +271,17 @@ pub struct PrivateField {
pub field: Field,
}
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum UnsafeLint {
+ HardError,
+ UnsafeOpInUnsafeFn,
+ DeprecatedSafe2024,
+}
+
#[derive(Debug)]
pub struct MissingUnsafe {
pub node: InFile>>,
- /// If true, the diagnostics is an `unsafe_op_in_unsafe_fn` lint instead of a hard error.
- pub only_lint: bool,
+ pub lint: UnsafeLint,
pub reason: UnsafetyReason,
}
@@ -411,7 +417,7 @@ impl AnyDiagnostic {
pub(crate) fn body_validation_diagnostic(
db: &dyn HirDatabase,
diagnostic: BodyValidationDiagnostic,
- source_map: &hir_def::body::BodySourceMap,
+ source_map: &hir_def::expr_store::BodySourceMap,
) -> Option {
match diagnostic {
BodyValidationDiagnostic::RecordMissingFields { record, variant, missed_fields } => {
@@ -547,7 +553,7 @@ impl AnyDiagnostic {
def: DefWithBodyId,
d: &InferenceDiagnostic,
outer_types_source_map: &TypesSourceMap,
- source_map: &hir_def::body::BodySourceMap,
+ source_map: &hir_def::expr_store::BodySourceMap,
) -> Option {
let expr_syntax = |expr| {
source_map.expr_syntax(expr).inspect_err(|_| stdx::never!("synthetic syntax")).ok()
diff --git a/src/tools/rust-analyzer/crates/hir/src/display.rs b/src/tools/rust-analyzer/crates/hir/src/display.rs
index b29c91694d371..6f4168ab0867d 100644
--- a/src/tools/rust-analyzer/crates/hir/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/display.rs
@@ -80,7 +80,9 @@ impl HirDisplay for Function {
if data.is_async() {
f.write_str("async ")?;
}
- if self.is_unsafe_to_call(db) {
+ // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
+ // (they are conditionally unsafe to call). We probably should show something else.
+ if self.is_unsafe_to_call(db, None, f.edition()) {
f.write_str("unsafe ")?;
}
if let Some(abi) = &data.abi {
diff --git a/src/tools/rust-analyzer/crates/hir/src/from_id.rs b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
index 2ad39817b2fe2..537401afdc34a 100644
--- a/src/tools/rust-analyzer/crates/hir/src/from_id.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/from_id.rs
@@ -183,6 +183,7 @@ impl From for GenericDefId {
GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
GenericDef::Const(it) => GenericDefId::ConstId(it.id),
+ GenericDef::Static(it) => GenericDefId::StaticId(it.id),
}
}
}
@@ -197,6 +198,7 @@ impl From for GenericDef {
GenericDefId::TypeAliasId(it) => GenericDef::TypeAlias(it.into()),
GenericDefId::ImplId(it) => GenericDef::Impl(it.into()),
GenericDefId::ConstId(it) => GenericDef::Const(it.into()),
+ GenericDefId::StaticId(it) => GenericDef::Static(it.into()),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 0cbc75726bf39..56090bc6b6057 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -42,8 +42,8 @@ use arrayvec::ArrayVec;
use base_db::{CrateDisplayName, CrateId, CrateOrigin};
use either::Either;
use hir_def::{
- body::BodyDiagnostic,
data::{adt::VariantData, TraitFlags},
+ expr_store::ExpressionStoreDiagnostics,
generics::{LifetimeParamData, TypeOrConstParamData, TypeParamProvenance},
hir::{BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat},
item_tree::{AttrOwner, FieldParent, ItemTreeFieldId, ItemTreeNode},
@@ -1892,10 +1892,10 @@ impl DefWithBody {
for diag in source_map.diagnostics() {
acc.push(match diag {
- BodyDiagnostic::InactiveCode { node, cfg, opts } => {
+ ExpressionStoreDiagnostics::InactiveCode { node, cfg, opts } => {
InactiveCode { node: *node, cfg: cfg.clone(), opts: opts.clone() }.into()
}
- BodyDiagnostic::MacroError { node, err } => {
+ ExpressionStoreDiagnostics::MacroError { node, err } => {
let RenderedExpandError { message, error, kind } =
err.render_to_string(db.upcast());
@@ -1919,20 +1919,22 @@ impl DefWithBody {
}
.into()
}
- BodyDiagnostic::UnresolvedMacroCall { node, path } => UnresolvedMacroCall {
- macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
- precise_location: None,
- path: path.clone(),
- is_bang: true,
+ ExpressionStoreDiagnostics::UnresolvedMacroCall { node, path } => {
+ UnresolvedMacroCall {
+ macro_call: (*node).map(|ast_ptr| ast_ptr.into()),
+ precise_location: None,
+ path: path.clone(),
+ is_bang: true,
+ }
+ .into()
}
- .into(),
- BodyDiagnostic::AwaitOutsideOfAsync { node, location } => {
+ ExpressionStoreDiagnostics::AwaitOutsideOfAsync { node, location } => {
AwaitOutsideOfAsync { node: *node, location: location.clone() }.into()
}
- BodyDiagnostic::UnreachableLabel { node, name } => {
+ ExpressionStoreDiagnostics::UnreachableLabel { node, name } => {
UnreachableLabel { node: *node, name: name.clone() }.into()
}
- BodyDiagnostic::UndeclaredLabel { node, name } => {
+ ExpressionStoreDiagnostics::UndeclaredLabel { node, name } => {
UndeclaredLabel { node: *node, name: name.clone() }.into()
}
});
@@ -1976,16 +1978,40 @@ impl DefWithBody {
);
}
- let (unsafe_exprs, only_lint) = hir_ty::diagnostics::missing_unsafe(db, self.into());
- for (node, reason) in unsafe_exprs {
+ let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, self.into());
+ for (node, reason) in missing_unsafe.unsafe_exprs {
match source_map.expr_or_pat_syntax(node) {
- Ok(node) => acc.push(MissingUnsafe { node, only_lint, reason }.into()),
+ Ok(node) => acc.push(
+ MissingUnsafe {
+ node,
+ lint: if missing_unsafe.fn_is_unsafe {
+ UnsafeLint::UnsafeOpInUnsafeFn
+ } else {
+ UnsafeLint::HardError
+ },
+ reason,
+ }
+ .into(),
+ ),
Err(SyntheticSyntax) => {
// FIXME: Here and elsewhere in this file, the `expr` was
// desugared, report or assert that this doesn't happen.
}
}
}
+ for node in missing_unsafe.deprecated_safe_calls {
+ match source_map.expr_syntax(node) {
+ Ok(node) => acc.push(
+ MissingUnsafe {
+ node: node.map(|it| it.wrap_left()),
+ lint: UnsafeLint::DeprecatedSafe2024,
+ reason: UnsafetyReason::UnsafeFnCall,
+ }
+ .into(),
+ ),
+ Err(SyntheticSyntax) => never!("synthetic DeprecatedSafe2024"),
+ }
+ }
if let Ok(borrowck_results) = db.borrowck(self.into()) {
for borrowck_result in borrowck_results.iter() {
@@ -2361,8 +2387,19 @@ impl Function {
db.attrs(self.id.into()).is_unstable()
}
- pub fn is_unsafe_to_call(self, db: &dyn HirDatabase) -> bool {
- hir_ty::is_fn_unsafe_to_call(db, self.id)
+ pub fn is_unsafe_to_call(
+ self,
+ db: &dyn HirDatabase,
+ caller: Option,
+ call_edition: Edition,
+ ) -> bool {
+ let target_features = caller
+ .map(|caller| hir_ty::TargetFeatures::from_attrs(&db.attrs(caller.id.into())))
+ .unwrap_or_default();
+ matches!(
+ hir_ty::is_fn_unsafe_to_call(db, self.id, &target_features, call_edition),
+ hir_ty::Unsafety::Unsafe
+ )
}
/// Whether this function declaration has a definition.
@@ -3453,6 +3490,7 @@ pub enum GenericDef {
Impl(Impl),
// consts can have type parameters from their parents (i.e. associated consts of traits)
Const(Const),
+ Static(Static),
}
impl_from!(
Function,
@@ -3461,7 +3499,8 @@ impl_from!(
TraitAlias,
TypeAlias,
Impl,
- Const
+ Const,
+ Static
for GenericDef
);
@@ -3511,6 +3550,7 @@ impl GenericDef {
GenericDef::TypeAlias(it) => it.id.into(),
GenericDef::Impl(it) => it.id.into(),
GenericDef::Const(it) => it.id.into(),
+ GenericDef::Static(it) => it.id.into(),
}
}
@@ -3568,6 +3608,7 @@ impl GenericDef {
item_tree_source_maps.impl_(id.value).generics()
}
GenericDefId::ConstId(_) => return,
+ GenericDefId::StaticId(_) => return,
},
};
@@ -4624,17 +4665,6 @@ impl Type {
Type { env: TraitEnvironment::empty(krate), ty }
}
- pub fn reference(inner: &Type, m: Mutability) -> Type {
- inner.derived(
- TyKind::Ref(
- if m.is_mut() { hir_ty::Mutability::Mut } else { hir_ty::Mutability::Not },
- hir_ty::error_lifetime(),
- inner.ty.clone(),
- )
- .intern(Interner),
- )
- }
-
fn new(db: &dyn HirDatabase, lexical_env: impl HasResolver, ty: Ty) -> Type {
let resolver = lexical_env.resolver(db.upcast());
let environment = resolver
@@ -4866,6 +4896,17 @@ impl Type {
self.normalize_trait_assoc_type(db, &[], iterator_item.into())
}
+ pub fn impls_iterator(self, db: &dyn HirDatabase) -> bool {
+ let Some(iterator_trait) =
+ db.lang_item(self.env.krate, LangItem::Iterator).and_then(|it| it.as_trait())
+ else {
+ return false;
+ };
+ let canonical_ty =
+ Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
+ method_resolution::implements_trait_unique(&canonical_ty, db, &self.env, iterator_trait)
+ }
+
/// Resolves the projection `::IntoIter` and returns the resulting type
pub fn into_iterator_iter(self, db: &dyn HirDatabase) -> Option {
let trait_ = db.lang_item(self.env.krate, LangItem::IntoIterIntoIter).and_then(|it| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index 09470bed9cfb4..882a27182f015 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -2040,6 +2040,13 @@ impl SemanticsScope<'_> {
Crate { id: self.resolver.krate() }
}
+ pub fn containing_function(&self) -> Option {
+ self.resolver.body_owner().and_then(|owner| match owner {
+ DefWithBodyId::FunctionId(id) => Some(id.into()),
+ _ => None,
+ })
+ }
+
pub(crate) fn resolver(&self) -> &Resolver {
&self.resolver
}
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index b699ccde4128e..23e7518883b56 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -14,7 +14,7 @@ use crate::{
};
use either::Either;
use hir_def::{
- body::{
+ expr_store::{
scope::{ExprScopes, ScopeId},
Body, BodySourceMap, HygieneId,
},
@@ -1105,16 +1105,9 @@ impl SourceAnalyzer {
if let Some(expanded_expr) = sm.macro_expansion_expr(macro_expr) {
let mut is_unsafe = false;
let mut walk_expr = |expr_id| {
- unsafe_expressions(
- db,
- infer,
- *def,
- body,
- expr_id,
- &mut |_, inside_unsafe_block, _| {
- is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
- },
- )
+ unsafe_expressions(db, infer, *def, body, expr_id, &mut |inside_unsafe_block| {
+ is_unsafe |= inside_unsafe_block == InsideUnsafeBlock::No
+ })
};
match expanded_expr {
ExprOrPatId::ExprId(expanded_expr) => walk_expr(expanded_expr),
@@ -1259,7 +1252,11 @@ fn scope_for(
node: InFile<&SyntaxNode>,
) -> Option {
node.ancestors_with_macros(db.upcast())
- .take_while(|it| !ast::Item::can_cast(it.kind()) || ast::MacroCall::can_cast(it.kind()))
+ .take_while(|it| {
+ !ast::Item::can_cast(it.kind())
+ || ast::MacroCall::can_cast(it.kind())
+ || ast::Use::can_cast(it.kind())
+ })
.filter_map(|it| it.map(ast::Expr::cast).transpose())
.filter_map(|it| source_map.node_expr(it.as_ref())?.as_expr())
.find_map(|it| scopes.scope_for(it))
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search.rs b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
index 6f8451370848e..af72179305c8f 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search.rs
@@ -145,7 +145,7 @@ impl LookupTable {
self.data
.iter()
.find(|(t, _)| {
- Type::reference(t, Mutability::Shared).could_unify_with_deeply(db, ty)
+ t.add_reference(Mutability::Shared).could_unify_with_deeply(db, ty)
})
.map(|(t, it)| {
it.exprs(t)
diff --git a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
index 1b0e6f8bd5b0a..847304d503a84 100644
--- a/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/term_search/tactics.rs
@@ -15,6 +15,7 @@ use hir_ty::mir::BorrowKind;
use hir_ty::TyBuilder;
use itertools::Itertools;
use rustc_hash::FxHashSet;
+use span::Edition;
use crate::{
Adt, AssocItem, GenericDef, GenericParam, HasAttrs, HasVisibility, Impl, ModuleDef, ScopeDef,
@@ -365,7 +366,7 @@ pub(super) fn free_function<'a, DB: HirDatabase>(
let ret_ty = it.ret_type_with_args(db, generics.iter().cloned());
// Filter out private and unsafe functions
if !it.is_visible_from(db, module)
- || it.is_unsafe_to_call(db)
+ || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME)
|| it.is_unstable(db)
|| ctx.config.enable_borrowcheck && ret_ty.contains_reference(db)
|| ret_ty.is_raw_ptr()
@@ -470,7 +471,10 @@ pub(super) fn impl_method<'a, DB: HirDatabase>(
}
// Filter out private and unsafe functions
- if !it.is_visible_from(db, module) || it.is_unsafe_to_call(db) || it.is_unstable(db) {
+ if !it.is_visible_from(db, module)
+ || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME)
+ || it.is_unstable(db)
+ {
return None;
}
@@ -658,7 +662,10 @@ pub(super) fn impl_static_method<'a, DB: HirDatabase>(
}
// Filter out private and unsafe functions
- if !it.is_visible_from(db, module) || it.is_unsafe_to_call(db) || it.is_unstable(db) {
+ if !it.is_visible_from(db, module)
+ || it.is_unsafe_to_call(db, None, Edition::CURRENT_FIXME)
+ || it.is_unstable(db)
+ {
return None;
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
index 70fb5680052b0..491727a30a88b 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/apply_demorgan.rs
@@ -15,7 +15,7 @@ use crate::{utils::invert_boolean_expression, AssistContext, AssistId, AssistKin
// Assist: apply_demorgan
//
-// Apply https://en.wikipedia.org/wiki/De_Morgan%27s_laws[De Morgan's law].
+// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws).
// This transforms expressions of the form `!l || !r` into `!(l && r)`.
// This also works with `&&`. This assist can only be applied with the cursor
// on either `||` or `&&`.
@@ -131,7 +131,7 @@ pub(crate) fn apply_demorgan(acc: &mut Assists, ctx: &AssistContext<'_>) -> Opti
// Assist: apply_demorgan_iterator
//
-// Apply https://en.wikipedia.org/wiki/De_Morgan%27s_laws[De Morgan's law] to
+// Apply [De Morgan's law](https://en.wikipedia.org/wiki/De_Morgan%27s_laws) to
// `Iterator::all` and `Iterator::any`.
//
// This transforms expressions of the form `!iter.any(|x| predicate(x))` into
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
index d86948818b163..a92a000c3fbd3 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/auto_import.rs
@@ -38,7 +38,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
// use super::AssistContext;
// ```
//
-// .Import Granularity
+// #### Import Granularity
//
// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
// It has the following configurations:
@@ -54,7 +54,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
//
// In `VS Code` the configuration for this is `rust-analyzer.imports.granularity.group`.
//
-// .Import Prefix
+// #### Import Prefix
//
// The style of imports in the same crate is configurable through the `imports.prefix` setting.
// It has the following configurations:
@@ -68,7 +68,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
//
// In `VS Code` the configuration for this is `rust-analyzer.imports.prefix`.
//
-// image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
+// 
// Assist: auto_import
//
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index 3c84f83906a9b..f6e516db88835 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -140,8 +140,10 @@ fn edit_struct_references(
match_ast! {
match node {
ast::TupleStructPat(tuple_struct_pat) => {
+ let file_range = ctx.sema.original_range_opt(&node)?;
+ edit.edit_file(file_range.file_id);
edit.replace(
- tuple_struct_pat.syntax().text_range(),
+ file_range.range,
ast::make::record_pat_with_fields(
tuple_struct_pat.path()?,
ast::make::record_pat_field_list(tuple_struct_pat.fields().zip(names).map(
@@ -921,6 +923,104 @@ pub struct $0Foo(#[my_custom_attr] u32);
"#,
r#"
pub struct Foo { #[my_custom_attr] field1: u32 }
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_in_macro_pattern_args() {
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+macro_rules! foo {
+ ($expression:expr, $pattern:pat) => {
+ match $expression {
+ $pattern => true,
+ _ => false
+ }
+ };
+}
+enum Expr {
+ A$0(usize),
+}
+fn main() {
+ let e = Expr::A(0);
+ foo!(e, Expr::A(0));
+}
+"#,
+ r#"
+macro_rules! foo {
+ ($expression:expr, $pattern:pat) => {
+ match $expression {
+ $pattern => true,
+ _ => false
+ }
+ };
+}
+enum Expr {
+ A { field1: usize },
+}
+fn main() {
+ let e = Expr::A { field1: 0 };
+ foo!(e, Expr::A { field1: 0 });
+}
+"#,
+ );
+ }
+
+ #[test]
+ fn convert_in_multi_file_macro_pattern_args() {
+ check_assist(
+ convert_tuple_struct_to_named_struct,
+ r#"
+//- /main.rs
+mod foo;
+
+enum Test {
+ A$0(i32)
+}
+
+//- /foo.rs
+use crate::Test;
+
+macro_rules! foo {
+ ($expression:expr, $pattern:pat) => {
+ match $expression {
+ $pattern => true,
+ _ => false
+ }
+ };
+}
+
+fn foo() {
+ let a = Test::A(0);
+ foo!(a, Test::A(0));
+}
+"#,
+ r#"
+//- /main.rs
+mod foo;
+
+enum Test {
+ A { field1: i32 }
+}
+
+//- /foo.rs
+use crate::Test;
+
+macro_rules! foo {
+ ($expression:expr, $pattern:pat) => {
+ match $expression {
+ $pattern => true,
+ _ => false
+ }
+ };
+}
+
+fn foo() {
+ let a = Test::A { field1: 0 };
+ foo!(a, Test::A { field1: 0 });
+}
"#,
);
}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 54e42f126bc53..4b0fa704a22ba 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -1,4 +1,4 @@
-//! Generated by `cargo codegen assists-doc-tests`, do not edit by hand.
+//! Generated by `cargo xtask codegen assists-doc-tests`, do not edit by hand.
use super::check_doc_test;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
index 78ff441791343..c1332d99bff9a 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/utils.rs
@@ -793,8 +793,8 @@ pub(crate) fn convert_reference_type(
}
fn could_deref_to_target(ty: &hir::Type, target: &hir::Type, db: &dyn HirDatabase) -> bool {
- let ty_ref = hir::Type::reference(ty, hir::Mutability::Shared);
- let target_ref = hir::Type::reference(target, hir::Mutability::Shared);
+ let ty_ref = ty.add_reference(hir::Mutability::Shared);
+ let target_ref = target.add_reference(hir::Mutability::Shared);
ty_ref.could_coerce_to(db, &target_ref)
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
index d12654665ce95..b38b9ac1f5391 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs
@@ -89,7 +89,7 @@ pub(crate) fn complete_dot(
acc.add_method(ctx, dot_access, func, None, None)
});
- if ctx.config.enable_auto_iter {
+ if ctx.config.enable_auto_iter && !receiver_ty.strip_references().impls_iterator(ctx.db) {
// FIXME:
// Checking for the existence of `iter()` is complicated in our setup, because we need to substitute
// its return type, so we instead check for `<&Self as IntoIterator>::IntoIter`.
@@ -1499,10 +1499,32 @@ fn main() {
let bar = Bar;
bar.$0
}
+"#,
+ expect![[r#""#]],
+ );
+ }
+
+ #[test]
+ fn no_iter_suggestion_on_iterator() {
+ check_no_kw(
+ r#"
+//- minicore: iterator
+struct MyIter;
+impl Iterator for MyIter {
+ type Item = ();
+ fn next(&mut self) -> Option { None }
+}
+
+fn main() {
+ MyIter.$0
+}
"#,
expect![[r#"
- me foo() fn(self: Bar)
-"#]],
+ me by_ref() (as Iterator) fn(&mut self) -> &mut Self
+ me into_iter() (as IntoIterator) fn(self) -> ::IntoIter
+ me next() (as Iterator) fn(&mut self) -> Option<::Item>
+ me nth(…) (as Iterator) fn(&mut self, usize) -> Option<::Item>
+ "#]],
);
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
index 24243f57b46a0..b5555e6610240 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/flyimport.rs
@@ -83,19 +83,19 @@ use crate::{
// NOTE: currently, if an assoc item comes from a trait that's not currently imported, and it also has an unresolved and/or partially-qualified path,
// no imports will be proposed.
//
-// .Fuzzy search details
+// #### Fuzzy search details
//
// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
// (i.e. in `HashMap` in the `std::collections::HashMap` path).
// For the same reasons, avoids searching for any path imports for inputs with their length less than 2 symbols
// (but shows all associated items for any input length).
//
-// .Import configuration
+// #### Import configuration
//
// It is possible to configure how use-trees are merged with the `imports.granularity.group` setting.
// Mimics the corresponding behavior of the `Auto Import` feature.
//
-// .LSP and performance implications
+// #### LSP and performance implications
//
// The feature is enabled only if the LSP client supports LSP protocol version 3.16+ and reports the `additionalTextEdits`
// (case-sensitive) resolve client capability in its client capabilities.
@@ -103,7 +103,7 @@ use crate::{
// For clients with no such support, all edits have to be calculated on the completion request, including the fuzzy search completion ones,
// which might be slow ergo the feature is automatically disabled.
//
-// .Feature toggle
+// #### Feature toggle
//
// The feature can be forcefully turned off in the settings with the `rust-analyzer.completion.autoimport.enable` flag.
// Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corresponding
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
index 2755329bb31a5..c612170eb54bc 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -14,7 +14,7 @@
// ** `logw` -> `log::warn!(...)`
// ** `loge` -> `log::error!(...)`
//
-// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
+// 
use ide_db::{
syntax_helpers::format_string_exprs::{parse_format_exprs, with_placeholders, Arg},
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 2f1860cbb59af..7862b258789c4 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -442,6 +442,8 @@ pub(crate) struct CompletionContext<'a> {
pub(crate) krate: hir::Crate,
/// The module of the `scope`.
pub(crate) module: hir::Module,
+ /// The function where we're completing, if inside a function.
+ pub(crate) containing_function: Option,
/// Whether nightly toolchain is used. Cached since this is looked up a lot.
pub(crate) is_nightly: bool,
/// The edition of the current crate
@@ -760,6 +762,7 @@ impl<'a> CompletionContext<'a> {
let krate = scope.krate();
let module = scope.module();
+ let containing_function = scope.containing_function();
let edition = krate.edition(db);
let toolchain = db.toolchain_channel(krate.into());
@@ -874,6 +877,7 @@ impl<'a> CompletionContext<'a> {
token,
krate,
module,
+ containing_function,
is_nightly,
edition,
expected_name,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index f5a50ae81907f..eecd412bc43e3 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -59,7 +59,7 @@ pub(super) fn expand_and_analyze(
// make the offset point to the start of the original token, as that is what the
// intermediate offsets calculated in expansion always points to
let offset = offset - relative_offset;
- let expansion = expand(
+ let expansion = expand_maybe_stop(
sema,
original_file.clone(),
speculative_file.clone(),
@@ -118,7 +118,7 @@ fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Opt
/// that we check, we subtract `COMPLETION_MARKER.len()`. This may not be accurate because proc macros
/// can insert the text of the completion marker in other places while removing the span, but this is
/// the best we can do.
-fn expand(
+fn expand_maybe_stop(
sema: &Semantics<'_, RootDatabase>,
original_file: SyntaxNode,
speculative_file: SyntaxNode,
@@ -126,23 +126,48 @@ fn expand(
fake_ident_token: SyntaxToken,
relative_offset: TextSize,
) -> Option {
- let _p = tracing::info_span!("CompletionContext::expand").entered();
+ if let result @ Some(_) = expand(
+ sema,
+ original_file.clone(),
+ speculative_file.clone(),
+ original_offset,
+ fake_ident_token.clone(),
+ relative_offset,
+ ) {
+ return result;
+ }
+ // This needs to come after the recursive call, because our "inside macro" detection is subtly wrong
+ // with regard to attribute macros named `test` that are not std's test. So hopefully we will expand
+ // them successfully above and be able to analyze.
// Left biased since there may already be an identifier token there, and we appended to it.
if !sema.might_be_inside_macro_call(&fake_ident_token)
&& token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
.is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
{
// Recursion base case.
- return Some(ExpansionResult {
+ Some(ExpansionResult {
original_file,
speculative_file,
original_offset,
speculative_offset: fake_ident_token.text_range().start(),
fake_ident_token,
derive_ctx: None,
- });
+ })
+ } else {
+ None
}
+}
+
+fn expand(
+ sema: &Semantics<'_, RootDatabase>,
+ original_file: SyntaxNode,
+ speculative_file: SyntaxNode,
+ original_offset: TextSize,
+ fake_ident_token: SyntaxToken,
+ relative_offset: TextSize,
+) -> Option {
+ let _p = tracing::info_span!("CompletionContext::expand").entered();
let parent_item =
|item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
@@ -197,7 +222,7 @@ fn expand(
// stop here to prevent problems from happening
return None;
}
- let result = expand(
+ let result = expand_maybe_stop(
sema,
actual_expansion.clone(),
fake_expansion.clone(),
@@ -317,7 +342,7 @@ fn expand(
// stop here to prevent problems from happening
return None;
}
- let result = expand(
+ let result = expand_maybe_stop(
sema,
actual_expansion.clone(),
fake_expansion.clone(),
@@ -386,7 +411,7 @@ fn expand(
// stop here to prevent problems from happening
return None;
}
- let result = expand(
+ let result = expand_maybe_stop(
sema,
actual_expansion.clone(),
fake_expansion.clone(),
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
index 8051d48ca5fe0..a1f2eaeb1b6d6 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/lib.rs
@@ -106,11 +106,13 @@ impl CompletionFieldsToResolve {
//
// There also snippet completions:
//
-// .Expressions
+// #### Expressions
+//
// - `pd` -> `eprintln!(" = {:?}", );`
// - `ppd` -> `eprintln!(" = {:#?}", );`
//
-// .Items
+// #### Items
+//
// - `tfn` -> `#[test] fn feature(){}`
// - `tmod` ->
// ```rust
@@ -127,7 +129,7 @@ impl CompletionFieldsToResolve {
// Those are the additional completion options with automatic `use` import and options from all project importable items,
// fuzzy matched against the completion input.
//
-// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]
+// 
/// Main entry point for completion. We run completion as a two-phase process.
///
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
index c3354902c3b78..fd90613964af0 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/render/function.rs
@@ -144,7 +144,7 @@ fn render(
let detail = if ctx.completion.config.full_function_signatures {
detail_full(db, func, ctx.completion.edition)
} else {
- detail(db, func, ctx.completion.edition)
+ detail(ctx.completion, func, ctx.completion.edition)
};
item.set_documentation(ctx.docs(func))
.set_deprecated(ctx.is_deprecated(func) || ctx.is_deprecated_assoc_item(func))
@@ -307,26 +307,26 @@ fn ref_of_param(ctx: &CompletionContext<'_>, arg: &str, ty: &hir::Type) -> &'sta
""
}
-fn detail(db: &dyn HirDatabase, func: hir::Function, edition: Edition) -> String {
- let mut ret_ty = func.ret_type(db);
+fn detail(ctx: &CompletionContext<'_>, func: hir::Function, edition: Edition) -> String {
+ let mut ret_ty = func.ret_type(ctx.db);
let mut detail = String::new();
- if func.is_const(db) {
+ if func.is_const(ctx.db) {
format_to!(detail, "const ");
}
- if func.is_async(db) {
+ if func.is_async(ctx.db) {
format_to!(detail, "async ");
- if let Some(async_ret) = func.async_ret_type(db) {
+ if let Some(async_ret) = func.async_ret_type(ctx.db) {
ret_ty = async_ret;
}
}
- if func.is_unsafe_to_call(db) {
+ if func.is_unsafe_to_call(ctx.db, ctx.containing_function, ctx.edition) {
format_to!(detail, "unsafe ");
}
- format_to!(detail, "fn({})", params_display(db, func, edition));
+ format_to!(detail, "fn({})", params_display(ctx.db, func, edition));
if !ret_ty.is_unit() {
- format_to!(detail, " -> {}", ret_ty.display(db, edition));
+ format_to!(detail, " -> {}", ret_ty.display(ctx.db, edition));
}
detail
}
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
index 866b83a614603..07f33a826e4c7 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/snippet.rs
@@ -8,8 +8,7 @@
//
// A custom snippet can be defined by adding it to the `rust-analyzer.completion.snippets.custom` object respectively.
//
-// [source,json]
-// ----
+// ```json
// {
// "rust-analyzer.completion.snippets.custom": {
// "thread spawn": {
@@ -25,7 +24,7 @@
// }
// }
// }
-// ----
+// ```
//
// In the example above:
//
@@ -39,6 +38,7 @@
// * `description` is an optional description of the snippet, if unset the snippet name will be used.
//
// * `requires` is an optional list of item paths that have to be resolvable in the current crate where the completion is rendered.
+
// On failure of resolution the snippet won't be applicable, otherwise the snippet will insert an import for the items on insertion if
// the items aren't yet in scope.
//
@@ -55,8 +55,8 @@
//
// For the VSCode editor, rust-analyzer also ships with a small set of defaults which can be removed
// by overwriting the settings object mentioned above, the defaults are:
-// [source,json]
-// ----
+//
+// ```json
// {
// "Arc::new": {
// "postfix": "arc",
@@ -98,7 +98,7 @@
// "scope": "expr"
// }
// }
-// ----
+// ````
use hir::{ModPath, Name, Symbol};
use ide_db::imports::import_assets::LocatedImport;
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index 663a038580d55..375575128377d 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -1986,3 +1986,53 @@ fn foo() {
"#]],
);
}
+
+#[test]
+fn non_std_test_attr_macro() {
+ check(
+ r#"
+//- proc_macros: identity
+use proc_macros::identity as test;
+
+#[test]
+fn foo() {
+ $0
+}
+ "#,
+ expect![[r#"
+ fn foo() fn()
+ md proc_macros
+ bt u32 u32
+ kw async
+ kw const
+ kw crate::
+ kw enum
+ kw extern
+ kw false
+ kw fn
+ kw for
+ kw if
+ kw if let
+ kw impl
+ kw let
+ kw loop
+ kw match
+ kw mod
+ kw return
+ kw self::
+ kw static
+ kw struct
+ kw trait
+ kw true
+ kw type
+ kw union
+ kw unsafe
+ kw use
+ kw while
+ kw while let
+ sn macro_rules
+ sn pd
+ sn ppd
+ "#]],
+ );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
index 35e3a8d9bf7f5..46ff4fbf9e904 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs
@@ -44,12 +44,11 @@ impl RootDatabase {
//
// Clears rust-analyzer's internal database and prints memory usage statistics.
//
- // |===
- // | Editor | Action Name
- //
+ // | Editor | Action Name |
+ // |---------|-------------|
// | VS Code | **rust-analyzer: Memory Usage (Clears Database)**
- // |===
- // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
+
+ // 
pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes, usize)> {
let mut acc: Vec<(String, Bytes, usize)> = vec![];
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
index d12bda0816fd3..bad536080567f 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/defs.rs
@@ -986,6 +986,7 @@ impl From for Definition {
GenericDef::TypeAlias(it) => it.into(),
GenericDef::Impl(it) => it.into(),
GenericDef::Const(it) => it.into(),
+ GenericDef::Static(it) => it.into(),
}
}
}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
index 0002fda0ba732..22dc3d9e29d65 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs
@@ -6,12 +6,13 @@ mod topologic_sort;
use std::time::Duration;
-use hir::db::DefDatabase;
+use hir::{db::DefDatabase, Symbol};
+use itertools::Itertools;
use crate::{
base_db::{
ra_salsa::{Database, ParallelDatabase, Snapshot},
- Cancelled, CrateId, SourceDatabase, SourceRootDatabase,
+ Cancelled, CrateId, SourceDatabase,
},
symbol_index::SymbolsDatabase,
FxIndexMap, RootDatabase,
@@ -21,11 +22,12 @@ use crate::{
#[derive(Debug)]
pub struct ParallelPrimeCachesProgress {
/// the crates that we are currently priming.
- pub crates_currently_indexing: Vec,
+ pub crates_currently_indexing: Vec,
/// the total number of crates we want to prime.
pub crates_total: usize,
/// the total number of crates that have finished priming
pub crates_done: usize,
+ pub work_type: &'static str,
}
pub fn parallel_prime_caches(
@@ -47,41 +49,32 @@ pub fn parallel_prime_caches(
};
enum ParallelPrimeCacheWorkerProgress {
- BeginCrate { crate_id: CrateId, crate_name: String },
+ BeginCrate { crate_id: CrateId, crate_name: Symbol },
EndCrate { crate_id: CrateId },
}
+ // We split off def map computation from other work,
+ // as the def map is the relevant one. Once the defmaps are computed
+ // the project is ready to go, the other indices are just nice to have for some IDE features.
+ #[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone)]
+ enum PrimingPhase {
+ DefMap,
+ ImportMap,
+ CrateSymbols,
+ }
+
let (work_sender, progress_receiver) = {
let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
let (work_sender, work_receiver) = crossbeam_channel::unbounded();
- let graph = graph.clone();
- let local_roots = db.local_roots();
let prime_caches_worker = move |db: Snapshot| {
- while let Ok((crate_id, crate_name)) = work_receiver.recv() {
+ while let Ok((crate_id, crate_name, kind)) = work_receiver.recv() {
progress_sender
.send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
- // Compute the DefMap and possibly ImportMap
- let file_id = graph[crate_id].root_file_id;
- let root_id = db.file_source_root(file_id);
- if db.source_root(root_id).is_library {
- db.crate_def_map(crate_id);
- } else {
- // This also computes the DefMap
- db.import_map(crate_id);
- }
-
- // Compute the symbol search index.
- // This primes the cache for `ide_db::symbol_index::world_symbols()`.
- //
- // We do this for workspace crates only (members of local_roots), because doing it
- // for all dependencies could be *very* unnecessarily slow in a large project.
- //
- // FIXME: We should do it unconditionally if the configuration is set to default to
- // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
- // would need to pipe that configuration information down here.
- if local_roots.contains(&root_id) {
- db.crate_symbols(crate_id.into());
+ match kind {
+ PrimingPhase::DefMap => _ = db.crate_def_map(crate_id),
+ PrimingPhase::ImportMap => _ = db.import_map(crate_id),
+ PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()),
}
progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?;
@@ -112,16 +105,34 @@ pub fn parallel_prime_caches(
let mut crates_currently_indexing =
FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
+ let mut additional_phases = vec![];
+
while crates_done < crates_total {
db.unwind_if_cancelled();
for crate_id in &mut crates_to_prime {
- work_sender
- .send((
- crate_id,
- graph[crate_id].display_name.as_deref().unwrap_or_default().to_owned(),
- ))
- .ok();
+ let krate = &graph[crate_id];
+ let name = krate
+ .display_name
+ .as_deref()
+ .cloned()
+ .unwrap_or_else(|| Symbol::integer(crate_id.into_raw().into_u32() as usize));
+ if krate.origin.is_lang() {
+ additional_phases.push((crate_id, name.clone(), PrimingPhase::ImportMap));
+ } else if krate.origin.is_local() {
+ // Compute the symbol search index.
+ // This primes the cache for `ide_db::symbol_index::world_symbols()`.
+ //
+ // We do this for workspace crates only (members of local_roots), because doing it
+ // for all dependencies could be *very* unnecessarily slow in a large project.
+ //
+ // FIXME: We should do it unconditionally if the configuration is set to default to
+ // searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
+ // would need to pipe that configuration information down here.
+ additional_phases.push((crate_id, name.clone(), PrimingPhase::CrateSymbols));
+ }
+
+ work_sender.send((crate_id, name, PrimingPhase::DefMap)).ok();
}
// recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
@@ -153,6 +164,50 @@ pub fn parallel_prime_caches(
crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
crates_done,
crates_total,
+ work_type: "Indexing",
+ };
+
+ cb(progress);
+ }
+
+ let mut crates_done = 0;
+ let crates_total = additional_phases.len();
+ for w in additional_phases.into_iter().sorted_by_key(|&(_, _, phase)| phase) {
+ work_sender.send(w).ok();
+ }
+
+ while crates_done < crates_total {
+ db.unwind_if_cancelled();
+
+ // recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
+ // is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
+ // if this thread exits, and closes the work channel.
+ let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
+ Ok(p) => p,
+ Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
+ continue;
+ }
+ Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
+ // our workers may have died from a cancelled task, so we'll check and re-raise here.
+ db.unwind_if_cancelled();
+ break;
+ }
+ };
+ match worker_progress {
+ ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
+ crates_currently_indexing.insert(crate_id, crate_name);
+ }
+ ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
+ crates_currently_indexing.swap_remove(&crate_id);
+ crates_done += 1;
+ }
+ };
+
+ let progress = ParallelPrimeCachesProgress {
+ crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
+ crates_done,
+ crates_total,
+ work_type: "Populating symbols",
};
cb(progress);
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 7fc563a424104..7963e8ae4f78c 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -354,6 +354,7 @@ impl Definition {
hir::GenericDef::TypeAlias(it) => it.source(db).map(|src| src.syntax().cloned()),
hir::GenericDef::Impl(it) => it.source(db).map(|src| src.syntax().cloned()),
hir::GenericDef::Const(it) => it.source(db).map(|src| src.syntax().cloned()),
+ hir::GenericDef::Static(it) => it.source(db).map(|src| src.syntax().cloned()),
};
return match def {
Some(def) => SearchScope::file_range(
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
index e5ce10a771ef9..bb4c289c9084e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs
@@ -193,11 +193,9 @@ impl std::ops::Deref for Snap {
// `rust-analyzer.workspace.symbol.search.kind` settings. Symbols prefixed
// with `__` are hidden from the search results unless configured otherwise.
//
-// |===
-// | Editor | Shortcut
-//
-// | VS Code | kbd:[Ctrl+T]
-// |===
+// | Editor | Shortcut |
+// |---------|-----------|
+// | VS Code | Ctrl+T
pub fn world_symbols(db: &RootDatabase, query: Query) -> Vec {
let _p = tracing::info_span!("world_symbols", query = ?query.query).entered();
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
index bbdeb7cf08507..246330e6efaac 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs
@@ -12,7 +12,7 @@ use crate::{
// Diagnostic: incorrect-ident-case
//
-// This diagnostic is triggered if an item name doesn't follow https://doc.rust-lang.org/1.0.0/style/style/naming/README.html[Rust naming convention].
+// This diagnostic is triggered if an item name doesn't follow [Rust naming convention](https://doc.rust-lang.org/1.0.0/style/style/naming/README.html).
pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Diagnostic {
let code = match d.expected_case {
CaseType::LowerSnakeCase => DiagnosticCode::RustcLint("non_snake_case"),
@@ -936,6 +936,7 @@ fn func() {
fn override_lint_level() {
check_diagnostics(
r#"
+#![allow(unused_variables)]
#[warn(nonstandard_style)]
fn foo() {
let BAR;
@@ -992,6 +993,7 @@ struct QUX;
const foo: i32 = 0;
fn BAR() {
let BAZ;
+ _ = BAZ;
}
"#,
);
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index c7cdcf4982027..5730508436d2c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -1129,4 +1129,39 @@ fn main() {
"#,
);
}
+
+ #[test]
+ fn regression_18682() {
+ check_diagnostics(
+ r#"
+//- minicore: coerce_unsized
+struct Flexible {
+ body: [u8],
+}
+
+trait Field {
+ type Type: ?Sized;
+}
+
+impl Field for Flexible {
+ type Type = [u8];
+}
+
+trait KnownLayout {
+ type MaybeUninit: ?Sized;
+}
+
+
+impl KnownLayout for [T] {
+ type MaybeUninit = [T];
+}
+
+struct ZerocopyKnownLayoutMaybeUninit(<::Type as KnownLayout>::MaybeUninit);
+
+fn test(ptr: *mut [u8]) -> *mut ZerocopyKnownLayoutMaybeUninit {
+ ptr as *mut _
+}
+"#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 8117401a5342a..323a5723d4a3e 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -1,5 +1,5 @@
use hir::db::ExpandDatabase;
-use hir::{HirFileIdExt, UnsafetyReason};
+use hir::{HirFileIdExt, UnsafeLint, UnsafetyReason};
use ide_db::text_edit::TextEdit;
use ide_db::{assists::Assist, source_change::SourceChange};
use syntax::{ast, SyntaxNode};
@@ -11,10 +11,10 @@ use crate::{fix, Diagnostic, DiagnosticCode, DiagnosticsContext};
//
// This diagnostic is triggered if an operation marked as `unsafe` is used outside of an `unsafe` function or block.
pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsafe) -> Diagnostic {
- let code = if d.only_lint {
- DiagnosticCode::RustcLint("unsafe_op_in_unsafe_fn")
- } else {
- DiagnosticCode::RustcHardError("E0133")
+ let code = match d.lint {
+ UnsafeLint::HardError => DiagnosticCode::RustcHardError("E0133"),
+ UnsafeLint::UnsafeOpInUnsafeFn => DiagnosticCode::RustcLint("unsafe_op_in_unsafe_fn"),
+ UnsafeLint::DeprecatedSafe2024 => DiagnosticCode::RustcLint("deprecated_safe_2024"),
};
let operation = display_unsafety_reason(d.reason);
Diagnostic::new_with_syntax_node_ptr(
@@ -585,24 +585,58 @@ fn main() {
r#"
//- /ed2021.rs crate:ed2021 edition:2021
#[rustc_deprecated_safe_2024]
-unsafe fn safe() -> u8 {
+unsafe fn deprecated_safe() -> u8 {
0
}
+
//- /ed2024.rs crate:ed2024 edition:2024
#[rustc_deprecated_safe_2024]
-unsafe fn not_safe() -> u8 {
+unsafe fn deprecated_safe() -> u8 {
0
}
-//- /main.rs crate:main deps:ed2021,ed2024
+
+//- /dep1.rs crate:dep1 deps:ed2021,ed2024 edition:2021
+fn main() {
+ ed2021::deprecated_safe();
+ ed2024::deprecated_safe();
+}
+
+//- /dep2.rs crate:dep2 deps:ed2021,ed2024 edition:2024
+fn main() {
+ ed2021::deprecated_safe();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
+ ed2024::deprecated_safe();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
+}
+
+//- /dep3.rs crate:dep3 deps:ed2021,ed2024 edition:2021
+#![warn(deprecated_safe)]
+
fn main() {
- ed2021::safe();
- ed2024::not_safe();
- //^^^^^^^^^^^^^^^^^^💡 error: call to unsafe function is unsafe and requires an unsafe function or block
+ ed2021::deprecated_safe();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 warn: call to unsafe function is unsafe and requires an unsafe function or block
+ ed2024::deprecated_safe();
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^💡 warn: call to unsafe function is unsafe and requires an unsafe function or block
}
"#,
)
}
+ #[test]
+ fn orphan_unsafe_format_args() {
+ // Checks that we don't place orphan arguments for formatting under an unsafe block.
+ check_diagnostics(
+ r#"
+//- minicore: fmt
+fn foo() {
+ let p = 0xDEADBEEF as *const i32;
+ format_args!("", *p);
+ // ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
+}
+ "#,
+ );
+ }
+
#[test]
fn unsafe_op_in_unsafe_fn_allowed_by_default_in_edition_2021() {
check_diagnostics(
@@ -812,4 +846,36 @@ fn main() {
"#,
)
}
+
+ #[test]
+ fn target_feature() {
+ check_diagnostics(
+ r#"
+#[target_feature(enable = "avx")]
+fn foo() {}
+
+#[target_feature(enable = "avx,avx2")]
+fn bar() {
+ foo();
+}
+
+fn baz() {
+ foo();
+ // ^^^^^ 💡 error: call to unsafe function is unsafe and requires an unsafe function or block
+}
+ "#,
+ );
+ }
+
+ #[test]
+ fn unsafe_fn_ptr_call() {
+ check_diagnostics(
+ r#"
+fn f(it: unsafe fn()){
+ it();
+ // ^^^^ 💡 error: call to unsafe function is unsafe and requires an unsafe function or block
+}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
index 139797914440c..0e3c4c7aa3642 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/mutability_errors.rs
@@ -831,13 +831,14 @@ fn f() {
#[test]
fn or_pattern() {
- // FIXME: `None` is inferred as unknown here for some reason
check_diagnostics(
r#"
//- minicore: option
fn f(_: i32) {}
fn main() {
let ((Some(mut x), None) | (_, Some(mut x))) = (None, Some(7)) else { return };
+ //^^^^^ 💡 warn: variable does not need to be mutable
+
f(x);
}
"#,
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 56afb38cc81af..73dcbc13b79a1 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1,5 +1,5 @@
use either::Either;
-use hir::{db::ExpandDatabase, CallableKind, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
+use hir::{db::ExpandDatabase, CallableKind, ClosureStyle, HirDisplay, HirFileIdExt, InFile};
use ide_db::{
famous_defs::FamousDefs,
source_change::{SourceChange, SourceChangeBuilder},
@@ -88,7 +88,7 @@ fn add_reference(
let range = ctx.sema.diagnostics_display_range((*expr_ptr).map(|it| it.into()));
let (_, mutability) = d.expected.as_reference()?;
- let actual_with_ref = Type::reference(&d.actual, mutability);
+ let actual_with_ref = d.actual.add_reference(mutability);
if !actual_with_ref.could_coerce_to(ctx.sema.db, &d.expected) {
return None;
}
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 6b654f8934516..889258c94c535 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -33,12 +33,10 @@
//
// Supported constraints:
//
-// |===
-// | Constraint | Restricts placeholder
-//
-// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`)
-// | not(a) | Negates the constraint `a`
-// |===
+// | Constraint | Restricts placeholder |
+// |---------------|------------------------|
+// | kind(literal) | Is a literal (e.g. `42` or `"forty two"`) |
+// | not(a) | Negates the constraint `a` |
//
// Available via the command `rust-analyzer.ssr`.
//
@@ -52,11 +50,9 @@
// String::from((y + 5).foo(z))
// ```
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Structural Search Replace**
-// |===
+// | Editor | Action Name |
+// |---------|--------------|
+// | VS Code | **rust-analyzer: Structural Search Replace** |
//
// Also available as an assist, by writing a comment containing the structural
// search and replace rule. You will only see the assist if the comment can
diff --git a/src/tools/rust-analyzer/crates/ide/src/annotations.rs b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
index 18f866eb9fc96..006e6e8246e1c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/annotations.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/annotations.rs
@@ -21,7 +21,7 @@ mod fn_references;
// Provides user with annotations above items for looking up references or impl blocks
// and running/debugging binaries.
//
-// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[]
+// 
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct Annotation {
pub range: TextRange,
diff --git a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
index cfd8919730ad2..e35e47e747188 100644
--- a/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/doc_links.rs
@@ -122,11 +122,9 @@ pub(crate) fn remove_links(markdown: &str) -> String {
// The simplest way to use this feature is via the context menu. Right-click on
// the selected item. The context menu opens. Select **Open Docs**.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Open Docs**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Open Docs** |
pub(crate) fn external_docs(
db: &RootDatabase,
FilePosition { file_id, offset }: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 0ad894427b2c5..ad4308e06a14b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -19,13 +19,11 @@ pub struct ExpandedMacro {
//
// Shows the full macro expansion of the macro at the current caret position.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Expand macro recursively at caret** |
//
-// | VS Code | **rust-analyzer: Expand macro recursively at caret**
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
+// 
pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option {
let sema = Semantics::new(db);
let file = sema.parse_guess_edition(position.file_id);
diff --git a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
index 3d49082f2858d..76414854e91ef 100644
--- a/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/extend_selection.rs
@@ -17,13 +17,11 @@ use crate::FileRange;
// Extends or shrinks the current selection to the encompassing syntactic construct
// (expression, statement, item, module, etc). It works with multiple cursors.
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | Alt+Shift+→ , Alt+Shift+← |
//
-// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[]
+// 
pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
let sema = Semantics::new(db);
let src = sema.parse_guess_edition(frange.file_id);
diff --git a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
index 37b3cb03b3331..5ed2144430741 100644
--- a/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/fetch_crates.rs
@@ -14,13 +14,11 @@ pub struct CrateInfo {
//
// Shows a view tree with all the dependencies of this project
//
-// |===
-// | Editor | Panel Name
+// | Editor | Panel Name |
+// |---------|------------|
+// | VS Code | **Rust Dependencies** |
//
-// | VS Code | **Rust Dependencies**
-// |===
-//
-// image::https://user-images.githubusercontent.com/5748995/229394139-2625beab-f4c9-484b-84ed-ad5dee0b1e1a.png[]
+// 
pub(crate) fn fetch_crates(db: &RootDatabase) -> FxIndexSet {
let crate_graph = db.crate_graph();
crate_graph
diff --git a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
index 50977ee840c82..52fbab6fa12b1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/file_structure.rs
@@ -31,14 +31,11 @@ pub enum StructureNodeKind {
// * draw breadcrumbs to describe the context around the cursor
// * draw outline of the file
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | Ctrl+Shift+O |
//
-// | VS Code | kbd:[Ctrl+Shift+O]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[]
-
+// 
pub(crate) fn file_structure(file: &SourceFile) -> Vec {
let mut res = Vec::new();
let mut stack = Vec::new();
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
index d18732a6b846b..bdafb701ff534 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_definition.rs
@@ -31,13 +31,11 @@ use syntax::{
//
// For outline modules, this will navigate to the source file of the module.
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | F12 |
//
-// | VS Code | kbd:[F12]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
+// 
pub(crate) fn goto_definition(
db: &RootDatabase,
FilePosition { file_id, offset }: FilePosition,
@@ -3274,4 +3272,22 @@ fn f() {
"#,
);
}
+
+ #[test]
+ fn use_inside_body() {
+ check(
+ r#"
+fn main() {
+ mod nice_module {
+ pub(super) struct NiceStruct;
+ // ^^^^^^^^^^
+ }
+
+ use nice_module::NiceStruct$0;
+
+ let _ = NiceStruct;
+}
+ "#,
+ );
+ }
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
index e926378367ece..e1d834b5d1c69 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_implementation.rs
@@ -12,13 +12,11 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
//
// Navigates to the impl items of types.
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | Ctrl+F12
//
-// | VS Code | kbd:[Ctrl+F12]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[]
+// 
pub(crate) fn goto_implementation(
db: &RootDatabase,
FilePosition { file_id, offset }: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
index 2610d6c8863a0..ddc274a830352 100644
--- a/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/goto_type_definition.rs
@@ -8,13 +8,11 @@ use crate::{FilePosition, NavigationTarget, RangeInfo, TryToNav};
//
// Navigates to the type of an identifier.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **Go to Type Definition** |
//
-// | VS Code | **Go to Type Definition**
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[]
+// 
pub(crate) fn goto_type_definition(
db: &RootDatabase,
FilePosition { file_id, offset }: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index 612bc36f62846..6463206596af5 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -43,12 +43,12 @@ pub struct HighlightRelatedConfig {
//
// Highlights constructs related to the thing under the cursor:
//
-// . if on an identifier, highlights all references to that identifier in the current file
-// .. additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
-// . if on an `async` or `await` token, highlights all yield points for that async context
-// . if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
-// . if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
-// . if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
+// 1. if on an identifier, highlights all references to that identifier in the current file
+// * additionally, if the identifier is a trait in a where clause, type parameter trait bound or use item, highlights all references to that trait's assoc items in the corresponding scope
+// 1. if on an `async` or `await` token, highlights all yield points for that async context
+// 1. if on a `return` or `fn` keyword, `?` character or `->` return type arrow, highlights all exit points for that context
+// 1. if on a `break`, `loop`, `while` or `for` token, highlights all break points for that loop or block context
+// 1. if on a `move` or `|` token that belongs to a closure, highlights all captures of the closure.
//
// Note: `?`, `|` and `->` do not currently trigger this behavior in the VSCode editor.
pub(crate) fn highlight_related(
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 9d4c103fc2e01..95a720e7e452a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -118,7 +118,7 @@ pub struct HoverResult {
// Shows additional information, like the type of an expression or the documentation for a definition when "focusing" code.
// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
//
-// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
+// 
pub(crate) fn hover(
db: &RootDatabase,
frange @ FileRange { file_id, range }: FileRange,
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index 40f3406b72d37..c996230c3a1ff 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -434,6 +434,7 @@ fn definition_owner_name(db: &RootDatabase, def: Definition, edition: Edition) -
None => it.name(db),
}
}
+ hir::GenericDef::Static(it) => Some(it.name(db)),
},
Definition::DeriveHelper(derive_helper) => Some(derive_helper.derive().name(db)),
d => {
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 1f723c85df7aa..63039b1cd34e0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
@@ -59,7 +59,7 @@ mod range_exclusive;
//
// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
// any of the
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria]
+// [following criteria](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99)
// are met:
//
// * the parameter name is a suffix of the function's name
@@ -68,13 +68,13 @@ mod range_exclusive;
// of argument with _ splitting it off
// * the parameter name starts with `ra_fixture`
// * the parameter name is a
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name]
+// [well known name](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200)
// in a unary function
// * the parameter name is a
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character]
+// [single character](https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201)
// in a unary function
//
-// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
+// 
pub(crate) fn inlay_hints(
db: &RootDatabase,
file_id: FileId,
@@ -294,6 +294,7 @@ pub struct InlayHintsConfig {
pub param_names_for_lifetime_elision_hints: bool,
pub hide_named_constructor_hints: bool,
pub hide_closure_initialization_hints: bool,
+ pub hide_closure_parameter_hints: bool,
pub range_exclusive_hints: bool,
pub closure_style: ClosureStyle,
pub max_length: Option,
@@ -860,6 +861,7 @@ mod tests {
binding_mode_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
+ hide_closure_parameter_hints: false,
closure_style: ClosureStyle::ImplFn,
param_names_for_lifetime_elision_hints: false,
max_length: None,
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
index 2acd4021cc155..d3b95750f7e18 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/adjustment.rs
@@ -13,11 +13,7 @@ use ide_db::famous_defs::FamousDefs;
use ide_db::text_edit::TextEditBuilder;
use span::EditionedFileId;
-use stdx::never;
-use syntax::{
- ast::{self, make, AstNode},
- ted,
-};
+use syntax::ast::{self, prec::ExprPrecedence, AstNode};
use crate::{
AdjustmentHints, AdjustmentHintsMode, InlayHint, InlayHintLabel, InlayHintLabelPart,
@@ -104,12 +100,14 @@ pub(super) fn hints(
};
let iter: &mut dyn Iterator- = iter.as_mut().either(|it| it as _, |it| it as _);
+ let mut has_adjustments = false;
let mut allow_edit = !postfix;
for Adjustment { source, target, kind } in iter {
if source == target {
cov_mark::hit!(same_type_adjustment);
continue;
}
+ has_adjustments = true;
// FIXME: Add some nicer tooltips to each of these
let (text, coercion) = match kind {
@@ -172,6 +170,10 @@ pub(super) fn hints(
};
if postfix { &mut post } else { &mut pre }.label.append_part(label);
}
+ if !has_adjustments {
+ return None;
+ }
+
if !postfix && needs_inner_parens {
pre.label.append_str("(");
}
@@ -254,71 +256,31 @@ fn mode_and_needs_parens_for_adjustment_hints(
/// Returns whatever we need to add parentheses on the inside and/or outside of `expr`,
/// if we are going to add (`postfix`) adjustments hints to it.
fn needs_parens_for_adjustment_hints(expr: &ast::Expr, postfix: bool) -> (bool, bool) {
- // This is a very miserable pile of hacks...
- //
- // `Expr::needs_parens_in` requires that the expression is the child of the other expression,
- // that is supposed to be its parent.
- //
- // But we want to check what would happen if we add `*`/`.*` to the inner expression.
- // To check for inner we need `` expr.needs_parens_in(`*expr`) ``,
- // to check for outer we need `` `*expr`.needs_parens_in(parent) ``,
- // where "expr" is the `expr` parameter, `*expr` is the edited `expr`,
- // and "parent" is the parent of the original expression...
- //
- // For this we utilize mutable trees, which is a HACK, but it works.
- //
- // FIXME: comeup with a better API for `needs_parens_in`, so that we don't have to do *this*
-
- // Make `&expr`/`expr?`
- let dummy_expr = {
- // `make::*` function go through a string, so they parse wrongly.
- // for example `` make::expr_try(`|| a`) `` would result in a
- // `|| (a?)` and not `(|| a)?`.
- //
- // Thus we need dummy parens to preserve the relationship we want.
- // The parens are then simply ignored by the following code.
- let dummy_paren = make::expr_paren(expr.clone());
- if postfix {
- make::expr_try(dummy_paren)
- } else {
- make::expr_ref(dummy_paren, false)
- }
- };
-
- // Do the dark mutable tree magic.
- // This essentially makes `dummy_expr` and `expr` switch places (families),
- // so that `expr`'s parent is not `dummy_expr`'s parent.
- let dummy_expr = dummy_expr.clone_for_update();
- let expr = expr.clone_for_update();
- ted::replace(expr.syntax(), dummy_expr.syntax());
-
- let parent = dummy_expr.syntax().parent();
- let Some(expr) = (|| {
- if postfix {
- let ast::Expr::TryExpr(e) = &dummy_expr else { return None };
- let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
-
- e.expr()
- } else {
- let ast::Expr::RefExpr(e) = &dummy_expr else { return None };
- let Some(ast::Expr::ParenExpr(e)) = e.expr() else { return None };
-
- e.expr()
- }
- })() else {
- never!("broken syntax tree?\n{:?}\n{:?}", expr, dummy_expr);
- return (true, true);
- };
-
- // At this point
- // - `parent` is the parent of the original expression
- // - `dummy_expr` is the original expression wrapped in the operator we want (`*`/`.*`)
- // - `expr` is the clone of the original expression (with `dummy_expr` as the parent)
-
- let needs_outer_parens = parent.is_some_and(|p| dummy_expr.needs_parens_in(p));
- let needs_inner_parens = expr.needs_parens_in(dummy_expr.syntax().clone());
-
- (needs_outer_parens, needs_inner_parens)
+ let prec = expr.precedence();
+ if postfix {
+ // postfix ops have higher precedence than any other operator, so we need to wrap
+ // any inner expression that is below (except for jumps if they don't have a value)
+ let needs_inner_parens = prec < ExprPrecedence::Unambiguous && {
+ prec != ExprPrecedence::Jump || !expr.is_ret_like_with_no_value()
+ };
+ // given we are the higher precedence, no parent expression will have stronger requirements
+ let needs_outer_parens = false;
+ (needs_outer_parens, needs_inner_parens)
+ } else {
+ // We need to wrap all binary like things, thats everything below prefix except for jumps
+ let needs_inner_parens = prec < ExprPrecedence::Prefix && prec != ExprPrecedence::Jump;
+ let parent = expr
+ .syntax()
+ .parent()
+ .and_then(ast::Expr::cast)
+ // if we are already wrapped, great, no need to wrap again
+ .filter(|it| !matches!(it, ast::Expr::ParenExpr(_)))
+ .map(|it| it.precedence());
+ // if we have no parent, we don't need outer parens to disambiguate
+ // otherwise anything with higher precedence than what we insert needs to wrap us
+ let needs_outer_parens = parent.is_some_and(|prec| prec > ExprPrecedence::Prefix);
+ (needs_outer_parens, needs_inner_parens)
+ }
}
#[cfg(test)]
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 01a1a4545c478..c2986a9aa6626 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
@@ -36,6 +36,9 @@ pub(super) fn hints(
if it.ty().is_some() {
return None;
}
+ if config.hide_closure_parameter_hints && it.syntax().ancestors().nth(2).is_none_or(|n| matches!(ast::Expr::cast(n), Some(ast::Expr::ClosureExpr(_)))) {
+ return None;
+ }
Some(it.colon_token())
},
ast::LetStmt(it) => {
@@ -949,6 +952,36 @@ fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
);
}
+ #[test]
+ fn skip_closure_parameter_hints() {
+ check_with_config(
+ InlayHintsConfig {
+ type_hints: true,
+ hide_closure_parameter_hints: true,
+ ..DISABLED_CONFIG
+ },
+ r#"
+//- minicore: fn
+struct Foo;
+impl Foo {
+ fn foo(self: Self) {}
+ fn bar(self: &Self) {}
+}
+fn main() {
+ let closure = |x, y| x + y;
+ // ^^^^^^^ impl Fn(i32, i32) -> {unknown}
+ closure(2, 3);
+ let point = (10, 20);
+ // ^^^^^ (i32, i32)
+ let (x, y) = point;
+ // ^ i32 ^ i32
+ Foo::foo(Foo);
+ Foo::bar(&Foo);
+}
+"#,
+ );
+ }
+
#[test]
fn hint_truncation() {
check_with_config(
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
index 3e91618d08e6f..9b981c0a3acf7 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_captures.rs
@@ -1,4 +1,4 @@
-//! Implementation of "closure return type" inlay hints.
+//! Implementation of "closure captures" inlay hints.
//!
//! Tests live in [`bind_pat`][super::bind_pat] module.
use ide_db::famous_defs::FamousDefs;
diff --git a/src/tools/rust-analyzer/crates/ide/src/interpret.rs b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
index e0fdc3dd6f97c..ae11072e34b74 100644
--- a/src/tools/rust-analyzer/crates/ide/src/interpret.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/interpret.rs
@@ -7,11 +7,9 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode, TextRange};
// Feature: Interpret A Function, Static Or Const.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Interpret**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Interpret** |
pub(crate) fn interpret(db: &RootDatabase, position: FilePosition) -> String {
match find_and_interpret(db, position) {
Some((duration, mut result)) => {
diff --git a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
index e4670177ecf21..ea18a97070c3a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/join_lines.rs
@@ -21,17 +21,13 @@ pub struct JoinLinesConfig {
//
// Join selected lines into one, smartly fixing up whitespace, trailing commas, and braces.
//
-// See
-// https://user-images.githubusercontent.com/1711539/124515923-4504e800-dde9-11eb-8d58-d97945a1a785.gif[this gif]
-// for the cases handled specially by joined lines.
+// See [this gif](https://user-images.githubusercontent.com/1711539/124515923-4504e800-dde9-11eb-8d58-d97945a1a785.gif) for the cases handled specially by joined lines.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Join lines** |
//
-// | VS Code | **rust-analyzer: Join lines**
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[]
+// 
pub(crate) fn join_lines(
config: &JoinLinesConfig,
file: &SourceFile,
diff --git a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
index 5735615283663..67346ea9cf90f 100644
--- a/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/matching_brace.rs
@@ -9,13 +9,11 @@ use syntax::{
// moves cursor to the matching brace. It uses the actual parser to determine
// braces, so it won't confuse generics with comparisons.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Find matching brace** |
//
-// | VS Code | **rust-analyzer: Find matching brace**
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[]
+// 
pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option
{
const BRACES: &[SyntaxKind] =
&[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
diff --git a/src/tools/rust-analyzer/crates/ide/src/moniker.rs b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
index d97c12ebafb38..66ea49a98a088 100644
--- a/src/tools/rust-analyzer/crates/ide/src/moniker.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/moniker.rs
@@ -289,7 +289,10 @@ fn def_to_non_local_moniker(
definition: Definition,
from_crate: Crate,
) -> Option {
- let module = definition.module(db)?;
+ let module = match definition {
+ Definition::Module(module) if module.is_crate_root() => module,
+ _ => definition.module(db)?,
+ };
let krate = module.krate();
let edition = krate.edition(db);
@@ -322,12 +325,18 @@ fn def_to_non_local_moniker(
name: name.display(db, edition).to_string(),
desc: def_to_kind(db, def).into(),
});
- } else if reverse_description.is_empty() {
- // Don't allow the last descriptor to be absent.
- return None;
} else {
match def {
- Definition::Module(module) if module.is_crate_root() => {}
+ Definition::Module(module) if module.is_crate_root() => {
+ // only include `crate` namespace by itself because we prefer
+ // `rust-analyzer cargo foo . bar/` over `rust-analyzer cargo foo . crate/bar/`
+ if reverse_description.is_empty() {
+ reverse_description.push(MonikerDescriptor {
+ name: "crate".to_owned(),
+ desc: MonikerDescriptorKind::Namespace,
+ });
+ }
+ }
_ => {
tracing::error!(?def, "Encountered enclosing definition with no name");
}
@@ -340,6 +349,9 @@ fn def_to_non_local_moniker(
};
def = next_def;
}
+ if reverse_description.is_empty() {
+ return None;
+ }
reverse_description.reverse();
let description = reverse_description;
diff --git a/src/tools/rust-analyzer/crates/ide/src/move_item.rs b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
index b0df9257ba10b..3fb3a788b9182 100644
--- a/src/tools/rust-analyzer/crates/ide/src/move_item.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/move_item.rs
@@ -17,14 +17,12 @@ pub enum Direction {
//
// Move item under cursor or selection up and down.
//
-// |===
-// | Editor | Action Name
-//
+// | Editor | Action Name |
+// |---------|-------------|
// | VS Code | **rust-analyzer: Move item up**
// | VS Code | **rust-analyzer: Move item down**
-// |===
//
-// image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
+// 
pub(crate) fn move_item(
db: &RootDatabase,
range: FileRange,
diff --git a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
index 7a0c28d925aee..6d82f9b0634b4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/parent_module.rs
@@ -15,13 +15,11 @@ use crate::NavigationTarget;
//
// Navigates to the parent module of the current module.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Locate parent module** |
//
-// | VS Code | **rust-analyzer: Locate parent module**
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
+// 
/// This returns `Vec` because a module may be included from several places.
pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec {
diff --git a/src/tools/rust-analyzer/crates/ide/src/references.rs b/src/tools/rust-analyzer/crates/ide/src/references.rs
index b1079312d3bb0..069818d50e76a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/references.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/references.rs
@@ -43,13 +43,11 @@ pub struct Declaration {
//
// Shows all references of the item at the cursor location
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | Shift+Alt+F12 |
//
-// | VS Code | kbd:[Shift+Alt+F12]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[]
+// 
pub(crate) fn find_all_refs(
sema: &Semantics<'_, RootDatabase>,
position: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/rename.rs b/src/tools/rust-analyzer/crates/ide/src/rename.rs
index 07dfd83c4eb7f..3e8295e3f08ee 100644
--- a/src/tools/rust-analyzer/crates/ide/src/rename.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/rename.rs
@@ -71,13 +71,11 @@ pub(crate) fn prepare_rename(
//
// Renames the item below the cursor and all of its references
//
-// |===
-// | Editor | Shortcut
+// | Editor | Shortcut |
+// |---------|----------|
+// | VS Code | F2 |
//
-// | VS Code | kbd:[F2]
-// |===
-//
-// image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[]
+// 
pub(crate) fn rename(
db: &RootDatabase,
position: FilePosition,
@@ -2003,19 +2001,37 @@ impl Foo {
"foo",
r#"
fn f($0self) -> i32 {
- use self as _;
self.i
}
"#,
r#"
fn f(foo: _) -> i32 {
- use self as _;
foo.i
}
"#,
);
}
+ #[test]
+ fn no_type_value_ns_confuse() {
+ // Test that we don't rename items from different namespaces.
+ check(
+ "bar",
+ r#"
+struct foo {}
+fn f(foo$0: i32) -> i32 {
+ use foo as _;
+}
+"#,
+ r#"
+struct foo {}
+fn f(bar: i32) -> i32 {
+ use foo as _;
+}
+"#,
+ );
+ }
+
#[test]
fn test_self_in_path_to_parameter() {
check(
diff --git a/src/tools/rust-analyzer/crates/ide/src/runnables.rs b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
index 32edacee51c7d..78c9f2309a0d4 100644
--- a/src/tools/rust-analyzer/crates/ide/src/runnables.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/runnables.rs
@@ -119,12 +119,11 @@ impl Runnable {
// location**. Super useful for repeatedly running just a single test. Do bind this
// to a shortcut!
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Run** |
//
-// | VS Code | **rust-analyzer: Run**
-// |===
-// image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
+// 
pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec {
let sema = Semantics::new(db);
@@ -207,11 +206,9 @@ pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec {
// The simplest way to use this feature is via the context menu. Right-click on
// the selected item. The context menu opens. Select **Peek Related Tests**.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Peek Related Tests**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Peek Related Tests** |
pub(crate) fn related_tests(
db: &RootDatabase,
position: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
index f8c60418eb014..f99721160041c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/signature_help.rs
@@ -321,7 +321,9 @@ fn signature_help_for_generics(
format_to!(res.signature, "type {}", it.name(db).display(db, edition));
}
// These don't have generic args that can be specified
- hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
+ hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) | hir::GenericDef::Static(_) => {
+ return None
+ }
}
let params = generics_def.params(sema.db);
diff --git a/src/tools/rust-analyzer/crates/ide/src/static_index.rs b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
index 8050a38b3ca13..07553a87d28fc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/static_index.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/static_index.rs
@@ -154,6 +154,7 @@ impl StaticIndex<'_> {
implicit_drop_hints: false,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
+ hide_closure_parameter_hints: false,
closure_style: hir::ClosureStyle::ImplFn,
param_names_for_lifetime_elision_hints: false,
binding_mode_hints: false,
@@ -169,10 +170,10 @@ impl StaticIndex<'_> {
.unwrap();
// hovers
let sema = hir::Semantics::new(self.db);
- let tokens_or_nodes = sema.parse_guess_edition(file_id).syntax().clone();
+ let root = sema.parse_guess_edition(file_id).syntax().clone();
let edition =
sema.attach_first_edition(file_id).map(|it| it.edition()).unwrap_or(Edition::CURRENT);
- let tokens = tokens_or_nodes.descendants_with_tokens().filter_map(|it| match it {
+ let tokens = root.descendants_with_tokens().filter_map(|it| match it {
syntax::NodeOrToken::Node(_) => None,
syntax::NodeOrToken::Token(it) => Some(it),
});
@@ -194,24 +195,19 @@ impl StaticIndex<'_> {
)
});
let mut result = StaticIndexedFile { file_id, inlay_hints, folds, tokens: vec![] };
- for token in tokens {
- let range = token.text_range();
- let node = token.parent().unwrap();
- let def = match get_definition(&sema, token.clone()) {
- Some(it) => it,
- None => continue,
- };
+
+ let mut add_token = |def: Definition, range: TextRange, scope_node: &SyntaxNode| {
let id = if let Some(it) = self.def_map.get(&def) {
*it
} else {
let it = self.tokens.insert(TokenStaticData {
- documentation: documentation_for_definition(&sema, def, &node),
+ documentation: documentation_for_definition(&sema, def, scope_node),
hover: Some(hover_for_definition(
&sema,
file_id,
def,
None,
- &node,
+ scope_node,
None,
false,
&hover_config,
@@ -240,6 +236,22 @@ impl StaticIndex<'_> {
},
});
result.tokens.push((range, id));
+ };
+
+ if let Some(module) = sema.file_to_module_def(file_id) {
+ let def = Definition::Module(module);
+ let range = root.text_range();
+ add_token(def, range, &root);
+ }
+
+ for token in tokens {
+ let range = token.text_range();
+ let node = token.parent().unwrap();
+ let def = match get_definition(&sema, token.clone()) {
+ Some(it) => it,
+ None => continue,
+ };
+ add_token(def, range, &node);
}
self.files.push(result);
}
@@ -300,6 +312,10 @@ mod tests {
let mut range_set: FxHashSet<_> = ranges.iter().map(|it| it.0).collect();
for f in s.files {
for (range, _) in f.tokens {
+ if range.start() == TextSize::from(0) {
+ // ignore whole file range corresponding to module definition
+ continue;
+ }
let it = FileRange { file_id: f.file_id, range };
if !range_set.contains(&it) {
panic!("additional range {it:?}");
diff --git a/src/tools/rust-analyzer/crates/ide/src/status.rs b/src/tools/rust-analyzer/crates/ide/src/status.rs
index 9e823daa2bec9..b0022cfac765b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/status.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/status.rs
@@ -29,12 +29,11 @@ use triomphe::Arc;
//
// Shows internal statistic about memory usage of rust-analyzer.
//
-// |===
-// | Editor | Action Name
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Status** |
//
-// | VS Code | **rust-analyzer: Status**
-// |===
-// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
+// 
pub(crate) fn status(db: &RootDatabase, file_id: Option) -> String {
let mut buf = String::new();
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
index f53f0aec09842..1853e3a340740 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting.rs
@@ -76,113 +76,118 @@ pub struct HighlightConfig {
// We also give special modifier for `mut` and `&mut` local variables.
//
//
-// .Token Tags
+// #### Token Tags
//
// Rust-analyzer currently emits the following token tags:
//
// - For items:
-// +
-// [horizontal]
-// attribute:: Emitted for attribute macros.
-// enum:: Emitted for enums.
-// function:: Emitted for free-standing functions.
-// derive:: Emitted for derive macros.
-// macro:: Emitted for function-like macros.
-// method:: Emitted for associated functions, also knowns as methods.
-// namespace:: Emitted for modules.
-// struct:: Emitted for structs.
-// trait:: Emitted for traits.
-// typeAlias:: Emitted for type aliases and `Self` in `impl`s.
-// union:: Emitted for unions.
+//
+// | | |
+// |-----------|--------------------------------|
+// | attribute | Emitted for attribute macros. |
+// |enum| Emitted for enums. |
+// |function| Emitted for free-standing functions. |
+// |derive| Emitted for derive macros. |
+// |macro| Emitted for function-like macros. |
+// |method| Emitted for associated functions, also knowns as methods. |
+// |namespace| Emitted for modules. |
+// |struct| Emitted for structs.|
+// |trait| Emitted for traits.|
+// |typeAlias| Emitted for type aliases and `Self` in `impl`s.|
+// |union| Emitted for unions.|
//
// - For literals:
-// +
-// [horizontal]
-// boolean:: Emitted for the boolean literals `true` and `false`.
-// character:: Emitted for character literals.
-// number:: Emitted for numeric literals.
-// string:: Emitted for string literals.
-// escapeSequence:: Emitted for escaped sequences inside strings like `\n`.
-// formatSpecifier:: Emitted for format specifiers `{:?}` in `format!`-like macros.
+//
+// | | |
+// |-----------|--------------------------------|
+// | boolean| Emitted for the boolean literals `true` and `false`.|
+// | character| Emitted for character literals.|
+// | number| Emitted for numeric literals.|
+// | string| Emitted for string literals.|
+// | escapeSequence| Emitted for escaped sequences inside strings like `\n`.|
+// | formatSpecifier| Emitted for format specifiers `{:?}` in `format!`-like macros.|
//
// - For operators:
-// +
-// [horizontal]
-// operator:: Emitted for general operators.
-// arithmetic:: Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.
-// bitwise:: Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.
-// comparison:: Emitted for the comparison operators `>`, `<`, `==`, `>=`, `<=`, `!=`.
-// logical:: Emitted for the logical operators `||`, `&&`, `!`.
+//
+// | | |
+// |-----------|--------------------------------|
+// |operator| Emitted for general operators.|
+// |arithmetic| Emitted for the arithmetic operators `+`, `-`, `*`, `/`, `+=`, `-=`, `*=`, `/=`.|
+// |bitwise| Emitted for the bitwise operators `|`, `&`, `!`, `^`, `|=`, `&=`, `^=`.|
+// |comparison| Emitted for the comparison oerators `>`, `<`, `==`, `>=`, `<=`, `!=`.|
+// |logical| Emitted for the logical operatos `||`, `&&`, `!`.|
//
// - For punctuation:
-// +
-// [horizontal]
-// punctuation:: Emitted for general punctuation.
-// attributeBracket:: Emitted for attribute invocation brackets, that is the `#[` and `]` tokens.
-// angle:: Emitted for `<>` angle brackets.
-// brace:: Emitted for `{}` braces.
-// bracket:: Emitted for `[]` brackets.
-// parenthesis:: Emitted for `()` parentheses.
-// colon:: Emitted for the `:` token.
-// comma:: Emitted for the `,` token.
-// dot:: Emitted for the `.` token.
-// semi:: Emitted for the `;` token.
-// macroBang:: Emitted for the `!` token in macro calls.
//
-// //-
+// | | |
+// |-----------|--------------------------------|
+// |punctuation| Emitted for general punctuation.|
+// |attributeBracket| Emitted for attribute invocation brackets, that is the `#[` and `]` tokens.|
+// |angle| Emitted for `<>` angle brackets.|
+// |brace| Emitted for `{}` braces.|
+// |bracket| Emitted for `[]` brackets.|
+// |parenthesis| Emitted for `()` parentheses.|
+// |colon| Emitted for the `:` token.|
+// |comma| Emitted for the `,` token.|
+// |dot| Emitted for the `.` token.|
+// |semi| Emitted for the `;` token.|
+// |macroBang| Emitted for the `!` token in macro calls.|
//
-// [horizontal]
-// builtinAttribute:: Emitted for names to builtin attributes in attribute path, the `repr` in `#[repr(u8)]` for example.
-// builtinType:: Emitted for builtin types like `u32`, `str` and `f32`.
-// comment:: Emitted for comments.
-// constParameter:: Emitted for const parameters.
-// deriveHelper:: Emitted for derive helper attributes.
-// enumMember:: Emitted for enum variants.
-// generic:: Emitted for generic tokens that have no mapping.
-// keyword:: Emitted for keywords.
-// label:: Emitted for labels.
-// lifetime:: Emitted for lifetimes.
-// parameter:: Emitted for non-self function parameters.
-// property:: Emitted for struct and union fields.
-// selfKeyword:: Emitted for the self function parameter and self path-specifier.
-// selfTypeKeyword:: Emitted for the Self type parameter.
-// toolModule:: Emitted for tool modules.
-// typeParameter:: Emitted for type parameters.
-// unresolvedReference:: Emitted for unresolved references, names that rust-analyzer can't find the definition of.
-// variable:: Emitted for locals, constants and statics.
+//-
//
+// | | |
+// |-----------|--------------------------------|
+// |builtinAttribute| Emitted for names to builtin attributes in attribute path, the `repr` in `#[repr(u8)]` for example.|
+// |builtinType| Emitted for builtin types like `u32`, `str` and `f32`.|
+// |comment| Emitted for comments.|
+// |constParameter| Emitted for const parameters.|
+// |deriveHelper| Emitted for derive helper attributes.|
+// |enumMember| Emitted for enum variants.|
+// |generic| Emitted for generic tokens that have no mapping.|
+// |keyword| Emitted for keywords.|
+// |label| Emitted for labels.|
+// |lifetime| Emitted for lifetimes.|
+// |parameter| Emitted for non-self function parameters.|
+// |property| Emitted for struct and union fields.|
+// |selfKeyword| Emitted for the self function parameter and self path-specifier.|
+// |selfTypeKeyword| Emitted for the Self type parameter.|
+// |toolModule| Emitted for tool modules.|
+// |typeParameter| Emitted for type parameters.|
+// |unresolvedReference| Emitted for unresolved references, names that rust-analyzer can't find the definition of.|
+// |variable| Emitted for locals, constants and statics.|
//
-// .Token Modifiers
+//
+// #### Token Modifiers
//
// Token modifiers allow to style some elements in the source code more precisely.
//
// Rust-analyzer currently emits the following token modifiers:
//
-// [horizontal]
-// async:: Emitted for async functions and the `async` and `await` keywords.
-// attribute:: Emitted for tokens inside attributes.
-// callable:: Emitted for locals whose types implements one of the `Fn*` traits.
-// constant:: Emitted for consts.
-// consuming:: Emitted for locals that are being consumed when use in a function call.
-// controlFlow:: Emitted for control-flow related tokens, this includes the `?` operator.
-// crateRoot:: Emitted for crate names, like `serde` and `crate`.
-// declaration:: Emitted for names of definitions, like `foo` in `fn foo() {}`.
-// defaultLibrary:: Emitted for items from built-in crates (std, core, alloc, test and proc_macro).
-// documentation:: Emitted for documentation comments.
-// injected:: Emitted for doc-string injected highlighting like rust source blocks in documentation.
-// intraDocLink:: Emitted for intra doc links in doc-strings.
-// library:: Emitted for items that are defined outside of the current crate.
-// macro:: Emitted for tokens inside macro calls.
-// mutable:: Emitted for mutable locals and statics as well as functions taking `&mut self`.
-// public:: Emitted for items that are from the current crate and are `pub`.
-// reference:: Emitted for locals behind a reference and functions taking `self` by reference.
-// static:: Emitted for "static" functions, also known as functions that do not take a `self` param, as well as statics and consts.
-// trait:: Emitted for associated trait items.
-// unsafe:: Emitted for unsafe operations, like unsafe function calls, as well as the `unsafe` token.
-//
+// | | |
+// |-----------|--------------------------------|
+// |async| Emitted for async functions and the `async` and `await` keywords.|
+// |attribute| Emitted for tokens inside attributes.|
+// |callable| Emitted for locals whose types implements one of the `Fn*` traits.|
+// |constant| Emitted for const.|
+// |consuming| Emitted for locals that are being consumed when use in a function call.|
+// |controlFlow| Emitted for control-flow related tokens, this includes th `?` operator.|
+// |crateRoot| Emitted for crate names, like `serde` and `crate.|
+// |declaration| Emitted for names of definitions, like `foo` in `fn foo(){}`.|
+// |defaultLibrary| Emitted for items from built-in crates (std, core, allc, test and proc_macro).|
+// |documentation| Emitted for documentation comment.|
+// |injected| Emitted for doc-string injected highlighting like rust source blocks in documentation.|
+// |intraDocLink| Emitted for intra doc links in doc-string.|
+// |library| Emitted for items that are defined outside of the current crae.|
+// |macro| Emitted for tokens inside macro call.|
+// |mutable| Emitted for mutable locals and statics as well as functions taking `&mut self`.|
+// |public| Emitted for items that are from the current crate and are `pub.|
+// |reference| Emitted for locals behind a reference and functions taking self` by reference.|
+// |static| Emitted for "static" functions, also known as functions that d not take a `self` param, as well as statics and consts.|
+// |trait| Emitted for associated trait item.|
+// |unsafe| Emitted for unsafe operations, like unsafe function calls, as ell as the `unsafe` token.|
//
-// image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[]
-// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
+// 
+// 
pub(crate) fn highlight(
db: &RootDatabase,
config: HighlightConfig,
@@ -478,7 +483,15 @@ fn traverse(
{
continue;
}
- highlight_format_string(hl, sema, krate, &string, &expanded_string, range);
+ highlight_format_string(
+ hl,
+ sema,
+ krate,
+ &string,
+ &expanded_string,
+ range,
+ file_id.edition(),
+ );
if !string.is_raw() {
highlight_escape_string(hl, &string, range.start());
@@ -526,6 +539,7 @@ fn traverse(
&mut bindings_shadow_count,
config.syntactic_name_ref_highlighting,
name_like,
+ file_id.edition(),
),
NodeOrToken::Token(token) => {
highlight::token(sema, token, file_id.edition()).zip(Some(None))
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
index 7234108701a34..43a6bdad7e9bc 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/format.rs
@@ -4,6 +4,7 @@ use ide_db::{
syntax_helpers::format_string::{is_format_string, lex_format_specifiers, FormatSpecifier},
SymbolKind,
};
+use span::Edition;
use syntax::{ast, TextRange};
use crate::{
@@ -18,6 +19,7 @@ pub(super) fn highlight_format_string(
string: &ast::String,
expanded_string: &ast::String,
range: TextRange,
+ edition: Edition,
) {
if is_format_string(expanded_string) {
// FIXME: Replace this with the HIR info we have now.
@@ -39,7 +41,7 @@ pub(super) fn highlight_format_string(
if let Some(res) = res {
stack.add(HlRange {
range,
- highlight: highlight_def(sema, krate, Definition::from(res)),
+ highlight: highlight_def(sema, krate, Definition::from(res), edition),
binding_hash: None,
})
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
index 22a2fe4e9eb26..479c0b381a4bb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/highlight.rs
@@ -58,6 +58,7 @@ pub(super) fn name_like(
bindings_shadow_count: &mut FxHashMap,
syntactic_name_ref_highlighting: bool,
name_like: ast::NameLike,
+ edition: Edition,
) -> Option<(Highlight, Option)> {
let mut binding_hash = None;
let highlight = match name_like {
@@ -68,16 +69,17 @@ pub(super) fn name_like(
&mut binding_hash,
syntactic_name_ref_highlighting,
name_ref,
+ edition,
),
ast::NameLike::Name(name) => {
- highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name)
+ highlight_name(sema, bindings_shadow_count, &mut binding_hash, krate, name, edition)
}
ast::NameLike::Lifetime(lifetime) => match IdentClass::classify_lifetime(sema, &lifetime) {
Some(IdentClass::NameClass(NameClass::Definition(def))) => {
- highlight_def(sema, krate, def) | HlMod::Definition
+ highlight_def(sema, krate, def, edition) | HlMod::Definition
}
Some(IdentClass::NameRefClass(NameRefClass::Definition(def, _))) => {
- highlight_def(sema, krate, def)
+ highlight_def(sema, krate, def, edition)
}
// FIXME: Fallback for 'static and '_, as we do not resolve these yet
_ => SymbolKind::LifetimeParam.into(),
@@ -234,16 +236,17 @@ fn highlight_name_ref(
binding_hash: &mut Option,
syntactic_name_ref_highlighting: bool,
name_ref: ast::NameRef,
+ edition: Edition,
) -> Highlight {
let db = sema.db;
- if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref) {
+ if let Some(res) = highlight_method_call_by_name_ref(sema, krate, &name_ref, edition) {
return res;
}
let name_class = match NameRefClass::classify(sema, &name_ref) {
Some(name_kind) => name_kind,
None if syntactic_name_ref_highlighting => {
- return highlight_name_ref_by_syntax(name_ref, sema, krate)
+ return highlight_name_ref_by_syntax(name_ref, sema, krate, edition)
}
// FIXME: This is required for helper attributes used by proc-macros, as those do not map down
// to anything when used.
@@ -267,7 +270,7 @@ fn highlight_name_ref(
*binding_hash = Some(calc_binding_hash(&name, *shadow_count))
};
- let mut h = highlight_def(sema, krate, def);
+ let mut h = highlight_def(sema, krate, def, edition);
match def {
Definition::Local(local) if is_consumed_lvalue(name_ref.syntax(), &local, db) => {
@@ -305,7 +308,7 @@ fn highlight_name_ref(
h
}
NameRefClass::FieldShorthand { field_ref, .. } => {
- highlight_def(sema, krate, field_ref.into())
+ highlight_def(sema, krate, field_ref.into(), edition)
}
NameRefClass::ExternCrateShorthand { decl, krate: resolved_krate } => {
let mut h = HlTag::Symbol(SymbolKind::Module).into();
@@ -341,6 +344,7 @@ fn highlight_name(
binding_hash: &mut Option,
krate: hir::Crate,
name: ast::Name,
+ edition: Edition,
) -> Highlight {
let name_kind = NameClass::classify(sema, &name);
if let Some(NameClass::Definition(Definition::Local(local))) = &name_kind {
@@ -351,7 +355,7 @@ fn highlight_name(
};
match name_kind {
Some(NameClass::Definition(def)) => {
- let mut h = highlight_def(sema, krate, def) | HlMod::Definition;
+ let mut h = highlight_def(sema, krate, def, edition) | HlMod::Definition;
if let Definition::Trait(trait_) = &def {
if trait_.is_unsafe(sema.db) {
h |= HlMod::Unsafe;
@@ -359,7 +363,7 @@ fn highlight_name(
}
h
}
- Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def),
+ Some(NameClass::ConstReference(def)) => highlight_def(sema, krate, def, edition),
Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
let mut h = HlTag::Symbol(SymbolKind::Field).into();
if let hir::VariantDef::Union(_) = field_ref.parent_def(sema.db) {
@@ -379,6 +383,7 @@ pub(super) fn highlight_def(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
def: Definition,
+ edition: Edition,
) -> Highlight {
let db = sema.db;
let mut h = match def {
@@ -427,7 +432,12 @@ pub(super) fn highlight_def(
}
}
- if func.is_unsafe_to_call(db) {
+ // FIXME: Passing `None` here means not-unsafe functions with `#[target_feature]` will be
+ // highlighted as unsafe, even when the current target features set is a superset (RFC 2396).
+ // We probably should consider checking the current function, but I found no easy way to do
+ // that (also I'm worried about perf). There's also an instance below.
+ // FIXME: This should be the edition of the call.
+ if func.is_unsafe_to_call(db, None, edition) {
h |= HlMod::Unsafe;
}
if func.is_async(db) {
@@ -575,21 +585,23 @@ fn highlight_method_call_by_name_ref(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
name_ref: &ast::NameRef,
+ edition: Edition,
) -> Option {
let mc = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast)?;
- highlight_method_call(sema, krate, &mc)
+ highlight_method_call(sema, krate, &mc, edition)
}
fn highlight_method_call(
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
method_call: &ast::MethodCallExpr,
+ edition: Edition,
) -> Option {
let func = sema.resolve_method_call(method_call)?;
let mut h = SymbolKind::Method.into();
- if func.is_unsafe_to_call(sema.db) || sema.is_unsafe_method_call(method_call) {
+ if func.is_unsafe_to_call(sema.db, None, edition) || sema.is_unsafe_method_call(method_call) {
h |= HlMod::Unsafe;
}
if func.is_async(sema.db) {
@@ -665,6 +677,12 @@ fn highlight_name_by_syntax(name: ast::Name) -> Highlight {
STATIC => SymbolKind::Static,
IDENT_PAT => SymbolKind::Local,
FORMAT_ARGS_ARG => SymbolKind::Local,
+ RENAME => SymbolKind::Local,
+ MACRO_RULES => SymbolKind::Macro,
+ CONST_PARAM => SymbolKind::ConstParam,
+ SELF_PARAM => SymbolKind::SelfParam,
+ TRAIT_ALIAS => SymbolKind::TraitAlias,
+ ASM_OPERAND_NAMED => SymbolKind::Local,
_ => return default.into(),
};
@@ -675,6 +693,7 @@ fn highlight_name_ref_by_syntax(
name: ast::NameRef,
sema: &Semantics<'_, RootDatabase>,
krate: hir::Crate,
+ edition: Edition,
) -> Highlight {
let default = HlTag::UnresolvedReference;
@@ -685,7 +704,7 @@ fn highlight_name_ref_by_syntax(
match parent.kind() {
METHOD_CALL_EXPR => ast::MethodCallExpr::cast(parent)
- .and_then(|it| highlight_method_call(sema, krate, &it))
+ .and_then(|it| highlight_method_call(sema, krate, &it, edition))
.unwrap_or_else(|| SymbolKind::Method.into()),
FIELD_EXPR => {
let h = HlTag::Symbol(SymbolKind::Field);
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 0a7e273950da6..1794d7dbfe29e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -82,6 +82,10 @@
( $ literal: literal) = > { { stringify! ( $ literal) ; format_args! ( $ literal) } } ;
}
+use foo :: bar as baz ;
+trait Bar = Baz ;
+trait Foo = Bar ;
+
fn main ( ) {
let a = ' \n ' ;
let a = ' \t ' ;
diff --git a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
index af52b33de64bd..b9520ae2bba27 100644
--- a/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/tests.rs
@@ -466,6 +466,10 @@ macro_rules! reuse_twice {
($literal:literal) => {{stringify!($literal); format_args!($literal)}};
}
+use foo::bar as baz;
+trait Bar = Baz;
+trait Foo = Bar;
+
fn main() {
let a = '\n';
let a = '\t';
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing.rs b/src/tools/rust-analyzer/crates/ide/src/typing.rs
index 47d75f1c9570d..8c9dd05145272 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing.rs
@@ -51,16 +51,15 @@ struct ExtendedTextEdit {
// - typing `{` in a use item adds a closing `}` in the right place
// - typing `>` to complete a return type `->` will insert a whitespace after it
//
-// VS Code::
+// #### VS Code
//
// Add the following to `settings.json`:
-// [source,json]
-// ----
+// ```json
// "editor.formatOnType": true,
-// ----
+// ```
//
-// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[]
-// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[]
+// 
+// 
pub(crate) fn on_char_typed(
db: &RootDatabase,
position: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
index e249c38c73d62..c6d1c283f4eca 100644
--- a/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/typing/on_enter.rs
@@ -16,12 +16,12 @@ use ide_db::text_edit::TextEdit;
// Feature: On Enter
//
-// rust-analyzer can override kbd:[Enter] key to make it smarter:
+// rust-analyzer can override Enter key to make it smarter:
//
-// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
-// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
-// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
-// - kbd:[Enter] after `{` indents contents and closing `}` of single-line block
+// - Enter inside triple-slash comments automatically inserts `///`
+// - Enter in the middle or after a trailing space in `//` inserts `//`
+// - Enter inside `//!` doc comments automatically inserts `//!`
+// - Enter after `{` indents contents and closing `}` of single-line block
//
// This action needs to be assigned to shortcut explicitly.
//
@@ -29,29 +29,27 @@ use ide_db::text_edit::TextEdit;
// Similarly, if rust-analyzer crashes or stops responding, `Enter` might not work.
// In that case, you can still press `Shift-Enter` to insert a newline.
//
-// VS Code::
+// #### VS Code
//
// Add the following to `keybindings.json`:
-// [source,json]
-// ----
+// ```json
// {
// "key": "Enter",
// "command": "rust-analyzer.onEnter",
// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
// }
-// ----
+// ````
//
// When using the Vim plugin:
-// [source,json]
-// ----
+// ```json
// {
// "key": "Enter",
// "command": "rust-analyzer.onEnter",
// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust && vim.mode == 'Insert'"
// }
-// ----
+// ````
//
-// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
+// 
pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option {
let parse = db.parse(EditionedFileId::current_edition(position.file_id));
let file = parse.tree();
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
index 9ff099f479e7b..eb6eb7da1e90a 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_crate_graph.rs
@@ -12,11 +12,9 @@ use triomphe::Arc;
//
// Only workspace crates are included, no crates.io dependencies or sysroot crates.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: View Crate Graph**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: View Crate Graph** |
pub(crate) fn view_crate_graph(db: &RootDatabase, full: bool) -> Result {
let crate_graph = db.crate_graph();
let crates_to_render = crate_graph
@@ -86,7 +84,8 @@ impl<'a> dot::Labeller<'a, CrateId, Edge<'a>> for DotCrateGraph {
}
fn node_label(&'a self, n: &CrateId) -> LabelText<'a> {
- let name = self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| name);
+ let name =
+ self.graph[*n].display_name.as_ref().map_or("(unnamed crate)", |name| name.as_str());
LabelText::LabelStr(name.into())
}
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
index fe532f4cc55ee..bfdf9d0f3374e 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_hir.rs
@@ -4,12 +4,11 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode};
// Feature: View Hir
//
-// |===
-// | Editor | Action Name
-//
+// | Editor | Action Name |
+// |---------|--------------|
// | VS Code | **rust-analyzer: View Hir**
-// |===
-// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
+//
+// 
pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
index a6352b99d4f52..67c241cbb9153 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_item_tree.rs
@@ -6,11 +6,9 @@ use span::EditionedFileId;
//
// Displays the ItemTree of the currently open file, for debugging.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: Debug ItemTree**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: Debug ItemTree** |
pub(crate) fn view_item_tree(db: &RootDatabase, file_id: FileId) -> String {
let sema = Semantics::new(db);
let file_id = sema
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
index ff74e05e9437c..edb83bc4eac4c 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_memory_layout.rs
@@ -75,11 +75,9 @@ impl FieldOrTupleIdx {
//
// Displays the recursive memory layout of a datatype.
//
-// |===
-// | Editor | Action Name
-//
-// | VS Code | **rust-analyzer: View Memory Layout**
-// |===
+// | Editor | Action Name |
+// |---------|-------------|
+// | VS Code | **rust-analyzer: View Memory Layout** |
pub(crate) fn view_memory_layout(
db: &RootDatabase,
position: FilePosition,
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
index 7a228375d5e97..aa4ff64a819e1 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_mir.rs
@@ -4,11 +4,9 @@ use syntax::{algo::ancestors_at_offset, ast, AstNode};
// Feature: View Mir
//
-// |===
-// | Editor | Action Name
-//
+// | Editor | Action Name |
+// |---------|-------------|
// | VS Code | **rust-analyzer: View Mir**
-// |===
pub(crate) fn view_mir(db: &RootDatabase, position: FilePosition) -> String {
body_mir(db, position).unwrap_or_else(|| "Not inside a function body".to_owned())
}
diff --git a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
index 218ee15a7dd32..407720864bfdb 100644
--- a/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/view_syntax_tree.rs
@@ -1,41 +1,50 @@
use hir::Semantics;
-use ide_db::{FileId, RootDatabase};
-use span::TextRange;
+use ide_db::{
+ line_index::{LineCol, LineIndex},
+ FileId, LineIndexDatabase, RootDatabase,
+};
+use span::{TextRange, TextSize};
use stdx::format_to;
use syntax::{
ast::{self, IsString},
AstNode, AstToken, NodeOrToken, SourceFile, SyntaxNode, SyntaxToken, WalkEvent,
};
+use triomphe::Arc;
// Feature: Show Syntax Tree
//
// Shows a tree view with the syntax tree of the current file
//
-// |===
-// | Editor | Panel Name
-//
-// | VS Code | **Rust Syntax Tree**
-// |===
+// | Editor | Panel Name |
+// |---------|-------------|
+// | VS Code | **Rust Syntax Tree** |
pub(crate) fn view_syntax_tree(db: &RootDatabase, file_id: FileId) -> String {
let sema = Semantics::new(db);
+ let line_index = db.line_index(file_id);
let parse = sema.parse_guess_edition(file_id);
- syntax_node_to_json(parse.syntax(), None)
+
+ let ctx = SyntaxTreeCtx { line_index, in_string: None };
+
+ syntax_node_to_json(parse.syntax(), &ctx)
}
-fn syntax_node_to_json(node: &SyntaxNode, ctx: Option) -> String {
+fn syntax_node_to_json(node: &SyntaxNode, ctx: &SyntaxTreeCtx) -> String {
let mut result = String::new();
for event in node.preorder_with_tokens() {
match event {
WalkEvent::Enter(it) => {
let kind = it.kind();
- let (text_range, inner_range_str) = match &ctx {
- Some(ctx) => {
+ let (text_range, inner_range_str) = match &ctx.in_string {
+ Some(in_string) => {
+ let start_pos = TextPosition::new(&ctx.line_index, it.text_range().start());
+ let end_pos = TextPosition::new(&ctx.line_index, it.text_range().end());
+
let inner_start: u32 = it.text_range().start().into();
- let inner_end: u32 = it.text_range().end().into();
+ let inner_end: u32 = it.text_range().start().into();
- let mut true_start = inner_start + ctx.offset;
- let mut true_end = inner_end + ctx.offset;
- for pos in &ctx.marker_positions {
+ let mut true_start = inner_start + in_string.offset;
+ let mut true_end = inner_end + in_string.offset;
+ for pos in &in_string.marker_positions {
if *pos >= inner_end {
break;
}
@@ -48,39 +57,33 @@ fn syntax_node_to_json(node: &SyntaxNode, ctx: Option) -> String {
let true_range = TextRange::new(true_start.into(), true_end.into());
- (
- true_range,
- format!(
- r#","istart":{:?},"iend":{:?}"#,
- it.text_range().start(),
- it.text_range().end()
- ),
- )
+ (true_range, format!(r#","istart":{start_pos},"iend":{end_pos}"#,))
}
None => (it.text_range(), "".to_owned()),
};
- let start = text_range.start();
- let end = text_range.end();
+
+ let start = TextPosition::new(&ctx.line_index, text_range.start());
+ let end = TextPosition::new(&ctx.line_index, text_range.end());
match it {
NodeOrToken::Node(_) => {
format_to!(
result,
- r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":["#
+ r#"{{"type":"Node","kind":"{kind:?}","start":{start},"end":{end}{inner_range_str},"children":["#
);
}
NodeOrToken::Token(token) => {
let comma = if token.next_sibling_or_token().is_some() { "," } else { "" };
- match parse_rust_string(token) {
+ match parse_rust_string(token, ctx) {
Some(parsed) => {
format_to!(
result,
- r#"{{"type":"Node","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str},"children":[{parsed}]}}{comma}"#
+ r#"{{"type":"Node","kind":"{kind:?}","start":{start},"end":{end}{inner_range_str},"children":[{parsed}]}}{comma}"#
);
}
None => format_to!(
result,
- r#"{{"type":"Token","kind":"{kind:?}","start":{start:?},"end":{end:?}{inner_range_str}}}{comma}"#
+ r#"{{"type":"Token","kind":"{kind:?}","start":{start},"end":{end}{inner_range_str}}}{comma}"#
),
}
}
@@ -99,7 +102,26 @@ fn syntax_node_to_json(node: &SyntaxNode, ctx: Option) -> String {
result
}
-fn parse_rust_string(token: SyntaxToken) -> Option {
+struct TextPosition {
+ offset: TextSize,
+ line: u32,
+ col: u32,
+}
+
+impl std::fmt::Display for TextPosition {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ write!(f, "[{:?},{},{}]", self.offset, self.line, self.col)
+ }
+}
+
+impl TextPosition {
+ pub(crate) fn new(line_index: &LineIndex, offset: TextSize) -> Self {
+ let LineCol { line, col } = line_index.line_col(offset);
+ Self { offset, line, col }
+ }
+}
+
+fn parse_rust_string(token: SyntaxToken, ctx: &SyntaxTreeCtx) -> Option {
let string_node = ast::String::cast(token)?;
let text = string_node.value().ok()?;
@@ -128,13 +150,20 @@ fn parse_rust_string(token: SyntaxToken) -> Option {
return None;
}
- Some(syntax_node_to_json(
- node,
- Some(InStringCtx {
+ let ctx = SyntaxTreeCtx {
+ line_index: ctx.line_index.clone(),
+ in_string: Some(InStringCtx {
offset: string_node.text_range_between_quotes()?.start().into(),
marker_positions,
}),
- ))
+ };
+
+ Some(syntax_node_to_json(node, &ctx))
+}
+
+struct SyntaxTreeCtx {
+ line_index: Arc,
+ in_string: Option,
}
struct InStringCtx {
@@ -160,7 +189,7 @@ mod tests {
check(
r#"fn foo() {}"#,
expect![[
- r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":11,"children":[{"type":"Node","kind":"FN","start":0,"end":11,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":6,"children":[{"type":"Token","kind":"IDENT","start":3,"end":6}]},{"type":"Node","kind":"PARAM_LIST","start":6,"end":8,"children":[{"type":"Token","kind":"L_PAREN","start":6,"end":7},{"type":"Token","kind":"R_PAREN","start":7,"end":8}]},{"type":"Token","kind":"WHITESPACE","start":8,"end":9},{"type":"Node","kind":"BLOCK_EXPR","start":9,"end":11,"children":[{"type":"Node","kind":"STMT_LIST","start":9,"end":11,"children":[{"type":"Token","kind":"L_CURLY","start":9,"end":10},{"type":"Token","kind":"R_CURLY","start":10,"end":11}]}]}]}]}"#
+ r#"{"type":"Node","kind":"SOURCE_FILE","start":[0,0,0],"end":[11,0,11],"children":[{"type":"Node","kind":"FN","start":[0,0,0],"end":[11,0,11],"children":[{"type":"Token","kind":"FN_KW","start":[0,0,0],"end":[2,0,2]},{"type":"Token","kind":"WHITESPACE","start":[2,0,2],"end":[3,0,3]},{"type":"Node","kind":"NAME","start":[3,0,3],"end":[6,0,6],"children":[{"type":"Token","kind":"IDENT","start":[3,0,3],"end":[6,0,6]}]},{"type":"Node","kind":"PARAM_LIST","start":[6,0,6],"end":[8,0,8],"children":[{"type":"Token","kind":"L_PAREN","start":[6,0,6],"end":[7,0,7]},{"type":"Token","kind":"R_PAREN","start":[7,0,7],"end":[8,0,8]}]},{"type":"Token","kind":"WHITESPACE","start":[8,0,8],"end":[9,0,9]},{"type":"Node","kind":"BLOCK_EXPR","start":[9,0,9],"end":[11,0,11],"children":[{"type":"Node","kind":"STMT_LIST","start":[9,0,9],"end":[11,0,11],"children":[{"type":"Token","kind":"L_CURLY","start":[9,0,9],"end":[10,0,10]},{"type":"Token","kind":"R_CURLY","start":[10,0,10],"end":[11,0,11]}]}]}]}]}"#
]],
);
@@ -173,7 +202,7 @@ fn test() {
", "");
}"#,
expect![[
- r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":60,"children":[{"type":"Node","kind":"FN","start":0,"end":60,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":60,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":60,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":58,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":57,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":57,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":57,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":52,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":51,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":30,"istart":0,"iend":5},{"type":"Node","kind":"FN","start":30,"end":46,"istart":5,"iend":21,"children":[{"type":"Token","kind":"FN_KW","start":30,"end":32,"istart":5,"iend":7},{"type":"Token","kind":"WHITESPACE","start":32,"end":33,"istart":7,"iend":8},{"type":"Node","kind":"NAME","start":33,"end":36,"istart":8,"iend":11,"children":[{"type":"Token","kind":"IDENT","start":33,"end":36,"istart":8,"iend":11}]},{"type":"Node","kind":"PARAM_LIST","start":36,"end":38,"istart":11,"iend":13,"children":[{"type":"Token","kind":"L_PAREN","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_PAREN","start":37,"end":38,"istart":12,"iend":13}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"BLOCK_EXPR","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Node","kind":"STMT_LIST","start":39,"end":46,"istart":14,"iend":21,"children":[{"type":"Token","kind":"L_CURLY","start":39,"end":40,"istart":14,"iend":15},{"type":"Token","kind":"WHITESPACE","start":40,"end":45,"istart":15,"iend":20},{"type":"Token","kind":"R_CURLY","start":45,"end":46,"istart":20,"iend":21}]}]}]},{"type":"Token","kind":"WHITESPACE","start":46,"end":51,"istart":21,"iend":26}]}]},{"type":"Token","kind":"COMMA","start":52,"end":53},{"type":"Token","kind":"WHITESPACE","start":53,"end":54},{"type":"Token","kind":"STRING","start":54,"end":56},{"type":"Token","kind":"R_PAREN","start":56,"end":57}]}]}]},{"type":"Token","kind":"SEMICOLON","start":57,"end":58}]},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"R_CURLY","start":59,"end":60}]}]}]}]}"#
+ r#"{"type":"Node","kind":"SOURCE_FILE","start":[0,0,0],"end":[60,5,1],"children":[{"type":"Node","kind":"FN","start":[0,0,0],"end":[60,5,1],"children":[{"type":"Token","kind":"FN_KW","start":[0,0,0],"end":[2,0,2]},{"type":"Token","kind":"WHITESPACE","start":[2,0,2],"end":[3,0,3]},{"type":"Node","kind":"NAME","start":[3,0,3],"end":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[3,0,3],"end":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[7,0,7],"end":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[7,0,7],"end":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[8,0,8],"end":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[9,0,9],"end":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[10,0,10],"end":[60,5,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[10,0,10],"end":[60,5,1],"children":[{"type":"Token","kind":"L_CURLY","start":[10,0,10],"end":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[11,0,11],"end":[16,1,4]},{"type":"Node","kind":"EXPR_STMT","start":[16,1,4],"end":[58,4,11],"children":[{"type":"Node","kind":"MACRO_EXPR","start":[16,1,4],"end":[57,4,10],"children":[{"type":"Node","kind":"MACRO_CALL","start":[16,1,4],"end":[57,4,10],"children":[{"type":"Node","kind":"PATH","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"PATH_SEGMENT","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"NAME_REF","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Token","kind":"IDENT","start":[16,1,4],"end":[22,1,10]}]}]}]},{"type":"Token","kind":"BANG","start":[22,1,10],"end":[23,1,11]},{"type":"Node","kind":"TOKEN_TREE","start":[23,1,11],"end":[57,4,10],"children":[{"type":"Token","kind":"L_PAREN","start":[23,1,11],"end":[24,1,12]},{"type":"Node","kind":"STRING","start":[24,1,12],"end":[52,4,5],"children":[{"type":"Node","kind":"SOURCE_FILE","start":[25,1,13],"end":[25,1,13],"istart":[0,0,0],"iend":[26,2,0],"children":[{"type":"Token","kind":"WHITESPACE","start":[25,1,13],"end":[25,1,13],"istart":[0,0,0],"iend":[5,0,5]},{"type":"Node","kind":"FN","start":[30,2,4],"end":[30,2,4],"istart":[5,0,5],"iend":[21,1,9],"children":[{"type":"Token","kind":"FN_KW","start":[30,2,4],"end":[30,2,4],"istart":[5,0,5],"iend":[7,0,7]},{"type":"Token","kind":"WHITESPACE","start":[32,2,6],"end":[32,2,6],"istart":[7,0,7],"iend":[8,0,8]},{"type":"Node","kind":"NAME","start":[33,2,7],"end":[33,2,7],"istart":[8,0,8],"iend":[11,0,11],"children":[{"type":"Token","kind":"IDENT","start":[33,2,7],"end":[33,2,7],"istart":[8,0,8],"iend":[11,0,11]}]},{"type":"Node","kind":"PARAM_LIST","start":[36,2,10],"end":[36,2,10],"istart":[11,0,11],"iend":[13,1,1],"children":[{"type":"Token","kind":"L_PAREN","start":[36,2,10],"end":[36,2,10],"istart":[11,0,11],"iend":[12,1,0]},{"type":"Token","kind":"R_PAREN","start":[37,2,11],"end":[37,2,11],"istart":[12,1,0],"iend":[13,1,1]}]},{"type":"Token","kind":"WHITESPACE","start":[38,2,12],"end":[38,2,12],"istart":[13,1,1],"iend":[14,1,2]},{"type":"Node","kind":"BLOCK_EXPR","start":[39,2,13],"end":[39,2,13],"istart":[14,1,2],"iend":[21,1,9],"children":[{"type":"Node","kind":"STMT_LIST","start":[39,2,13],"end":[39,2,13],"istart":[14,1,2],"iend":[21,1,9],"children":[{"type":"Token","kind":"L_CURLY","start":[39,2,13],"end":[39,2,13],"istart":[14,1,2],"iend":[15,1,3]},{"type":"Token","kind":"WHITESPACE","start":[40,2,14],"end":[40,2,14],"istart":[15,1,3],"iend":[20,1,8]},{"type":"Token","kind":"R_CURLY","start":[45,3,4],"end":[45,3,4],"istart":[20,1,8],"iend":[21,1,9]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[46,3,5],"end":[46,3,5],"istart":[21,1,9],"iend":[26,2,0]}]}]},{"type":"Token","kind":"COMMA","start":[52,4,5],"end":[53,4,6]},{"type":"Token","kind":"WHITESPACE","start":[53,4,6],"end":[54,4,7]},{"type":"Token","kind":"STRING","start":[54,4,7],"end":[56,4,9]},{"type":"Token","kind":"R_PAREN","start":[56,4,9],"end":[57,4,10]}]}]}]},{"type":"Token","kind":"SEMICOLON","start":[57,4,10],"end":[58,4,11]}]},{"type":"Token","kind":"WHITESPACE","start":[58,4,11],"end":[59,5,0]},{"type":"Token","kind":"R_CURLY","start":[59,5,0],"end":[60,5,1]}]}]}]}]}"#
]],
)
}
@@ -190,7 +219,7 @@ fn bar() {
", "");
}"#,
expect![[
- r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":65,"children":[{"type":"Node","kind":"FN","start":0,"end":65,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":65,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":65,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":63,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":62,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":62,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":62,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":57,"children":[{"type":"Node","kind":"SOURCE_FILE","start":25,"end":56,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":25,"end":26,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":26,"end":38,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":26,"end":28,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":28,"end":29,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":29,"end":32,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":29,"end":32,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":32,"end":34,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":32,"end":33,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":33,"end":34,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":34,"end":35,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":35,"end":38,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":35,"end":36,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":37,"end":38,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":39,"end":51,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":39,"end":41,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":41,"end":42,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":42,"end":45,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":42,"end":45,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":45,"end":47,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":45,"end":46,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":46,"end":47,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":47,"end":48,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":48,"end":51,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":48,"end":49,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":50,"end":51,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":51,"end":56,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":57,"end":58},{"type":"Token","kind":"WHITESPACE","start":58,"end":59},{"type":"Token","kind":"STRING","start":59,"end":61},{"type":"Token","kind":"R_PAREN","start":61,"end":62}]}]}]},{"type":"Token","kind":"SEMICOLON","start":62,"end":63}]},{"type":"Token","kind":"WHITESPACE","start":63,"end":64},{"type":"Token","kind":"R_CURLY","start":64,"end":65}]}]}]}]}"#
+ r#"{"type":"Node","kind":"SOURCE_FILE","start":[0,0,0],"end":[65,7,1],"children":[{"type":"Node","kind":"FN","start":[0,0,0],"end":[65,7,1],"children":[{"type":"Token","kind":"FN_KW","start":[0,0,0],"end":[2,0,2]},{"type":"Token","kind":"WHITESPACE","start":[2,0,2],"end":[3,0,3]},{"type":"Node","kind":"NAME","start":[3,0,3],"end":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[3,0,3],"end":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[7,0,7],"end":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[7,0,7],"end":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[8,0,8],"end":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[9,0,9],"end":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[10,0,10],"end":[65,7,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[10,0,10],"end":[65,7,1],"children":[{"type":"Token","kind":"L_CURLY","start":[10,0,10],"end":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[11,0,11],"end":[16,1,4]},{"type":"Node","kind":"EXPR_STMT","start":[16,1,4],"end":[63,6,11],"children":[{"type":"Node","kind":"MACRO_EXPR","start":[16,1,4],"end":[62,6,10],"children":[{"type":"Node","kind":"MACRO_CALL","start":[16,1,4],"end":[62,6,10],"children":[{"type":"Node","kind":"PATH","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"PATH_SEGMENT","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"NAME_REF","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Token","kind":"IDENT","start":[16,1,4],"end":[22,1,10]}]}]}]},{"type":"Token","kind":"BANG","start":[22,1,10],"end":[23,1,11]},{"type":"Node","kind":"TOKEN_TREE","start":[23,1,11],"end":[62,6,10],"children":[{"type":"Token","kind":"L_PAREN","start":[23,1,11],"end":[24,1,12]},{"type":"Node","kind":"STRING","start":[24,1,12],"end":[57,6,5],"children":[{"type":"Node","kind":"SOURCE_FILE","start":[25,1,13],"end":[25,1,13],"istart":[0,0,0],"iend":[31,2,5],"children":[{"type":"Token","kind":"WHITESPACE","start":[25,1,13],"end":[25,1,13],"istart":[0,0,0],"iend":[1,0,1]},{"type":"Node","kind":"FN","start":[26,2,0],"end":[26,2,0],"istart":[1,0,1],"iend":[13,1,1],"children":[{"type":"Token","kind":"FN_KW","start":[26,2,0],"end":[26,2,0],"istart":[1,0,1],"iend":[3,0,3]},{"type":"Token","kind":"WHITESPACE","start":[28,2,2],"end":[28,2,2],"istart":[3,0,3],"iend":[4,0,4]},{"type":"Node","kind":"NAME","start":[29,2,3],"end":[29,2,3],"istart":[4,0,4],"iend":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[29,2,3],"end":[29,2,3],"istart":[4,0,4],"iend":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[32,2,6],"end":[32,2,6],"istart":[7,0,7],"iend":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[32,2,6],"end":[32,2,6],"istart":[7,0,7],"iend":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[33,2,7],"end":[33,2,7],"istart":[8,0,8],"iend":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[34,2,8],"end":[34,2,8],"istart":[9,0,9],"iend":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[35,2,9],"end":[35,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[35,2,9],"end":[35,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Token","kind":"L_CURLY","start":[35,2,9],"end":[35,2,9],"istart":[10,0,10],"iend":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[36,2,10],"end":[36,2,10],"istart":[11,0,11],"iend":[12,1,0]},{"type":"Token","kind":"R_CURLY","start":[37,3,0],"end":[37,3,0],"istart":[12,1,0],"iend":[13,1,1]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[38,3,1],"end":[38,3,1],"istart":[13,1,1],"iend":[14,1,2]},{"type":"Node","kind":"FN","start":[39,4,0],"end":[39,4,0],"istart":[14,1,2],"iend":[26,2,0],"children":[{"type":"Token","kind":"FN_KW","start":[39,4,0],"end":[39,4,0],"istart":[14,1,2],"iend":[16,1,4]},{"type":"Token","kind":"WHITESPACE","start":[41,4,2],"end":[41,4,2],"istart":[16,1,4],"iend":[17,1,5]},{"type":"Node","kind":"NAME","start":[42,4,3],"end":[42,4,3],"istart":[17,1,5],"iend":[20,1,8],"children":[{"type":"Token","kind":"IDENT","start":[42,4,3],"end":[42,4,3],"istart":[17,1,5],"iend":[20,1,8]}]},{"type":"Node","kind":"PARAM_LIST","start":[45,4,6],"end":[45,4,6],"istart":[20,1,8],"iend":[22,1,10],"children":[{"type":"Token","kind":"L_PAREN","start":[45,4,6],"end":[45,4,6],"istart":[20,1,8],"iend":[21,1,9]},{"type":"Token","kind":"R_PAREN","start":[46,4,7],"end":[46,4,7],"istart":[21,1,9],"iend":[22,1,10]}]},{"type":"Token","kind":"WHITESPACE","start":[47,4,8],"end":[47,4,8],"istart":[22,1,10],"iend":[23,1,11]},{"type":"Node","kind":"BLOCK_EXPR","start":[48,4,9],"end":[48,4,9],"istart":[23,1,11],"iend":[26,2,0],"children":[{"type":"Node","kind":"STMT_LIST","start":[48,4,9],"end":[48,4,9],"istart":[23,1,11],"iend":[26,2,0],"children":[{"type":"Token","kind":"L_CURLY","start":[48,4,9],"end":[48,4,9],"istart":[23,1,11],"iend":[24,1,12]},{"type":"Token","kind":"WHITESPACE","start":[49,4,10],"end":[49,4,10],"istart":[24,1,12],"iend":[25,1,13]},{"type":"Token","kind":"R_CURLY","start":[50,5,0],"end":[50,5,0],"istart":[25,1,13],"iend":[26,2,0]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[51,5,1],"end":[51,5,1],"istart":[26,2,0],"iend":[31,2,5]}]}]},{"type":"Token","kind":"COMMA","start":[57,6,5],"end":[58,6,6]},{"type":"Token","kind":"WHITESPACE","start":[58,6,6],"end":[59,6,7]},{"type":"Token","kind":"STRING","start":[59,6,7],"end":[61,6,9]},{"type":"Token","kind":"R_PAREN","start":[61,6,9],"end":[62,6,10]}]}]}]},{"type":"Token","kind":"SEMICOLON","start":[62,6,10],"end":[63,6,11]}]},{"type":"Token","kind":"WHITESPACE","start":[63,6,11],"end":[64,7,0]},{"type":"Token","kind":"R_CURLY","start":[64,7,0],"end":[65,7,1]}]}]}]}]}"#
]],
);
@@ -205,7 +234,7 @@ fn bar() {
"#, "");
}"###,
expect![[
- r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":68,"children":[{"type":"Node","kind":"FN","start":0,"end":68,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":68,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":68,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":66,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":65,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":65,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":65,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":60,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":58,"istart":0,"iend":31,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]},{"type":"Token","kind":"WHITESPACE","start":53,"end":58,"istart":26,"iend":31}]}]},{"type":"Token","kind":"COMMA","start":60,"end":61},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"STRING","start":62,"end":64},{"type":"Token","kind":"R_PAREN","start":64,"end":65}]}]}]},{"type":"Token","kind":"SEMICOLON","start":65,"end":66}]},{"type":"Token","kind":"WHITESPACE","start":66,"end":67},{"type":"Token","kind":"R_CURLY","start":67,"end":68}]}]}]}]}"#
+ r#"{"type":"Node","kind":"SOURCE_FILE","start":[0,0,0],"end":[68,7,1],"children":[{"type":"Node","kind":"FN","start":[0,0,0],"end":[68,7,1],"children":[{"type":"Token","kind":"FN_KW","start":[0,0,0],"end":[2,0,2]},{"type":"Token","kind":"WHITESPACE","start":[2,0,2],"end":[3,0,3]},{"type":"Node","kind":"NAME","start":[3,0,3],"end":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[3,0,3],"end":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[7,0,7],"end":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[7,0,7],"end":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[8,0,8],"end":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[9,0,9],"end":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[10,0,10],"end":[68,7,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[10,0,10],"end":[68,7,1],"children":[{"type":"Token","kind":"L_CURLY","start":[10,0,10],"end":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[11,0,11],"end":[16,1,4]},{"type":"Node","kind":"EXPR_STMT","start":[16,1,4],"end":[66,6,12],"children":[{"type":"Node","kind":"MACRO_EXPR","start":[16,1,4],"end":[65,6,11],"children":[{"type":"Node","kind":"MACRO_CALL","start":[16,1,4],"end":[65,6,11],"children":[{"type":"Node","kind":"PATH","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"PATH_SEGMENT","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"NAME_REF","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Token","kind":"IDENT","start":[16,1,4],"end":[22,1,10]}]}]}]},{"type":"Token","kind":"BANG","start":[22,1,10],"end":[23,1,11]},{"type":"Node","kind":"TOKEN_TREE","start":[23,1,11],"end":[65,6,11],"children":[{"type":"Token","kind":"L_PAREN","start":[23,1,11],"end":[24,1,12]},{"type":"Node","kind":"STRING","start":[24,1,12],"end":[60,6,6],"children":[{"type":"Node","kind":"SOURCE_FILE","start":[27,1,15],"end":[27,1,15],"istart":[0,0,0],"iend":[31,2,3],"children":[{"type":"Token","kind":"WHITESPACE","start":[27,1,15],"end":[27,1,15],"istart":[0,0,0],"iend":[1,0,1]},{"type":"Node","kind":"FN","start":[28,2,0],"end":[28,2,0],"istart":[1,0,1],"iend":[13,1,1],"children":[{"type":"Token","kind":"FN_KW","start":[28,2,0],"end":[28,2,0],"istart":[1,0,1],"iend":[3,0,3]},{"type":"Token","kind":"WHITESPACE","start":[30,2,2],"end":[30,2,2],"istart":[3,0,3],"iend":[4,0,4]},{"type":"Node","kind":"NAME","start":[31,2,3],"end":[31,2,3],"istart":[4,0,4],"iend":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[31,2,3],"end":[31,2,3],"istart":[4,0,4],"iend":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[34,2,6],"end":[34,2,6],"istart":[7,0,7],"iend":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[34,2,6],"end":[34,2,6],"istart":[7,0,7],"iend":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[35,2,7],"end":[35,2,7],"istart":[8,0,8],"iend":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[36,2,8],"end":[36,2,8],"istart":[9,0,9],"iend":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Token","kind":"L_CURLY","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[38,2,10],"end":[38,2,10],"istart":[11,0,11],"iend":[12,1,0]},{"type":"Token","kind":"R_CURLY","start":[39,3,0],"end":[39,3,0],"istart":[12,1,0],"iend":[13,1,1]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[40,3,1],"end":[40,3,1],"istart":[13,1,1],"iend":[14,1,2]},{"type":"Node","kind":"FN","start":[41,4,0],"end":[41,4,0],"istart":[14,1,2],"iend":[26,1,14],"children":[{"type":"Token","kind":"FN_KW","start":[41,4,0],"end":[41,4,0],"istart":[14,1,2],"iend":[16,1,4]},{"type":"Token","kind":"WHITESPACE","start":[43,4,2],"end":[43,4,2],"istart":[16,1,4],"iend":[17,1,5]},{"type":"Node","kind":"NAME","start":[44,4,3],"end":[44,4,3],"istart":[17,1,5],"iend":[20,1,8],"children":[{"type":"Token","kind":"IDENT","start":[44,4,3],"end":[44,4,3],"istart":[17,1,5],"iend":[20,1,8]}]},{"type":"Node","kind":"PARAM_LIST","start":[47,4,6],"end":[47,4,6],"istart":[20,1,8],"iend":[22,1,10],"children":[{"type":"Token","kind":"L_PAREN","start":[47,4,6],"end":[47,4,6],"istart":[20,1,8],"iend":[21,1,9]},{"type":"Token","kind":"R_PAREN","start":[48,4,7],"end":[48,4,7],"istart":[21,1,9],"iend":[22,1,10]}]},{"type":"Token","kind":"WHITESPACE","start":[49,4,8],"end":[49,4,8],"istart":[22,1,10],"iend":[23,1,11]},{"type":"Node","kind":"BLOCK_EXPR","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[26,1,14],"children":[{"type":"Node","kind":"STMT_LIST","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[26,1,14],"children":[{"type":"Token","kind":"L_CURLY","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[24,1,12]},{"type":"Token","kind":"WHITESPACE","start":[51,4,10],"end":[51,4,10],"istart":[24,1,12],"iend":[25,1,13]},{"type":"Token","kind":"R_CURLY","start":[52,5,0],"end":[52,5,0],"istart":[25,1,13],"iend":[26,1,14]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[53,5,1],"end":[53,5,1],"istart":[26,1,14],"iend":[31,2,3]}]}]},{"type":"Token","kind":"COMMA","start":[60,6,6],"end":[61,6,7]},{"type":"Token","kind":"WHITESPACE","start":[61,6,7],"end":[62,6,8]},{"type":"Token","kind":"STRING","start":[62,6,8],"end":[64,6,10]},{"type":"Token","kind":"R_PAREN","start":[64,6,10],"end":[65,6,11]}]}]}]},{"type":"Token","kind":"SEMICOLON","start":[65,6,11],"end":[66,6,12]}]},{"type":"Token","kind":"WHITESPACE","start":[66,6,12],"end":[67,7,0]},{"type":"Token","kind":"R_CURLY","start":[67,7,0],"end":[68,7,1]}]}]}]}]}"#
]],
);
@@ -219,7 +248,7 @@ fn bar() {
}"$0#, "");
}"###,
expect![[
- r#"{"type":"Node","kind":"SOURCE_FILE","start":0,"end":63,"children":[{"type":"Node","kind":"FN","start":0,"end":63,"children":[{"type":"Token","kind":"FN_KW","start":0,"end":2},{"type":"Token","kind":"WHITESPACE","start":2,"end":3},{"type":"Node","kind":"NAME","start":3,"end":7,"children":[{"type":"Token","kind":"IDENT","start":3,"end":7}]},{"type":"Node","kind":"PARAM_LIST","start":7,"end":9,"children":[{"type":"Token","kind":"L_PAREN","start":7,"end":8},{"type":"Token","kind":"R_PAREN","start":8,"end":9}]},{"type":"Token","kind":"WHITESPACE","start":9,"end":10},{"type":"Node","kind":"BLOCK_EXPR","start":10,"end":63,"children":[{"type":"Node","kind":"STMT_LIST","start":10,"end":63,"children":[{"type":"Token","kind":"L_CURLY","start":10,"end":11},{"type":"Token","kind":"WHITESPACE","start":11,"end":16},{"type":"Node","kind":"EXPR_STMT","start":16,"end":61,"children":[{"type":"Node","kind":"MACRO_EXPR","start":16,"end":60,"children":[{"type":"Node","kind":"MACRO_CALL","start":16,"end":60,"children":[{"type":"Node","kind":"PATH","start":16,"end":22,"children":[{"type":"Node","kind":"PATH_SEGMENT","start":16,"end":22,"children":[{"type":"Node","kind":"NAME_REF","start":16,"end":22,"children":[{"type":"Token","kind":"IDENT","start":16,"end":22}]}]}]},{"type":"Token","kind":"BANG","start":22,"end":23},{"type":"Node","kind":"TOKEN_TREE","start":23,"end":60,"children":[{"type":"Token","kind":"L_PAREN","start":23,"end":24},{"type":"Node","kind":"STRING","start":24,"end":55,"children":[{"type":"Node","kind":"SOURCE_FILE","start":27,"end":53,"istart":0,"iend":26,"children":[{"type":"Token","kind":"WHITESPACE","start":27,"end":28,"istart":0,"iend":1},{"type":"Node","kind":"FN","start":28,"end":40,"istart":1,"iend":13,"children":[{"type":"Token","kind":"FN_KW","start":28,"end":30,"istart":1,"iend":3},{"type":"Token","kind":"WHITESPACE","start":30,"end":31,"istart":3,"iend":4},{"type":"Node","kind":"NAME","start":31,"end":34,"istart":4,"iend":7,"children":[{"type":"Token","kind":"IDENT","start":31,"end":34,"istart":4,"iend":7}]},{"type":"Node","kind":"PARAM_LIST","start":34,"end":36,"istart":7,"iend":9,"children":[{"type":"Token","kind":"L_PAREN","start":34,"end":35,"istart":7,"iend":8},{"type":"Token","kind":"R_PAREN","start":35,"end":36,"istart":8,"iend":9}]},{"type":"Token","kind":"WHITESPACE","start":36,"end":37,"istart":9,"iend":10},{"type":"Node","kind":"BLOCK_EXPR","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Node","kind":"STMT_LIST","start":37,"end":40,"istart":10,"iend":13,"children":[{"type":"Token","kind":"L_CURLY","start":37,"end":38,"istart":10,"iend":11},{"type":"Token","kind":"WHITESPACE","start":38,"end":39,"istart":11,"iend":12},{"type":"Token","kind":"R_CURLY","start":39,"end":40,"istart":12,"iend":13}]}]}]},{"type":"Token","kind":"WHITESPACE","start":40,"end":41,"istart":13,"iend":14},{"type":"Node","kind":"FN","start":41,"end":53,"istart":14,"iend":26,"children":[{"type":"Token","kind":"FN_KW","start":41,"end":43,"istart":14,"iend":16},{"type":"Token","kind":"WHITESPACE","start":43,"end":44,"istart":16,"iend":17},{"type":"Node","kind":"NAME","start":44,"end":47,"istart":17,"iend":20,"children":[{"type":"Token","kind":"IDENT","start":44,"end":47,"istart":17,"iend":20}]},{"type":"Node","kind":"PARAM_LIST","start":47,"end":49,"istart":20,"iend":22,"children":[{"type":"Token","kind":"L_PAREN","start":47,"end":48,"istart":20,"iend":21},{"type":"Token","kind":"R_PAREN","start":48,"end":49,"istart":21,"iend":22}]},{"type":"Token","kind":"WHITESPACE","start":49,"end":50,"istart":22,"iend":23},{"type":"Node","kind":"BLOCK_EXPR","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Node","kind":"STMT_LIST","start":50,"end":53,"istart":23,"iend":26,"children":[{"type":"Token","kind":"L_CURLY","start":50,"end":51,"istart":23,"iend":24},{"type":"Token","kind":"WHITESPACE","start":51,"end":52,"istart":24,"iend":25},{"type":"Token","kind":"R_CURLY","start":52,"end":53,"istart":25,"iend":26}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":55,"end":56},{"type":"Token","kind":"WHITESPACE","start":56,"end":57},{"type":"Token","kind":"STRING","start":57,"end":59},{"type":"Token","kind":"R_PAREN","start":59,"end":60}]}]}]},{"type":"Token","kind":"SEMICOLON","start":60,"end":61}]},{"type":"Token","kind":"WHITESPACE","start":61,"end":62},{"type":"Token","kind":"R_CURLY","start":62,"end":63}]}]}]}]}"#
+ r#"{"type":"Node","kind":"SOURCE_FILE","start":[0,0,0],"end":[63,6,1],"children":[{"type":"Node","kind":"FN","start":[0,0,0],"end":[63,6,1],"children":[{"type":"Token","kind":"FN_KW","start":[0,0,0],"end":[2,0,2]},{"type":"Token","kind":"WHITESPACE","start":[2,0,2],"end":[3,0,3]},{"type":"Node","kind":"NAME","start":[3,0,3],"end":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[3,0,3],"end":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[7,0,7],"end":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[7,0,7],"end":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[8,0,8],"end":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[9,0,9],"end":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[10,0,10],"end":[63,6,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[10,0,10],"end":[63,6,1],"children":[{"type":"Token","kind":"L_CURLY","start":[10,0,10],"end":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[11,0,11],"end":[16,1,4]},{"type":"Node","kind":"EXPR_STMT","start":[16,1,4],"end":[61,5,9],"children":[{"type":"Node","kind":"MACRO_EXPR","start":[16,1,4],"end":[60,5,8],"children":[{"type":"Node","kind":"MACRO_CALL","start":[16,1,4],"end":[60,5,8],"children":[{"type":"Node","kind":"PATH","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"PATH_SEGMENT","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Node","kind":"NAME_REF","start":[16,1,4],"end":[22,1,10],"children":[{"type":"Token","kind":"IDENT","start":[16,1,4],"end":[22,1,10]}]}]}]},{"type":"Token","kind":"BANG","start":[22,1,10],"end":[23,1,11]},{"type":"Node","kind":"TOKEN_TREE","start":[23,1,11],"end":[60,5,8],"children":[{"type":"Token","kind":"L_PAREN","start":[23,1,11],"end":[24,1,12]},{"type":"Node","kind":"STRING","start":[24,1,12],"end":[55,5,3],"children":[{"type":"Node","kind":"SOURCE_FILE","start":[27,1,15],"end":[27,1,15],"istart":[0,0,0],"iend":[26,1,14],"children":[{"type":"Token","kind":"WHITESPACE","start":[27,1,15],"end":[27,1,15],"istart":[0,0,0],"iend":[1,0,1]},{"type":"Node","kind":"FN","start":[28,2,0],"end":[28,2,0],"istart":[1,0,1],"iend":[13,1,1],"children":[{"type":"Token","kind":"FN_KW","start":[28,2,0],"end":[28,2,0],"istart":[1,0,1],"iend":[3,0,3]},{"type":"Token","kind":"WHITESPACE","start":[30,2,2],"end":[30,2,2],"istart":[3,0,3],"iend":[4,0,4]},{"type":"Node","kind":"NAME","start":[31,2,3],"end":[31,2,3],"istart":[4,0,4],"iend":[7,0,7],"children":[{"type":"Token","kind":"IDENT","start":[31,2,3],"end":[31,2,3],"istart":[4,0,4],"iend":[7,0,7]}]},{"type":"Node","kind":"PARAM_LIST","start":[34,2,6],"end":[34,2,6],"istart":[7,0,7],"iend":[9,0,9],"children":[{"type":"Token","kind":"L_PAREN","start":[34,2,6],"end":[34,2,6],"istart":[7,0,7],"iend":[8,0,8]},{"type":"Token","kind":"R_PAREN","start":[35,2,7],"end":[35,2,7],"istart":[8,0,8],"iend":[9,0,9]}]},{"type":"Token","kind":"WHITESPACE","start":[36,2,8],"end":[36,2,8],"istart":[9,0,9],"iend":[10,0,10]},{"type":"Node","kind":"BLOCK_EXPR","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Node","kind":"STMT_LIST","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[13,1,1],"children":[{"type":"Token","kind":"L_CURLY","start":[37,2,9],"end":[37,2,9],"istart":[10,0,10],"iend":[11,0,11]},{"type":"Token","kind":"WHITESPACE","start":[38,2,10],"end":[38,2,10],"istart":[11,0,11],"iend":[12,1,0]},{"type":"Token","kind":"R_CURLY","start":[39,3,0],"end":[39,3,0],"istart":[12,1,0],"iend":[13,1,1]}]}]}]},{"type":"Token","kind":"WHITESPACE","start":[40,3,1],"end":[40,3,1],"istart":[13,1,1],"iend":[14,1,2]},{"type":"Node","kind":"FN","start":[41,4,0],"end":[41,4,0],"istart":[14,1,2],"iend":[26,1,14],"children":[{"type":"Token","kind":"FN_KW","start":[41,4,0],"end":[41,4,0],"istart":[14,1,2],"iend":[16,1,4]},{"type":"Token","kind":"WHITESPACE","start":[43,4,2],"end":[43,4,2],"istart":[16,1,4],"iend":[17,1,5]},{"type":"Node","kind":"NAME","start":[44,4,3],"end":[44,4,3],"istart":[17,1,5],"iend":[20,1,8],"children":[{"type":"Token","kind":"IDENT","start":[44,4,3],"end":[44,4,3],"istart":[17,1,5],"iend":[20,1,8]}]},{"type":"Node","kind":"PARAM_LIST","start":[47,4,6],"end":[47,4,6],"istart":[20,1,8],"iend":[22,1,10],"children":[{"type":"Token","kind":"L_PAREN","start":[47,4,6],"end":[47,4,6],"istart":[20,1,8],"iend":[21,1,9]},{"type":"Token","kind":"R_PAREN","start":[48,4,7],"end":[48,4,7],"istart":[21,1,9],"iend":[22,1,10]}]},{"type":"Token","kind":"WHITESPACE","start":[49,4,8],"end":[49,4,8],"istart":[22,1,10],"iend":[23,1,11]},{"type":"Node","kind":"BLOCK_EXPR","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[26,1,14],"children":[{"type":"Node","kind":"STMT_LIST","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[26,1,14],"children":[{"type":"Token","kind":"L_CURLY","start":[50,4,9],"end":[50,4,9],"istart":[23,1,11],"iend":[24,1,12]},{"type":"Token","kind":"WHITESPACE","start":[51,4,10],"end":[51,4,10],"istart":[24,1,12],"iend":[25,1,13]},{"type":"Token","kind":"R_CURLY","start":[52,5,0],"end":[52,5,0],"istart":[25,1,13],"iend":[26,1,14]}]}]}]}]}]},{"type":"Token","kind":"COMMA","start":[55,5,3],"end":[56,5,4]},{"type":"Token","kind":"WHITESPACE","start":[56,5,4],"end":[57,5,5]},{"type":"Token","kind":"STRING","start":[57,5,5],"end":[59,5,7]},{"type":"Token","kind":"R_PAREN","start":[59,5,7],"end":[60,5,8]}]}]}]},{"type":"Token","kind":"SEMICOLON","start":[60,5,8],"end":[61,5,9]}]},{"type":"Token","kind":"WHITESPACE","start":[61,5,9],"end":[62,6,0]},{"type":"Token","kind":"R_CURLY","start":[62,6,0],"end":[63,6,1]}]}]}]}]}"#
]],
);
}
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index ae1c6efe0cb1f..66553a2661a20 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -347,6 +347,7 @@ define_symbols! {
option,
Option,
Ord,
+ Ordering,
Output,
CallRefFuture,
CallOnceFuture,
@@ -458,6 +459,8 @@ define_symbols! {
system,
sysv64,
Target,
+ target_feature,
+ enable,
termination,
test_case,
test,
@@ -479,6 +482,7 @@ define_symbols! {
u64,
u8,
unadjusted,
+ unknown,
Unknown,
unpin,
unreachable_2015,
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
index 389c01933c999..fe1316c9bfde3 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/expressions.rs
@@ -678,6 +678,8 @@ fn path_expr(p: &mut Parser<'_>, r: Restrictions) -> (CompletedMarker, BlockLike
// S { x };
// S { x, y: 32, };
// S { x, y: 32, ..Default::default() };
+// S { x, y: 32, .. };
+// S { .. };
// S { x: ::default() };
// TupleStruct { 0: 1 };
// }
@@ -709,6 +711,8 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// fn main() {
// S { field ..S::default() }
// S { 0 ..S::default() }
+ // S { field .. }
+ // S { 0 .. }
// }
name_ref_or_index(p);
p.error("expected `:`");
@@ -739,7 +743,13 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// S { .. } = S {};
// }
- // We permit `.. }` on the left-hand side of a destructuring assignment.
+ // test struct_initializer_with_defaults
+ // fn foo() {
+ // let _s = S { .. };
+ // }
+
+ // We permit `.. }` on the left-hand side of a destructuring assignment
+ // or defaults values.
if !p.at(T!['}']) {
expr(p);
@@ -750,6 +760,12 @@ pub(crate) fn record_expr_field_list(p: &mut Parser<'_>) {
// S { ..x, a: 0 }
// }
+ // test_err comma_after_default_values_syntax
+ // fn foo() {
+ // S { .., };
+ // S { .., a: 0 }
+ // }
+
// Do not bump, so we can support additional fields after this comma.
p.error("cannot use a comma after the base struct");
}
diff --git a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
index 21078175c0ec0..9a16c9db6daf1 100644
--- a/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/grammar/items/adt.rs
@@ -135,6 +135,11 @@ pub(crate) fn record_field_list(p: &mut Parser<'_>) {
name(p);
p.expect(T![:]);
types::type_(p);
+ // test record_field_default_values
+ // struct S { f: f32 = 0.0 }
+ if p.eat(T![=]) {
+ expressions::expr(p);
+ }
m.complete(p, RECORD_FIELD);
} else {
m.abandon(p);
diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
index 318f71a2d4df2..79900425a17cc 100644
--- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
+++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs
@@ -1,4 +1,4 @@
-//! Generated by `cargo codegen grammar`, do not edit by hand.
+//! Generated by `cargo xtask codegen grammar`, do not edit by hand.
#![allow(bad_style, missing_docs, unreachable_pub)]
use crate::Edition;
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
index b9f87b6af2421..c8ea8c547a98b 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs
@@ -482,6 +482,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/record_field_attrs.rs");
}
#[test]
+ fn record_field_default_values() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/record_field_default_values.rs");
+ }
+ #[test]
fn record_field_list() {
run_and_expect_no_errors("test_data/parser/inline/ok/record_field_list.rs");
}
@@ -544,6 +548,10 @@ mod ok {
run_and_expect_no_errors("test_data/parser/inline/ok/stmt_postfix_expr_ambiguity.rs");
}
#[test]
+ fn struct_initializer_with_defaults() {
+ run_and_expect_no_errors("test_data/parser/inline/ok/struct_initializer_with_defaults.rs");
+ }
+ #[test]
fn struct_item() { run_and_expect_no_errors("test_data/parser/inline/ok/struct_item.rs"); }
#[test]
fn trait_alias() { run_and_expect_no_errors("test_data/parser/inline/ok/trait_alias.rs"); }
@@ -719,6 +727,10 @@ mod err {
);
}
#[test]
+ fn comma_after_default_values_syntax() {
+ run_and_expect_errors("test_data/parser/inline/err/comma_after_default_values_syntax.rs");
+ }
+ #[test]
fn crate_visibility_empty_recover() {
run_and_expect_errors("test_data/parser/inline/err/crate_visibility_empty_recover.rs");
}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast
new file mode 100644
index 0000000000000..feb617e1aa2ab
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rast
@@ -0,0 +1,59 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ ERROR
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "a"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "0"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
+error 21: expected expression
+error 36: expected expression
+error 37: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs
new file mode 100644
index 0000000000000..f1ecdf89fab17
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/comma_after_default_values_syntax.rs
@@ -0,0 +1,4 @@
+fn foo() {
+ S { .., };
+ S { .., a: 0 }
+}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
index 08ae906421c30..12b4e233e3044 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rast
@@ -44,6 +44,56 @@ SOURCE_FILE
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ INT_NUMBER "0"
+ WHITESPACE " "
+ DOT2 ".."
+ CALL_EXPR
+ PATH_EXPR
+ PATH
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ COLON2 "::"
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "default"
+ ARG_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "field"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n "
RECORD_EXPR
PATH
PATH_SEGMENT
@@ -58,20 +108,6 @@ SOURCE_FILE
INT_NUMBER "0"
WHITESPACE " "
DOT2 ".."
- CALL_EXPR
- PATH_EXPR
- PATH
- PATH
- PATH_SEGMENT
- NAME_REF
- IDENT "S"
- COLON2 "::"
- PATH_SEGMENT
- NAME_REF
- IDENT "default"
- ARG_LIST
- L_PAREN "("
- R_PAREN ")"
WHITESPACE " "
R_CURLY "}"
WHITESPACE "\n"
@@ -82,3 +118,9 @@ error 25: expected COMMA
error 42: expected SEMICOLON
error 52: expected `:`
error 52: expected COMMA
+error 69: expected SEMICOLON
+error 83: expected `:`
+error 83: expected COMMA
+error 88: expected SEMICOLON
+error 98: expected `:`
+error 98: expected COMMA
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
index 65398ccb88e5d..416cd763fdb56 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/err/record_literal_before_ellipsis_recovery.rs
@@ -1,4 +1,6 @@
fn main() {
S { field ..S::default() }
S { 0 ..S::default() }
+ S { field .. }
+ S { 0 .. }
}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
new file mode 100644
index 0000000000000..33088f2cabf39
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rast
@@ -0,0 +1,28 @@
+SOURCE_FILE
+ STRUCT
+ STRUCT_KW "struct"
+ WHITESPACE " "
+ NAME
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_FIELD
+ NAME
+ IDENT "f"
+ COLON ":"
+ WHITESPACE " "
+ PATH_TYPE
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "f32"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ LITERAL
+ FLOAT_NUMBER "0.0"
+ WHITESPACE " "
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs
new file mode 100644
index 0000000000000..d7b38944a8aa8
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_field_default_values.rs
@@ -0,0 +1 @@
+struct S { f: f32 = 0.0 }
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rast
index 00948c322f4c9..b868da55bcea7 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rast
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rast
@@ -120,6 +120,53 @@ SOURCE_FILE
R_CURLY "}"
SEMICOLON ";"
WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ PATH_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "x"
+ COMMA ","
+ WHITESPACE " "
+ RECORD_EXPR_FIELD
+ NAME_REF
+ IDENT "y"
+ COLON ":"
+ WHITESPACE " "
+ LITERAL
+ INT_NUMBER "32"
+ COMMA ","
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
+ EXPR_STMT
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n "
EXPR_STMT
RECORD_EXPR
PATH
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rs
index 86411fbb7dc05..42895f759b2be 100644
--- a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rs
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/record_lit.rs
@@ -3,6 +3,8 @@ fn foo() {
S { x };
S { x, y: 32, };
S { x, y: 32, ..Default::default() };
+ S { x, y: 32, .. };
+ S { .. };
S { x: ::default() };
TupleStruct { 0: 1 };
}
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast
new file mode 100644
index 0000000000000..987e219ae822b
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rast
@@ -0,0 +1,39 @@
+SOURCE_FILE
+ FN
+ FN_KW "fn"
+ WHITESPACE " "
+ NAME
+ IDENT "foo"
+ PARAM_LIST
+ L_PAREN "("
+ R_PAREN ")"
+ WHITESPACE " "
+ BLOCK_EXPR
+ STMT_LIST
+ L_CURLY "{"
+ WHITESPACE "\n "
+ LET_STMT
+ LET_KW "let"
+ WHITESPACE " "
+ IDENT_PAT
+ NAME
+ IDENT "_s"
+ WHITESPACE " "
+ EQ "="
+ WHITESPACE " "
+ RECORD_EXPR
+ PATH
+ PATH_SEGMENT
+ NAME_REF
+ IDENT "S"
+ WHITESPACE " "
+ RECORD_EXPR_FIELD_LIST
+ L_CURLY "{"
+ WHITESPACE " "
+ DOT2 ".."
+ WHITESPACE " "
+ R_CURLY "}"
+ SEMICOLON ";"
+ WHITESPACE "\n"
+ R_CURLY "}"
+ WHITESPACE "\n"
diff --git a/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs
new file mode 100644
index 0000000000000..e08204f94c4b4
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/struct_initializer_with_defaults.rs
@@ -0,0 +1,3 @@
+fn foo() {
+ let _s = S { .. };
+}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
index ba1fcd8e336a5..569070766f1c6 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs
@@ -21,18 +21,16 @@ pub(crate) fn run() -> io::Result<()> {
}
}
- let read_request =
- |buf: &mut String| msg::Request::read(read_json, &mut io::stdin().lock(), buf);
-
+ let mut buf = String::new();
+ let mut read_request = || msg::Request::read(read_json, &mut io::stdin().lock(), &mut buf);
let write_response = |msg: msg::Response| msg.write(write_json, &mut io::stdout().lock());
let env = EnvSnapshot::default();
- let mut srv = proc_macro_srv::ProcMacroSrv::new(&env);
- let mut buf = String::new();
+ let srv = proc_macro_srv::ProcMacroSrv::new(&env);
let mut span_mode = SpanMode::Id;
- while let Some(req) = read_request(&mut buf)? {
+ while let Some(req) = read_request()? {
let res = match req {
msg::Request::ListMacros { dylib_path } => {
msg::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| {
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
index 7ae75713ebfe9..f28821b4afc5c 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs
@@ -35,6 +35,7 @@ use std::{
ffi::OsString,
fs,
path::{Path, PathBuf},
+ sync::{Arc, Mutex, PoisonError},
thread,
};
@@ -53,7 +54,7 @@ pub enum ProcMacroKind {
pub const RUSTC_VERSION_STRING: &str = env!("RUSTC_VERSION");
pub struct ProcMacroSrv<'env> {
- expanders: HashMap,
+ expanders: Mutex>>,
env: &'env EnvSnapshot,
}
@@ -67,7 +68,7 @@ const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
impl ProcMacroSrv<'_> {
pub fn expand(
- &mut self,
+ &self,
lib: impl AsRef,
env: Vec<(String, String)>,
current_dir: Option>,
@@ -118,29 +119,37 @@ impl ProcMacroSrv<'_> {
}
pub fn list_macros(
- &mut self,
+ &self,
dylib_path: &Utf8Path,
) -> Result, String> {
let expander = self.expander(dylib_path)?;
Ok(expander.list_macros())
}
- fn expander(&mut self, path: &Utf8Path) -> Result<&dylib::Expander, String> {
+ fn expander(&self, path: &Utf8Path) -> Result, String> {
let expander = || {
- dylib::Expander::new(path)
- .map_err(|err| format!("Cannot create expander for {path}: {err}",))
+ let expander = dylib::Expander::new(path)
+ .map_err(|err| format!("Cannot create expander for {path}: {err}",));
+ expander.map(Arc::new)
};
- Ok(match self.expanders.entry(path.to_path_buf()) {
- Entry::Vacant(v) => v.insert(expander()?),
- Entry::Occupied(mut e) => {
- let time = fs::metadata(path).and_then(|it| it.modified()).ok();
- if Some(e.get().modified_time()) != time {
- e.insert(expander()?);
+ Ok(
+ match self
+ .expanders
+ .lock()
+ .unwrap_or_else(PoisonError::into_inner)
+ .entry(path.to_path_buf())
+ {
+ Entry::Vacant(v) => v.insert(expander()?).clone(),
+ Entry::Occupied(mut e) => {
+ let time = fs::metadata(path).and_then(|it| it.modified()).ok();
+ if Some(e.get().modified_time()) != time {
+ e.insert(expander()?);
+ }
+ e.get().clone()
}
- e.into_mut()
- }
- })
+ },
+ )
}
}
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
index 4ce4544243ab5..1b085520d5656 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs
@@ -107,7 +107,7 @@ fn assert_expand_impl(
pub(crate) fn list() -> Vec {
let dylib_path = proc_macro_test_dylib_path();
let env = EnvSnapshot::default();
- let mut srv = ProcMacroSrv::new(&env);
+ let srv = ProcMacroSrv::new(&env);
let res = srv.list_macros(&dylib_path).unwrap();
res.into_iter().map(|(name, kind)| format!("{name} [{kind:?}]")).collect()
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
index a396396761041..feee40a1fc9b2 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/project_json.rs
@@ -508,5 +508,5 @@ fn serialize_crate_name(name: &CrateName, se: S) -> Result
where
S: serde::Serializer,
{
- se.serialize_str(name)
+ se.serialize_str(name.as_str())
}
diff --git a/src/tools/rust-analyzer/crates/project-model/src/tests.rs b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
index f111383112593..2856086543666 100644
--- a/src/tools/rust-analyzer/crates/project-model/src/tests.rs
+++ b/src/tools/rust-analyzer/crates/project-model/src/tests.rs
@@ -230,7 +230,7 @@ fn rust_project_is_proc_macro_has_proc_macro_dep() {
let crate_data = &crate_graph[crate_id];
// Assert that the project crate with `is_proc_macro` has a dependency
// on the proc_macro sysroot crate.
- crate_data.dependencies.iter().find(|&dep| dep.name.deref() == "proc_macro").unwrap();
+ crate_data.dependencies.iter().find(|&dep| *dep.name.deref() == sym::proc_macro).unwrap();
}
#[test]
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
index c24cbb4a31176..b8ce2b7430b98 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/Cargo.toml
@@ -37,7 +37,7 @@ rustc-hash.workspace = true
serde_json = { workspace = true, features = ["preserve_order"] }
serde.workspace = true
serde_derive.workspace = true
-tenthash = "0.4.0"
+tenthash = "1.0.0"
num_cpus = "1.15.0"
mimalloc = { version = "0.1.30", default-features = false, optional = true }
lsp-server.workspace = true
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 18c27c844964b..4fc6180920f5f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -13,7 +13,7 @@ use hir::{
ModuleDef, Name,
};
use hir_def::{
- body::BodySourceMap,
+ expr_store::BodySourceMap,
hir::{ExprId, PatId},
SyntheticSyntax,
};
@@ -1072,6 +1072,7 @@ impl flags::AnalysisStats {
param_names_for_lifetime_elision_hints: true,
hide_named_constructor_hints: false,
hide_closure_initialization_hints: false,
+ hide_closure_parameter_hints: false,
closure_style: hir::ClosureStyle::ImplFn,
max_length: Some(25),
closing_brace_hints_min_lines: Some(20),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
index 28f25975d64aa..6a3ceb640b91a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -4,7 +4,7 @@
use project_model::{CargoConfig, RustLibSource};
use rustc_hash::FxHashSet;
-use hir::{db::HirDatabase, Crate, HirFileIdExt, Module};
+use hir::{db::HirDatabase, sym, Crate, HirFileIdExt, Module};
use ide::{AnalysisHost, AssistResolveStrategy, Diagnostic, DiagnosticsConfig, Severity};
use ide_db::{base_db::SourceRootDatabase, LineIndexDatabase};
use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
@@ -60,7 +60,7 @@ impl flags::Diagnostics {
let file_id = module.definition_source_file_id(db).original_file(db);
if !visited_files.contains(&file_id) {
let crate_name =
- module.krate().display_name(db).as_deref().unwrap_or("unknown").to_owned();
+ module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned();
println!(
"processing crate: {crate_name}, module: {}",
_vfs.file_path(file_id.into())
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
index dc0f722aae6a0..fe75872105aec 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/scip.rs
@@ -139,45 +139,42 @@ impl flags::Scip {
let mut occurrences = Vec::new();
let mut symbols = Vec::new();
- tokens.into_iter().for_each(|(text_range, id)| {
+ for (text_range, id) in tokens.into_iter() {
let token = si.tokens.get(id).unwrap();
- let (symbol, enclosing_symbol, is_inherent_impl) =
- if let Some(TokenSymbols { symbol, enclosing_symbol, is_inherent_impl }) =
- symbol_generator.token_symbols(id, token)
- {
- (symbol, enclosing_symbol, is_inherent_impl)
- } else {
- ("".to_owned(), None, false)
- };
+ let Some(TokenSymbols { symbol, enclosing_symbol, is_inherent_impl }) =
+ symbol_generator.token_symbols(id, token)
+ else {
+ // token did not have a moniker, so there is no reasonable occurrence to emit
+ // see ide::moniker::def_to_moniker
+ continue;
+ };
- if !symbol.is_empty() {
- let is_defined_in_this_document = match token.definition {
- Some(def) => def.file_id == file_id,
- _ => false,
- };
- if is_defined_in_this_document {
- if token_ids_emitted.insert(id) {
- // token_ids_emitted does deduplication. This checks that this results
- // in unique emitted symbols, as otherwise references are ambiguous.
- let should_emit = record_error_if_symbol_already_used(
+ let is_defined_in_this_document = match token.definition {
+ Some(def) => def.file_id == file_id,
+ _ => false,
+ };
+ if is_defined_in_this_document {
+ if token_ids_emitted.insert(id) {
+ // token_ids_emitted does deduplication. This checks that this results
+ // in unique emitted symbols, as otherwise references are ambiguous.
+ let should_emit = record_error_if_symbol_already_used(
+ symbol.clone(),
+ is_inherent_impl,
+ relative_path.as_str(),
+ &line_index,
+ text_range,
+ );
+ if should_emit {
+ symbols.push(compute_symbol_info(
symbol.clone(),
- is_inherent_impl,
- relative_path.as_str(),
- &line_index,
- text_range,
- );
- if should_emit {
- symbols.push(compute_symbol_info(
- symbol.clone(),
- enclosing_symbol,
- token,
- ));
- }
+ enclosing_symbol,
+ token,
+ ));
}
- } else {
- token_ids_referenced.insert(id);
}
+ } else {
+ token_ids_referenced.insert(id);
}
// If the range of the def and the range of the token are the same, this must be the definition.
@@ -202,7 +199,7 @@ impl flags::Scip {
special_fields: Default::default(),
enclosing_range: Vec::new(),
});
- });
+ }
if occurrences.is_empty() {
continue;
@@ -444,14 +441,14 @@ impl SymbolGenerator {
MonikerResult::Moniker(moniker) => TokenSymbols {
symbol: scip::symbol::format_symbol(moniker_to_symbol(moniker)),
enclosing_symbol: None,
- is_inherent_impl: moniker
- .identifier
- .description
- .get(moniker.identifier.description.len() - 2)
- .is_some_and(|descriptor| {
+ is_inherent_impl: match &moniker.identifier.description[..] {
+ // inherent impls are represented as impl#[SelfType]
+ [.., descriptor, _] => {
descriptor.desc == MonikerDescriptorKind::Type
&& descriptor.name == "impl"
- }),
+ }
+ _ => false,
+ },
},
MonikerResult::Local { enclosing_moniker } => {
let local_symbol = scip::types::Symbol::new_local(local_count);
@@ -549,7 +546,9 @@ mod test {
continue;
}
for &(range, id) in &file.tokens {
- if range.contains(offset - TextSize::from(1)) {
+ // check if cursor is within token, ignoring token for the module defined by the file (whose range is the whole file)
+ if range.start() != TextSize::from(0) && range.contains(offset - TextSize::from(1))
+ {
let token = si.tokens.get(id).unwrap();
found_symbol = match token.moniker.as_ref() {
None => None,
@@ -885,7 +884,7 @@ pub mod example_mod {
);
let file = si.files.first().unwrap();
- let (_, token_id) = file.tokens.first().unwrap();
+ let (_, token_id) = file.tokens.get(1).unwrap(); // first token is file module, second is `bar`
let token = si.tokens.get(*token_id).unwrap();
assert_eq!(token.documentation.as_ref().map(|d| d.as_str()), Some("foo"));
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs
index 986bd018b424d..021b1bff39301 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/unresolved_references.rs
@@ -1,5 +1,5 @@
//! Reports references in code that the IDE layer cannot resolve.
-use hir::{db::HirDatabase, AnyDiagnostic, Crate, HirFileIdExt as _, Module, Semantics};
+use hir::{db::HirDatabase, sym, AnyDiagnostic, Crate, HirFileIdExt as _, Module, Semantics};
use ide::{AnalysisHost, RootDatabase, TextRange};
use ide_db::{
base_db::{SourceDatabase, SourceRootDatabase},
@@ -66,7 +66,7 @@ impl flags::UnresolvedReferences {
let file_id = module.definition_source_file_id(db).original_file(db);
if !visited_files.contains(&file_id) {
let crate_name =
- module.krate().display_name(db).as_deref().unwrap_or("unknown").to_owned();
+ module.krate().display_name(db).as_deref().unwrap_or(&sym::unknown).to_owned();
let file_path = vfs.file_path(file_id.into());
eprintln!("processing crate: {crate_name}, module: {file_path}",);
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 44325fa1a29e6..e915e55722bbb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -208,6 +208,8 @@ config_data! {
/// Whether to hide inlay type hints for `let` statements that initialize to a closure.
/// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
inlayHints_typeHints_hideClosureInitialization: bool = false,
+ /// Whether to hide inlay parameter type hints for closures.
+ inlayHints_typeHints_hideClosureParameter:bool = false,
/// Whether to hide inlay type hints for constructors.
inlayHints_typeHints_hideNamedConstructor: bool = false,
@@ -528,7 +530,7 @@ config_data! {
imports_granularity_enforce: bool = false,
/// How imports should be grouped into use statements.
imports_granularity_group: ImportGranularityDef = ImportGranularityDef::Crate,
- /// Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-import[following order]. Groups are separated by newlines.
+ /// Group inserted imports by the [following order](https://rust-analyzer.github.io/manual.html#auto-import). Groups are separated by newlines.
imports_group_enable: bool = true,
/// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
imports_merge_glob: bool = true,
@@ -1666,6 +1668,9 @@ impl Config {
hide_closure_initialization_hints: self
.inlayHints_typeHints_hideClosureInitialization()
.to_owned(),
+ hide_closure_parameter_hints: self
+ .inlayHints_typeHints_hideClosureParameter()
+ .to_owned(),
closure_style: match self.inlayHints_closureStyle() {
ClosureStyle::ImplFn => hir::ClosureStyle::ImplFn,
ClosureStyle::RustAnalyzer => hir::ClosureStyle::RANotation,
@@ -3624,21 +3629,9 @@ fn manual(fields: &[SchemaField]) -> String {
let name = format!("rust-analyzer.{}", field.replace('_', "."));
let doc = doc_comment_to_string(doc);
if default.contains('\n') {
- format_to_acc!(
- acc,
- r#"[[{name}]]{name}::
-+
---
-Default:
-----
-{default}
-----
-{doc}
---
-"#
- )
+ format_to_acc!(acc, " **{name}**\n\nDefault:\n\n```{default}\n\n```\n\n {doc}\n\n ")
} else {
- format_to_acc!(acc, "[[{name}]]{name} (default: `{default}`)::\n+\n--\n{doc}--\n")
+ format_to_acc!(acc, "**{name}** (default: {default})\n\n {doc}\n\n")
}
})
}
@@ -3716,7 +3709,7 @@ mod tests {
#[test]
fn generate_config_documentation() {
- let docs_path = project_root().join("docs/user/generated_config.adoc");
+ let docs_path = project_root().join("docs/book/src/configuration_generated.md");
let expected = FullConfigInput::manual();
ensure_file_contents(docs_path.as_std_path(), &expected);
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
index 0f2d7823b7e7c..b52f64aaacecb 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs
@@ -396,6 +396,7 @@ impl GlobalState {
|| !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
{
let config_change = {
+ let _p = span!(Level::INFO, "GlobalState::process_changes/config_change").entered();
let user_config_path = (|| {
let mut p = Config::user_config_dir_path()?;
p.push("rust-analyzer.toml");
@@ -569,12 +570,12 @@ impl GlobalState {
if let Some((method, start)) = self.req_queue.incoming.complete(&response.id) {
if let Some(err) = &response.error {
if err.message.starts_with("server panicked") {
- self.poke_rust_analyzer_developer(format!("{}, check the log", err.message))
+ self.poke_rust_analyzer_developer(format!("{}, check the log", err.message));
}
}
let duration = start.elapsed();
- tracing::debug!("handled {} - ({}) in {:0.2?}", method, response.id, duration);
+ tracing::debug!(name: "message response", method, %response.id, duration = format_args!("{:0.2?}", duration));
self.send(response.into());
}
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
index ff50f7533a64e..4683877db69b0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/dispatch.rs
@@ -118,7 +118,7 @@ impl RequestDispatcher<'_> {
}
return self;
}
- self.on_with_thread_intent::(
+ self.on_with_thread_intent::(
ThreadIntent::Worker,
f,
Self::content_modified_error,
@@ -147,7 +147,7 @@ impl RequestDispatcher<'_> {
}
return self;
}
- self.on_with_thread_intent::(ThreadIntent::Worker, f, on_cancelled)
+ self.on_with_thread_intent::(ThreadIntent::Worker, f, on_cancelled)
}
/// Dispatches a non-latency-sensitive request onto the thread pool. When the VFS is marked not
@@ -166,7 +166,7 @@ impl RequestDispatcher<'_> {
}
return self;
}
- self.on_with_thread_intent::(
+ self.on_with_thread_intent::(
ThreadIntent::Worker,
f,
Self::content_modified_error,
@@ -193,7 +193,7 @@ impl RequestDispatcher<'_> {
}
return self;
}
- self.on_with_thread_intent::(
+ self.on_with_thread_intent::(
ThreadIntent::LatencySensitive,
f,
Self::content_modified_error,
@@ -212,7 +212,7 @@ impl RequestDispatcher<'_> {
R::Params: DeserializeOwned + panic::UnwindSafe + Send + fmt::Debug,
R::Result: Serialize,
{
- self.on_with_thread_intent::(
+ self.on_with_thread_intent::(
ThreadIntent::LatencySensitive,
f,
Self::content_modified_error,
@@ -231,7 +231,7 @@ impl RequestDispatcher<'_> {
}
}
- fn on_with_thread_intent(
+ fn on_with_thread_intent(
&mut self,
intent: ThreadIntent,
f: fn(GlobalStateSnapshot, R::Params) -> anyhow::Result,
@@ -251,10 +251,10 @@ impl RequestDispatcher<'_> {
tracing::debug!(?params);
let world = self.global_state.snapshot();
- if MAIN_POOL {
- &mut self.global_state.task_pool.handle
- } else {
+ if RUSTFMT {
&mut self.global_state.fmt_pool.handle
+ } else {
+ &mut self.global_state.task_pool.handle
}
.spawn(intent, move || {
let result = panic::catch_unwind(move || {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
index 84ba89d9f31f9..48856d19e155d 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/notification.rs
@@ -74,7 +74,8 @@ pub(crate) fn handle_did_open_text_document(
tracing::error!("duplicate DidOpenTextDocument: {}", path);
}
- state.vfs.write().0.set_file_contents(path, Some(params.text_document.text.into_bytes()));
+ let contents = params.text_document.text.into_bytes();
+ state.vfs.write().0.set_file_contents(path, Some(contents));
if state.config.discover_workspace_config().is_some() {
tracing::debug!("queuing task");
let _ = state
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
index 39cbf53eaa21d..ed028f1d37b67 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs
@@ -2318,18 +2318,21 @@ fn run_rustfmt(
}
};
- tracing::debug!(?command, "created format command");
+ let output = {
+ let _p = tracing::info_span!("rustfmt", ?command).entered();
- let mut rustfmt = command
- .stdin(Stdio::piped())
- .stdout(Stdio::piped())
- .stderr(Stdio::piped())
- .spawn()
- .context(format!("Failed to spawn {command:?}"))?;
+ let mut rustfmt = command
+ .stdin(Stdio::piped())
+ .stdout(Stdio::piped())
+ .stderr(Stdio::piped())
+ .spawn()
+ .context(format!("Failed to spawn {command:?}"))?;
- rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
+ rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
+
+ rustfmt.wait_with_output()?
+ };
- let output = rustfmt.wait_with_output()?;
let captured_stdout = String::from_utf8(output.stdout)?;
let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
index ccffa7a671e66..1221f7c7012e7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lib.rs
@@ -50,7 +50,7 @@ mod integrated_benchmarks;
use hir::Mutability;
use ide::{CompletionItem, CompletionItemRefMode, CompletionRelevance};
use serde::de::DeserializeOwned;
-use tenthash::TentHasher;
+use tenthash::TentHash;
pub use crate::{
lsp::capabilities::server_capabilities, main_loop::main_loop, reload::ws_to_crate_graph,
@@ -66,7 +66,7 @@ pub fn from_json(
}
fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8; 20] {
- fn hash_completion_relevance(hasher: &mut TentHasher, relevance: &CompletionRelevance) {
+ fn hash_completion_relevance(hasher: &mut TentHash, relevance: &CompletionRelevance) {
use ide_completion::{
CompletionRelevancePostfixMatch, CompletionRelevanceReturnType,
CompletionRelevanceTypeMatch,
@@ -79,71 +79,97 @@ fn completion_item_hash(item: &CompletionItem, is_ref_completion: bool) -> [u8;
u8::from(relevance.requires_import),
u8::from(relevance.is_private_editable),
]);
- if let Some(type_match) = &relevance.type_match {
- let label = match type_match {
- CompletionRelevanceTypeMatch::CouldUnify => "could_unify",
- CompletionRelevanceTypeMatch::Exact => "exact",
- };
- hasher.update(label);
+
+ match relevance.type_match {
+ None => hasher.update([0u8]),
+ Some(CompletionRelevanceTypeMatch::CouldUnify) => hasher.update([1u8]),
+ Some(CompletionRelevanceTypeMatch::Exact) => hasher.update([2u8]),
}
+
+ hasher.update([u8::from(relevance.trait_.is_some())]);
if let Some(trait_) = &relevance.trait_ {
hasher.update([u8::from(trait_.is_op_method), u8::from(trait_.notable_trait)]);
}
- if let Some(postfix_match) = &relevance.postfix_match {
- let label = match postfix_match {
- CompletionRelevancePostfixMatch::NonExact => "non_exact",
- CompletionRelevancePostfixMatch::Exact => "exact",
- };
- hasher.update(label);
+
+ match relevance.postfix_match {
+ None => hasher.update([0u8]),
+ Some(CompletionRelevancePostfixMatch::NonExact) => hasher.update([1u8]),
+ Some(CompletionRelevancePostfixMatch::Exact) => hasher.update([2u8]),
}
+
+ hasher.update([u8::from(relevance.function.is_some())]);
if let Some(function) = &relevance.function {
hasher.update([u8::from(function.has_params), u8::from(function.has_self_param)]);
- let label = match function.return_type {
- CompletionRelevanceReturnType::Other => "other",
- CompletionRelevanceReturnType::DirectConstructor => "direct_constructor",
- CompletionRelevanceReturnType::Constructor => "constructor",
- CompletionRelevanceReturnType::Builder => "builder",
+ let discriminant: u8 = match function.return_type {
+ CompletionRelevanceReturnType::Other => 0,
+ CompletionRelevanceReturnType::DirectConstructor => 1,
+ CompletionRelevanceReturnType::Constructor => 2,
+ CompletionRelevanceReturnType::Builder => 3,
};
- hasher.update(label);
+ hasher.update([discriminant]);
}
}
- let mut hasher = TentHasher::new();
+ let mut hasher = TentHash::new();
hasher.update([
u8::from(is_ref_completion),
u8::from(item.is_snippet),
u8::from(item.deprecated),
u8::from(item.trigger_call_info),
]);
+
+ hasher.update(item.label.primary.len().to_ne_bytes());
hasher.update(&item.label.primary);
+
+ hasher.update([u8::from(item.label.detail_left.is_some())]);
if let Some(label_detail) = &item.label.detail_left {
+ hasher.update(label_detail.len().to_ne_bytes());
hasher.update(label_detail);
}
+
+ hasher.update([u8::from(item.label.detail_right.is_some())]);
if let Some(label_detail) = &item.label.detail_right {
+ hasher.update(label_detail.len().to_ne_bytes());
hasher.update(label_detail);
}
+
// NB: do not hash edits or source range, as those may change between the time the client sends the resolve request
// and the time it receives it: some editors do allow changing the buffer between that, leading to ranges being different.
//
// Documentation hashing is skipped too, as it's a large blob to process,
// while not really making completion properties more unique as they are already.
- hasher.update(item.kind.tag());
+
+ let kind_tag = item.kind.tag();
+ hasher.update(kind_tag.len().to_ne_bytes());
+ hasher.update(kind_tag);
+
+ hasher.update(item.lookup.len().to_ne_bytes());
hasher.update(&item.lookup);
+
+ hasher.update([u8::from(item.detail.is_some())]);
if let Some(detail) = &item.detail {
+ hasher.update(detail.len().to_ne_bytes());
hasher.update(detail);
}
+
hash_completion_relevance(&mut hasher, &item.relevance);
+
+ hasher.update([u8::from(item.ref_match.is_some())]);
if let Some((ref_mode, text_size)) = &item.ref_match {
- let prefix = match ref_mode {
- CompletionItemRefMode::Reference(Mutability::Shared) => "&",
- CompletionItemRefMode::Reference(Mutability::Mut) => "&mut ",
- CompletionItemRefMode::Dereference => "*",
+ let discriminant = match ref_mode {
+ CompletionItemRefMode::Reference(Mutability::Shared) => 0u8,
+ CompletionItemRefMode::Reference(Mutability::Mut) => 1u8,
+ CompletionItemRefMode::Dereference => 2u8,
};
- hasher.update(prefix);
- hasher.update(u32::from(*text_size).to_le_bytes());
+ hasher.update([discriminant]);
+ hasher.update(u32::from(*text_size).to_ne_bytes());
}
+
+ hasher.update(item.import_to_add.len().to_ne_bytes());
for import_path in &item.import_to_add {
+ hasher.update(import_path.len().to_ne_bytes());
hasher.update(import_path);
}
+
hasher.finalize()
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
index 991c10743f7a6..3c21e19925257 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/semantic_tokens.rs
@@ -24,7 +24,7 @@ macro_rules! define_semantic_token_types {
}
pub(crate) const SUPPORTED_TYPES: &[SemanticTokenType] = &[
- $(SemanticTokenType::$standard,)*
+ $(self::types::$standard,)*
$(self::types::$custom),*
];
@@ -32,7 +32,7 @@ macro_rules! define_semantic_token_types {
use self::types::*;
$(
if token == $custom {
- None $(.or(Some(SemanticTokenType::$fallback)))?
+ None $(.or(Some(self::types::$fallback)))?
} else
)*
{ Some(token )}
@@ -60,6 +60,7 @@ define_semantic_token_types![
STRUCT,
TYPE_PARAMETER,
VARIABLE,
+ TYPE,
}
custom {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
index d6dc8b521fd6e..ebc65373b5226 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs
@@ -253,6 +253,11 @@ impl GlobalState {
&self,
inbox: &Receiver,
) -> Result, crossbeam_channel::RecvError> {
+ // Make sure we reply to formatting requests ASAP so the editor doesn't block
+ if let Ok(task) = self.fmt_pool.receiver.try_recv() {
+ return Ok(Some(Event::Task(task)));
+ }
+
select! {
recv(inbox) -> msg =>
return Ok(msg.ok().map(Event::Lsp)),
@@ -320,26 +325,30 @@ impl GlobalState {
}
for progress in prime_caches_progress {
- let (state, message, fraction);
+ let (state, message, fraction, title);
match progress {
PrimeCachesProgress::Begin => {
state = Progress::Begin;
message = None;
fraction = 0.0;
+ title = "Indexing";
}
PrimeCachesProgress::Report(report) => {
state = Progress::Report;
+ title = report.work_type;
- message = match &report.crates_currently_indexing[..] {
+ message = match &*report.crates_currently_indexing {
[crate_name] => Some(format!(
- "{}/{} ({crate_name})",
- report.crates_done, report.crates_total
+ "{}/{} ({})",
+ report.crates_done,
+ report.crates_total,
+ crate_name.as_str(),
)),
[crate_name, rest @ ..] => Some(format!(
"{}/{} ({} + {} more)",
report.crates_done,
report.crates_total,
- crate_name,
+ crate_name.as_str(),
rest.len()
)),
_ => None,
@@ -351,6 +360,7 @@ impl GlobalState {
state = Progress::End;
message = None;
fraction = 1.0;
+ title = "Indexing";
self.prime_caches_queue.op_completed(());
if cancelled {
@@ -360,7 +370,13 @@ impl GlobalState {
}
};
- self.report_progress("Indexing", state, message, Some(fraction), None);
+ self.report_progress(
+ title,
+ state,
+ message,
+ Some(fraction),
+ Some("rustAnalyzer/cachePriming".to_owned()),
+ );
}
}
Event::Vfs(message) => {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
index 0add2cdf5a71a..d18e577047749 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs
@@ -701,8 +701,7 @@ impl GlobalState {
let (crate_graph, proc_macro_paths, ws_data) = {
// Create crate graph from all the workspaces
- let vfs = &mut self.vfs.write().0;
-
+ let vfs = &self.vfs.read().0;
let load = |path: &AbsPath| {
let vfs_path = vfs::VfsPath::from(path.to_path_buf());
self.crate_graph_file_dependencies.insert(vfs_path.clone());
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
index 2bcd8505e8100..c5de69bb9fc83 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs
@@ -1,6 +1,8 @@
//! A thin wrapper around [`stdx::thread::Pool`] which threads a sender through spawned jobs.
//! It is used in [`crate::global_state::GlobalState`] throughout the main loop.
+use std::panic::UnwindSafe;
+
use crossbeam_channel::Sender;
use stdx::thread::{Pool, ThreadIntent};
@@ -18,7 +20,7 @@ impl TaskPool {
pub(crate) fn spawn(&mut self, intent: ThreadIntent, task: F)
where
- F: FnOnce() -> T + Send + 'static,
+ F: FnOnce() -> T + Send + UnwindSafe + 'static,
T: Send + 'static,
{
self.pool.spawn(intent, {
@@ -29,7 +31,7 @@ impl TaskPool {
pub(crate) fn spawn_with_sender(&mut self, intent: ThreadIntent, task: F)
where
- F: FnOnce(Sender) + Send + 'static,
+ F: FnOnce(Sender) + Send + UnwindSafe + 'static,
T: Send + 'static,
{
self.pool.spawn(intent, {
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
index fba5466691289..4ef930e9854ea 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/cli.rs
@@ -43,89 +43,93 @@ mod tests {
expect![[r#"
{"id":2,"type":"vertex","label":"foldingRangeResult","result":[{"startLine":2,"startCharacter":43,"endLine":6,"endCharacter":1},{"startLine":3,"startCharacter":19,"endLine":5,"endCharacter":5},{"startLine":9,"startCharacter":10,"endLine":12,"endCharacter":1}]}
{"id":3,"type":"edge","label":"textDocument/foldingRange","inV":2,"outV":1}
- {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}}
+ {"id":4,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}}
{"id":5,"type":"vertex","label":"resultSet"}
{"id":6,"type":"edge","label":"next","inV":5,"outV":4}
- {"id":7,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}}
+ {"id":7,"type":"vertex","label":"range","start":{"line":0,"character":3},"end":{"line":0,"character":8}}
{"id":8,"type":"vertex","label":"resultSet"}
{"id":9,"type":"edge","label":"next","inV":8,"outV":7}
- {"id":10,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}}
- {"id":11,"type":"edge","label":"next","inV":8,"outV":10}
- {"id":12,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}}
- {"id":13,"type":"vertex","label":"resultSet"}
- {"id":14,"type":"edge","label":"next","inV":13,"outV":12}
- {"id":15,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}}
+ {"id":10,"type":"vertex","label":"range","start":{"line":2,"character":13},"end":{"line":2,"character":43}}
+ {"id":11,"type":"vertex","label":"resultSet"}
+ {"id":12,"type":"edge","label":"next","inV":11,"outV":10}
+ {"id":13,"type":"vertex","label":"range","start":{"line":8,"character":0},"end":{"line":8,"character":30}}
+ {"id":14,"type":"edge","label":"next","inV":11,"outV":13}
+ {"id":15,"type":"vertex","label":"range","start":{"line":8,"character":32},"end":{"line":8,"character":39}}
{"id":16,"type":"vertex","label":"resultSet"}
{"id":17,"type":"edge","label":"next","inV":16,"outV":15}
- {"id":18,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}}
+ {"id":18,"type":"vertex","label":"range","start":{"line":9,"character":4},"end":{"line":9,"character":9}}
{"id":19,"type":"vertex","label":"resultSet"}
{"id":20,"type":"edge","label":"next","inV":19,"outV":18}
- {"id":21,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}}
- {"id":22,"type":"edge","label":"next","inV":8,"outV":21}
- {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}}
- {"id":24,"type":"vertex","label":"resultSet"}
- {"id":25,"type":"edge","label":"next","inV":24,"outV":23}
- {"id":26,"type":"edge","label":"contains","inVs":[4,7,10,12,15,18,21,23],"outV":1}
- {"id":27,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}}
- {"id":28,"type":"edge","label":"textDocument/hover","inV":27,"outV":5}
- {"id":29,"type":"vertex","label":"referenceResult"}
- {"id":30,"type":"edge","label":"textDocument/references","inV":29,"outV":5}
- {"id":31,"type":"edge","label":"item","document":1,"property":"references","inVs":[4],"outV":29}
- {"id":32,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}}
- {"id":33,"type":"edge","label":"textDocument/hover","inV":32,"outV":8}
- {"id":34,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"}
- {"id":35,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"}
- {"id":36,"type":"edge","label":"packageInformation","inV":34,"outV":35}
- {"id":37,"type":"edge","label":"moniker","inV":35,"outV":8}
- {"id":38,"type":"vertex","label":"definitionResult"}
- {"id":39,"type":"edge","label":"item","document":1,"inVs":[7],"outV":38}
- {"id":40,"type":"edge","label":"textDocument/definition","inV":38,"outV":8}
- {"id":41,"type":"vertex","label":"referenceResult"}
- {"id":42,"type":"edge","label":"textDocument/references","inV":41,"outV":8}
- {"id":43,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[7],"outV":41}
- {"id":44,"type":"edge","label":"item","document":1,"property":"references","inVs":[10,21],"outV":41}
- {"id":45,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}}
- {"id":46,"type":"edge","label":"textDocument/hover","inV":45,"outV":13}
- {"id":47,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"}
- {"id":48,"type":"edge","label":"packageInformation","inV":34,"outV":47}
- {"id":49,"type":"edge","label":"moniker","inV":47,"outV":13}
- {"id":50,"type":"vertex","label":"definitionResult"}
- {"id":51,"type":"edge","label":"item","document":1,"inVs":[12],"outV":50}
- {"id":52,"type":"edge","label":"textDocument/definition","inV":50,"outV":13}
- {"id":53,"type":"vertex","label":"referenceResult"}
- {"id":54,"type":"edge","label":"textDocument/references","inV":53,"outV":13}
- {"id":55,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[12],"outV":53}
- {"id":56,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}}
- {"id":57,"type":"edge","label":"textDocument/hover","inV":56,"outV":16}
- {"id":58,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"}
- {"id":59,"type":"edge","label":"packageInformation","inV":34,"outV":58}
- {"id":60,"type":"edge","label":"moniker","inV":58,"outV":16}
- {"id":61,"type":"vertex","label":"definitionResult"}
- {"id":62,"type":"edge","label":"item","document":1,"inVs":[15],"outV":61}
- {"id":63,"type":"edge","label":"textDocument/definition","inV":61,"outV":16}
- {"id":64,"type":"vertex","label":"referenceResult"}
- {"id":65,"type":"edge","label":"textDocument/references","inV":64,"outV":16}
- {"id":66,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":64}
- {"id":67,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}}
- {"id":68,"type":"edge","label":"textDocument/hover","inV":67,"outV":19}
- {"id":69,"type":"vertex","label":"definitionResult"}
- {"id":70,"type":"vertex","label":"range","start":{"line":0,"character":0},"end":{"line":13,"character":0}}
- {"id":71,"type":"edge","label":"contains","inVs":[70],"outV":1}
- {"id":72,"type":"edge","label":"item","document":1,"inVs":[70],"outV":69}
- {"id":73,"type":"edge","label":"textDocument/definition","inV":69,"outV":19}
- {"id":74,"type":"vertex","label":"referenceResult"}
- {"id":75,"type":"edge","label":"textDocument/references","inV":74,"outV":19}
- {"id":76,"type":"edge","label":"item","document":1,"property":"references","inVs":[18],"outV":74}
- {"id":77,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}}
- {"id":78,"type":"edge","label":"textDocument/hover","inV":77,"outV":24}
- {"id":79,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"}
- {"id":80,"type":"edge","label":"packageInformation","inV":34,"outV":79}
- {"id":81,"type":"edge","label":"moniker","inV":79,"outV":24}
- {"id":82,"type":"vertex","label":"definitionResult"}
- {"id":83,"type":"edge","label":"item","document":1,"inVs":[23],"outV":82}
- {"id":84,"type":"edge","label":"textDocument/definition","inV":82,"outV":24}
- {"id":85,"type":"vertex","label":"referenceResult"}
- {"id":86,"type":"edge","label":"textDocument/references","inV":85,"outV":24}
- {"id":87,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[23],"outV":85}
+ {"id":21,"type":"vertex","label":"range","start":{"line":10,"character":8},"end":{"line":10,"character":13}}
+ {"id":22,"type":"edge","label":"next","inV":5,"outV":21}
+ {"id":23,"type":"vertex","label":"range","start":{"line":11,"character":4},"end":{"line":11,"character":34}}
+ {"id":24,"type":"edge","label":"next","inV":11,"outV":23}
+ {"id":25,"type":"vertex","label":"range","start":{"line":11,"character":36},"end":{"line":11,"character":43}}
+ {"id":26,"type":"vertex","label":"resultSet"}
+ {"id":27,"type":"edge","label":"next","inV":26,"outV":25}
+ {"id":28,"type":"edge","label":"contains","inVs":[4,7,10,13,15,18,21,23,25],"outV":1}
+ {"id":29,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nextern crate foo\n```"}}}
+ {"id":30,"type":"edge","label":"textDocument/hover","inV":29,"outV":5}
+ {"id":31,"type":"vertex","label":"packageInformation","name":"foo","manager":"cargo","version":"0.0.0"}
+ {"id":32,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::crate","unique":"scheme","kind":"export"}
+ {"id":33,"type":"edge","label":"packageInformation","inV":31,"outV":32}
+ {"id":34,"type":"edge","label":"moniker","inV":32,"outV":5}
+ {"id":35,"type":"vertex","label":"definitionResult"}
+ {"id":36,"type":"edge","label":"item","document":1,"inVs":[4],"outV":35}
+ {"id":37,"type":"edge","label":"textDocument/definition","inV":35,"outV":5}
+ {"id":38,"type":"vertex","label":"referenceResult"}
+ {"id":39,"type":"edge","label":"textDocument/references","inV":38,"outV":5}
+ {"id":40,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[4],"outV":38}
+ {"id":41,"type":"edge","label":"item","document":1,"property":"references","inVs":[21],"outV":38}
+ {"id":42,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\n#[allow]\n```\n\n---\n\nValid forms are:\n\n* \\#\\[allow(lint1, lint2, ..., /\\*opt\\*/ reason = \"...\")\\]"}}}
+ {"id":43,"type":"edge","label":"textDocument/hover","inV":42,"outV":8}
+ {"id":44,"type":"vertex","label":"referenceResult"}
+ {"id":45,"type":"edge","label":"textDocument/references","inV":44,"outV":8}
+ {"id":46,"type":"edge","label":"item","document":1,"property":"references","inVs":[7],"outV":44}
+ {"id":47,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmacro_rules! generate_const_from_identifier\n```"}}}
+ {"id":48,"type":"edge","label":"textDocument/hover","inV":47,"outV":11}
+ {"id":49,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::generate_const_from_identifier","unique":"scheme","kind":"export"}
+ {"id":50,"type":"edge","label":"packageInformation","inV":31,"outV":49}
+ {"id":51,"type":"edge","label":"moniker","inV":49,"outV":11}
+ {"id":52,"type":"vertex","label":"definitionResult"}
+ {"id":53,"type":"edge","label":"item","document":1,"inVs":[10],"outV":52}
+ {"id":54,"type":"edge","label":"textDocument/definition","inV":52,"outV":11}
+ {"id":55,"type":"vertex","label":"referenceResult"}
+ {"id":56,"type":"edge","label":"textDocument/references","inV":55,"outV":11}
+ {"id":57,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[10],"outV":55}
+ {"id":58,"type":"edge","label":"item","document":1,"property":"references","inVs":[13,23],"outV":55}
+ {"id":59,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nconst REQ_001: &str = \"encoded_data\"\n```"}}}
+ {"id":60,"type":"edge","label":"textDocument/hover","inV":59,"outV":16}
+ {"id":61,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::REQ_001","unique":"scheme","kind":"export"}
+ {"id":62,"type":"edge","label":"packageInformation","inV":31,"outV":61}
+ {"id":63,"type":"edge","label":"moniker","inV":61,"outV":16}
+ {"id":64,"type":"vertex","label":"definitionResult"}
+ {"id":65,"type":"edge","label":"item","document":1,"inVs":[15],"outV":64}
+ {"id":66,"type":"edge","label":"textDocument/definition","inV":64,"outV":16}
+ {"id":67,"type":"vertex","label":"referenceResult"}
+ {"id":68,"type":"edge","label":"textDocument/references","inV":67,"outV":16}
+ {"id":69,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[15],"outV":67}
+ {"id":70,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo\n```\n\n```rust\nmod tests\n```"}}}
+ {"id":71,"type":"edge","label":"textDocument/hover","inV":70,"outV":19}
+ {"id":72,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests","unique":"scheme","kind":"export"}
+ {"id":73,"type":"edge","label":"packageInformation","inV":31,"outV":72}
+ {"id":74,"type":"edge","label":"moniker","inV":72,"outV":19}
+ {"id":75,"type":"vertex","label":"definitionResult"}
+ {"id":76,"type":"edge","label":"item","document":1,"inVs":[18],"outV":75}
+ {"id":77,"type":"edge","label":"textDocument/definition","inV":75,"outV":19}
+ {"id":78,"type":"vertex","label":"referenceResult"}
+ {"id":79,"type":"edge","label":"textDocument/references","inV":78,"outV":19}
+ {"id":80,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[18],"outV":78}
+ {"id":81,"type":"vertex","label":"hoverResult","result":{"contents":{"kind":"markdown","value":"\n```rust\nfoo::tests\n```\n\n```rust\nconst REQ_002: &str = \"encoded_data\"\n```"}}}
+ {"id":82,"type":"edge","label":"textDocument/hover","inV":81,"outV":26}
+ {"id":83,"type":"vertex","label":"moniker","scheme":"rust-analyzer","identifier":"foo::tests::REQ_002","unique":"scheme","kind":"export"}
+ {"id":84,"type":"edge","label":"packageInformation","inV":31,"outV":83}
+ {"id":85,"type":"edge","label":"moniker","inV":83,"outV":26}
+ {"id":86,"type":"vertex","label":"definitionResult"}
+ {"id":87,"type":"edge","label":"item","document":1,"inVs":[25],"outV":86}
+ {"id":88,"type":"edge","label":"textDocument/definition","inV":86,"outV":26}
+ {"id":89,"type":"vertex","label":"referenceResult"}
+ {"id":90,"type":"edge","label":"textDocument/references","inV":89,"outV":26}
+ {"id":91,"type":"edge","label":"item","document":1,"property":"definitions","inVs":[25],"outV":89}
"#]].assert_eq(stdout);
}
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
index d113bd512789a..409be2894fea7 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/tests/slow-tests/testdir.rs
@@ -43,10 +43,15 @@ impl TestDir {
}
fs::create_dir_all(&path).unwrap();
- #[cfg(any(target_os = "macos", target_os = "linux", target_os = "windows"))]
+ #[cfg(any(
+ target_os = "macos",
+ target_os = "linux",
+ target_os = "windows",
+ target_os = "freebsd"
+ ))]
if symlink {
let symlink_path = base.join(format!("{pid}_{cnt}_symlink"));
- #[cfg(any(target_os = "macos", target_os = "linux"))]
+ #[cfg(any(target_os = "macos", target_os = "linux", target_os = "freebsd"))]
std::os::unix::fs::symlink(path, &symlink_path).unwrap();
#[cfg(target_os = "windows")]
diff --git a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
index 2ddd7da74c291..9acc1de922af9 100644
--- a/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
+++ b/src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs
@@ -7,9 +7,12 @@
//! The thread pool is implemented entirely using
//! the threading utilities in [`crate::thread`].
-use std::sync::{
- atomic::{AtomicUsize, Ordering},
- Arc,
+use std::{
+ panic::{self, UnwindSafe},
+ sync::{
+ atomic::{AtomicUsize, Ordering},
+ Arc,
+ },
};
use crossbeam_channel::{Receiver, Sender};
@@ -25,13 +28,13 @@ pub struct Pool {
// so that the channel is actually closed
// before we join the worker threads!
job_sender: Sender,
- _handles: Vec,
+ _handles: Box<[JoinHandle]>,
extant_tasks: Arc,
}
struct Job {
requested_intent: ThreadIntent,
- f: Box,
+ f: Box,
}
impl Pool {
@@ -47,6 +50,7 @@ impl Pool {
let handle = Builder::new(INITIAL_INTENT)
.stack_size(STACK_SIZE)
.name("Worker".into())
+ .allow_leak(true)
.spawn({
let extant_tasks = Arc::clone(&extant_tasks);
let job_receiver: Receiver = job_receiver.clone();
@@ -58,7 +62,8 @@ impl Pool {
current_intent = job.requested_intent;
}
extant_tasks.fetch_add(1, Ordering::SeqCst);
- (job.f)();
+ // discard the panic, we should've logged the backtrace already
+ _ = panic::catch_unwind(job.f);
extant_tasks.fetch_sub(1, Ordering::SeqCst);
}
}
@@ -68,12 +73,12 @@ impl Pool {
handles.push(handle);
}
- Pool { _handles: handles, extant_tasks, job_sender }
+ Pool { _handles: handles.into_boxed_slice(), extant_tasks, job_sender }
}
pub fn spawn(&self, intent: ThreadIntent, f: F)
where
- F: FnOnce() + Send + 'static,
+ F: FnOnce() + Send + UnwindSafe + 'static,
{
let f = Box::new(move || {
if cfg!(debug_assertions) {
diff --git a/src/tools/rust-analyzer/crates/syntax/rust.ungram b/src/tools/rust-analyzer/crates/syntax/rust.ungram
index 4e2a70d6cd917..bbb8413cbc080 100644
--- a/src/tools/rust-analyzer/crates/syntax/rust.ungram
+++ b/src/tools/rust-analyzer/crates/syntax/rust.ungram
@@ -241,7 +241,7 @@ RecordFieldList =
RecordField =
Attr* Visibility?
- Name ':' Type
+ Name ':' Type ('=' Expr)?
TupleFieldList =
'(' fields:(TupleField (',' TupleField)* ','?)? ')'
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
index 69e2a9f9c1b22..58c76a456ab10 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs
@@ -1,4 +1,4 @@
-//! Generated by `cargo codegen grammar`, do not edit by hand.
+//! Generated by `cargo xtask codegen grammar`, do not edit by hand.
#![allow(non_snake_case)]
use crate::{
@@ -1538,10 +1538,14 @@ impl ast::HasDocComments for RecordField {}
impl ast::HasName for RecordField {}
impl ast::HasVisibility for RecordField {}
impl RecordField {
+ #[inline]
+ pub fn expr(&self) -> Option { support::child(&self.syntax) }
#[inline]
pub fn ty(&self) -> Option { support::child(&self.syntax) }
#[inline]
pub fn colon_token(&self) -> Option { support::token(&self.syntax, T![:]) }
+ #[inline]
+ pub fn eq_token(&self) -> Option