authorbors <bors@rust-lang.org> 2025-12-31 18:42:17 UTC
committerbors <bors@rust-lang.org> 2025-12-31 18:42:17 UTC
log8d670b93d40737e1b320fd892c6f169ffa35e49e
tree5fed883320ab985956d875eb3e3aa568bc1eda34
parenta2bc948b7fff08ef1318747e3f4470f54f8a1694
parent552918bfcd826a9d035e2f22a491f1c636cee82b

Auto merge of #150546 - JonathanBrouwer:rollup-jkqji1j, r=JonathanBrouwer

Rollup of 5 pull requests Successful merges: - rust-lang/rust#146798 (RISC-V: Implement (Zkne or Zknd) intrinsics correctly) - rust-lang/rust#150337 (docs: fix typo in std::io::buffered) - rust-lang/rust#150530 (Remove `feature(string_deref_patterns)`) - rust-lang/rust#150543 (`rust-analyzer` subtree update) - rust-lang/rust#150544 (Use --print target-libdir in run-make tests) r? `@ghost` `@rustbot` modify labels: rollup

238 files changed, 8013 insertions(+), 3230 deletions(-)

compiler/rustc_codegen_llvm/src/llvm_util.rs+5
......@@ -262,6 +262,11 @@ pub(crate) fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> Option<LLVMFea
262262 "power8-crypto" => Some(LLVMFeature::new("crypto")),
263263 s => Some(LLVMFeature::new(s)),
264264 },
265 Arch::RiscV32 | Arch::RiscV64 => match s {
266 // Filter out Rust-specific *virtual* target feature
267 "zkne_or_zknd" => None,
268 s => Some(LLVMFeature::new(s)),
269 },
265270 Arch::Sparc | Arch::Sparc64 => match s {
266271 "leoncasa" => Some(LLVMFeature::new("hasleoncasa")),
267272 s => Some(LLVMFeature::new(s)),
compiler/rustc_feature/src/removed.rs+2
......@@ -271,6 +271,8 @@ declare_features! (
271271 /// Allows `#[link(kind = "static-nobundle", ...)]`.
272272 (removed, static_nobundle, "1.63.0", Some(37403),
273273 Some(r#"subsumed by `#[link(kind = "static", modifiers = "-bundle", ...)]`"#), 95818),
274 /// Allows string patterns to dereference values to match them.
275 (removed, string_deref_patterns, "CURRENT_RUSTC_VERSION", Some(87121), Some("superseded by `deref_patterns`"), 150530),
274276 (removed, struct_inherit, "1.0.0", None, None),
275277 (removed, test_removed_feature, "1.0.0", None, None),
276278 /// Allows using items which are missing stability attributes
compiler/rustc_feature/src/unstable.rs-2
......@@ -647,8 +647,6 @@ declare_features! (
647647 (unstable, stmt_expr_attributes, "1.6.0", Some(15701)),
648648 /// Allows lints part of the strict provenance effort.
649649 (unstable, strict_provenance_lints, "1.61.0", Some(130351)),
650 /// Allows string patterns to dereference values to match them.
651 (unstable, string_deref_patterns, "1.67.0", Some(87121)),
652650 /// Allows `super let` statements.
653651 (unstable, super_let, "1.88.0", Some(139076)),
654652 /// Allows subtrait items to shadow supertrait items.
compiler/rustc_hir_typeck/src/pat.rs-14
......@@ -996,20 +996,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
996996 pat_ty = self.tcx.types.str_;
997997 }
998998
999 if self.tcx.features().string_deref_patterns()
1000 && let hir::PatExprKind::Lit {
1001 lit: Spanned { node: ast::LitKind::Str(..), .. }, ..
1002 } = lt.kind
1003 {
1004 let tcx = self.tcx;
1005 let expected = self.resolve_vars_if_possible(expected);
1006 pat_ty = match expected.kind() {
1007 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => expected,
1008 ty::Str => Ty::new_static_str(tcx),
1009 _ => pat_ty,
1010 };
1011 }
1012
1013999 // Somewhat surprising: in this case, the subtyping relation goes the
10141000 // opposite way as the other cases. Actually what we really want is not
10151001 // a subtyping relation at all but rather that there exists a LUB
compiler/rustc_middle/src/thir.rs-1
......@@ -827,7 +827,6 @@ pub enum PatKind<'tcx> {
827827 /// much simpler.
828828 /// * raw pointers derived from integers, other raw pointers will have already resulted in an
829829 /// error.
830 /// * `String`, if `string_deref_patterns` is enabled.
831830 Constant {
832831 value: ty::Value<'tcx>,
833832 },
compiler/rustc_mir_build/src/builder/matches/test.rs+1-29
......@@ -150,7 +150,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
150150 let mut expect = self.literal_operand(test.span, Const::from_ty_value(tcx, value));
151151
152152 let mut place = place;
153 let mut block = block;
153
154154 match cast_ty.kind() {
155155 ty::Str => {
156156 // String literal patterns may have type `str` if `deref_patterns` is
......@@ -175,34 +175,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
175175 place = ref_place;
176176 cast_ty = ref_str_ty;
177177 }
178 ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
179 if !tcx.features().string_deref_patterns() {
180 span_bug!(
181 test.span,
182 "matching on `String` went through without enabling string_deref_patterns"
183 );
184 }
185 let re_erased = tcx.lifetimes.re_erased;
186 let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
187 let ref_str = self.temp(ref_str_ty, test.span);
188 let eq_block = self.cfg.start_new_block();
189 // `let ref_str: &str = <String as Deref>::deref(&place);`
190 self.call_deref(
191 block,
192 eq_block,
193 place,
194 Mutability::Not,
195 cast_ty,
196 ref_str,
197 test.span,
198 );
199 // Since we generated a `ref_str = <String as Deref>::deref(&place) -> eq_block` terminator,
200 // we need to add all further statements to `eq_block`.
201 // Similarly, the normal test code should be generated for the `&str`, instead of the `String`.
202 block = eq_block;
203 place = ref_str;
204 cast_ty = ref_str_ty;
205 }
206178 &ty::Pat(base, _) => {
207179 assert_eq!(cast_ty, value.ty);
208180 assert!(base.is_trivially_pure_clone_copy());
compiler/rustc_mir_build/src/thir/pattern/mod.rs+1-17
......@@ -11,7 +11,7 @@ use rustc_abi::{FieldIdx, Integer};
1111use rustc_errors::codes::*;
1212use rustc_hir::def::{CtorOf, DefKind, Res};
1313use rustc_hir::pat_util::EnumerateAndAdjustIterator;
14use rustc_hir::{self as hir, LangItem, RangeEnd};
14use rustc_hir::{self as hir, RangeEnd};
1515use rustc_index::Idx;
1616use rustc_middle::mir::interpret::LitToConstInput;
1717use rustc_middle::thir::{
......@@ -626,23 +626,7 @@ impl<'tcx> PatCtxt<'tcx> {
626626 // the pattern's type will be `&[u8]` whereas the literal's type is `&[u8; 3]`; using the
627627 // pattern's type means we'll properly translate it to a slice reference pattern. This works
628628 // because slices and arrays have the same valtree representation.
629 // HACK: As an exception, use the literal's type if `pat_ty` is `String`; this can happen if
630 // `string_deref_patterns` is enabled. There's a special case for that when lowering to MIR.
631 // FIXME(deref_patterns): This hack won't be necessary once `string_deref_patterns` is
632 // superseded by a more general implementation of deref patterns.
633629 let ct_ty = match pat_ty {
634 Some(pat_ty)
635 if let ty::Adt(def, _) = *pat_ty.kind()
636 && self.tcx.is_lang_item(def.did(), LangItem::String) =>
637 {
638 if !self.tcx.features().string_deref_patterns() {
639 span_bug!(
640 expr.span,
641 "matching on `String` went through without enabling string_deref_patterns"
642 );
643 }
644 self.typeck_results.node_type(expr.hir_id)
645 }
646630 Some(pat_ty) => pat_ty,
647631 None => self.typeck_results.node_type(expr.hir_id),
648632 };
compiler/rustc_target/src/target_features.rs+3-2
......@@ -690,8 +690,9 @@ static RISCV_FEATURES: &[(&str, Stability, ImpliedFeatures)] = &[
690690 ("zimop", Unstable(sym::riscv_target_feature), &[]),
691691 ("zk", Stable, &["zkn", "zkr", "zkt"]),
692692 ("zkn", Stable, &["zbkb", "zbkc", "zbkx", "zkne", "zknd", "zknh"]),
693 ("zknd", Stable, &[]),
694 ("zkne", Stable, &[]),
693 ("zknd", Stable, &["zkne_or_zknd"]),
694 ("zkne", Stable, &["zkne_or_zknd"]),
695 ("zkne_or_zknd", Unstable(sym::riscv_target_feature), &[]), // Not an extension
695696 ("zknh", Stable, &[]),
696697 ("zkr", Stable, &[]),
697698 ("zks", Stable, &["zbkb", "zbkc", "zbkx", "zksed", "zksh"]),
library/std/src/io/buffered/bufreader/buffer.rs+1-1
......@@ -48,7 +48,7 @@ impl Buffer {
4848
4949 #[inline]
5050 pub fn buffer(&self) -> &[u8] {
51 // SAFETY: self.pos and self.cap are valid, and self.cap => self.pos, and
51 // SAFETY: self.pos and self.filled are valid, and self.filled >= self.pos, and
5252 // that region is initialized because those are all invariants of this type.
5353 unsafe { self.buf.get_unchecked(self.pos..self.filled).assume_init_ref() }
5454 }
library/std/src/io/buffered/linewritershim.rs+3-3
......@@ -52,7 +52,7 @@ impl<'a, W: ?Sized + Write> LineWriterShim<'a, W> {
5252}
5353
5454impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
55 /// Writes some data into this BufReader with line buffering.
55 /// Writes some data into this BufWriter with line buffering.
5656 ///
5757 /// This means that, if any newlines are present in the data, the data up to
5858 /// the last newline is sent directly to the underlying writer, and data
......@@ -146,7 +146,7 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
146146 self.buffer.flush()
147147 }
148148
149 /// Writes some vectored data into this BufReader with line buffering.
149 /// Writes some vectored data into this BufWriter with line buffering.
150150 ///
151151 /// This means that, if any newlines are present in the data, the data up to
152152 /// and including the buffer containing the last newline is sent directly to
......@@ -256,7 +256,7 @@ impl<'a, W: ?Sized + Write> Write for LineWriterShim<'a, W> {
256256 self.inner().is_write_vectored()
257257 }
258258
259 /// Writes some data into this BufReader with line buffering.
259 /// Writes some data into this BufWriter with line buffering.
260260 ///
261261 /// This means that, if any newlines are present in the data, the data up to
262262 /// the last newline is sent directly to the underlying writer, and data
library/stdarch/crates/core_arch/src/riscv64/zk.rs+32-13
......@@ -1,6 +1,8 @@
11#[cfg(test)]
22use stdarch_test::assert_instr;
33
4use crate::arch::asm;
5
46unsafe extern "unadjusted" {
57 #[link_name = "llvm.riscv.aes64es"]
68 fn _aes64es(rs1: i64, rs2: i64) -> i64;
......@@ -14,12 +16,6 @@ unsafe extern "unadjusted" {
1416 #[link_name = "llvm.riscv.aes64dsm"]
1517 fn _aes64dsm(rs1: i64, rs2: i64) -> i64;
1618
17 #[link_name = "llvm.riscv.aes64ks1i"]
18 fn _aes64ks1i(rs1: i64, rnum: i32) -> i64;
19
20 #[link_name = "llvm.riscv.aes64ks2"]
21 fn _aes64ks2(rs1: i64, rs2: i64) -> i64;
22
2319 #[link_name = "llvm.riscv.aes64im"]
2420 fn _aes64im(rs1: i64) -> i64;
2521
......@@ -133,15 +129,26 @@ pub fn aes64dsm(rs1: u64, rs2: u64) -> u64 {
133129/// # Note
134130///
135131/// The `RNUM` parameter is expected to be a constant value inside the range of `0..=10`.
136#[target_feature(enable = "zkne", enable = "zknd")]
132#[target_feature(enable = "zkne_or_zknd")]
137133#[rustc_legacy_const_generics(1)]
138#[cfg_attr(test, assert_instr(aes64ks1i, RNUM = 0))]
139134#[inline]
140135#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
141136pub fn aes64ks1i<const RNUM: u8>(rs1: u64) -> u64 {
142137 static_assert!(RNUM <= 10);
143
144 unsafe { _aes64ks1i(rs1 as i64, RNUM as i32) as u64 }
138 unsafe {
139 let rd: u64;
140 asm!(
141 ".option push",
142 ".option arch, +zkne",
143 "aes64ks1i {}, {}, {}",
144 ".option pop",
145 lateout(reg) rd,
146 in(reg) rs1,
147 const RNUM,
148 options(pure, nomem, nostack, preserves_flags)
149 );
150 rd
151 }
145152}
146153
147154/// This instruction implements part of the KeySchedule operation for the AES Block cipher.
......@@ -155,12 +162,24 @@ pub fn aes64ks1i<const RNUM: u8>(rs1: u64) -> u64 {
155162/// Version: v1.0.1
156163///
157164/// Section: 3.11
158#[target_feature(enable = "zkne", enable = "zknd")]
159#[cfg_attr(test, assert_instr(aes64ks2))]
165#[target_feature(enable = "zkne_or_zknd")]
160166#[inline]
161167#[unstable(feature = "riscv_ext_intrinsics", issue = "114544")]
162168pub fn aes64ks2(rs1: u64, rs2: u64) -> u64 {
163 unsafe { _aes64ks2(rs1 as i64, rs2 as i64) as u64 }
169 unsafe {
170 let rd: u64;
171 asm!(
172 ".option push",
173 ".option arch, +zkne",
174 "aes64ks2 {}, {}, {}",
175 ".option pop",
176 lateout(reg) rd,
177 in(reg) rs1,
178 in(reg) rs2,
179 options(pure, nomem, nostack, preserves_flags)
180 );
181 rd
182 }
164183}
165184
166185/// This instruction accelerates the inverse MixColumns step of the AES Block Cipher, and is used to aid creation of
src/doc/unstable-book/src/language-features/deref-patterns.md+1-2
......@@ -7,7 +7,7 @@ The tracking issue for this feature is: [#87121]
77------------------------
88
99> **Note**: This feature is incomplete. In the future, it is meant to supersede
10> [`box_patterns`] and [`string_deref_patterns`].
10> [`box_patterns`].
1111
1212This feature permits pattern matching on [smart pointers in the standard library] through their
1313`Deref` target types, either implicitly or with explicit `deref!(_)` patterns (the syntax of which
......@@ -103,5 +103,4 @@ match *(b"test" as &[u8]) {
103103```
104104
105105[`box_patterns`]: ./box-patterns.md
106[`string_deref_patterns`]: ./string-deref-patterns.md
107106[smart pointers in the standard library]: https://doc.rust-lang.org/std/ops/trait.DerefPure.html#implementors
src/doc/unstable-book/src/language-features/string-deref-patterns.md deleted-48
......@@ -1,48 +0,0 @@
1# `string_deref_patterns`
2
3The tracking issue for this feature is: [#87121]
4
5[#87121]: https://github.com/rust-lang/rust/issues/87121
6
7------------------------
8
9> **Note**: This feature will be superseded by [`deref_patterns`] in the future.
10
11This feature permits pattern matching `String` to `&str` through [its `Deref` implementation].
12
13```rust
14#![feature(string_deref_patterns)]
15
16pub enum Value {
17 String(String),
18 Number(u32),
19}
20
21pub fn is_it_the_answer(value: Value) -> bool {
22 match value {
23 Value::String("42") => true,
24 Value::Number(42) => true,
25 _ => false,
26 }
27}
28```
29
30Without this feature other constructs such as match guards have to be used.
31
32```rust
33# pub enum Value {
34# String(String),
35# Number(u32),
36# }
37#
38pub fn is_it_the_answer(value: Value) -> bool {
39 match value {
40 Value::String(s) if s == "42" => true,
41 Value::Number(42) => true,
42 _ => false,
43 }
44}
45```
46
47[`deref_patterns`]: ./deref-patterns.md
48[its `Deref` implementation]: https://doc.rust-lang.org/std/string/struct.String.html#impl-Deref-for-String
src/tools/rust-analyzer/.github/workflows/ci.yaml+6
......@@ -122,6 +122,12 @@ jobs:
122122 - name: Run tests
123123 run: cargo nextest run --no-fail-fast --hide-progress-bar --status-level fail
124124
125 - name: Install cargo-machete
126 uses: taiki-e/install-action@cargo-machete
127
128 - name: Run cargo-machete
129 run: cargo machete
130
125131 - name: Run Clippy
126132 if: matrix.os == 'macos-latest'
127133 run: cargo clippy --all-targets -- -D clippy::disallowed_macros -D clippy::dbg_macro -D clippy::todo -D clippy::print_stdout -D clippy::print_stderr
src/tools/rust-analyzer/CONTRIBUTING.md+1-1
......@@ -38,6 +38,6 @@ considered accepted feel free to just drop a comment and ask!
3838
3939AI tool use is not discouraged on the rust-analyzer codebase, as long as it meets our quality standards.
4040We kindly ask you to disclose usage of AI tools in your contributions.
41If you used them without disclosing it, we may reject your contribution on that basis alone due to the assumption that you likely not reviewed your own submission (so why should we?).
41If you used them without disclosing it, we may reject your contribution on that basis alone due to the assumption that you have, most likely, not reviewed your own submission (so why should we?).
4242
4343We may still reject AI-assisted contributions if we deem the quality of the contribution to be unsatisfactory as to reduce impact on the team's review budget.
src/tools/rust-analyzer/Cargo.lock+4-4
......@@ -234,6 +234,7 @@ dependencies = [
234234 "intern",
235235 "oorandom",
236236 "rustc-hash 2.1.1",
237 "span",
237238 "syntax",
238239 "syntax-bridge",
239240 "tracing",
......@@ -821,7 +822,6 @@ dependencies = [
821822 "intern",
822823 "itertools 0.14.0",
823824 "la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
824 "mbe",
825825 "query-group-macro",
826826 "ra-ap-rustc_abi",
827827 "ra-ap-rustc_parse_format",
......@@ -1219,7 +1219,6 @@ dependencies = [
12191219 "hashbrown 0.14.5",
12201220 "rayon",
12211221 "rustc-hash 2.1.1",
1222 "smallvec",
12231222 "triomphe",
12241223]
12251224
......@@ -1882,7 +1881,6 @@ dependencies = [
18821881 "postcard",
18831882 "proc-macro-api",
18841883 "proc-macro-srv",
1885 "tt",
18861884]
18871885
18881886[[package]]
......@@ -2782,7 +2780,6 @@ dependencies = [
27822780 "hir-expand",
27832781 "intern",
27842782 "paths",
2785 "rustc-hash 2.1.1",
27862783 "span",
27872784 "stdx",
27882785 "test-utils",
......@@ -3088,8 +3085,11 @@ name = "tt"
30883085version = "0.0.0"
30893086dependencies = [
30903087 "arrayvec",
3088 "indexmap",
30913089 "intern",
30923090 "ra-ap-rustc_lexer",
3091 "rustc-hash 2.1.1",
3092 "span",
30933093 "stdx",
30943094 "text-size 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
30953095]
src/tools/rust-analyzer/crates/base-db/src/change.rs+14-2
......@@ -3,11 +3,14 @@
33
44use std::fmt;
55
6use salsa::Durability;
6use rustc_hash::FxHashSet;
7use salsa::{Durability, Setter as _};
78use triomphe::Arc;
89use vfs::FileId;
910
10use crate::{CrateGraphBuilder, CratesIdMap, RootQueryDb, SourceRoot, SourceRootId};
11use crate::{
12 CrateGraphBuilder, CratesIdMap, LibraryRoots, LocalRoots, RootQueryDb, SourceRoot, SourceRootId,
13};
1114
1215/// Encapsulate a bunch of raw `.set` calls on the database.
1316#[derive(Default)]
......@@ -49,8 +52,15 @@ impl FileChange {
4952 pub fn apply(self, db: &mut dyn RootQueryDb) -> Option<CratesIdMap> {
5053 let _p = tracing::info_span!("FileChange::apply").entered();
5154 if let Some(roots) = self.roots {
55 let mut local_roots = FxHashSet::default();
56 let mut library_roots = FxHashSet::default();
5257 for (idx, root) in roots.into_iter().enumerate() {
5358 let root_id = SourceRootId(idx as u32);
59 if root.is_library {
60 library_roots.insert(root_id);
61 } else {
62 local_roots.insert(root_id);
63 }
5464 let durability = source_root_durability(&root);
5565 for file_id in root.iter() {
5666 db.set_file_source_root_with_durability(file_id, root_id, durability);
......@@ -58,6 +68,8 @@ impl FileChange {
5868
5969 db.set_source_root_with_durability(root_id, Arc::new(root), durability);
6070 }
71 LocalRoots::get(db).set_roots(db).to(local_roots);
72 LibraryRoots::get(db).set_roots(db).to(library_roots);
6173 }
6274
6375 for (file_id, text) in self.files_changed {
src/tools/rust-analyzer/crates/base-db/src/lib.rs+17-1
......@@ -33,7 +33,7 @@ pub use crate::{
3333};
3434use dashmap::{DashMap, mapref::entry::Entry};
3535pub use query_group::{self};
36use rustc_hash::FxHasher;
36use rustc_hash::{FxHashSet, FxHasher};
3737use salsa::{Durability, Setter};
3838pub use semver::{BuildMetadata, Prerelease, Version, VersionReq};
3939use syntax::{Parse, SyntaxError, ast};
......@@ -203,6 +203,22 @@ impl Files {
203203 }
204204}
205205
206/// The set of roots for crates.io libraries.
207/// Files in libraries are assumed to never change.
208#[salsa::input(singleton, debug)]
209pub struct LibraryRoots {
210 #[returns(ref)]
211 pub roots: FxHashSet<SourceRootId>,
212}
213
214/// The set of "local" (that is, from the current workspace) roots.
215/// Files in local roots are assumed to change frequently.
216#[salsa::input(singleton, debug)]
217pub struct LocalRoots {
218 #[returns(ref)]
219 pub roots: FxHashSet<SourceRootId>,
220}
221
206222#[salsa_macros::input(debug)]
207223pub struct FileText {
208224 #[returns(ref)]
src/tools/rust-analyzer/crates/cfg/Cargo.toml+3
......@@ -19,6 +19,7 @@ tracing.workspace = true
1919# locals deps
2020tt = { workspace = true, optional = true }
2121syntax = { workspace = true, optional = true }
22span = { path = "../span", version = "0.0", optional = true }
2223intern.workspace = true
2324
2425[dev-dependencies]
......@@ -35,6 +36,8 @@ cfg = { path = ".", default-features = false, features = ["tt"] }
3536
3637[features]
3738default = []
39syntax = ["dep:syntax", "dep:span"]
40tt = ["dep:tt"]
3841in-rust-tree = []
3942
4043[lints]
src/tools/rust-analyzer/crates/cfg/src/cfg_expr.rs+20-10
......@@ -96,12 +96,12 @@ impl CfgExpr {
9696 // FIXME: Parsing from `tt` is only used in a handful of places, reconsider
9797 // if we should switch them to AST.
9898 #[cfg(feature = "tt")]
99 pub fn parse<S: Copy>(tt: &tt::TopSubtree<S>) -> CfgExpr {
99 pub fn parse(tt: &tt::TopSubtree) -> CfgExpr {
100100 next_cfg_expr(&mut tt.iter()).unwrap_or(CfgExpr::Invalid)
101101 }
102102
103103 #[cfg(feature = "tt")]
104 pub fn parse_from_iter<S: Copy>(tt: &mut tt::iter::TtIter<'_, S>) -> CfgExpr {
104 pub fn parse_from_iter(tt: &mut tt::iter::TtIter<'_>) -> CfgExpr {
105105 next_cfg_expr(tt).unwrap_or(CfgExpr::Invalid)
106106 }
107107
......@@ -149,7 +149,16 @@ fn next_cfg_expr_from_ast(
149149 if let Some(NodeOrToken::Token(literal)) = it.peek()
150150 && matches!(literal.kind(), SyntaxKind::STRING)
151151 {
152 let literal = tt::token_to_literal(literal.text(), ()).symbol;
152 let dummy_span = span::Span {
153 range: span::TextRange::empty(span::TextSize::new(0)),
154 anchor: span::SpanAnchor {
155 file_id: span::EditionedFileId::from_raw(0),
156 ast_id: span::FIXUP_ERASED_FILE_AST_ID_MARKER,
157 },
158 ctx: span::SyntaxContext::root(span::Edition::Edition2015),
159 };
160 let literal =
161 Symbol::intern(tt::token_to_literal(literal.text(), dummy_span).text());
153162 it.next();
154163 CfgAtom::KeyValue { key: name, value: literal.clone() }.into()
155164 } else {
......@@ -179,7 +188,7 @@ fn next_cfg_expr_from_ast(
179188}
180189
181190#[cfg(feature = "tt")]
182fn next_cfg_expr<S: Copy>(it: &mut tt::iter::TtIter<'_, S>) -> Option<CfgExpr> {
191fn next_cfg_expr(it: &mut tt::iter::TtIter<'_>) -> Option<CfgExpr> {
183192 use intern::sym;
184193 use tt::iter::TtElement;
185194
......@@ -189,20 +198,21 @@ fn next_cfg_expr<S: Copy>(it: &mut tt::iter::TtIter<'_, S>) -> Option<CfgExpr> {
189198 Some(_) => return Some(CfgExpr::Invalid),
190199 };
191200
192 let ret = match it.peek() {
201 let mut it_clone = it.clone();
202 let ret = match it_clone.next() {
193203 Some(TtElement::Leaf(tt::Leaf::Punct(punct)))
194204 // Don't consume on e.g. `=>`.
195205 if punct.char == '='
196206 && (punct.spacing == tt::Spacing::Alone
197 || it.remaining().flat_tokens().get(1).is_none_or(|peek2| {
198 !matches!(peek2, tt::TokenTree::Leaf(tt::Leaf::Punct(_)))
207 || it_clone.peek().is_none_or(|peek2| {
208 !matches!(peek2, tt::TtElement::Leaf(tt::Leaf::Punct(_)))
199209 })) =>
200210 {
201 match it.remaining().flat_tokens().get(1) {
202 Some(tt::TokenTree::Leaf(tt::Leaf::Literal(literal))) => {
211 match it_clone.next() {
212 Some(tt::TtElement::Leaf(tt::Leaf::Literal(literal))) => {
203213 it.next();
204214 it.next();
205 CfgAtom::KeyValue { key: name, value: literal.symbol.clone() }.into()
215 CfgAtom::KeyValue { key: name, value: Symbol::intern(literal.text()) }.into()
206216 }
207217 _ => return Some(CfgExpr::Invalid),
208218 }
src/tools/rust-analyzer/crates/hir-def/Cargo.toml-1
......@@ -40,7 +40,6 @@ intern.workspace = true
4040base-db.workspace = true
4141syntax.workspace = true
4242hir-expand.workspace = true
43mbe.workspace = true
4443cfg.workspace = true
4544tt.workspace = true
4645span.workspace = true
src/tools/rust-analyzer/crates/hir-def/src/attrs.rs+21
......@@ -99,6 +99,20 @@ fn extract_ra_completions(attr_flags: &mut AttrFlags, tt: ast::TokenTree) {
9999 }
100100}
101101
102fn extract_ra_macro_style(attr_flags: &mut AttrFlags, tt: ast::TokenTree) {
103 let tt = TokenTreeChildren::new(&tt);
104 if let Ok(NodeOrToken::Token(option)) = Itertools::exactly_one(tt)
105 && option.kind().is_any_identifier()
106 {
107 match option.text() {
108 "braces" => attr_flags.insert(AttrFlags::MACRO_STYLE_BRACES),
109 "brackets" => attr_flags.insert(AttrFlags::MACRO_STYLE_BRACKETS),
110 "parentheses" => attr_flags.insert(AttrFlags::MACRO_STYLE_PARENTHESES),
111 _ => {}
112 }
113 }
114}
115
102116fn extract_rustc_skip_during_method_dispatch(attr_flags: &mut AttrFlags, tt: ast::TokenTree) {
103117 let iter = TokenTreeChildren::new(&tt);
104118 for kind in iter {
......@@ -163,6 +177,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal
163177 2 => match path.segments[0].text() {
164178 "rust_analyzer" => match path.segments[1].text() {
165179 "completions" => extract_ra_completions(attr_flags, tt),
180 "macro_style" => extract_ra_macro_style(attr_flags, tt),
166181 _ => {}
167182 },
168183 _ => {}
......@@ -188,6 +203,7 @@ fn match_attr_flags(attr_flags: &mut AttrFlags, attr: Meta) -> ControlFlow<Infal
188203 "deprecated" => attr_flags.insert(AttrFlags::IS_DEPRECATED),
189204 "macro_export" => attr_flags.insert(AttrFlags::IS_MACRO_EXPORT),
190205 "no_mangle" => attr_flags.insert(AttrFlags::NO_MANGLE),
206 "pointee" => attr_flags.insert(AttrFlags::IS_POINTEE),
191207 "non_exhaustive" => attr_flags.insert(AttrFlags::NON_EXHAUSTIVE),
192208 "ignore" => attr_flags.insert(AttrFlags::IS_IGNORE),
193209 "bench" => attr_flags.insert(AttrFlags::IS_BENCH),
......@@ -289,6 +305,11 @@ bitflags::bitflags! {
289305 const RUSTC_PAREN_SUGAR = 1 << 42;
290306 const RUSTC_COINDUCTIVE = 1 << 43;
291307 const RUSTC_FORCE_INLINE = 1 << 44;
308 const IS_POINTEE = 1 << 45;
309
310 const MACRO_STYLE_BRACES = 1 << 46;
311 const MACRO_STYLE_BRACKETS = 1 << 47;
312 const MACRO_STYLE_PARENTHESES = 1 << 48;
292313 }
293314}
294315
src/tools/rust-analyzer/crates/hir-def/src/builtin_derive.rs created+149
......@@ -0,0 +1,149 @@
1//! Definition of builtin derive impls.
2//!
3//! To save time and memory, builtin derives are not really expanded. Instead, we record them
4//! and create their impls based on lowered data, see crates/hir-ty/src/builtin_derive.rs.
5
6use hir_expand::{InFile, builtin::BuiltinDeriveExpander, name::Name};
7use intern::{Symbol, sym};
8use tt::TextRange;
9
10use crate::{
11 AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, FunctionId, HasModule, db::DefDatabase,
12};
13
14macro_rules! declare_enum {
15 ( $( $trait:ident => [ $( $method:ident ),* ] ),* $(,)? ) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub enum BuiltinDeriveImplTrait {
18 $( $trait, )*
19 }
20
21 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
22 #[allow(non_camel_case_types)]
23 pub enum BuiltinDeriveImplMethod {
24 $( $( $method, )* )*
25 }
26
27 impl BuiltinDeriveImplTrait {
28 #[inline]
29 pub fn name(self) -> Symbol {
30 match self {
31 $( Self::$trait => sym::$trait, )*
32 }
33 }
34
35 #[inline]
36 pub fn get_id(self, lang_items: &crate::lang_item::LangItems) -> Option<crate::TraitId> {
37 match self {
38 $( Self::$trait => lang_items.$trait, )*
39 }
40 }
41
42 #[inline]
43 pub fn get_method(self, method_name: &Symbol) -> Option<BuiltinDeriveImplMethod> {
44 match self {
45 $(
46 Self::$trait => {
47 match method_name {
48 $( _ if *method_name == sym::$method => Some(BuiltinDeriveImplMethod::$method), )*
49 _ => None,
50 }
51 }
52 )*
53 }
54 }
55
56 #[inline]
57 pub fn all_methods(self) -> &'static [BuiltinDeriveImplMethod] {
58 match self {
59 $( Self::$trait => &[ $(BuiltinDeriveImplMethod::$method),* ], )*
60 }
61 }
62 }
63
64 impl BuiltinDeriveImplMethod {
65 #[inline]
66 pub fn name(self) -> Symbol {
67 match self {
68 $( $( BuiltinDeriveImplMethod::$method => sym::$method, )* )*
69 }
70 }
71 }
72 };
73}
74
75declare_enum!(
76 Copy => [],
77 Clone => [clone],
78 Default => [default],
79 Debug => [fmt],
80 Hash => [hash],
81 Ord => [cmp],
82 PartialOrd => [partial_cmp],
83 Eq => [],
84 PartialEq => [eq],
85 CoerceUnsized => [],
86 DispatchFromDyn => [],
87);
88
89impl BuiltinDeriveImplMethod {
90 pub fn trait_method(
91 self,
92 db: &dyn DefDatabase,
93 impl_: BuiltinDeriveImplId,
94 ) -> Option<FunctionId> {
95 let loc = impl_.loc(db);
96 let lang_items = crate::lang_item::lang_items(db, loc.krate(db));
97 let trait_ = impl_.loc(db).trait_.get_id(lang_items)?;
98 trait_.trait_items(db).method_by_name(&Name::new_symbol_root(self.name()))
99 }
100}
101
102pub(crate) fn with_derive_traits(
103 derive: BuiltinDeriveExpander,
104 mut f: impl FnMut(BuiltinDeriveImplTrait),
105) {
106 let trait_ = match derive {
107 BuiltinDeriveExpander::Copy => BuiltinDeriveImplTrait::Copy,
108 BuiltinDeriveExpander::Clone => BuiltinDeriveImplTrait::Clone,
109 BuiltinDeriveExpander::Default => BuiltinDeriveImplTrait::Default,
110 BuiltinDeriveExpander::Debug => BuiltinDeriveImplTrait::Debug,
111 BuiltinDeriveExpander::Hash => BuiltinDeriveImplTrait::Hash,
112 BuiltinDeriveExpander::Ord => BuiltinDeriveImplTrait::Ord,
113 BuiltinDeriveExpander::PartialOrd => BuiltinDeriveImplTrait::PartialOrd,
114 BuiltinDeriveExpander::Eq => BuiltinDeriveImplTrait::Eq,
115 BuiltinDeriveExpander::PartialEq => BuiltinDeriveImplTrait::PartialEq,
116 BuiltinDeriveExpander::CoercePointee => {
117 f(BuiltinDeriveImplTrait::CoerceUnsized);
118 f(BuiltinDeriveImplTrait::DispatchFromDyn);
119 return;
120 }
121 };
122 f(trait_);
123}
124
125impl BuiltinDeriveImplLoc {
126 pub fn source(&self, db: &dyn DefDatabase) -> InFile<TextRange> {
127 let (adt_ast_id, module) = match self.adt {
128 AdtId::StructId(adt) => {
129 let adt_loc = adt.loc(db);
130 (adt_loc.id.upcast(), adt_loc.container)
131 }
132 AdtId::UnionId(adt) => {
133 let adt_loc = adt.loc(db);
134 (adt_loc.id.upcast(), adt_loc.container)
135 }
136 AdtId::EnumId(adt) => {
137 let adt_loc = adt.loc(db);
138 (adt_loc.id.upcast(), adt_loc.container)
139 }
140 };
141 let derive_range = self.derive_attr_id.find_derive_range(
142 db,
143 module.krate(db),
144 adt_ast_id,
145 self.derive_index,
146 );
147 adt_ast_id.with_value(derive_range)
148 }
149}
src/tools/rust-analyzer/crates/hir-def/src/expr_store/lower/format_args.rs+4-7
......@@ -1,12 +1,9 @@
11//! Lowering of `format_args!()`.
22
33use base_db::FxIndexSet;
4use hir_expand::name::{AsName, Name};
4use hir_expand::name::Name;
55use intern::{Symbol, sym};
6use syntax::{
7 AstPtr, AstToken as _,
8 ast::{self, HasName},
9};
6use syntax::{AstPtr, AstToken as _, ast};
107
118use crate::{
129 builtin_type::BuiltinUint,
......@@ -32,8 +29,8 @@ impl<'db> ExprCollector<'db> {
3229 let mut args = FormatArgumentsCollector::default();
3330 f.args().for_each(|arg| {
3431 args.add(FormatArgument {
35 kind: match arg.name() {
36 Some(name) => FormatArgumentKind::Named(name.as_name()),
32 kind: match arg.arg_name() {
33 Some(name) => FormatArgumentKind::Named(Name::new_root(name.name().text())),
3734 None => FormatArgumentKind::Normal,
3835 },
3936 expr: self.collect_expr_opt(arg.expr()),
src/tools/rust-analyzer/crates/hir-def/src/expr_store/tests/body/block.rs+3-3
......@@ -190,13 +190,13 @@ fn f() {
190190 "#,
191191 expect![[r#"
192192 ModuleIdLt {
193 [salsa id]: Id(3003),
193 [salsa id]: Id(3803),
194194 krate: Crate(
195 Id(1c00),
195 Id(2400),
196196 ),
197197 block: Some(
198198 BlockId(
199 3c01,
199 4401,
200200 ),
201201 ),
202202 }"#]],
src/tools/rust-analyzer/crates/hir-def/src/item_scope.rs+17-5
......@@ -9,15 +9,15 @@ use indexmap::map::Entry;
99use itertools::Itertools;
1010use la_arena::Idx;
1111use rustc_hash::{FxHashMap, FxHashSet};
12use smallvec::{SmallVec, smallvec};
12use smallvec::SmallVec;
1313use span::Edition;
1414use stdx::format_to;
1515use syntax::ast;
1616use thin_vec::ThinVec;
1717
1818use crate::{
19 AdtId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap, HasModule, ImplId,
20 Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
19 AdtId, BuiltinDeriveImplId, BuiltinType, ConstId, ExternBlockId, ExternCrateId, FxIndexMap,
20 HasModule, ImplId, Lookup, MacroCallStyles, MacroId, ModuleDefId, ModuleId, TraitId, UseId,
2121 db::DefDatabase,
2222 per_ns::{Item, MacrosItem, PerNs, TypesItem, ValuesItem},
2323 visibility::Visibility,
......@@ -159,6 +159,7 @@ pub struct ItemScope {
159159 declarations: ThinVec<ModuleDefId>,
160160
161161 impls: ThinVec<ImplId>,
162 builtin_derive_impls: ThinVec<BuiltinDeriveImplId>,
162163 extern_blocks: ThinVec<ExternBlockId>,
163164 unnamed_consts: ThinVec<ConstId>,
164165 /// Traits imported via `use Trait as _;`.
......@@ -329,6 +330,10 @@ impl ItemScope {
329330 self.impls.iter().copied()
330331 }
331332
333 pub fn builtin_derive_impls(&self) -> impl ExactSizeIterator<Item = BuiltinDeriveImplId> + '_ {
334 self.builtin_derive_impls.iter().copied()
335 }
336
332337 pub fn all_macro_calls(&self) -> impl Iterator<Item = MacroCallId> + '_ {
333338 self.macro_invocations.values().copied().chain(self.attr_macros.values().copied()).chain(
334339 self.derive_macros.values().flat_map(|it| {
......@@ -471,6 +476,10 @@ impl ItemScope {
471476 self.impls.push(imp);
472477 }
473478
479 pub(crate) fn define_builtin_derive_impl(&mut self, imp: BuiltinDeriveImplId) {
480 self.builtin_derive_impls.push(imp);
481 }
482
474483 pub(crate) fn define_extern_block(&mut self, extern_block: ExternBlockId) {
475484 self.extern_blocks.push(extern_block);
476485 }
......@@ -522,12 +531,13 @@ impl ItemScope {
522531 adt: AstId<ast::Adt>,
523532 attr_id: AttrId,
524533 attr_call_id: MacroCallId,
525 len: usize,
534 mut derive_call_ids: SmallVec<[Option<MacroCallId>; 4]>,
526535 ) {
536 derive_call_ids.shrink_to_fit();
527537 self.derive_macros.entry(adt).or_default().push(DeriveMacroInvocation {
528538 attr_id,
529539 attr_call_id,
530 derive_call_ids: smallvec![None; len],
540 derive_call_ids,
531541 });
532542 }
533543
......@@ -811,6 +821,7 @@ impl ItemScope {
811821 unresolved,
812822 declarations,
813823 impls,
824 builtin_derive_impls,
814825 unnamed_consts,
815826 unnamed_trait_imports,
816827 legacy_macros,
......@@ -834,6 +845,7 @@ impl ItemScope {
834845 unresolved.shrink_to_fit();
835846 declarations.shrink_to_fit();
836847 impls.shrink_to_fit();
848 builtin_derive_impls.shrink_to_fit();
837849 unnamed_consts.shrink_to_fit();
838850 unnamed_trait_imports.shrink_to_fit();
839851 legacy_macros.shrink_to_fit();
src/tools/rust-analyzer/crates/hir-def/src/item_tree.rs+1-1
......@@ -103,7 +103,7 @@ fn lower_extra_crate_attrs<'a>(
103103 struct FakeSpanMap {
104104 file_id: span::EditionedFileId,
105105 }
106 impl syntax_bridge::SpanMapper<Span> for FakeSpanMap {
106 impl syntax_bridge::SpanMapper for FakeSpanMap {
107107 fn span_for(&self, range: TextRange) -> Span {
108108 Span {
109109 range,
src/tools/rust-analyzer/crates/hir-def/src/item_tree/attrs.rs+2-3
......@@ -18,7 +18,6 @@ use hir_expand::{
1818 name::Name,
1919};
2020use intern::{Interned, Symbol, sym};
21use span::Span;
2221use syntax::{AstNode, T, ast};
2322use syntax_bridge::DocCommentDesugarMode;
2423use tt::token_to_literal;
......@@ -49,7 +48,7 @@ impl AttrsOrCfg {
4948 span_map: S,
5049 ) -> AttrsOrCfg
5150 where
52 S: syntax_bridge::SpanMapper<Span> + Copy,
51 S: syntax_bridge::SpanMapper + Copy,
5352 {
5453 let mut attrs = Vec::new();
5554 let result =
......@@ -227,7 +226,7 @@ impl<'attr> AttrQuery<'attr> {
227226 }
228227
229228 #[inline]
230 pub(crate) fn string_value_with_span(self) -> Option<(&'attr Symbol, span::Span)> {
229 pub(crate) fn string_value_with_span(self) -> Option<(&'attr str, span::Span)> {
231230 self.attrs().find_map(|attr| attr.string_value_with_span())
232231 }
233232
src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs+50-1
......@@ -2,6 +2,7 @@
22//!
33//! This attribute to tell the compiler about semi built-in std library
44//! features, such as Fn family of traits.
5use hir_expand::name::Name;
56use intern::{Symbol, sym};
67use stdx::impl_from;
78
......@@ -10,7 +11,7 @@ use crate::{
1011 StaticId, StructId, TraitId, TypeAliasId, UnionId,
1112 attrs::AttrFlags,
1213 db::DefDatabase,
13 nameres::{assoc::TraitItems, crate_def_map, crate_local_def_map},
14 nameres::{DefMap, assoc::TraitItems, crate_def_map, crate_local_def_map},
1415};
1516
1617#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
......@@ -93,6 +94,10 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
9394 }
9495 }
9596
97 if matches!(krate.data(db).origin, base_db::CrateOrigin::Lang(base_db::LangCrateOrigin::Core)) {
98 lang_items.fill_non_lang_core_traits(db, crate_def_map);
99 }
100
96101 if lang_items.is_empty() { None } else { Some(Box::new(lang_items)) }
97102}
98103
......@@ -135,6 +140,31 @@ impl LangItems {
135140 }
136141}
137142
143fn resolve_core_trait(
144 db: &dyn DefDatabase,
145 core_def_map: &DefMap,
146 modules: &[Symbol],
147 name: Symbol,
148) -> Option<TraitId> {
149 let mut current = &core_def_map[core_def_map.root];
150 for module in modules {
151 let Some((ModuleDefId::ModuleId(cur), _)) =
152 current.scope.type_(&Name::new_symbol_root(module.clone()))
153 else {
154 return None;
155 };
156 if cur.krate(db) != core_def_map.krate() || cur.block(db) != core_def_map.block_id() {
157 return None;
158 }
159 current = &core_def_map[cur];
160 }
161 let Some((ModuleDefId::TraitId(trait_), _)) = current.scope.type_(&Name::new_symbol_root(name))
162 else {
163 return None;
164 };
165 Some(trait_)
166}
167
138168#[salsa::tracked(returns(as_deref))]
139169pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
140170 let mut traits = Vec::new();
......@@ -158,6 +188,10 @@ macro_rules! language_item_table {
158188 (
159189 $LangItems:ident =>
160190 $( $(#[$attr:meta])* $lang_item:ident, $module:ident :: $name:ident, $target:ident; )*
191
192 @non_lang_core_traits:
193
194 $( core::$($non_lang_module:ident)::*, $non_lang_trait:ident; )*
161195 ) => {
162196 #[allow(non_snake_case)] // FIXME: Should we remove this?
163197 #[derive(Debug, Default, Clone, PartialEq, Eq, Hash)]
......@@ -166,6 +200,9 @@ macro_rules! language_item_table {
166200 $(#[$attr])*
167201 pub $lang_item: Option<$target>,
168202 )*
203 $(
204 pub $non_lang_trait: Option<TraitId>,
205 )*
169206 }
170207
171208 impl LangItems {
......@@ -176,6 +213,7 @@ macro_rules! language_item_table {
176213 /// Merges `self` with `other`, with preference to `self` items.
177214 fn merge_prefer_self(&mut self, other: &Self) {
178215 $( self.$lang_item = self.$lang_item.or(other.$lang_item); )*
216 $( self.$non_lang_trait = self.$non_lang_trait.or(other.$non_lang_trait); )*
179217 }
180218
181219 fn assign_lang_item(&mut self, name: Symbol, target: LangItemTarget) {
......@@ -190,6 +228,10 @@ macro_rules! language_item_table {
190228 _ => {}
191229 }
192230 }
231
232 fn fill_non_lang_core_traits(&mut self, db: &dyn DefDatabase, core_def_map: &DefMap) {
233 $( self.$non_lang_trait = resolve_core_trait(db, core_def_map, &[ $(sym::$non_lang_module),* ], sym::$non_lang_trait); )*
234 }
193235 }
194236
195237 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
......@@ -426,4 +468,11 @@ language_item_table! { LangItems =>
426468 String, sym::String, StructId;
427469 CStr, sym::CStr, StructId;
428470 Ordering, sym::Ordering, EnumId;
471
472 @non_lang_core_traits:
473 core::default, Default;
474 core::fmt, Debug;
475 core::hash, Hash;
476 core::cmp, Ord;
477 core::cmp, Eq;
429478}
src/tools/rust-analyzer/crates/hir-def/src/lib.rs+44
......@@ -30,6 +30,7 @@ pub mod dyn_map;
3030
3131pub mod item_tree;
3232
33pub mod builtin_derive;
3334pub mod lang_item;
3435
3536pub mod hir;
......@@ -63,6 +64,7 @@ use base_db::{Crate, impl_intern_key};
6364use hir_expand::{
6465 AstId, ExpandResult, ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroCallStyles,
6566 MacroDefId, MacroDefKind,
67 attrs::AttrId,
6668 builtin::{BuiltinAttrExpander, BuiltinDeriveExpander, BuiltinFnLikeExpander, EagerExpander},
6769 db::ExpandDatabase,
6870 eager::expand_eager_macro_input,
......@@ -80,6 +82,7 @@ pub use hir_expand::{Intern, Lookup, tt};
8082
8183use crate::{
8284 attrs::AttrFlags,
85 builtin_derive::BuiltinDeriveImplTrait,
8386 builtin_type::BuiltinType,
8487 db::DefDatabase,
8588 expr_store::ExpressionStoreSourceMap,
......@@ -331,6 +334,21 @@ impl ImplId {
331334 }
332335}
333336
337#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
338pub struct BuiltinDeriveImplLoc {
339 pub adt: AdtId,
340 pub trait_: BuiltinDeriveImplTrait,
341 pub derive_attr_id: AttrId,
342 pub derive_index: u32,
343}
344
345#[salsa::interned(debug, no_lifetime)]
346#[derive(PartialOrd, Ord)]
347pub struct BuiltinDeriveImplId {
348 #[returns(ref)]
349 pub loc: BuiltinDeriveImplLoc,
350}
351
334352type UseLoc = ItemLoc<ast::Use>;
335353impl_intern!(UseId, UseLoc, intern_use, lookup_intern_use);
336354
......@@ -660,6 +678,18 @@ impl_from!(
660678 for ModuleDefId
661679);
662680
681impl From<DefWithBodyId> for ModuleDefId {
682 #[inline]
683 fn from(value: DefWithBodyId) -> Self {
684 match value {
685 DefWithBodyId::FunctionId(id) => id.into(),
686 DefWithBodyId::StaticId(id) => id.into(),
687 DefWithBodyId::ConstId(id) => id.into(),
688 DefWithBodyId::VariantId(id) => id.into(),
689 }
690 }
691}
692
663693/// A constant, which might appears as a const item, an anonymous const block in expressions
664694/// or patterns, or as a constant in types with const generics.
665695#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
......@@ -1009,6 +1039,20 @@ fn module_for_assoc_item_loc<'db>(
10091039 id.lookup(db).container.module(db)
10101040}
10111041
1042impl HasModule for BuiltinDeriveImplLoc {
1043 #[inline]
1044 fn module(&self, db: &dyn DefDatabase) -> ModuleId {
1045 self.adt.module(db)
1046 }
1047}
1048
1049impl HasModule for BuiltinDeriveImplId {
1050 #[inline]
1051 fn module(&self, db: &dyn DefDatabase) -> ModuleId {
1052 self.loc(db).module(db)
1053 }
1054}
1055
10121056impl HasModule for FunctionId {
10131057 #[inline]
10141058 fn module(&self, db: &dyn DefDatabase) -> ModuleId {
src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mbe.rs+8-8
......@@ -35,9 +35,9 @@ macro_rules! f {
3535 };
3636}
3737
38struct#0:MacroRules[BE8F, 0]@58..64#15360# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#15360#
39 map#0:MacroRules[BE8F, 0]@86..89#15360#:#0:MacroRules[BE8F, 0]@89..90#15360# #0:MacroRules[BE8F, 0]@89..90#15360#::#0:MacroRules[BE8F, 0]@91..93#15360#std#0:MacroRules[BE8F, 0]@93..96#15360#::#0:MacroRules[BE8F, 0]@96..98#15360#collections#0:MacroRules[BE8F, 0]@98..109#15360#::#0:MacroRules[BE8F, 0]@109..111#15360#HashSet#0:MacroRules[BE8F, 0]@111..118#15360#<#0:MacroRules[BE8F, 0]@118..119#15360#(#0:MacroRules[BE8F, 0]@119..120#15360#)#0:MacroRules[BE8F, 0]@120..121#15360#>#0:MacroRules[BE8F, 0]@121..122#15360#,#0:MacroRules[BE8F, 0]@122..123#15360#
40}#0:MacroRules[BE8F, 0]@132..133#15360#
38struct#0:MacroRules[BE8F, 0]@58..64#17408# MyTraitMap2#0:MacroCall[BE8F, 0]@31..42#ROOT2024# {#0:MacroRules[BE8F, 0]@72..73#17408#
39 map#0:MacroRules[BE8F, 0]@86..89#17408#:#0:MacroRules[BE8F, 0]@89..90#17408# #0:MacroRules[BE8F, 0]@89..90#17408#::#0:MacroRules[BE8F, 0]@91..93#17408#std#0:MacroRules[BE8F, 0]@93..96#17408#::#0:MacroRules[BE8F, 0]@96..98#17408#collections#0:MacroRules[BE8F, 0]@98..109#17408#::#0:MacroRules[BE8F, 0]@109..111#17408#HashSet#0:MacroRules[BE8F, 0]@111..118#17408#<#0:MacroRules[BE8F, 0]@118..119#17408#(#0:MacroRules[BE8F, 0]@119..120#17408#)#0:MacroRules[BE8F, 0]@120..121#17408#>#0:MacroRules[BE8F, 0]@121..122#17408#,#0:MacroRules[BE8F, 0]@122..123#17408#
40}#0:MacroRules[BE8F, 0]@132..133#17408#
4141"#]],
4242 );
4343}
......@@ -197,7 +197,7 @@ macro_rules! mk_struct {
197197#[macro_use]
198198mod foo;
199199
200struct#1:MacroRules[DB0C, 0]@59..65#15360# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#15360#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#15360#;#1:MacroRules[DB0C, 0]@75..76#15360#
200struct#1:MacroRules[DB0C, 0]@59..65#17408# Foo#0:MacroCall[DB0C, 0]@32..35#ROOT2024#(#1:MacroRules[DB0C, 0]@70..71#17408#u32#0:MacroCall[DB0C, 0]@41..44#ROOT2024#)#1:MacroRules[DB0C, 0]@74..75#17408#;#1:MacroRules[DB0C, 0]@75..76#17408#
201201"#]],
202202 );
203203}
......@@ -423,10 +423,10 @@ m! { foo, bar }
423423macro_rules! m {
424424 ($($i:ident),*) => ( impl Bar { $(fn $i() {})* } );
425425}
426impl#\15360# Bar#\15360# {#\15360#
427 fn#\15360# foo#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360#
428 fn#\15360# bar#\ROOT2024#(#\15360#)#\15360# {#\15360#}#\15360#
429}#\15360#
426impl#\17408# Bar#\17408# {#\17408#
427 fn#\17408# foo#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
428 fn#\17408# bar#\ROOT2024#(#\17408#)#\17408# {#\17408#}#\17408#
429}#\17408#
430430"#]],
431431 );
432432}
src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/mod.rs+11-1
......@@ -16,7 +16,7 @@ mod proc_macros;
1616
1717use std::{any::TypeId, iter, ops::Range, sync};
1818
19use base_db::RootQueryDb;
19use base_db::{RootQueryDb, SourceDatabase};
2020use expect_test::Expect;
2121use hir_expand::{
2222 AstId, ExpansionInfo, InFile, MacroCallId, MacroCallKind, MacroKind,
......@@ -53,6 +53,8 @@ use crate::{
5353
5454#[track_caller]
5555fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
56 crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false);
57
5658 let db = TestDB::with_files(ra_fixture);
5759 let krate = db.fetch_test_crate();
5860 let def_map = crate_def_map(&db, krate);
......@@ -80,10 +82,15 @@ fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect)
8082 .sorted_unstable_by_key(|(range, _)| range.start())
8183 .format_with("\n", |(range, err), format| format(&format_args!("{range:?}: {err}")))
8284 .to_string();
85
86 crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true);
87
8388 expect.assert_eq(&errors);
8489}
8590
8691fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, mut expect: Expect) {
92 crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(false);
93
8794 let extra_proc_macros = vec![(
8895 r#"
8996#[proc_macro_attribute]
......@@ -246,6 +253,8 @@ pub fn identity_when_valid(_attr: TokenStream, item: TokenStream) -> TokenStream
246253 }
247254 }
248255
256 crate::nameres::ENABLE_BUILTIN_DERIVE_FAST_PATH.set(true);
257
249258 expect.indent(false);
250259 expect.assert_eq(&expanded_text);
251260}
......@@ -378,6 +387,7 @@ struct IdentityWhenValidProcMacroExpander;
378387impl ProcMacroExpander for IdentityWhenValidProcMacroExpander {
379388 fn expand(
380389 &self,
390 _: &dyn SourceDatabase,
381391 subtree: &TopSubtree,
382392 _: Option<&TopSubtree>,
383393 _: &base_db::Env,
src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/proc_macros.rs+4-4
......@@ -122,16 +122,16 @@ struct Foo {
122122 v4: bool // No comma here
123123}
124124
125#[attr1]
126#[derive(Bar)]
127#[attr2] struct S;
125128#[attr1]
126129#[my_cool_derive()] struct Foo {
127130 v1: i32, #[attr3]v2: fn(#[attr4]param2: u32), v3: Foo< {
128131 456
129132 }
130133 >,
131}
132#[attr1]
133#[derive(Bar)]
134#[attr2] struct S;"#]],
134}"#]],
135135 );
136136}
137137
src/tools/rust-analyzer/crates/hir-def/src/nameres.rs+39-2
......@@ -87,6 +87,25 @@ use crate::{
8787
8888pub use self::path_resolution::ResolvePathResultPrefixInfo;
8989
90#[cfg(test)]
91thread_local! {
92 /// HACK: In order to test builtin derive expansion, we gate their fast path with this atomic when cfg(test).
93 pub(crate) static ENABLE_BUILTIN_DERIVE_FAST_PATH: std::cell::Cell<bool> =
94 const { std::cell::Cell::new(true) };
95}
96
97#[inline]
98#[cfg(test)]
99fn enable_builtin_derive_fast_path() -> bool {
100 ENABLE_BUILTIN_DERIVE_FAST_PATH.get()
101}
102
103#[inline(always)]
104#[cfg(not(test))]
105fn enable_builtin_derive_fast_path() -> bool {
106 true
107}
108
90109const PREDEFINED_TOOLS: &[SmolStr] = &[
91110 SmolStr::new_static("clippy"),
92111 SmolStr::new_static("rustfmt"),
......@@ -483,6 +502,7 @@ impl DefMap {
483502}
484503
485504impl DefMap {
505 /// Returns all modules in the crate that are associated with the given file.
486506 pub fn modules_for_file<'a>(
487507 &'a self,
488508 db: &'a dyn DefDatabase,
......@@ -490,16 +510,33 @@ impl DefMap {
490510 ) -> impl Iterator<Item = ModuleId> + 'a {
491511 self.modules
492512 .iter()
493 .filter(move |(_id, data)| {
513 .filter(move |(_, data)| {
494514 data.origin.file_id().map(|file_id| file_id.file_id(db)) == Some(file_id)
495515 })
496 .map(|(id, _data)| id)
516 .map(|(id, _)| id)
497517 }
498518
499519 pub fn modules(&self) -> impl Iterator<Item = (ModuleId, &ModuleData)> + '_ {
500520 self.modules.iter()
501521 }
502522
523 /// Returns all inline modules (mod name { ... }) in the crate that are associated with the given macro expansion.
524 pub fn inline_modules_for_macro_file(
525 &self,
526 file_id: MacroCallId,
527 ) -> impl Iterator<Item = ModuleId> + '_ {
528 self.modules
529 .iter()
530 .filter(move |(_, data)| {
531 matches!(
532 data.origin,
533 ModuleOrigin::Inline { definition_tree_id, .. }
534 if definition_tree_id.file_id().macro_file() == Some(file_id)
535 )
536 })
537 .map(|(id, _)| id)
538 }
539
503540 pub fn derive_helpers_in_scope(
504541 &self,
505542 id: AstId<ast::Adt>,
src/tools/rust-analyzer/crates/hir-def/src/nameres/attr_resolution.rs+1-1
......@@ -114,7 +114,7 @@ pub(super) fn attr_macro_as_call_id(
114114 let arg = match macro_attr.input.as_deref() {
115115 Some(AttrInput::TokenTree(tt)) => {
116116 let mut tt = tt.clone();
117 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
117 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
118118 Some(tt)
119119 }
120120
src/tools/rust-analyzer/crates/hir-def/src/nameres/collector.rs+195-46
......@@ -12,26 +12,28 @@ use hir_expand::{
1212 AttrMacroAttrIds, EditionedFileId, ErasedAstId, ExpandTo, HirFileId, InFile, MacroCallId,
1313 MacroCallKind, MacroDefId, MacroDefKind,
1414 attrs::{Attr, AttrId},
15 builtin::{find_builtin_attr, find_builtin_derive, find_builtin_macro},
15 builtin::{BuiltinDeriveExpander, find_builtin_attr, find_builtin_derive, find_builtin_macro},
1616 mod_path::{ModPath, PathKind},
1717 name::{AsName, Name},
1818 proc_macro::CustomProcMacroExpander,
1919};
20use intern::{Interned, sym};
20use intern::{Interned, Symbol, sym};
2121use itertools::izip;
2222use la_arena::Idx;
2323use rustc_hash::{FxHashMap, FxHashSet};
2424use smallvec::SmallVec;
2525use span::{Edition, FileAstId, SyntaxContext};
26use stdx::always;
2627use syntax::ast;
2728use triomphe::Arc;
2829
2930use crate::{
30 AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, EnumLoc, ExternBlockLoc, ExternCrateId,
31 ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap, ImplLoc, Intern, ItemContainerId, Lookup,
32 Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId, MacroRulesLoc, MacroRulesLocFlags,
33 ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc,
34 UnionLoc, UnresolvedMacro, UseId, UseLoc,
31 AdtId, AssocItemId, AstId, AstIdWithPath, BuiltinDeriveImplId, BuiltinDeriveImplLoc, ConstLoc,
32 EnumLoc, ExternBlockLoc, ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, FxIndexMap,
33 ImplLoc, Intern, ItemContainerId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId,
34 MacroRulesId, MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId,
35 ProcMacroLoc, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, UnresolvedMacro, UseId,
36 UseLoc,
3537 db::DefDatabase,
3638 item_scope::{GlobId, ImportId, ImportOrExternCrate, PerNsGlobImports},
3739 item_tree::{
......@@ -104,6 +106,7 @@ pub(super) fn collect_defs(
104106 prev_active_attrs: Default::default(),
105107 unresolved_extern_crates: Default::default(),
106108 is_proc_macro: krate.is_proc_macro,
109 deferred_builtin_derives: Default::default(),
107110 };
108111 if tree_id.is_block() {
109112 collector.seed_with_inner(tree_id);
......@@ -214,6 +217,17 @@ enum MacroDirectiveKind<'db> {
214217 },
215218}
216219
220#[derive(Debug)]
221struct DeferredBuiltinDerive {
222 call_id: MacroCallId,
223 derive: BuiltinDeriveExpander,
224 module_id: ModuleId,
225 depth: usize,
226 container: ItemContainerId,
227 derive_attr_id: AttrId,
228 derive_index: u32,
229}
230
217231/// Walks the tree of module recursively
218232struct DefCollector<'db> {
219233 db: &'db dyn DefDatabase,
......@@ -252,6 +266,11 @@ struct DefCollector<'db> {
252266 /// on the same item. Therefore, this holds all active attributes that we already
253267 /// expanded.
254268 prev_active_attrs: FxHashMap<AstId<ast::Item>, SmallVec<[AttrId; 1]>>,
269 /// To save memory, we do not really expand builtin derives. Instead, we save them as a `BuiltinDeriveImplId`.
270 ///
271 /// However, we can only do that when the derive is directly above the item, and there is no attribute in between.
272 /// Otherwise, all sorts of weird things can happen, like the item name resolving to something else.
273 deferred_builtin_derives: FxHashMap<AstId<ast::Item>, Vec<DeferredBuiltinDerive>>,
255274}
256275
257276impl<'db> DefCollector<'db> {
......@@ -273,13 +292,13 @@ impl<'db> DefCollector<'db> {
273292 match () {
274293 () if *attr_name == sym::recursion_limit => {
275294 if let Some(limit) = attr.string_value()
276 && let Ok(limit) = limit.as_str().parse()
295 && let Ok(limit) = limit.parse()
277296 {
278297 crate_data.recursion_limit = Some(limit);
279298 }
280299 }
281300 () if *attr_name == sym::crate_type => {
282 if attr.string_value() == Some(&sym::proc_dash_macro) {
301 if attr.string_value() == Some("proc-macro") {
283302 self.is_proc_macro = true;
284303 }
285304 }
......@@ -1241,7 +1260,7 @@ impl<'db> DefCollector<'db> {
12411260 fn resolve_macros(&mut self) -> ReachedFixedPoint {
12421261 let mut macros = mem::take(&mut self.unresolved_macros);
12431262 let mut resolved = Vec::new();
1244 let mut push_resolved = |directive: &MacroDirective<'_>, call_id| {
1263 let push_resolved = |resolved: &mut Vec<_>, directive: &MacroDirective<'_>, call_id| {
12451264 let attr_macro_item = match &directive.kind {
12461265 MacroDirectiveKind::Attr { ast_id, .. } => Some(ast_id.ast_id),
12471266 MacroDirectiveKind::FnLike { .. } | MacroDirectiveKind::Derive { .. } => None,
......@@ -1271,8 +1290,8 @@ impl<'db> DefCollector<'db> {
12711290 MacroSubNs::Attr
12721291 }
12731292 };
1274 let resolver = |path: &_| {
1275 let resolved_res = self.def_map.resolve_path_fp_with_macro(
1293 let resolver = |def_map: &DefMap, path: &_| {
1294 let resolved_res = def_map.resolve_path_fp_with_macro(
12761295 self.crate_local_def_map.unwrap_or(&self.local_def_map),
12771296 self.db,
12781297 ResolveMode::Other,
......@@ -1283,7 +1302,7 @@ impl<'db> DefCollector<'db> {
12831302 );
12841303 resolved_res.resolved_def.take_macros().map(|it| (it, self.db.macro_def(it)))
12851304 };
1286 let resolver_def_id = |path: &_| resolver(path).map(|(_, it)| it);
1305 let resolver_def_id = |path: &_| resolver(&self.def_map, path).map(|(_, it)| it);
12871306
12881307 match &directive.kind {
12891308 MacroDirectiveKind::FnLike { ast_id, expand_to, ctxt: call_site } => {
......@@ -1306,7 +1325,7 @@ impl<'db> DefCollector<'db> {
13061325 .scope
13071326 .add_macro_invoc(ast_id.ast_id, call_id);
13081327
1309 push_resolved(directive, call_id);
1328 push_resolved(&mut resolved, directive, call_id);
13101329
13111330 res = ReachedFixedPoint::No;
13121331 return Resolved::Yes;
......@@ -1320,6 +1339,7 @@ impl<'db> DefCollector<'db> {
13201339 ctxt: call_site,
13211340 derive_macro_id,
13221341 } => {
1342 // FIXME: This code is almost duplicate below.
13231343 let id = derive_macro_as_call_id(
13241344 self.db,
13251345 ast_id,
......@@ -1327,7 +1347,7 @@ impl<'db> DefCollector<'db> {
13271347 *derive_pos as u32,
13281348 *call_site,
13291349 self.def_map.krate,
1330 resolver,
1350 |path| resolver(&self.def_map, path),
13311351 *derive_macro_id,
13321352 );
13331353
......@@ -1354,7 +1374,8 @@ impl<'db> DefCollector<'db> {
13541374 }
13551375 }
13561376
1357 push_resolved(directive, call_id);
1377 push_resolved(&mut resolved, directive, call_id);
1378
13581379 res = ReachedFixedPoint::No;
13591380 return Resolved::Yes;
13601381 }
......@@ -1460,29 +1481,85 @@ impl<'db> DefCollector<'db> {
14601481
14611482 let ast_id = ast_id.with_value(ast_adt_id);
14621483
1484 let mut derive_call_ids = SmallVec::new();
14631485 match attr.parse_path_comma_token_tree(self.db) {
14641486 Some(derive_macros) => {
14651487 let call_id = call_id();
1466 let mut len = 0;
14671488 for (idx, (path, call_site, _)) in derive_macros.enumerate() {
14681489 let ast_id = AstIdWithPath::new(
14691490 file_id,
14701491 ast_id.value,
14711492 Interned::new(path),
14721493 );
1473 self.unresolved_macros.push(MacroDirective {
1474 module_id: directive.module_id,
1475 depth: directive.depth + 1,
1476 kind: MacroDirectiveKind::Derive {
1477 ast_id,
1478 derive_attr: *attr_id,
1479 derive_pos: idx,
1480 ctxt: call_site.ctx,
1481 derive_macro_id: call_id,
1482 },
1483 container: directive.container,
1484 });
1485 len = idx;
1494
1495 // Try to resolve the derive immediately. If we succeed, we can also use the fast path
1496 // for builtin derives. If not, we cannot use it, as it can cause the ADT to become
1497 // interned while the derive is still unresolved, which will cause it to get forgotten.
1498 let id = derive_macro_as_call_id(
1499 self.db,
1500 &ast_id,
1501 *attr_id,
1502 idx as u32,
1503 call_site.ctx,
1504 self.def_map.krate,
1505 |path| resolver(&self.def_map, path),
1506 call_id,
1507 );
1508
1509 if let Ok((macro_id, def_id, call_id)) = id {
1510 derive_call_ids.push(Some(call_id));
1511 // Record its helper attributes.
1512 if def_id.krate != self.def_map.krate {
1513 let def_map = crate_def_map(self.db, def_id.krate);
1514 if let Some(helpers) =
1515 def_map.data.exported_derives.get(&macro_id)
1516 {
1517 self.def_map
1518 .derive_helpers_in_scope
1519 .entry(ast_id.ast_id.map(|it| it.upcast()))
1520 .or_default()
1521 .extend(izip!(
1522 helpers.iter().cloned(),
1523 iter::repeat(macro_id),
1524 iter::repeat(call_id),
1525 ));
1526 }
1527 }
1528
1529 if super::enable_builtin_derive_fast_path()
1530 && let MacroDefKind::BuiltInDerive(_, builtin_derive) =
1531 def_id.kind
1532 {
1533 self.deferred_builtin_derives
1534 .entry(ast_id.ast_id.upcast())
1535 .or_default()
1536 .push(DeferredBuiltinDerive {
1537 call_id,
1538 derive: builtin_derive,
1539 module_id: directive.module_id,
1540 container: directive.container,
1541 depth: directive.depth,
1542 derive_attr_id: *attr_id,
1543 derive_index: idx as u32,
1544 });
1545 } else {
1546 push_resolved(&mut resolved, directive, call_id);
1547 }
1548 } else {
1549 derive_call_ids.push(None);
1550 self.unresolved_macros.push(MacroDirective {
1551 module_id: directive.module_id,
1552 depth: directive.depth + 1,
1553 kind: MacroDirectiveKind::Derive {
1554 ast_id,
1555 derive_attr: *attr_id,
1556 derive_pos: idx,
1557 ctxt: call_site.ctx,
1558 derive_macro_id: call_id,
1559 },
1560 container: directive.container,
1561 });
1562 }
14861563 }
14871564
14881565 // We treat the #[derive] macro as an attribute call, but we do not resolve it for nameres collection.
......@@ -1491,7 +1568,12 @@ impl<'db> DefCollector<'db> {
14911568 // Check the comment in [`builtin_attr_macro`].
14921569 self.def_map.modules[directive.module_id]
14931570 .scope
1494 .init_derive_attribute(ast_id, *attr_id, call_id, len + 1);
1571 .init_derive_attribute(
1572 ast_id,
1573 *attr_id,
1574 call_id,
1575 derive_call_ids,
1576 );
14951577 }
14961578 None => {
14971579 let diag = DefDiagnostic::malformed_derive(
......@@ -1522,12 +1604,25 @@ impl<'db> DefCollector<'db> {
15221604 }
15231605 }
15241606
1607 // Clear deferred derives for this item, unfortunately we cannot use them due to the attribute.
1608 if let Some(deferred_derives) = self.deferred_builtin_derives.remove(&ast_id) {
1609 resolved.extend(deferred_derives.into_iter().map(|derive| {
1610 (
1611 derive.module_id,
1612 derive.depth,
1613 derive.container,
1614 derive.call_id,
1615 Some(ast_id),
1616 )
1617 }));
1618 }
1619
15251620 let call_id = call_id();
15261621 self.def_map.modules[directive.module_id]
15271622 .scope
15281623 .add_attr_macro_invoc(ast_id, call_id);
15291624
1530 push_resolved(directive, call_id);
1625 push_resolved(&mut resolved, directive, call_id);
15311626 res = ReachedFixedPoint::No;
15321627 return Resolved::Yes;
15331628 }
......@@ -1709,6 +1804,12 @@ impl<'db> DefCollector<'db> {
17091804 ));
17101805 }
17111806
1807 always!(
1808 self.deferred_builtin_derives.is_empty(),
1809 "self.deferred_builtin_derives={:#?}",
1810 self.deferred_builtin_derives,
1811 );
1812
17121813 (self.def_map, self.local_def_map)
17131814 }
17141815}
......@@ -1751,6 +1852,33 @@ impl ModCollector<'_, '_> {
17511852 }
17521853 let db = self.def_collector.db;
17531854 let module_id = self.module_id;
1855 let consider_deferred_derives =
1856 |file_id: HirFileId,
1857 deferred_derives: &mut FxHashMap<_, Vec<DeferredBuiltinDerive>>,
1858 ast_id: FileAstId<ast::Adt>,
1859 id: AdtId,
1860 def_map: &mut DefMap| {
1861 let Some(deferred_derives) =
1862 deferred_derives.remove(&InFile::new(file_id, ast_id.upcast()))
1863 else {
1864 return;
1865 };
1866 let module = &mut def_map.modules[module_id];
1867 for deferred_derive in deferred_derives {
1868 crate::builtin_derive::with_derive_traits(deferred_derive.derive, |trait_| {
1869 let impl_id = BuiltinDeriveImplId::new(
1870 db,
1871 BuiltinDeriveImplLoc {
1872 adt: id,
1873 trait_,
1874 derive_attr_id: deferred_derive.derive_attr_id,
1875 derive_index: deferred_derive.derive_index,
1876 },
1877 );
1878 module.scope.define_builtin_derive_impl(impl_id);
1879 });
1880 }
1881 };
17541882 let update_def =
17551883 |def_collector: &mut DefCollector<'_>, id, name: &Name, vis, has_constructor| {
17561884 def_collector.def_map.modules[module_id].scope.declare(id);
......@@ -1928,11 +2056,21 @@ impl ModCollector<'_, '_> {
19282056 let it = &self.item_tree[id];
19292057
19302058 let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
2059 let interned = StructLoc {
2060 container: module_id,
2061 id: InFile::new(self.tree_id.file_id(), id),
2062 }
2063 .intern(db);
2064 consider_deferred_derives(
2065 self.tree_id.file_id(),
2066 &mut self.def_collector.deferred_builtin_derives,
2067 id.upcast(),
2068 interned.into(),
2069 def_map,
2070 );
19312071 update_def(
19322072 self.def_collector,
1933 StructLoc { container: module_id, id: InFile::new(self.file_id(), id) }
1934 .intern(db)
1935 .into(),
2073 interned.into(),
19362074 &it.name,
19372075 vis,
19382076 !matches!(it.shape, FieldsShape::Record),
......@@ -1942,15 +2080,19 @@ impl ModCollector<'_, '_> {
19422080 let it = &self.item_tree[id];
19432081
19442082 let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
1945 update_def(
1946 self.def_collector,
1947 UnionLoc { container: module_id, id: InFile::new(self.file_id(), id) }
1948 .intern(db)
1949 .into(),
1950 &it.name,
1951 vis,
1952 false,
2083 let interned = UnionLoc {
2084 container: module_id,
2085 id: InFile::new(self.tree_id.file_id(), id),
2086 }
2087 .intern(db);
2088 consider_deferred_derives(
2089 self.tree_id.file_id(),
2090 &mut self.def_collector.deferred_builtin_derives,
2091 id.upcast(),
2092 interned.into(),
2093 def_map,
19532094 );
2095 update_def(self.def_collector, interned.into(), &it.name, vis, false);
19542096 }
19552097 ModItemId::Enum(id) => {
19562098 let it = &self.item_tree[id];
......@@ -1960,6 +2102,13 @@ impl ModCollector<'_, '_> {
19602102 }
19612103 .intern(db);
19622104
2105 consider_deferred_derives(
2106 self.tree_id.file_id(),
2107 &mut self.def_collector.deferred_builtin_derives,
2108 id.upcast(),
2109 enum_.into(),
2110 def_map,
2111 );
19632112 let vis = resolve_vis(def_map, local_def_map, &self.item_tree[it.visibility]);
19642113 update_def(self.def_collector, enum_.into(), &it.name, vis, false);
19652114 }
......@@ -2311,14 +2460,14 @@ impl ModCollector<'_, '_> {
23112460 let name;
23122461 let name = match attrs.by_key(sym::rustc_builtin_macro).string_value_with_span() {
23132462 Some((it, span)) => {
2314 name = Name::new_symbol(it.clone(), span.ctx);
2463 name = Name::new_symbol(Symbol::intern(it), span.ctx);
23152464 &name
23162465 }
23172466 None => {
23182467 let explicit_name =
23192468 attrs.by_key(sym::rustc_builtin_macro).tt_values().next().and_then(|tt| {
2320 match tt.token_trees().flat_tokens().first() {
2321 Some(tt::TokenTree::Leaf(tt::Leaf::Ident(name))) => Some(name),
2469 match tt.token_trees().iter().next() {
2470 Some(tt::TtElement::Leaf(tt::Leaf::Ident(name))) => Some(name),
23222471 _ => None,
23232472 }
23242473 });
src/tools/rust-analyzer/crates/hir-def/src/nameres/proc_macro.rs+26-25
......@@ -2,10 +2,11 @@
22
33use hir_expand::name::{AsName, Name};
44use intern::sym;
5use itertools::Itertools;
56
67use crate::{
78 item_tree::Attrs,
8 tt::{Leaf, TokenTree, TopSubtree, TtElement},
9 tt::{Leaf, TopSubtree, TtElement},
910};
1011
1112#[derive(Debug, PartialEq, Eq)]
......@@ -61,35 +62,35 @@ impl Attrs<'_> {
6162
6263// This fn is intended for `#[proc_macro_derive(..)]` and `#[rustc_builtin_macro(..)]`, which have
6364// the same structure.
64#[rustfmt::skip]
6565pub(crate) fn parse_macro_name_and_helper_attrs(tt: &TopSubtree) -> Option<(Name, Box<[Name]>)> {
66 match tt.token_trees().flat_tokens() {
66 if let Some([TtElement::Leaf(Leaf::Ident(trait_name))]) =
67 tt.token_trees().iter().collect_array()
68 {
6769 // `#[proc_macro_derive(Trait)]`
6870 // `#[rustc_builtin_macro(Trait)]`
69 [TokenTree::Leaf(Leaf::Ident(trait_name))] => Some((trait_name.as_name(), Box::new([]))),
70
71 Some((trait_name.as_name(), Box::new([])))
72 } else if let Some(
73 [
74 TtElement::Leaf(Leaf::Ident(trait_name)),
75 TtElement::Leaf(Leaf::Punct(comma)),
76 TtElement::Leaf(Leaf::Ident(attributes)),
77 TtElement::Subtree(_, helpers),
78 ],
79 ) = tt.token_trees().iter().collect_array()
80 && comma.char == ','
81 && attributes.sym == sym::attributes
82 {
7183 // `#[proc_macro_derive(Trait, attributes(helper1, helper2, ...))]`
7284 // `#[rustc_builtin_macro(Trait, attributes(helper1, helper2, ...))]`
73 [
74 TokenTree::Leaf(Leaf::Ident(trait_name)),
75 TokenTree::Leaf(Leaf::Punct(comma)),
76 TokenTree::Leaf(Leaf::Ident(attributes)),
77 TokenTree::Subtree(_),
78 ..
79 ] if comma.char == ',' && attributes.sym == sym::attributes =>
80 {
81 let helpers = tt::TokenTreesView::new(&tt.token_trees().flat_tokens()[3..]).try_into_subtree()?;
82 let helpers = helpers
83 .iter()
84 .filter_map(|tt| match tt {
85 TtElement::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
86 _ => None,
87 })
88 .collect::<Box<[_]>>();
89
90 Some((trait_name.as_name(), helpers))
91 }
85 let helpers = helpers
86 .filter_map(|tt| match tt {
87 TtElement::Leaf(Leaf::Ident(helper)) => Some(helper.as_name()),
88 _ => None,
89 })
90 .collect::<Box<[_]>>();
9291
93 _ => None,
92 Some((trait_name.as_name(), helpers))
93 } else {
94 None
9495 }
9596}
src/tools/rust-analyzer/crates/hir-def/src/nameres/tests/macros.rs+4-4
......@@ -784,7 +784,7 @@ macro_rules! foo {
784784
785785pub use core::clone::Clone;
786786"#,
787 |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
787 |map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
788788 );
789789}
790790
......@@ -806,7 +806,7 @@ pub macro Copy {}
806806#[rustc_builtin_macro]
807807pub macro Clone {}
808808"#,
809 |map| assert_eq!(map.modules[map.root].scope.impls().len(), 2),
809 |map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 2),
810810 );
811811}
812812
......@@ -849,7 +849,7 @@ pub macro derive($item:item) {}
849849#[rustc_builtin_macro]
850850pub macro Clone {}
851851"#,
852 |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
852 |map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
853853 );
854854}
855855
......@@ -1609,7 +1609,7 @@ macro_rules! derive { () => {} }
16091609#[derive(Clone)]
16101610struct S;
16111611 "#,
1612 |map| assert_eq!(map.modules[map.root].scope.impls().len(), 1),
1612 |map| assert_eq!(map.modules[map.root].scope.builtin_derive_impls().len(), 1),
16131613 );
16141614}
16151615
src/tools/rust-analyzer/crates/hir-def/src/signatures.rs+11
......@@ -185,6 +185,9 @@ impl UnionSignature {
185185bitflags! {
186186 #[derive(Debug, Copy, Clone, PartialEq, Eq)]
187187 pub struct EnumFlags: u8 {
188 /// Indicates whether this enum has `#[repr]`.
189 const HAS_REPR = 1 << 0;
190 /// Indicates whether the enum has a `#[rustc_has_incoherent_inherent_impls]` attribute.
188191 const RUSTC_HAS_INCOHERENT_INHERENT_IMPLS = 1 << 1;
189192 }
190193}
......@@ -205,6 +208,9 @@ impl EnumSignature {
205208 if attrs.contains(AttrFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS) {
206209 flags |= EnumFlags::RUSTC_HAS_INCOHERENT_INHERENT_IMPLS;
207210 }
211 if attrs.contains(AttrFlags::HAS_REPR) {
212 flags |= EnumFlags::HAS_REPR;
213 }
208214
209215 let InFile { file_id, value: source } = loc.source(db);
210216 let (store, generic_params, source_map) = lower_generic_params(
......@@ -233,6 +239,11 @@ impl EnumSignature {
233239 _ => IntegerType::Pointer(true),
234240 }
235241 }
242
243 #[inline]
244 pub fn repr(&self, db: &dyn DefDatabase, id: EnumId) -> Option<ReprOptions> {
245 if self.flags.contains(EnumFlags::HAS_REPR) { AttrFlags::repr(db, id.into()) } else { None }
246 }
236247}
237248bitflags::bitflags! {
238249 #[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
src/tools/rust-analyzer/crates/hir-def/src/test_db.rs+6
......@@ -49,6 +49,12 @@ impl Default for TestDB {
4949 this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
5050 // This needs to be here otherwise `CrateGraphBuilder` panics.
5151 this.set_all_crates(Arc::new(Box::new([])));
52 _ = base_db::LibraryRoots::builder(Default::default())
53 .durability(Durability::MEDIUM)
54 .new(&this);
55 _ = base_db::LocalRoots::builder(Default::default())
56 .durability(Durability::MEDIUM)
57 .new(&this);
5258 CrateGraphBuilder::default().set_in_db(&mut this);
5359 this
5460 }
src/tools/rust-analyzer/crates/hir-expand/src/attrs.rs+22-30
......@@ -35,7 +35,8 @@ use arrayvec::ArrayVec;
3535use base_db::Crate;
3636use cfg::{CfgExpr, CfgOptions};
3737use either::Either;
38use intern::{Interned, Symbol};
38use intern::Interned;
39use itertools::Itertools;
3940use mbe::{DelimiterKind, Punct};
4041use parser::T;
4142use smallvec::SmallVec;
......@@ -416,47 +417,42 @@ impl fmt::Display for AttrInput {
416417
417418impl Attr {
418419 /// #[path = "string"]
419 pub fn string_value(&self) -> Option<&Symbol> {
420 pub fn string_value(&self) -> Option<&str> {
420421 match self.input.as_deref()? {
421 AttrInput::Literal(tt::Literal {
422 symbol: text,
423 kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
424 ..
425 }) => Some(text),
422 AttrInput::Literal(
423 lit @ tt::Literal { kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), .. },
424 ) => Some(lit.text()),
426425 _ => None,
427426 }
428427 }
429428
430429 /// #[path = "string"]
431 pub fn string_value_with_span(&self) -> Option<(&Symbol, span::Span)> {
430 pub fn string_value_with_span(&self) -> Option<(&str, span::Span)> {
432431 match self.input.as_deref()? {
433 AttrInput::Literal(tt::Literal {
434 symbol: text,
435 kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
436 span,
437 suffix: _,
438 }) => Some((text, *span)),
432 AttrInput::Literal(
433 lit @ tt::Literal { kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), span, .. },
434 ) => Some((lit.text(), *span)),
439435 _ => None,
440436 }
441437 }
442438
443439 pub fn string_value_unescape(&self) -> Option<Cow<'_, str>> {
444440 match self.input.as_deref()? {
445 AttrInput::Literal(tt::Literal {
446 symbol: text, kind: tt::LitKind::StrRaw(_), ..
447 }) => Some(Cow::Borrowed(text.as_str())),
448 AttrInput::Literal(tt::Literal { symbol: text, kind: tt::LitKind::Str, .. }) => {
449 unescape(text.as_str())
441 AttrInput::Literal(lit @ tt::Literal { kind: tt::LitKind::StrRaw(_), .. }) => {
442 Some(Cow::Borrowed(lit.text()))
443 }
444 AttrInput::Literal(lit @ tt::Literal { kind: tt::LitKind::Str, .. }) => {
445 unescape(lit.text())
450446 }
451447 _ => None,
452448 }
453449 }
454450
455451 /// #[path(ident)]
456 pub fn single_ident_value(&self) -> Option<&tt::Ident> {
452 pub fn single_ident_value(&self) -> Option<tt::Ident> {
457453 match self.input.as_deref()? {
458 AttrInput::TokenTree(tt) => match tt.token_trees().flat_tokens() {
459 [tt::TokenTree::Leaf(tt::Leaf::Ident(ident))] => Some(ident),
454 AttrInput::TokenTree(tt) => match tt.token_trees().iter().collect_array() {
455 Some([tt::TtElement::Leaf(tt::Leaf::Ident(ident))]) => Some(ident),
460456 _ => None,
461457 },
462458 _ => None,
......@@ -492,7 +488,7 @@ fn parse_path_comma_token_tree<'a>(
492488 args.token_trees()
493489 .split(|tt| matches!(tt, tt::TtElement::Leaf(tt::Leaf::Punct(Punct { char: ',', .. }))))
494490 .filter_map(move |tts| {
495 let span = tts.flat_tokens().first()?.first_span();
491 let span = tts.first_span()?;
496492 Some((ModPath::from_tt(db, tts)?, span, tts))
497493 })
498494}
......@@ -611,16 +607,12 @@ impl AttrId {
611607 else {
612608 return derive_attr_range;
613609 };
614 let (Some(first_tt), Some(last_tt)) =
615 (derive_tts.flat_tokens().first(), derive_tts.flat_tokens().last())
610 let (Some(first_span), Some(last_span)) = (derive_tts.first_span(), derive_tts.last_span())
616611 else {
617612 return derive_attr_range;
618613 };
619 let start = first_tt.first_span().range.start();
620 let end = match last_tt {
621 tt::TokenTree::Leaf(it) => it.span().range.end(),
622 tt::TokenTree::Subtree(it) => it.delimiter.close.range.end(),
623 };
614 let start = first_span.range.start();
615 let end = last_span.range.end();
624616 TextRange::new(start, end)
625617 }
626618}
src/tools/rust-analyzer/crates/hir-expand/src/builtin/derive_macro.rs+5-6
......@@ -5,7 +5,7 @@ use intern::sym;
55use itertools::{Itertools, izip};
66use parser::SyntaxKind;
77use rustc_hash::FxHashSet;
8use span::{Edition, Span, SyntaxContext};
8use span::{Edition, Span};
99use stdx::never;
1010use syntax_bridge::DocCommentDesugarMode;
1111use tracing::debug;
......@@ -28,7 +28,7 @@ use syntax::{
2828};
2929
3030macro_rules! register_builtin {
31 ( $($trait:ident => $expand:ident),* ) => {
31 ( $($trait:ident => $expand:ident),* $(,)? ) => {
3232 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3333 pub enum BuiltinDeriveExpander {
3434 $($trait),*
......@@ -48,7 +48,6 @@ macro_rules! register_builtin {
4848 }
4949 }
5050 }
51
5251 };
5352}
5453
......@@ -75,7 +74,7 @@ register_builtin! {
7574 PartialOrd => partial_ord_expand,
7675 Eq => eq_expand,
7776 PartialEq => partial_eq_expand,
78 CoercePointee => coerce_pointee_expand
77 CoercePointee => coerce_pointee_expand,
7978}
8079
8180pub fn find_builtin_derive(ident: &name::Name) -> Option<BuiltinDeriveExpander> {
......@@ -239,7 +238,7 @@ fn parse_adt(
239238
240239fn parse_adt_from_syntax(
241240 adt: &ast::Adt,
242 tm: &span::SpanMap<SyntaxContext>,
241 tm: &span::SpanMap,
243242 call_site: Span,
244243) -> Result<BasicAdtInfo, ExpandError> {
245244 let (name, generic_param_list, where_clause, shape) = match &adt {
......@@ -391,7 +390,7 @@ fn to_adt_syntax(
391390 db: &dyn ExpandDatabase,
392391 tt: &tt::TopSubtree,
393392 call_site: Span,
394) -> Result<(ast::Adt, span::SpanMap<SyntaxContext>), ExpandError> {
393) -> Result<(ast::Adt, span::SpanMap), ExpandError> {
395394 let (parsed, tm) = crate::db::token_tree_to_syntax_node(db, tt, crate::ExpandTo::Items);
396395 let macro_items = ast::MacroItems::cast(parsed.syntax_node())
397396 .ok_or_else(|| ExpandError::other(call_site, "invalid item definition"))?;
src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs+65-87
......@@ -1,5 +1,7 @@
11//! Builtin macro
22
3use std::borrow::Cow;
4
35use base_db::AnchoredPath;
46use cfg::CfgExpr;
57use either::Either;
......@@ -13,7 +15,7 @@ use span::{Edition, FileId, Span};
1315use stdx::format_to;
1416use syntax::{
1517 format_smolstr,
16 unescape::{unescape_byte, unescape_char, unescape_str},
18 unescape::{unescape_byte, unescape_char},
1719};
1820use syntax_bridge::syntax_node_to_token_tree;
1921
......@@ -177,12 +179,7 @@ fn line_expand(
177179 // not incremental
178180 ExpandResult::ok(tt::TopSubtree::invisible_from_leaves(
179181 span,
180 [tt::Leaf::Literal(tt::Literal {
181 symbol: sym::INTEGER_0,
182 span,
183 kind: tt::LitKind::Integer,
184 suffix: Some(sym::u32),
185 })],
182 [tt::Leaf::Literal(tt::Literal::new("0", span, tt::LitKind::Integer, "u32"))],
186183 ))
187184}
188185
......@@ -210,7 +207,7 @@ fn stringify_expand(
210207 tt: &tt::TopSubtree,
211208 span: Span,
212209) -> ExpandResult<tt::TopSubtree> {
213 let pretty = ::tt::pretty(tt.token_trees().flat_tokens());
210 let pretty = ::tt::pretty(tt.token_trees());
214211
215212 let expanded = quote! {span =>
216213 #pretty
......@@ -283,7 +280,7 @@ fn format_args_expand(
283280) -> ExpandResult<tt::TopSubtree> {
284281 let pound = mk_pound(span);
285282 let mut tt = tt.clone();
286 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
283 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
287284 ExpandResult::ok(quote! {span =>
288285 builtin #pound format_args #tt
289286 })
......@@ -297,14 +294,15 @@ fn format_args_nl_expand(
297294) -> ExpandResult<tt::TopSubtree> {
298295 let pound = mk_pound(span);
299296 let mut tt = tt.clone();
300 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
301 if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
302 symbol: text,
303 kind: tt::LitKind::Str,
304 ..
305 }))) = tt.0.get_mut(1)
297 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
298 let lit = tt.as_token_trees().iter_flat_tokens().nth(1);
299 if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(
300 mut lit @ tt::Literal { kind: tt::LitKind::Str, .. },
301 ))) = lit
306302 {
307 *text = Symbol::intern(&format_smolstr!("{}\\n", text.as_str()));
303 let (text, suffix) = lit.text_and_suffix();
304 lit.text_and_suffix = Symbol::intern(&format_smolstr!("{text}\\n{suffix}"));
305 tt.set_token(1, lit.into());
308306 }
309307 ExpandResult::ok(quote! {span =>
310308 builtin #pound format_args #tt
......@@ -318,7 +316,7 @@ fn asm_expand(
318316 span: Span,
319317) -> ExpandResult<tt::TopSubtree> {
320318 let mut tt = tt.clone();
321 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
319 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
322320 let pound = mk_pound(span);
323321 let expanded = quote! {span =>
324322 builtin #pound asm #tt
......@@ -333,7 +331,7 @@ fn global_asm_expand(
333331 span: Span,
334332) -> ExpandResult<tt::TopSubtree> {
335333 let mut tt = tt.clone();
336 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
334 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
337335 let pound = mk_pound(span);
338336 let expanded = quote! {span =>
339337 builtin #pound global_asm #tt
......@@ -348,7 +346,7 @@ fn naked_asm_expand(
348346 span: Span,
349347) -> ExpandResult<tt::TopSubtree> {
350348 let mut tt = tt.clone();
351 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Parenthesis;
349 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
352350 let pound = mk_pound(span);
353351 let expanded = quote! {span =>
354352 builtin #pound naked_asm #tt
......@@ -478,11 +476,11 @@ fn unreachable_expand(
478476
479477 // Pass the original arguments
480478 let mut subtree = tt.clone();
481 *subtree.top_subtree_delimiter_mut() = tt::Delimiter {
479 subtree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Parenthesis);
480 subtree.set_top_subtree_delimiter_span(tt::DelimSpan {
482481 open: call_site_span,
483482 close: call_site_span,
484 kind: tt::DelimiterKind::Parenthesis,
485 };
483 });
486484
487485 // Expand to a macro call `$crate::panic::panic_{edition}`
488486 let call = quote!(call_site_span =>#dollar_crate::panic::#mac! #subtree);
......@@ -518,16 +516,14 @@ fn compile_error_expand(
518516 tt: &tt::TopSubtree,
519517 span: Span,
520518) -> ExpandResult<tt::TopSubtree> {
521 let err = match &*tt.0 {
522 [
523 _,
524 tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
525 symbol: text,
526 span: _,
527 kind: tt::LitKind::Str | tt::LitKind::StrRaw(_),
528 suffix: _,
529 })),
530 ] => ExpandError::other(span, Box::from(unescape_symbol(text).as_str())),
519 let err = match tt.iter().collect_array() {
520 Some(
521 [
522 tt::TtElement::Leaf(tt::Leaf::Literal(
523 lit @ tt::Literal { kind: tt::LitKind::Str | tt::LitKind::StrRaw(_), .. },
524 )),
525 ],
526 ) => ExpandError::other(span, Box::from(unescape_str(lit.text()))),
531527 _ => ExpandError::other(span, "`compile_error!` argument must be a string"),
532528 };
533529
......@@ -556,7 +552,7 @@ fn concat_expand(
556552 // to ensure the right parsing order, so skip the parentheses here. Ideally we'd
557553 // implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
558554 if let TtElement::Subtree(subtree, subtree_iter) = &t
559 && let [tt::TokenTree::Leaf(tt)] = subtree_iter.remaining().flat_tokens()
555 && let Some([tt::TtElement::Leaf(tt)]) = subtree_iter.clone().collect_array()
560556 && subtree.delimiter.kind == tt::DelimiterKind::Parenthesis
561557 {
562558 t = TtElement::Leaf(tt);
......@@ -568,20 +564,20 @@ fn concat_expand(
568564 // as-is.
569565 match it.kind {
570566 tt::LitKind::Char => {
571 if let Ok(c) = unescape_char(it.symbol.as_str()) {
567 if let Ok(c) = unescape_char(it.text()) {
572568 text.push(c);
573569 }
574570 record_span(it.span);
575571 }
576572 tt::LitKind::Integer | tt::LitKind::Float => {
577 format_to!(text, "{}", it.symbol.as_str())
573 format_to!(text, "{}", it.text())
578574 }
579575 tt::LitKind::Str => {
580 text.push_str(unescape_symbol(&it.symbol).as_str());
576 text.push_str(&unescape_str(it.text()));
581577 record_span(it.span);
582578 }
583579 tt::LitKind::StrRaw(_) => {
584 format_to!(text, "{}", it.symbol.as_str());
580 format_to!(text, "{}", it.text());
585581 record_span(it.span);
586582 }
587583 tt::LitKind::Byte
......@@ -619,7 +615,7 @@ fn concat_expand(
619615 TtElement::Leaf(tt::Leaf::Literal(it))
620616 if matches!(it.kind, tt::LitKind::Integer | tt::LitKind::Float) =>
621617 {
622 format_to!(text, "-{}", it.symbol.as_str());
618 format_to!(text, "-{}", it.text());
623619 record_span(punct.span.cover(it.span));
624620 }
625621 _ => {
......@@ -657,29 +653,25 @@ fn concat_bytes_expand(
657653 };
658654 for (i, t) in tt.iter().enumerate() {
659655 match t {
660 TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
661 symbol: text,
662 span,
663 kind,
664 suffix: _,
665 })) => {
666 record_span(*span);
656 TtElement::Leaf(tt::Leaf::Literal(lit @ tt::Literal { span, kind, .. })) => {
657 let text = lit.text();
658 record_span(span);
667659 match kind {
668660 tt::LitKind::Byte => {
669 if let Ok(b) = unescape_byte(text.as_str()) {
661 if let Ok(b) = unescape_byte(text) {
670662 bytes.extend(
671663 b.escape_ascii().filter_map(|it| char::from_u32(it as u32)),
672664 );
673665 }
674666 }
675667 tt::LitKind::ByteStr => {
676 bytes.push_str(text.as_str());
668 bytes.push_str(text);
677669 }
678670 tt::LitKind::ByteStrRaw(_) => {
679 bytes.extend(text.as_str().escape_debug());
671 bytes.extend(text.escape_debug());
680672 }
681673 _ => {
682 err.get_or_insert(ExpandError::other(*span, "unexpected token"));
674 err.get_or_insert(ExpandError::other(span, "unexpected token"));
683675 break;
684676 }
685677 }
......@@ -705,12 +697,7 @@ fn concat_bytes_expand(
705697 ExpandResult {
706698 value: tt::TopSubtree::invisible_from_leaves(
707699 span,
708 [tt::Leaf::Literal(tt::Literal {
709 symbol: Symbol::intern(&bytes),
710 span,
711 kind: tt::LitKind::ByteStr,
712 suffix: None,
713 })],
700 [tt::Leaf::Literal(tt::Literal::new_no_suffix(&bytes, span, tt::LitKind::ByteStr))],
714701 ),
715702 err,
716703 }
......@@ -724,25 +711,19 @@ fn concat_bytes_expand_subtree(
724711) -> Result<(), ExpandError> {
725712 for (ti, tt) in tree_iter.enumerate() {
726713 match tt {
727 TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
728 symbol: text,
729 span,
730 kind: tt::LitKind::Byte,
731 suffix: _,
732 })) => {
733 if let Ok(b) = unescape_byte(text.as_str()) {
714 TtElement::Leaf(tt::Leaf::Literal(
715 lit @ tt::Literal { span, kind: tt::LitKind::Byte, .. },
716 )) => {
717 if let Ok(b) = unescape_byte(lit.text()) {
734718 bytes.extend(b.escape_ascii().filter_map(|it| char::from_u32(it as u32)));
735719 }
736 record_span(*span);
720 record_span(span);
737721 }
738 TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
739 symbol: text,
740 span,
741 kind: tt::LitKind::Integer,
742 suffix: _,
743 })) => {
744 record_span(*span);
745 if let Ok(b) = text.as_str().parse::<u8>() {
722 TtElement::Leaf(tt::Leaf::Literal(
723 lit @ tt::Literal { span, kind: tt::LitKind::Integer, .. },
724 )) => {
725 record_span(span);
726 if let Ok(b) = lit.text().parse::<u8>() {
746727 bytes.extend(b.escape_ascii().filter_map(|it| char::from_u32(it as u32)));
747728 }
748729 }
......@@ -791,18 +772,16 @@ fn parse_string(tt: &tt::TopSubtree) -> Result<(Symbol, Span), ExpandError> {
791772 }
792773
793774 match tt {
794 TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
795 symbol: text,
775 TtElement::Leaf(tt::Leaf::Literal(lit @ tt::Literal {
796776 span,
797777 kind: tt::LitKind::Str,
798 suffix: _,
799 })) => Ok((unescape_symbol(text), *span)),
800 TtElement::Leaf(tt::Leaf::Literal(tt::Literal {
801 symbol: text,
778 ..
779 })) => Ok((Symbol::intern(&unescape_str(lit.text())), span)),
780 TtElement::Leaf(tt::Leaf::Literal(lit @ tt::Literal {
802781 span,
803782 kind: tt::LitKind::StrRaw(_),
804 suffix: _,
805 })) => Ok((text.clone(), *span)),
783 ..
784 })) => Ok((Symbol::intern(lit.text()), span)),
806785 TtElement::Leaf(l) => Err(*l.span()),
807786 TtElement::Subtree(tt, _) => Err(tt.delimiter.open.cover(tt.delimiter.close)),
808787 }
......@@ -854,10 +833,10 @@ fn include_bytes_expand(
854833 let res = tt::TopSubtree::invisible_from_leaves(
855834 span,
856835 [tt::Leaf::Literal(tt::Literal {
857 symbol: Symbol::empty(),
836 text_and_suffix: Symbol::empty(),
858837 span,
859838 kind: tt::LitKind::ByteStrRaw(1),
860 suffix: None,
839 suffix_len: 0,
861840 })],
862841 );
863842 ExpandResult::ok(res)
......@@ -978,17 +957,16 @@ fn quote_expand(
978957 )
979958}
980959
981fn unescape_symbol(s: &Symbol) -> Symbol {
982 if s.as_str().contains('\\') {
983 let s = s.as_str();
960fn unescape_str(s: &str) -> Cow<'_, str> {
961 if s.contains('\\') {
984962 let mut buf = String::with_capacity(s.len());
985 unescape_str(s, |_, c| {
963 syntax::unescape::unescape_str(s, |_, c| {
986964 if let Ok(c) = c {
987965 buf.push(c)
988966 }
989967 });
990 Symbol::intern(&buf)
968 Cow::Owned(buf)
991969 } else {
992 s.clone()
970 Cow::Borrowed(s)
993971 }
994972}
src/tools/rust-analyzer/crates/hir-expand/src/builtin/quote.rs+10-11
......@@ -8,7 +8,7 @@ use tt::IdentIsRaw;
88
99use crate::{name::Name, tt::TopSubtreeBuilder};
1010
11pub(crate) fn dollar_crate(span: Span) -> tt::Ident<Span> {
11pub(crate) fn dollar_crate(span: Span) -> tt::Ident {
1212 tt::Ident { sym: sym::dollar_crate, span, is_raw: tt::IdentIsRaw::No }
1313}
1414
......@@ -163,7 +163,7 @@ impl ToTokenTree for crate::tt::SubtreeView<'_> {
163163
164164impl ToTokenTree for crate::tt::TopSubtree {
165165 fn to_tokens(self, _: Span, builder: &mut TopSubtreeBuilder) {
166 builder.extend_tt_dangerous(self.0);
166 builder.extend_with_tt(self.as_token_trees());
167167 }
168168}
169169
......@@ -172,10 +172,9 @@ impl ToTokenTree for crate::tt::TtElement<'_> {
172172 match self {
173173 crate::tt::TtElement::Leaf(leaf) => builder.push(leaf.clone()),
174174 crate::tt::TtElement::Subtree(subtree, subtree_iter) => {
175 builder.extend_tt_dangerous(
176 std::iter::once(crate::tt::TokenTree::Subtree(subtree.clone()))
177 .chain(subtree_iter.remaining().flat_tokens().iter().cloned()),
178 );
175 builder.open(subtree.delimiter.kind, subtree.delimiter.open);
176 builder.extend_with_tt(subtree_iter.remaining());
177 builder.close(subtree.delimiter.close);
179178 }
180179 }
181180 }
......@@ -200,16 +199,16 @@ impl<T: ToTokenTree + Clone> ToTokenTree for &T {
200199}
201200
202201impl_to_to_tokentrees! {
203 span: u32 => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
204 span: usize => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
205 span: i32 => self { crate::tt::Literal{symbol: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix: None } };
202 span: u32 => self { crate::tt::Literal{text_and_suffix: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix_len: 0 } };
203 span: usize => self { crate::tt::Literal{text_and_suffix: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix_len: 0 } };
204 span: i32 => self { crate::tt::Literal{text_and_suffix: Symbol::integer(self as _), span, kind: tt::LitKind::Integer, suffix_len: 0 } };
206205 span: bool => self { crate::tt::Ident{sym: if self { sym::true_ } else { sym::false_ }, span, is_raw: tt::IdentIsRaw::No } };
207206 _span: crate::tt::Leaf => self { self };
208207 _span: crate::tt::Literal => self { self };
209208 _span: crate::tt::Ident => self { self };
210209 _span: crate::tt::Punct => self { self };
211 span: &str => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }};
212 span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }};
210 span: &str => self { crate::tt::Literal{text_and_suffix: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix_len: 0 }};
211 span: String => self { crate::tt::Literal{text_and_suffix: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix_len: 0 }};
213212 span: Name => self {
214213 let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str());
215214 crate::tt::Ident{sym: Symbol::intern(s), span, is_raw }
src/tools/rust-analyzer/crates/hir-expand/src/db.rs+8-6
......@@ -237,7 +237,8 @@ pub fn expand_speculative(
237237 span,
238238 DocCommentDesugarMode::ProcMacro,
239239 );
240 *tree.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
240 tree.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
241 tree.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span));
241242 tree
242243 },
243244 )
......@@ -255,7 +256,7 @@ pub fn expand_speculative(
255256 span,
256257 DocCommentDesugarMode::ProcMacro,
257258 );
258 attr_arg.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
259 attr_arg.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
259260 Some(attr_arg)
260261 }
261262 _ => None,
......@@ -270,7 +271,8 @@ pub fn expand_speculative(
270271 let mut speculative_expansion = match loc.def.kind {
271272 MacroDefKind::ProcMacro(ast, expander, _) => {
272273 let span = db.proc_macro_span(ast);
273 *tt.top_subtree_delimiter_mut() = tt::Delimiter::invisible_spanned(span);
274 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
275 tt.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(span));
274276 expander.expand(
275277 db,
276278 loc.def.krate,
......@@ -430,7 +432,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
430432 (
431433 Arc::new(tt::TopSubtree::from_token_trees(
432434 tt::Delimiter { open: span, close: span, kind },
433 tt::TokenTreesView::new(&[]),
435 tt::TokenTreesView::empty(),
434436 )),
435437 SyntaxFixupUndoInfo::default(),
436438 span,
......@@ -478,7 +480,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
478480 );
479481 if loc.def.is_proc_macro() {
480482 // proc macros expect their inputs without parentheses, MBEs expect it with them included
481 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
483 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
482484 }
483485 return (Arc::new(tt), SyntaxFixupUndoInfo::NONE, span);
484486 }
......@@ -512,7 +514,7 @@ fn macro_arg(db: &dyn ExpandDatabase, id: MacroCallId) -> MacroArgResult {
512514
513515 if loc.def.is_proc_macro() {
514516 // proc macros expect their inputs without parentheses, MBEs expect it with them included
515 tt.top_subtree_delimiter_mut().kind = tt::DelimiterKind::Invisible;
517 tt.set_top_subtree_delimiter_kind(tt::DelimiterKind::Invisible);
516518 }
517519
518520 (Arc::new(tt), undo_info, span)
src/tools/rust-analyzer/crates/hir-expand/src/eager.rs+1-1
......@@ -96,7 +96,7 @@ pub fn expand_eager_macro_input(
9696 DocCommentDesugarMode::Mbe,
9797 );
9898
99 subtree.top_subtree_delimiter_mut().kind = crate::tt::DelimiterKind::Invisible;
99 subtree.set_top_subtree_delimiter_kind(crate::tt::DelimiterKind::Invisible);
100100
101101 let loc = MacroCallLoc {
102102 def,
src/tools/rust-analyzer/crates/hir-expand/src/fixup.rs+16-81
......@@ -15,7 +15,7 @@ use syntax::{
1515};
1616use syntax_bridge::DocCommentDesugarMode;
1717use triomphe::Arc;
18use tt::Spacing;
18use tt::{Spacing, TransformTtAction, transform_tt};
1919
2020use crate::{
2121 span_map::SpanMapRef,
......@@ -343,93 +343,29 @@ fn has_error_to_handle(node: &SyntaxNode) -> bool {
343343pub(crate) fn reverse_fixups(tt: &mut TopSubtree, undo_info: &SyntaxFixupUndoInfo) {
344344 let Some(undo_info) = undo_info.original.as_deref() else { return };
345345 let undo_info = &**undo_info;
346 let delimiter = tt.top_subtree_delimiter_mut();
346 let top_subtree = tt.top_subtree();
347 let open_span = top_subtree.delimiter.open;
348 let close_span = top_subtree.delimiter.close;
347349 #[allow(deprecated)]
348350 if never!(
349 delimiter.close.anchor.ast_id == FIXUP_DUMMY_AST_ID
350 || delimiter.open.anchor.ast_id == FIXUP_DUMMY_AST_ID
351 close_span.anchor.ast_id == FIXUP_DUMMY_AST_ID
352 || open_span.anchor.ast_id == FIXUP_DUMMY_AST_ID
351353 ) {
352354 let span = |file_id| Span {
353355 range: TextRange::empty(TextSize::new(0)),
354356 anchor: SpanAnchor { file_id, ast_id: ROOT_ERASED_FILE_AST_ID },
355357 ctx: SyntaxContext::root(span::Edition::Edition2015),
356358 };
357 delimiter.open = span(delimiter.open.anchor.file_id);
358 delimiter.close = span(delimiter.close.anchor.file_id);
359 tt.set_top_subtree_delimiter_span(tt::DelimSpan {
360 open: span(open_span.anchor.file_id),
361 close: span(close_span.anchor.file_id),
362 });
359363 }
360364 reverse_fixups_(tt, undo_info);
361365}
362366
363#[derive(Debug)]
364enum TransformTtAction<'a> {
365 Keep,
366 ReplaceWith(tt::TokenTreesView<'a>),
367}
368
369impl TransformTtAction<'_> {
370 fn remove() -> Self {
371 Self::ReplaceWith(tt::TokenTreesView::new(&[]))
372 }
373}
374
375/// This function takes a token tree, and calls `callback` with each token tree in it.
376/// Then it does what the callback says: keeps the tt or replaces it with a (possibly empty)
377/// tts view.
378fn transform_tt<'a, 'b>(
379 tt: &'a mut Vec<tt::TokenTree>,
380 mut callback: impl FnMut(&mut tt::TokenTree) -> TransformTtAction<'b>,
381) {
382 // We need to keep a stack of the currently open subtrees, because we need to update
383 // them if we change the number of items in them.
384 let mut subtrees_stack = Vec::new();
385 let mut i = 0;
386 while i < tt.len() {
387 'pop_finished_subtrees: while let Some(&subtree_idx) = subtrees_stack.last() {
388 let tt::TokenTree::Subtree(subtree) = &tt[subtree_idx] else {
389 unreachable!("non-subtree on subtrees stack");
390 };
391 if i >= subtree_idx + 1 + subtree.usize_len() {
392 subtrees_stack.pop();
393 } else {
394 break 'pop_finished_subtrees;
395 }
396 }
397
398 let action = callback(&mut tt[i]);
399 match action {
400 TransformTtAction::Keep => {
401 // This cannot be shared with the replaced case, because then we may push the same subtree
402 // twice, and will update it twice which will lead to errors.
403 if let tt::TokenTree::Subtree(_) = &tt[i] {
404 subtrees_stack.push(i);
405 }
406
407 i += 1;
408 }
409 TransformTtAction::ReplaceWith(replacement) => {
410 let old_len = 1 + match &tt[i] {
411 tt::TokenTree::Leaf(_) => 0,
412 tt::TokenTree::Subtree(subtree) => subtree.usize_len(),
413 };
414 let len_diff = replacement.len() as i64 - old_len as i64;
415 tt.splice(i..i + old_len, replacement.flat_tokens().iter().cloned());
416 // Skip the newly inserted replacement, we don't want to visit it.
417 i += replacement.len();
418
419 for &subtree_idx in &subtrees_stack {
420 let tt::TokenTree::Subtree(subtree) = &mut tt[subtree_idx] else {
421 unreachable!("non-subtree on subtrees stack");
422 };
423 subtree.len = (i64::from(subtree.len) + len_diff).try_into().unwrap();
424 }
425 }
426 }
427 }
428}
429
430367fn reverse_fixups_(tt: &mut TopSubtree, undo_info: &[TopSubtree]) {
431 let mut tts = std::mem::take(&mut tt.0).into_vec();
432 transform_tt(&mut tts, |tt| match tt {
368 transform_tt(tt, |tt| match tt {
433369 tt::TokenTree::Leaf(leaf) => {
434370 let span = leaf.span();
435371 let is_real_leaf = span.anchor.ast_id != FIXUP_DUMMY_AST_ID;
......@@ -459,7 +395,6 @@ fn reverse_fixups_(tt: &mut TopSubtree, undo_info: &[TopSubtree]) {
459395 TransformTtAction::Keep
460396 }
461397 });
462 tt.0 = tts.into_boxed_slice();
463398}
464399
465400#[cfg(test)]
......@@ -480,7 +415,7 @@ mod tests {
480415 // `TokenTree`s, see the last assertion in `check()`.
481416 fn check_leaf_eq(a: &tt::Leaf, b: &tt::Leaf) -> bool {
482417 match (a, b) {
483 (tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.symbol == b.symbol,
418 (tt::Leaf::Literal(a), tt::Leaf::Literal(b)) => a.text_and_suffix == b.text_and_suffix,
484419 (tt::Leaf::Punct(a), tt::Leaf::Punct(b)) => a.char == b.char,
485420 (tt::Leaf::Ident(a), tt::Leaf::Ident(b)) => a.sym == b.sym,
486421 _ => false,
......@@ -488,9 +423,9 @@ mod tests {
488423 }
489424
490425 fn check_subtree_eq(a: &tt::TopSubtree, b: &tt::TopSubtree) -> bool {
491 let a = a.view().as_token_trees().flat_tokens();
492 let b = b.view().as_token_trees().flat_tokens();
493 a.len() == b.len() && std::iter::zip(a, b).all(|(a, b)| check_tt_eq(a, b))
426 let a = a.view().as_token_trees().iter_flat_tokens();
427 let b = b.view().as_token_trees().iter_flat_tokens();
428 a.len() == b.len() && std::iter::zip(a, b).all(|(a, b)| check_tt_eq(&a, &b))
494429 }
495430
496431 fn check_tt_eq(a: &tt::TokenTree, b: &tt::TokenTree) -> bool {
......@@ -545,7 +480,7 @@ mod tests {
545480
546481 // the fixed-up tree should not contain braces as punct
547482 // FIXME: should probably instead check that it's a valid punctuation character
548 for x in tt.token_trees().flat_tokens() {
483 for x in tt.token_trees().iter_flat_tokens() {
549484 match x {
550485 ::tt::TokenTree::Leaf(::tt::Leaf::Punct(punct)) => {
551486 assert!(!matches!(punct.char, '{' | '}' | '(' | ')' | '[' | ']'))
src/tools/rust-analyzer/crates/hir-expand/src/lib.rs+1-19
......@@ -66,25 +66,7 @@ pub use crate::{
6666pub use base_db::EditionedFileId;
6767pub use mbe::{DeclarativeMacro, MacroCallStyle, MacroCallStyles, ValueResult};
6868
69pub mod tt {
70 pub use span::Span;
71 pub use tt::{DelimiterKind, IdentIsRaw, LitKind, Spacing, token_to_literal};
72
73 pub type Delimiter = ::tt::Delimiter<Span>;
74 pub type DelimSpan = ::tt::DelimSpan<Span>;
75 pub type Subtree = ::tt::Subtree<Span>;
76 pub type Leaf = ::tt::Leaf<Span>;
77 pub type Literal = ::tt::Literal<Span>;
78 pub type Punct = ::tt::Punct<Span>;
79 pub type Ident = ::tt::Ident<Span>;
80 pub type TokenTree = ::tt::TokenTree<Span>;
81 pub type TopSubtree = ::tt::TopSubtree<Span>;
82 pub type TopSubtreeBuilder = ::tt::TopSubtreeBuilder<Span>;
83 pub type TokenTreesView<'a> = ::tt::TokenTreesView<'a, Span>;
84 pub type SubtreeView<'a> = ::tt::SubtreeView<'a, Span>;
85 pub type TtElement<'a> = ::tt::iter::TtElement<'a, Span>;
86 pub type TtIter<'a> = ::tt::iter::TtIter<'a, Span>;
87}
69pub use tt;
8870
8971#[macro_export]
9072macro_rules! impl_intern_lookup {
src/tools/rust-analyzer/crates/hir-expand/src/mod_path.rs+5-5
......@@ -355,16 +355,16 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio
355355 tt::Leaf::Punct(tt::Punct { char: ':', .. }) => PathKind::Abs,
356356 _ => return None,
357357 },
358 tt::Leaf::Ident(tt::Ident { sym: text, span, .. }) if *text == sym::dollar_crate => {
358 tt::Leaf::Ident(tt::Ident { sym: text, span, .. }) if text == sym::dollar_crate => {
359359 resolve_crate_root(db, span.ctx).map(PathKind::DollarCrate).unwrap_or(PathKind::Crate)
360360 }
361 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::self_ => PathKind::SELF,
362 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::super_ => {
361 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::self_ => PathKind::SELF,
362 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::super_ => {
363363 let mut deg = 1;
364364 while let Some(tt::Leaf::Ident(tt::Ident { sym: text, span, is_raw: _ })) =
365365 leaves.next()
366366 {
367 if *text != sym::super_ {
367 if text != sym::super_ {
368368 segments.push(Name::new_symbol(text.clone(), span.ctx));
369369 break;
370370 }
......@@ -372,7 +372,7 @@ fn convert_path_tt(db: &dyn ExpandDatabase, tt: tt::TokenTreesView<'_>) -> Optio
372372 }
373373 PathKind::Super(deg)
374374 }
375 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if *text == sym::crate_ => PathKind::Crate,
375 tt::Leaf::Ident(tt::Ident { sym: text, .. }) if text == sym::crate_ => PathKind::Crate,
376376 tt::Leaf::Ident(ident) => {
377377 segments.push(Name::new_symbol(ident.sym.clone(), ident.span.ctx));
378378 PathKind::Plain
src/tools/rust-analyzer/crates/hir-expand/src/name.rs+1-1
......@@ -258,7 +258,7 @@ impl AsName for ast::NameOrNameRef {
258258 }
259259}
260260
261impl<Span> AsName for tt::Ident<Span> {
261impl AsName for tt::Ident {
262262 fn as_name(&self) -> Name {
263263 Name::new_root(self.sym.as_str())
264264 }
src/tools/rust-analyzer/crates/hir-expand/src/proc_macro.rs+3-1
......@@ -4,7 +4,7 @@ use core::fmt;
44use std::any::Any;
55use std::{panic::RefUnwindSafe, sync};
66
7use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError};
7use base_db::{Crate, CrateBuilderId, CratesIdMap, Env, ProcMacroLoadingError, SourceDatabase};
88use intern::Symbol;
99use rustc_hash::FxHashMap;
1010use span::Span;
......@@ -25,6 +25,7 @@ pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
2525 /// [`ProcMacroKind::Attr`]), environment variables, and span information.
2626 fn expand(
2727 &self,
28 db: &dyn SourceDatabase,
2829 subtree: &tt::TopSubtree,
2930 attrs: Option<&tt::TopSubtree>,
3031 env: &Env,
......@@ -309,6 +310,7 @@ impl CustomProcMacroExpander {
309310 let current_dir = calling_crate.data(db).proc_macro_cwd.to_string();
310311
311312 match proc_macro.expander.expand(
313 db,
312314 tt,
313315 attr_arg,
314316 env,
src/tools/rust-analyzer/crates/hir-expand/src/span_map.rs+4-4
......@@ -1,6 +1,6 @@
11//! Span maps for real files and macro expansions.
22
3use span::{Span, SyntaxContext};
3use span::Span;
44use syntax::{AstNode, TextRange, ast};
55use triomphe::Arc;
66
......@@ -8,7 +8,7 @@ pub use span::RealSpanMap;
88
99use crate::{HirFileId, MacroCallId, db::ExpandDatabase};
1010
11pub type ExpansionSpanMap = span::SpanMap<SyntaxContext>;
11pub type ExpansionSpanMap = span::SpanMap;
1212
1313/// Spanmap for a macro file or a real file
1414#[derive(Clone, Debug, PartialEq, Eq)]
......@@ -27,13 +27,13 @@ pub enum SpanMapRef<'a> {
2727 RealSpanMap(&'a RealSpanMap),
2828}
2929
30impl syntax_bridge::SpanMapper<Span> for SpanMap {
30impl syntax_bridge::SpanMapper for SpanMap {
3131 fn span_for(&self, range: TextRange) -> Span {
3232 self.span_for_range(range)
3333 }
3434}
3535
36impl syntax_bridge::SpanMapper<Span> for SpanMapRef<'_> {
36impl syntax_bridge::SpanMapper for SpanMapRef<'_> {
3737 fn span_for(&self, range: TextRange) -> Span {
3838 self.span_for_range(range)
3939 }
src/tools/rust-analyzer/crates/hir-ty/src/builtin_derive.rs created+599
......@@ -0,0 +1,599 @@
1//! Implementation of builtin derive impls.
2
3use std::ops::ControlFlow;
4
5use hir_def::{
6 AdtId, BuiltinDeriveImplId, BuiltinDeriveImplLoc, HasModule, LocalFieldId, TraitId,
7 TypeOrConstParamId, TypeParamId,
8 attrs::AttrFlags,
9 builtin_derive::BuiltinDeriveImplTrait,
10 hir::generics::{GenericParams, TypeOrConstParamData},
11};
12use itertools::Itertools;
13use la_arena::ArenaMap;
14use rustc_type_ir::{
15 AliasTyKind, Interner, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, Upcast,
16 inherent::{GenericArgs as _, IntoKind},
17};
18
19use crate::{
20 GenericPredicates,
21 db::HirDatabase,
22 next_solver::{
23 Clause, Clauses, DbInterner, EarlyBinder, GenericArgs, ParamEnv, StoredEarlyBinder,
24 StoredTy, TraitRef, Ty, TyKind, fold::fold_tys, generics::Generics,
25 },
26};
27
28fn coerce_pointee_new_type_param(trait_id: TraitId) -> TypeParamId {
29 // HACK: Fake the param.
30 // We cannot use a dummy param here, because it can leak into the IDE layer and that'll cause panics
31 // when e.g. trying to display it. So we use an existing param.
32 TypeParamId::from_unchecked(TypeOrConstParamId {
33 parent: trait_id.into(),
34 local_id: la_arena::Idx::from_raw(la_arena::RawIdx::from_u32(1)),
35 })
36}
37
38pub(crate) fn generics_of<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> Generics {
39 let db = interner.db;
40 let loc = id.loc(db);
41 match loc.trait_ {
42 BuiltinDeriveImplTrait::Copy
43 | BuiltinDeriveImplTrait::Clone
44 | BuiltinDeriveImplTrait::Default
45 | BuiltinDeriveImplTrait::Debug
46 | BuiltinDeriveImplTrait::Hash
47 | BuiltinDeriveImplTrait::Ord
48 | BuiltinDeriveImplTrait::PartialOrd
49 | BuiltinDeriveImplTrait::Eq
50 | BuiltinDeriveImplTrait::PartialEq => interner.generics_of(loc.adt.into()),
51 BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
52 let mut generics = interner.generics_of(loc.adt.into());
53 let trait_id = loc
54 .trait_
55 .get_id(interner.lang_items())
56 .expect("we don't pass the impl to the solver if we can't resolve the trait");
57 generics.push_param(coerce_pointee_new_type_param(trait_id).into());
58 generics
59 }
60 }
61}
62
63pub fn generic_params_count(db: &dyn HirDatabase, id: BuiltinDeriveImplId) -> usize {
64 let loc = id.loc(db);
65 let adt_params = GenericParams::new(db, loc.adt.into());
66 let extra_params_count = match loc.trait_ {
67 BuiltinDeriveImplTrait::Copy
68 | BuiltinDeriveImplTrait::Clone
69 | BuiltinDeriveImplTrait::Default
70 | BuiltinDeriveImplTrait::Debug
71 | BuiltinDeriveImplTrait::Hash
72 | BuiltinDeriveImplTrait::Ord
73 | BuiltinDeriveImplTrait::PartialOrd
74 | BuiltinDeriveImplTrait::Eq
75 | BuiltinDeriveImplTrait::PartialEq => 0,
76 BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => 1,
77 };
78 adt_params.len() + extra_params_count
79}
80
81pub fn impl_trait<'db>(
82 interner: DbInterner<'db>,
83 id: BuiltinDeriveImplId,
84) -> EarlyBinder<'db, TraitRef<'db>> {
85 let db = interner.db;
86 let loc = id.loc(db);
87 let trait_id = loc
88 .trait_
89 .get_id(interner.lang_items())
90 .expect("we don't pass the impl to the solver if we can't resolve the trait");
91 match loc.trait_ {
92 BuiltinDeriveImplTrait::Copy
93 | BuiltinDeriveImplTrait::Clone
94 | BuiltinDeriveImplTrait::Default
95 | BuiltinDeriveImplTrait::Debug
96 | BuiltinDeriveImplTrait::Hash
97 | BuiltinDeriveImplTrait::Ord
98 | BuiltinDeriveImplTrait::Eq => {
99 let self_ty = Ty::new_adt(
100 interner,
101 loc.adt,
102 GenericArgs::identity_for_item(interner, loc.adt.into()),
103 );
104 EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty]))
105 }
106 BuiltinDeriveImplTrait::PartialOrd | BuiltinDeriveImplTrait::PartialEq => {
107 let self_ty = Ty::new_adt(
108 interner,
109 loc.adt,
110 GenericArgs::identity_for_item(interner, loc.adt.into()),
111 );
112 EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty, self_ty]))
113 }
114 BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
115 let generic_params = GenericParams::new(db, loc.adt.into());
116 let interner = DbInterner::new_no_crate(db);
117 let args = GenericArgs::identity_for_item(interner, loc.adt.into());
118 let self_ty = Ty::new_adt(interner, loc.adt, args);
119 let Some((pointee_param_idx, _, new_param_ty)) =
120 coerce_pointee_params(interner, loc, &generic_params, trait_id)
121 else {
122 // Malformed derive.
123 return EarlyBinder::bind(TraitRef::new(
124 interner,
125 trait_id.into(),
126 [self_ty, self_ty],
127 ));
128 };
129 let changed_args = replace_pointee(interner, pointee_param_idx, new_param_ty, args);
130 let changed_self_ty = Ty::new_adt(interner, loc.adt, changed_args);
131 EarlyBinder::bind(TraitRef::new(interner, trait_id.into(), [self_ty, changed_self_ty]))
132 }
133 }
134}
135
136#[salsa::tracked(returns(ref), unsafe(non_update_types))]
137pub fn predicates<'db>(db: &'db dyn HirDatabase, impl_: BuiltinDeriveImplId) -> GenericPredicates {
138 let loc = impl_.loc(db);
139 let generic_params = GenericParams::new(db, loc.adt.into());
140 let interner = DbInterner::new_with(db, loc.module(db).krate(db));
141 let adt_predicates = GenericPredicates::query(db, loc.adt.into());
142 let trait_id = loc
143 .trait_
144 .get_id(interner.lang_items())
145 .expect("we don't pass the impl to the solver if we can't resolve the trait");
146 match loc.trait_ {
147 BuiltinDeriveImplTrait::Copy
148 | BuiltinDeriveImplTrait::Clone
149 | BuiltinDeriveImplTrait::Debug
150 | BuiltinDeriveImplTrait::Hash
151 | BuiltinDeriveImplTrait::Ord
152 | BuiltinDeriveImplTrait::PartialOrd
153 | BuiltinDeriveImplTrait::Eq
154 | BuiltinDeriveImplTrait::PartialEq => {
155 simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id)
156 }
157 BuiltinDeriveImplTrait::Default => {
158 if matches!(loc.adt, AdtId::EnumId(_)) {
159 // Enums don't have extra bounds.
160 GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
161 Clauses::new_from_slice(adt_predicates.explicit_predicates().skip_binder())
162 .store(),
163 ))
164 } else {
165 simple_trait_predicates(interner, loc, &generic_params, adt_predicates, trait_id)
166 }
167 }
168 BuiltinDeriveImplTrait::CoerceUnsized | BuiltinDeriveImplTrait::DispatchFromDyn => {
169 let Some((pointee_param_idx, pointee_param_id, new_param_ty)) =
170 coerce_pointee_params(interner, loc, &generic_params, trait_id)
171 else {
172 // Malformed derive.
173 return GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
174 Clauses::default().store(),
175 ));
176 };
177 let duplicated_bounds =
178 adt_predicates.explicit_predicates().iter_identity_copied().filter_map(|pred| {
179 let mentions_pointee =
180 pred.visit_with(&mut MentionsPointee { pointee_param_idx }).is_break();
181 if !mentions_pointee {
182 return None;
183 }
184 let transformed =
185 replace_pointee(interner, pointee_param_idx, new_param_ty, pred);
186 Some(transformed)
187 });
188 let unsize_trait = interner.lang_items().Unsize;
189 let unsize_bound = unsize_trait.map(|unsize_trait| {
190 let pointee_param_ty = Ty::new_param(interner, pointee_param_id, pointee_param_idx);
191 TraitRef::new(interner, unsize_trait.into(), [pointee_param_ty, new_param_ty])
192 .upcast(interner)
193 });
194 GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
195 Clauses::new_from_iter(
196 interner,
197 adt_predicates
198 .explicit_predicates()
199 .iter_identity_copied()
200 .chain(duplicated_bounds)
201 .chain(unsize_bound),
202 )
203 .store(),
204 ))
205 }
206 }
207}
208
209/// Not cached in a query, currently used in `hir` only. If you need this in `hir-ty` consider introducing a query.
210pub fn param_env<'db>(interner: DbInterner<'db>, id: BuiltinDeriveImplId) -> ParamEnv<'db> {
211 let predicates = predicates(interner.db, id);
212 crate::lower::param_env_from_predicates(interner, predicates)
213}
214
215struct MentionsPointee {
216 pointee_param_idx: u32,
217}
218
219impl<'db> TypeVisitor<DbInterner<'db>> for MentionsPointee {
220 type Result = ControlFlow<()>;
221
222 fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
223 if let TyKind::Param(param) = t.kind()
224 && param.index == self.pointee_param_idx
225 {
226 ControlFlow::Break(())
227 } else {
228 t.super_visit_with(self)
229 }
230 }
231}
232
233fn replace_pointee<'db, T: TypeFoldable<DbInterner<'db>>>(
234 interner: DbInterner<'db>,
235 pointee_param_idx: u32,
236 new_param_ty: Ty<'db>,
237 t: T,
238) -> T {
239 fold_tys(interner, t, |ty| match ty.kind() {
240 TyKind::Param(param) if param.index == pointee_param_idx => new_param_ty,
241 _ => ty,
242 })
243}
244
245fn simple_trait_predicates<'db>(
246 interner: DbInterner<'db>,
247 loc: &BuiltinDeriveImplLoc,
248 generic_params: &GenericParams,
249 adt_predicates: &GenericPredicates,
250 trait_id: TraitId,
251) -> GenericPredicates {
252 let extra_predicates = generic_params
253 .iter_type_or_consts()
254 .filter(|(_, data)| matches!(data, TypeOrConstParamData::TypeParamData(_)))
255 .map(|(param_idx, _)| {
256 let param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
257 parent: loc.adt.into(),
258 local_id: param_idx,
259 });
260 let param_idx =
261 param_idx.into_raw().into_u32() + (generic_params.len_lifetimes() as u32);
262 let param_ty = Ty::new_param(interner, param_id, param_idx);
263 let trait_ref = TraitRef::new(interner, trait_id.into(), [param_ty]);
264 trait_ref.upcast(interner)
265 });
266 let mut assoc_type_bounds = Vec::new();
267 match loc.adt {
268 AdtId::StructId(id) => extend_assoc_type_bounds(
269 interner,
270 &mut assoc_type_bounds,
271 interner.db.field_types(id.into()),
272 trait_id,
273 ),
274 AdtId::UnionId(id) => extend_assoc_type_bounds(
275 interner,
276 &mut assoc_type_bounds,
277 interner.db.field_types(id.into()),
278 trait_id,
279 ),
280 AdtId::EnumId(id) => {
281 for &(variant_id, _, _) in &id.enum_variants(interner.db).variants {
282 extend_assoc_type_bounds(
283 interner,
284 &mut assoc_type_bounds,
285 interner.db.field_types(variant_id.into()),
286 trait_id,
287 )
288 }
289 }
290 }
291 GenericPredicates::from_explicit_own_predicates(StoredEarlyBinder::bind(
292 Clauses::new_from_iter(
293 interner,
294 adt_predicates
295 .explicit_predicates()
296 .iter_identity_copied()
297 .chain(extra_predicates)
298 .chain(assoc_type_bounds),
299 )
300 .store(),
301 ))
302}
303
304fn extend_assoc_type_bounds<'db>(
305 interner: DbInterner<'db>,
306 assoc_type_bounds: &mut Vec<Clause<'db>>,
307 fields: &ArenaMap<LocalFieldId, StoredEarlyBinder<StoredTy>>,
308 trait_: TraitId,
309) {
310 struct ProjectionFinder<'a, 'db> {
311 interner: DbInterner<'db>,
312 assoc_type_bounds: &'a mut Vec<Clause<'db>>,
313 trait_: TraitId,
314 }
315
316 impl<'db> TypeVisitor<DbInterner<'db>> for ProjectionFinder<'_, 'db> {
317 type Result = ();
318
319 fn visit_ty(&mut self, t: Ty<'db>) -> Self::Result {
320 if let TyKind::Alias(AliasTyKind::Projection, _) = t.kind() {
321 self.assoc_type_bounds.push(
322 TraitRef::new(self.interner, self.trait_.into(), [t]).upcast(self.interner),
323 );
324 }
325
326 t.super_visit_with(self)
327 }
328 }
329
330 let mut visitor = ProjectionFinder { interner, assoc_type_bounds, trait_ };
331 for (_, field) in fields.iter() {
332 field.get().instantiate_identity().visit_with(&mut visitor);
333 }
334}
335
336fn coerce_pointee_params<'db>(
337 interner: DbInterner<'db>,
338 loc: &BuiltinDeriveImplLoc,
339 generic_params: &GenericParams,
340 trait_id: TraitId,
341) -> Option<(u32, TypeParamId, Ty<'db>)> {
342 let pointee_param = {
343 if let Ok((pointee_param, _)) = generic_params
344 .iter_type_or_consts()
345 .filter(|param| matches!(param.1, TypeOrConstParamData::TypeParamData(_)))
346 .exactly_one()
347 {
348 pointee_param
349 } else {
350 let (_, generic_param_attrs) =
351 AttrFlags::query_generic_params(interner.db, loc.adt.into());
352 generic_param_attrs
353 .iter()
354 .find(|param| param.1.contains(AttrFlags::IS_POINTEE))
355 .map(|(param, _)| param)
356 .or_else(|| {
357 generic_params
358 .iter_type_or_consts()
359 .find(|param| matches!(param.1, TypeOrConstParamData::TypeParamData(_)))
360 .map(|(idx, _)| idx)
361 })?
362 }
363 };
364 let pointee_param_id = TypeParamId::from_unchecked(TypeOrConstParamId {
365 parent: loc.adt.into(),
366 local_id: pointee_param,
367 });
368 let pointee_param_idx =
369 pointee_param.into_raw().into_u32() + (generic_params.len_lifetimes() as u32);
370 let new_param_idx = generic_params.len() as u32;
371 let new_param_id = coerce_pointee_new_type_param(trait_id);
372 let new_param_ty = Ty::new_param(interner, new_param_id, new_param_idx);
373 Some((pointee_param_idx, pointee_param_id, new_param_ty))
374}
375
376#[cfg(test)]
377mod tests {
378 use expect_test::{Expect, expect};
379 use hir_def::nameres::crate_def_map;
380 use itertools::Itertools;
381 use stdx::format_to;
382 use test_fixture::WithFixture;
383
384 use crate::{builtin_derive::impl_trait, next_solver::DbInterner, test_db::TestDB};
385
386 fn check_trait_refs(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) {
387 let db = TestDB::with_files(ra_fixture);
388 let def_map = crate_def_map(&db, db.test_crate());
389
390 let interner = DbInterner::new_with(&db, db.test_crate());
391 crate::attach_db(&db, || {
392 let mut trait_refs = Vec::new();
393 for (_, module) in def_map.modules() {
394 for derive in module.scope.builtin_derive_impls() {
395 let trait_ref = impl_trait(interner, derive).skip_binder();
396 trait_refs.push(format!("{trait_ref:?}"));
397 }
398 }
399
400 expectation.assert_eq(&trait_refs.join("\n"));
401 });
402 }
403
404 fn check_predicates(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) {
405 let db = TestDB::with_files(ra_fixture);
406 let def_map = crate_def_map(&db, db.test_crate());
407
408 crate::attach_db(&db, || {
409 let mut predicates = String::new();
410 for (_, module) in def_map.modules() {
411 for derive in module.scope.builtin_derive_impls() {
412 let preds = super::predicates(&db, derive).all_predicates().skip_binder();
413 format_to!(
414 predicates,
415 "{}\n\n",
416 preds.iter().format_with("\n", |pred, formatter| formatter(&format_args!(
417 "{pred:?}"
418 ))),
419 );
420 }
421 }
422
423 expectation.assert_eq(&predicates);
424 });
425 }
426
427 #[test]
428 fn simple_macros_trait_ref() {
429 check_trait_refs(
430 r#"
431//- minicore: derive, clone, copy, eq, ord, hash, fmt
432
433#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
434struct Simple;
435
436trait Trait {}
437
438#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
439struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]);
440 "#,
441 expect![[r#"
442 Simple: Debug
443 Simple: Clone
444 Simple: Copy
445 Simple: PartialEq<[Simple]>
446 Simple: Eq
447 Simple: PartialOrd<[Simple]>
448 Simple: Ord
449 Simple: Hash
450 WithGenerics<#0, #1, #2>: Debug
451 WithGenerics<#0, #1, #2>: Clone
452 WithGenerics<#0, #1, #2>: Copy
453 WithGenerics<#0, #1, #2>: PartialEq<[WithGenerics<#0, #1, #2>]>
454 WithGenerics<#0, #1, #2>: Eq
455 WithGenerics<#0, #1, #2>: PartialOrd<[WithGenerics<#0, #1, #2>]>
456 WithGenerics<#0, #1, #2>: Ord
457 WithGenerics<#0, #1, #2>: Hash"#]],
458 );
459 }
460
461 #[test]
462 fn coerce_pointee_trait_ref() {
463 check_trait_refs(
464 r#"
465//- minicore: derive, coerce_pointee
466use core::marker::CoercePointee;
467
468#[derive(CoercePointee)]
469struct Simple<T: ?Sized>(*const T);
470
471#[derive(CoercePointee)]
472struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U);
473 "#,
474 expect![[r#"
475 Simple<#0>: CoerceUnsized<[Simple<#1>]>
476 Simple<#0>: DispatchFromDyn<[Simple<#1>]>
477 MultiGenericParams<#0, #1, #2, #3>: CoerceUnsized<[MultiGenericParams<#0, #1, #4, #3>]>
478 MultiGenericParams<#0, #1, #2, #3>: DispatchFromDyn<[MultiGenericParams<#0, #1, #4, #3>]>"#]],
479 );
480 }
481
482 #[test]
483 fn simple_macros_predicates() {
484 check_predicates(
485 r#"
486//- minicore: derive, clone, copy, eq, ord, hash, fmt
487
488#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
489struct Simple;
490
491trait Trait {}
492
493#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
494struct WithGenerics<'a, T: Trait, const N: usize>(&'a [T; N]);
495 "#,
496 expect![[r#"
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
514 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
515 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
516 Clause(Binder { value: TraitPredicate(#1: Debug, polarity:Positive), bound_vars: [] })
517
518 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
519 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
520 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
521 Clause(Binder { value: TraitPredicate(#1: Clone, polarity:Positive), bound_vars: [] })
522
523 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
524 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
525 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
526 Clause(Binder { value: TraitPredicate(#1: Copy, polarity:Positive), bound_vars: [] })
527
528 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
529 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
530 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
531 Clause(Binder { value: TraitPredicate(#1: PartialEq, polarity:Positive), bound_vars: [] })
532
533 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
534 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
535 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
536 Clause(Binder { value: TraitPredicate(#1: Eq, polarity:Positive), bound_vars: [] })
537
538 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
539 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
540 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
541 Clause(Binder { value: TraitPredicate(#1: PartialOrd, polarity:Positive), bound_vars: [] })
542
543 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
544 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
545 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
546 Clause(Binder { value: TraitPredicate(#1: Ord, polarity:Positive), bound_vars: [] })
547
548 Clause(Binder { value: TraitPredicate(#1: Trait, polarity:Positive), bound_vars: [] })
549 Clause(Binder { value: ConstArgHasType(#2, usize), bound_vars: [] })
550 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
551 Clause(Binder { value: TraitPredicate(#1: Hash, polarity:Positive), bound_vars: [] })
552
553 "#]],
554 );
555 }
556
557 #[test]
558 fn coerce_pointee_predicates() {
559 check_predicates(
560 r#"
561//- minicore: derive, coerce_pointee
562use core::marker::CoercePointee;
563
564#[derive(CoercePointee)]
565struct Simple<T: ?Sized>(*const T);
566
567trait Trait<T> {}
568
569#[derive(CoercePointee)]
570struct MultiGenericParams<'a, T, #[pointee] U: ?Sized, const N: usize>(*const U)
571where
572 T: Trait<U>,
573 U: Trait<U>;
574 "#,
575 expect![[r#"
576 Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] })
577
578 Clause(Binder { value: TraitPredicate(#0: Unsize<[#1]>, polarity:Positive), bound_vars: [] })
579
580 Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] })
581 Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] })
582 Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] })
583 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
584 Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] })
585 Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] })
586 Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] })
587
588 Clause(Binder { value: TraitPredicate(#1: Trait<[#2]>, polarity:Positive), bound_vars: [] })
589 Clause(Binder { value: TraitPredicate(#2: Trait<[#2]>, polarity:Positive), bound_vars: [] })
590 Clause(Binder { value: ConstArgHasType(#3, usize), bound_vars: [] })
591 Clause(Binder { value: TraitPredicate(#1: Sized, polarity:Positive), bound_vars: [] })
592 Clause(Binder { value: TraitPredicate(#1: Trait<[#4]>, polarity:Positive), bound_vars: [] })
593 Clause(Binder { value: TraitPredicate(#4: Trait<[#4]>, polarity:Positive), bound_vars: [] })
594 Clause(Binder { value: TraitPredicate(#2: Unsize<[#4]>, polarity:Positive), bound_vars: [] })
595
596 "#]],
597 );
598 }
599}
src/tools/rust-analyzer/crates/hir-ty/src/consteval/tests.rs+1
......@@ -1568,6 +1568,7 @@ const GOAL: u8 = {
15681568}
15691569
15701570#[test]
1571#[ignore = "builtin derive macros are currently not working with MIR eval"]
15711572fn builtin_derive_macro() {
15721573 check_number(
15731574 r#"
src/tools/rust-analyzer/crates/hir-ty/src/db.rs+6-4
......@@ -2,10 +2,12 @@
22//! type inference-related queries.
33
44use base_db::{Crate, target::TargetLoadError};
5use either::Either;
56use hir_def::{
6 AdtId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
7 GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, VariantId,
8 db::DefDatabase, hir::ExprId, layout::TargetDataLayout,
7 AdtId, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId,
8 FunctionId, GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId,
9 TypeAliasId, VariantId, builtin_derive::BuiltinDeriveImplMethod, db::DefDatabase, hir::ExprId,
10 layout::TargetDataLayout,
911};
1012use la_arena::ArenaMap;
1113use salsa::plumbing::AsId;
......@@ -83,7 +85,7 @@ pub trait HirDatabase: DefDatabase + std::fmt::Debug {
8385 env: ParamEnvAndCrate<'db>,
8486 func: FunctionId,
8587 fn_subst: GenericArgs<'db>,
86 ) -> (FunctionId, GenericArgs<'db>);
88 ) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>);
8789
8890 // endregion:mir
8991
src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/decl_check.rs+24-13
......@@ -293,12 +293,18 @@ impl<'a> DeclValidator<'a> {
293293 fn validate_struct(&mut self, struct_id: StructId) {
294294 // Check the structure name.
295295 let data = self.db.struct_signature(struct_id);
296 self.create_incorrect_case_diagnostic_for_item_name(
297 struct_id,
298 &data.name,
299 CaseType::UpperCamelCase,
300 IdentType::Structure,
301 );
296
297 // rustc implementation excuses repr(C) since C structs predominantly don't
298 // use camel case.
299 let has_repr_c = data.repr(self.db, struct_id).is_some_and(|repr| repr.c());
300 if !has_repr_c {
301 self.create_incorrect_case_diagnostic_for_item_name(
302 struct_id,
303 &data.name,
304 CaseType::UpperCamelCase,
305 IdentType::Structure,
306 );
307 }
302308
303309 // Check the field names.
304310 self.validate_struct_fields(struct_id);
......@@ -378,15 +384,20 @@ impl<'a> DeclValidator<'a> {
378384 }
379385
380386 fn validate_enum(&mut self, enum_id: EnumId) {
387 // Check the enum name.
381388 let data = self.db.enum_signature(enum_id);
382389
383 // Check the enum name.
384 self.create_incorrect_case_diagnostic_for_item_name(
385 enum_id,
386 &data.name,
387 CaseType::UpperCamelCase,
388 IdentType::Enum,
389 );
390 // rustc implementation excuses repr(C) since C structs predominantly don't
391 // use camel case.
392 let has_repr_c = data.repr(self.db, enum_id).is_some_and(|repr| repr.c());
393 if !has_repr_c {
394 self.create_incorrect_case_diagnostic_for_item_name(
395 enum_id,
396 &data.name,
397 CaseType::UpperCamelCase,
398 IdentType::Enum,
399 );
400 }
390401
391402 // Check the variant names.
392403 self.validate_enum_variants(enum_id)
src/tools/rust-analyzer/crates/hir-ty/src/display.rs+69-33
......@@ -7,7 +7,7 @@ use std::{
77 mem,
88};
99
10use base_db::Crate;
10use base_db::{Crate, FxIndexMap};
1111use either::Either;
1212use hir_def::{
1313 FindPathConfig, GenericDefId, HasModule, LocalFieldId, Lookup, ModuleDefId, ModuleId, TraitId,
......@@ -143,11 +143,11 @@ impl<'db> BoundsFormattingCtx<'db> {
143143}
144144
145145impl<'db> HirFormatter<'_, 'db> {
146 fn start_location_link(&mut self, location: ModuleDefId) {
146 pub fn start_location_link(&mut self, location: ModuleDefId) {
147147 self.fmt.start_location_link(location);
148148 }
149149
150 fn end_location_link(&mut self) {
150 pub fn end_location_link(&mut self) {
151151 self.fmt.end_location_link();
152152 }
153153
......@@ -1383,37 +1383,30 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
13831383 }
13841384 _ => (),
13851385 }
1386 let sig = substs
1387 .split_closure_args_untupled()
1388 .closure_sig_as_fn_ptr_ty
1389 .callable_sig(interner);
1390 if let Some(sig) = sig {
1391 let sig = sig.skip_binder();
1392 let InternedClosure(def, _) = db.lookup_intern_closure(id);
1393 let infer = InferenceResult::for_body(db, def);
1394 let (_, kind) = infer.closure_info(id);
1395 match f.closure_style {
1396 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1397 ClosureStyle::RANotation => write!(f, "|")?,
1398 _ => unreachable!(),
1399 }
1400 if sig.inputs().is_empty() {
1401 } else if f.should_truncate() {
1402 write!(f, "{TYPE_HINT_TRUNCATION}")?;
1403 } else {
1404 f.write_joined(sig.inputs(), ", ")?;
1405 };
1406 match f.closure_style {
1407 ClosureStyle::ImplFn => write!(f, ")")?,
1408 ClosureStyle::RANotation => write!(f, "|")?,
1409 _ => unreachable!(),
1410 }
1411 if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
1412 write!(f, " -> ")?;
1413 sig.output().hir_fmt(f)?;
1414 }
1386 let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
1387 let sig = sig.skip_binder();
1388 let InternedClosure(def, _) = db.lookup_intern_closure(id);
1389 let infer = InferenceResult::for_body(db, def);
1390 let (_, kind) = infer.closure_info(id);
1391 match f.closure_style {
1392 ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
1393 ClosureStyle::RANotation => write!(f, "|")?,
1394 _ => unreachable!(),
1395 }
1396 if sig.inputs().is_empty() {
1397 } else if f.should_truncate() {
1398 write!(f, "{TYPE_HINT_TRUNCATION}")?;
14151399 } else {
1416 write!(f, "{{closure}}")?;
1400 f.write_joined(sig.inputs(), ", ")?;
1401 };
1402 match f.closure_style {
1403 ClosureStyle::ImplFn => write!(f, ")")?,
1404 ClosureStyle::RANotation => write!(f, "|")?,
1405 _ => unreachable!(),
1406 }
1407 if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
1408 write!(f, " -> ")?;
1409 sig.output().hir_fmt(f)?;
14171410 }
14181411 }
14191412 TyKind::CoroutineClosure(id, args) => {
......@@ -1978,6 +1971,49 @@ fn write_bounds_like_dyn_trait<'db>(
19781971 Ok(())
19791972}
19801973
1974pub fn write_params_bounds<'db>(
1975 f: &mut HirFormatter<'_, 'db>,
1976 predicates: &[Clause<'db>],
1977) -> Result {
1978 // Use an FxIndexMap to keep user's order, as far as possible.
1979 let mut per_type = FxIndexMap::<_, Vec<_>>::default();
1980 for &predicate in predicates {
1981 let base_ty = match predicate.kind().skip_binder() {
1982 ClauseKind::Trait(clause) => Either::Left(clause.self_ty()),
1983 ClauseKind::RegionOutlives(clause) => Either::Right(clause.0),
1984 ClauseKind::TypeOutlives(clause) => Either::Left(clause.0),
1985 ClauseKind::Projection(clause) => Either::Left(clause.self_ty()),
1986 ClauseKind::ConstArgHasType(..)
1987 | ClauseKind::WellFormed(_)
1988 | ClauseKind::ConstEvaluatable(_)
1989 | ClauseKind::HostEffect(..)
1990 | ClauseKind::UnstableFeature(_) => continue,
1991 };
1992 per_type.entry(base_ty).or_default().push(predicate);
1993 }
1994
1995 for (base_ty, clauses) in per_type {
1996 f.write_str(" ")?;
1997 match base_ty {
1998 Either::Left(it) => it.hir_fmt(f)?,
1999 Either::Right(it) => it.hir_fmt(f)?,
2000 }
2001 f.write_str(": ")?;
2002 // Rudimentary approximation: type params are `Sized` by default, everything else not.
2003 // FIXME: This is not correct, really. But I'm not sure how we can from the ty representation
2004 // to extract the default sizedness, and if it's possible at all.
2005 let default_sized = match base_ty {
2006 Either::Left(ty) if matches!(ty.kind(), TyKind::Param(_)) => {
2007 SizedByDefault::Sized { anchor: f.krate() }
2008 }
2009 _ => SizedByDefault::NotSized,
2010 };
2011 write_bounds_like_dyn_trait(f, base_ty, &clauses, default_sized)?;
2012 f.write_str(",\n")?;
2013 }
2014 Ok(())
2015}
2016
19812017impl<'db> HirDisplay<'db> for TraitRef<'db> {
19822018 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
19832019 let trait_ = self.def_id.0;
src/tools/rust-analyzer/crates/hir-ty/src/drop.rs+1-1
......@@ -32,7 +32,7 @@ fn has_destructor(interner: DbInterner<'_>, adt: AdtId) -> bool {
3232 },
3333 None => TraitImpls::for_crate(db, module.krate(db)),
3434 };
35 !impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty()
35 !impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).0.is_empty()
3636}
3737
3838#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs+10-1
......@@ -68,7 +68,6 @@ impl<'db> InferenceContext<'_, 'db> {
6868 let ClosureSignatures { bound_sig, liberated_sig } =
6969 self.sig_of_closure(arg_types, ret_type, expected_sig);
7070 let body_ret_ty = bound_sig.output().skip_binder();
71 let sig_ty = Ty::new_fn_ptr(interner, bound_sig);
7271
7372 let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into());
7473 // FIXME: Make this an infer var and infer it later.
......@@ -117,6 +116,16 @@ impl<'db> InferenceContext<'_, 'db> {
117116 }
118117 None => {}
119118 };
119 let sig = bound_sig.map_bound(|sig| {
120 interner.mk_fn_sig(
121 [Ty::new_tup(interner, sig.inputs())],
122 sig.output(),
123 sig.c_variadic,
124 sig.safety,
125 sig.abi,
126 )
127 });
128 let sig_ty = Ty::new_fn_ptr(interner, sig);
120129 // FIXME: Infer the kind later if needed.
121130 let parts = ClosureArgsParts {
122131 parent_args: parent_args.as_slice(),
src/tools/rust-analyzer/crates/hir-ty/src/infer/closure/analysis.rs+111-83
......@@ -1,10 +1,10 @@
11//! Post-inference closure analysis: captures and closure kind.
22
3use std::{cmp, convert::Infallible, mem};
3use std::{cmp, mem};
44
5use either::Either;
5use base_db::Crate;
66use hir_def::{
7 DefWithBodyId, FieldId, HasModule, TupleFieldId, TupleId, VariantId,
7 DefWithBodyId, FieldId, HasModule, VariantId,
88 expr_store::path::Path,
99 hir::{
1010 Array, AsmOperand, BinaryOp, BindingId, CaptureBy, Expr, ExprId, ExprOrPatId, Pat, PatId,
......@@ -15,7 +15,7 @@ use hir_def::{
1515};
1616use rustc_ast_ir::Mutability;
1717use rustc_hash::{FxHashMap, FxHashSet};
18use rustc_type_ir::inherent::{IntoKind, Ty as _};
18use rustc_type_ir::inherent::{GenericArgs as _, IntoKind, Ty as _};
1919use smallvec::{SmallVec, smallvec};
2020use stdx::{format_to, never};
2121use syntax::utils::is_raw_identifier;
......@@ -23,33 +23,97 @@ use syntax::utils::is_raw_identifier;
2323use crate::{
2424 Adjust, Adjustment, BindingMode,
2525 db::{HirDatabase, InternedClosure, InternedClosureId},
26 display::{DisplayTarget, HirDisplay as _},
2627 infer::InferenceContext,
27 mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
28 next_solver::{DbInterner, GenericArgs, StoredEarlyBinder, StoredTy, Ty, TyKind},
28 mir::{BorrowKind, MirSpan, MutBorrowKind},
29 next_solver::{
30 DbInterner, ErrorGuaranteed, GenericArgs, ParamEnv, StoredEarlyBinder, StoredTy, Ty,
31 TyKind,
32 infer::{InferCtxt, traits::ObligationCause},
33 obligation_ctxt::ObligationCtxt,
34 },
2935 traits::FnTrait,
3036};
3137
3238// The below functions handle capture and closure kind (Fn, FnMut, ..)
3339
40#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
41pub(crate) enum HirPlaceProjection {
42 Deref,
43 Field(FieldId),
44 TupleField(u32),
45}
46
47impl HirPlaceProjection {
48 fn projected_ty<'db>(
49 self,
50 infcx: &InferCtxt<'db>,
51 env: ParamEnv<'db>,
52 mut base: Ty<'db>,
53 krate: Crate,
54 ) -> Ty<'db> {
55 let interner = infcx.interner;
56 let db = interner.db;
57 if base.is_ty_error() {
58 return Ty::new_error(interner, ErrorGuaranteed);
59 }
60
61 if matches!(base.kind(), TyKind::Alias(..)) {
62 let mut ocx = ObligationCtxt::new(infcx);
63 match ocx.structurally_normalize_ty(&ObligationCause::dummy(), env, base) {
64 Ok(it) => base = it,
65 Err(_) => return Ty::new_error(interner, ErrorGuaranteed),
66 }
67 }
68 match self {
69 HirPlaceProjection::Deref => match base.kind() {
70 TyKind::RawPtr(inner, _) | TyKind::Ref(_, inner, _) => inner,
71 TyKind::Adt(adt_def, subst) if adt_def.is_box() => subst.type_at(0),
72 _ => {
73 never!(
74 "Overloaded deref on type {} is not a projection",
75 base.display(db, DisplayTarget::from_crate(db, krate))
76 );
77 Ty::new_error(interner, ErrorGuaranteed)
78 }
79 },
80 HirPlaceProjection::Field(f) => match base.kind() {
81 TyKind::Adt(_, subst) => {
82 db.field_types(f.parent)[f.local_id].get().instantiate(interner, subst)
83 }
84 ty => {
85 never!("Only adt has field, found {:?}", ty);
86 Ty::new_error(interner, ErrorGuaranteed)
87 }
88 },
89 HirPlaceProjection::TupleField(idx) => match base.kind() {
90 TyKind::Tuple(subst) => {
91 subst.as_slice().get(idx as usize).copied().unwrap_or_else(|| {
92 never!("Out of bound tuple field");
93 Ty::new_error(interner, ErrorGuaranteed)
94 })
95 }
96 ty => {
97 never!("Only tuple has tuple field: {:?}", ty);
98 Ty::new_error(interner, ErrorGuaranteed)
99 }
100 },
101 }
102 }
103}
104
34105#[derive(Debug, Clone, PartialEq, Eq, Hash, salsa::Update)]
35106pub(crate) struct HirPlace {
36107 pub(crate) local: BindingId,
37 pub(crate) projections: Vec<ProjectionElem<Infallible>>,
108 pub(crate) projections: Vec<HirPlaceProjection>,
38109}
39110
40111impl HirPlace {
41112 fn ty<'db>(&self, ctx: &mut InferenceContext<'_, 'db>) -> Ty<'db> {
113 let krate = ctx.krate();
42114 let mut ty = ctx.table.resolve_completely(ctx.result.binding_ty(self.local));
43115 for p in &self.projections {
44 ty = p.projected_ty(
45 &ctx.table.infer_ctxt,
46 ctx.table.param_env,
47 ty,
48 |_, _, _| {
49 unreachable!("Closure field only happens in MIR");
50 },
51 ctx.owner.module(ctx.db).krate(ctx.db),
52 );
116 ty = p.projected_ty(ctx.infcx(), ctx.table.param_env, ty, krate);
53117 }
54118 ty
55119 }
......@@ -62,7 +126,7 @@ impl HirPlace {
62126 if let CaptureKind::ByRef(BorrowKind::Mut {
63127 kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow,
64128 }) = current_capture
65 && self.projections[len..].contains(&ProjectionElem::Deref)
129 && self.projections[len..].contains(&HirPlaceProjection::Deref)
66130 {
67131 current_capture =
68132 CaptureKind::ByRef(BorrowKind::Mut { kind: MutBorrowKind::ClosureCapture });
......@@ -98,12 +162,12 @@ impl CapturedItem {
98162
99163 /// Returns whether this place has any field (aka. non-deref) projections.
100164 pub fn has_field_projections(&self) -> bool {
101 self.place.projections.iter().any(|it| !matches!(it, ProjectionElem::Deref))
165 self.place.projections.iter().any(|it| !matches!(it, HirPlaceProjection::Deref))
102166 }
103167
104168 pub fn ty<'db>(&self, db: &'db dyn HirDatabase, subst: GenericArgs<'db>) -> Ty<'db> {
105169 let interner = DbInterner::new_no_crate(db);
106 self.ty.get().instantiate(interner, subst.split_closure_args_untupled().parent_args)
170 self.ty.get().instantiate(interner, subst.as_closure().parent_args())
107171 }
108172
109173 pub fn kind(&self) -> CaptureKind {
......@@ -120,8 +184,8 @@ impl CapturedItem {
120184 let mut result = body[self.place.local].name.as_str().to_owned();
121185 for proj in &self.place.projections {
122186 match proj {
123 ProjectionElem::Deref => {}
124 ProjectionElem::Field(Either::Left(f)) => {
187 HirPlaceProjection::Deref => {}
188 HirPlaceProjection::Field(f) => {
125189 let variant_data = f.parent.fields(db);
126190 match variant_data.shape {
127191 FieldsShape::Record => {
......@@ -138,14 +202,8 @@ impl CapturedItem {
138202 FieldsShape::Unit => {}
139203 }
140204 }
141 ProjectionElem::Field(Either::Right(f)) => format_to!(result, "_{}", f.index),
142 &ProjectionElem::ClosureField(field) => format_to!(result, "_{field}"),
143 ProjectionElem::Index(_)
144 | ProjectionElem::ConstantIndex { .. }
145 | ProjectionElem::Subslice { .. }
146 | ProjectionElem::OpaqueCast(_) => {
147 never!("Not happen in closure capture");
148 continue;
205 HirPlaceProjection::TupleField(idx) => {
206 format_to!(result, "_{idx}")
149207 }
150208 }
151209 }
......@@ -163,8 +221,8 @@ impl CapturedItem {
163221 for proj in &self.place.projections {
164222 match proj {
165223 // In source code autoderef kicks in.
166 ProjectionElem::Deref => {}
167 ProjectionElem::Field(Either::Left(f)) => {
224 HirPlaceProjection::Deref => {}
225 HirPlaceProjection::Field(f) => {
168226 let variant_data = f.parent.fields(db);
169227 match variant_data.shape {
170228 FieldsShape::Record => format_to!(
......@@ -184,19 +242,8 @@ impl CapturedItem {
184242 FieldsShape::Unit => {}
185243 }
186244 }
187 ProjectionElem::Field(Either::Right(f)) => {
188 let field = f.index;
189 format_to!(result, ".{field}");
190 }
191 &ProjectionElem::ClosureField(field) => {
192 format_to!(result, ".{field}");
193 }
194 ProjectionElem::Index(_)
195 | ProjectionElem::ConstantIndex { .. }
196 | ProjectionElem::Subslice { .. }
197 | ProjectionElem::OpaqueCast(_) => {
198 never!("Not happen in closure capture");
199 continue;
245 HirPlaceProjection::TupleField(idx) => {
246 format_to!(result, ".{idx}")
200247 }
201248 }
202249 }
......@@ -205,7 +252,7 @@ impl CapturedItem {
205252 .projections
206253 .iter()
207254 .rev()
208 .take_while(|proj| matches!(proj, ProjectionElem::Deref))
255 .take_while(|proj| matches!(proj, HirPlaceProjection::Deref))
209256 .count();
210257 result.insert_str(0, &"*".repeat(final_derefs_count));
211258 result
......@@ -219,11 +266,11 @@ impl CapturedItem {
219266 let mut field_need_paren = false;
220267 for proj in &self.place.projections {
221268 match proj {
222 ProjectionElem::Deref => {
269 HirPlaceProjection::Deref => {
223270 result = format!("*{result}");
224271 field_need_paren = true;
225272 }
226 ProjectionElem::Field(Either::Left(f)) => {
273 HirPlaceProjection::Field(f) => {
227274 if field_need_paren {
228275 result = format!("({result})");
229276 }
......@@ -243,28 +290,13 @@ impl CapturedItem {
243290 result = format!("{result}.{field}");
244291 field_need_paren = false;
245292 }
246 ProjectionElem::Field(Either::Right(f)) => {
247 let field = f.index;
248 if field_need_paren {
249 result = format!("({result})");
250 }
251 result = format!("{result}.{field}");
252 field_need_paren = false;
253 }
254 &ProjectionElem::ClosureField(field) => {
293 HirPlaceProjection::TupleField(idx) => {
255294 if field_need_paren {
256295 result = format!("({result})");
257296 }
258 result = format!("{result}.{field}");
297 result = format!("{result}.{idx}");
259298 field_need_paren = false;
260299 }
261 ProjectionElem::Index(_)
262 | ProjectionElem::ConstantIndex { .. }
263 | ProjectionElem::Subslice { .. }
264 | ProjectionElem::OpaqueCast(_) => {
265 never!("Not happen in closure capture");
266 continue;
267 }
268300 }
269301 }
270302 result
......@@ -345,7 +377,9 @@ impl<'db> InferenceContext<'_, 'db> {
345377 let mut place = self.place_of_expr(*expr)?;
346378 let field = self.result.field_resolution(tgt_expr)?;
347379 self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
348 place.projections.push(ProjectionElem::Field(field));
380 place.projections.push(field.either(HirPlaceProjection::Field, |f| {
381 HirPlaceProjection::TupleField(f.index)
382 }));
349383 return Some(place);
350384 }
351385 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
......@@ -357,7 +391,7 @@ impl<'db> InferenceContext<'_, 'db> {
357391 if is_builtin_deref {
358392 let mut place = self.place_of_expr(*expr)?;
359393 self.current_capture_span_stack.push(MirSpan::ExprId(tgt_expr));
360 place.projections.push(ProjectionElem::Deref);
394 place.projections.push(HirPlaceProjection::Deref);
361395 return Some(place);
362396 }
363397 }
......@@ -832,9 +866,6 @@ impl<'db> InferenceContext<'_, 'db> {
832866 &self.table.infer_ctxt,
833867 self.table.param_env,
834868 ty,
835 |_, _, _| {
836 unreachable!("Closure field only happens in MIR");
837 },
838869 self.owner.module(self.db).krate(self.db),
839870 );
840871 if ty.is_raw_ptr() || ty.is_union() {
......@@ -853,7 +884,7 @@ impl<'db> InferenceContext<'_, 'db> {
853884 let mut current_captures = std::mem::take(&mut self.current_captures);
854885 for capture in &mut current_captures {
855886 if let Some(first_deref) =
856 capture.place.projections.iter().position(|proj| *proj == ProjectionElem::Deref)
887 capture.place.projections.iter().position(|proj| *proj == HirPlaceProjection::Deref)
857888 {
858889 self.truncate_capture_spans(capture, first_deref);
859890 capture.place.projections.truncate(first_deref);
......@@ -876,7 +907,7 @@ impl<'db> InferenceContext<'_, 'db> {
876907 }
877908 match it.next() {
878909 Some(it) => {
879 lookup_place.projections.push(it.clone());
910 lookup_place.projections.push(*it);
880911 }
881912 None => break None,
882913 }
......@@ -903,7 +934,7 @@ impl<'db> InferenceContext<'_, 'db> {
903934 fn consume_with_pat(&mut self, mut place: HirPlace, tgt_pat: PatId) {
904935 let adjustments_count =
905936 self.result.pat_adjustments.get(&tgt_pat).map(|it| it.len()).unwrap_or_default();
906 place.projections.extend((0..adjustments_count).map(|_| ProjectionElem::Deref));
937 place.projections.extend((0..adjustments_count).map(|_| HirPlaceProjection::Deref));
907938 self.current_capture_span_stack
908939 .extend((0..adjustments_count).map(|_| MirSpan::PatId(tgt_pat)));
909940 'reset_span_stack: {
......@@ -920,10 +951,7 @@ impl<'db> InferenceContext<'_, 'db> {
920951 for (&arg, i) in it {
921952 let mut p = place.clone();
922953 self.current_capture_span_stack.push(MirSpan::PatId(arg));
923 p.projections.push(ProjectionElem::Field(Either::Right(TupleFieldId {
924 tuple: TupleId(!0), // dummy this, as its unused anyways
925 index: i as u32,
926 })));
954 p.projections.push(HirPlaceProjection::TupleField(i as u32));
927955 self.consume_with_pat(p, arg);
928956 self.current_capture_span_stack.pop();
929957 }
......@@ -950,10 +978,10 @@ impl<'db> InferenceContext<'_, 'db> {
950978 };
951979 let mut p = place.clone();
952980 self.current_capture_span_stack.push(MirSpan::PatId(arg));
953 p.projections.push(ProjectionElem::Field(Either::Left(FieldId {
981 p.projections.push(HirPlaceProjection::Field(FieldId {
954982 parent: variant,
955983 local_id,
956 })));
984 }));
957985 self.consume_with_pat(p, arg);
958986 self.current_capture_span_stack.pop();
959987 }
......@@ -1005,10 +1033,10 @@ impl<'db> InferenceContext<'_, 'db> {
10051033 for (&arg, (i, _)) in it {
10061034 let mut p = place.clone();
10071035 self.current_capture_span_stack.push(MirSpan::PatId(arg));
1008 p.projections.push(ProjectionElem::Field(Either::Left(FieldId {
1036 p.projections.push(HirPlaceProjection::Field(FieldId {
10091037 parent: variant,
10101038 local_id: i,
1011 })));
1039 }));
10121040 self.consume_with_pat(p, arg);
10131041 self.current_capture_span_stack.pop();
10141042 }
......@@ -1017,7 +1045,7 @@ impl<'db> InferenceContext<'_, 'db> {
10171045 }
10181046 Pat::Ref { pat, mutability: _ } => {
10191047 self.current_capture_span_stack.push(MirSpan::PatId(tgt_pat));
1020 place.projections.push(ProjectionElem::Deref);
1048 place.projections.push(HirPlaceProjection::Deref);
10211049 self.consume_with_pat(place, *pat);
10221050 self.current_capture_span_stack.pop();
10231051 }
......@@ -1071,7 +1099,7 @@ impl<'db> InferenceContext<'_, 'db> {
10711099 CaptureKind::ByRef(BorrowKind::Mut {
10721100 kind: MutBorrowKind::Default | MutBorrowKind::TwoPhasedBorrow
10731101 })
1074 ) && !item.place.projections.contains(&ProjectionElem::Deref)
1102 ) && !item.place.projections.contains(&HirPlaceProjection::Deref)
10751103 {
10761104 // FIXME: remove the `mutated_bindings_in_closure` completely and add proper fake reads in
10771105 // MIR. I didn't do that due duplicate diagnostics.
......@@ -1221,7 +1249,7 @@ fn apply_adjusts_to_place(
12211249 match &adj.kind {
12221250 Adjust::Deref(None) => {
12231251 current_capture_span_stack.push(span);
1224 r.projections.push(ProjectionElem::Deref);
1252 r.projections.push(HirPlaceProjection::Deref);
12251253 }
12261254 _ => return None,
12271255 }
src/tools/rust-analyzer/crates/hir-ty/src/infer/coerce.rs+38-39
......@@ -46,7 +46,9 @@ use rustc_type_ir::{
4646 BoundVar, DebruijnIndex, TyVid, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
4747 TypeVisitableExt,
4848 error::TypeError,
49 inherent::{Const as _, GenericArg as _, IntoKind, Safety, SliceLike, Ty as _},
49 inherent::{
50 Const as _, GenericArg as _, GenericArgs as _, IntoKind, Safety as _, SliceLike, Ty as _,
51 },
5052};
5153use smallvec::{SmallVec, smallvec};
5254use tracing::{debug, instrument};
......@@ -54,7 +56,7 @@ use tracing::{debug, instrument};
5456use crate::{
5557 Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures,
5658 autoderef::Autoderef,
57 db::{HirDatabase, InternedClosureId},
59 db::{HirDatabase, InternedClosure, InternedClosureId},
5860 infer::{
5961 AllowTwoPhase, AutoBorrowMutability, InferenceContext, TypeMismatch, expr::ExprIsRead,
6062 },
......@@ -63,6 +65,7 @@ use crate::{
6365 Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed,
6466 GenericArgs, ParamEnv, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
6567 TypingMode,
68 abi::Safety,
6669 infer::{
6770 DbInternerInferExt, InferCtxt, InferOk, InferResult,
6871 relate::RelateResult,
......@@ -71,6 +74,7 @@ use crate::{
7174 },
7275 obligation_ctxt::ObligationCtxt,
7376 },
77 upvars::upvars_mentioned,
7478 utils::TargetFeatureIsSafeInTarget,
7579};
7680
......@@ -893,7 +897,7 @@ where
893897 fn coerce_closure_to_fn(
894898 &mut self,
895899 a: Ty<'db>,
896 _closure_def_id_a: InternedClosureId,
900 closure_def_id_a: InternedClosureId,
897901 args_a: GenericArgs<'db>,
898902 b: Ty<'db>,
899903 ) -> CoerceResult<'db> {
......@@ -901,19 +905,7 @@ where
901905 debug_assert!(self.infcx().shallow_resolve(b) == b);
902906
903907 match b.kind() {
904 // FIXME: We need to have an `upvars_mentioned()` query:
905 // At this point we haven't done capture analysis, which means
906 // that the ClosureArgs just contains an inference variable instead
907 // of tuple of captured types.
908 //
909 // All we care here is if any variable is being captured and not the exact paths,
910 // so we check `upvars_mentioned` for root variables being captured.
911 TyKind::FnPtr(_, hdr) =>
912 // if self
913 // .db
914 // .upvars_mentioned(closure_def_id_a.expect_local())
915 // .is_none_or(|u| u.is_empty()) =>
916 {
908 TyKind::FnPtr(_, hdr) if !is_capturing_closure(self.db(), closure_def_id_a) => {
917909 // We coerce the closure, which has fn type
918910 // `extern "rust-call" fn((arg0,arg1,...)) -> _`
919911 // to
......@@ -921,10 +913,8 @@ where
921913 // or
922914 // `unsafe fn(arg0,arg1,...) -> _`
923915 let safety = hdr.safety;
924 let closure_sig = args_a.closure_sig_untupled().map_bound(|mut sig| {
925 sig.safety = hdr.safety;
926 sig
927 });
916 let closure_sig =
917 self.interner().signature_unclosure(args_a.as_closure().sig(), safety);
928918 let pointer_ty = Ty::new_fn_ptr(self.interner(), closure_sig);
929919 debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
930920 self.unify_and(
......@@ -1088,14 +1078,12 @@ impl<'db> InferenceContext<'_, 'db> {
10881078 // Special-case that coercion alone cannot handle:
10891079 // Function items or non-capturing closures of differing IDs or GenericArgs.
10901080 let (a_sig, b_sig) = {
1091 let is_capturing_closure = |_ty: Ty<'db>| {
1092 // FIXME:
1093 // if let TyKind::Closure(closure_def_id, _args) = ty.kind() {
1094 // self.db.upvars_mentioned(closure_def_id.expect_local()).is_some()
1095 // } else {
1096 // false
1097 // }
1098 false
1081 let is_capturing_closure = |ty: Ty<'db>| {
1082 if let TyKind::Closure(closure_def_id, _args) = ty.kind() {
1083 is_capturing_closure(self.db, closure_def_id.0)
1084 } else {
1085 false
1086 }
10991087 };
11001088 if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) {
11011089 (None, None)
......@@ -1125,23 +1113,28 @@ impl<'db> InferenceContext<'_, 'db> {
11251113 }
11261114 (TyKind::Closure(_, args), TyKind::FnDef(..)) => {
11271115 let b_sig = new_ty.fn_sig(self.table.interner());
1128 let a_sig = args.closure_sig_untupled().map_bound(|mut sig| {
1129 sig.safety = b_sig.safety();
1130 sig
1131 });
1116 let a_sig = self
1117 .interner()
1118 .signature_unclosure(args.as_closure().sig(), b_sig.safety());
11321119 (Some(a_sig), Some(b_sig))
11331120 }
11341121 (TyKind::FnDef(..), TyKind::Closure(_, args)) => {
11351122 let a_sig = prev_ty.fn_sig(self.table.interner());
1136 let b_sig = args.closure_sig_untupled().map_bound(|mut sig| {
1137 sig.safety = a_sig.safety();
1138 sig
1139 });
1123 let b_sig = self
1124 .interner()
1125 .signature_unclosure(args.as_closure().sig(), a_sig.safety());
11401126 (Some(a_sig), Some(b_sig))
11411127 }
1142 (TyKind::Closure(_, args_a), TyKind::Closure(_, args_b)) => {
1143 (Some(args_a.closure_sig_untupled()), Some(args_b.closure_sig_untupled()))
1144 }
1128 (TyKind::Closure(_, args_a), TyKind::Closure(_, args_b)) => (
1129 Some(
1130 self.interner()
1131 .signature_unclosure(args_a.as_closure().sig(), Safety::Safe),
1132 ),
1133 Some(
1134 self.interner()
1135 .signature_unclosure(args_b.as_closure().sig(), Safety::Safe),
1136 ),
1137 ),
11451138 _ => (None, None),
11461139 }
11471140 }
......@@ -1722,3 +1715,9 @@ fn coerce<'db>(
17221715 .collect();
17231716 Ok((adjustments, ty))
17241717}
1718
1719fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool {
1720 let InternedClosure(owner, expr) = closure.loc(db);
1721 upvars_mentioned(db, owner)
1722 .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty()))
1723}
src/tools/rust-analyzer/crates/hir-ty/src/layout.rs+5-5
......@@ -14,7 +14,10 @@ use rustc_abi::{
1414 TargetDataLayout, WrappingRange,
1515};
1616use rustc_index::IndexVec;
17use rustc_type_ir::{FloatTy, IntTy, UintTy, inherent::IntoKind};
17use rustc_type_ir::{
18 FloatTy, IntTy, UintTy,
19 inherent::{GenericArgs as _, IntoKind},
20};
1821use triomphe::Arc;
1922
2023use crate::{
......@@ -335,10 +338,7 @@ pub fn layout_of_ty_query(
335338 let fields = captures
336339 .iter()
337340 .map(|it| {
338 let ty = it
339 .ty
340 .get()
341 .instantiate(interner, args.split_closure_args_untupled().parent_args);
341 let ty = it.ty.get().instantiate(interner, args.as_closure().parent_args());
342342 db.layout_of_ty(ty.store(), trait_env.clone())
343343 })
344344 .collect::<Result<Vec<_>, _>>()?;
src/tools/rust-analyzer/crates/hir-ty/src/lib.rs+2
......@@ -25,6 +25,7 @@ extern crate ra_ap_rustc_next_trait_solver as rustc_next_trait_solver;
2525
2626extern crate self as hir_ty;
2727
28pub mod builtin_derive;
2829mod infer;
2930mod inhabitedness;
3031mod lower;
......@@ -49,6 +50,7 @@ pub mod method_resolution;
4950pub mod mir;
5051pub mod primitive;
5152pub mod traits;
53pub mod upvars;
5254
5355#[cfg(test)]
5456mod test_db;
src/tools/rust-analyzer/crates/hir-ty/src/lower.rs+23-7
......@@ -1790,6 +1790,13 @@ impl<'db> GenericPredicates {
17901790}
17911791
17921792impl GenericPredicates {
1793 #[inline]
1794 pub(crate) fn from_explicit_own_predicates(
1795 predicates: StoredEarlyBinder<StoredClauses>,
1796 ) -> Self {
1797 Self { predicates, own_predicates_start: 0, is_trait: false, parent_is_trait: false }
1798 }
1799
17931800 #[inline]
17941801 pub fn query(db: &dyn HirDatabase, def: GenericDefId) -> &GenericPredicates {
17951802 &Self::query_with_diagnostics(db, def).0
......@@ -1848,6 +1855,20 @@ pub(crate) fn trait_environment_for_body_query(
18481855 db.trait_environment(def)
18491856}
18501857
1858pub(crate) fn param_env_from_predicates<'db>(
1859 interner: DbInterner<'db>,
1860 predicates: &'db GenericPredicates,
1861) -> ParamEnv<'db> {
1862 let clauses = rustc_type_ir::elaborate::elaborate(
1863 interner,
1864 predicates.all_predicates().iter_identity_copied(),
1865 );
1866 let clauses = Clauses::new_from_iter(interner, clauses);
1867
1868 // FIXME: We should normalize projections here, like rustc does.
1869 ParamEnv { clauses }
1870}
1871
18511872pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId) -> ParamEnv<'db> {
18521873 return ParamEnv { clauses: trait_environment_query(db, def).as_ref() };
18531874
......@@ -1858,13 +1879,8 @@ pub(crate) fn trait_environment<'db>(db: &'db dyn HirDatabase, def: GenericDefId
18581879 ) -> StoredClauses {
18591880 let module = def.module(db);
18601881 let interner = DbInterner::new_with(db, module.krate(db));
1861 let predicates = GenericPredicates::query_all(db, def);
1862 let clauses =
1863 rustc_type_ir::elaborate::elaborate(interner, predicates.iter_identity_copied());
1864 let clauses = Clauses::new_from_iter(interner, clauses);
1865
1866 // FIXME: We should normalize projections here, like rustc does.
1867 clauses.store()
1882 let predicates = GenericPredicates::query(db, def);
1883 param_env_from_predicates(interner, predicates).clauses.store()
18681884 }
18691885}
18701886
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution.rs+84-35
......@@ -13,11 +13,13 @@ use tracing::{debug, instrument};
1313
1414use base_db::Crate;
1515use hir_def::{
16 AssocItemId, BlockId, ConstId, FunctionId, GenericParamId, HasModule, ImplId, ItemContainerId,
17 ModuleId, TraitId,
16 AssocItemId, BlockId, BuiltinDeriveImplId, ConstId, FunctionId, GenericParamId, HasModule,
17 ImplId, ItemContainerId, ModuleId, TraitId,
1818 attrs::AttrFlags,
19 builtin_derive::BuiltinDeriveImplMethod,
1920 expr_store::path::GenericArgs as HirGenericArgs,
2021 hir::ExprId,
22 lang_item::LangItems,
2123 nameres::{DefMap, block_def_map, crate_def_map},
2224 resolver::Resolver,
2325};
......@@ -37,7 +39,7 @@ use crate::{
3739 infer::{InferenceContext, unify::InferenceTable},
3840 lower::GenericPredicates,
3941 next_solver::{
40 Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
42 AnyImplId, Binder, ClauseKind, DbInterner, FnSig, GenericArgs, ParamEnv, PredicateKind,
4143 SimplifiedType, SolverDefId, TraitRef, Ty, TyKind, TypingMode,
4244 infer::{
4345 BoundRegionConversionTime, DbInternerInferExt, InferCtxt, InferOk,
......@@ -132,7 +134,7 @@ pub enum MethodError<'db> {
132134// candidate can arise. Used for error reporting only.
133135#[derive(Copy, Clone, Debug, Eq, PartialEq)]
134136pub enum CandidateSource {
135 Impl(ImplId),
137 Impl(AnyImplId),
136138 Trait(TraitId),
137139}
138140
......@@ -371,9 +373,13 @@ pub fn lookup_impl_const<'db>(
371373 };
372374
373375 lookup_impl_assoc_item_for_trait_ref(infcx, trait_ref, env, name)
374 .and_then(
375 |assoc| if let (AssocItemId::ConstId(id), s) = assoc { Some((id, s)) } else { None },
376 )
376 .and_then(|assoc| {
377 if let (Either::Left(AssocItemId::ConstId(id)), s) = assoc {
378 Some((id, s))
379 } else {
380 None
381 }
382 })
377383 .unwrap_or((const_id, subs))
378384}
379385
......@@ -419,12 +425,12 @@ pub(crate) fn lookup_impl_method_query<'db>(
419425 env: ParamEnvAndCrate<'db>,
420426 func: FunctionId,
421427 fn_subst: GenericArgs<'db>,
422) -> (FunctionId, GenericArgs<'db>) {
428) -> (Either<FunctionId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>) {
423429 let interner = DbInterner::new_with(db, env.krate);
424430 let infcx = interner.infer_ctxt().build(TypingMode::PostAnalysis);
425431
426432 let ItemContainerId::TraitId(trait_id) = func.loc(db).container else {
427 return (func, fn_subst);
433 return (Either::Left(func), fn_subst);
428434 };
429435 let trait_params = db.generic_params(trait_id.into()).len();
430436 let trait_ref = TraitRef::new_from_args(
......@@ -434,16 +440,19 @@ pub(crate) fn lookup_impl_method_query<'db>(
434440 );
435441
436442 let name = &db.function_signature(func).name;
437 let Some((impl_fn, impl_subst)) = lookup_impl_assoc_item_for_trait_ref(
438 &infcx,
439 trait_ref,
440 env.param_env,
441 name,
442 )
443 .and_then(|assoc| {
444 if let (AssocItemId::FunctionId(id), subst) = assoc { Some((id, subst)) } else { None }
445 }) else {
446 return (func, fn_subst);
443 let Some((impl_fn, impl_subst)) =
444 lookup_impl_assoc_item_for_trait_ref(&infcx, trait_ref, env.param_env, name).and_then(
445 |(assoc, impl_args)| {
446 let assoc = match assoc {
447 Either::Left(AssocItemId::FunctionId(id)) => Either::Left(id),
448 Either::Right(it) => Either::Right(it),
449 _ => return None,
450 };
451 Some((assoc, impl_args))
452 },
453 )
454 else {
455 return (Either::Left(func), fn_subst);
447456 };
448457
449458 (
......@@ -460,22 +469,33 @@ fn lookup_impl_assoc_item_for_trait_ref<'db>(
460469 trait_ref: TraitRef<'db>,
461470 env: ParamEnv<'db>,
462471 name: &Name,
463) -> Option<(AssocItemId, GenericArgs<'db>)> {
472) -> Option<(Either<AssocItemId, (BuiltinDeriveImplId, BuiltinDeriveImplMethod)>, GenericArgs<'db>)>
473{
464474 let (impl_id, impl_subst) = find_matching_impl(infcx, env, trait_ref)?;
475 let impl_id = match impl_id {
476 AnyImplId::ImplId(it) => it,
477 AnyImplId::BuiltinDeriveImplId(impl_) => {
478 return impl_
479 .loc(infcx.interner.db)
480 .trait_
481 .get_method(name.symbol())
482 .map(|method| (Either::Right((impl_, method)), impl_subst));
483 }
484 };
465485 let item =
466486 impl_id.impl_items(infcx.interner.db).items.iter().find_map(|(n, it)| match *it {
467487 AssocItemId::FunctionId(f) => (n == name).then_some(AssocItemId::FunctionId(f)),
468488 AssocItemId::ConstId(c) => (n == name).then_some(AssocItemId::ConstId(c)),
469489 AssocItemId::TypeAliasId(_) => None,
470490 })?;
471 Some((item, impl_subst))
491 Some((Either::Left(item), impl_subst))
472492}
473493
474494pub(crate) fn find_matching_impl<'db>(
475495 infcx: &InferCtxt<'db>,
476496 env: ParamEnv<'db>,
477497 trait_ref: TraitRef<'db>,
478) -> Option<(ImplId, GenericArgs<'db>)> {
498) -> Option<(AnyImplId, GenericArgs<'db>)> {
479499 let trait_ref = infcx.at(&ObligationCause::dummy(), env).deeply_normalize(trait_ref).ok()?;
480500
481501 let obligation = Obligation::new(infcx.interner, ObligationCause::dummy(), env, trait_ref);
......@@ -635,13 +655,13 @@ impl InherentImpls {
635655
636656#[derive(Debug, PartialEq)]
637657struct OneTraitImpls {
638 non_blanket_impls: FxHashMap<SimplifiedType, Box<[ImplId]>>,
658 non_blanket_impls: FxHashMap<SimplifiedType, (Box<[ImplId]>, Box<[BuiltinDeriveImplId]>)>,
639659 blanket_impls: Box<[ImplId]>,
640660}
641661
642662#[derive(Default)]
643663struct OneTraitImplsBuilder {
644 non_blanket_impls: FxHashMap<SimplifiedType, Vec<ImplId>>,
664 non_blanket_impls: FxHashMap<SimplifiedType, (Vec<ImplId>, Vec<BuiltinDeriveImplId>)>,
645665 blanket_impls: Vec<ImplId>,
646666}
647667
......@@ -650,7 +670,9 @@ impl OneTraitImplsBuilder {
650670 let mut non_blanket_impls = self
651671 .non_blanket_impls
652672 .into_iter()
653 .map(|(self_ty, impls)| (self_ty, impls.into_boxed_slice()))
673 .map(|(self_ty, (impls, builtin_derive_impls))| {
674 (self_ty, (impls.into_boxed_slice(), builtin_derive_impls.into_boxed_slice()))
675 })
654676 .collect::<FxHashMap<_, _>>();
655677 non_blanket_impls.shrink_to_fit();
656678 let blanket_impls = self.blanket_impls.into_boxed_slice();
......@@ -691,8 +713,9 @@ impl TraitImpls {
691713
692714impl TraitImpls {
693715 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap) -> Self {
716 let lang_items = hir_def::lang_item::lang_items(db, def_map.krate());
694717 let mut map = FxHashMap::default();
695 collect(db, def_map, &mut map);
718 collect(db, def_map, lang_items, &mut map);
696719 let mut map = map
697720 .into_iter()
698721 .map(|(trait_id, trait_map)| (trait_id, trait_map.finish()))
......@@ -703,6 +726,7 @@ impl TraitImpls {
703726 fn collect(
704727 db: &dyn HirDatabase,
705728 def_map: &DefMap,
729 lang_items: &LangItems,
706730 map: &mut FxHashMap<TraitId, OneTraitImplsBuilder>,
707731 ) {
708732 for (_module_id, module_data) in def_map.modules() {
......@@ -727,18 +751,29 @@ impl TraitImpls {
727751 let entry = map.entry(trait_ref.def_id.0).or_default();
728752 match simplify_type(interner, self_ty, TreatParams::InstantiateWithInfer) {
729753 Some(self_ty) => {
730 entry.non_blanket_impls.entry(self_ty).or_default().push(impl_id)
754 entry.non_blanket_impls.entry(self_ty).or_default().0.push(impl_id)
731755 }
732756 None => entry.blanket_impls.push(impl_id),
733757 }
734758 }
735759
760 for impl_id in module_data.scope.builtin_derive_impls() {
761 let loc = impl_id.loc(db);
762 let Some(trait_id) = loc.trait_.get_id(lang_items) else { continue };
763 let entry = map.entry(trait_id).or_default();
764 let entry = entry
765 .non_blanket_impls
766 .entry(SimplifiedType::Adt(loc.adt.into()))
767 .or_default();
768 entry.1.push(impl_id);
769 }
770
736771 // To better support custom derives, collect impls in all unnamed const items.
737772 // const _: () = { ... };
738773 for konst in module_data.scope.unnamed_consts() {
739774 let body = db.body(konst.into());
740775 for (_, block_def_map) in body.blocks(db) {
741 collect(db, block_def_map, map);
776 collect(db, block_def_map, lang_items, map);
742777 }
743778 }
744779 }
......@@ -761,27 +796,41 @@ impl TraitImpls {
761796 })
762797 }
763798
764 pub fn for_trait_and_self_ty(&self, trait_: TraitId, self_ty: &SimplifiedType) -> &[ImplId] {
799 pub fn for_trait_and_self_ty(
800 &self,
801 trait_: TraitId,
802 self_ty: &SimplifiedType,
803 ) -> (&[ImplId], &[BuiltinDeriveImplId]) {
765804 self.map
766805 .get(&trait_)
767806 .and_then(|map| map.non_blanket_impls.get(self_ty))
768 .map(|it| &**it)
807 .map(|it| (&*it.0, &*it.1))
769808 .unwrap_or_default()
770809 }
771810
772 pub fn for_trait(&self, trait_: TraitId, mut callback: impl FnMut(&[ImplId])) {
811 pub fn for_trait(
812 &self,
813 trait_: TraitId,
814 mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
815 ) {
773816 if let Some(impls) = self.map.get(&trait_) {
774 callback(&impls.blanket_impls);
817 callback(Either::Left(&impls.blanket_impls));
775818 for impls in impls.non_blanket_impls.values() {
776 callback(impls);
819 callback(Either::Left(&impls.0));
820 callback(Either::Right(&impls.1));
777821 }
778822 }
779823 }
780824
781 pub fn for_self_ty(&self, self_ty: &SimplifiedType, mut callback: impl FnMut(&[ImplId])) {
825 pub fn for_self_ty(
826 &self,
827 self_ty: &SimplifiedType,
828 mut callback: impl FnMut(Either<&[ImplId], &[BuiltinDeriveImplId]>),
829 ) {
782830 for for_trait in self.map.values() {
783831 if let Some(for_ty) = for_trait.non_blanket_impls.get(self_ty) {
784 callback(for_ty);
832 callback(Either::Left(&for_ty.0));
833 callback(Either::Right(&for_ty.1));
785834 }
786835 }
787836 }
src/tools/rust-analyzer/crates/hir-ty/src/method_resolution/probe.rs+3-3
......@@ -1001,7 +1001,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
10011001 self.with_impl_item(impl_def_id, |this, item| {
10021002 if !this.has_applicable_self(item) {
10031003 // No receiver declared. Not a candidate.
1004 this.record_static_candidate(CandidateSource::Impl(impl_def_id));
1004 this.record_static_candidate(CandidateSource::Impl(impl_def_id.into()));
10051005 return;
10061006 }
10071007 this.push_candidate(
......@@ -1490,7 +1490,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
14901490 /// so do not use to make a decision that may lead to a successful compilation.
14911491 fn candidate_source(&self, candidate: &Candidate<'db>, self_ty: Ty<'db>) -> CandidateSource {
14921492 match candidate.kind {
1493 InherentImplCandidate { impl_def_id, .. } => CandidateSource::Impl(impl_def_id),
1493 InherentImplCandidate { impl_def_id, .. } => CandidateSource::Impl(impl_def_id.into()),
14941494 ObjectCandidate(trait_ref) | WhereClauseCandidate(trait_ref) => {
14951495 CandidateSource::Trait(trait_ref.def_id().0)
14961496 }
......@@ -1524,7 +1524,7 @@ impl<'a, 'db, Choice: ProbeChoice<'db>> ProbeContext<'a, 'db, Choice> {
15241524
15251525 fn candidate_source_from_pick(&self, pick: &Pick<'db>) -> CandidateSource {
15261526 match pick.kind {
1527 InherentImplPick(impl_) => CandidateSource::Impl(impl_),
1527 InherentImplPick(impl_) => CandidateSource::Impl(impl_.into()),
15281528 ObjectPick(trait_) | TraitPick(trait_) => CandidateSource::Trait(trait_),
15291529 WhereClausePick(trait_ref) => CandidateSource::Trait(trait_ref.skip_binder().def_id.0),
15301530 }
src/tools/rust-analyzer/crates/hir-ty/src/mir/borrowck.rs+2-1
......@@ -8,6 +8,7 @@ use std::iter;
88use hir_def::{DefWithBodyId, HasModule};
99use la_arena::ArenaMap;
1010use rustc_hash::FxHashMap;
11use rustc_type_ir::inherent::GenericArgs as _;
1112use stdx::never;
1213use triomphe::Arc;
1314
......@@ -123,7 +124,7 @@ fn make_fetch_closure_field<'db>(
123124 let InternedClosure(def, _) = db.lookup_intern_closure(c);
124125 let infer = InferenceResult::for_body(db, def);
125126 let (captures, _) = infer.closure_info(c);
126 let parent_subst = subst.split_closure_args_untupled().parent_args;
127 let parent_subst = subst.as_closure().parent_args();
127128 let interner = DbInterner::new_no_crate(db);
128129 captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst)
129130 }
src/tools/rust-analyzer/crates/hir-ty/src/mir/eval.rs+9-4
......@@ -27,7 +27,7 @@ use rustc_ast_ir::Mutability;
2727use rustc_hash::{FxHashMap, FxHashSet};
2828use rustc_type_ir::{
2929 AliasTyKind,
30 inherent::{AdtDef, IntoKind, Region as _, SliceLike, Ty as _},
30 inherent::{AdtDef, GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
3131};
3232use span::FileId;
3333use stdx::never;
......@@ -77,12 +77,14 @@ macro_rules! from_bytes {
7777 }).into())
7878 };
7979}
80use from_bytes;
8081
8182macro_rules! not_supported {
8283 ($it: expr) => {
83 return Err(MirEvalError::NotSupported(format!($it)))
84 return Err($crate::mir::eval::MirEvalError::NotSupported(format!($it)))
8485 };
8586}
87use not_supported;
8688
8789#[derive(Debug, Default, Clone, PartialEq, Eq, GenericTypeVisitable)]
8890pub struct VTableMap<'db> {
......@@ -731,7 +733,7 @@ impl<'db> Evaluator<'db> {
731733 let InternedClosure(def, _) = self.db.lookup_intern_closure(c);
732734 let infer = InferenceResult::for_body(self.db, def);
733735 let (captures, _) = infer.closure_info(c);
734 let parent_subst = subst.split_closure_args_untupled().parent_args;
736 let parent_subst = subst.as_closure().parent_args();
735737 captures
736738 .get(f)
737739 .expect("broken closure field")
......@@ -2622,6 +2624,9 @@ impl<'db> Evaluator<'db> {
26222624 def,
26232625 generic_args,
26242626 );
2627 let Either::Left(imp) = imp else {
2628 not_supported!("evaluating builtin derive impls is not supported")
2629 };
26252630
26262631 let mir_body = self
26272632 .db
......@@ -2771,7 +2776,7 @@ impl<'db> Evaluator<'db> {
27712776 TyKind::Closure(closure, subst) => self.exec_closure(
27722777 closure.0,
27732778 func_data,
2774 GenericArgs::new_from_slice(subst.split_closure_args_untupled().parent_args),
2779 GenericArgs::new_from_slice(subst.as_closure().parent_args()),
27752780 destination,
27762781 &args[1..],
27772782 locals,
src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs+2-17
......@@ -16,29 +16,14 @@ use crate::{
1616 mir::eval::{
1717 Address, AdtId, Arc, Evaluator, FunctionId, GenericArgs, HasModule, HirDisplay,
1818 InternedClosure, Interval, IntervalAndTy, IntervalOrOwned, ItemContainerId, Layout, Locals,
19 Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, pad16,
19 Lookup, MirEvalError, MirSpan, Mutability, Result, Ty, TyKind, from_bytes, not_supported,
20 pad16,
2021 },
2122 next_solver::Region,
2223};
2324
2425mod simd;
2526
26macro_rules! from_bytes {
27 ($ty:tt, $value:expr) => {
28 ($ty::from_le_bytes(match ($value).try_into() {
29 Ok(it) => it,
30 #[allow(unreachable_patterns)]
31 Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
32 }))
33 };
34}
35
36macro_rules! not_supported {
37 ($it: expr) => {
38 return Err(MirEvalError::NotSupported(format!($it)))
39 };
40}
41
4227#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4328enum EvalLangItem {
4429 BeginPanic,
src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim/simd.rs-15
......@@ -6,21 +6,6 @@ use crate::consteval::try_const_usize;
66
77use super::*;
88
9macro_rules! from_bytes {
10 ($ty:tt, $value:expr) => {
11 ($ty::from_le_bytes(match ($value).try_into() {
12 Ok(it) => it,
13 Err(_) => return Err(MirEvalError::InternalError("mismatched size".into())),
14 }))
15 };
16}
17
18macro_rules! not_supported {
19 ($it: expr) => {
20 return Err(MirEvalError::NotSupported(format!($it)))
21 };
22}
23
249impl<'db> Evaluator<'db> {
2510 fn detect_simd_ty(&self, ty: Ty<'db>) -> Result<'db, (usize, Ty<'db>)> {
2611 match ty.kind() {
src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs+21-24
......@@ -19,7 +19,7 @@ use hir_expand::name::Name;
1919use la_arena::ArenaMap;
2020use rustc_apfloat::Float;
2121use rustc_hash::FxHashMap;
22use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _};
22use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _};
2323use span::{Edition, FileId};
2424use syntax::TextRange;
2525use triomphe::Arc;
......@@ -30,7 +30,10 @@ use crate::{
3030 db::{HirDatabase, InternedClosure, InternedClosureId},
3131 display::{DisplayTarget, HirDisplay, hir_display_with_store},
3232 generics::generics,
33 infer::{CaptureKind, CapturedItem, TypeMismatch, cast::CastTy},
33 infer::{
34 CaptureKind, CapturedItem, TypeMismatch, cast::CastTy,
35 closure::analysis::HirPlaceProjection,
36 },
3437 inhabitedness::is_ty_uninhabited_from,
3538 layout::LayoutError,
3639 method_resolution::CandidateId,
......@@ -44,6 +47,7 @@ use crate::{
4447 next_solver::{
4548 Const, DbInterner, ParamConst, ParamEnv, Region, StoredGenericArgs, StoredTy, TyKind,
4649 TypingMode, UnevaluatedConst,
50 abi::Safety,
4751 infer::{DbInternerInferExt, InferCtxt},
4852 },
4953 traits::FnTrait,
......@@ -1257,22 +1261,16 @@ impl<'a, 'db> MirLowerCtx<'a, 'db> {
12571261 .clone()
12581262 .into_iter()
12591263 .map(|it| match it {
1260 ProjectionElem::Deref => ProjectionElem::Deref,
1261 ProjectionElem::Field(it) => ProjectionElem::Field(it),
1262 ProjectionElem::ClosureField(it) => {
1263 ProjectionElem::ClosureField(it)
1264 }
1265 ProjectionElem::ConstantIndex { offset, from_end } => {
1266 ProjectionElem::ConstantIndex { offset, from_end }
1267 }
1268 ProjectionElem::Subslice { from, to } => {
1269 ProjectionElem::Subslice { from, to }
1264 HirPlaceProjection::Deref => ProjectionElem::Deref,
1265 HirPlaceProjection::Field(field_id) => {
1266 ProjectionElem::Field(Either::Left(field_id))
12701267 }
1271 ProjectionElem::OpaqueCast(it) => {
1272 ProjectionElem::OpaqueCast(it)
1268 HirPlaceProjection::TupleField(idx) => {
1269 ProjectionElem::Field(Either::Right(TupleFieldId {
1270 tuple: TupleId(!0), // Dummy as it's unused
1271 index: idx,
1272 }))
12731273 }
1274 #[allow(unreachable_patterns)]
1275 ProjectionElem::Index(it) => match it {},
12761274 })
12771275 .collect(),
12781276 ),
......@@ -2138,11 +2136,7 @@ pub fn mir_body_for_closure_query<'db>(
21382136 .store(),
21392137 });
21402138 ctx.result.param_locals.push(closure_local);
2141 let Some(sig) =
2142 substs.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.callable_sig(ctx.interner())
2143 else {
2144 implementation_error!("closure has not callable sig");
2145 };
2139 let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe);
21462140 let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr);
21472141 let current = ctx.lower_params_and_bindings(
21482142 args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)),
......@@ -2176,10 +2170,13 @@ pub fn mir_body_for_closure_query<'db>(
21762170 for (it, y) in p.projection.lookup(store).iter().zip(it.0.place.projections.iter())
21772171 {
21782172 match (it, y) {
2179 (ProjectionElem::Deref, ProjectionElem::Deref) => (),
2180 (ProjectionElem::Field(it), ProjectionElem::Field(y)) if it == y => (),
2181 (ProjectionElem::ClosureField(it), ProjectionElem::ClosureField(y))
2173 (ProjectionElem::Deref, HirPlaceProjection::Deref) => (),
2174 (ProjectionElem::Field(Either::Left(it)), HirPlaceProjection::Field(y))
21822175 if it == y => {}
2176 (
2177 ProjectionElem::Field(Either::Right(it)),
2178 HirPlaceProjection::TupleField(y),
2179 ) if it.index == *y => (),
21832180 _ => return false,
21842181 }
21852182 }
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/def_id.rs+47-27
......@@ -1,9 +1,9 @@
11//! Definition of `SolverDefId`
22
33use hir_def::{
4 AdtId, AttrDefId, CallableDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId,
5 GeneralConstId, GenericDefId, HasModule, ImplId, ModuleId, StaticId, StructId, TraitId,
6 TypeAliasId, UnionId, db::DefDatabase,
4 AdtId, AttrDefId, BuiltinDeriveImplId, CallableDefId, ConstId, DefWithBodyId, EnumId,
5 EnumVariantId, FunctionId, GeneralConstId, GenericDefId, ImplId, StaticId, StructId, TraitId,
6 TypeAliasId, UnionId,
77};
88use rustc_type_ir::inherent;
99use stdx::impl_from;
......@@ -24,6 +24,7 @@ pub enum SolverDefId {
2424 ConstId(ConstId),
2525 FunctionId(FunctionId),
2626 ImplId(ImplId),
27 BuiltinDeriveImplId(BuiltinDeriveImplId),
2728 StaticId(StaticId),
2829 TraitId(TraitId),
2930 TypeAliasId(TypeAliasId),
......@@ -57,6 +58,7 @@ impl std::fmt::Debug for SolverDefId {
5758 f.debug_tuple("FunctionId").field(&db.function_signature(id).name.as_str()).finish()
5859 }
5960 SolverDefId::ImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
61 SolverDefId::BuiltinDeriveImplId(id) => f.debug_tuple("ImplId").field(&id).finish(),
6062 SolverDefId::StaticId(id) => {
6163 f.debug_tuple("StaticId").field(&db.static_signature(id).name.as_str()).finish()
6264 }
......@@ -108,6 +110,7 @@ impl_from!(
108110 ConstId,
109111 FunctionId,
110112 ImplId,
113 BuiltinDeriveImplId,
111114 StaticId,
112115 TraitId,
113116 TypeAliasId,
......@@ -170,7 +173,8 @@ impl TryFrom<SolverDefId> for AttrDefId {
170173 SolverDefId::EnumVariantId(it) => Ok(it.into()),
171174 SolverDefId::Ctor(Ctor::Struct(it)) => Ok(it.into()),
172175 SolverDefId::Ctor(Ctor::Enum(it)) => Ok(it.into()),
173 SolverDefId::InternedClosureId(_)
176 SolverDefId::BuiltinDeriveImplId(_)
177 | SolverDefId::InternedClosureId(_)
174178 | SolverDefId::InternedCoroutineId(_)
175179 | SolverDefId::InternedOpaqueTyId(_) => Err(()),
176180 }
......@@ -191,6 +195,7 @@ impl TryFrom<SolverDefId> for DefWithBodyId {
191195 | SolverDefId::TraitId(_)
192196 | SolverDefId::TypeAliasId(_)
193197 | SolverDefId::ImplId(_)
198 | SolverDefId::BuiltinDeriveImplId(_)
194199 | SolverDefId::InternedClosureId(_)
195200 | SolverDefId::InternedCoroutineId(_)
196201 | SolverDefId::Ctor(Ctor::Struct(_))
......@@ -216,6 +221,7 @@ impl TryFrom<SolverDefId> for GenericDefId {
216221 | SolverDefId::InternedCoroutineId(_)
217222 | SolverDefId::InternedOpaqueTyId(_)
218223 | SolverDefId::EnumVariantId(_)
224 | SolverDefId::BuiltinDeriveImplId(_)
219225 | SolverDefId::Ctor(_) => return Err(()),
220226 })
221227 }
......@@ -241,28 +247,6 @@ impl SolverDefId {
241247 }
242248}
243249
244impl HasModule for SolverDefId {
245 fn module(&self, db: &dyn DefDatabase) -> ModuleId {
246 match *self {
247 SolverDefId::AdtId(id) => id.module(db),
248 SolverDefId::ConstId(id) => id.module(db),
249 SolverDefId::FunctionId(id) => id.module(db),
250 SolverDefId::ImplId(id) => id.module(db),
251 SolverDefId::StaticId(id) => id.module(db),
252 SolverDefId::TraitId(id) => id.module(db),
253 SolverDefId::TypeAliasId(id) => id.module(db),
254 SolverDefId::InternedClosureId(id) => id.loc(db).0.module(db),
255 SolverDefId::InternedCoroutineId(id) => id.loc(db).0.module(db),
256 SolverDefId::InternedOpaqueTyId(id) => match id.loc(db) {
257 crate::ImplTraitId::ReturnTypeImplTrait(owner, _) => owner.module(db),
258 crate::ImplTraitId::TypeAliasImplTrait(owner, _) => owner.module(db),
259 },
260 SolverDefId::Ctor(Ctor::Enum(id)) | SolverDefId::EnumVariantId(id) => id.module(db),
261 SolverDefId::Ctor(Ctor::Struct(id)) => id.module(db),
262 }
263 }
264}
265
266250impl<'db> inherent::DefId<DbInterner<'db>> for SolverDefId {
267251 fn as_local(self) -> Option<SolverDefId> {
268252 Some(self)
......@@ -332,7 +316,6 @@ declare_id_wrapper!(TypeAliasIdWrapper, TypeAliasId);
332316declare_id_wrapper!(ClosureIdWrapper, InternedClosureId);
333317declare_id_wrapper!(CoroutineIdWrapper, InternedCoroutineId);
334318declare_id_wrapper!(AdtIdWrapper, AdtId);
335declare_id_wrapper!(ImplIdWrapper, ImplId);
336319
337320#[derive(Clone, Copy, PartialEq, Eq, Hash)]
338321pub struct GeneralConstIdWrapper(pub GeneralConstId);
......@@ -433,3 +416,40 @@ impl<'db> inherent::DefId<DbInterner<'db>> for CallableIdWrapper {
433416 true
434417 }
435418}
419
420#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
421pub enum AnyImplId {
422 ImplId(ImplId),
423 BuiltinDeriveImplId(BuiltinDeriveImplId),
424}
425
426impl_from!(ImplId, BuiltinDeriveImplId for AnyImplId);
427
428impl From<AnyImplId> for SolverDefId {
429 #[inline]
430 fn from(value: AnyImplId) -> SolverDefId {
431 match value {
432 AnyImplId::ImplId(it) => it.into(),
433 AnyImplId::BuiltinDeriveImplId(it) => it.into(),
434 }
435 }
436}
437impl TryFrom<SolverDefId> for AnyImplId {
438 type Error = ();
439 #[inline]
440 fn try_from(value: SolverDefId) -> Result<Self, Self::Error> {
441 match value {
442 SolverDefId::ImplId(it) => Ok(it.into()),
443 SolverDefId::BuiltinDeriveImplId(it) => Ok(it.into()),
444 _ => Err(()),
445 }
446 }
447}
448impl<'db> inherent::DefId<DbInterner<'db>> for AnyImplId {
449 fn as_local(self) -> Option<SolverDefId> {
450 Some(self.into())
451 }
452 fn is_local(self) -> bool {
453 true
454 }
455}
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/format_proof_tree.rs+24-7
......@@ -1,8 +1,8 @@
11use rustc_type_ir::{solve::GoalSource, solve::inspect::GoalEvaluation};
22use serde_derive::{Deserialize, Serialize};
33
4use crate::next_solver::infer::InferCtxt;
54use crate::next_solver::inspect::{InspectCandidate, InspectGoal};
5use crate::next_solver::{AnyImplId, infer::InferCtxt};
66use crate::next_solver::{DbInterner, Span};
77
88#[derive(Debug, Clone, Serialize, Deserialize)]
......@@ -76,14 +76,31 @@ impl<'a, 'db> ProofTreeSerializer<'a, 'db> {
7676 use rustc_type_ir::solve::inspect::ProbeKind;
7777 match candidate.kind() {
7878 ProbeKind::TraitCandidate { source, .. } => {
79 use hir_def::{Lookup, src::HasSource};
7980 use rustc_type_ir::solve::CandidateSource;
81 let db = self.infcx.interner.db;
8082 match source {
81 CandidateSource::Impl(impl_def_id) => {
82 use hir_def::{Lookup, src::HasSource};
83 let db = self.infcx.interner.db;
84 let impl_src = impl_def_id.0.lookup(db).source(db);
85 Some(impl_src.value.to_string())
86 }
83 CandidateSource::Impl(impl_def_id) => match impl_def_id {
84 AnyImplId::ImplId(impl_def_id) => {
85 let impl_src = impl_def_id.lookup(db).source(db);
86 Some(impl_src.value.to_string())
87 }
88 AnyImplId::BuiltinDeriveImplId(impl_id) => {
89 let impl_loc = impl_id.loc(db);
90 let adt_src = match impl_loc.adt {
91 hir_def::AdtId::StructId(adt) => {
92 adt.loc(db).source(db).value.to_string()
93 }
94 hir_def::AdtId::UnionId(adt) => {
95 adt.loc(db).source(db).value.to_string()
96 }
97 hir_def::AdtId::EnumId(adt) => {
98 adt.loc(db).source(db).value.to_string()
99 }
100 };
101 Some(format!("#[derive(${})]\n{}", impl_loc.trait_.name(), adt_src))
102 }
103 },
87104 _ => None,
88105 }
89106 }
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generic_arg.rs+6-52
......@@ -11,9 +11,9 @@ use std::{hint::unreachable_unchecked, marker::PhantomData, ptr::NonNull};
1111use hir_def::{GenericDefId, GenericParamId};
1212use intern::InternedRef;
1313use rustc_type_ir::{
14 ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, FnSigTys,
15 GenericTypeVisitable, Interner, TyKind, TyVid, TypeFoldable, TypeFolder, TypeVisitable,
16 TypeVisitor, Variance,
14 ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder,
15 GenericTypeVisitable, Interner, TyVid, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
16 Variance,
1717 inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _},
1818 relate::{Relate, VarianceDiagInfo},
1919 walk::TypeWalker,
......@@ -21,12 +21,11 @@ use rustc_type_ir::{
2121use smallvec::SmallVec;
2222
2323use crate::next_solver::{
24 ConstInterned, PolyFnSig, RegionInterned, TyInterned, impl_foldable_for_interned_slice,
25 interned_slice,
24 ConstInterned, RegionInterned, TyInterned, impl_foldable_for_interned_slice, interned_slice,
2625};
2726
2827use super::{
29 Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys,
28 Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty,
3029 generics::Generics,
3130};
3231
......@@ -566,33 +565,6 @@ impl<'db> GenericArgs<'db> {
566565 }
567566 }
568567
569 pub fn closure_sig_untupled(self) -> PolyFnSig<'db> {
570 let TyKind::FnPtr(inputs_and_output, hdr) =
571 self.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.kind()
572 else {
573 unreachable!("not a function pointer")
574 };
575 inputs_and_output.with(hdr)
576 }
577
578 /// A "sensible" `.split_closure_args()`, where the arguments are not in a tuple.
579 pub fn split_closure_args_untupled(self) -> rustc_type_ir::ClosureArgsParts<DbInterner<'db>> {
580 // FIXME: should use `ClosureSubst` when possible
581 match self.as_slice() {
582 [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
583 rustc_type_ir::ClosureArgsParts {
584 parent_args,
585 closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
586 closure_kind_ty: closure_kind_ty.expect_ty(),
587 tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
588 }
589 }
590 _ => {
591 unreachable!("unexpected closure sig");
592 }
593 }
594 }
595
596568 pub fn types(self) -> impl Iterator<Item = Ty<'db>> {
597569 self.iter().filter_map(|it| it.as_type())
598570 }
......@@ -688,27 +660,9 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<
688660 // FIXME: should use `ClosureSubst` when possible
689661 match self.as_slice() {
690662 [parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
691 let interner = DbInterner::conjure();
692 // This is stupid, but the next solver expects the first input to actually be a tuple
693 let sig_ty = match sig_ty.expect_ty().kind() {
694 TyKind::FnPtr(sig_tys, header) => Ty::new(
695 interner,
696 TyKind::FnPtr(
697 sig_tys.map_bound(|s| {
698 let inputs = Ty::new_tup(interner, s.inputs());
699 let output = s.output();
700 FnSigTys {
701 inputs_and_output: Tys::new_from_slice(&[inputs, output]),
702 }
703 }),
704 header,
705 ),
706 ),
707 _ => unreachable!("sig_ty should be last"),
708 };
709663 rustc_type_ir::ClosureArgsParts {
710664 parent_args,
711 closure_sig_as_fn_ptr_ty: sig_ty,
665 closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
712666 closure_kind_ty: closure_kind_ty.expect_ty(),
713667 tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
714668 }
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/generics.rs+15-3
......@@ -4,14 +4,15 @@ use hir_def::{
44 ConstParamId, GenericDefId, GenericParamId, LifetimeParamId, TypeOrConstParamId, TypeParamId,
55 hir::generics::{GenericParams, TypeOrConstParamData},
66};
7use rustc_type_ir::inherent::GenericsOf;
78
8use crate::{db::HirDatabase, generics::parent_generic_def};
9use crate::generics::parent_generic_def;
910
1011use super::SolverDefId;
1112
1213use super::DbInterner;
1314
14pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
15pub(crate) fn generics(interner: DbInterner<'_>, def: SolverDefId) -> Generics {
1516 let mk_lt = |parent, index, local_id| {
1617 let id = GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id });
1718 GenericParamDef { index, id }
......@@ -50,6 +51,7 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
5051 result
5152 };
5253
54 let db = interner.db;
5355 let (parent, own_params) = match (def.try_into(), def) {
5456 (Ok(def), _) => (
5557 parent_generic_def(db, def),
......@@ -66,9 +68,12 @@ pub(crate) fn generics(db: &dyn HirDatabase, def: SolverDefId) -> Generics {
6668 }
6769 }
6870 }
71 (_, SolverDefId::BuiltinDeriveImplId(id)) => {
72 return crate::builtin_derive::generics_of(interner, id);
73 }
6974 _ => panic!("No generics for {def:?}"),
7075 };
71 let parent_generics = parent.map(|def| Box::new(generics(db, def.into())));
76 let parent_generics = parent.map(|def| Box::new(generics(interner, def.into())));
7277
7378 Generics {
7479 parent,
......@@ -84,6 +89,13 @@ pub struct Generics {
8489 pub own_params: Vec<GenericParamDef>,
8590}
8691
92impl Generics {
93 pub(crate) fn push_param(&mut self, id: GenericParamId) {
94 let index = self.count() as u32;
95 self.own_params.push(GenericParamDef { index, id });
96 }
97}
98
8799#[derive(Debug)]
88100pub struct GenericParamDef {
89101 index: u32,
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/infer/select.rs+4-4
......@@ -2,7 +2,7 @@
22
33use std::ops::ControlFlow;
44
5use hir_def::{ImplId, TraitId};
5use hir_def::TraitId;
66use macros::{TypeFoldable, TypeVisitable};
77use rustc_type_ir::{
88 Interner,
......@@ -12,7 +12,7 @@ use rustc_type_ir::{
1212use crate::{
1313 db::InternedOpaqueTyId,
1414 next_solver::{
15 Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
15 AnyImplId, Const, ErrorGuaranteed, GenericArgs, Goal, TraitRef, Ty, TypeError,
1616 infer::{
1717 InferCtxt,
1818 select::EvaluationResult::*,
......@@ -249,7 +249,7 @@ impl<'db, N> ImplSource<'db, N> {
249249pub(crate) struct ImplSourceUserDefinedData<'db, N> {
250250 #[type_visitable(ignore)]
251251 #[type_foldable(identity)]
252 pub(crate) impl_def_id: ImplId,
252 pub(crate) impl_def_id: AnyImplId,
253253 pub(crate) args: GenericArgs<'db>,
254254 pub(crate) nested: Vec<N>,
255255}
......@@ -395,7 +395,7 @@ fn to_selection<'db>(cand: InspectCandidate<'_, 'db>) -> Option<Selection<'db>>
395395 // FIXME: Remove this in favor of storing this in the tree
396396 // For impl candidates, we do the rematch manually to compute the args.
397397 ImplSource::UserDefined(ImplSourceUserDefinedData {
398 impl_def_id: impl_def_id.0,
398 impl_def_id,
399399 args: cand.instantiate_impl_args(),
400400 nested,
401401 })
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/interner.rs+70-43
......@@ -38,10 +38,10 @@ use crate::{
3838 lower::GenericPredicates,
3939 method_resolution::TraitImpls,
4040 next_solver::{
41 AdtIdWrapper, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
42 CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, ImplIdWrapper,
43 OpaqueTypeKey, RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds,
44 TraitIdWrapper, TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
41 AdtIdWrapper, AnyImplId, BoundConst, CallableIdWrapper, CanonicalVarKind, ClosureIdWrapper,
42 CoroutineIdWrapper, Ctor, FnSig, FxIndexMap, GeneralConstIdWrapper, OpaqueTypeKey,
43 RegionAssumptions, SimplifiedType, SolverContext, SolverDefIds, TraitIdWrapper,
44 TypeAliasIdWrapper, UnevaluatedConst, util::explicit_item_bounds,
4545 },
4646};
4747
......@@ -1020,7 +1020,7 @@ impl<'db> Interner for DbInterner<'db> {
10201020 type CoroutineClosureId = CoroutineIdWrapper;
10211021 type CoroutineId = CoroutineIdWrapper;
10221022 type AdtId = AdtIdWrapper;
1023 type ImplId = ImplIdWrapper;
1023 type ImplId = AnyImplId;
10241024 type UnevaluatedConstId = GeneralConstIdWrapper;
10251025 type Span = Span;
10261026
......@@ -1164,7 +1164,7 @@ impl<'db> Interner for DbInterner<'db> {
11641164 }
11651165
11661166 fn generics_of(self, def_id: Self::DefId) -> Self::GenericsOf {
1167 generics(self.db(), def_id)
1167 generics(self, def_id)
11681168 }
11691169
11701170 fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf {
......@@ -1190,6 +1190,7 @@ impl<'db> Interner for DbInterner<'db> {
11901190 | SolverDefId::TraitId(_)
11911191 | SolverDefId::TypeAliasId(_)
11921192 | SolverDefId::ImplId(_)
1193 | SolverDefId::BuiltinDeriveImplId(_)
11931194 | SolverDefId::InternedClosureId(_)
11941195 | SolverDefId::InternedCoroutineId(_) => {
11951196 return VariancesOf::empty(self);
......@@ -1327,6 +1328,7 @@ impl<'db> Interner for DbInterner<'db> {
13271328 | SolverDefId::AdtId(_)
13281329 | SolverDefId::TraitId(_)
13291330 | SolverDefId::ImplId(_)
1331 | SolverDefId::BuiltinDeriveImplId(_)
13301332 | SolverDefId::EnumVariantId(..)
13311333 | SolverDefId::Ctor(..)
13321334 | SolverDefId::InternedOpaqueTyId(..) => panic!(),
......@@ -1445,8 +1447,7 @@ impl<'db> Interner for DbInterner<'db> {
14451447 self,
14461448 def_id: Self::DefId,
14471449 ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
1448 GenericPredicates::query_all(self.db, def_id.try_into().unwrap())
1449 .map_bound(|it| it.iter().copied())
1450 predicates_of(self.db, def_id).all_predicates().map_bound(|it| it.iter().copied())
14501451 }
14511452
14521453 #[tracing::instrument(level = "debug", skip(self), ret)]
......@@ -1454,8 +1455,7 @@ impl<'db> Interner for DbInterner<'db> {
14541455 self,
14551456 def_id: Self::DefId,
14561457 ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
1457 GenericPredicates::query_own(self.db, def_id.try_into().unwrap())
1458 .map_bound(|it| it.iter().copied())
1458 predicates_of(self.db, def_id).own_predicates().map_bound(|it| it.iter().copied())
14591459 }
14601460
14611461 #[tracing::instrument(skip(self), ret)]
......@@ -1500,32 +1500,30 @@ impl<'db> Interner for DbInterner<'db> {
15001500 }
15011501 }
15021502
1503 GenericPredicates::query_explicit(self.db, def_id.try_into().unwrap()).map_bound(
1504 |predicates| {
1505 predicates
1506 .iter()
1507 .copied()
1508 .filter(|p| match p.kind().skip_binder() {
1509 ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
1510 ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
1511 ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
1512 ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
1513 // FIXME: Not sure is this correct to allow other clauses but we might replace
1514 // `generic_predicates_ns` query here with something closer to rustc's
1515 // `implied_bounds_with_filter`, which is more granular lowering than this
1516 // "lower at once and then filter" implementation.
1517 _ => true,
1518 })
1519 .map(|p| (p, Span::dummy()))
1520 },
1521 )
1503 predicates_of(self.db, def_id).explicit_predicates().map_bound(|predicates| {
1504 predicates
1505 .iter()
1506 .copied()
1507 .filter(|p| match p.kind().skip_binder() {
1508 ClauseKind::Trait(it) => is_self_or_assoc(it.self_ty()),
1509 ClauseKind::TypeOutlives(it) => is_self_or_assoc(it.0),
1510 ClauseKind::Projection(it) => is_self_or_assoc(it.self_ty()),
1511 ClauseKind::HostEffect(it) => is_self_or_assoc(it.self_ty()),
1512 // FIXME: Not sure is this correct to allow other clauses but we might replace
1513 // `generic_predicates_ns` query here with something closer to rustc's
1514 // `implied_bounds_with_filter`, which is more granular lowering than this
1515 // "lower at once and then filter" implementation.
1516 _ => true,
1517 })
1518 .map(|p| (p, Span::dummy()))
1519 })
15221520 }
15231521
15241522 fn impl_super_outlives(
15251523 self,
15261524 impl_id: Self::ImplId,
15271525 ) -> EarlyBinder<Self, impl IntoIterator<Item = Self::Clause>> {
1528 let trait_ref = self.db().impl_trait(impl_id.0).expect("expected an impl of trait");
1526 let trait_ref = self.impl_trait_ref(impl_id);
15291527 trait_ref.map_bound(|trait_ref| {
15301528 let clause: Clause<'_> = trait_ref.upcast(self);
15311529 elaborate(self, [clause]).filter(|clause| {
......@@ -1790,6 +1788,7 @@ impl<'db> Interner for DbInterner<'db> {
17901788 SolverDefId::ConstId(_)
17911789 | SolverDefId::FunctionId(_)
17921790 | SolverDefId::ImplId(_)
1791 | SolverDefId::BuiltinDeriveImplId(_)
17931792 | SolverDefId::StaticId(_)
17941793 | SolverDefId::InternedClosureId(_)
17951794 | SolverDefId::InternedCoroutineId(_)
......@@ -1805,7 +1804,12 @@ impl<'db> Interner for DbInterner<'db> {
18051804 type_block,
18061805 trait_block,
18071806 &mut |impls| {
1808 for &impl_ in impls.for_trait_and_self_ty(trait_def_id.0, &simp) {
1807 let (regular_impls, builtin_derive_impls) =
1808 impls.for_trait_and_self_ty(trait_def_id.0, &simp);
1809 for &impl_ in regular_impls {
1810 f(impl_.into());
1811 }
1812 for &impl_ in builtin_derive_impls {
18091813 f(impl_.into());
18101814 }
18111815 },
......@@ -1927,7 +1931,10 @@ impl<'db> Interner for DbInterner<'db> {
19271931 }
19281932
19291933 fn impl_is_default(self, impl_def_id: Self::ImplId) -> bool {
1930 self.db.impl_signature(impl_def_id.0).is_default()
1934 match impl_def_id {
1935 AnyImplId::ImplId(impl_id) => self.db.impl_signature(impl_id).is_default(),
1936 AnyImplId::BuiltinDeriveImplId(_) => false,
1937 }
19311938 }
19321939
19331940 #[tracing::instrument(skip(self), ret)]
......@@ -1935,14 +1942,24 @@ impl<'db> Interner for DbInterner<'db> {
19351942 self,
19361943 impl_id: Self::ImplId,
19371944 ) -> EarlyBinder<Self, rustc_type_ir::TraitRef<Self>> {
1938 let db = self.db();
1939 db.impl_trait(impl_id.0)
1940 // ImplIds for impls where the trait ref can't be resolved should never reach trait solving
1941 .expect("invalid impl passed to trait solver")
1945 match impl_id {
1946 AnyImplId::ImplId(impl_id) => {
1947 let db = self.db();
1948 db.impl_trait(impl_id)
1949 // ImplIds for impls where the trait ref can't be resolved should never reach trait solving
1950 .expect("invalid impl passed to trait solver")
1951 }
1952 AnyImplId::BuiltinDeriveImplId(impl_id) => {
1953 crate::builtin_derive::impl_trait(self, impl_id)
1954 }
1955 }
19421956 }
19431957
19441958 fn impl_polarity(self, impl_id: Self::ImplId) -> rustc_type_ir::ImplPolarity {
1945 let impl_data = self.db().impl_signature(impl_id.0);
1959 let AnyImplId::ImplId(impl_id) = impl_id else {
1960 return ImplPolarity::Positive;
1961 };
1962 let impl_data = self.db().impl_signature(impl_id);
19461963 if impl_data.flags.contains(ImplFlags::NEGATIVE) {
19471964 ImplPolarity::Negative
19481965 } else {
......@@ -2230,11 +2247,13 @@ impl<'db> Interner for DbInterner<'db> {
22302247 specializing_impl_def_id: Self::ImplId,
22312248 parent_impl_def_id: Self::ImplId,
22322249 ) -> bool {
2233 crate::specialization::specializes(
2234 self.db,
2235 specializing_impl_def_id.0,
2236 parent_impl_def_id.0,
2237 )
2250 let (AnyImplId::ImplId(specializing_impl_def_id), AnyImplId::ImplId(parent_impl_def_id)) =
2251 (specializing_impl_def_id, parent_impl_def_id)
2252 else {
2253 // No builtin derive allow specialization currently.
2254 return false;
2255 };
2256 crate::specialization::specializes(self.db, specializing_impl_def_id, parent_impl_def_id)
22382257 }
22392258
22402259 fn next_trait_solver_globally(self) -> bool {
......@@ -2349,6 +2368,14 @@ impl<'db> DbInterner<'db> {
23492368 }
23502369}
23512370
2371fn predicates_of(db: &dyn HirDatabase, def_id: SolverDefId) -> &GenericPredicates {
2372 if let SolverDefId::BuiltinDeriveImplId(impl_) = def_id {
2373 crate::builtin_derive::predicates(db, impl_)
2374 } else {
2375 GenericPredicates::query(db, def_id.try_into().unwrap())
2376 }
2377}
2378
23522379macro_rules! TrivialTypeTraversalImpls {
23532380 ($($ty:ty,)+) => {
23542381 $(
......@@ -2396,7 +2423,7 @@ TrivialTypeTraversalImpls! {
23962423 ClosureIdWrapper,
23972424 CoroutineIdWrapper,
23982425 AdtIdWrapper,
2399 ImplIdWrapper,
2426 AnyImplId,
24002427 GeneralConstIdWrapper,
24012428 Safety,
24022429 FnAbi,
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/solver.rs+7-3
......@@ -12,7 +12,7 @@ use rustc_type_ir::{
1212use tracing::debug;
1313
1414use crate::next_solver::{
15 AliasTy, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs, ImplIdWrapper,
15 AliasTy, AnyImplId, CanonicalVarKind, Clause, ClauseKind, CoercePredicate, GenericArgs,
1616 ParamEnv, Predicate, PredicateKind, SubtypePredicate, Ty, TyKind, fold::fold_tys,
1717 util::sizedness_fast_path,
1818};
......@@ -174,9 +174,13 @@ impl<'db> SolverDelegate for SolverContext<'db> {
174174 &self,
175175 _goal_trait_ref: rustc_type_ir::TraitRef<Self::Interner>,
176176 trait_assoc_def_id: SolverDefId,
177 impl_id: ImplIdWrapper,
177 impl_id: AnyImplId,
178178 ) -> Result<Option<SolverDefId>, ErrorGuaranteed> {
179 let impl_items = impl_id.0.impl_items(self.0.interner.db());
179 let AnyImplId::ImplId(impl_id) = impl_id else {
180 // Builtin derive traits don't have type/consts assoc items.
181 return Ok(None);
182 };
183 let impl_items = impl_id.impl_items(self.0.interner.db());
180184 let id =
181185 match trait_assoc_def_id {
182186 SolverDefId::TypeAliasId(trait_assoc_id) => {
src/tools/rust-analyzer/crates/hir-ty/src/next_solver/ty.rs+23-4
......@@ -26,6 +26,7 @@ use rustc_type_ir::{
2626};
2727
2828use crate::{
29 FnAbi,
2930 db::{HirDatabase, InternedCoroutine},
3031 lower::GenericPredicates,
3132 next_solver::{
......@@ -495,10 +496,9 @@ impl<'db> Ty<'db> {
495496 Some(interner.fn_sig(callable).instantiate(interner, args))
496497 }
497498 TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)),
498 TyKind::Closure(_, closure_args) => closure_args
499 .split_closure_args_untupled()
500 .closure_sig_as_fn_ptr_ty
501 .callable_sig(interner),
499 TyKind::Closure(_, closure_args) => {
500 Some(interner.signature_unclosure(closure_args.as_closure().sig(), Safety::Safe))
501 }
502502 TyKind::CoroutineClosure(coroutine_id, args) => {
503503 Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
504504 let unit_ty = Ty::new_unit(interner);
......@@ -1426,3 +1426,22 @@ impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderTy {
14261426 Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
14271427 }
14281428}
1429
1430impl<'db> DbInterner<'db> {
1431 /// Given a closure signature, returns an equivalent fn signature. Detuples
1432 /// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
1433 /// you would get a `fn(u32, i32)`.
1434 /// `unsafety` determines the unsafety of the fn signature. If you pass
1435 /// `Safety::Unsafe` in the previous example, then you would get
1436 /// an `unsafe fn (u32, i32)`.
1437 /// It cannot convert a closure that requires unsafe.
1438 pub fn signature_unclosure(self, sig: PolyFnSig<'db>, safety: Safety) -> PolyFnSig<'db> {
1439 sig.map_bound(|s| {
1440 let params = match s.inputs()[0].kind() {
1441 TyKind::Tuple(params) => params,
1442 _ => panic!(),
1443 };
1444 self.mk_fn_sig(params, s.output(), s.c_variadic, safety, FnAbi::Rust)
1445 })
1446 }
1447}
src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs+6
......@@ -46,6 +46,12 @@ impl Default for TestDB {
4646 this.set_expand_proc_attr_macros_with_durability(true, Durability::HIGH);
4747 // This needs to be here otherwise `CrateGraphBuilder` panics.
4848 this.set_all_crates(Arc::new(Box::new([])));
49 _ = base_db::LibraryRoots::builder(Default::default())
50 .durability(Durability::MEDIUM)
51 .new(&this);
52 _ = base_db::LocalRoots::builder(Default::default())
53 .durability(Durability::MEDIUM)
54 .new(&this);
4955 CrateGraphBuilder::default().set_in_db(&mut this);
5056 this
5157 }
src/tools/rust-analyzer/crates/hir-ty/src/tests/closure_captures.rs+25
......@@ -503,3 +503,28 @@ fn main() {
503503 expect!["73..149;37..38;103..104 ByValue b Option<Box>"],
504504 );
505505}
506
507#[test]
508fn alias_needs_to_be_normalized() {
509 check_closure_captures(
510 r#"
511//- minicore:copy
512trait Trait {
513 type Associated;
514}
515struct A;
516struct B { x: i32 }
517impl Trait for A {
518 type Associated = B;
519}
520struct C { b: <A as Trait>::Associated }
521fn main() {
522 let c: C = C { b: B { x: 1 } };
523 let closure = || {
524 let _move = c.b.x;
525 };
526}
527"#,
528 expect!["220..257;174..175;245..250 ByRef(Shared) c.b.x &'? i32"],
529 );
530}
src/tools/rust-analyzer/crates/hir-ty/src/tests/incremental.rs+35-5
......@@ -243,6 +243,10 @@ $0",
243243 "parse_shim",
244244 "real_span_map_shim",
245245 "TraitImpls::for_crate_",
246 "lang_items",
247 "crate_lang_items",
248 "AttrFlags::query_",
249 "AttrFlags::query_",
246250 ]
247251 "#]],
248252 );
......@@ -279,6 +283,10 @@ pub struct NewStruct {
279283 "real_span_map_shim",
280284 "crate_local_def_map",
281285 "TraitImpls::for_crate_",
286 "crate_lang_items",
287 "AttrFlags::query_",
288 "AttrFlags::query_",
289 "AttrFlags::query_",
282290 ]
283291 "#]],
284292 );
......@@ -314,6 +322,10 @@ $0",
314322 "parse_shim",
315323 "real_span_map_shim",
316324 "TraitImpls::for_crate_",
325 "lang_items",
326 "crate_lang_items",
327 "AttrFlags::query_",
328 "AttrFlags::query_",
317329 ]
318330 "#]],
319331 );
......@@ -351,6 +363,13 @@ pub enum SomeEnum {
351363 "real_span_map_shim",
352364 "crate_local_def_map",
353365 "TraitImpls::for_crate_",
366 "crate_lang_items",
367 "AttrFlags::query_",
368 "AttrFlags::query_",
369 "AttrFlags::query_",
370 "EnumVariants::of_",
371 "AttrFlags::query_",
372 "AttrFlags::query_",
354373 ]
355374 "#]],
356375 );
......@@ -386,6 +405,10 @@ $0",
386405 "parse_shim",
387406 "real_span_map_shim",
388407 "TraitImpls::for_crate_",
408 "lang_items",
409 "crate_lang_items",
410 "AttrFlags::query_",
411 "AttrFlags::query_",
389412 ]
390413 "#]],
391414 );
......@@ -420,6 +443,9 @@ fn bar() -> f32 {
420443 "real_span_map_shim",
421444 "crate_local_def_map",
422445 "TraitImpls::for_crate_",
446 "crate_lang_items",
447 "AttrFlags::query_",
448 "AttrFlags::query_",
423449 ]
424450 "#]],
425451 );
......@@ -459,6 +485,11 @@ $0",
459485 "parse_shim",
460486 "real_span_map_shim",
461487 "TraitImpls::for_crate_",
488 "lang_items",
489 "crate_lang_items",
490 "AttrFlags::query_",
491 "AttrFlags::query_",
492 "AttrFlags::query_",
462493 ]
463494 "#]],
464495 );
......@@ -501,17 +532,16 @@ impl SomeStruct {
501532 "real_span_map_shim",
502533 "crate_local_def_map",
503534 "TraitImpls::for_crate_",
504 "AttrFlags::query_",
505 "impl_trait_with_diagnostics_query",
506 "impl_signature_shim",
507 "impl_signature_with_source_map_shim",
508 "lang_items",
509535 "crate_lang_items",
536 "AttrFlags::query_",
510537 "ImplItems::of_",
511538 "AttrFlags::query_",
512539 "AttrFlags::query_",
513540 "AttrFlags::query_",
514541 "AttrFlags::query_",
542 "impl_trait_with_diagnostics_query",
543 "impl_signature_shim",
544 "impl_signature_with_source_map_shim",
515545 "impl_self_ty_with_diagnostics_query",
516546 "struct_signature_shim",
517547 "struct_signature_with_source_map_shim",
src/tools/rust-analyzer/crates/hir-ty/src/tests/simple.rs+23
......@@ -1,5 +1,7 @@
11use expect_test::expect;
22
3use crate::tests::check_infer_with_mismatches;
4
35use super::{check, check_infer, check_no_mismatches, check_types};
46
57#[test]
......@@ -3956,3 +3958,24 @@ fn bar() {
39563958 "#,
39573959 );
39583960}
3961
3962#[test]
3963fn cannot_coerce_capturing_closure_to_fn_ptr() {
3964 check_infer_with_mismatches(
3965 r#"
3966fn foo() {
3967 let a = 1;
3968 let _: fn() -> i32 = || a;
3969}
3970 "#,
3971 expect![[r#"
3972 9..58 '{ ...| a; }': ()
3973 19..20 'a': i32
3974 23..24 '1': i32
3975 34..35 '_': fn() -> i32
3976 51..55 '|| a': impl Fn() -> i32
3977 54..55 'a': i32
3978 51..55: expected fn() -> i32, got impl Fn() -> i32
3979 "#]],
3980 );
3981}
src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs+12-12
......@@ -851,7 +851,7 @@ struct S;
851851trait Trait<T> {}
852852impl Trait<&str> for S {}
853853
854struct O<T>;
854struct O<T>(T);
855855impl<U, T: Trait<U>> O<T> {
856856 fn foo(&self) -> U { loop {} }
857857}
......@@ -1492,7 +1492,7 @@ fn dyn_trait_in_impl() {
14921492trait Trait<T, U> {
14931493 fn foo(&self) -> (T, U);
14941494}
1495struct S<T, U> {}
1495struct S<T, U>(T, U);
14961496impl<T, U> S<T, U> {
14971497 fn bar(&self) -> &dyn Trait<T, U> { loop {} }
14981498}
......@@ -1506,16 +1506,16 @@ fn test(s: S<u32, i32>) {
15061506}"#,
15071507 expect![[r#"
15081508 32..36 'self': &'? Self
1509 102..106 'self': &'? S<T, U>
1510 128..139 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
1511 130..137 'loop {}': !
1512 135..137 '{}': ()
1513 175..179 'self': &'? Self
1514 251..252 's': S<u32, i32>
1515 267..289 '{ ...z(); }': ()
1516 273..274 's': S<u32, i32>
1517 273..280 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
1518 273..286 's.bar().baz()': (u32, i32)
1509 106..110 'self': &'? S<T, U>
1510 132..143 '{ loop {} }': &'? (dyn Trait<T, U> + 'static)
1511 134..141 'loop {}': !
1512 139..141 '{}': ()
1513 179..183 'self': &'? Self
1514 255..256 's': S<u32, i32>
1515 271..293 '{ ...z(); }': ()
1516 277..278 's': S<u32, i32>
1517 277..284 's.bar()': &'? (dyn Trait<u32, i32> + 'static)
1518 277..290 's.bar().baz()': (u32, i32)
15191519 "#]],
15201520 );
15211521}
src/tools/rust-analyzer/crates/hir-ty/src/upvars.rs created+319
......@@ -0,0 +1,319 @@
1//! A simple query to collect tall locals (upvars) a closure use.
2
3use hir_def::{
4 DefWithBodyId,
5 expr_store::{Body, path::Path},
6 hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
7 resolver::{HasResolver, Resolver, ValueNs},
8};
9use hir_expand::mod_path::PathKind;
10use rustc_hash::{FxHashMap, FxHashSet};
11
12use crate::db::HirDatabase;
13
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15// Kept sorted.
16pub struct Upvars(Box<[BindingId]>);
17
18impl Upvars {
19 fn new(upvars: &FxHashSet<BindingId>) -> Upvars {
20 let mut upvars = upvars.iter().copied().collect::<Box<[_]>>();
21 upvars.sort_unstable();
22 Upvars(upvars)
23 }
24
25 #[inline]
26 pub fn contains(&self, local: BindingId) -> bool {
27 self.0.binary_search(&local).is_ok()
28 }
29
30 #[inline]
31 pub fn iter(&self) -> impl ExactSizeIterator<Item = BindingId> {
32 self.0.iter().copied()
33 }
34
35 #[inline]
36 pub fn is_empty(&self) -> bool {
37 self.0.is_empty()
38 }
39}
40
41/// Returns a map from `Expr::Closure` to its upvars.
42#[salsa::tracked(returns(as_deref))]
43pub fn upvars_mentioned(
44 db: &dyn HirDatabase,
45 owner: DefWithBodyId,
46) -> Option<Box<FxHashMap<ExprId, Upvars>>> {
47 let body = db.body(owner);
48 let mut resolver = owner.resolver(db);
49 let mut result = FxHashMap::default();
50 handle_expr_outside_closure(db, &mut resolver, owner, &body, body.body_expr, &mut result);
51 return if result.is_empty() {
52 None
53 } else {
54 result.shrink_to_fit();
55 Some(Box::new(result))
56 };
57
58 fn handle_expr_outside_closure<'db>(
59 db: &'db dyn HirDatabase,
60 resolver: &mut Resolver<'db>,
61 owner: DefWithBodyId,
62 body: &Body,
63 expr: ExprId,
64 closures_map: &mut FxHashMap<ExprId, Upvars>,
65 ) {
66 match &body[expr] {
67 &Expr::Closure { body: body_expr, .. } => {
68 let mut upvars = FxHashSet::default();
69 handle_expr_inside_closure(
70 db,
71 resolver,
72 owner,
73 body,
74 expr,
75 body_expr,
76 &mut upvars,
77 closures_map,
78 );
79 if !upvars.is_empty() {
80 closures_map.insert(expr, Upvars::new(&upvars));
81 }
82 }
83 _ => body.walk_child_exprs(expr, |expr| {
84 handle_expr_outside_closure(db, resolver, owner, body, expr, closures_map)
85 }),
86 }
87 }
88
89 fn handle_expr_inside_closure<'db>(
90 db: &'db dyn HirDatabase,
91 resolver: &mut Resolver<'db>,
92 owner: DefWithBodyId,
93 body: &Body,
94 current_closure: ExprId,
95 expr: ExprId,
96 upvars: &mut FxHashSet<BindingId>,
97 closures_map: &mut FxHashMap<ExprId, Upvars>,
98 ) {
99 match &body[expr] {
100 Expr::Path(path) => {
101 resolve_maybe_upvar(
102 db,
103 resolver,
104 owner,
105 body,
106 current_closure,
107 expr,
108 expr.into(),
109 upvars,
110 path,
111 );
112 }
113 &Expr::Assignment { target, .. } => {
114 body.walk_pats(target, &mut |pat| {
115 let Pat::Path(path) = &body[pat] else { return };
116 resolve_maybe_upvar(
117 db,
118 resolver,
119 owner,
120 body,
121 current_closure,
122 expr,
123 pat.into(),
124 upvars,
125 path,
126 );
127 });
128 }
129 &Expr::Closure { body: body_expr, .. } => {
130 let mut closure_upvars = FxHashSet::default();
131 handle_expr_inside_closure(
132 db,
133 resolver,
134 owner,
135 body,
136 expr,
137 body_expr,
138 &mut closure_upvars,
139 closures_map,
140 );
141 if !closure_upvars.is_empty() {
142 closures_map.insert(expr, Upvars::new(&closure_upvars));
143 // All nested closure's upvars are also upvars of the parent closure.
144 upvars.extend(
145 closure_upvars
146 .iter()
147 .copied()
148 .filter(|local| body.binding_owner(*local) != Some(current_closure)),
149 );
150 }
151 return;
152 }
153 _ => {}
154 }
155 body.walk_child_exprs(expr, |expr| {
156 handle_expr_inside_closure(
157 db,
158 resolver,
159 owner,
160 body,
161 current_closure,
162 expr,
163 upvars,
164 closures_map,
165 )
166 });
167 }
168}
169
170fn resolve_maybe_upvar<'db>(
171 db: &'db dyn HirDatabase,
172 resolver: &mut Resolver<'db>,
173 owner: DefWithBodyId,
174 body: &Body,
175 current_closure: ExprId,
176 expr: ExprId,
177 id: ExprOrPatId,
178 upvars: &mut FxHashSet<BindingId>,
179 path: &Path,
180) {
181 if let Path::BarePath(mod_path) = path
182 && matches!(mod_path.kind, PathKind::Plain)
183 && mod_path.segments().len() == 1
184 {
185 // Could be a variable.
186 let guard = resolver.update_to_inner_scope(db, owner, expr);
187 let resolution =
188 resolver.resolve_path_in_value_ns_fully(db, path, body.expr_or_pat_path_hygiene(id));
189 if let Some(ValueNs::LocalBinding(local)) = resolution
190 && body.binding_owner(local) != Some(current_closure)
191 {
192 upvars.insert(local);
193 }
194 resolver.reset_to_guard(guard);
195 }
196}
197
198#[cfg(test)]
199mod tests {
200 use expect_test::{Expect, expect};
201 use hir_def::{ModuleDefId, db::DefDatabase, nameres::crate_def_map};
202 use itertools::Itertools;
203 use span::Edition;
204 use test_fixture::WithFixture;
205
206 use crate::{test_db::TestDB, upvars::upvars_mentioned};
207
208 #[track_caller]
209 fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expectation: Expect) {
210 let db = TestDB::with_files(ra_fixture);
211 crate::attach_db(&db, || {
212 let def_map = crate_def_map(&db, db.test_crate());
213 let func = def_map
214 .modules()
215 .flat_map(|(_, module)| module.scope.declarations())
216 .filter_map(|decl| match decl {
217 ModuleDefId::FunctionId(func) => Some(func),
218 _ => None,
219 })
220 .exactly_one()
221 .unwrap_or_else(|_| panic!("expected one function"));
222 let (body, source_map) = db.body_with_source_map(func.into());
223 let Some(upvars) = upvars_mentioned(&db, func.into()) else {
224 expectation.assert_eq("");
225 return;
226 };
227 let mut closures = Vec::new();
228 for (&closure, upvars) in upvars {
229 let closure_range = source_map.expr_syntax(closure).unwrap().value.text_range();
230 let upvars = upvars
231 .iter()
232 .map(|local| body[local].name.display(&db, Edition::CURRENT))
233 .join(", ");
234 closures.push((closure_range, upvars));
235 }
236 closures.sort_unstable_by_key(|(range, _)| (range.start(), range.end()));
237 let closures = closures
238 .into_iter()
239 .map(|(range, upvars)| format!("{range:?}: {upvars}"))
240 .join("\n");
241 expectation.assert_eq(&closures);
242 });
243 }
244
245 #[test]
246 fn simple() {
247 check(
248 r#"
249struct foo;
250fn foo(param: i32) {
251 let local = "boo";
252 || { param; foo };
253 || local;
254 || { param; local; param; local; };
255 || 0xDEAFBEAF;
256}
257 "#,
258 expect![[r#"
259 60..77: param
260 83..91: local
261 97..131: param, local"#]],
262 );
263 }
264
265 #[test]
266 fn nested() {
267 check(
268 r#"
269fn foo() {
270 let (a, b);
271 || {
272 || a;
273 || b;
274 };
275}
276 "#,
277 expect![[r#"
278 31..69: a, b
279 44..48: a
280 58..62: b"#]],
281 );
282 }
283
284 #[test]
285 fn closure_var() {
286 check(
287 r#"
288fn foo() {
289 let upvar = 1;
290 |closure_param: i32| {
291 let closure_local = closure_param;
292 closure_local + upvar
293 };
294}
295 "#,
296 expect!["34..135: upvar"],
297 );
298 }
299
300 #[test]
301 fn closure_var_nested() {
302 check(
303 r#"
304fn foo() {
305 let a = 1;
306 |b: i32| {
307 || {
308 let c = 123;
309 a + b + c
310 }
311 };
312}
313 "#,
314 expect![[r#"
315 30..116: a
316 49..110: a, b"#]],
317 );
318 }
319}
src/tools/rust-analyzer/crates/hir-ty/src/variance.rs+31-48
......@@ -36,9 +36,8 @@ pub(crate) fn variances_of(db: &dyn HirDatabase, def: GenericDefId) -> Variances
3636
3737#[salsa::tracked(
3838 returns(ref),
39 // cycle_fn = crate::variance::variances_of_cycle_fn,
40 // cycle_initial = crate::variance::variances_of_cycle_initial,
41 cycle_result = crate::variance::variances_of_cycle_initial,
39 cycle_fn = crate::variance::variances_of_cycle_fn,
40 cycle_initial = crate::variance::variances_of_cycle_initial,
4241)]
4342fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariancesOf {
4443 tracing::debug!("variances_of(def={:?})", def);
......@@ -64,35 +63,20 @@ fn variances_of_query(db: &dyn HirDatabase, def: GenericDefId) -> StoredVariance
6463 if count == 0 {
6564 return VariancesOf::empty(interner).store();
6665 }
67 let mut variances =
68 Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
69
70 // FIXME(next-solver): This is *not* the correct behavior. I don't know if it has an actual effect,
71 // since bivariance is prohibited in Rust, but rustc definitely does not fallback bivariance.
72 // So why do we do this? Because, with the new solver, the effects of bivariance are catastrophic:
73 // it leads to not relating types properly, and to very, very hard to debug bugs (speaking from experience).
74 // Furthermore, our variance infra is known to not handle cycles properly. Therefore, at least until we fix
75 // cycles, and perhaps forever at least for out tests, not allowing bivariance makes sense.
76 // Why specifically invariance? I don't have a strong reason, mainly that invariance is a stronger relationship
77 // (therefore, less room for mistakes) and that IMO incorrect covariance can be more problematic that incorrect
78 // bivariance, at least while we don't handle lifetimes anyway.
79 for variance in &mut variances {
80 if *variance == Variance::Bivariant {
81 *variance = Variance::Invariant;
82 }
83 }
66 let variances = Context { generics, variances: vec![Variance::Bivariant; count], db }.solve();
8467
8568 VariancesOf::new_from_slice(&variances).store()
8669}
8770
88// pub(crate) fn variances_of_cycle_fn(
89// _db: &dyn HirDatabase,
90// _result: &Option<Arc<[Variance]>>,
91// _count: u32,
92// _def: GenericDefId,
93// ) -> salsa::CycleRecoveryAction<Option<Arc<[Variance]>>> {
94// salsa::CycleRecoveryAction::Iterate
95// }
71pub(crate) fn variances_of_cycle_fn(
72 _db: &dyn HirDatabase,
73 _: &salsa::Cycle<'_>,
74 _last_provisional_value: &StoredVariancesOf,
75 value: StoredVariancesOf,
76 _def: GenericDefId,
77) -> StoredVariancesOf {
78 value
79}
9680
9781fn glb(v1: Variance, v2: Variance) -> Variance {
9882 // Greatest lower bound of the variance lattice as defined in The Paper:
......@@ -123,8 +107,7 @@ pub(crate) fn variances_of_cycle_initial(
123107 let generics = generics(db, def);
124108 let count = generics.len();
125109
126 // FIXME(next-solver): Returns `Invariance` and not `Bivariance` here, see the comment in the main query.
127 VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Invariant, count)).store()
110 VariancesOf::new_from_iter(interner, std::iter::repeat_n(Variance::Bivariant, count)).store()
128111}
129112
130113struct Context<'db> {
......@@ -484,8 +467,8 @@ struct Other<'a> {
484467}
485468"#,
486469 expect![[r#"
487 Hello['a: invariant]
488 Other['a: invariant]
470 Hello['a: bivariant]
471 Other['a: bivariant]
489472 "#]],
490473 );
491474 }
......@@ -504,7 +487,7 @@ struct Foo<T: Trait> { //~ ERROR [T: o]
504487}
505488"#,
506489 expect![[r#"
507 Foo[T: invariant]
490 Foo[T: bivariant]
508491 "#]],
509492 );
510493 }
......@@ -586,9 +569,9 @@ struct TestBox<U,T:Getter<U>+Setter<U>> { //~ ERROR [U: *, T: +]
586569 get[Self: contravariant, T: covariant]
587570 get[Self: contravariant, T: contravariant]
588571 TestStruct[U: covariant, T: covariant]
589 TestEnum[U: invariant, T: covariant]
590 TestContraStruct[U: invariant, T: covariant]
591 TestBox[U: invariant, T: covariant]
572 TestEnum[U: bivariant, T: covariant]
573 TestContraStruct[U: bivariant, T: covariant]
574 TestBox[U: bivariant, T: covariant]
592575 "#]],
593576 );
594577 }
......@@ -708,8 +691,8 @@ enum SomeEnum<'a> { Nothing } //~ ERROR parameter `'a` is never used
708691trait SomeTrait<'a> { fn foo(&self); } // OK on traits.
709692"#,
710693 expect![[r#"
711 SomeStruct['a: invariant]
712 SomeEnum['a: invariant]
694 SomeStruct['a: bivariant]
695 SomeEnum['a: bivariant]
713696 foo[Self: contravariant, 'a: invariant]
714697 "#]],
715698 );
......@@ -737,14 +720,14 @@ struct DoubleNothing<T> {
737720
738721"#,
739722 expect![[r#"
740 SomeStruct[A: invariant]
741 SomeEnum[A: invariant]
742 ListCell[T: invariant]
743 SelfTyAlias[T: invariant]
744 WithBounds[T: invariant]
745 WithWhereBounds[T: invariant]
746 WithOutlivesBounds[T: invariant]
747 DoubleNothing[T: invariant]
723 SomeStruct[A: bivariant]
724 SomeEnum[A: bivariant]
725 ListCell[T: bivariant]
726 SelfTyAlias[T: bivariant]
727 WithBounds[T: bivariant]
728 WithWhereBounds[T: bivariant]
729 WithOutlivesBounds[T: bivariant]
730 DoubleNothing[T: bivariant]
748731 "#]],
749732 );
750733 }
......@@ -855,7 +838,7 @@ struct S3<T>(S<T, T>);
855838"#,
856839 expect![[r#"
857840 S[T: covariant]
858 S2[T: invariant]
841 S2[T: bivariant]
859842 S3[T: covariant]
860843 "#]],
861844 );
......@@ -868,7 +851,7 @@ struct S3<T>(S<T, T>);
868851struct FixedPoint<T, U, V>(&'static FixedPoint<(), T, U>, V);
869852"#,
870853 expect![[r#"
871 FixedPoint[T: invariant, U: invariant, V: invariant]
854 FixedPoint[T: covariant, U: covariant, V: covariant]
872855 "#]],
873856 );
874857 }
src/tools/rust-analyzer/crates/hir/src/attrs.rs+38-7
......@@ -35,6 +35,8 @@ pub enum AttrsOwner {
3535 Field(FieldId),
3636 LifetimeParam(LifetimeParamId),
3737 TypeOrConstParam(TypeOrConstParamId),
38 /// Things that do not have attributes. Used for builtin derives.
39 Dummy,
3840}
3941
4042impl AttrsOwner {
......@@ -123,7 +125,9 @@ impl AttrsWithOwner {
123125 let owner = match self.owner {
124126 AttrsOwner::AttrDef(it) => Either::Left(it),
125127 AttrsOwner::Field(it) => Either::Right(it),
126 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return &[],
128 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
129 return &[];
130 }
127131 };
128132 self.attrs.doc_aliases(db, owner)
129133 }
......@@ -133,7 +137,9 @@ impl AttrsWithOwner {
133137 let owner = match self.owner {
134138 AttrsOwner::AttrDef(it) => Either::Left(it),
135139 AttrsOwner::Field(it) => Either::Right(it),
136 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None,
140 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
141 return None;
142 }
137143 };
138144 self.attrs.cfgs(db, owner)
139145 }
......@@ -143,7 +149,9 @@ impl AttrsWithOwner {
143149 match self.owner {
144150 AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(),
145151 AttrsOwner::Field(it) => AttrFlags::field_docs(db, it),
146 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None,
152 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
153 None
154 }
147155 }
148156 }
149157}
......@@ -156,6 +164,9 @@ pub trait HasAttrs: Sized {
156164 AttrsOwner::Field(it) => AttrsWithOwner::new_field(db, it),
157165 AttrsOwner::LifetimeParam(it) => AttrsWithOwner::new_lifetime_param(db, it),
158166 AttrsOwner::TypeOrConstParam(it) => AttrsWithOwner::new_type_or_const_param(db, it),
167 AttrsOwner::Dummy => {
168 AttrsWithOwner { attrs: AttrFlags::empty(), owner: AttrsOwner::Dummy }
169 }
159170 }
160171 }
161172
......@@ -167,7 +178,9 @@ pub trait HasAttrs: Sized {
167178 match self.attr_id(db) {
168179 AttrsOwner::AttrDef(it) => AttrFlags::docs(db, it).as_deref(),
169180 AttrsOwner::Field(it) => AttrFlags::field_docs(db, it),
170 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => None,
181 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
182 None
183 }
171184 }
172185 }
173186}
......@@ -190,12 +203,28 @@ impl_has_attrs![
190203 (Trait, TraitId),
191204 (TypeAlias, TypeAliasId),
192205 (Macro, MacroId),
193 (Function, FunctionId),
194206 (Adt, AdtId),
195 (Impl, ImplId),
196207 (ExternCrateDecl, ExternCrateId),
197208];
198209
210impl HasAttrs for Function {
211 fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner {
212 match self.id {
213 crate::AnyFunctionId::FunctionId(id) => AttrsOwner::AttrDef(id.into()),
214 crate::AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrsOwner::Dummy,
215 }
216 }
217}
218
219impl HasAttrs for Impl {
220 fn attr_id(self, _db: &dyn HirDatabase) -> AttrsOwner {
221 match self.id {
222 hir_ty::next_solver::AnyImplId::ImplId(id) => AttrsOwner::AttrDef(id.into()),
223 hir_ty::next_solver::AnyImplId::BuiltinDeriveImplId(..) => AttrsOwner::Dummy,
224 }
225 }
226}
227
199228macro_rules! impl_has_attrs_enum {
200229 ($($variant:ident),* for $enum:ident) => {$(
201230 impl HasAttrs for $variant {
......@@ -294,7 +323,9 @@ fn resolve_doc_path_on_(
294323 AttrsOwner::AttrDef(AttrDefId::MacroId(it)) => it.resolver(db),
295324 AttrsOwner::AttrDef(AttrDefId::ExternCrateId(it)) => it.resolver(db),
296325 AttrsOwner::Field(it) => it.parent.resolver(db),
297 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) => return None,
326 AttrsOwner::LifetimeParam(_) | AttrsOwner::TypeOrConstParam(_) | AttrsOwner::Dummy => {
327 return None;
328 }
298329 };
299330
300331 let mut modpath = doc_modpath_from_str(link)?;
src/tools/rust-analyzer/crates/hir/src/display.rs+218-125
......@@ -2,19 +2,22 @@
22
33use either::Either;
44use hir_def::{
5 AdtId, GenericDefId,
5 AdtId, BuiltinDeriveImplId, FunctionId, GenericDefId, ImplId, ItemContainerId,
6 builtin_derive::BuiltinDeriveImplMethod,
67 expr_store::ExpressionStore,
78 hir::generics::{GenericParams, TypeOrConstParamData, TypeParamProvenance, WherePredicate},
89 item_tree::FieldsShape,
910 signatures::{StaticFlags, TraitFlags},
1011 type_ref::{TypeBound, TypeRef, TypeRefId},
1112};
13use hir_expand::name::Name;
1214use hir_ty::{
1315 GenericPredicates,
1416 db::HirDatabase,
1517 display::{
1618 HirDisplay, HirDisplayWithExpressionStore, HirFormatter, Result, SizedByDefault,
17 hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_visibility,
19 hir_display_with_store, write_bounds_like_dyn_trait_with_prefix, write_params_bounds,
20 write_visibility,
1821 },
1922 next_solver::ClauseKind,
2023};
......@@ -22,25 +25,78 @@ use itertools::Itertools;
2225use rustc_type_ir::inherent::IntoKind;
2326
2427use crate::{
25 Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
28 Adt, AnyFunctionId, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Crate, Enum,
2629 ExternCrateDecl, Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam,
2730 Macro, Module, SelfParam, Static, Struct, StructKind, Trait, TraitRef, TupleField, Type,
2831 TypeAlias, TypeNs, TypeOrConstParam, TypeParam, Union, Variant,
2932};
3033
34fn write_builtin_derive_impl_method<'db>(
35 f: &mut HirFormatter<'_, 'db>,
36 impl_: BuiltinDeriveImplId,
37 method: BuiltinDeriveImplMethod,
38) -> Result {
39 let db = f.db;
40 let loc = impl_.loc(db);
41 let (adt_params, _adt_params_store) = db.generic_params_and_store(loc.adt.into());
42
43 if f.show_container_bounds() && !adt_params.is_empty() {
44 f.write_str("impl")?;
45 write_generic_params(loc.adt.into(), f)?;
46 f.write_char(' ')?;
47 let trait_id = loc.trait_.get_id(f.lang_items());
48 if let Some(trait_id) = trait_id {
49 f.start_location_link(trait_id.into());
50 }
51 write!(f, "{}", Name::new_symbol_root(loc.trait_.name()).display(db, f.edition()))?;
52 if trait_id.is_some() {
53 f.end_location_link();
54 }
55 f.write_str(" for ")?;
56 f.start_location_link(loc.adt.into());
57 write!(f, "{}", Adt::from(loc.adt).name(db).display(db, f.edition()))?;
58 f.end_location_link();
59 write_generic_args(loc.adt.into(), f)?;
60 f.write_char('\n')?;
61 }
62
63 let Some(trait_method) = method.trait_method(db, impl_) else {
64 return write!(f, "fn {}(…)", method.name());
65 };
66 let has_written_where = write_function(f, trait_method)?;
67
68 if f.show_container_bounds() && !adt_params.is_empty() {
69 if !has_written_where {
70 f.write_str("\nwhere")?
71 }
72 write!(f, "\n // Bounds from impl:")?;
73
74 let predicates =
75 hir_ty::builtin_derive::predicates(db, impl_).explicit_predicates().skip_binder();
76 write_params_bounds(f, predicates)?;
77 }
78
79 Ok(())
80}
81
3182impl<'db> HirDisplay<'db> for Function {
3283 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
84 let id = match self.id {
85 AnyFunctionId::FunctionId(id) => id,
86 AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
87 return write_builtin_derive_impl_method(f, impl_, method);
88 }
89 };
90
3391 let db = f.db;
34 let data = db.function_signature(self.id);
35 let container = self.as_assoc_item(db).map(|it| it.container(db));
36 let mut module = self.module(db);
92 let container = id.loc(db).container;
3793
3894 // Write container (trait or impl)
3995 let container_params = match container {
40 Some(AssocItemContainer::Trait(trait_)) => {
41 let (params, params_store) = f.db.generic_params_and_store(trait_.id.into());
96 ItemContainerId::TraitId(trait_) => {
97 let (params, params_store) = f.db.generic_params_and_store(trait_.into());
4298 if f.show_container_bounds() && !params.is_empty() {
43 write_trait_header(&trait_, f)?;
99 write_trait_header(trait_.into(), f)?;
44100 f.write_char('\n')?;
45101 has_disaplayable_predicates(f.db, &params, &params_store)
46102 .then_some((params, params_store))
......@@ -48,10 +104,10 @@ impl<'db> HirDisplay<'db> for Function {
48104 None
49105 }
50106 }
51 Some(AssocItemContainer::Impl(impl_)) => {
52 let (params, params_store) = f.db.generic_params_and_store(impl_.id.into());
107 ItemContainerId::ImplId(impl_) => {
108 let (params, params_store) = f.db.generic_params_and_store(impl_.into());
53109 if f.show_container_bounds() && !params.is_empty() {
54 write_impl_header(&impl_, f)?;
110 write_impl_header(impl_, f)?;
55111 f.write_char('\n')?;
56112 has_disaplayable_predicates(f.db, &params, &params_store)
57113 .then_some((params, params_store))
......@@ -59,140 +115,151 @@ impl<'db> HirDisplay<'db> for Function {
59115 None
60116 }
61117 }
62 None => None,
118 _ => None,
63119 };
64120
65121 // Write signature of the function
66122
67 // Block-local impls are "hoisted" to the nearest (non-block) module.
68 if let Some(AssocItemContainer::Impl(_)) = container {
69 module = module.nearest_non_block_module(db);
123 let has_written_where = write_function(f, id)?;
124 if let Some((container_params, container_params_store)) = container_params {
125 if !has_written_where {
126 f.write_str("\nwhere")?;
127 }
128 let container_name = match container {
129 ItemContainerId::TraitId(_) => "trait",
130 ItemContainerId::ImplId(_) => "impl",
131 _ => unreachable!(),
132 };
133 write!(f, "\n // Bounds from {container_name}:",)?;
134 write_where_predicates(&container_params, &container_params_store, f)?;
70135 }
71 let module_id = module.id;
72
73 write_visibility(module_id, self.visibility(db), f)?;
136 Ok(())
137 }
138}
74139
75 if data.is_default() {
76 f.write_str("default ")?;
77 }
78 if data.is_const() {
79 f.write_str("const ")?;
80 }
81 if data.is_async() {
82 f.write_str("async ")?;
83 }
84 // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
85 // (they are conditionally unsafe to call). We probably should show something else.
86 if self.is_unsafe_to_call(db, None, f.edition()) {
87 f.write_str("unsafe ")?;
88 }
89 if let Some(abi) = &data.abi {
90 write!(f, "extern \"{}\" ", abi.as_str())?;
91 }
92 write!(f, "fn {}", data.name.display(f.db, f.edition()))?;
140fn write_function<'db>(f: &mut HirFormatter<'_, 'db>, func_id: FunctionId) -> Result<bool> {
141 let db = f.db;
142 let func = Function::from(func_id);
143 let data = db.function_signature(func_id);
93144
94 write_generic_params(GenericDefId::FunctionId(self.id), f)?;
145 let mut module = func.module(db);
146 // Block-local impls are "hoisted" to the nearest (non-block) module.
147 if let ItemContainerId::ImplId(_) = func_id.loc(db).container {
148 module = module.nearest_non_block_module(db);
149 }
150 let module_id = module.id;
95151
96 f.write_char('(')?;
152 write_visibility(module_id, func.visibility(db), f)?;
97153
98 let mut first = true;
99 let mut skip_self = 0;
100 if let Some(self_param) = self.self_param(db) {
101 self_param.hir_fmt(f)?;
102 first = false;
103 skip_self = 1;
104 }
154 if data.is_default() {
155 f.write_str("default ")?;
156 }
157 if data.is_const() {
158 f.write_str("const ")?;
159 }
160 if data.is_async() {
161 f.write_str("async ")?;
162 }
163 // FIXME: This will show `unsafe` for functions that are `#[target_feature]` but not unsafe
164 // (they are conditionally unsafe to call). We probably should show something else.
165 if func.is_unsafe_to_call(db, None, f.edition()) {
166 f.write_str("unsafe ")?;
167 }
168 if let Some(abi) = &data.abi {
169 write!(f, "extern \"{}\" ", abi.as_str())?;
170 }
171 write!(f, "fn {}", data.name.display(f.db, f.edition()))?;
105172
106 // FIXME: Use resolved `param.ty` once we no longer discard lifetimes
107 let body = db.body(self.id.into());
108 for (type_ref, param) in data.params.iter().zip(self.assoc_fn_params(db)).skip(skip_self) {
109 if !first {
110 f.write_str(", ")?;
111 } else {
112 first = false;
113 }
173 write_generic_params(GenericDefId::FunctionId(func_id), f)?;
114174
115 let pat_id = body.params[param.idx - body.self_param.is_some() as usize];
116 let pat_str = body.pretty_print_pat(db, self.id.into(), pat_id, true, f.edition());
117 f.write_str(&pat_str)?;
175 f.write_char('(')?;
118176
119 f.write_str(": ")?;
120 type_ref.hir_fmt(f, &data.store)?;
177 let mut first = true;
178 let mut skip_self = 0;
179 if let Some(self_param) = func.self_param(db) {
180 self_param.hir_fmt(f)?;
181 first = false;
182 skip_self = 1;
183 }
184
185 // FIXME: Use resolved `param.ty` once we no longer discard lifetimes
186 let body = db.body(func_id.into());
187 for (type_ref, param) in data.params.iter().zip(func.assoc_fn_params(db)).skip(skip_self) {
188 if !first {
189 f.write_str(", ")?;
190 } else {
191 first = false;
121192 }
122193
123 if data.is_varargs() {
124 if !first {
125 f.write_str(", ")?;
126 }
127 f.write_str("...")?;
128 }
129
130 f.write_char(')')?;
131
132 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
133 // Use ugly pattern match to strip the Future trait.
134 // Better way?
135 let ret_type = if !data.is_async() {
136 data.ret_type
137 } else if let Some(ret_type) = data.ret_type {
138 match &data.store[ret_type] {
139 TypeRef::ImplTrait(bounds) => match &bounds[0] {
140 &TypeBound::Path(path, _) => Some(
141 *data.store[path]
142 .segments()
143 .iter()
144 .last()
145 .unwrap()
146 .args_and_bindings
147 .unwrap()
148 .bindings[0]
149 .type_ref
150 .as_ref()
151 .unwrap(),
152 ),
153 _ => None,
154 },
194 let pat_id = body.params[param.idx - body.self_param.is_some() as usize];
195 let pat_str = body.pretty_print_pat(db, func_id.into(), pat_id, true, f.edition());
196 f.write_str(&pat_str)?;
197
198 f.write_str(": ")?;
199 type_ref.hir_fmt(f, &data.store)?;
200 }
201
202 if data.is_varargs() {
203 if !first {
204 f.write_str(", ")?;
205 }
206 f.write_str("...")?;
207 }
208
209 f.write_char(')')?;
210
211 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
212 // Use ugly pattern match to strip the Future trait.
213 // Better way?
214 let ret_type = if !data.is_async() {
215 data.ret_type
216 } else if let Some(ret_type) = data.ret_type {
217 match &data.store[ret_type] {
218 TypeRef::ImplTrait(bounds) => match &bounds[0] {
219 &TypeBound::Path(path, _) => Some(
220 *data.store[path]
221 .segments()
222 .iter()
223 .last()
224 .unwrap()
225 .args_and_bindings
226 .unwrap()
227 .bindings[0]
228 .type_ref
229 .as_ref()
230 .unwrap(),
231 ),
155232 _ => None,
156 }
157 } else {
158 None
159 };
160
161 if let Some(ret_type) = ret_type {
162 match &data.store[ret_type] {
163 TypeRef::Tuple(tup) if tup.is_empty() => {}
164 _ => {
165 f.write_str(" -> ")?;
166 ret_type.hir_fmt(f, &data.store)?;
167 }
168 }
233 },
234 _ => None,
169235 }
236 } else {
237 None
238 };
170239
171 // Write where clauses
172 let has_written_where = write_where_clause(GenericDefId::FunctionId(self.id), f)?;
173 if let Some((container_params, container_params_store)) = container_params {
174 if !has_written_where {
175 f.write_str("\nwhere")?;
240 if let Some(ret_type) = ret_type {
241 match &data.store[ret_type] {
242 TypeRef::Tuple(tup) if tup.is_empty() => {}
243 _ => {
244 f.write_str(" -> ")?;
245 ret_type.hir_fmt(f, &data.store)?;
176246 }
177 let container_name = match container.unwrap() {
178 AssocItemContainer::Trait(_) => "trait",
179 AssocItemContainer::Impl(_) => "impl",
180 };
181 write!(f, "\n // Bounds from {container_name}:",)?;
182 write_where_predicates(&container_params, &container_params_store, f)?;
183247 }
184 Ok(())
185248 }
249
250 // Write where clauses
251 let has_written_where = write_where_clause(GenericDefId::FunctionId(func_id), f)?;
252 Ok(has_written_where)
186253}
187254
188fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result {
255fn write_impl_header<'db>(impl_: ImplId, f: &mut HirFormatter<'_, 'db>) -> Result {
189256 let db = f.db;
190257
191258 f.write_str("impl")?;
192 let def_id = GenericDefId::ImplId(impl_.id);
259 let def_id = GenericDefId::ImplId(impl_);
193260 write_generic_params(def_id, f)?;
194261
195 let impl_data = db.impl_signature(impl_.id);
262 let impl_data = db.impl_signature(impl_);
196263 if let Some(target_trait) = &impl_data.target_trait {
197264 f.write_char(' ')?;
198265 hir_display_with_store(&impl_data.store[target_trait.path], &impl_data.store).hir_fmt(f)?;
......@@ -200,14 +267,28 @@ fn write_impl_header<'db>(impl_: &Impl, f: &mut HirFormatter<'_, 'db>) -> Result
200267 }
201268
202269 f.write_char(' ')?;
203 impl_.self_ty(db).hir_fmt(f)?;
270 Impl::from(impl_).self_ty(db).hir_fmt(f)?;
204271
205272 Ok(())
206273}
207274
208275impl<'db> HirDisplay<'db> for SelfParam {
209276 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
210 let data = f.db.function_signature(self.func);
277 let func = match self.func.id {
278 AnyFunctionId::FunctionId(id) => id,
279 AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
280 BuiltinDeriveImplMethod::clone
281 | BuiltinDeriveImplMethod::fmt
282 | BuiltinDeriveImplMethod::hash
283 | BuiltinDeriveImplMethod::cmp
284 | BuiltinDeriveImplMethod::partial_cmp
285 | BuiltinDeriveImplMethod::eq => return f.write_str("&self"),
286 BuiltinDeriveImplMethod::default => {
287 unreachable!("this trait method does not have a self param")
288 }
289 },
290 };
291 let data = f.db.function_signature(func);
211292 let param = *data.params.first().unwrap();
212293 match &data.store[param] {
213294 TypeRef::Path(p) if p.is_self_type() => f.write_str("self"),
......@@ -553,6 +634,18 @@ impl<'db> HirDisplay<'db> for ConstParam {
553634}
554635
555636fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
637 write_generic_params_or_args(def, f, true)
638}
639
640fn write_generic_args<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -> Result {
641 write_generic_params_or_args(def, f, false)
642}
643
644fn write_generic_params_or_args<'db>(
645 def: GenericDefId,
646 f: &mut HirFormatter<'_, 'db>,
647 include_defaults: bool,
648) -> Result {
556649 let (params, store) = f.db.generic_params_and_store(def);
557650 if params.iter_lt().next().is_none()
558651 && params.iter_type_or_consts().all(|it| it.1.const_param().is_none())
......@@ -587,7 +680,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -
587680 }
588681 delim(f)?;
589682 write!(f, "{}", name.display(f.db, f.edition()))?;
590 if let Some(default) = &ty.default {
683 if include_defaults && let Some(default) = &ty.default {
591684 f.write_str(" = ")?;
592685 default.hir_fmt(f, &store)?;
593686 }
......@@ -597,7 +690,7 @@ fn write_generic_params<'db>(def: GenericDefId, f: &mut HirFormatter<'_, 'db>) -
597690 write!(f, "const {}: ", name.display(f.db, f.edition()))?;
598691 c.ty.hir_fmt(f, &store)?;
599692
600 if let Some(default) = &c.default {
693 if include_defaults && let Some(default) = &c.default {
601694 f.write_str(" = ")?;
602695 default.hir_fmt(f, &store)?;
603696 }
......@@ -746,7 +839,7 @@ impl<'db> HirDisplay<'db> for TraitRef<'db> {
746839impl<'db> HirDisplay<'db> for Trait {
747840 fn hir_fmt(&self, f: &mut HirFormatter<'_, 'db>) -> Result {
748841 // FIXME(trait-alias) needs special handling to print the equal sign
749 write_trait_header(self, f)?;
842 write_trait_header(*self, f)?;
750843 let def_id = GenericDefId::TraitId(self.id);
751844 let has_where_clause = write_where_clause(def_id, f)?;
752845
......@@ -783,7 +876,7 @@ impl<'db> HirDisplay<'db> for Trait {
783876 }
784877}
785878
786fn write_trait_header<'db>(trait_: &Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
879fn write_trait_header<'db>(trait_: Trait, f: &mut HirFormatter<'_, 'db>) -> Result {
787880 write_visibility(trait_.module(f.db).id, trait_.visibility(f.db), f)?;
788881 let data = f.db.trait_signature(trait_.id);
789882 if data.flags.contains(TraitFlags::UNSAFE) {
src/tools/rust-analyzer/crates/hir/src/from_id.rs+64-38
......@@ -4,14 +4,15 @@
44//! are splitting the hir.
55
66use hir_def::{
7 AdtId, AssocItemId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId, GenericParamId,
8 ModuleDefId, VariantId,
7 AdtId, AssocItemId, BuiltinDeriveImplId, DefWithBodyId, EnumVariantId, FieldId, GenericDefId,
8 GenericParamId, ModuleDefId, VariantId,
99 hir::{BindingId, LabelId},
1010};
11use hir_ty::next_solver::AnyImplId;
1112
1213use crate::{
13 Adt, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam, ItemInNs, Label,
14 Local, ModuleDef, Variant, VariantDef,
14 Adt, AnyFunctionId, AssocItem, BuiltinType, DefWithBody, Field, GenericDef, GenericParam,
15 ItemInNs, Label, Local, ModuleDef, Variant, VariantDef,
1516};
1617
1718macro_rules! from_id {
......@@ -39,8 +40,8 @@ from_id![
3940 (hir_def::TraitId, crate::Trait),
4041 (hir_def::StaticId, crate::Static),
4142 (hir_def::ConstId, crate::Const),
42 (hir_def::FunctionId, crate::Function),
43 (hir_def::ImplId, crate::Impl),
43 (crate::AnyFunctionId, crate::Function),
44 (hir_ty::next_solver::AnyImplId, crate::Impl),
4445 (hir_def::TypeOrConstParamId, crate::TypeOrConstParam),
4546 (hir_def::TypeParamId, crate::TypeParam),
4647 (hir_def::ConstParamId, crate::ConstParam),
......@@ -119,11 +120,15 @@ impl From<ModuleDefId> for ModuleDef {
119120 }
120121}
121122
122impl From<ModuleDef> for ModuleDefId {
123 fn from(id: ModuleDef) -> Self {
124 match id {
123impl TryFrom<ModuleDef> for ModuleDefId {
124 type Error = ();
125 fn try_from(id: ModuleDef) -> Result<Self, Self::Error> {
126 Ok(match id {
125127 ModuleDef::Module(it) => ModuleDefId::ModuleId(it.into()),
126 ModuleDef::Function(it) => ModuleDefId::FunctionId(it.into()),
128 ModuleDef::Function(it) => match it.id {
129 AnyFunctionId::FunctionId(it) => it.into(),
130 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
131 },
127132 ModuleDef::Adt(it) => ModuleDefId::AdtId(it.into()),
128133 ModuleDef::Variant(it) => ModuleDefId::EnumVariantId(it.into()),
129134 ModuleDef::Const(it) => ModuleDefId::ConstId(it.into()),
......@@ -132,18 +137,22 @@ impl From<ModuleDef> for ModuleDefId {
132137 ModuleDef::TypeAlias(it) => ModuleDefId::TypeAliasId(it.into()),
133138 ModuleDef::BuiltinType(it) => ModuleDefId::BuiltinType(it.into()),
134139 ModuleDef::Macro(it) => ModuleDefId::MacroId(it.into()),
135 }
140 })
136141 }
137142}
138143
139impl From<DefWithBody> for DefWithBodyId {
140 fn from(def: DefWithBody) -> Self {
141 match def {
142 DefWithBody::Function(it) => DefWithBodyId::FunctionId(it.id),
144impl TryFrom<DefWithBody> for DefWithBodyId {
145 type Error = ();
146 fn try_from(def: DefWithBody) -> Result<Self, ()> {
147 Ok(match def {
148 DefWithBody::Function(it) => match it.id {
149 AnyFunctionId::FunctionId(it) => it.into(),
150 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
151 },
143152 DefWithBody::Static(it) => DefWithBodyId::StaticId(it.id),
144153 DefWithBody::Const(it) => DefWithBodyId::ConstId(it.id),
145154 DefWithBody::Variant(it) => DefWithBodyId::VariantId(it.into()),
146 }
155 })
147156 }
148157}
149158
......@@ -168,17 +177,11 @@ impl From<AssocItemId> for AssocItem {
168177 }
169178}
170179
171impl From<GenericDef> for GenericDefId {
172 fn from(def: GenericDef) -> Self {
173 match def {
174 GenericDef::Function(it) => GenericDefId::FunctionId(it.id),
175 GenericDef::Adt(it) => GenericDefId::AdtId(it.into()),
176 GenericDef::Trait(it) => GenericDefId::TraitId(it.id),
177 GenericDef::TypeAlias(it) => GenericDefId::TypeAliasId(it.id),
178 GenericDef::Impl(it) => GenericDefId::ImplId(it.id),
179 GenericDef::Const(it) => GenericDefId::ConstId(it.id),
180 GenericDef::Static(it) => GenericDefId::StaticId(it.id),
181 }
180impl TryFrom<GenericDef> for GenericDefId {
181 type Error = ();
182
183 fn try_from(def: GenericDef) -> Result<Self, Self::Error> {
184 def.id().ok_or(())
182185 }
183186}
184187
......@@ -238,13 +241,17 @@ impl From<FieldId> for Field {
238241 }
239242}
240243
241impl From<AssocItem> for GenericDefId {
242 fn from(item: AssocItem) -> Self {
243 match item {
244 AssocItem::Function(f) => f.id.into(),
244impl TryFrom<AssocItem> for GenericDefId {
245 type Error = ();
246 fn try_from(item: AssocItem) -> Result<Self, Self::Error> {
247 Ok(match item {
248 AssocItem::Function(f) => match f.id {
249 AnyFunctionId::FunctionId(it) => it.into(),
250 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Err(()),
251 },
245252 AssocItem::Const(c) => c.id.into(),
246253 AssocItem::TypeAlias(t) => t.id.into(),
247 }
254 })
248255 }
249256}
250257
......@@ -270,13 +277,14 @@ impl From<hir_def::item_scope::ItemInNs> for ItemInNs {
270277 }
271278}
272279
273impl From<ItemInNs> for hir_def::item_scope::ItemInNs {
274 fn from(it: ItemInNs) -> Self {
275 match it {
276 ItemInNs::Types(it) => Self::Types(it.into()),
277 ItemInNs::Values(it) => Self::Values(it.into()),
280impl TryFrom<ItemInNs> for hir_def::item_scope::ItemInNs {
281 type Error = ();
282 fn try_from(it: ItemInNs) -> Result<Self, Self::Error> {
283 Ok(match it {
284 ItemInNs::Types(it) => Self::Types(it.try_into()?),
285 ItemInNs::Values(it) => Self::Values(it.try_into()?),
278286 ItemInNs::Macros(it) => Self::Macros(it.into()),
279 }
287 })
280288 }
281289}
282290
......@@ -291,3 +299,21 @@ impl From<BuiltinType> for hir_def::builtin_type::BuiltinType {
291299 it.inner
292300 }
293301}
302
303impl From<hir_def::ImplId> for crate::Impl {
304 fn from(value: hir_def::ImplId) -> Self {
305 crate::Impl { id: AnyImplId::ImplId(value) }
306 }
307}
308
309impl From<BuiltinDeriveImplId> for crate::Impl {
310 fn from(value: BuiltinDeriveImplId) -> Self {
311 crate::Impl { id: AnyImplId::BuiltinDeriveImplId(value) }
312 }
313}
314
315impl From<hir_def::FunctionId> for crate::Function {
316 fn from(value: hir_def::FunctionId) -> Self {
317 crate::Function { id: AnyFunctionId::FunctionId(value) }
318 }
319}
src/tools/rust-analyzer/crates/hir/src/has_source.rs+63-9
......@@ -7,18 +7,18 @@ use hir_def::{
77 src::{HasChildSource, HasSource as _},
88};
99use hir_expand::{EditionedFileId, HirFileId, InFile};
10use hir_ty::db::InternedClosure;
11use syntax::ast;
10use hir_ty::{db::InternedClosure, next_solver::AnyImplId};
11use syntax::{AstNode, ast};
1212use tt::TextRange;
1313
1414use crate::{
15 Adt, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
15 Adt, AnyFunctionId, Callee, Const, Enum, ExternCrateDecl, Field, FieldSource, Function, Impl,
1616 InlineAsmOperand, Label, LifetimeParam, LocalSource, Macro, Module, Param, SelfParam, Static,
1717 Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant, VariantDef, db::HirDatabase,
1818};
1919
20pub trait HasSource {
21 type Ast;
20pub trait HasSource: Sized {
21 type Ast: AstNode;
2222 /// Fetches the definition's source node.
2323 /// Using [`crate::SemanticsImpl::source`] is preferred when working with [`crate::Semantics`],
2424 /// as that caches the parsed file in the semantics' cache.
......@@ -27,6 +27,20 @@ pub trait HasSource {
2727 /// But we made this method `Option` to support rlib in the future
2828 /// by <https://github.com/rust-lang/rust-analyzer/issues/6913>
2929 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>>;
30
31 /// Fetches the source node, along with its full range.
32 ///
33 /// The reason for the separate existence of this method is that some things, notably builtin derive impls,
34 /// do not really have a source node, at least not of the correct type. But we still can trace them
35 /// to source code (the derive producing them). So this method will return the range if it is supported,
36 /// and if the node is supported too it will return it as well.
37 fn source_with_range(
38 self,
39 db: &dyn HirDatabase,
40 ) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
41 let source = self.source(db)?;
42 Some(source.map(|node| (node.syntax().text_range(), Some(node))))
43 }
3044}
3145
3246/// NB: Module is !HasSource, because it has two source nodes at the same time:
......@@ -146,7 +160,30 @@ impl HasSource for Variant {
146160impl HasSource for Function {
147161 type Ast = ast::Fn;
148162 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
149 Some(self.id.lookup(db).source(db))
163 match self.id {
164 AnyFunctionId::FunctionId(id) => Some(id.loc(db).source(db)),
165 // When calling `source()`, we use the trait method source, but when calling `source_with_range()`,
166 // we return `None` as the syntax node source. This is relying on the assumption that if you are calling
167 // `source_with_range()` (e.g. in navigation) you're prepared to deal with no source node, while if
168 // you call `source()` maybe you don't - therefore we fall back to the trait method, to not lose features.
169 AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => method
170 .trait_method(db, impl_)
171 .and_then(|trait_method| Function::from(trait_method).source(db)),
172 }
173 }
174
175 fn source_with_range(
176 self,
177 db: &dyn HirDatabase,
178 ) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
179 match self.id {
180 AnyFunctionId::FunctionId(id) => Some(
181 id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))),
182 ),
183 AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
184 Some(impl_.loc(db).source(db).map(|range| (range, None)))
185 }
186 }
150187 }
151188}
152189impl HasSource for Const {
......@@ -190,7 +227,24 @@ impl HasSource for Macro {
190227impl HasSource for Impl {
191228 type Ast = ast::Impl;
192229 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
193 Some(self.id.lookup(db).source(db))
230 match self.id {
231 AnyImplId::ImplId(id) => Some(id.loc(db).source(db)),
232 AnyImplId::BuiltinDeriveImplId(_) => None,
233 }
234 }
235
236 fn source_with_range(
237 self,
238 db: &dyn HirDatabase,
239 ) -> Option<InFile<(TextRange, Option<Self::Ast>)>> {
240 match self.id {
241 AnyImplId::ImplId(id) => Some(
242 id.loc(db).source(db).map(|source| (source.syntax().text_range(), Some(source))),
243 ),
244 AnyImplId::BuiltinDeriveImplId(impl_) => {
245 Some(impl_.loc(db).source(db).map(|range| (range, None)))
246 }
247 }
194248 }
195249}
196250
......@@ -224,7 +278,7 @@ impl HasSource for Param<'_> {
224278 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
225279 match self.func {
226280 Callee::Def(CallableDefId::FunctionId(func)) => {
227 let InFile { file_id, value } = Function { id: func }.source(db)?;
281 let InFile { file_id, value } = Function::from(func).source(db)?;
228282 let params = value.param_list()?;
229283 if let Some(self_param) = params.self_param() {
230284 if let Some(idx) = self.idx.checked_sub(1) {
......@@ -261,7 +315,7 @@ impl HasSource for SelfParam {
261315 type Ast = ast::SelfParam;
262316
263317 fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
264 let InFile { file_id, value } = Function::from(self.func).source(db)?;
318 let InFile { file_id, value } = self.func.source(db)?;
265319 value
266320 .param_list()
267321 .and_then(|params| params.self_param())
src/tools/rust-analyzer/crates/hir/src/lib.rs+731-275
......@@ -48,12 +48,13 @@ use arrayvec::ArrayVec;
4848use base_db::{CrateDisplayName, CrateOrigin, LangCrateOrigin};
4949use either::Either;
5050use hir_def::{
51 AdtId, AssocItemId, AssocItemLoc, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
52 EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId, GenericParamId,
53 HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup, MacroExpander,
54 MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId, TypeOrConstParamId,
55 TypeParamId, UnionId,
51 AdtId, AssocItemId, AssocItemLoc, BuiltinDeriveImplId, CallableDefId, ConstId, ConstParamId,
52 DefWithBodyId, EnumId, EnumVariantId, ExternBlockId, ExternCrateId, FunctionId, GenericDefId,
53 GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId, LocalFieldId, Lookup,
54 MacroExpander, MacroId, StaticId, StructId, SyntheticSyntax, TupleId, TypeAliasId,
55 TypeOrConstParamId, TypeParamId, UnionId,
5656 attrs::AttrFlags,
57 builtin_derive::BuiltinDeriveImplMethod,
5758 expr_store::{ExpressionStoreDiagnostics, ExpressionStoreSourceMap},
5859 hir::{
5960 BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, LabelId, Pat,
......@@ -73,7 +74,8 @@ use hir_def::{
7374 visibility::visibility_from_ast,
7475};
7576use hir_expand::{
76 AstId, MacroCallKind, RenderedExpandError, ValueResult, proc_macro::ProcMacroKind,
77 AstId, MacroCallKind, RenderedExpandError, ValueResult, builtin::BuiltinDeriveExpander,
78 proc_macro::ProcMacroKind,
7779};
7880use hir_ty::{
7981 GenericPredicates, InferenceResult, ParamEnvAndCrate, TyDefId, TyLoweringDiagnostic,
......@@ -88,8 +90,9 @@ use hir_ty::{
8890 },
8991 mir::{MutBorrowKind, interpret_mir},
9092 next_solver::{
91 AliasTy, ClauseKind, ConstKind, DbInterner, ErrorGuaranteed, GenericArg, GenericArgs,
92 ParamEnv, PolyFnSig, Region, SolverDefId, Ty, TyKind, TypingMode,
93 AliasTy, AnyImplId, ClauseKind, ConstKind, DbInterner, EarlyBinder, EarlyParamRegion,
94 ErrorGuaranteed, GenericArg, GenericArgs, ParamConst, ParamEnv, PolyFnSig, Region,
95 RegionKind, SolverDefId, Ty, TyKind, TypingMode,
9396 infer::{DbInternerInferExt, InferCtxt},
9497 },
9598 traits::{self, is_inherent_impl_coherent, structurally_normalize_ty},
......@@ -97,7 +100,8 @@ use hir_ty::{
97100use itertools::Itertools;
98101use rustc_hash::FxHashSet;
99102use rustc_type_ir::{
100 AliasTyKind, TypeSuperVisitable, TypeVisitable, TypeVisitor, fast_reject,
103 AliasTyKind, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable,
104 TypeVisitor, fast_reject,
101105 inherent::{AdtDef, GenericArgs as _, IntoKind, SliceLike, Term as _, Ty as _},
102106};
103107use smallvec::SmallVec;
......@@ -105,7 +109,7 @@ use span::{AstIdNode, Edition, FileId};
105109use stdx::{format_to, impl_from, never, variance::PhantomCovariantLifetime};
106110use syntax::{
107111 AstNode, AstPtr, SmolStr, SyntaxNode, SyntaxNodePtr, TextRange, ToSmolStr,
108 ast::{self, HasName, HasVisibility as _},
112 ast::{self, HasName as _, HasVisibility as _},
109113 format_smolstr,
110114};
111115use triomphe::{Arc, ThinArc};
......@@ -440,7 +444,10 @@ impl ModuleDef {
440444 Adt::Union(it) => it.id.into(),
441445 },
442446 ModuleDef::Trait(it) => it.id.into(),
443 ModuleDef::Function(it) => it.id.into(),
447 ModuleDef::Function(it) => match it.id {
448 AnyFunctionId::FunctionId(it) => it.into(),
449 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return Vec::new(),
450 },
444451 ModuleDef::TypeAlias(it) => it.id.into(),
445452 ModuleDef::Module(it) => it.id.into(),
446453 ModuleDef::Const(it) => it.id.into(),
......@@ -504,7 +511,7 @@ impl ModuleDef {
504511 pub fn attrs(&self, db: &dyn HirDatabase) -> Option<AttrsWithOwner> {
505512 Some(match self {
506513 ModuleDef::Module(it) => it.attrs(db),
507 ModuleDef::Function(it) => it.attrs(db),
514 ModuleDef::Function(it) => HasAttrs::attrs(*it, db),
508515 ModuleDef::Adt(it) => it.attrs(db),
509516 ModuleDef::Variant(it) => it.attrs(db),
510517 ModuleDef::Const(it) => it.attrs(db),
......@@ -772,8 +779,11 @@ impl Module {
772779 for impl_def in self.impl_defs(db) {
773780 GenericDef::Impl(impl_def).diagnostics(db, acc);
774781
775 let loc = impl_def.id.lookup(db);
776 let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_def.id);
782 let AnyImplId::ImplId(impl_id) = impl_def.id else {
783 continue;
784 };
785 let loc = impl_id.lookup(db);
786 let (impl_signature, source_map) = db.impl_signature_with_source_map(impl_id);
777787 expr_store_diagnostics(db, acc, &source_map);
778788
779789 let file_id = loc.id.file_id;
......@@ -789,12 +799,12 @@ impl Module {
789799
790800 let ast_id_map = db.ast_id_map(file_id);
791801
792 for diag in impl_def.id.impl_items_with_diagnostics(db).1.iter() {
802 for diag in impl_id.impl_items_with_diagnostics(db).1.iter() {
793803 emit_def_diagnostic(db, acc, diag, edition, loc.container.krate(db));
794804 }
795805
796806 if impl_signature.target_trait.is_none()
797 && !is_inherent_impl_coherent(db, def_map, impl_def.id)
807 && !is_inherent_impl_coherent(db, def_map, impl_id)
798808 {
799809 acc.push(IncoherentImpl { impl_: ast_id_map.get(loc.id.value), file_id }.into())
800810 }
......@@ -822,7 +832,7 @@ impl Module {
822832 if drop_trait != trait_.into() {
823833 return None;
824834 }
825 let parent = impl_def.id.into();
835 let parent = impl_id.into();
826836 let (lifetimes_attrs, type_and_consts_attrs) =
827837 AttrFlags::query_generic_params(db, parent);
828838 let res = lifetimes_attrs.values().any(|it| it.contains(AttrFlags::MAY_DANGLE))
......@@ -851,7 +861,7 @@ impl Module {
851861 AssocItemId::ConstId(id) => !db.const_signature(id).has_body(),
852862 AssocItemId::TypeAliasId(it) => db.type_alias_signature(it).ty.is_none(),
853863 });
854 impl_assoc_items_scratch.extend(impl_def.id.impl_items(db).items.iter().cloned());
864 impl_assoc_items_scratch.extend(impl_id.impl_items(db).items.iter().cloned());
855865
856866 let redundant = impl_assoc_items_scratch
857867 .iter()
......@@ -883,11 +893,11 @@ impl Module {
883893 .collect();
884894
885895 if !missing.is_empty() {
886 let self_ty = db.impl_self_ty(impl_def.id).instantiate_identity();
896 let self_ty = db.impl_self_ty(impl_id).instantiate_identity();
887897 let self_ty = structurally_normalize_ty(
888898 &infcx,
889899 self_ty,
890 db.trait_environment(impl_def.id.into()),
900 db.trait_environment(impl_id.into()),
891901 );
892902 let self_ty_is_guaranteed_unsized = matches!(
893903 self_ty.kind(),
......@@ -896,7 +906,13 @@ impl Module {
896906 if self_ty_is_guaranteed_unsized {
897907 missing.retain(|(_, assoc_item)| {
898908 let assoc_item = match *assoc_item {
899 AssocItem::Function(it) => it.id.into(),
909 AssocItem::Function(it) => match it.id {
910 AnyFunctionId::FunctionId(id) => id.into(),
911 AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
912 never!("should not have an `AnyFunctionId::BuiltinDeriveImplMethod` here");
913 return false;
914 },
915 },
900916 AssocItem::Const(it) => it.id.into(),
901917 AssocItem::TypeAlias(it) => it.id.into(),
902918 };
......@@ -918,20 +934,15 @@ impl Module {
918934 impl_assoc_items_scratch.clear();
919935 }
920936
937 push_ty_diagnostics(db, acc, db.impl_self_ty_with_diagnostics(impl_id).1, &source_map);
921938 push_ty_diagnostics(
922939 db,
923940 acc,
924 db.impl_self_ty_with_diagnostics(impl_def.id).1,
925 &source_map,
926 );
927 push_ty_diagnostics(
928 db,
929 acc,
930 db.impl_trait_with_diagnostics(impl_def.id).and_then(|it| it.1),
941 db.impl_trait_with_diagnostics(impl_id).and_then(|it| it.1),
931942 &source_map,
932943 );
933944
934 for &(_, item) in impl_def.id.impl_items(db).items.iter() {
945 for &(_, item) in impl_id.impl_items(db).items.iter() {
935946 AssocItem::from(item).diagnostics(db, acc, style_lints);
936947 }
937948 }
......@@ -955,7 +966,8 @@ impl Module {
955966
956967 pub fn impl_defs(self, db: &dyn HirDatabase) -> Vec<Impl> {
957968 let def_map = self.id.def_map(db);
958 def_map[self.id].scope.impls().map(Impl::from).collect()
969 let scope = &def_map[self.id].scope;
970 scope.impls().map(Impl::from).chain(scope.builtin_derive_impls().map(Impl::from)).collect()
959971 }
960972
961973 /// Finds a path that can be used to refer to the given item from within
......@@ -968,7 +980,7 @@ impl Module {
968980 ) -> Option<ModPath> {
969981 hir_def::find_path::find_path(
970982 db,
971 item.into().into(),
983 item.into().try_into().ok()?,
972984 self.into(),
973985 PrefixKind::Plain,
974986 false,
......@@ -985,7 +997,14 @@ impl Module {
985997 prefix_kind: PrefixKind,
986998 cfg: FindPathConfig,
987999 ) -> Option<ModPath> {
988 hir_def::find_path::find_path(db, item.into().into(), self.into(), prefix_kind, true, cfg)
1000 hir_def::find_path::find_path(
1001 db,
1002 item.into().try_into().ok()?,
1003 self.into(),
1004 prefix_kind,
1005 true,
1006 cfg,
1007 )
9891008 }
9901009
9911010 #[inline]
......@@ -1863,9 +1882,9 @@ impl VariantDef {
18631882
18641883 pub fn name(&self, db: &dyn HirDatabase) -> Name {
18651884 match self {
1866 VariantDef::Struct(s) => s.name(db),
1867 VariantDef::Union(u) => u.name(db),
1868 VariantDef::Variant(e) => e.name(db),
1885 VariantDef::Struct(s) => (*s).name(db),
1886 VariantDef::Union(u) => (*u).name(db),
1887 VariantDef::Variant(e) => (*e).name(db),
18691888 }
18701889 }
18711890}
......@@ -1909,24 +1928,33 @@ impl DefWithBody {
19091928 }
19101929 }
19111930
1912 fn id(&self) -> DefWithBodyId {
1913 match self {
1914 DefWithBody::Function(it) => it.id.into(),
1931 fn id(&self) -> Option<DefWithBodyId> {
1932 Some(match self {
1933 DefWithBody::Function(it) => match it.id {
1934 AnyFunctionId::FunctionId(id) => id.into(),
1935 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None,
1936 },
19151937 DefWithBody::Static(it) => it.id.into(),
19161938 DefWithBody::Const(it) => it.id.into(),
19171939 DefWithBody::Variant(it) => it.into(),
1918 }
1940 })
19191941 }
19201942
19211943 /// A textual representation of the HIR of this def's body for debugging purposes.
19221944 pub fn debug_hir(self, db: &dyn HirDatabase) -> String {
1923 let body = db.body(self.id());
1924 body.pretty_print(db, self.id(), Edition::CURRENT)
1945 let Some(id) = self.id() else {
1946 return String::new();
1947 };
1948 let body = db.body(id);
1949 body.pretty_print(db, id, Edition::CURRENT)
19251950 }
19261951
19271952 /// A textual representation of the MIR of this def's body for debugging purposes.
19281953 pub fn debug_mir(self, db: &dyn HirDatabase) -> String {
1929 let body = db.mir_body(self.id());
1954 let Some(id) = self.id() else {
1955 return String::new();
1956 };
1957 let body = db.mir_body(id);
19301958 match body {
19311959 Ok(body) => body.pretty_print(db, self.module(db).krate(db).to_display_target(db)),
19321960 Err(e) => format!("error:\n{e:?}"),
......@@ -1939,11 +1967,17 @@ impl DefWithBody {
19391967 acc: &mut Vec<AnyDiagnostic<'db>>,
19401968 style_lints: bool,
19411969 ) {
1970 let Ok(id) = self.try_into() else {
1971 return;
1972 };
19421973 let krate = self.module(db).id.krate(db);
19431974
1944 let (body, source_map) = db.body_with_source_map(self.into());
1975 let (body, source_map) = db.body_with_source_map(id);
19451976 let sig_source_map = match self {
1946 DefWithBody::Function(id) => db.function_signature_with_source_map(id.into()).1,
1977 DefWithBody::Function(id) => match id.id {
1978 AnyFunctionId::FunctionId(id) => db.function_signature_with_source_map(id).1,
1979 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return,
1980 },
19471981 DefWithBody::Static(id) => db.static_signature_with_source_map(id.into()).1,
19481982 DefWithBody::Const(id) => db.const_signature_with_source_map(id.into()).1,
19491983 DefWithBody::Variant(variant) => {
......@@ -1958,11 +1992,11 @@ impl DefWithBody {
19581992
19591993 expr_store_diagnostics(db, acc, &source_map);
19601994
1961 let infer = InferenceResult::for_body(db, self.into());
1995 let infer = InferenceResult::for_body(db, id);
19621996 for d in infer.diagnostics() {
19631997 acc.extend(AnyDiagnostic::inference_diagnostic(
19641998 db,
1965 self.into(),
1999 id,
19662000 d,
19672001 &source_map,
19682002 &sig_source_map,
......@@ -1989,14 +2023,14 @@ impl DefWithBody {
19892023 acc.push(
19902024 TypeMismatch {
19912025 expr_or_pat,
1992 expected: Type::new(db, DefWithBodyId::from(self), mismatch.expected.as_ref()),
1993 actual: Type::new(db, DefWithBodyId::from(self), mismatch.actual.as_ref()),
2026 expected: Type::new(db, id, mismatch.expected.as_ref()),
2027 actual: Type::new(db, id, mismatch.actual.as_ref()),
19942028 }
19952029 .into(),
19962030 );
19972031 }
19982032
1999 let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, self.into());
2033 let missing_unsafe = hir_ty::diagnostics::missing_unsafe(db, id);
20002034 for (node, reason) in missing_unsafe.unsafe_exprs {
20012035 match source_map.expr_or_pat_syntax(node) {
20022036 Ok(node) => acc.push(
......@@ -2031,7 +2065,7 @@ impl DefWithBody {
20312065 }
20322066 }
20332067
2034 if let Ok(borrowck_results) = db.borrowck(self.into()) {
2068 if let Ok(borrowck_results) = db.borrowck(id) {
20352069 for borrowck_result in borrowck_results.iter() {
20362070 let mir_body = &borrowck_result.mir_body;
20372071 for moof in &borrowck_result.moved_out_of_ref {
......@@ -2088,7 +2122,7 @@ impl DefWithBody {
20882122 {
20892123 need_mut = &mir::MutabilityReason::Not;
20902124 }
2091 let local = Local { parent: self.into(), binding_id };
2125 let local = Local { parent: id, binding_id };
20922126 let is_mut = body[binding_id].mode == BindingAnnotation::Mutable;
20932127
20942128 match (need_mut, is_mut) {
......@@ -2144,17 +2178,11 @@ impl DefWithBody {
21442178 }
21452179 }
21462180
2147 for diagnostic in BodyValidationDiagnostic::collect(db, self.into(), style_lints) {
2181 for diagnostic in BodyValidationDiagnostic::collect(db, id, style_lints) {
21482182 acc.extend(AnyDiagnostic::body_validation_diagnostic(db, diagnostic, &source_map));
21492183 }
21502184
2151 let def: ModuleDef = match self {
2152 DefWithBody::Function(it) => it.into(),
2153 DefWithBody::Static(it) => it.into(),
2154 DefWithBody::Const(it) => it.into(),
2155 DefWithBody::Variant(it) => it.into(),
2156 };
2157 for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
2185 for diag in hir_ty::diagnostics::incorrect_case(db, id.into()) {
21582186 acc.push(diag.into())
21592187 }
21602188 }
......@@ -2192,45 +2220,181 @@ fn expr_store_diagnostics<'db>(
21922220 .macro_calls()
21932221 .for_each(|(_ast_id, call_id)| macro_call_diagnostics(db, call_id, acc));
21942222}
2223
21952224#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
2225enum AnyFunctionId {
2226 FunctionId(FunctionId),
2227 BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId },
2228}
2229
2230#[derive(Clone, Copy, PartialEq, Eq, Hash)]
21962231pub struct Function {
2197 pub(crate) id: FunctionId,
2232 pub(crate) id: AnyFunctionId,
2233}
2234
2235impl fmt::Debug for Function {
2236 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
2237 fmt::Debug::fmt(&self.id, f)
2238 }
21982239}
21992240
22002241impl Function {
22012242 pub fn module(self, db: &dyn HirDatabase) -> Module {
2202 self.id.module(db).into()
2243 match self.id {
2244 AnyFunctionId::FunctionId(id) => id.module(db).into(),
2245 AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => impl_.module(db).into(),
2246 }
22032247 }
22042248
22052249 pub fn name(self, db: &dyn HirDatabase) -> Name {
2206 db.function_signature(self.id).name.clone()
2250 match self.id {
2251 AnyFunctionId::FunctionId(id) => db.function_signature(id).name.clone(),
2252 AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => {
2253 Name::new_symbol_root(method.name())
2254 }
2255 }
22072256 }
22082257
22092258 pub fn ty(self, db: &dyn HirDatabase) -> Type<'_> {
2210 Type::from_value_def(db, self.id)
2259 match self.id {
2260 AnyFunctionId::FunctionId(id) => Type::from_value_def(db, id),
2261 AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
2262 // Get the type for the trait function, as we can't get the type for the impl function
2263 // because it has not `CallableDefId`.
2264 let krate = impl_.module(db).krate(db);
2265 let interner = DbInterner::new_with(db, krate);
2266 let param_env = hir_ty::builtin_derive::param_env(interner, impl_);
2267 let env = ParamEnvAndCrate { param_env, krate };
2268 let Some(trait_method) = method.trait_method(db, impl_) else {
2269 return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) };
2270 };
2271 Function::from(trait_method).ty(db)
2272 }
2273 }
22112274 }
22122275
22132276 pub fn fn_ptr_type(self, db: &dyn HirDatabase) -> Type<'_> {
2214 let resolver = self.id.resolver(db);
2215 let interner = DbInterner::new_no_crate(db);
2216 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2217 let callable_sig = db.callable_item_signature(self.id.into()).instantiate_identity();
2218 let ty = Ty::new_fn_ptr(interner, callable_sig);
2219 Type::new_with_resolver_inner(db, &resolver, ty)
2277 match self.id {
2278 AnyFunctionId::FunctionId(id) => {
2279 let resolver = id.resolver(db);
2280 let interner = DbInterner::new_no_crate(db);
2281 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2282 let callable_sig = db.callable_item_signature(id.into()).instantiate_identity();
2283 let ty = Ty::new_fn_ptr(interner, callable_sig);
2284 Type::new_with_resolver_inner(db, &resolver, ty)
2285 }
2286 AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
2287 struct ParamsShifter<'db> {
2288 interner: DbInterner<'db>,
2289 shift_by: i32,
2290 }
2291
2292 impl<'db> TypeFolder<DbInterner<'db>> for ParamsShifter<'db> {
2293 fn cx(&self) -> DbInterner<'db> {
2294 self.interner
2295 }
2296
2297 fn fold_ty(&mut self, ty: Ty<'db>) -> Ty<'db> {
2298 if let TyKind::Param(param) = ty.kind() {
2299 Ty::new_param(
2300 self.interner,
2301 param.id,
2302 param.index.checked_add_signed(self.shift_by).unwrap(),
2303 )
2304 } else {
2305 ty.super_fold_with(self)
2306 }
2307 }
2308
2309 fn fold_const(
2310 &mut self,
2311 ct: hir_ty::next_solver::Const<'db>,
2312 ) -> hir_ty::next_solver::Const<'db> {
2313 if let ConstKind::Param(param) = ct.kind() {
2314 hir_ty::next_solver::Const::new_param(
2315 self.interner,
2316 ParamConst {
2317 id: param.id,
2318 index: param.index.checked_add_signed(self.shift_by).unwrap(),
2319 },
2320 )
2321 } else {
2322 ct.super_fold_with(self)
2323 }
2324 }
2325
2326 fn fold_region(&mut self, r: Region<'db>) -> Region<'db> {
2327 if let RegionKind::ReEarlyParam(param) = r.kind() {
2328 Region::new_early_param(
2329 self.interner,
2330 EarlyParamRegion {
2331 id: param.id,
2332 index: param.index.checked_add_signed(self.shift_by).unwrap(),
2333 },
2334 )
2335 } else {
2336 r
2337 }
2338 }
2339 }
2340
2341 // Get the type for the trait function, as we can't get the type for the impl function
2342 // because it has not `CallableDefId`.
2343 let krate = impl_.module(db).krate(db);
2344 let interner = DbInterner::new_with(db, krate);
2345 let param_env = hir_ty::builtin_derive::param_env(interner, impl_);
2346 let env = ParamEnvAndCrate { param_env, krate };
2347 let Some(trait_method) = method.trait_method(db, impl_) else {
2348 return Type { env, ty: Ty::new_error(interner, ErrorGuaranteed) };
2349 };
2350 // The procedure works as follows: the method may have additional generic parameters (e.g. `Hash::hash()`),
2351 // and we want them to be params of the impl method as well. So we start with the trait method identity
2352 // args and extract from them the trait method own args. In parallel, we retrieve the impl trait ref.
2353 // Now we can put our args as [...impl_trait_ref.args, ...trait_method_own_args], but we have one problem:
2354 // the args in `trait_method_own_args` use indices appropriate for the trait method, which are not necessarily
2355 // good for the impl method. So we shift them by `impl_generics_len - trait_generics_len`, which is essentially
2356 // `impl_generics_len - impl_trait_ref.args.len()`.
2357 let trait_method_fn_ptr = Ty::new_fn_ptr(
2358 interner,
2359 db.callable_item_signature(trait_method.into()).instantiate_identity(),
2360 );
2361 let impl_trait_ref =
2362 hir_ty::builtin_derive::impl_trait(interner, impl_).instantiate_identity();
2363 let trait_method_args =
2364 GenericArgs::identity_for_item(interner, trait_method.into());
2365 let trait_method_own_args = GenericArgs::new_from_iter(
2366 interner,
2367 trait_method_args.iter().skip(impl_trait_ref.args.len()),
2368 );
2369 let impl_params_count = hir_ty::builtin_derive::generic_params_count(db, impl_);
2370 let shift_args_by = impl_params_count as i32 - impl_trait_ref.args.len() as i32;
2371 let shifted_trait_method_own_args = trait_method_own_args
2372 .fold_with(&mut ParamsShifter { interner, shift_by: shift_args_by });
2373 let impl_method_args = GenericArgs::new_from_iter(
2374 interner,
2375 impl_trait_ref.args.iter().chain(shifted_trait_method_own_args),
2376 );
2377 let impl_method_fn_ptr =
2378 EarlyBinder::bind(trait_method_fn_ptr).instantiate(interner, impl_method_args);
2379 Type { env, ty: impl_method_fn_ptr }
2380 }
2381 }
2382 }
2383
2384 fn fn_sig<'db>(self, db: &'db dyn HirDatabase) -> (ParamEnvAndCrate<'db>, PolyFnSig<'db>) {
2385 let fn_ptr = self.fn_ptr_type(db);
2386 let TyKind::FnPtr(sig_tys, hdr) = fn_ptr.ty.kind() else {
2387 unreachable!();
2388 };
2389 (fn_ptr.env, sig_tys.with(hdr))
22202390 }
22212391
22222392 // FIXME: Find a better API to express all combinations here, perhaps we should have `PreInstantiationType`?
22232393
22242394 /// Get this function's return type
22252395 pub fn ret_type(self, db: &dyn HirDatabase) -> Type<'_> {
2226 let resolver = self.id.resolver(db);
2227 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2228 let ty = db
2229 .callable_item_signature(self.id.into())
2230 .instantiate_identity()
2231 .skip_binder()
2232 .output();
2233 Type::new_with_resolver_inner(db, &resolver, ty)
2396 let (env, sig) = self.fn_sig(db);
2397 Type { env, ty: sig.skip_binder().output() }
22342398 }
22352399
22362400 // FIXME: Find better API to also handle const generics
......@@ -2239,30 +2403,41 @@ impl Function {
22392403 db: &'db dyn HirDatabase,
22402404 generics: impl Iterator<Item = Type<'db>>,
22412405 ) -> Type<'db> {
2242 let resolver = self.id.resolver(db);
2406 let ret_type = self.ret_type(db);
22432407 let interner = DbInterner::new_no_crate(db);
2244 let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty));
2408 let args = self.adapt_generic_args(interner, generics);
2409 ret_type.derived(EarlyBinder::bind(ret_type.ty).instantiate(interner, args))
2410 }
22452411
2246 let interner = DbInterner::new_no_crate(db);
2247 let ty = db
2248 .callable_item_signature(self.id.into())
2249 .instantiate(interner, args)
2250 .skip_binder()
2251 .output();
2252 Type::new_with_resolver_inner(db, &resolver, ty)
2412 fn adapt_generic_args<'db>(
2413 self,
2414 interner: DbInterner<'db>,
2415 generics: impl Iterator<Item = Type<'db>>,
2416 ) -> GenericArgs<'db> {
2417 let generics = generics.map(|ty| ty.ty);
2418 match self.id {
2419 AnyFunctionId::FunctionId(id) => generic_args_from_tys(interner, id.into(), generics),
2420 AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
2421 let impl_args = GenericArgs::identity_for_item(interner, impl_.into());
2422 GenericArgs::new_from_iter(
2423 interner,
2424 impl_args.iter().chain(generics.map(Into::into)),
2425 )
2426 }
2427 }
22532428 }
22542429
22552430 pub fn async_ret_type<'db>(self, db: &'db dyn HirDatabase) -> Option<Type<'db>> {
2431 let AnyFunctionId::FunctionId(id) = self.id else {
2432 return None;
2433 };
22562434 if !self.is_async(db) {
22572435 return None;
22582436 }
2259 let resolver = self.id.resolver(db);
2437 let resolver = id.resolver(db);
22602438 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2261 let ret_ty = db
2262 .callable_item_signature(self.id.into())
2263 .instantiate_identity()
2264 .skip_binder()
2265 .output();
2439 let ret_ty =
2440 db.callable_item_signature(id.into()).instantiate_identity().skip_binder().output();
22662441 for pred in ret_ty.impl_trait_bounds(db).into_iter().flatten() {
22672442 if let ClauseKind::Projection(projection) = pred.kind().skip_binder()
22682443 && let Some(output_ty) = projection.term.as_type()
......@@ -2274,31 +2449,47 @@ impl Function {
22742449 }
22752450
22762451 pub fn has_self_param(self, db: &dyn HirDatabase) -> bool {
2277 db.function_signature(self.id).has_self_param()
2452 match self.id {
2453 AnyFunctionId::FunctionId(id) => db.function_signature(id).has_self_param(),
2454 AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
2455 BuiltinDeriveImplMethod::clone
2456 | BuiltinDeriveImplMethod::fmt
2457 | BuiltinDeriveImplMethod::hash
2458 | BuiltinDeriveImplMethod::cmp
2459 | BuiltinDeriveImplMethod::partial_cmp
2460 | BuiltinDeriveImplMethod::eq => true,
2461 BuiltinDeriveImplMethod::default => false,
2462 },
2463 }
22782464 }
22792465
22802466 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
2281 self.has_self_param(db).then_some(SelfParam { func: self.id })
2467 self.has_self_param(db).then_some(SelfParam { func: self })
22822468 }
22832469
22842470 pub fn assoc_fn_params(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
2285 let environment = param_env_from_has_crate(db, self.id);
2286 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2287 let callable_sig =
2288 db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
2289 callable_sig
2471 let (env, sig) = self.fn_sig(db);
2472 let func = match self.id {
2473 AnyFunctionId::FunctionId(id) => Callee::Def(CallableDefId::FunctionId(id)),
2474 AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } => {
2475 Callee::BuiltinDeriveImplMethod { method, impl_ }
2476 }
2477 };
2478 sig.skip_binder()
22902479 .inputs()
22912480 .iter()
22922481 .enumerate()
2293 .map(|(idx, &ty)| {
2294 let ty = Type { env: environment, ty };
2295 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
2296 })
2482 .map(|(idx, &ty)| Param { func: func.clone(), ty: Type { env, ty }, idx })
22972483 .collect()
22982484 }
22992485
23002486 pub fn num_params(self, db: &dyn HirDatabase) -> usize {
2301 db.function_signature(self.id).params.len()
2487 match self.id {
2488 AnyFunctionId::FunctionId(id) => db.function_signature(id).params.len(),
2489 AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
2490 self.fn_sig(db).1.skip_binder().inputs().len()
2491 }
2492 }
23022493 }
23032494
23042495 pub fn method_params(self, db: &dyn HirDatabase) -> Option<Vec<Param<'_>>> {
......@@ -2307,21 +2498,11 @@ impl Function {
23072498 }
23082499
23092500 pub fn params_without_self(self, db: &dyn HirDatabase) -> Vec<Param<'_>> {
2310 let environment = param_env_from_has_crate(db, self.id);
2311 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2312 let callable_sig =
2313 db.callable_item_signature(self.id.into()).instantiate_identity().skip_binder();
2314 let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
2315 callable_sig
2316 .inputs()
2317 .iter()
2318 .enumerate()
2319 .skip(skip)
2320 .map(|(idx, &ty)| {
2321 let ty = Type { env: environment, ty };
2322 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
2323 })
2324 .collect()
2501 let mut params = self.assoc_fn_params(db);
2502 if self.has_self_param(db) {
2503 params.remove(0);
2504 }
2505 params
23252506 }
23262507
23272508 // FIXME: Find better API to also handle const generics
......@@ -2330,40 +2511,50 @@ impl Function {
23302511 db: &'db dyn HirDatabase,
23312512 generics: impl Iterator<Item = Type<'db>>,
23322513 ) -> Vec<Param<'db>> {
2333 let environment = param_env_from_has_crate(db, self.id);
23342514 let interner = DbInterner::new_no_crate(db);
2335 let args = generic_args_from_tys(interner, self.id.into(), generics.map(|ty| ty.ty));
2336 let callable_sig =
2337 db.callable_item_signature(self.id.into()).instantiate(interner, args).skip_binder();
2338 let skip = if db.function_signature(self.id).has_self_param() { 1 } else { 0 };
2339 callable_sig
2340 .inputs()
2341 .iter()
2342 .enumerate()
2343 .skip(skip)
2344 .map(|(idx, &ty)| {
2345 let ty = Type { env: environment, ty };
2346 Param { func: Callee::Def(CallableDefId::FunctionId(self.id)), ty, idx }
2515 let args = self.adapt_generic_args(interner, generics);
2516 let params = self.params_without_self(db);
2517 params
2518 .into_iter()
2519 .map(|param| Param {
2520 func: param.func,
2521 idx: param.idx,
2522 ty: Type {
2523 env: param.ty.env,
2524 ty: EarlyBinder::bind(param.ty.ty).instantiate(interner, args),
2525 },
23472526 })
23482527 .collect()
23492528 }
23502529
23512530 pub fn is_const(self, db: &dyn HirDatabase) -> bool {
2352 db.function_signature(self.id).is_const()
2531 match self.id {
2532 AnyFunctionId::FunctionId(id) => db.function_signature(id).is_const(),
2533 AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
2534 }
23532535 }
23542536
23552537 pub fn is_async(self, db: &dyn HirDatabase) -> bool {
2356 db.function_signature(self.id).is_async()
2538 match self.id {
2539 AnyFunctionId::FunctionId(id) => db.function_signature(id).is_async(),
2540 AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
2541 }
23572542 }
23582543
23592544 pub fn is_varargs(self, db: &dyn HirDatabase) -> bool {
2360 db.function_signature(self.id).is_varargs()
2545 match self.id {
2546 AnyFunctionId::FunctionId(id) => db.function_signature(id).is_varargs(),
2547 AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
2548 }
23612549 }
23622550
23632551 pub fn extern_block(self, db: &dyn HirDatabase) -> Option<ExternBlock> {
2364 match self.id.lookup(db).container {
2365 ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
2366 _ => None,
2552 match self.id {
2553 AnyFunctionId::FunctionId(id) => match id.lookup(db).container {
2554 ItemContainerId::ExternBlockId(id) => Some(ExternBlock { id }),
2555 _ => None,
2556 },
2557 AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
23672558 }
23682559 }
23692560
......@@ -2396,33 +2587,46 @@ impl Function {
23962587
23972588 /// Does this function have `#[test]` attribute?
23982589 pub fn is_test(self, db: &dyn HirDatabase) -> bool {
2399 self.attrs(db).is_test()
2590 self.attrs(db).contains(AttrFlags::IS_TEST)
24002591 }
24012592
24022593 /// is this a `fn main` or a function with an `export_name` of `main`?
24032594 pub fn is_main(self, db: &dyn HirDatabase) -> bool {
2404 self.exported_main(db)
2405 || self.module(db).is_crate_root(db) && db.function_signature(self.id).name == sym::main
2595 match self.id {
2596 AnyFunctionId::FunctionId(id) => {
2597 self.exported_main(db)
2598 || self.module(db).is_crate_root(db)
2599 && db.function_signature(id).name == sym::main
2600 }
2601 AnyFunctionId::BuiltinDeriveImplMethod { .. } => false,
2602 }
2603 }
2604
2605 fn attrs(self, db: &dyn HirDatabase) -> AttrFlags {
2606 match self.id {
2607 AnyFunctionId::FunctionId(id) => AttrFlags::query(db, id.into()),
2608 AnyFunctionId::BuiltinDeriveImplMethod { .. } => AttrFlags::empty(),
2609 }
24062610 }
24072611
24082612 /// Is this a function with an `export_name` of `main`?
24092613 pub fn exported_main(self, db: &dyn HirDatabase) -> bool {
2410 AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_EXPORT_NAME_MAIN)
2614 self.attrs(db).contains(AttrFlags::IS_EXPORT_NAME_MAIN)
24112615 }
24122616
24132617 /// Does this function have the ignore attribute?
24142618 pub fn is_ignore(self, db: &dyn HirDatabase) -> bool {
2415 AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_IGNORE)
2619 self.attrs(db).contains(AttrFlags::IS_IGNORE)
24162620 }
24172621
24182622 /// Does this function have `#[bench]` attribute?
24192623 pub fn is_bench(self, db: &dyn HirDatabase) -> bool {
2420 AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_BENCH)
2624 self.attrs(db).contains(AttrFlags::IS_BENCH)
24212625 }
24222626
24232627 /// Is this function marked as unstable with `#[feature]` attribute?
24242628 pub fn is_unstable(self, db: &dyn HirDatabase) -> bool {
2425 AttrFlags::query(db, self.id.into()).contains(AttrFlags::IS_UNSTABLE)
2629 self.attrs(db).contains(AttrFlags::IS_UNSTABLE)
24262630 }
24272631
24282632 pub fn is_unsafe_to_call(
......@@ -2431,9 +2635,17 @@ impl Function {
24312635 caller: Option<Function>,
24322636 call_edition: Edition,
24332637 ) -> bool {
2638 let AnyFunctionId::FunctionId(id) = self.id else {
2639 return false;
2640 };
24342641 let (target_features, target_feature_is_safe_in_target) = caller
24352642 .map(|caller| {
2436 let target_features = hir_ty::TargetFeatures::from_fn(db, caller.id);
2643 let target_features = match caller.id {
2644 AnyFunctionId::FunctionId(id) => hir_ty::TargetFeatures::from_fn(db, id),
2645 AnyFunctionId::BuiltinDeriveImplMethod { .. } => {
2646 hir_ty::TargetFeatures::default()
2647 }
2648 };
24372649 let target_feature_is_safe_in_target =
24382650 match &caller.krate(db).id.workspace_data(db).target {
24392651 Ok(target) => hir_ty::target_feature_is_safe_in_target(target),
......@@ -2447,7 +2659,7 @@ impl Function {
24472659 matches!(
24482660 hir_ty::is_fn_unsafe_to_call(
24492661 db,
2450 self.id,
2662 id,
24512663 &target_features,
24522664 call_edition,
24532665 target_feature_is_safe_in_target
......@@ -2460,12 +2672,18 @@ impl Function {
24602672 ///
24612673 /// This is false in the case of required (not provided) trait methods.
24622674 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
2463 db.function_signature(self.id).has_body()
2675 match self.id {
2676 AnyFunctionId::FunctionId(id) => db.function_signature(id).has_body(),
2677 AnyFunctionId::BuiltinDeriveImplMethod { .. } => true,
2678 }
24642679 }
24652680
24662681 pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
2467 let def_map = crate_def_map(db, HasModule::krate(&self.id, db));
2468 def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
2682 let AnyFunctionId::FunctionId(id) = self.id else {
2683 return None;
2684 };
2685 let def_map = crate_def_map(db, HasModule::krate(&id, db));
2686 def_map.fn_as_proc_macro(id).map(|id| Macro { id: id.into() })
24692687 }
24702688
24712689 pub fn eval(
......@@ -2473,13 +2691,18 @@ impl Function {
24732691 db: &dyn HirDatabase,
24742692 span_formatter: impl Fn(FileId, TextRange) -> String,
24752693 ) -> Result<String, ConstEvalError> {
2694 let AnyFunctionId::FunctionId(id) = self.id else {
2695 return Err(ConstEvalError::MirEvalError(MirEvalError::NotSupported(
2696 "evaluation of builtin derive impl methods is not supported".to_owned(),
2697 )));
2698 };
24762699 let interner = DbInterner::new_no_crate(db);
24772700 let body = db.monomorphized_mir_body(
2478 self.id.into(),
2701 id.into(),
24792702 GenericArgs::empty(interner).store(),
24802703 ParamEnvAndCrate {
2481 param_env: db.trait_environment(self.id.into()),
2482 krate: self.id.module(db).krate(db),
2704 param_env: db.trait_environment(id.into()),
2705 krate: id.module(db).krate(db),
24832706 }
24842707 .store(),
24852708 )?;
......@@ -2596,36 +2819,47 @@ impl<'db> Param<'db> {
25962819
25972820#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
25982821pub struct SelfParam {
2599 func: FunctionId,
2822 func: Function,
26002823}
26012824
26022825impl SelfParam {
26032826 pub fn access(self, db: &dyn HirDatabase) -> Access {
2604 let func_data = db.function_signature(self.func);
2605 func_data
2606 .params
2607 .first()
2608 .map(|&param| match &func_data.store[param] {
2609 TypeRef::Reference(ref_) => match ref_.mutability {
2610 hir_def::type_ref::Mutability::Shared => Access::Shared,
2611 hir_def::type_ref::Mutability::Mut => Access::Exclusive,
2612 },
2613 _ => Access::Owned,
2614 })
2615 .unwrap_or(Access::Owned)
2827 match self.func.id {
2828 AnyFunctionId::FunctionId(id) => {
2829 let func_data = db.function_signature(id);
2830 func_data
2831 .params
2832 .first()
2833 .map(|&param| match &func_data.store[param] {
2834 TypeRef::Reference(ref_) => match ref_.mutability {
2835 hir_def::type_ref::Mutability::Shared => Access::Shared,
2836 hir_def::type_ref::Mutability::Mut => Access::Exclusive,
2837 },
2838 _ => Access::Owned,
2839 })
2840 .unwrap_or(Access::Owned)
2841 }
2842 AnyFunctionId::BuiltinDeriveImplMethod { method, .. } => match method {
2843 BuiltinDeriveImplMethod::clone
2844 | BuiltinDeriveImplMethod::fmt
2845 | BuiltinDeriveImplMethod::hash
2846 | BuiltinDeriveImplMethod::cmp
2847 | BuiltinDeriveImplMethod::partial_cmp
2848 | BuiltinDeriveImplMethod::eq => Access::Shared,
2849 BuiltinDeriveImplMethod::default => {
2850 unreachable!("this function does not have a self param")
2851 }
2852 },
2853 }
26162854 }
26172855
26182856 pub fn parent_fn(&self) -> Function {
2619 Function::from(self.func)
2857 self.func
26202858 }
26212859
26222860 pub fn ty<'db>(&self, db: &'db dyn HirDatabase) -> Type<'db> {
2623 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
2624 let callable_sig =
2625 db.callable_item_signature(self.func.into()).instantiate_identity().skip_binder();
2626 let environment = param_env_from_has_crate(db, self.func);
2627 let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0];
2628 Type { env: environment, ty }
2861 let (env, sig) = self.func.fn_sig(db);
2862 Type { env, ty: sig.skip_binder().inputs()[0] }
26292863 }
26302864
26312865 // FIXME: Find better API to also handle const generics
......@@ -2635,18 +2869,18 @@ impl SelfParam {
26352869 generics: impl Iterator<Item = Type<'db>>,
26362870 ) -> Type<'db> {
26372871 let interner = DbInterner::new_no_crate(db);
2638 let args = generic_args_from_tys(interner, self.func.into(), generics.map(|ty| ty.ty));
2639 let callable_sig =
2640 db.callable_item_signature(self.func.into()).instantiate(interner, args).skip_binder();
2641 let environment = param_env_from_has_crate(db, self.func);
2642 let ty = rustc_type_ir::inherent::SliceLike::as_slice(&callable_sig.inputs())[0];
2643 Type { env: environment, ty }
2872 let args = self.func.adapt_generic_args(interner, generics);
2873 let Type { env, ty } = self.ty(db);
2874 Type { env, ty: EarlyBinder::bind(ty).instantiate(interner, args) }
26442875 }
26452876}
26462877
26472878impl HasVisibility for Function {
26482879 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
2649 db.assoc_visibility(self.id.into())
2880 match self.id {
2881 AnyFunctionId::FunctionId(id) => db.assoc_visibility(id.into()),
2882 AnyFunctionId::BuiltinDeriveImplMethod { .. } => Visibility::Public,
2883 }
26502884 }
26512885}
26522886
......@@ -2870,7 +3104,7 @@ impl Trait {
28703104 pub fn function(self, db: &dyn HirDatabase, name: impl PartialEq<Name>) -> Option<Function> {
28713105 self.id.trait_items(db).items.iter().find(|(n, _)| name == *n).and_then(|&(_, it)| match it
28723106 {
2873 AssocItemId::FunctionId(id) => Some(Function { id }),
3107 AssocItemId::FunctionId(id) => Some(id.into()),
28743108 _ => None,
28753109 })
28763110 }
......@@ -3151,15 +3385,15 @@ impl Macro {
31513385 )
31523386 }
31533387
3154 pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> bool {
3155 match self.id {
3156 MacroId::Macro2Id(it) => {
3157 matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_))
3158 }
3159 MacroId::MacroRulesId(it) => {
3160 matches!(it.lookup(db).expander, MacroExpander::BuiltInDerive(_))
3161 }
3162 MacroId::ProcMacroId(_) => false,
3388 pub fn builtin_derive_kind(&self, db: &dyn HirDatabase) -> Option<BuiltinDeriveMacroKind> {
3389 let expander = match self.id {
3390 MacroId::Macro2Id(it) => it.lookup(db).expander,
3391 MacroId::MacroRulesId(it) => it.lookup(db).expander,
3392 MacroId::ProcMacroId(_) => return None,
3393 };
3394 match expander {
3395 MacroExpander::BuiltInDerive(kind) => Some(BuiltinDeriveMacroKind(kind)),
3396 _ => None,
31633397 }
31643398 }
31653399
......@@ -3195,8 +3429,55 @@ impl Macro {
31953429 pub fn is_derive(&self, db: &dyn HirDatabase) -> bool {
31963430 matches!(self.kind(db), MacroKind::Derive | MacroKind::DeriveBuiltIn)
31973431 }
3432
3433 pub fn preferred_brace_style(&self, db: &dyn HirDatabase) -> Option<MacroBraces> {
3434 let attrs = self.attrs(db);
3435 MacroBraces::extract(attrs.attrs)
3436 }
3437}
3438
3439// Feature: Macro Brace Style Attribute
3440// Crate authors can declare the preferred brace style for their macro. This will affect how completion
3441// insert calls to it.
3442//
3443// This is only supported on function-like macros.
3444//
3445// To do that, insert the `#[rust_analyzer::macro_style(style)]` attribute on the macro (for proc macros,
3446// insert it for the macro's function). `style` can be one of:
3447//
3448// - `braces` for `{...}` style.
3449// - `brackets` for `[...]` style.
3450// - `parentheses` for `(...)` style.
3451//
3452// Malformed attributes will be ignored without warnings.
3453//
3454// Note that users have no way to override this attribute, so be careful and only include things
3455// users definitely do not want to be completed!
3456
3457#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
3458pub enum MacroBraces {
3459 Braces,
3460 Brackets,
3461 Parentheses,
3462}
3463
3464impl MacroBraces {
3465 fn extract(attrs: AttrFlags) -> Option<Self> {
3466 if attrs.contains(AttrFlags::MACRO_STYLE_BRACES) {
3467 Some(Self::Braces)
3468 } else if attrs.contains(AttrFlags::MACRO_STYLE_BRACKETS) {
3469 Some(Self::Brackets)
3470 } else if attrs.contains(AttrFlags::MACRO_STYLE_PARENTHESES) {
3471 Some(Self::Parentheses)
3472 } else {
3473 None
3474 }
3475 }
31983476}
31993477
3478#[derive(Clone, Copy, PartialEq, Eq, Hash)]
3479pub struct BuiltinDeriveMacroKind(BuiltinDeriveExpander);
3480
32003481impl HasVisibility for Macro {
32013482 fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
32023483 match self.id {
......@@ -3275,7 +3556,10 @@ pub trait AsExternAssocItem {
32753556
32763557impl AsExternAssocItem for Function {
32773558 fn as_extern_assoc_item(self, db: &dyn HirDatabase) -> Option<ExternAssocItem> {
3278 as_extern_assoc_item(db, ExternAssocItem::Function, self.id)
3559 let AnyFunctionId::FunctionId(id) = self.id else {
3560 return None;
3561 };
3562 as_extern_assoc_item(db, ExternAssocItem::Function, id)
32793563 }
32803564}
32813565
......@@ -3303,7 +3587,7 @@ pub enum AssocItem {
33033587impl From<method_resolution::CandidateId> for AssocItem {
33043588 fn from(value: method_resolution::CandidateId) -> Self {
33053589 match value {
3306 method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(Function { id }),
3590 method_resolution::CandidateId::FunctionId(id) => AssocItem::Function(id.into()),
33073591 method_resolution::CandidateId::ConstId(id) => AssocItem::Const(Const { id }),
33083592 }
33093593 }
......@@ -3321,7 +3605,10 @@ pub trait AsAssocItem {
33213605
33223606impl AsAssocItem for Function {
33233607 fn as_assoc_item(self, db: &dyn HirDatabase) -> Option<AssocItem> {
3324 as_assoc_item(db, AssocItem::Function, self.id)
3608 match self.id {
3609 AnyFunctionId::FunctionId(id) => as_assoc_item(db, AssocItem::Function, id),
3610 AnyFunctionId::BuiltinDeriveImplMethod { .. } => Some(AssocItem::Function(self)),
3611 }
33253612 }
33263613}
33273614
......@@ -3450,7 +3737,14 @@ impl AssocItem {
34503737
34513738 pub fn container(self, db: &dyn HirDatabase) -> AssocItemContainer {
34523739 let container = match self {
3453 AssocItem::Function(it) => it.id.lookup(db).container,
3740 AssocItem::Function(it) => match it.id {
3741 AnyFunctionId::FunctionId(id) => id.lookup(db).container,
3742 AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
3743 return AssocItemContainer::Impl(Impl {
3744 id: AnyImplId::BuiltinDeriveImplId(impl_),
3745 });
3746 }
3747 },
34543748 AssocItem::Const(it) => it.id.lookup(db).container,
34553749 AssocItem::TypeAlias(it) => it.id.lookup(db).container,
34563750 };
......@@ -3587,9 +3881,13 @@ impl_from!(
35873881
35883882impl GenericDef {
35893883 pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
3590 let generics = db.generic_params(self.into());
3884 let Ok(id) = self.try_into() else {
3885 // Let's pretend builtin derive impls don't have generic parameters.
3886 return Vec::new();
3887 };
3888 let generics = db.generic_params(id);
35913889 let ty_params = generics.iter_type_or_consts().map(|(local_id, _)| {
3592 let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
3890 let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: id, local_id } };
35933891 match toc.split(db) {
35943892 Either::Left(it) => GenericParam::ConstParam(it),
35953893 Either::Right(it) => GenericParam::TypeParam(it),
......@@ -3603,39 +3901,51 @@ impl GenericDef {
36033901 }
36043902
36053903 pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec<LifetimeParam> {
3606 let generics = db.generic_params(self.into());
3904 let Ok(id) = self.try_into() else {
3905 // Let's pretend builtin derive impls don't have generic parameters.
3906 return Vec::new();
3907 };
3908 let generics = db.generic_params(id);
36073909 generics
36083910 .iter_lt()
3609 .map(|(local_id, _)| LifetimeParam {
3610 id: LifetimeParamId { parent: self.into(), local_id },
3611 })
3911 .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: id, local_id } })
36123912 .collect()
36133913 }
36143914
36153915 pub fn type_or_const_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
3616 let generics = db.generic_params(self.into());
3916 let Ok(id) = self.try_into() else {
3917 // Let's pretend builtin derive impls don't have generic parameters.
3918 return Vec::new();
3919 };
3920 let generics = db.generic_params(id);
36173921 generics
36183922 .iter_type_or_consts()
36193923 .map(|(local_id, _)| TypeOrConstParam {
3620 id: TypeOrConstParamId { parent: self.into(), local_id },
3924 id: TypeOrConstParamId { parent: id, local_id },
36213925 })
36223926 .collect()
36233927 }
36243928
3625 fn id(self) -> GenericDefId {
3626 match self {
3627 GenericDef::Function(it) => it.id.into(),
3929 fn id(self) -> Option<GenericDefId> {
3930 Some(match self {
3931 GenericDef::Function(it) => match it.id {
3932 AnyFunctionId::FunctionId(it) => it.into(),
3933 AnyFunctionId::BuiltinDeriveImplMethod { .. } => return None,
3934 },
36283935 GenericDef::Adt(it) => it.into(),
36293936 GenericDef::Trait(it) => it.id.into(),
36303937 GenericDef::TypeAlias(it) => it.id.into(),
3631 GenericDef::Impl(it) => it.id.into(),
3938 GenericDef::Impl(it) => match it.id {
3939 AnyImplId::ImplId(it) => it.into(),
3940 AnyImplId::BuiltinDeriveImplId(_) => return None,
3941 },
36323942 GenericDef::Const(it) => it.id.into(),
36333943 GenericDef::Static(it) => it.id.into(),
3634 }
3944 })
36353945 }
36363946
36373947 pub fn diagnostics<'db>(self, db: &'db dyn HirDatabase, acc: &mut Vec<AnyDiagnostic<'db>>) {
3638 let def = self.id();
3948 let Some(def) = self.id() else { return };
36393949
36403950 let generics = db.generic_params(def);
36413951
......@@ -3708,6 +4018,17 @@ impl<'db> GenericSubstitution<'db> {
37084018 Self { def, subst, env }
37094019 }
37104020
4021 fn new_from_fn(
4022 def: Function,
4023 subst: GenericArgs<'db>,
4024 env: ParamEnvAndCrate<'db>,
4025 ) -> Option<Self> {
4026 match def.id {
4027 AnyFunctionId::FunctionId(def) => Some(Self::new(def.into(), subst, env)),
4028 AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
4029 }
4030 }
4031
37114032 pub fn types(&self, db: &'db dyn HirDatabase) -> Vec<(Symbol, Type<'db>)> {
37124033 let container = match self.def {
37134034 GenericDefId::ConstId(id) => Some(id.lookup(db).container),
......@@ -3820,7 +4141,9 @@ impl Local {
38204141
38214142 pub fn as_self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
38224143 match self.parent {
3823 DefWithBodyId::FunctionId(func) if self.is_self(db) => Some(SelfParam { func }),
4144 DefWithBodyId::FunctionId(func) if self.is_self(db) => {
4145 Some(SelfParam { func: func.into() })
4146 }
38244147 _ => None,
38254148 }
38264149 }
......@@ -4308,7 +4631,7 @@ impl TypeOrConstParam {
43084631
43094632#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
43104633pub struct Impl {
4311 pub(crate) id: ImplId,
4634 pub(crate) id: AnyImplId,
43124635}
43134636
43144637impl Impl {
......@@ -4320,6 +4643,7 @@ impl Impl {
43204643 fn extend_with_def_map(db: &dyn HirDatabase, def_map: &DefMap, result: &mut Vec<Impl>) {
43214644 for (_, module) in def_map.modules() {
43224645 result.extend(module.scope.impls().map(Impl::from));
4646 result.extend(module.scope.builtin_derive_impls().map(Impl::from));
43234647
43244648 for unnamed_const in module.scope.unnamed_consts() {
43254649 for (_, block_def_map) in db.body(unnamed_const.into()).blocks(db) {
......@@ -4331,7 +4655,7 @@ impl Impl {
43314655 }
43324656
43334657 pub fn all_in_module(db: &dyn HirDatabase, module: Module) -> Vec<Impl> {
4334 module.id.def_map(db)[module.id].scope.impls().map(Into::into).collect()
4658 module.impl_defs(db)
43354659 }
43364660
43374661 /// **Note:** This is an **approximation** that strives to give the *human-perceived notion* of an "impl for type",
......@@ -4347,20 +4671,19 @@ impl Impl {
43474671 else {
43484672 return Vec::new();
43494673 };
4350 let mut extend_with_impls =
4351 |impls: &[ImplId]| result.extend(impls.iter().copied().map(Impl::from));
4352 method_resolution::with_incoherent_inherent_impls(
4353 db,
4354 env.krate,
4355 &simplified_ty,
4356 &mut extend_with_impls,
4357 );
4674 let mut extend_with_impls = |impls: Either<&[ImplId], &[BuiltinDeriveImplId]>| match impls {
4675 Either::Left(impls) => result.extend(impls.iter().copied().map(Impl::from)),
4676 Either::Right(impls) => result.extend(impls.iter().copied().map(Impl::from)),
4677 };
4678 method_resolution::with_incoherent_inherent_impls(db, env.krate, &simplified_ty, |impls| {
4679 extend_with_impls(Either::Left(impls))
4680 });
43584681 if let Some(module) = method_resolution::simplified_type_module(db, &simplified_ty) {
43594682 InherentImpls::for_each_crate_and_block(
43604683 db,
43614684 module.krate(db),
43624685 module.block(db),
4363 &mut |impls| extend_with_impls(impls.for_self_ty(&simplified_ty)),
4686 &mut |impls| extend_with_impls(Either::Left(impls.for_self_ty(&simplified_ty))),
43644687 );
43654688 std::iter::successors(module.block(db), |block| block.loc(db).module.block(db))
43664689 .filter_map(|block| TraitImpls::for_block(db, block).as_deref())
......@@ -4382,7 +4705,10 @@ impl Impl {
43824705 let module = trait_.module(db).id;
43834706 let mut all = Vec::new();
43844707 let mut handle_impls = |impls: &TraitImpls| {
4385 impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from)));
4708 impls.for_trait(trait_.id, |impls| match impls {
4709 Either::Left(impls) => all.extend(impls.iter().copied().map(Impl::from)),
4710 Either::Right(impls) => all.extend(impls.iter().copied().map(Impl::from)),
4711 });
43864712 };
43874713 for krate in module.krate(db).transitive_rev_deps(db) {
43884714 handle_impls(TraitImpls::for_crate(db, krate));
......@@ -4396,75 +4722,118 @@ impl Impl {
43964722 }
43974723
43984724 pub fn trait_(self, db: &dyn HirDatabase) -> Option<Trait> {
4399 let trait_ref = db.impl_trait(self.id)?;
4400 let id = trait_ref.skip_binder().def_id;
4401 Some(Trait { id: id.0 })
4725 match self.id {
4726 AnyImplId::ImplId(id) => {
4727 let trait_ref = db.impl_trait(id)?;
4728 let id = trait_ref.skip_binder().def_id;
4729 Some(Trait { id: id.0 })
4730 }
4731 AnyImplId::BuiltinDeriveImplId(id) => {
4732 let loc = id.loc(db);
4733 let lang_items = hir_def::lang_item::lang_items(db, loc.adt.module(db).krate(db));
4734 loc.trait_.get_id(lang_items).map(Trait::from)
4735 }
4736 }
44024737 }
44034738
44044739 pub fn trait_ref(self, db: &dyn HirDatabase) -> Option<TraitRef<'_>> {
4405 let trait_ref = db.impl_trait(self.id)?.instantiate_identity();
4406 let resolver = self.id.resolver(db);
4407 Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
4740 match self.id {
4741 AnyImplId::ImplId(id) => {
4742 let trait_ref = db.impl_trait(id)?.instantiate_identity();
4743 let resolver = id.resolver(db);
4744 Some(TraitRef::new_with_resolver(db, &resolver, trait_ref))
4745 }
4746 AnyImplId::BuiltinDeriveImplId(id) => {
4747 let loc = id.loc(db);
4748 let krate = loc.module(db).krate(db);
4749 let interner = DbInterner::new_with(db, krate);
4750 let env = ParamEnvAndCrate {
4751 param_env: hir_ty::builtin_derive::param_env(interner, id),
4752 krate,
4753 };
4754 let trait_ref =
4755 hir_ty::builtin_derive::impl_trait(interner, id).instantiate_identity();
4756 Some(TraitRef { env, trait_ref })
4757 }
4758 }
44084759 }
44094760
44104761 pub fn self_ty(self, db: &dyn HirDatabase) -> Type<'_> {
4411 let resolver = self.id.resolver(db);
4412 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
4413 let ty = db.impl_self_ty(self.id).instantiate_identity();
4414 Type::new_with_resolver_inner(db, &resolver, ty)
4762 match self.id {
4763 AnyImplId::ImplId(id) => {
4764 let resolver = id.resolver(db);
4765 // FIXME: This shouldn't be `instantiate_identity()`, we shouldn't leak `TyKind::Param`s.
4766 let ty = db.impl_self_ty(id).instantiate_identity();
4767 Type::new_with_resolver_inner(db, &resolver, ty)
4768 }
4769 AnyImplId::BuiltinDeriveImplId(id) => {
4770 let loc = id.loc(db);
4771 let krate = loc.module(db).krate(db);
4772 let interner = DbInterner::new_with(db, krate);
4773 let env = ParamEnvAndCrate {
4774 param_env: hir_ty::builtin_derive::param_env(interner, id),
4775 krate,
4776 };
4777 let ty = hir_ty::builtin_derive::impl_trait(interner, id)
4778 .instantiate_identity()
4779 .self_ty();
4780 Type { env, ty }
4781 }
4782 }
44154783 }
44164784
44174785 pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> {
4418 self.id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
4786 match self.id {
4787 AnyImplId::ImplId(id) => {
4788 id.impl_items(db).items.iter().map(|&(_, it)| it.into()).collect()
4789 }
4790 AnyImplId::BuiltinDeriveImplId(impl_) => impl_
4791 .loc(db)
4792 .trait_
4793 .all_methods()
4794 .iter()
4795 .map(|&method| {
4796 AssocItem::Function(Function {
4797 id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ },
4798 })
4799 })
4800 .collect(),
4801 }
44194802 }
44204803
44214804 pub fn is_negative(self, db: &dyn HirDatabase) -> bool {
4422 db.impl_signature(self.id).flags.contains(ImplFlags::NEGATIVE)
4805 match self.id {
4806 AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::NEGATIVE),
4807 AnyImplId::BuiltinDeriveImplId(_) => false,
4808 }
44234809 }
44244810
44254811 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
4426 db.impl_signature(self.id).flags.contains(ImplFlags::UNSAFE)
4812 match self.id {
4813 AnyImplId::ImplId(id) => db.impl_signature(id).flags.contains(ImplFlags::UNSAFE),
4814 AnyImplId::BuiltinDeriveImplId(_) => false,
4815 }
44274816 }
44284817
44294818 pub fn module(self, db: &dyn HirDatabase) -> Module {
4430 self.id.lookup(db).container.into()
4431 }
4432
4433 pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option<InMacroFile<ast::Path>> {
4434 let src = self.source(db)?;
4435
4436 let macro_file = src.file_id.macro_file()?;
4437 let loc = macro_file.lookup(db);
4438 let (derive_attr, derive_index) = match loc.kind {
4439 MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
4440 let module_id = self.id.lookup(db).container;
4441 (
4442 module_id.def_map(db)[module_id]
4443 .scope
4444 .derive_macro_invoc(ast_id, derive_attr_index)?,
4445 derive_index,
4446 )
4447 }
4448 _ => return None,
4449 };
4450 let path = db
4451 .parse_macro_expansion(derive_attr)
4452 .value
4453 .0
4454 .syntax_node()
4455 .children()
4456 .nth(derive_index as usize)
4457 .and_then(<ast::Attr as AstNode>::cast)
4458 .and_then(|it| it.path())?;
4459 Some(InMacroFile { file_id: derive_attr, value: path })
4819 match self.id {
4820 AnyImplId::ImplId(id) => id.module(db).into(),
4821 AnyImplId::BuiltinDeriveImplId(id) => id.module(db).into(),
4822 }
44604823 }
44614824
44624825 pub fn check_orphan_rules(self, db: &dyn HirDatabase) -> bool {
4463 check_orphan_rules(db, self.id)
4826 match self.id {
4827 AnyImplId::ImplId(id) => check_orphan_rules(db, id),
4828 AnyImplId::BuiltinDeriveImplId(_) => true,
4829 }
44644830 }
44654831
44664832 fn all_macro_calls(&self, db: &dyn HirDatabase) -> Box<[(AstId<ast::Item>, MacroCallId)]> {
4467 self.id.impl_items(db).macro_calls.to_vec().into_boxed_slice()
4833 match self.id {
4834 AnyImplId::ImplId(id) => id.impl_items(db).macro_calls.to_vec().into_boxed_slice(),
4835 AnyImplId::BuiltinDeriveImplId(_) => Box::default(),
4836 }
44684837 }
44694838}
44704839
......@@ -5540,7 +5909,7 @@ impl<'db> Type<'db> {
55405909 else {
55415910 unreachable!("`Mode::MethodCall` can only return functions");
55425911 };
5543 let id = Function { id };
5912 let id = Function { id: AnyFunctionId::FunctionId(id) };
55445913 match candidate.kind {
55455914 method_resolution::PickKind::InherentImplPick(_)
55465915 | method_resolution::PickKind::ObjectPick(..)
......@@ -5564,7 +5933,7 @@ impl<'db> Type<'db> {
55645933 else {
55655934 unreachable!("`Mode::MethodCall` can only return functions");
55665935 };
5567 let id = Function { id };
5936 let id = Function { id: AnyFunctionId::FunctionId(id) };
55685937 match candidate.candidate.kind {
55695938 method_resolution::CandidateKind::InherentImplCandidate {
55705939 ..
......@@ -5919,6 +6288,7 @@ enum Callee<'db> {
59196288 CoroutineClosure(InternedCoroutineId, GenericArgs<'db>),
59206289 FnPtr,
59216290 FnImpl(traits::FnTrait),
6291 BuiltinDeriveImplMethod { method: BuiltinDeriveImplMethod, impl_: BuiltinDeriveImplId },
59226292}
59236293
59246294pub enum CallableKind<'db> {
......@@ -5934,6 +6304,9 @@ impl<'db> Callable<'db> {
59346304 pub fn kind(&self) -> CallableKind<'db> {
59356305 match self.callee {
59366306 Callee::Def(CallableDefId::FunctionId(it)) => CallableKind::Function(it.into()),
6307 Callee::BuiltinDeriveImplMethod { method, impl_ } => CallableKind::Function(Function {
6308 id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ },
6309 }),
59376310 Callee::Def(CallableDefId::StructId(it)) => CallableKind::TupleStruct(it.into()),
59386311 Callee::Def(CallableDefId::EnumVariantId(it)) => {
59396312 CallableKind::TupleEnumVariant(it.into())
......@@ -5948,12 +6321,22 @@ impl<'db> Callable<'db> {
59486321 Callee::FnImpl(fn_) => CallableKind::FnImpl(fn_.into()),
59496322 }
59506323 }
6324
6325 fn as_function(&self) -> Option<Function> {
6326 match self.callee {
6327 Callee::Def(CallableDefId::FunctionId(it)) => Some(it.into()),
6328 Callee::BuiltinDeriveImplMethod { method, impl_ } => {
6329 Some(Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } })
6330 }
6331 _ => None,
6332 }
6333 }
6334
59516335 pub fn receiver_param(&self, db: &'db dyn HirDatabase) -> Option<(SelfParam, Type<'db>)> {
5952 let func = match self.callee {
5953 Callee::Def(CallableDefId::FunctionId(it)) if self.is_bound_method => it,
5954 _ => return None,
5955 };
5956 let func = Function { id: func };
6336 if !self.is_bound_method {
6337 return None;
6338 }
6339 let func = self.as_function()?;
59576340 Some((
59586341 func.self_param(db)?,
59596342 self.ty.derived(self.sig.skip_binder().inputs_and_output.inputs()[0]),
......@@ -6350,7 +6733,12 @@ impl HasContainer for Module {
63506733
63516734impl HasContainer for Function {
63526735 fn container(&self, db: &dyn HirDatabase) -> ItemContainer {
6353 container_id_to_hir(self.id.lookup(db).container)
6736 match self.id {
6737 AnyFunctionId::FunctionId(id) => container_id_to_hir(id.lookup(db).container),
6738 AnyFunctionId::BuiltinDeriveImplMethod { impl_, .. } => {
6739 ItemContainer::Impl(Impl { id: AnyImplId::BuiltinDeriveImplId(impl_) })
6740 }
6741 }
63546742 }
63556743}
63566744
......@@ -6402,11 +6790,79 @@ impl HasContainer for ExternBlock {
64026790 }
64036791}
64046792
6793pub trait HasName {
6794 fn name(&self, db: &dyn HirDatabase) -> Option<Name>;
6795}
6796
6797macro_rules! impl_has_name {
6798 ( $( $ty:ident ),* $(,)? ) => {
6799 $(
6800 impl HasName for $ty {
6801 fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
6802 (*self).name(db).into()
6803 }
6804 }
6805 )*
6806 };
6807}
6808
6809impl_has_name!(
6810 ModuleDef,
6811 Module,
6812 Field,
6813 Struct,
6814 Union,
6815 Enum,
6816 Variant,
6817 Adt,
6818 VariantDef,
6819 DefWithBody,
6820 Function,
6821 ExternCrateDecl,
6822 Const,
6823 Static,
6824 Trait,
6825 TypeAlias,
6826 Macro,
6827 ExternAssocItem,
6828 AssocItem,
6829 Local,
6830 DeriveHelper,
6831 ToolModule,
6832 Label,
6833 GenericParam,
6834 TypeParam,
6835 LifetimeParam,
6836 ConstParam,
6837 TypeOrConstParam,
6838 InlineAsmOperand,
6839);
6840
6841macro_rules! impl_has_name_no_db {
6842 ( $( $ty:ident ),* $(,)? ) => {
6843 $(
6844 impl HasName for $ty {
6845 fn name(&self, _db: &dyn HirDatabase) -> Option<Name> {
6846 (*self).name().into()
6847 }
6848 }
6849 )*
6850 };
6851}
6852
6853impl_has_name_no_db!(TupleField, StaticLifetime, BuiltinType, BuiltinAttr);
6854
6855impl HasName for Param<'_> {
6856 fn name(&self, db: &dyn HirDatabase) -> Option<Name> {
6857 self.name(db)
6858 }
6859}
6860
64056861fn container_id_to_hir(c: ItemContainerId) -> ItemContainer {
64066862 match c {
64076863 ItemContainerId::ExternBlockId(id) => ItemContainer::ExternBlock(ExternBlock { id }),
64086864 ItemContainerId::ModuleId(id) => ItemContainer::Module(Module { id }),
6409 ItemContainerId::ImplId(id) => ItemContainer::Impl(Impl { id }),
6865 ItemContainerId::ImplId(id) => ItemContainer::Impl(id.into()),
64106866 ItemContainerId::TraitId(id) => ItemContainer::Trait(Trait { id }),
64116867 }
64126868}
src/tools/rust-analyzer/crates/hir/src/semantics.rs+54-30
......@@ -13,7 +13,7 @@ use std::{
1313use base_db::FxIndexSet;
1414use either::Either;
1515use hir_def::{
16 DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
16 DefWithBodyId, MacroId, StructId, TraitId, VariantId,
1717 attrs::parse_extra_crate_attrs,
1818 expr_store::{Body, ExprOrPatSource, HygieneId, path::Path},
1919 hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
......@@ -34,7 +34,7 @@ use hir_ty::{
3434 diagnostics::{unsafe_operations, unsafe_operations_for_body},
3535 infer_query_with_inspect,
3636 next_solver::{
37 DbInterner, Span,
37 AnyImplId, DbInterner, Span,
3838 format_proof_tree::{ProofTreeData, dump_proof_tree_structured},
3939 },
4040};
......@@ -53,11 +53,11 @@ use syntax::{
5353};
5454
5555use crate::{
56 Adjust, Adjustment, Adt, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const, ConstParam,
57 Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution, HasSource, Impl,
58 InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro, Module, ModuleDef,
59 Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait, TupleField, Type,
60 TypeAlias, TypeParam, Union, Variant, VariantDef,
56 Adjust, Adjustment, Adt, AnyFunctionId, AutoBorrow, BindingMode, BuiltinAttr, Callable, Const,
57 ConstParam, Crate, DefWithBody, DeriveHelper, Enum, Field, Function, GenericSubstitution,
58 HasSource, Impl, InFile, InlineAsmOperand, ItemInNs, Label, LifetimeParam, Local, Macro,
59 Module, ModuleDef, Name, OverloadedDeref, ScopeDef, Static, Struct, ToolModule, Trait,
60 TupleField, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
6161 db::HirDatabase,
6262 semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
6363 source_analyzer::{SourceAnalyzer, resolve_hir_path},
......@@ -106,7 +106,10 @@ impl PathResolution {
106106 | PathResolution::DeriveHelper(_)
107107 | PathResolution::ConstParam(_) => None,
108108 PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
109 PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
109 PathResolution::SelfType(impl_def) => match impl_def.id {
110 AnyImplId::ImplId(id) => Some(TypeNs::SelfType(id)),
111 AnyImplId::BuiltinDeriveImplId(_) => None,
112 },
110113 }
111114 }
112115}
......@@ -345,23 +348,23 @@ impl<DB: HirDatabase + ?Sized> Semantics<'_, DB> {
345348 }
346349
347350 pub fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
348 self.imp.resolve_await_to_poll(await_expr).map(Function::from)
351 self.imp.resolve_await_to_poll(await_expr)
349352 }
350353
351354 pub fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
352 self.imp.resolve_prefix_expr(prefix_expr).map(Function::from)
355 self.imp.resolve_prefix_expr(prefix_expr)
353356 }
354357
355358 pub fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
356 self.imp.resolve_index_expr(index_expr).map(Function::from)
359 self.imp.resolve_index_expr(index_expr)
357360 }
358361
359362 pub fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
360 self.imp.resolve_bin_expr(bin_expr).map(Function::from)
363 self.imp.resolve_bin_expr(bin_expr)
361364 }
362365
363366 pub fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
364 self.imp.resolve_try_expr(try_expr).map(Function::from)
367 self.imp.resolve_try_expr(try_expr)
365368 }
366369
367370 pub fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantDef> {
......@@ -833,7 +836,7 @@ impl<'db> SemanticsImpl<'db> {
833836 // FIXME: Type the return type
834837 /// Returns the range (pre-expansion) in the string literal corresponding to the resolution,
835838 /// absolute file range (post-expansion)
836 /// of the part in the format string, the corresponding string token and the resolution if it
839 /// of the part in the format string (post-expansion), the corresponding string token and the resolution if it
837840 /// exists.
838841 // FIXME: Remove this in favor of `check_for_format_args_template_with_file`
839842 pub fn check_for_format_args_template(
......@@ -1749,6 +1752,7 @@ impl<'db> SemanticsImpl<'db> {
17491752 func: Function,
17501753 subst: impl IntoIterator<Item = Type<'db>>,
17511754 ) -> Option<Function> {
1755 let AnyFunctionId::FunctionId(func) = func.id else { return Some(func) };
17521756 let interner = DbInterner::new_no_crate(self.db);
17531757 let mut subst = subst.into_iter();
17541758 let substs =
......@@ -1757,7 +1761,12 @@ impl<'db> SemanticsImpl<'db> {
17571761 subst.next().expect("too few subst").ty.into()
17581762 });
17591763 assert!(subst.next().is_none(), "too many subst");
1760 Some(self.db.lookup_impl_method(env.env, func.into(), substs).0.into())
1764 Some(match self.db.lookup_impl_method(env.env, func, substs).0 {
1765 Either::Left(it) => it.into(),
1766 Either::Right((impl_, method)) => {
1767 Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }
1768 }
1769 })
17611770 }
17621771
17631772 fn resolve_range_pat(&self, range_pat: &ast::RangePat) -> Option<StructId> {
......@@ -1768,23 +1777,23 @@ impl<'db> SemanticsImpl<'db> {
17681777 self.analyze(range_expr.syntax())?.resolve_range_expr(self.db, range_expr)
17691778 }
17701779
1771 fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<FunctionId> {
1780 fn resolve_await_to_poll(&self, await_expr: &ast::AwaitExpr) -> Option<Function> {
17721781 self.analyze(await_expr.syntax())?.resolve_await_to_poll(self.db, await_expr)
17731782 }
17741783
1775 fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<FunctionId> {
1784 fn resolve_prefix_expr(&self, prefix_expr: &ast::PrefixExpr) -> Option<Function> {
17761785 self.analyze(prefix_expr.syntax())?.resolve_prefix_expr(self.db, prefix_expr)
17771786 }
17781787
1779 fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<FunctionId> {
1788 fn resolve_index_expr(&self, index_expr: &ast::IndexExpr) -> Option<Function> {
17801789 self.analyze(index_expr.syntax())?.resolve_index_expr(self.db, index_expr)
17811790 }
17821791
1783 fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<FunctionId> {
1792 fn resolve_bin_expr(&self, bin_expr: &ast::BinExpr) -> Option<Function> {
17841793 self.analyze(bin_expr.syntax())?.resolve_bin_expr(self.db, bin_expr)
17851794 }
17861795
1787 fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<FunctionId> {
1796 fn resolve_try_expr(&self, try_expr: &ast::TryExpr) -> Option<Function> {
17881797 self.analyze(try_expr.syntax())?.resolve_try_expr(self.db, try_expr)
17891798 }
17901799
......@@ -1861,7 +1870,9 @@ impl<'db> SemanticsImpl<'db> {
18611870 }
18621871
18631872 pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
1864 let def = DefWithBodyId::from(def);
1873 let Ok(def) = DefWithBodyId::try_from(def) else {
1874 return FxHashSet::default();
1875 };
18651876 let (body, source_map) = self.db.body_with_source_map(def);
18661877 let infer = InferenceResult::for_body(self.db, def);
18671878 let mut res = FxHashSet::default();
......@@ -1877,7 +1888,9 @@ impl<'db> SemanticsImpl<'db> {
18771888 always!(block.unsafe_token().is_some());
18781889 let block = self.wrap_node_infile(ast::Expr::from(block));
18791890 let Some(def) = self.body_for(block.syntax()) else { return Vec::new() };
1880 let def = def.into();
1891 let Ok(def) = def.try_into() else {
1892 return Vec::new();
1893 };
18811894 let (body, source_map) = self.db.body_with_source_map(def);
18821895 let infer = InferenceResult::for_body(self.db, def);
18831896 let Some(ExprOrPatId::ExprId(block)) = source_map.node_expr(block.as_ref()) else {
......@@ -2023,16 +2036,22 @@ impl<'db> SemanticsImpl<'db> {
20232036 }
20242037
20252038 /// Search for a definition's source and cache its syntax tree
2026 pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>>
2027 where
2028 Def::Ast: AstNode,
2029 {
2039 pub fn source<Def: HasSource>(&self, def: Def) -> Option<InFile<Def::Ast>> {
20302040 // FIXME: source call should go through the parse cache
20312041 let res = def.source(self.db)?;
20322042 self.cache(find_root(res.value.syntax()), res.file_id);
20332043 Some(res)
20342044 }
20352045
2046 pub fn source_with_range<Def: HasSource>(
2047 &self,
2048 def: Def,
2049 ) -> Option<InFile<(TextRange, Option<Def::Ast>)>> {
2050 let res = def.source_with_range(self.db)?;
2051 self.parse_or_expand(res.file_id);
2052 Some(res)
2053 }
2054
20362055 pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
20372056 let container = self.with_ctx(|ctx| ctx.find_container(node))?;
20382057
......@@ -2162,9 +2181,10 @@ impl<'db> SemanticsImpl<'db> {
21622181
21632182 let def = match &enclosing_item {
21642183 Either::Left(ast::Item::Fn(it)) if it.unsafe_token().is_some() => return true,
2165 Either::Left(ast::Item::Fn(it)) => {
2166 self.to_def(it).map(<_>::into).map(DefWithBodyId::FunctionId)
2167 }
2184 Either::Left(ast::Item::Fn(it)) => (|| match self.to_def(it)?.id {
2185 AnyFunctionId::FunctionId(id) => Some(DefWithBodyId::FunctionId(id)),
2186 AnyFunctionId::BuiltinDeriveImplMethod { .. } => None,
2187 })(),
21682188 Either::Left(ast::Item::Const(it)) => {
21692189 self.to_def(it).map(<_>::into).map(DefWithBodyId::ConstId)
21702190 }
......@@ -2201,7 +2221,11 @@ impl<'db> SemanticsImpl<'db> {
22012221 }
22022222
22032223 pub fn impl_generated_from_derive(&self, impl_: Impl) -> Option<Adt> {
2204 let source = hir_def::src::HasSource::ast_ptr(&impl_.id.loc(self.db), self.db);
2224 let id = match impl_.id {
2225 AnyImplId::ImplId(id) => id,
2226 AnyImplId::BuiltinDeriveImplId(id) => return Some(id.loc(self.db).adt.into()),
2227 };
2228 let source = hir_def::src::HasSource::ast_ptr(&id.loc(self.db), self.db);
22052229 let mut file_id = source.file_id;
22062230 let adt_ast_id = loop {
22072231 let macro_call = file_id.macro_file()?;
src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs+30-24
......@@ -57,9 +57,9 @@ use syntax::{
5757use triomphe::Arc;
5858
5959use crate::{
60 Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field,
61 Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait,
62 TupleField, Type, TypeAlias, Variant,
60 Adt, AnyFunctionId, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const,
61 DeriveHelper, Field, Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct,
62 ToolModule, Trait, TupleField, Type, TypeAlias, Variant,
6363 db::HirDatabase,
6464 semantics::{PathResolution, PathResolutionPerNs},
6565};
......@@ -431,7 +431,7 @@ impl<'db> SourceAnalyzer<'db> {
431431 let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
432432 let (f_in_trait, substs) = self.infer()?.method_resolution(expr_id)?;
433433
434 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs).into())
434 Some(self.resolve_impl_method_or_trait_def(db, f_in_trait, substs))
435435 }
436436
437437 pub(crate) fn resolve_method_call_fallback(
......@@ -446,8 +446,8 @@ impl<'db> SourceAnalyzer<'db> {
446446 let (fn_, subst) =
447447 self.resolve_impl_method_or_trait_def_with_subst(db, f_in_trait, substs);
448448 Some((
449 Either::Left(fn_.into()),
450 Some(GenericSubstitution::new(fn_.into(), subst, self.trait_environment(db))),
449 Either::Left(fn_),
450 GenericSubstitution::new_from_fn(fn_, subst, self.trait_environment(db)),
451451 ))
452452 }
453453 None => {
......@@ -519,8 +519,8 @@ impl<'db> SourceAnalyzer<'db> {
519519 None => inference_result.method_resolution(expr_id).map(|(f, substs)| {
520520 let (f, subst) = self.resolve_impl_method_or_trait_def_with_subst(db, f, substs);
521521 (
522 Either::Right(f.into()),
523 Some(GenericSubstitution::new(f.into(), subst, self.trait_environment(db))),
522 Either::Right(f),
523 GenericSubstitution::new_from_fn(f, subst, self.trait_environment(db)),
524524 )
525525 }),
526526 }
......@@ -569,7 +569,7 @@ impl<'db> SourceAnalyzer<'db> {
569569 &self,
570570 db: &'db dyn HirDatabase,
571571 await_expr: &ast::AwaitExpr,
572 ) -> Option<FunctionId> {
572 ) -> Option<Function> {
573573 let mut ty = self.ty_of_expr(await_expr.expr()?)?;
574574
575575 let into_future_trait = self
......@@ -605,7 +605,7 @@ impl<'db> SourceAnalyzer<'db> {
605605 &self,
606606 db: &'db dyn HirDatabase,
607607 prefix_expr: &ast::PrefixExpr,
608 ) -> Option<FunctionId> {
608 ) -> Option<Function> {
609609 let (_op_trait, op_fn) = match prefix_expr.op_kind()? {
610610 ast::UnaryOp::Deref => {
611611 // This can be either `Deref::deref` or `DerefMut::deref_mut`.
......@@ -650,7 +650,7 @@ impl<'db> SourceAnalyzer<'db> {
650650 &self,
651651 db: &'db dyn HirDatabase,
652652 index_expr: &ast::IndexExpr,
653 ) -> Option<FunctionId> {
653 ) -> Option<Function> {
654654 let base_ty = self.ty_of_expr(index_expr.base()?)?;
655655 let index_ty = self.ty_of_expr(index_expr.index()?)?;
656656
......@@ -679,7 +679,7 @@ impl<'db> SourceAnalyzer<'db> {
679679 &self,
680680 db: &'db dyn HirDatabase,
681681 binop_expr: &ast::BinExpr,
682 ) -> Option<FunctionId> {
682 ) -> Option<Function> {
683683 let op = binop_expr.op_kind()?;
684684 let lhs = self.ty_of_expr(binop_expr.lhs()?)?;
685685 let rhs = self.ty_of_expr(binop_expr.rhs()?)?;
......@@ -699,7 +699,7 @@ impl<'db> SourceAnalyzer<'db> {
699699 &self,
700700 db: &'db dyn HirDatabase,
701701 try_expr: &ast::TryExpr,
702 ) -> Option<FunctionId> {
702 ) -> Option<Function> {
703703 let ty = self.ty_of_expr(try_expr.expr()?)?;
704704
705705 let op_fn = self.lang_items(db).TryTraitBranch?;
......@@ -905,7 +905,7 @@ impl<'db> SourceAnalyzer<'db> {
905905 subs,
906906 self.trait_environment(db),
907907 );
908 (AssocItemId::from(f_in_trait), subst)
908 (AssocItem::Function(f_in_trait.into()), Some(subst))
909909 }
910910 Some(func_ty) => {
911911 if let TyKind::FnDef(_fn_def, subs) = func_ty.kind() {
......@@ -913,19 +913,19 @@ impl<'db> SourceAnalyzer<'db> {
913913 .resolve_impl_method_or_trait_def_with_subst(
914914 db, f_in_trait, subs,
915915 );
916 let subst = GenericSubstitution::new(
917 fn_.into(),
916 let subst = GenericSubstitution::new_from_fn(
917 fn_,
918918 subst,
919919 self.trait_environment(db),
920920 );
921 (fn_.into(), subst)
921 (AssocItem::Function(fn_), subst)
922922 } else {
923923 let subst = GenericSubstitution::new(
924924 f_in_trait.into(),
925925 subs,
926926 self.trait_environment(db),
927927 );
928 (f_in_trait.into(), subst)
928 (AssocItem::Function(f_in_trait.into()), Some(subst))
929929 }
930930 }
931931 }
......@@ -938,11 +938,11 @@ impl<'db> SourceAnalyzer<'db> {
938938 subst,
939939 self.trait_environment(db),
940940 );
941 (konst.into(), subst)
941 (AssocItem::Const(konst.into()), Some(subst))
942942 }
943943 };
944944
945 return Some((PathResolution::Def(AssocItem::from(assoc).into()), Some(subst)));
945 return Some((PathResolution::Def(assoc.into()), subst));
946946 }
947947 if let Some(VariantId::EnumVariantId(variant)) =
948948 infer.variant_resolution_for_expr_or_pat(expr_id)
......@@ -1401,7 +1401,7 @@ impl<'db> SourceAnalyzer<'db> {
14011401 db: &'db dyn HirDatabase,
14021402 func: FunctionId,
14031403 substs: GenericArgs<'db>,
1404 ) -> FunctionId {
1404 ) -> Function {
14051405 self.resolve_impl_method_or_trait_def_with_subst(db, func, substs).0
14061406 }
14071407
......@@ -1410,13 +1410,19 @@ impl<'db> SourceAnalyzer<'db> {
14101410 db: &'db dyn HirDatabase,
14111411 func: FunctionId,
14121412 substs: GenericArgs<'db>,
1413 ) -> (FunctionId, GenericArgs<'db>) {
1413 ) -> (Function, GenericArgs<'db>) {
14141414 let owner = match self.resolver.body_owner() {
14151415 Some(it) => it,
1416 None => return (func, substs),
1416 None => return (func.into(), substs),
14171417 };
14181418 let env = self.param_and(db.trait_environment_for_body(owner));
1419 db.lookup_impl_method(env, func, substs)
1419 let (func, args) = db.lookup_impl_method(env, func, substs);
1420 match func {
1421 Either::Left(func) => (func.into(), args),
1422 Either::Right((impl_, method)) => {
1423 (Function { id: AnyFunctionId::BuiltinDeriveImplMethod { method, impl_ } }, args)
1424 }
1425 }
14201426 }
14211427
14221428 fn resolve_impl_const_or_trait_def_with_subst(
src/tools/rust-analyzer/crates/ide-assists/src/assist_config.rs+6
......@@ -9,6 +9,7 @@ use ide_db::{
99 SnippetCap,
1010 assists::ExprFillDefaultMode,
1111 imports::{import_assets::ImportPathConfig, insert_use::InsertUseConfig},
12 rename::RenameConfig,
1213};
1314
1415use crate::AssistKind;
......@@ -27,6 +28,7 @@ pub struct AssistConfig {
2728 pub code_action_grouping: bool,
2829 pub expr_fill_default: ExprFillDefaultMode,
2930 pub prefer_self_ty: bool,
31 pub show_rename_conflicts: bool,
3032}
3133
3234impl AssistConfig {
......@@ -46,4 +48,8 @@ impl AssistConfig {
4648 allow_unstable,
4749 }
4850 }
51
52 pub fn rename_config(&self) -> RenameConfig {
53 RenameConfig { show_conflicts: self.show_rename_conflicts }
54 }
4955}
src/tools/rust-analyzer/crates/ide-assists/src/handlers/convert_to_guarded_return.rs+60-3
......@@ -218,7 +218,7 @@ fn let_stmt_to_guarded_return(
218218 let let_else_stmt = make::let_else_stmt(
219219 happy_pattern,
220220 let_stmt.ty(),
221 expr,
221 expr.reset_indent(),
222222 ast::make::tail_only_block_expr(early_expression),
223223 );
224224 let let_else_stmt = let_else_stmt.indent(let_indent_level);
......@@ -275,11 +275,11 @@ fn flat_let_chain(mut expr: ast::Expr) -> Vec<ast::Expr> {
275275 && bin_expr.op_kind() == Some(ast::BinaryOp::LogicOp(ast::LogicOp::And))
276276 && let (Some(lhs), Some(rhs)) = (bin_expr.lhs(), bin_expr.rhs())
277277 {
278 reduce_cond(rhs);
278 reduce_cond(rhs.reset_indent());
279279 expr = lhs;
280280 }
281281
282 reduce_cond(expr);
282 reduce_cond(expr.reset_indent());
283283 chains.reverse();
284284 chains
285285}
......@@ -1019,6 +1019,63 @@ fn main() {
10191019 );
10201020 }
10211021
1022 #[test]
1023 fn indentations() {
1024 check_assist(
1025 convert_to_guarded_return,
1026 r#"
1027mod indent {
1028 fn main() {
1029 $0if let None = Some(
1030 92
1031 ) {
1032 foo(
1033 93
1034 );
1035 }
1036 }
1037}
1038"#,
1039 r#"
1040mod indent {
1041 fn main() {
1042 let None = Some(
1043 92
1044 ) else { return };
1045 foo(
1046 93
1047 );
1048 }
1049}
1050"#,
1051 );
1052
1053 check_assist(
1054 convert_to_guarded_return,
1055 r#"
1056//- minicore: option
1057mod indent {
1058 fn foo(_: i32) -> Option<i32> { None }
1059 fn main() {
1060 $0let x = foo(
1061 2
1062 );
1063 }
1064}
1065"#,
1066 r#"
1067mod indent {
1068 fn foo(_: i32) -> Option<i32> { None }
1069 fn main() {
1070 let Some(x) = foo(
1071 2
1072 ) else { return };
1073 }
1074}
1075"#,
1076 );
1077 }
1078
10221079 #[test]
10231080 fn ignore_already_converted_if() {
10241081 check_assist_not_applicable(
src/tools/rust-analyzer/crates/ide-assists/src/handlers/remove_underscore.rs+3-1
......@@ -62,7 +62,9 @@ pub(crate) fn remove_underscore(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
6262 "Remove underscore from a used variable",
6363 text_range,
6464 |builder| {
65 let changes = def.rename(&ctx.sema, new_name, RenameDefinition::Yes).unwrap();
65 let changes = def
66 .rename(&ctx.sema, new_name, RenameDefinition::Yes, &ctx.config.rename_config())
67 .unwrap();
6668 builder.source_change = changes;
6769 },
6870 )
src/tools/rust-analyzer/crates/ide-assists/src/tests.rs+4
......@@ -38,6 +38,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
3838 code_action_grouping: true,
3939 expr_fill_default: ExprFillDefaultMode::Todo,
4040 prefer_self_ty: false,
41 show_rename_conflicts: true,
4142};
4243
4344pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
......@@ -59,6 +60,7 @@ pub(crate) const TEST_CONFIG_NO_GROUPING: AssistConfig = AssistConfig {
5960 code_action_grouping: false,
6061 expr_fill_default: ExprFillDefaultMode::Todo,
6162 prefer_self_ty: false,
63 show_rename_conflicts: true,
6264};
6365
6466pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
......@@ -80,6 +82,7 @@ pub(crate) const TEST_CONFIG_NO_SNIPPET_CAP: AssistConfig = AssistConfig {
8082 code_action_grouping: true,
8183 expr_fill_default: ExprFillDefaultMode::Todo,
8284 prefer_self_ty: false,
85 show_rename_conflicts: true,
8386};
8487
8588pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
......@@ -101,6 +104,7 @@ pub(crate) const TEST_CONFIG_IMPORT_ONE: AssistConfig = AssistConfig {
101104 code_action_grouping: true,
102105 expr_fill_default: ExprFillDefaultMode::Todo,
103106 prefer_self_ty: false,
107 show_rename_conflicts: true,
104108};
105109
106110fn assists(
src/tools/rust-analyzer/crates/ide-completion/src/completions.rs+1
......@@ -13,6 +13,7 @@ pub(crate) mod format_string;
1313pub(crate) mod item_list;
1414pub(crate) mod keyword;
1515pub(crate) mod lifetime;
16pub(crate) mod macro_def;
1617pub(crate) mod mod_;
1718pub(crate) mod pattern;
1819pub(crate) mod postfix;
src/tools/rust-analyzer/crates/ide-completion/src/completions/dot.rs+2-1
......@@ -652,7 +652,7 @@ fn foo(u: U) { u.$0 }
652652 fn test_method_completion_only_fitting_impls() {
653653 check_no_kw(
654654 r#"
655struct A<T> {}
655struct A<T>(T);
656656impl A<u32> {
657657 fn the_method(&self) {}
658658}
......@@ -662,6 +662,7 @@ impl A<i32> {
662662fn foo(a: A<u32>) { a.$0 }
663663"#,
664664 expect![[r#"
665 fd 0 u32
665666 me the_method() fn(&self)
666667 "#]],
667668 )
src/tools/rust-analyzer/crates/ide-completion/src/completions/macro_def.rs created+31
......@@ -0,0 +1,31 @@
1//! Completion for macro meta-variable segments
2
3use ide_db::SymbolKind;
4
5use crate::{CompletionItem, Completions, context::CompletionContext};
6
7pub(crate) fn complete_macro_segment(acc: &mut Completions, ctx: &CompletionContext<'_>) {
8 for &label in MACRO_SEGMENTS {
9 let item =
10 CompletionItem::new(SymbolKind::BuiltinAttr, ctx.source_range(), label, ctx.edition);
11 item.add_to(acc, ctx.db);
12 }
13}
14
15const MACRO_SEGMENTS: &[&str] = &[
16 "ident",
17 "block",
18 "stmt",
19 "expr",
20 "pat",
21 "ty",
22 "lifetime",
23 "literal",
24 "path",
25 "meta",
26 "tt",
27 "item",
28 "vis",
29 "expr_2021",
30 "pat_param",
31];
src/tools/rust-analyzer/crates/ide-completion/src/completions/record.rs+4-1
......@@ -70,8 +70,11 @@ pub(crate) fn complete_record_expr_fields(
7070 }
7171 _ => {
7272 let missing_fields = ctx.sema.record_literal_missing_fields(record_expr);
73 let update_exists = record_expr
74 .record_expr_field_list()
75 .is_some_and(|list| list.dotdot_token().is_some());
7376
74 if !missing_fields.is_empty() {
77 if !missing_fields.is_empty() && !update_exists {
7578 cov_mark::hit!(functional_update_field);
7679 add_default_update(acc, ctx, ty);
7780 }
src/tools/rust-analyzer/crates/ide-completion/src/context.rs+3-2
......@@ -13,7 +13,7 @@ use hir::{
1313};
1414use ide_db::{
1515 FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
16 helpers::is_editable_crate,
16 helpers::is_editable_crate, syntax_helpers::node_ext::is_in_macro_matcher,
1717};
1818use itertools::Either;
1919use syntax::{
......@@ -389,6 +389,7 @@ pub(crate) enum CompletionAnalysis<'db> {
389389 fake_attribute_under_caret: Option<ast::Attr>,
390390 extern_crate: Option<ast::ExternCrate>,
391391 },
392 MacroSegment,
392393}
393394
394395/// Information about the field or method access we are completing.
......@@ -729,7 +730,7 @@ impl<'db> CompletionContext<'db> {
729730 let prev_token = original_token.prev_token()?;
730731
731732 // only has a single colon
732 if prev_token.kind() != T![:] {
733 if prev_token.kind() != T![:] && !is_in_macro_matcher(&original_token) {
733734 return None;
734735 }
735736
src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs+16-1
......@@ -5,7 +5,7 @@ use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
55use ide_db::{
66 RootDatabase, active_parameter::ActiveParameter, syntax_helpers::node_ext::find_loops,
77};
8use itertools::Either;
8use itertools::{Either, Itertools};
99use stdx::always;
1010use syntax::{
1111 AstNode, AstToken, Direction, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken,
......@@ -510,6 +510,21 @@ fn analyze<'db>(
510510 colon_prefix,
511511 extern_crate: p.ancestors().find_map(ast::ExternCrate::cast),
512512 }
513 } else if p.kind() == SyntaxKind::TOKEN_TREE
514 && p.ancestors().any(|it| ast::Macro::can_cast(it.kind()))
515 {
516 if let Some([_ident, colon, _name, dollar]) = fake_ident_token
517 .siblings_with_tokens(Direction::Prev)
518 .filter(|it| !it.kind().is_trivia())
519 .take(4)
520 .collect_array()
521 && dollar.kind() == T![$]
522 && colon.kind() == T![:]
523 {
524 CompletionAnalysis::MacroSegment
525 } else {
526 return None;
527 }
513528 } else {
514529 return None;
515530 }
src/tools/rust-analyzer/crates/ide-completion/src/lib.rs+3
......@@ -263,6 +263,9 @@ pub fn completions(
263263 extern_crate.as_ref(),
264264 );
265265 }
266 CompletionAnalysis::MacroSegment => {
267 completions::macro_def::complete_macro_segment(acc, ctx);
268 }
266269 CompletionAnalysis::UnexpandedAttrTT { .. } | CompletionAnalysis::String { .. } => (),
267270 }
268271 }
src/tools/rust-analyzer/crates/ide-completion/src/render/macro_.rs+74-13
......@@ -1,6 +1,6 @@
11//! Renderer for macro invocations.
22
3use hir::HirDisplay;
3use hir::{HirDisplay, db::HirDatabase};
44use ide_db::{SymbolKind, documentation::Documentation};
55use syntax::{SmolStr, ToSmolStr, format_smolstr};
66
......@@ -46,17 +46,15 @@ fn render(
4646 ctx.source_range()
4747 };
4848
49 let orig_name = macro_.name(ctx.db());
50 let (name, orig_name, escaped_name) = (
51 name.as_str(),
52 orig_name.as_str(),
53 name.display(ctx.db(), completion.edition).to_smolstr(),
54 );
49 let (name, escaped_name) =
50 (name.as_str(), name.display(ctx.db(), completion.edition).to_smolstr());
5551 let docs = ctx.docs(macro_);
56 let docs_str = docs.as_ref().map(Documentation::as_str).unwrap_or_default();
5752 let is_fn_like = macro_.is_fn_like(completion.db);
58 let (bra, ket) =
59 if is_fn_like { guess_macro_braces(name, orig_name, docs_str) } else { ("", "") };
53 let (bra, ket) = if is_fn_like {
54 guess_macro_braces(ctx.db(), macro_, name, docs.as_ref())
55 } else {
56 ("", "")
57 };
6058
6159 let needs_bang = is_fn_like && !is_use_path && !has_macro_bang;
6260
......@@ -115,12 +113,24 @@ fn banged_name(name: &str) -> SmolStr {
115113}
116114
117115fn guess_macro_braces(
116 db: &dyn HirDatabase,
117 macro_: hir::Macro,
118118 macro_name: &str,
119 orig_name: &str,
120 docs: &str,
119 docs: Option<&Documentation<'_>>,
121120) -> (&'static str, &'static str) {
121 if let Some(style) = macro_.preferred_brace_style(db) {
122 return match style {
123 hir::MacroBraces::Braces => (" {", "}"),
124 hir::MacroBraces::Brackets => ("[", "]"),
125 hir::MacroBraces::Parentheses => ("(", ")"),
126 };
127 }
128
129 let orig_name = macro_.name(db);
130 let docs = docs.map(Documentation::as_str).unwrap_or_default();
131
122132 let mut votes = [0, 0, 0];
123 for (idx, s) in docs.match_indices(macro_name).chain(docs.match_indices(orig_name)) {
133 for (idx, s) in docs.match_indices(macro_name).chain(docs.match_indices(orig_name.as_str())) {
124134 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
125135 // Ensure to match the full word
126136 if after.starts_with('!')
......@@ -199,6 +209,57 @@ fn main() {
199209 );
200210 }
201211
212 #[test]
213 fn preferred_macro_braces() {
214 check_edit(
215 "vec!",
216 r#"
217#[rust_analyzer::macro_style(brackets)]
218macro_rules! vec { () => {} }
219
220fn main() { v$0 }
221"#,
222 r#"
223#[rust_analyzer::macro_style(brackets)]
224macro_rules! vec { () => {} }
225
226fn main() { vec![$0] }
227"#,
228 );
229
230 check_edit(
231 "foo!",
232 r#"
233#[rust_analyzer::macro_style(braces)]
234macro_rules! foo { () => {} }
235fn main() { $0 }
236"#,
237 r#"
238#[rust_analyzer::macro_style(braces)]
239macro_rules! foo { () => {} }
240fn main() { foo! {$0} }
241"#,
242 );
243
244 check_edit(
245 "bar!",
246 r#"
247#[macro_export]
248#[rust_analyzer::macro_style(brackets)]
249macro_rules! foo { () => {} }
250pub use crate::foo as bar;
251fn main() { $0 }
252"#,
253 r#"
254#[macro_export]
255#[rust_analyzer::macro_style(brackets)]
256macro_rules! foo { () => {} }
257pub use crate::foo as bar;
258fn main() { bar![$0] }
259"#,
260 );
261 }
262
202263 #[test]
203264 fn guesses_macro_braces() {
204265 check_edit(
src/tools/rust-analyzer/crates/ide-completion/src/tests/flyimport.rs+1
......@@ -79,6 +79,7 @@ fn macro_fuzzy_completion() {
7979 r#"
8080//- /lib.rs crate:dep
8181/// Please call me as macro_with_curlies! {}
82#[rust_analyzer::macro_style(braces)]
8283#[macro_export]
8384macro_rules! macro_with_curlies {
8485 () => {}
src/tools/rust-analyzer/crates/ide-completion/src/tests/record.rs+23
......@@ -263,6 +263,29 @@ fn main() {
263263 );
264264}
265265
266#[test]
267fn functional_update_exist_update() {
268 check(
269 r#"
270//- minicore:default
271struct Foo { foo1: u32, foo2: u32 }
272impl Default for Foo {
273 fn default() -> Self { loop {} }
274}
275
276fn main() {
277 let thing = 1;
278 let foo = Foo { foo1: 0, foo2: 0 };
279 let foo2 = Foo { thing, $0 ..Default::default() }
280}
281"#,
282 expect![[r#"
283 fd foo1 u32
284 fd foo2 u32
285 "#]],
286 );
287}
288
266289#[test]
267290fn empty_union_literal() {
268291 check(
src/tools/rust-analyzer/crates/ide-completion/src/tests/special.rs+229
......@@ -481,6 +481,226 @@ fn foo() {}
481481 );
482482}
483483
484#[test]
485fn completes_macro_segment() {
486 check(
487 r#"
488macro_rules! foo {
489 ($x:e$0) => ();
490}
491"#,
492 expect![[r#"
493 ba block
494 ba expr
495 ba expr_2021
496 ba ident
497 ba item
498 ba lifetime
499 ba literal
500 ba meta
501 ba pat
502 ba pat_param
503 ba path
504 ba stmt
505 ba tt
506 ba ty
507 ba vis
508 "#]],
509 );
510
511 check(
512 r#"
513macro_rules! foo {
514 ($x:$0) => ();
515}
516"#,
517 expect![[r#"
518 ba block
519 ba expr
520 ba expr_2021
521 ba ident
522 ba item
523 ba lifetime
524 ba literal
525 ba meta
526 ba pat
527 ba pat_param
528 ba path
529 ba stmt
530 ba tt
531 ba ty
532 ba vis
533 "#]],
534 );
535
536 check(
537 r#"
538macro_rules! foo {
539 ($($x:$0)*) => ();
540}
541"#,
542 expect![[r#"
543 ba block
544 ba expr
545 ba expr_2021
546 ba ident
547 ba item
548 ba lifetime
549 ba literal
550 ba meta
551 ba pat
552 ba pat_param
553 ba path
554 ba stmt
555 ba tt
556 ba ty
557 ba vis
558 "#]],
559 );
560
561 check(
562 r#"
563macro foo {
564 ($($x:$0)*) => ();
565}
566"#,
567 expect![[r#"
568 ba block
569 ba expr
570 ba expr_2021
571 ba ident
572 ba item
573 ba lifetime
574 ba literal
575 ba meta
576 ba pat
577 ba pat_param
578 ba path
579 ba stmt
580 ba tt
581 ba ty
582 ba vis
583 "#]],
584 );
585
586 check(
587 r#"
588macro foo($($x:$0)*) {
589 xxx;
590}
591"#,
592 expect![[r#"
593 ba block
594 ba expr
595 ba expr_2021
596 ba ident
597 ba item
598 ba lifetime
599 ba literal
600 ba meta
601 ba pat
602 ba pat_param
603 ba path
604 ba stmt
605 ba tt
606 ba ty
607 ba vis
608 "#]],
609 );
610
611 check_edit(
612 "expr",
613 r#"
614macro foo($($x:$0)*) {
615 xxx;
616}
617"#,
618 r#"
619macro foo($($x:expr)*) {
620 xxx;
621}
622"#,
623 );
624
625 check(
626 r#"
627macro_rules! foo {
628 ($fn : e$0) => ();
629}
630"#,
631 expect![[r#"
632 ba block
633 ba expr
634 ba expr_2021
635 ba ident
636 ba item
637 ba lifetime
638 ba literal
639 ba meta
640 ba pat
641 ba pat_param
642 ba path
643 ba stmt
644 ba tt
645 ba ty
646 ba vis
647 "#]],
648 );
649
650 check_edit(
651 "expr",
652 r#"
653macro foo($($x:ex$0)*) {
654 xxx;
655}
656"#,
657 r#"
658macro foo($($x:expr)*) {
659 xxx;
660}
661"#,
662 );
663}
664
665#[test]
666fn completes_in_macro_body() {
667 check(
668 r#"
669macro_rules! foo {
670 ($x:expr) => ($y:$0);
671}
672"#,
673 expect![[r#""#]],
674 );
675
676 check(
677 r#"
678macro_rules! foo {
679 ($x:expr) => ({$y:$0});
680}
681"#,
682 expect![[r#""#]],
683 );
684
685 check(
686 r#"
687macro foo {
688 ($x:expr) => ($y:$0);
689}
690"#,
691 expect![[r#""#]],
692 );
693
694 check(
695 r#"
696macro foo($x:expr) {
697 $y:$0
698}
699"#,
700 expect![[r#""#]],
701 );
702}
703
484704#[test]
485705fn function_mod_share_name() {
486706 check_no_kw(
......@@ -942,6 +1162,15 @@ fn foo { crate::$0 }
9421162 check_with_trigger_character(
9431163 r#"
9441164fn foo { crate:$0 }
1165"#,
1166 Some(':'),
1167 expect![""],
1168 );
1169
1170 check_with_trigger_character(
1171 r#"
1172macro_rules! bar { ($($x:tt)*) => ($($x)*); }
1173fn foo { bar!(crate:$0) }
9451174"#,
9461175 Some(':'),
9471176 expect![""],
src/tools/rust-analyzer/crates/ide-db/src/apply_change.rs+3-27
......@@ -1,39 +1,15 @@
11//! Applies changes to the IDE state transactionally.
22
3use base_db::SourceRootId;
43use profile::Bytes;
5use rustc_hash::FxHashSet;
6use salsa::{Database as _, Durability, Setter as _};
4use salsa::Database as _;
75
8use crate::{
9 ChangeWithProcMacros, RootDatabase,
10 symbol_index::{LibraryRoots, LocalRoots},
11};
6use crate::{ChangeWithProcMacros, RootDatabase};
127
138impl RootDatabase {
14 pub fn request_cancellation(&mut self) {
15 let _p = tracing::info_span!("RootDatabase::request_cancellation").entered();
16 self.synthetic_write(Durability::LOW);
17 }
18
199 pub fn apply_change(&mut self, change: ChangeWithProcMacros) {
2010 let _p = tracing::info_span!("RootDatabase::apply_change").entered();
21 self.request_cancellation();
11 self.trigger_cancellation();
2212 tracing::trace!("apply_change {:?}", change);
23 if let Some(roots) = &change.source_change.roots {
24 let mut local_roots = FxHashSet::default();
25 let mut library_roots = FxHashSet::default();
26 for (idx, root) in roots.iter().enumerate() {
27 let root_id = SourceRootId(idx as u32);
28 if root.is_library {
29 library_roots.insert(root_id);
30 } else {
31 local_roots.insert(root_id);
32 }
33 }
34 LocalRoots::get(self).set_roots(self).to(local_roots);
35 LibraryRoots::get(self).set_roots(self).to(library_roots);
36 }
3713 change.apply(self);
3814 }
3915
src/tools/rust-analyzer/crates/ide-db/src/lib.rs+3-3
......@@ -75,7 +75,7 @@ pub use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
7575pub use ::line_index;
7676
7777/// `base_db` is normally also needed in places where `ide_db` is used, so this re-export is for convenience.
78pub use base_db::{self, FxIndexMap, FxIndexSet};
78pub use base_db::{self, FxIndexMap, FxIndexSet, LibraryRoots, LocalRoots};
7979pub use span::{self, FileId};
8080
8181pub type FilePosition = FilePositionWrapper<FileId>;
......@@ -200,10 +200,10 @@ impl RootDatabase {
200200 db.set_all_crates(Arc::new(Box::new([])));
201201 CrateGraphBuilder::default().set_in_db(&mut db);
202202 db.set_proc_macros_with_durability(Default::default(), Durability::MEDIUM);
203 _ = crate::symbol_index::LibraryRoots::builder(Default::default())
203 _ = base_db::LibraryRoots::builder(Default::default())
204204 .durability(Durability::MEDIUM)
205205 .new(&db);
206 _ = crate::symbol_index::LocalRoots::builder(Default::default())
206 _ = base_db::LocalRoots::builder(Default::default())
207207 .durability(Durability::MEDIUM)
208208 .new(&db);
209209 db.set_expand_proc_attr_macros_with_durability(false, Durability::HIGH);
src/tools/rust-analyzer/crates/ide-db/src/prime_caches.rs+2-4
......@@ -108,10 +108,9 @@ pub fn parallel_prime_caches(
108108 hir::attach_db(&db, || {
109109 // method resolution is likely to hit all trait impls at some point
110110 // we pre-populate it here as this will hit a lot of parses ...
111 _ = hir::TraitImpls::for_crate(&db, crate_id);
112 // we compute the lang items here as the work for them is also highly recursive and will be trigger by the module symbols query
111 // This also computes the lang items, which is what we want as the work for them is also highly recursive and will be trigger by the module symbols query
113112 // slowing down leaf crate analysis tremendously as we go back to being blocked on a single thread
114 _ = hir::crate_lang_items(&db, crate_id);
113 _ = hir::TraitImpls::for_crate(&db, crate_id);
115114 })
116115 });
117116
......@@ -271,7 +270,6 @@ pub fn parallel_prime_caches(
271270 }
272271
273272 if crate_def_maps_done == crate_def_maps_total {
274 // Can we trigger lru-eviction once at this point to reduce peak memory usage?
275273 cb(ParallelPrimeCachesProgress {
276274 crates_currently_indexing: vec![],
277275 crates_done: crate_def_maps_done,
src/tools/rust-analyzer/crates/ide-db/src/rename.rs+34-19
......@@ -45,6 +45,11 @@ use crate::{
4545 traits::convert_to_def_in_trait,
4646};
4747
48#[derive(Clone, Debug, PartialEq, Eq)]
49pub struct RenameConfig {
50 pub show_conflicts: bool,
51}
52
4853pub type Result<T, E = RenameError> = std::result::Result<T, E>;
4954
5055#[derive(Debug)]
......@@ -81,6 +86,7 @@ impl Definition {
8186 sema: &Semantics<'_, RootDatabase>,
8287 new_name: &str,
8388 rename_definition: RenameDefinition,
89 config: &RenameConfig,
8490 ) -> Result<SourceChange> {
8591 // self.krate() returns None if
8692 // self is a built-in attr, built-in type or tool module.
......@@ -109,10 +115,15 @@ impl Definition {
109115 bail!("Cannot rename a builtin attr.")
110116 }
111117 Definition::SelfType(_) => bail!("Cannot rename `Self`"),
112 Definition::Macro(mac) => {
113 rename_reference(sema, Definition::Macro(mac), new_name, rename_definition, edition)
114 }
115 def => rename_reference(sema, def, new_name, rename_definition, edition),
118 Definition::Macro(mac) => rename_reference(
119 sema,
120 Definition::Macro(mac),
121 new_name,
122 rename_definition,
123 edition,
124 config,
125 ),
126 def => rename_reference(sema, def, new_name, rename_definition, edition, config),
116127 }
117128 }
118129
......@@ -338,6 +349,7 @@ fn rename_reference(
338349 new_name: &str,
339350 rename_definition: RenameDefinition,
340351 edition: Edition,
352 config: &RenameConfig,
341353) -> Result<SourceChange> {
342354 let (mut new_name, ident_kind) = IdentifierKind::classify(edition, new_name)?;
343355
......@@ -396,7 +408,8 @@ fn rename_reference(
396408 if rename_definition == RenameDefinition::Yes {
397409 // This needs to come after the references edits, because we change the annotation of existing edits
398410 // if a conflict is detected.
399 let (file_id, edit) = source_edit_from_def(sema, def, &new_name, &mut source_change)?;
411 let (file_id, edit) =
412 source_edit_from_def(sema, config, def, &new_name, &mut source_change)?;
400413 source_change.insert_source_edit(file_id, edit);
401414 }
402415 Ok(source_change)
......@@ -554,6 +567,7 @@ fn source_edit_from_name_ref(
554567
555568fn source_edit_from_def(
556569 sema: &Semantics<'_, RootDatabase>,
570 config: &RenameConfig,
557571 def: Definition,
558572 new_name: &Name,
559573 source_change: &mut SourceChange,
......@@ -562,21 +576,22 @@ fn source_edit_from_def(
562576 if let Definition::Local(local) = def {
563577 let mut file_id = None;
564578
565 let conflict_annotation = if !sema.rename_conflicts(&local, new_name).is_empty() {
566 Some(
567 source_change.insert_annotation(ChangeAnnotation {
568 label: "This rename will change the program's meaning".to_owned(),
569 needs_confirmation: true,
570 description: Some(
571 "Some variable(s) will shadow the renamed variable \
579 let conflict_annotation =
580 if config.show_conflicts && !sema.rename_conflicts(&local, new_name).is_empty() {
581 Some(
582 source_change.insert_annotation(ChangeAnnotation {
583 label: "This rename will change the program's meaning".to_owned(),
584 needs_confirmation: true,
585 description: Some(
586 "Some variable(s) will shadow the renamed variable \
572587 or be shadowed by it if the rename is performed"
573 .to_owned(),
574 ),
575 }),
576 )
577 } else {
578 None
579 };
588 .to_owned(),
589 ),
590 }),
591 )
592 } else {
593 None
594 };
580595
581596 for source in local.sources(sema.db) {
582597 let source = match source.source.clone().original_ast_node_rooted(sema.db) {
src/tools/rust-analyzer/crates/ide-db/src/symbol_index.rs+2-18
......@@ -27,7 +27,7 @@ use std::{
2727 ops::ControlFlow,
2828};
2929
30use base_db::{RootQueryDb, SourceRootId};
30use base_db::{LibraryRoots, LocalRoots, RootQueryDb, SourceRootId};
3131use fst::{Automaton, Streamer, raw::IndexedValue};
3232use hir::{
3333 Crate, Module,
......@@ -36,7 +36,6 @@ use hir::{
3636 symbols::{FileSymbol, SymbolCollector},
3737};
3838use rayon::prelude::*;
39use rustc_hash::FxHashSet;
4039use salsa::Update;
4140
4241use crate::RootDatabase;
......@@ -102,22 +101,6 @@ impl Query {
102101 }
103102}
104103
105/// The set of roots for crates.io libraries.
106/// Files in libraries are assumed to never change.
107#[salsa::input(singleton, debug)]
108pub struct LibraryRoots {
109 #[returns(ref)]
110 pub roots: FxHashSet<SourceRootId>,
111}
112
113/// The set of "local" (that is, from the current workspace) roots.
114/// Files in local roots are assumed to change frequently.
115#[salsa::input(singleton, debug)]
116pub struct LocalRoots {
117 #[returns(ref)]
118 pub roots: FxHashSet<SourceRootId>,
119}
120
121104/// The symbol indices of modules that make up a given crate.
122105pub fn crate_symbols(db: &dyn HirDatabase, krate: Crate) -> Box<[&SymbolIndex<'_>]> {
123106 let _p = tracing::info_span!("crate_symbols").entered();
......@@ -443,6 +426,7 @@ impl Query {
443426mod tests {
444427
445428 use expect_test::expect_file;
429 use rustc_hash::FxHashSet;
446430 use salsa::Setter;
447431 use test_fixture::{WORKSPACE, WithFixture};
448432
src/tools/rust-analyzer/crates/ide-db/src/syntax_helpers/node_ext.rs+38-1
......@@ -1,12 +1,15 @@
11//! Various helper functions to work with SyntaxNodes.
22use std::ops::ControlFlow;
33
4use either::Either;
45use itertools::Itertools;
56use parser::T;
67use span::Edition;
78use syntax::{
8 AstNode, AstToken, Preorder, RustLanguage, WalkEvent,
9 AstNode, AstToken, Direction, Preorder, RustLanguage, SyntaxToken, WalkEvent,
10 algo::non_trivia_sibling,
911 ast::{self, HasLoopBody, MacroCall, PathSegmentKind, VisibilityKind},
12 syntax_editor::Element,
1013};
1114
1215pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
......@@ -542,3 +545,37 @@ pub fn macro_call_for_string_token(string: &ast::String) -> Option<MacroCall> {
542545 let macro_call = string.syntax().parent_ancestors().find_map(ast::MacroCall::cast)?;
543546 Some(macro_call)
544547}
548
549pub fn is_in_macro_matcher(token: &SyntaxToken) -> bool {
550 let Some(macro_def) = token
551 .parent_ancestors()
552 .map_while(Either::<ast::TokenTree, ast::Macro>::cast)
553 .find_map(Either::right)
554 else {
555 return false;
556 };
557 let range = token.text_range();
558 let Some(body) = (match macro_def {
559 ast::Macro::MacroDef(macro_def) => {
560 if let Some(args) = macro_def.args() {
561 return args.syntax().text_range().contains_range(range);
562 }
563 macro_def.body()
564 }
565 ast::Macro::MacroRules(macro_rules) => macro_rules.token_tree(),
566 }) else {
567 return false;
568 };
569 if !body.syntax().text_range().contains_range(range) {
570 return false;
571 }
572 body.token_trees_and_tokens().filter_map(|tt| tt.into_node()).any(|tt| {
573 let Some(next) = non_trivia_sibling(tt.syntax().syntax_element(), Direction::Next) else {
574 return false;
575 };
576 let Some(next_next) = next.next_sibling_or_token() else { return false };
577 next.kind() == T![=]
578 && next_next.kind() == T![>]
579 && tt.syntax().text_range().contains_range(range)
580 })
581}
src/tools/rust-analyzer/crates/ide-db/src/test_data/test_symbol_index_collection.txt+12-12
......@@ -734,11 +734,11 @@
734734 FileSymbol {
735735 name: "generic_impl_fn",
736736 def: Function(
737 Function {
738 id: FunctionId(
737 FunctionId(
738 FunctionId(
739739 6402,
740740 ),
741 },
741 ),
742742 ),
743743 loc: DeclarationLocation {
744744 hir_file_id: FileId(
......@@ -769,11 +769,11 @@
769769 FileSymbol {
770770 name: "impl_fn",
771771 def: Function(
772 Function {
773 id: FunctionId(
772 FunctionId(
773 FunctionId(
774774 6401,
775775 ),
776 },
776 ),
777777 ),
778778 loc: DeclarationLocation {
779779 hir_file_id: FileId(
......@@ -839,11 +839,11 @@
839839 FileSymbol {
840840 name: "main",
841841 def: Function(
842 Function {
843 id: FunctionId(
842 FunctionId(
843 FunctionId(
844844 6400,
845845 ),
846 },
846 ),
847847 ),
848848 loc: DeclarationLocation {
849849 hir_file_id: FileId(
......@@ -907,11 +907,11 @@
907907 FileSymbol {
908908 name: "trait_fn",
909909 def: Function(
910 Function {
911 id: FunctionId(
910 FunctionId(
911 FunctionId(
912912 6403,
913913 ),
914 },
914 ),
915915 ),
916916 loc: DeclarationLocation {
917917 hir_file_id: FileId(
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/incorrect_case.rs+21-1
......@@ -44,7 +44,12 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCase) -> Option<Vec<Ass
4444 let label = format!("Rename to {}", d.suggested_text);
4545 let mut res = unresolved_fix("change_case", &label, frange.range);
4646 if ctx.resolve.should_resolve(&res.id) {
47 let source_change = def.rename(&ctx.sema, &d.suggested_text, RenameDefinition::Yes);
47 let source_change = def.rename(
48 &ctx.sema,
49 &d.suggested_text,
50 RenameDefinition::Yes,
51 &ctx.config.rename_config(),
52 );
4853 res.source_change = Some(source_change.ok().unwrap_or_default());
4954 }
5055
......@@ -1054,4 +1059,19 @@ fn foo(_HelloWorld: ()) {}
10541059 "#,
10551060 );
10561061 }
1062
1063 #[test]
1064 fn allow_with_repr_c() {
1065 check_diagnostics(
1066 r#"
1067#[repr(C)]
1068struct FFI_Struct;
1069
1070#[repr(C)]
1071enum FFI_Enum {
1072 Field,
1073}
1074 "#,
1075 );
1076 }
10571077}
src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs+1
......@@ -52,6 +52,7 @@ pub(crate) fn type_mismatch(ctx: &DiagnosticsContext<'_>, d: &hir::TypeMismatch<
5252 ),
5353 display_range,
5454 )
55 .stable()
5556 .with_fixes(fixes(ctx, d))
5657}
5758
src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs+7-1
......@@ -100,6 +100,7 @@ use ide_db::{
100100 generated::lints::{CLIPPY_LINT_GROUPS, DEFAULT_LINT_GROUPS, DEFAULT_LINTS, Lint, LintGroup},
101101 imports::insert_use::InsertUseConfig,
102102 label::Label,
103 rename::RenameConfig,
103104 source_change::SourceChange,
104105};
105106use syntax::{
......@@ -107,7 +108,6 @@ use syntax::{
107108 ast::{self, AstNode},
108109};
109110
110// FIXME: Make this an enum
111111#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
112112pub enum DiagnosticCode {
113113 RustcHardError(&'static str),
......@@ -238,6 +238,7 @@ pub struct DiagnosticsConfig {
238238 pub prefer_absolute: bool,
239239 pub term_search_fuel: u64,
240240 pub term_search_borrowck: bool,
241 pub show_rename_conflicts: bool,
241242}
242243
243244impl DiagnosticsConfig {
......@@ -266,8 +267,13 @@ impl DiagnosticsConfig {
266267 prefer_absolute: false,
267268 term_search_fuel: 400,
268269 term_search_borrowck: true,
270 show_rename_conflicts: true,
269271 }
270272 }
273
274 pub fn rename_config(&self) -> RenameConfig {
275 RenameConfig { show_conflicts: self.show_rename_conflicts }
276 }
271277}
272278
273279struct DiagnosticsContext<'a> {
src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs+1-1
......@@ -85,7 +85,7 @@ pub use crate::{errors::SsrError, from_comment::ssr_from_comment, matching::Matc
8585
8686use crate::{errors::bail, matching::MatchFailureReason};
8787use hir::{FileRange, Semantics};
88use ide_db::symbol_index::LocalRoots;
88use ide_db::LocalRoots;
8989use ide_db::text_edit::TextEdit;
9090use ide_db::{EditionedFileId, FileId, FxHashMap, RootDatabase, base_db::SourceDatabase};
9191use resolving::ResolvedRule;
src/tools/rust-analyzer/crates/ide-ssr/src/search.rs+1-2
......@@ -6,10 +6,9 @@ use crate::{
66};
77use hir::FileRange;
88use ide_db::{
9 FileId, FxHashSet,
9 FileId, FxHashSet, LocalRoots,
1010 defs::Definition,
1111 search::{SearchScope, UsageSearchResult},
12 symbol_index::LocalRoots,
1312};
1413use syntax::{AstNode, SyntaxKind, SyntaxNode, ast};
1514
src/tools/rust-analyzer/crates/ide-ssr/src/tests.rs+1-2
......@@ -1,9 +1,8 @@
11use expect_test::{Expect, expect};
22use hir::{FilePosition, FileRange};
33use ide_db::{
4 EditionedFileId, FxHashSet,
4 EditionedFileId, FxHashSet, LocalRoots,
55 base_db::{SourceDatabase, salsa::Setter},
6 symbol_index::LocalRoots,
76};
87use test_utils::RangeOrOffset;
98
src/tools/rust-analyzer/crates/ide/src/expand_macro.rs+4-4
......@@ -4,7 +4,7 @@ use ide_db::{
44 FileId, RootDatabase, base_db::Crate, helpers::pick_best_token,
55 syntax_helpers::prettify_macro_expansion,
66};
7use span::{SpanMap, SyntaxContext, TextRange, TextSize};
7use span::{SpanMap, TextRange, TextSize};
88use stdx::format_to;
99use syntax::{AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast, ted};
1010
......@@ -142,7 +142,7 @@ fn expand_macro_recur(
142142 sema: &Semantics<'_, RootDatabase>,
143143 macro_call: &ast::Item,
144144 error: &mut String,
145 result_span_map: &mut SpanMap<SyntaxContext>,
145 result_span_map: &mut SpanMap,
146146 offset_in_original_node: TextSize,
147147) -> Option<SyntaxNode> {
148148 let ExpandResult { value: expanded, err } = match macro_call {
......@@ -171,7 +171,7 @@ fn expand(
171171 sema: &Semantics<'_, RootDatabase>,
172172 expanded: SyntaxNode,
173173 error: &mut String,
174 result_span_map: &mut SpanMap<SyntaxContext>,
174 result_span_map: &mut SpanMap,
175175 mut offset_in_original_node: i32,
176176) -> SyntaxNode {
177177 let children = expanded.descendants().filter_map(ast::Item::cast);
......@@ -208,7 +208,7 @@ fn format(
208208 kind: SyntaxKind,
209209 file_id: FileId,
210210 expanded: SyntaxNode,
211 span_map: &SpanMap<SyntaxContext>,
211 span_map: &SpanMap,
212212 krate: Crate,
213213) -> String {
214214 let expansion = prettify_macro_expansion(db, expanded, span_map, krate).to_string();
src/tools/rust-analyzer/crates/ide/src/hover/render.rs+6-29
......@@ -228,37 +228,14 @@ pub(super) fn underscore(
228228 return None;
229229 }
230230 let parent = token.parent()?;
231 let _it = match_ast! {
231 match_ast! {
232232 match parent {
233 ast::InferType(it) => it,
234 ast::UnderscoreExpr(it) => return type_info_of(sema, config, &Either::Left(ast::Expr::UnderscoreExpr(it)),edition, display_target),
235 ast::WildcardPat(it) => return type_info_of(sema, config, &Either::Right(ast::Pat::WildcardPat(it)),edition, display_target),
236 _ => return None,
233 ast::InferType(it) => type_info(sema, config, TypeInfo { original: sema.resolve_type(&ast::Type::InferType(it))?, adjusted: None}, edition, display_target),
234 ast::UnderscoreExpr(it) => type_info(sema, config, sema.type_of_expr(&ast::Expr::UnderscoreExpr(it))?, edition, display_target),
235 ast::WildcardPat(it) => type_info(sema, config, sema.type_of_pat(&ast::Pat::WildcardPat(it))?, edition, display_target),
236 _ => None,
237237 }
238 };
239 // let it = infer_type.syntax().parent()?;
240 // match_ast! {
241 // match it {
242 // ast::LetStmt(_it) => (),
243 // ast::Param(_it) => (),
244 // ast::RetType(_it) => (),
245 // ast::TypeArg(_it) => (),
246
247 // ast::CastExpr(_it) => (),
248 // ast::ParenType(_it) => (),
249 // ast::TupleType(_it) => (),
250 // ast::PtrType(_it) => (),
251 // ast::RefType(_it) => (),
252 // ast::ArrayType(_it) => (),
253 // ast::SliceType(_it) => (),
254 // ast::ForType(_it) => (),
255 // _ => return None,
256 // }
257 // }
258
259 // FIXME: https://github.com/rust-lang/rust-analyzer/issues/11762, this currently always returns Unknown
260 // type_info(sema, config, sema.resolve_type(&ast::Type::InferType(it))?, None)
261 None
238 }
262239}
263240
264241pub(super) fn keyword(
src/tools/rust-analyzer/crates/ide/src/hover/tests.rs+14-2
......@@ -8199,19 +8199,31 @@ fn main() {
81998199
82008200#[test]
82018201fn hover_underscore_type() {
8202 check_hover_no_result(
8202 check(
82038203 r#"
82048204fn main() {
82058205 let x: _$0 = 0;
82068206}
82078207"#,
8208 expect![[r#"
8209 *_*
8210 ```rust
8211 i32
8212 ```
8213 "#]],
82088214 );
8209 check_hover_no_result(
8215 check(
82108216 r#"
82118217fn main() {
82128218 let x: (_$0,) = (0,);
82138219}
82148220"#,
8221 expect![[r#"
8222 *_*
8223 ```rust
8224 i32
8225 ```
8226 "#]],
82158227 );
82168228}
82178229
src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs+22-6
......@@ -767,14 +767,30 @@ fn label_of_ty(
767767 )
768768 });
769769
770 let module_def_location = |label_builder: &mut InlayHintLabelBuilder<'_>,
771 def: ModuleDef,
772 name| {
773 let def = def.try_into();
774 if let Ok(def) = def {
775 label_builder.start_location_link(def);
776 }
777 #[expect(
778 clippy::question_mark,
779 reason = "false positive; replacing with `?` leads to 'type annotations needed' error"
780 )]
781 if let Err(err) = label_builder.write_str(name) {
782 return Err(err);
783 }
784 if def.is_ok() {
785 label_builder.end_location_link();
786 }
787 Ok(())
788 };
789
770790 label_builder.write_str(LABEL_START)?;
771 label_builder.start_location_link(ModuleDef::from(iter_trait).into());
772 label_builder.write_str(LABEL_ITERATOR)?;
773 label_builder.end_location_link();
791 module_def_location(label_builder, ModuleDef::from(iter_trait), LABEL_ITERATOR)?;
774792 label_builder.write_str(LABEL_MIDDLE)?;
775 label_builder.start_location_link(ModuleDef::from(item).into());
776 label_builder.write_str(LABEL_ITEM)?;
777 label_builder.end_location_link();
793 module_def_location(label_builder, ModuleDef::from(item), LABEL_ITEM)?;
778794 label_builder.write_str(LABEL_MIDDLE2)?;
779795 rec(sema, famous_defs, max_length, &ty, label_builder, config, display_target)?;
780796 label_builder.write_str(LABEL_END)?;
src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs+6-6
......@@ -339,14 +339,14 @@ fn main(a: SliceIter<'_, Container>) {
339339 fn lt_hints() {
340340 check_types(
341341 r#"
342struct S<'lt>;
342struct S<'lt>(*mut &'lt ());
343343
344344fn f<'a>() {
345 let x = S::<'static>;
345 let x = S::<'static>(loop {});
346346 //^ S<'static>
347 let y = S::<'_>;
347 let y = S::<'_>(loop {});
348348 //^ S<'_>
349 let z = S::<'a>;
349 let z = S::<'a>(loop {});
350350 //^ S<'a>
351351
352352}
......@@ -632,10 +632,10 @@ fn main() {
632632 fn multi_dyn_trait_bounds() {
633633 check_types(
634634 r#"
635pub struct Vec<T> {}
635pub struct Vec<T>(*mut T);
636636
637637impl<T> Vec<T> {
638 pub fn new() -> Self { Vec {} }
638 pub fn new() -> Self { Vec(0 as *mut T) }
639639}
640640
641641pub struct Box<T> {}
src/tools/rust-analyzer/crates/ide/src/inlay_hints/implicit_drop.rs+3-2
......@@ -34,9 +34,10 @@ pub(super) fn hints(
3434 let def = sema.to_def(node)?;
3535 let def: DefWithBody = def.into();
3636
37 let (hir, source_map) = sema.db.body_with_source_map(def.into());
37 let def = def.try_into().ok()?;
38 let (hir, source_map) = sema.db.body_with_source_map(def);
3839
39 let mir = sema.db.mir_body(def.into()).ok()?;
40 let mir = sema.db.mir_body(def).ok()?;
4041
4142 let local_to_binding = mir.local_to_binding_map();
4243
src/tools/rust-analyzer/crates/ide/src/inlay_hints/implied_dyn_trait.rs+1
......@@ -105,6 +105,7 @@ impl T {}
105105 // ^ dyn
106106impl T for (T) {}
107107 // ^ dyn
108impl T for {}
108109impl T
109110"#,
110111 );
src/tools/rust-analyzer/crates/ide/src/lib.rs+10-4
......@@ -67,7 +67,7 @@ use ide_db::{
6767 FxHashMap, FxIndexSet, LineIndexDatabase,
6868 base_db::{
6969 CrateOrigin, CrateWorkspaceData, Env, FileSet, RootQueryDb, SourceDatabase, VfsPath,
70 salsa::Cancelled,
70 salsa::{Cancelled, Database},
7171 },
7272 prime_caches, symbol_index,
7373};
......@@ -199,8 +199,13 @@ impl AnalysisHost {
199199 pub fn per_query_memory_usage(&mut self) -> Vec<(String, profile::Bytes, usize)> {
200200 self.db.per_query_memory_usage()
201201 }
202 pub fn request_cancellation(&mut self) {
203 self.db.request_cancellation();
202 pub fn trigger_cancellation(&mut self) {
203 self.db.trigger_cancellation();
204 }
205 pub fn trigger_garbage_collection(&mut self) {
206 self.db.trigger_lru_eviction();
207 // SAFETY: `trigger_lru_eviction` triggers cancellation, so all running queries were canceled.
208 unsafe { hir::collect_ty_garbage() };
204209 }
205210 pub fn raw_database(&self) -> &RootDatabase {
206211 &self.db
......@@ -853,8 +858,9 @@ impl Analysis {
853858 &self,
854859 file_id: FileId,
855860 new_name_stem: &str,
861 config: &RenameConfig,
856862 ) -> Cancellable<Option<SourceChange>> {
857 self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem))
863 self.with_db(|db| rename::will_rename_file(db, file_id, new_name_stem, config))
858864 }
859865
860866 pub fn structural_search_replace(
src/tools/rust-analyzer/crates/ide/src/navigation_target.rs+46-16
......@@ -6,7 +6,7 @@ use arrayvec::ArrayVec;
66use either::Either;
77use hir::{
88 AssocItem, Crate, FieldSource, HasContainer, HasCrate, HasSource, HirDisplay, HirFileId,
9 InFile, LocalSource, ModuleSource, Semantics, Symbol, db::ExpandDatabase, sym,
9 InFile, LocalSource, ModuleSource, Name, Semantics, Symbol, db::ExpandDatabase, sym,
1010 symbols::FileSymbol,
1111};
1212use ide_db::{
......@@ -204,6 +204,22 @@ impl NavigationTarget {
204204 )
205205 }
206206
207 pub(crate) fn from_named_with_range(
208 db: &RootDatabase,
209 ranges: InFile<(TextRange, Option<TextRange>)>,
210 name: Option<Name>,
211 kind: SymbolKind,
212 ) -> UpmappingResult<NavigationTarget> {
213 let InFile { file_id, value: (full_range, focus_range) } = ranges;
214 let name = name.map(|name| name.symbol().clone()).unwrap_or_else(|| sym::underscore);
215
216 orig_range_with_focus_r(db, file_id, full_range, focus_range).map(
217 |(FileRange { file_id, range: full_range }, focus_range)| {
218 NavigationTarget::from_syntax(file_id, name.clone(), focus_range, full_range, kind)
219 },
220 )
221 }
222
207223 pub(crate) fn from_syntax(
208224 file_id: FileId,
209225 name: Symbol,
......@@ -414,7 +430,13 @@ impl ToNavFromAst for hir::Trait {
414430
415431impl<D> TryToNav for D
416432where
417 D: HasSource + ToNavFromAst + Copy + HasDocs + for<'db> HirDisplay<'db> + HasCrate,
433 D: HasSource
434 + ToNavFromAst
435 + Copy
436 + HasDocs
437 + for<'db> HirDisplay<'db>
438 + HasCrate
439 + hir::HasName,
418440 D::Ast: ast::HasName,
419441{
420442 fn try_to_nav(
......@@ -422,11 +444,19 @@ where
422444 sema: &Semantics<'_, RootDatabase>,
423445 ) -> Option<UpmappingResult<NavigationTarget>> {
424446 let db = sema.db;
425 let src = self.source(db)?;
447 let src = self.source_with_range(db)?;
426448 Some(
427 NavigationTarget::from_named(
449 NavigationTarget::from_named_with_range(
428450 db,
429 src.as_ref().map(|it| it as &dyn ast::HasName),
451 src.map(|(full_range, node)| {
452 (
453 full_range,
454 node.and_then(|node| {
455 Some(ast::HasName::name(&node)?.syntax().text_range())
456 }),
457 )
458 }),
459 self.name(db),
430460 D::KIND,
431461 )
432462 .map(|mut res| {
......@@ -477,16 +507,16 @@ impl TryToNav for hir::Impl {
477507 sema: &Semantics<'_, RootDatabase>,
478508 ) -> Option<UpmappingResult<NavigationTarget>> {
479509 let db = sema.db;
480 let InFile { file_id, value } = self.source(db)?;
481 let derive_path = self.as_builtin_derive_path(db);
482
483 let (file_id, focus, syntax) = match &derive_path {
484 Some(attr) => (attr.file_id.into(), None, attr.value.syntax()),
485 None => (file_id, value.self_ty(), value.syntax()),
486 };
510 let InFile { file_id, value: (full_range, source) } = self.source_with_range(db)?;
487511
488 Some(orig_range_with_focus(db, file_id, syntax, focus).map(
489 |(FileRange { file_id, range: full_range }, focus_range)| {
512 Some(
513 orig_range_with_focus_r(
514 db,
515 file_id,
516 full_range,
517 source.and_then(|source| Some(source.self_ty()?.syntax().text_range())),
518 )
519 .map(|(FileRange { file_id, range: full_range }, focus_range)| {
490520 NavigationTarget::from_syntax(
491521 file_id,
492522 sym::kw_impl,
......@@ -494,8 +524,8 @@ impl TryToNav for hir::Impl {
494524 full_range,
495525 SymbolKind::Impl,
496526 )
497 },
498 ))
527 }),
528 )
499529 }
500530}
501531
src/tools/rust-analyzer/crates/ide/src/references.rs+1-1
......@@ -2503,7 +2503,7 @@ fn r#fn$0() {}
25032503fn main() { r#fn(); }
25042504"#,
25052505 expect![[r#"
2506 r#fn Function FileId(0) 0..12 3..7
2506 fn Function FileId(0) 0..12 3..7
25072507
25082508 FileId(0) 25..29
25092509 "#]],
src/tools/rust-analyzer/crates/ide/src/rename.rs+16-5
......@@ -31,6 +31,7 @@ pub struct RenameConfig {
3131 pub prefer_no_std: bool,
3232 pub prefer_prelude: bool,
3333 pub prefer_absolute: bool,
34 pub show_conflicts: bool,
3435}
3536
3637impl RenameConfig {
......@@ -42,6 +43,10 @@ impl RenameConfig {
4243 allow_unstable: true,
4344 }
4445 }
46
47 fn ide_db_config(&self) -> ide_db::rename::RenameConfig {
48 ide_db::rename::RenameConfig { show_conflicts: self.show_conflicts }
49 }
4550}
4651
4752/// This is similar to `collect::<Result<Vec<_>, _>>`, but unlike it, it succeeds if there is *any* `Ok` item.
......@@ -190,7 +195,7 @@ pub(crate) fn rename(
190195 return rename_to_self(&sema, local);
191196 }
192197 }
193 def.rename(&sema, new_name.as_str(), rename_def)
198 def.rename(&sema, new_name.as_str(), rename_def, &config.ide_db_config())
194199 })),
195200 };
196201
......@@ -205,11 +210,13 @@ pub(crate) fn will_rename_file(
205210 db: &RootDatabase,
206211 file_id: FileId,
207212 new_name_stem: &str,
213 config: &RenameConfig,
208214) -> Option<SourceChange> {
209215 let sema = Semantics::new(db);
210216 let module = sema.file_to_module_def(file_id)?;
211217 let def = Definition::Module(module);
212 let mut change = def.rename(&sema, new_name_stem, RenameDefinition::Yes).ok()?;
218 let mut change =
219 def.rename(&sema, new_name_stem, RenameDefinition::Yes, &config.ide_db_config()).ok()?;
213220 change.file_system_edits.clear();
214221 Some(change)
215222}
......@@ -803,8 +810,12 @@ mod tests {
803810
804811 use super::{RangeInfo, RenameConfig, RenameError};
805812
806 const TEST_CONFIG: RenameConfig =
807 RenameConfig { prefer_no_std: false, prefer_prelude: true, prefer_absolute: false };
813 const TEST_CONFIG: RenameConfig = RenameConfig {
814 prefer_no_std: false,
815 prefer_prelude: true,
816 prefer_absolute: false,
817 show_conflicts: true,
818 };
808819
809820 #[track_caller]
810821 fn check(
......@@ -893,7 +904,7 @@ mod tests {
893904 ) {
894905 let (analysis, position) = fixture::position(ra_fixture);
895906 let source_change = analysis
896 .will_rename_file(position.file_id, new_name)
907 .will_rename_file(position.file_id, new_name, &TEST_CONFIG)
897908 .unwrap()
898909 .expect("Expect returned a RenameError");
899910 expect.assert_eq(&filter_expect(source_change))
src/tools/rust-analyzer/crates/ide/src/runnables.rs+4-4
......@@ -1679,11 +1679,11 @@ mod r#mod {
16791679 [
16801680 "(TestMod, NavigationTarget { file_id: FileId(0), full_range: 1..461, focus_range: 5..10, name: \"mod\", kind: Module, description: \"mod r#mod\" })",
16811681 "(Test, NavigationTarget { file_id: FileId(0), full_range: 17..41, focus_range: 32..36, name: \"r#fn\", kind: Function })",
1682 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"r#for\", container_name: \"mod\" })",
1683 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"r#struct\", container_name: \"mod\" })",
1682 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 47..84, name: \"for\", container_name: \"mod\" })",
1683 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 90..146, name: \"struct\", container_name: \"mod\" })",
16841684 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 152..266, focus_range: 189..205, name: \"impl\", kind: Impl })",
1685 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"r#fn\" })",
1686 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"r#fn\" })",
1685 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 216..260, name: \"fn\" })",
1686 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 323..367, name: \"fn\" })",
16871687 "(DocTest, NavigationTarget { file_id: FileId(0), full_range: 401..459, focus_range: 445..456, name: \"impl\", kind: Impl })",
16881688 ]
16891689 "#]],
src/tools/rust-analyzer/crates/ide/src/ssr.rs+1-3
......@@ -58,9 +58,7 @@ pub(crate) fn ssr_assists(
5858mod tests {
5959 use expect_test::expect;
6060 use ide_assists::{Assist, AssistResolveStrategy};
61 use ide_db::{
62 FileRange, FxHashSet, RootDatabase, base_db::salsa::Setter as _, symbol_index::LocalRoots,
63 };
61 use ide_db::{FileRange, FxHashSet, LocalRoots, RootDatabase, base_db::salsa::Setter as _};
6462 use test_fixture::WithFixture;
6563
6664 use super::ssr_assists;
src/tools/rust-analyzer/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html+11-11
......@@ -101,18 +101,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
101101 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello, </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"world"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "Hello, world!"</span>
102102 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"The number is </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "The number is 1"</span>
103103 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="parenthesis macro">(</span><span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="numeric_literal macro">4</span><span class="parenthesis macro">)</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "(3, 4)"</span>
104 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "4"</span>
104 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">value</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">value</span><span class="operator macro">=</span><span class="numeric_literal macro">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "4"</span>
105105 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "1 2"</span>
106106 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="numeric_literal">4</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">42</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "0042" with leading zerosV</span>
107107 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1 1 2"</span>
108 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "test"</span>
109 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1"</span>
110 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="variable declaration macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="variable declaration macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "a 3 b"</span>
108 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">argument</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">argument</span> <span class="operator macro">=</span> <span class="string_literal macro">"test"</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "test"</span>
109 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">1</span><span class="comma macro">,</span> <span class="none macro">name</span> <span class="operator macro">=</span> <span class="numeric_literal macro">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "2 1"</span>
110 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">a</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">c</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="variable">b</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">a</span><span class="operator macro">=</span><span class="string_literal macro">"a"</span><span class="comma macro">,</span> <span class="none macro">b</span><span class="operator macro">=</span><span class="char_literal macro">'b'</span><span class="comma macro">,</span> <span class="none macro">c</span><span class="operator macro">=</span><span class="numeric_literal macro">3</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "a 3 b"</span>
111111 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="escape_sequence">{{</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="numeric_literal macro">2</span><span class="parenthesis">)</span><span class="semicolon">;</span> <span class="comment">// =&gt; "{2}"</span>
112112 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
113113 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
114114 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">1</span><span class="format_specifier">:</span><span class="numeric_literal">0</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
115 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
115 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">width</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">width</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="parenthesis">)</span><span class="semicolon">;</span>
116116 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
117117 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">-</span><span class="format_specifier">&lt;</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
118118 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">^</span><span class="numeric_literal">5</span><span class="format_specifier">}</span><span class="string_literal macro">!"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
......@@ -127,10 +127,10 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
127127 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="numeric_literal">0</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="numeric_literal">1</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
128128 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
129129 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="numeric_literal">2</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
130 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="variable declaration macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="variable declaration macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
131 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span>
132 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
133 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="variable declaration macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
130 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"Hello </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> is </span><span class="format_specifier">{</span><span class="variable">number</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="variable">prec</span><span class="format_specifier">$</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="string_literal macro">"x"</span><span class="comma macro">,</span> <span class="none macro">prec</span> <span class="operator macro">=</span> <span class="numeric_literal macro">5</span><span class="comma macro">,</span> <span class="none macro">number</span> <span class="operator macro">=</span> <span class="numeric_literal macro">0.01</span><span class="parenthesis">)</span><span class="semicolon">;</span>
131 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 fractional digits"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="numeric_literal macro">1234.56</span><span class="parenthesis">)</span><span class="semicolon">;</span>
132 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
133 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro">, `</span><span class="format_specifier">{</span><span class="variable">name</span><span class="format_specifier">:</span><span class="format_specifier">&gt;</span><span class="numeric_literal">8</span><span class="format_specifier">.</span><span class="format_specifier">*</span><span class="format_specifier">}</span><span class="string_literal macro">` has 3 right-aligned characters"</span><span class="comma macro">,</span> <span class="string_literal macro">"Hello"</span><span class="comma macro">,</span> <span class="numeric_literal macro">3</span><span class="comma macro">,</span> <span class="none macro">name</span><span class="operator macro">=</span><span class="string_literal macro">"1234.56"</span><span class="parenthesis">)</span><span class="semicolon">;</span>
134134
135135 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{}"</span>
136136 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"{{}}"</span><span class="semicolon">;</span>
......@@ -154,8 +154,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
154154 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
155155 <span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
156156
157 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
158 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="variable declaration macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
157 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
158 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="variable">ничоси</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">ничоси</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis">)</span><span class="semicolon">;</span>
159159
160160 <span class="macro public">println</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="format_specifier">:</span><span class="variable">x</span><span class="format_specifier">?</span><span class="format_specifier">}</span><span class="string_literal macro"> </span><span class="format_specifier">{</span><span class="format_specifier">}</span><span class="string_literal macro"> "</span><span class="comma macro">,</span> <span class="unresolved_reference macro">thingy</span><span class="comma macro">,</span> <span class="unresolved_reference macro">n2</span><span class="parenthesis">)</span><span class="semicolon">;</span>
161161 <span class="macro default_library library">panic</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="string_literal macro">"{}"</span><span class="comma macro">,</span> <span class="numeric_literal macro">0</span><span class="parenthesis">)</span><span class="semicolon">;</span>
src/tools/rust-analyzer/crates/intern/Cargo.toml-1
......@@ -18,7 +18,6 @@ dashmap.workspace = true
1818hashbrown.workspace = true
1919rustc-hash.workspace = true
2020triomphe.workspace = true
21smallvec.workspace = true
2221rayon.workspace = true
2322
2423[lints]
src/tools/rust-analyzer/crates/intern/src/gc.rs+6-5
......@@ -87,20 +87,20 @@ pub trait GcInternedSliceVisit: SliceInternable {
8787#[derive(Default)]
8888pub struct GarbageCollector {
8989 alive: FxHashSet<usize>,
90 storages: Vec<Box<dyn Storage + Send + Sync>>,
90 storages: Vec<&'static (dyn Storage + Send + Sync)>,
9191}
9292
9393impl GarbageCollector {
9494 pub fn add_storage<T: Internable + GcInternedVisit>(&mut self) {
9595 const { assert!(T::USE_GC) };
9696
97 self.storages.push(Box::new(InternedStorage::<T>(PhantomData)));
97 self.storages.push(&InternedStorage::<T>(PhantomData));
9898 }
9999
100100 pub fn add_slice_storage<T: SliceInternable + GcInternedSliceVisit>(&mut self) {
101101 const { assert!(T::USE_GC) };
102102
103 self.storages.push(Box::new(InternedSliceStorage::<T>(PhantomData)));
103 self.storages.push(&InternedSliceStorage::<T>(PhantomData));
104104 }
105105
106106 /// # Safety
......@@ -111,11 +111,12 @@ impl GarbageCollector {
111111 /// - [`GcInternedVisit`] and [`GcInternedSliceVisit`] must mark all values reachable from the node.
112112 pub unsafe fn collect(mut self) {
113113 let total_nodes = self.storages.iter().map(|storage| storage.len()).sum();
114 self.alive = FxHashSet::with_capacity_and_hasher(total_nodes, FxBuildHasher);
114 self.alive.clear();
115 self.alive.reserve(total_nodes);
115116
116117 let storages = std::mem::take(&mut self.storages);
117118
118 for storage in &storages {
119 for &storage in &storages {
119120 storage.mark(&mut self);
120121 }
121122
src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs+5
......@@ -525,5 +525,10 @@ define_symbols! {
525525 arbitrary_self_types,
526526 arbitrary_self_types_pointers,
527527 supertrait_item_shadowing,
528 hash,
529 partial_cmp,
530 cmp,
531 CoerceUnsized,
532 DispatchFromDyn,
528533 define_opaque,
529534}
src/tools/rust-analyzer/crates/load-cargo/src/lib.rs+25-7
......@@ -17,15 +17,23 @@ use hir_expand::proc_macro::{
1717};
1818use ide_db::{
1919 ChangeWithProcMacros, FxHashMap, RootDatabase,
20 base_db::{CrateGraphBuilder, Env, ProcMacroLoadingError, SourceRoot, SourceRootId},
20 base_db::{
21 CrateGraphBuilder, Env, ProcMacroLoadingError, SourceDatabase, SourceRoot, SourceRootId,
22 },
2123 prime_caches,
2224};
2325use itertools::Itertools;
24use proc_macro_api::{MacroDylib, ProcMacroClient};
26use proc_macro_api::{
27 MacroDylib, ProcMacroClient,
28 bidirectional_protocol::{
29 msg::{SubRequest, SubResponse},
30 reject_subrequests,
31 },
32};
2533use project_model::{CargoConfig, PackageRoot, ProjectManifest, ProjectWorkspace};
2634use span::Span;
2735use vfs::{
28 AbsPath, AbsPathBuf, VfsPath,
36 AbsPath, AbsPathBuf, FileId, VfsPath,
2937 file_set::FileSetConfig,
3038 loader::{Handle, LoadingProgress},
3139};
......@@ -425,7 +433,7 @@ pub fn load_proc_macro(
425433) -> ProcMacroLoadResult {
426434 let res: Result<Vec<_>, _> = (|| {
427435 let dylib = MacroDylib::new(path.to_path_buf());
428 let vec = server.load_dylib(dylib).map_err(|e| {
436 let vec = server.load_dylib(dylib, Some(&mut reject_subrequests)).map_err(|e| {
429437 ProcMacroLoadingError::ProcMacroSrvError(format!("{e}").into_boxed_str())
430438 })?;
431439 if vec.is_empty() {
......@@ -522,14 +530,23 @@ struct Expander(proc_macro_api::ProcMacro);
522530impl ProcMacroExpander for Expander {
523531 fn expand(
524532 &self,
525 subtree: &tt::TopSubtree<Span>,
526 attrs: Option<&tt::TopSubtree<Span>>,
533 db: &dyn SourceDatabase,
534 subtree: &tt::TopSubtree,
535 attrs: Option<&tt::TopSubtree>,
527536 env: &Env,
528537 def_site: Span,
529538 call_site: Span,
530539 mixed_site: Span,
531540 current_dir: String,
532 ) -> Result<tt::TopSubtree<Span>, ProcMacroExpansionError> {
541 ) -> Result<tt::TopSubtree, ProcMacroExpansionError> {
542 let mut cb = |req| match req {
543 SubRequest::SourceText { file_id, start, end } => {
544 let file = FileId::from_raw(file_id);
545 let text = db.file_text(file).text(db);
546 let slice = text.get(start as usize..end as usize).map(ToOwned::to_owned);
547 Ok(SubResponse::SourceTextResult { text: slice })
548 }
549 };
533550 match self.0.expand(
534551 subtree.view(),
535552 attrs.map(|attrs| attrs.view()),
......@@ -538,6 +555,7 @@ impl ProcMacroExpander for Expander {
538555 call_site,
539556 mixed_site,
540557 current_dir,
558 Some(&mut cb),
541559 ) {
542560 Ok(Ok(subtree)) => Ok(subtree),
543561 Ok(Err(err)) => Err(ProcMacroExpansionError::Panic(err)),
src/tools/rust-analyzer/crates/mbe/src/benchmark.rs+9-15
......@@ -2,7 +2,6 @@
22
33use intern::Symbol;
44use rustc_hash::FxHashMap;
5use span::Span;
65use stdx::itertools::Itertools;
76use syntax::{
87 AstNode,
......@@ -55,7 +54,7 @@ fn benchmark_expand_macro_rules() {
5554 .map(|(id, tt)| {
5655 let res = rules[&id].expand(&db, &tt, |_| (), MacroCallStyle::FnLike, DUMMY);
5756 assert!(res.err.is_none());
58 res.value.0.0.len()
57 res.value.0.as_token_trees().len()
5958 })
6059 .sum()
6160 };
......@@ -70,7 +69,7 @@ fn macro_rules_fixtures() -> FxHashMap<String, DeclarativeMacro> {
7069 .collect()
7170}
7271
73fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::TopSubtree<Span>> {
72fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::TopSubtree> {
7473 let fixture = bench_fixture::numerous_macro_rules();
7574 let source_file = ast::SourceFile::parse(&fixture, span::Edition::CURRENT).ok().unwrap();
7675
......@@ -95,7 +94,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::TopSubtree<Span>> {
9594fn invocation_fixtures(
9695 db: &dyn salsa::Database,
9796 rules: &FxHashMap<String, DeclarativeMacro>,
98) -> Vec<(String, tt::TopSubtree<Span>)> {
97) -> Vec<(String, tt::TopSubtree)> {
9998 let mut seed = 123456789;
10099 let mut res = Vec::new();
101100
......@@ -140,7 +139,7 @@ fn invocation_fixtures(
140139 }
141140 return res;
142141
143 fn collect_from_op(op: &Op, builder: &mut tt::TopSubtreeBuilder<Span>, seed: &mut usize) {
142 fn collect_from_op(op: &Op, builder: &mut tt::TopSubtreeBuilder, seed: &mut usize) {
144143 return match op {
145144 Op::Var { kind, .. } => match kind.as_ref() {
146145 Some(MetaVarKind::Ident) => builder.push(make_ident("foo")),
......@@ -226,25 +225,20 @@ fn invocation_fixtures(
226225 *seed = usize::wrapping_add(usize::wrapping_mul(*seed, a), c);
227226 *seed
228227 }
229 fn make_ident(ident: &str) -> tt::Leaf<Span> {
228 fn make_ident(ident: &str) -> tt::Leaf {
230229 tt::Leaf::Ident(tt::Ident {
231230 span: DUMMY,
232231 sym: Symbol::intern(ident),
233232 is_raw: tt::IdentIsRaw::No,
234233 })
235234 }
236 fn make_punct(char: char) -> tt::Leaf<Span> {
235 fn make_punct(char: char) -> tt::Leaf {
237236 tt::Leaf::Punct(tt::Punct { span: DUMMY, char, spacing: tt::Spacing::Alone })
238237 }
239 fn make_literal(lit: &str) -> tt::Leaf<Span> {
240 tt::Leaf::Literal(tt::Literal {
241 span: DUMMY,
242 symbol: Symbol::intern(lit),
243 kind: tt::LitKind::Str,
244 suffix: None,
245 })
238 fn make_literal(lit: &str) -> tt::Leaf {
239 tt::Leaf::Literal(tt::Literal::new_no_suffix(lit, DUMMY, tt::LitKind::Str))
246240 }
247 fn make_subtree(kind: tt::DelimiterKind, builder: &mut tt::TopSubtreeBuilder<Span>) {
241 fn make_subtree(kind: tt::DelimiterKind, builder: &mut tt::TopSubtreeBuilder) {
248242 builder.open(kind, DUMMY);
249243 builder.close(DUMMY);
250244 }
src/tools/rust-analyzer/crates/mbe/src/expander.rs+7-7
......@@ -17,11 +17,11 @@ use crate::{
1717pub(crate) fn expand_rules(
1818 db: &dyn salsa::Database,
1919 rules: &[crate::Rule],
20 input: &tt::TopSubtree<Span>,
20 input: &tt::TopSubtree,
2121 marker: impl Fn(&mut Span) + Copy,
2222 call_style: MacroCallStyle,
2323 call_site: Span,
24) -> ExpandResult<(tt::TopSubtree<Span>, MatchedArmIndex)> {
24) -> ExpandResult<(tt::TopSubtree, MatchedArmIndex)> {
2525 let mut match_: Option<(matcher::Match<'_>, &crate::Rule, usize)> = None;
2626 for (idx, rule) in rules.iter().enumerate() {
2727 // Skip any rules that aren't relevant to the call style (fn-like/attr/derive).
......@@ -129,7 +129,7 @@ enum Fragment<'a> {
129129 Empty,
130130 /// token fragments are just copy-pasted into the output
131131 Tokens {
132 tree: tt::TokenTreesView<'a, Span>,
132 tree: tt::TokenTreesView<'a>,
133133 origin: TokensOrigin,
134134 },
135135 /// Expr ast fragments are surrounded with `()` on transcription to preserve precedence.
......@@ -141,7 +141,7 @@ enum Fragment<'a> {
141141 /// tricky to handle in the parser, and rustc doesn't handle those either.
142142 ///
143143 /// The span of the outer delimiters is marked on transcription.
144 Expr(tt::TokenTreesView<'a, Span>),
144 Expr(tt::TokenTreesView<'a>),
145145 /// There are roughly two types of paths: paths in expression context, where a
146146 /// separator `::` between an identifier and its following generic argument list
147147 /// is mandatory, and paths in type context, where `::` can be omitted.
......@@ -151,8 +151,8 @@ enum Fragment<'a> {
151151 /// and is trasncribed as an expression-context path, verbatim transcription
152152 /// would cause a syntax error. We need to fix it up just before transcribing;
153153 /// see `transcriber::fix_up_and_push_path_tt()`.
154 Path(tt::TokenTreesView<'a, Span>),
155 TokensOwned(tt::TopSubtree<Span>),
154 Path(tt::TokenTreesView<'a>),
155 TokensOwned(tt::TopSubtree),
156156}
157157
158158impl Fragment<'_> {
......@@ -162,7 +162,7 @@ impl Fragment<'_> {
162162 Fragment::Tokens { tree, .. } => tree.len() == 0,
163163 Fragment::Expr(it) => it.len() == 0,
164164 Fragment::Path(it) => it.len() == 0,
165 Fragment::TokensOwned(it) => it.0.is_empty(),
165 Fragment::TokensOwned(_) => false, // A `TopSubtree` is never empty
166166 }
167167 }
168168}
src/tools/rust-analyzer/crates/mbe/src/expander/matcher.rs+23-23
......@@ -63,7 +63,6 @@ use std::{rc::Rc, sync::Arc};
6363
6464use intern::{Symbol, sym};
6565use smallvec::{SmallVec, smallvec};
66use span::Span;
6766use tt::{
6867 DelimSpan,
6968 iter::{TtElement, TtIter},
......@@ -114,7 +113,7 @@ impl Match<'_> {
114113pub(super) fn match_<'t>(
115114 db: &dyn salsa::Database,
116115 pattern: &'t MetaTemplate,
117 input: &'t tt::TopSubtree<Span>,
116 input: &'t tt::TopSubtree,
118117) -> Match<'t> {
119118 let mut res = match_loop(db, pattern, input);
120119 res.bound_count = count(res.bindings.bindings());
......@@ -339,7 +338,7 @@ struct MatchState<'t> {
339338 bindings: BindingsIdx,
340339
341340 /// Cached result of meta variable parsing
342 meta_result: Option<(TtIter<'t, Span>, ExpandResult<Option<Fragment<'t>>>)>,
341 meta_result: Option<(TtIter<'t>, ExpandResult<Option<Fragment<'t>>>)>,
343342
344343 /// Is error occurred in this state, will `poised` to "parent"
345344 is_error: bool,
......@@ -366,8 +365,8 @@ struct MatchState<'t> {
366365#[inline]
367366fn match_loop_inner<'t>(
368367 db: &dyn salsa::Database,
369 src: TtIter<'t, Span>,
370 stack: &[TtIter<'t, Span>],
368 src: TtIter<'t>,
369 stack: &[TtIter<'t>],
371370 res: &mut Match<'t>,
372371 bindings_builder: &mut BindingsBuilder<'t>,
373372 cur_items: &mut SmallVec<[MatchState<'t>; 1]>,
......@@ -375,7 +374,7 @@ fn match_loop_inner<'t>(
375374 next_items: &mut Vec<MatchState<'t>>,
376375 eof_items: &mut SmallVec<[MatchState<'t>; 1]>,
377376 error_items: &mut SmallVec<[MatchState<'t>; 1]>,
378 delim_span: tt::DelimSpan<Span>,
377 delim_span: tt::DelimSpan,
379378) {
380379 macro_rules! try_push {
381380 ($items: expr, $it:expr) => {
......@@ -518,7 +517,8 @@ fn match_loop_inner<'t>(
518517 }
519518 OpDelimited::Op(Op::Literal(lhs)) => {
520519 if let Ok(rhs) = src.clone().expect_leaf() {
521 if matches!(rhs, tt::Leaf::Literal(it) if it.symbol == lhs.symbol) {
520 if matches!(&rhs, tt::Leaf::Literal(it) if it.text_and_suffix == lhs.text_and_suffix)
521 {
522522 item.dot.next();
523523 } else {
524524 res.add_err(ExpandError::new(
......@@ -538,7 +538,7 @@ fn match_loop_inner<'t>(
538538 }
539539 OpDelimited::Op(Op::Ident(lhs)) => {
540540 if let Ok(rhs) = src.clone().expect_leaf() {
541 if matches!(rhs, tt::Leaf::Ident(it) if it.sym == lhs.sym) {
541 if matches!(&rhs, tt::Leaf::Ident(it) if it.sym == lhs.sym) {
542542 item.dot.next();
543543 } else {
544544 res.add_err(ExpandError::new(
......@@ -623,11 +623,11 @@ fn match_loop_inner<'t>(
623623fn match_loop<'t>(
624624 db: &dyn salsa::Database,
625625 pattern: &'t MetaTemplate,
626 src: &'t tt::TopSubtree<Span>,
626 src: &'t tt::TopSubtree,
627627) -> Match<'t> {
628628 let span = src.top_subtree().delimiter.delim_span();
629629 let mut src = src.iter();
630 let mut stack: SmallVec<[TtIter<'_, Span>; 1]> = SmallVec::new();
630 let mut stack: SmallVec<[TtIter<'_>; 1]> = SmallVec::new();
631631 let mut res = Match::default();
632632 let mut error_recover_item = None;
633633
......@@ -702,7 +702,7 @@ fn match_loop<'t>(
702702 || !(bb_items.is_empty() || next_items.is_empty())
703703 || bb_items.len() > 1;
704704 if has_leftover_tokens {
705 res.unmatched_tts += src.remaining().flat_tokens().len();
705 res.unmatched_tts += src.remaining().len();
706706 res.add_err(ExpandError::new(span.open, ExpandErrorKind::LeftoverTokens));
707707
708708 if let Some(error_recover_item) = error_recover_item {
......@@ -774,8 +774,8 @@ fn match_loop<'t>(
774774fn match_meta_var<'t>(
775775 db: &dyn salsa::Database,
776776 kind: MetaVarKind,
777 input: &mut TtIter<'t, Span>,
778 delim_span: DelimSpan<Span>,
777 input: &mut TtIter<'t>,
778 delim_span: DelimSpan,
779779) -> ExpandResult<Fragment<'t>> {
780780 let fragment = match kind {
781781 MetaVarKind::Path => {
......@@ -879,10 +879,10 @@ fn collect_vars(collector_fun: &mut impl FnMut(Symbol), pattern: &MetaTemplate)
879879 }
880880}
881881impl MetaTemplate {
882 fn iter_delimited_with(&self, delimiter: tt::Delimiter<Span>) -> OpDelimitedIter<'_> {
882 fn iter_delimited_with(&self, delimiter: tt::Delimiter) -> OpDelimitedIter<'_> {
883883 OpDelimitedIter { inner: &self.0, idx: 0, delimited: delimiter }
884884 }
885 fn iter_delimited(&self, span: tt::DelimSpan<Span>) -> OpDelimitedIter<'_> {
885 fn iter_delimited(&self, span: tt::DelimSpan) -> OpDelimitedIter<'_> {
886886 OpDelimitedIter {
887887 inner: &self.0,
888888 idx: 0,
......@@ -901,7 +901,7 @@ enum OpDelimited<'a> {
901901#[derive(Debug, Clone, Copy)]
902902struct OpDelimitedIter<'a> {
903903 inner: &'a [Op],
904 delimited: tt::Delimiter<Span>,
904 delimited: tt::Delimiter,
905905 idx: usize,
906906}
907907
......@@ -945,7 +945,7 @@ impl<'a> Iterator for OpDelimitedIter<'a> {
945945 }
946946}
947947
948fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) -> bool {
948fn expect_separator(iter: &mut TtIter<'_>, separator: &Separator) -> bool {
949949 let mut fork = iter.clone();
950950 let ok = match separator {
951951 Separator::Ident(lhs) => match fork.expect_ident_or_underscore() {
......@@ -954,8 +954,8 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
954954 },
955955 Separator::Literal(lhs) => match fork.expect_literal() {
956956 Ok(rhs) => match rhs {
957 tt::Leaf::Literal(rhs) => rhs.symbol == lhs.symbol,
958 tt::Leaf::Ident(rhs) => rhs.sym == lhs.symbol,
957 tt::Leaf::Literal(rhs) => rhs.text_and_suffix == lhs.text_and_suffix,
958 tt::Leaf::Ident(rhs) => rhs.sym == lhs.text_and_suffix,
959959 tt::Leaf::Punct(_) => false,
960960 },
961961 Err(_) => false,
......@@ -979,7 +979,7 @@ fn expect_separator<S: Copy>(iter: &mut TtIter<'_, S>, separator: &Separator) ->
979979 ok
980980}
981981
982fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
982fn expect_tt(iter: &mut TtIter<'_>) -> Result<(), ()> {
983983 if let Some(TtElement::Leaf(tt::Leaf::Punct(punct))) = iter.peek() {
984984 if punct.char == '\'' {
985985 expect_lifetime(iter)?;
......@@ -992,7 +992,7 @@ fn expect_tt<S: Copy>(iter: &mut TtIter<'_, S>) -> Result<(), ()> {
992992 Ok(())
993993}
994994
995fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Ident<S>, ()> {
995fn expect_lifetime<'a>(iter: &mut TtIter<'a>) -> Result<tt::Ident, ()> {
996996 let punct = iter.expect_single_punct()?;
997997 if punct.char != '\'' {
998998 return Err(());
......@@ -1000,8 +1000,8 @@ fn expect_lifetime<'a, S: Copy>(iter: &mut TtIter<'a, S>) -> Result<&'a tt::Iden
10001000 iter.expect_ident_or_underscore()
10011001}
10021002
1003fn eat_char<S: Copy>(iter: &mut TtIter<'_, S>, c: char) {
1004 if matches!(iter.peek(), Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char, .. }))) if *char == c)
1003fn eat_char(iter: &mut TtIter<'_>, c: char) {
1004 if matches!(iter.peek(), Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char, .. }))) if char == c)
10051005 {
10061006 iter.next().expect("already peeked");
10071007 }
src/tools/rust-analyzer/crates/mbe/src/expander/transcriber.rs+28-28
......@@ -3,6 +3,7 @@
33
44use intern::{Symbol, sym};
55use span::{Edition, Span};
6use stdx::itertools::Itertools;
67use tt::{Delimiter, TopSubtreeBuilder, iter::TtElement};
78
89use super::TokensOrigin;
......@@ -125,7 +126,7 @@ pub(super) fn transcribe(
125126 bindings: &Bindings<'_>,
126127 marker: impl Fn(&mut Span) + Copy,
127128 call_site: Span,
128) -> ExpandResult<tt::TopSubtree<Span>> {
129) -> ExpandResult<tt::TopSubtree> {
129130 let mut ctx = ExpandCtx { bindings, nesting: Vec::new(), call_site };
130131 let mut builder = tt::TopSubtreeBuilder::new(tt::Delimiter::invisible_spanned(ctx.call_site));
131132 expand_subtree(&mut ctx, template, &mut builder, marker).map(|()| builder.build())
......@@ -152,8 +153,8 @@ struct ExpandCtx<'a> {
152153fn expand_subtree_with_delimiter(
153154 ctx: &mut ExpandCtx<'_>,
154155 template: &MetaTemplate,
155 builder: &mut tt::TopSubtreeBuilder<Span>,
156 delimiter: Option<Delimiter<Span>>,
156 builder: &mut tt::TopSubtreeBuilder,
157 delimiter: Option<Delimiter>,
157158 marker: impl Fn(&mut Span) + Copy,
158159) -> ExpandResult<()> {
159160 let delimiter = delimiter.unwrap_or_else(|| tt::Delimiter::invisible_spanned(ctx.call_site));
......@@ -166,7 +167,7 @@ fn expand_subtree_with_delimiter(
166167fn expand_subtree(
167168 ctx: &mut ExpandCtx<'_>,
168169 template: &MetaTemplate,
169 builder: &mut tt::TopSubtreeBuilder<Span>,
170 builder: &mut tt::TopSubtreeBuilder,
170171 marker: impl Fn(&mut Span) + Copy,
171172) -> ExpandResult<()> {
172173 let mut err = None;
......@@ -221,10 +222,10 @@ fn expand_subtree(
221222 let index =
222223 ctx.nesting.get(ctx.nesting.len() - 1 - depth).map_or(0, |nest| nest.idx);
223224 builder.push(tt::Leaf::Literal(tt::Literal {
224 symbol: Symbol::integer(index),
225 text_and_suffix: Symbol::integer(index),
225226 span: ctx.call_site,
226227 kind: tt::LitKind::Integer,
227 suffix: None,
228 suffix_len: 0,
228229 }));
229230 }
230231 Op::Len { depth } => {
......@@ -233,10 +234,10 @@ fn expand_subtree(
233234 0
234235 });
235236 builder.push(tt::Leaf::Literal(tt::Literal {
236 symbol: Symbol::integer(length),
237 text_and_suffix: Symbol::integer(length),
237238 span: ctx.call_site,
238239 kind: tt::LitKind::Integer,
239 suffix: None,
240 suffix_len: 0,
240241 }));
241242 }
242243 Op::Count { name, depth } => {
......@@ -277,9 +278,9 @@ fn expand_subtree(
277278 let res = count(binding, 0, depth.unwrap_or(0));
278279
279280 builder.push(tt::Leaf::Literal(tt::Literal {
280 symbol: Symbol::integer(res),
281 text_and_suffix: Symbol::integer(res),
281282 span: ctx.call_site,
282 suffix: None,
283 suffix_len: 0,
283284 kind: tt::LitKind::Integer,
284285 }));
285286 }
......@@ -293,7 +294,7 @@ fn expand_subtree(
293294 ConcatMetaVarExprElem::Literal(lit) => {
294295 // FIXME: This isn't really correct wrt. escaping, but that's what rustc does and anyway
295296 // escaping is used most of the times for characters that are invalid in identifiers.
296 concatenated.push_str(lit.symbol.as_str())
297 concatenated.push_str(lit.text())
297298 }
298299 ConcatMetaVarExprElem::Var(var) => {
299300 // Handling of repetitions in `${concat}` isn't fleshed out in rustc, so we currently
......@@ -324,13 +325,11 @@ fn expand_subtree(
324325 }
325326 _ => (None, None),
326327 };
327 let value = match values {
328 let value = match &values {
328329 (Some(TtElement::Leaf(tt::Leaf::Ident(ident))), None) => {
329330 ident.sym.as_str()
330331 }
331 (Some(TtElement::Leaf(tt::Leaf::Literal(lit))), None) => {
332 lit.symbol.as_str()
333 }
332 (Some(TtElement::Leaf(tt::Leaf::Literal(lit))), None) => lit.text(),
334333 _ => {
335334 if err.is_none() {
336335 err = Some(ExpandError::binding_error(
......@@ -382,7 +381,7 @@ fn expand_var(
382381 ctx: &mut ExpandCtx<'_>,
383382 v: &Symbol,
384383 id: Span,
385 builder: &mut tt::TopSubtreeBuilder<Span>,
384 builder: &mut tt::TopSubtreeBuilder,
386385 marker: impl Fn(&mut Span) + Copy,
387386) -> ExpandResult<()> {
388387 // We already handle $crate case in mbe parser
......@@ -412,15 +411,15 @@ fn expand_var(
412411 // Check if this is a simple negative literal (MINUS + LITERAL)
413412 // that should not be wrapped in parentheses
414413 let is_negative_literal = matches!(
415 sub.flat_tokens(),
416 [
417 tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
418 tt::TokenTree::Leaf(tt::Leaf::Literal(_))
419 ]
414 sub.iter().collect_array(),
415 Some([
416 tt::TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: '-', .. })),
417 tt::TtElement::Leaf(tt::Leaf::Literal(_))
418 ])
420419 );
421420
422421 let wrap_in_parens = !is_negative_literal
423 && !matches!(sub.flat_tokens(), [tt::TokenTree::Leaf(_)])
422 && !matches!(sub.iter().collect_array(), Some([tt::TtElement::Leaf(_)]))
424423 && sub.try_into_subtree().is_none_or(|it| {
425424 it.top_subtree().delimiter.kind == tt::DelimiterKind::Invisible
426425 });
......@@ -466,7 +465,7 @@ fn expand_repeat(
466465 template: &MetaTemplate,
467466 kind: RepeatKind,
468467 separator: Option<&Separator>,
469 builder: &mut tt::TopSubtreeBuilder<Span>,
468 builder: &mut tt::TopSubtreeBuilder,
470469 marker: impl Fn(&mut Span) + Copy,
471470) -> ExpandResult<()> {
472471 ctx.nesting.push(NestingState { idx: 0, at_end: false, hit: false });
......@@ -546,8 +545,8 @@ fn expand_repeat(
546545/// we need this fixup.
547546fn fix_up_and_push_path_tt(
548547 ctx: &ExpandCtx<'_>,
549 builder: &mut tt::TopSubtreeBuilder<Span>,
550 subtree: tt::TokenTreesView<'_, Span>,
548 builder: &mut tt::TopSubtreeBuilder,
549 subtree: tt::TokenTreesView<'_>,
551550) {
552551 let mut prev_was_ident = false;
553552 // Note that we only need to fix up the top-level `TokenTree`s because the
......@@ -560,8 +559,8 @@ fn fix_up_and_push_path_tt(
560559 // argument list and thus needs `::` between it and `FnOnce`. However in
561560 // today's Rust this type of path *semantically* cannot appear as a
562561 // top-level expression-context path, so we can safely ignore it.
563 if let [tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '<', .. }))] =
564 tt.flat_tokens()
562 if let Some([tt::TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: '<', .. }))]) =
563 tt.iter().collect_array()
565564 {
566565 builder.extend([
567566 tt::Leaf::Punct(tt::Punct {
......@@ -577,7 +576,8 @@ fn fix_up_and_push_path_tt(
577576 ]);
578577 }
579578 }
580 prev_was_ident = matches!(tt.flat_tokens(), [tt::TokenTree::Leaf(tt::Leaf::Ident(_))]);
579 prev_was_ident =
580 matches!(tt.iter().collect_array(), Some([tt::TtElement::Leaf(tt::Leaf::Ident(_))]));
581581 builder.extend_with_tt(tt);
582582 }
583583}
src/tools/rust-analyzer/crates/mbe/src/lib.rs+9-9
......@@ -152,7 +152,7 @@ impl DeclarativeMacro {
152152
153153 /// The old, `macro_rules! m {}` flavor.
154154 pub fn parse_macro_rules(
155 tt: &tt::TopSubtree<Span>,
155 tt: &tt::TopSubtree,
156156 ctx_edition: impl Copy + Fn(SyntaxContext) -> Edition,
157157 ) -> DeclarativeMacro {
158158 // Note: this parsing can be implemented using mbe machinery itself, by
......@@ -191,8 +191,8 @@ impl DeclarativeMacro {
191191
192192 /// The new, unstable `macro m {}` flavor.
193193 pub fn parse_macro2(
194 args: Option<&tt::TopSubtree<Span>>,
195 body: &tt::TopSubtree<Span>,
194 args: Option<&tt::TopSubtree>,
195 body: &tt::TopSubtree,
196196 ctx_edition: impl Copy + Fn(SyntaxContext) -> Edition,
197197 ) -> DeclarativeMacro {
198198 let mut rules = Vec::new();
......@@ -276,11 +276,11 @@ impl DeclarativeMacro {
276276 pub fn expand(
277277 &self,
278278 db: &dyn salsa::Database,
279 tt: &tt::TopSubtree<Span>,
279 tt: &tt::TopSubtree,
280280 marker: impl Fn(&mut Span) + Copy,
281281 call_style: MacroCallStyle,
282282 call_site: Span,
283 ) -> ExpandResult<(tt::TopSubtree<Span>, MatchedArmIndex)> {
283 ) -> ExpandResult<(tt::TopSubtree, MatchedArmIndex)> {
284284 expander::expand_rules(db, &self.rules, tt, marker, call_style, call_site)
285285 }
286286}
......@@ -288,7 +288,7 @@ impl DeclarativeMacro {
288288impl Rule {
289289 fn parse(
290290 edition: impl Copy + Fn(SyntaxContext) -> Edition,
291 src: &mut TtIter<'_, Span>,
291 src: &mut TtIter<'_>,
292292 ) -> Result<Self, ParseError> {
293293 // Parse an optional `attr()` or `derive()` prefix before the LHS pattern.
294294 let style = parser::parse_rule_style(src)?;
......@@ -391,10 +391,10 @@ impl<T: Default, E> From<Result<T, E>> for ValueResult<T, E> {
391391
392392pub fn expect_fragment<'t>(
393393 db: &dyn salsa::Database,
394 tt_iter: &mut TtIter<'t, Span>,
394 tt_iter: &mut TtIter<'t>,
395395 entry_point: ::parser::PrefixEntryPoint,
396 delim_span: DelimSpan<Span>,
397) -> ExpandResult<tt::TokenTreesView<'t, Span>> {
396 delim_span: DelimSpan,
397) -> ExpandResult<tt::TokenTreesView<'t>> {
398398 use ::parser;
399399 let buffer = tt_iter.remaining();
400400 let parser_input = to_parser_input(buffer, &mut |ctx| ctx.edition(db));
src/tools/rust-analyzer/crates/mbe/src/parser.rs+35-34
......@@ -13,7 +13,7 @@ use tt::{
1313
1414use crate::{MacroCallStyle, ParseError};
1515
16pub(crate) fn parse_rule_style(src: &mut TtIter<'_, Span>) -> Result<MacroCallStyle, ParseError> {
16pub(crate) fn parse_rule_style(src: &mut TtIter<'_>) -> Result<MacroCallStyle, ParseError> {
1717 // Skip an optional `unsafe`. This is only actually allowed for `attr`
1818 // rules, but we'll let rustc worry about that.
1919 if let Some(TtElement::Leaf(tt::Leaf::Ident(ident))) = src.peek()
......@@ -59,14 +59,14 @@ pub(crate) struct MetaTemplate(pub(crate) Box<[Op]>);
5959impl MetaTemplate {
6060 pub(crate) fn parse_pattern(
6161 edition: impl Copy + Fn(SyntaxContext) -> Edition,
62 pattern: TtIter<'_, Span>,
62 pattern: TtIter<'_>,
6363 ) -> Result<Self, ParseError> {
6464 MetaTemplate::parse(edition, pattern, Mode::Pattern)
6565 }
6666
6767 pub(crate) fn parse_template(
6868 edition: impl Copy + Fn(SyntaxContext) -> Edition,
69 template: TtIter<'_, Span>,
69 template: TtIter<'_>,
7070 ) -> Result<Self, ParseError> {
7171 MetaTemplate::parse(edition, template, Mode::Template)
7272 }
......@@ -77,7 +77,7 @@ impl MetaTemplate {
7777
7878 fn parse(
7979 edition: impl Copy + Fn(SyntaxContext) -> Edition,
80 mut src: TtIter<'_, Span>,
80 mut src: TtIter<'_>,
8181 mode: Mode,
8282 ) -> Result<Self, ParseError> {
8383 let mut res = Vec::new();
......@@ -123,23 +123,23 @@ pub(crate) enum Op {
123123 },
124124 Subtree {
125125 tokens: MetaTemplate,
126 delimiter: tt::Delimiter<Span>,
126 delimiter: tt::Delimiter,
127127 },
128 Literal(tt::Literal<Span>),
129 Punct(Box<ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>>),
130 Ident(tt::Ident<Span>),
128 Literal(tt::Literal),
129 Punct(Box<ArrayVec<tt::Punct, MAX_GLUED_PUNCT_LEN>>),
130 Ident(tt::Ident),
131131}
132132
133133#[derive(Clone, Debug, PartialEq, Eq)]
134134pub(crate) enum ConcatMetaVarExprElem {
135135 /// There is NO preceding dollar sign, which means that this identifier should be interpreted
136136 /// as a literal.
137 Ident(tt::Ident<Span>),
137 Ident(tt::Ident),
138138 /// There is a preceding dollar sign, which means that this identifier should be expanded
139139 /// and interpreted as a variable.
140 Var(tt::Ident<Span>),
140 Var(tt::Ident),
141141 /// For example, a number or a string.
142 Literal(tt::Literal<Span>),
142 Literal(tt::Literal),
143143}
144144
145145#[derive(Copy, Clone, Debug, PartialEq, Eq)]
......@@ -179,10 +179,10 @@ pub(crate) enum MetaVarKind {
179179
180180#[derive(Clone, Debug, Eq)]
181181pub(crate) enum Separator {
182 Literal(tt::Literal<Span>),
183 Ident(tt::Ident<Span>),
184 Puncts(ArrayVec<tt::Punct<Span>, MAX_GLUED_PUNCT_LEN>),
185 Lifetime(tt::Punct<Span>, tt::Ident<Span>),
182 Literal(tt::Literal),
183 Ident(tt::Ident),
184 Puncts(ArrayVec<tt::Punct, MAX_GLUED_PUNCT_LEN>),
185 Lifetime(tt::Punct, tt::Ident),
186186}
187187
188188// Note that when we compare a Separator, we just care about its textual value.
......@@ -192,7 +192,7 @@ impl PartialEq for Separator {
192192
193193 match (self, other) {
194194 (Ident(a), Ident(b)) => a.sym == b.sym,
195 (Literal(a), Literal(b)) => a.symbol == b.symbol,
195 (Literal(a), Literal(b)) => a.text_and_suffix == b.text_and_suffix,
196196 (Puncts(a), Puncts(b)) if a.len() == b.len() => {
197197 let a_iter = a.iter().map(|a| a.char);
198198 let b_iter = b.iter().map(|b| b.char);
......@@ -212,8 +212,8 @@ enum Mode {
212212
213213fn next_op(
214214 edition: impl Copy + Fn(SyntaxContext) -> Edition,
215 first_peeked: TtElement<'_, Span>,
216 src: &mut TtIter<'_, Span>,
215 first_peeked: TtElement<'_>,
216 src: &mut TtIter<'_>,
217217 mode: Mode,
218218) -> Result<Op, ParseError> {
219219 let res = match first_peeked {
......@@ -224,7 +224,7 @@ fn next_op(
224224 None => {
225225 return Ok(Op::Punct({
226226 let mut res = ArrayVec::new();
227 res.push(*p);
227 res.push(p);
228228 Box::new(res)
229229 }));
230230 }
......@@ -268,9 +268,9 @@ fn next_op(
268268 let id = ident.span;
269269 Op::Var { name, kind, id }
270270 }
271 tt::Leaf::Literal(lit) if is_boolean_literal(lit) => {
271 tt::Leaf::Literal(lit) if is_boolean_literal(&lit) => {
272272 let kind = eat_fragment_kind(edition, src, mode)?;
273 let name = lit.symbol.clone();
273 let name = lit.text_and_suffix.clone();
274274 let id = lit.span;
275275 Op::Var { name, kind, id }
276276 }
......@@ -282,7 +282,7 @@ fn next_op(
282282 }
283283 Mode::Template => Op::Punct({
284284 let mut res = ArrayVec::new();
285 res.push(*punct);
285 res.push(punct);
286286 Box::new(res)
287287 }),
288288 },
......@@ -320,7 +320,7 @@ fn next_op(
320320
321321fn eat_fragment_kind(
322322 edition: impl Copy + Fn(SyntaxContext) -> Edition,
323 src: &mut TtIter<'_, Span>,
323 src: &mut TtIter<'_>,
324324 mode: Mode,
325325) -> Result<Option<MetaVarKind>, ParseError> {
326326 if let Mode::Pattern = mode {
......@@ -363,11 +363,11 @@ fn eat_fragment_kind(
363363 Ok(None)
364364}
365365
366fn is_boolean_literal(lit: &tt::Literal<Span>) -> bool {
367 matches!(lit.symbol.as_str(), "true" | "false")
366fn is_boolean_literal(lit: &tt::Literal) -> bool {
367 lit.text_and_suffix == sym::true_ || lit.text_and_suffix == sym::false_
368368}
369369
370fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
370fn parse_repeat(src: &mut TtIter<'_>) -> Result<(Option<Separator>, RepeatKind), ParseError> {
371371 let mut separator = Separator::Puncts(ArrayVec::new());
372372 for tt in src {
373373 let tt = match tt {
......@@ -400,7 +400,7 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
400400 '?' => RepeatKind::ZeroOrOne,
401401 _ => match &mut separator {
402402 Separator::Puncts(puncts) if puncts.len() < 3 => {
403 puncts.push(*punct);
403 puncts.push(punct);
404404 continue;
405405 }
406406 _ => return Err(ParseError::InvalidRepeat),
......@@ -413,7 +413,7 @@ fn parse_repeat(src: &mut TtIter<'_, Span>) -> Result<(Option<Separator>, Repeat
413413 Err(ParseError::InvalidRepeat)
414414}
415415
416fn parse_metavar_expr(src: &mut TtIter<'_, Span>) -> Result<Op, ()> {
416fn parse_metavar_expr(src: &mut TtIter<'_>) -> Result<Op, ()> {
417417 let func = src.expect_ident()?;
418418 let (args, mut args_iter) = src.expect_subtree()?;
419419
......@@ -475,20 +475,21 @@ fn parse_metavar_expr(src: &mut TtIter<'_, Span>) -> Result<Op, ()> {
475475 Ok(op)
476476}
477477
478fn parse_depth(src: &mut TtIter<'_, Span>) -> Result<usize, ()> {
478fn parse_depth(src: &mut TtIter<'_>) -> Result<usize, ()> {
479479 if src.is_empty() {
480480 Ok(0)
481 } else if let tt::Leaf::Literal(tt::Literal { symbol: text, suffix: None, .. }) =
482 src.expect_literal()?
481 } else if let tt::Leaf::Literal(lit) = src.expect_literal()?
482 && let (text, suffix) = lit.text_and_suffix()
483 && suffix.is_empty()
483484 {
484485 // Suffixes are not allowed.
485 text.as_str().parse().map_err(|_| ())
486 text.parse().map_err(|_| ())
486487 } else {
487488 Err(())
488489 }
489490}
490491
491fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool {
492fn try_eat_comma(src: &mut TtIter<'_>) -> bool {
492493 if let Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: ',', .. }))) = src.peek() {
493494 let _ = src.next();
494495 return true;
......@@ -496,7 +497,7 @@ fn try_eat_comma(src: &mut TtIter<'_, Span>) -> bool {
496497 false
497498}
498499
499fn try_eat_dollar(src: &mut TtIter<'_, Span>) -> bool {
500fn try_eat_dollar(src: &mut TtIter<'_>) -> bool {
500501 if let Some(TtElement::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. }))) = src.peek() {
501502 let _ = src.next();
502503 return true;
src/tools/rust-analyzer/crates/parser/src/grammar/expressions/atom.rs+8-2
......@@ -278,14 +278,20 @@ fn builtin_expr(p: &mut Parser<'_>) -> Option<CompletedMarker> {
278278 }
279279 Some(m.complete(p, OFFSET_OF_EXPR))
280280 } else if p.eat_contextual_kw(T![format_args]) {
281 // test format_args_named_arg_keyword
282 // fn main() {
283 // builtin#format_args("{type}", type=1);
284 // }
281285 p.expect(T!['(']);
282286 expr(p);
283287 if p.eat(T![,]) {
284288 while !p.at(EOF) && !p.at(T![')']) {
285289 let m = p.start();
286 if p.at(IDENT) && p.nth_at(1, T![=]) && !p.nth_at(2, T![=]) {
287 name(p);
290 if p.current().is_any_identifier() && p.nth_at(1, T![=]) && !p.nth_at(2, T![=]) {
291 let m = p.start();
292 p.bump_any();
288293 p.bump(T![=]);
294 m.complete(p, FORMAT_ARGS_ARG_NAME);
289295 }
290296 if expr(p).is_none() {
291297 m.abandon(p);
src/tools/rust-analyzer/crates/parser/src/input.rs+1-1
......@@ -97,7 +97,7 @@ impl Input {
9797 let b_idx = n % (bits::BITS as usize);
9898 (idx, b_idx)
9999 }
100 fn len(&self) -> usize {
100 pub fn len(&self) -> usize {
101101 self.kind.len()
102102 }
103103}
src/tools/rust-analyzer/crates/parser/src/lexed_str.rs+6-1
......@@ -150,7 +150,12 @@ struct Converter<'a> {
150150impl<'a> Converter<'a> {
151151 fn new(edition: Edition, text: &'a str) -> Self {
152152 Self {
153 res: LexedStr { text, kind: Vec::new(), start: Vec::new(), error: Vec::new() },
153 res: LexedStr {
154 text,
155 kind: Vec::with_capacity(text.len() / 3),
156 start: Vec::with_capacity(text.len() / 3),
157 error: Vec::new(),
158 },
154159 offset: 0,
155160 edition,
156161 }
src/tools/rust-analyzer/crates/parser/src/parser.rs+1-1
......@@ -32,7 +32,7 @@ const PARSER_STEP_LIMIT: usize = if cfg!(debug_assertions) { 150_000 } else { 15
3232
3333impl<'t> Parser<'t> {
3434 pub(super) fn new(inp: &'t Input) -> Parser<'t> {
35 Parser { inp, pos: 0, events: Vec::new(), steps: Cell::new(0) }
35 Parser { inp, pos: 0, events: Vec::with_capacity(2 * inp.len()), steps: Cell::new(0) }
3636 }
3737
3838 pub(crate) fn finish(self) -> Vec<Event> {
src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs+2
......@@ -201,6 +201,7 @@ pub enum SyntaxKind {
201201 FN,
202202 FN_PTR_TYPE,
203203 FORMAT_ARGS_ARG,
204 FORMAT_ARGS_ARG_NAME,
204205 FORMAT_ARGS_EXPR,
205206 FOR_BINDER,
206207 FOR_EXPR,
......@@ -373,6 +374,7 @@ impl SyntaxKind {
373374 | FN
374375 | FN_PTR_TYPE
375376 | FORMAT_ARGS_ARG
377 | FORMAT_ARGS_ARG_NAME
376378 | FORMAT_ARGS_EXPR
377379 | FOR_BINDER
378380 | FOR_EXPR
src/tools/rust-analyzer/crates/parser/test_data/generated/runner.rs+4
......@@ -265,6 +265,10 @@ mod ok {
265265 #[test]
266266 fn for_type() { run_and_expect_no_errors("test_data/parser/inline/ok/for_type.rs"); }
267267 #[test]
268 fn format_args_named_arg_keyword() {
269 run_and_expect_no_errors("test_data/parser/inline/ok/format_args_named_arg_keyword.rs");
270 }
271 #[test]
268272 fn frontmatter() { run_and_expect_no_errors("test_data/parser/inline/ok/frontmatter.rs"); }
269273 #[test]
270274 fn full_range_expr() {
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/builtin_expr.rast+3-3
......@@ -44,10 +44,10 @@ SOURCE_FILE
4444 COMMA ","
4545 WHITESPACE " "
4646 FORMAT_ARGS_ARG
47 NAME
47 FORMAT_ARGS_ARG_NAME
4848 IDENT "a"
49 WHITESPACE " "
50 EQ "="
49 WHITESPACE " "
50 EQ "="
5151 WHITESPACE " "
5252 BIN_EXPR
5353 LITERAL
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rast created+35
......@@ -0,0 +1,35 @@
1SOURCE_FILE
2 FN
3 FN_KW "fn"
4 WHITESPACE " "
5 NAME
6 IDENT "main"
7 PARAM_LIST
8 L_PAREN "("
9 R_PAREN ")"
10 WHITESPACE " "
11 BLOCK_EXPR
12 STMT_LIST
13 L_CURLY "{"
14 WHITESPACE "\n "
15 EXPR_STMT
16 FORMAT_ARGS_EXPR
17 BUILTIN_KW "builtin"
18 POUND "#"
19 FORMAT_ARGS_KW "format_args"
20 L_PAREN "("
21 LITERAL
22 STRING "\"{type}\""
23 COMMA ","
24 WHITESPACE " "
25 FORMAT_ARGS_ARG
26 FORMAT_ARGS_ARG_NAME
27 TYPE_KW "type"
28 EQ "="
29 LITERAL
30 INT_NUMBER "1"
31 R_PAREN ")"
32 SEMICOLON ";"
33 WHITESPACE "\n"
34 R_CURLY "}"
35 WHITESPACE "\n"
src/tools/rust-analyzer/crates/parser/test_data/parser/inline/ok/format_args_named_arg_keyword.rs created+3
......@@ -0,0 +1,3 @@
1fn main() {
2 builtin#format_args("{type}", type=1);
3}
src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol.rs created+227
......@@ -0,0 +1,227 @@
1//! Bidirectional protocol methods
2
3use std::{
4 io::{self, BufRead, Write},
5 sync::Arc,
6};
7
8use paths::AbsPath;
9use span::Span;
10
11use crate::{
12 Codec, ProcMacro, ProcMacroKind, ServerError,
13 bidirectional_protocol::msg::{
14 BidirectionalMessage, ExpandMacro, ExpandMacroData, ExpnGlobals, Request, Response,
15 SubRequest, SubResponse,
16 },
17 legacy_protocol::{
18 SpanMode,
19 msg::{
20 FlatTree, ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map,
21 serialize_span_data_index_map,
22 },
23 },
24 process::ProcMacroServerProcess,
25 transport::codec::postcard::PostcardProtocol,
26 version,
27};
28
29pub mod msg;
30
31pub type SubCallback<'a> = &'a mut dyn FnMut(SubRequest) -> Result<SubResponse, ServerError>;
32
33pub fn run_conversation<C: Codec>(
34 writer: &mut dyn Write,
35 reader: &mut dyn BufRead,
36 buf: &mut C::Buf,
37 msg: BidirectionalMessage,
38 callback: SubCallback<'_>,
39) -> Result<BidirectionalMessage, ServerError> {
40 let encoded = C::encode(&msg).map_err(wrap_encode)?;
41 C::write(writer, &encoded).map_err(wrap_io("failed to write initial request"))?;
42
43 loop {
44 let maybe_buf = C::read(reader, buf).map_err(wrap_io("failed to read message"))?;
45 let Some(b) = maybe_buf else {
46 return Err(ServerError {
47 message: "proc-macro server closed the stream".into(),
48 io: Some(Arc::new(io::Error::new(io::ErrorKind::UnexpectedEof, "closed"))),
49 });
50 };
51
52 let msg: BidirectionalMessage = C::decode(b).map_err(wrap_decode)?;
53
54 match msg {
55 BidirectionalMessage::Response(response) => {
56 return Ok(BidirectionalMessage::Response(response));
57 }
58 BidirectionalMessage::SubRequest(sr) => {
59 let resp = callback(sr)?;
60 let reply = BidirectionalMessage::SubResponse(resp);
61 let encoded = C::encode(&reply).map_err(wrap_encode)?;
62 C::write(writer, &encoded).map_err(wrap_io("failed to write sub-response"))?;
63 }
64 _ => {
65 return Err(ServerError {
66 message: format!("unexpected message {:?}", msg),
67 io: None,
68 });
69 }
70 }
71 }
72}
73
74fn wrap_io(msg: &'static str) -> impl Fn(io::Error) -> ServerError {
75 move |err| ServerError { message: msg.into(), io: Some(Arc::new(err)) }
76}
77
78fn wrap_encode(err: io::Error) -> ServerError {
79 ServerError { message: "failed to encode message".into(), io: Some(Arc::new(err)) }
80}
81
82fn wrap_decode(err: io::Error) -> ServerError {
83 ServerError { message: "failed to decode message".into(), io: Some(Arc::new(err)) }
84}
85
86pub(crate) fn version_check(
87 srv: &ProcMacroServerProcess,
88 callback: SubCallback<'_>,
89) -> Result<u32, ServerError> {
90 let request = BidirectionalMessage::Request(Request::ApiVersionCheck {});
91
92 let response_payload = run_request(srv, request, callback)?;
93
94 match response_payload {
95 BidirectionalMessage::Response(Response::ApiVersionCheck(version)) => Ok(version),
96 other => {
97 Err(ServerError { message: format!("unexpected response: {:?}", other), io: None })
98 }
99 }
100}
101
102/// Enable support for rust-analyzer span mode if the server supports it.
103pub(crate) fn enable_rust_analyzer_spans(
104 srv: &ProcMacroServerProcess,
105 callback: SubCallback<'_>,
106) -> Result<SpanMode, ServerError> {
107 let request = BidirectionalMessage::Request(Request::SetConfig(ServerConfig {
108 span_mode: SpanMode::RustAnalyzer,
109 }));
110
111 let response_payload = run_request(srv, request, callback)?;
112
113 match response_payload {
114 BidirectionalMessage::Response(Response::SetConfig(ServerConfig { span_mode })) => {
115 Ok(span_mode)
116 }
117 _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
118 }
119}
120
121/// Finds proc-macros in a given dynamic library.
122pub(crate) fn find_proc_macros(
123 srv: &ProcMacroServerProcess,
124 dylib_path: &AbsPath,
125 callback: SubCallback<'_>,
126) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
127 let request = BidirectionalMessage::Request(Request::ListMacros {
128 dylib_path: dylib_path.to_path_buf().into(),
129 });
130
131 let response_payload = run_request(srv, request, callback)?;
132
133 match response_payload {
134 BidirectionalMessage::Response(Response::ListMacros(it)) => Ok(it),
135 _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
136 }
137}
138
139pub(crate) fn expand(
140 proc_macro: &ProcMacro,
141 subtree: tt::SubtreeView<'_>,
142 attr: Option<tt::SubtreeView<'_>>,
143 env: Vec<(String, String)>,
144 def_site: Span,
145 call_site: Span,
146 mixed_site: Span,
147 current_dir: String,
148 callback: SubCallback<'_>,
149) -> Result<Result<tt::TopSubtree, String>, crate::ServerError> {
150 let version = proc_macro.process.version();
151 let mut span_data_table = SpanDataIndexMap::default();
152 let def_site = span_data_table.insert_full(def_site).0;
153 let call_site = span_data_table.insert_full(call_site).0;
154 let mixed_site = span_data_table.insert_full(mixed_site).0;
155 let task = BidirectionalMessage::Request(Request::ExpandMacro(Box::new(ExpandMacro {
156 data: ExpandMacroData {
157 macro_body: FlatTree::from_subtree(subtree, version, &mut span_data_table),
158 macro_name: proc_macro.name.to_string(),
159 attributes: attr
160 .map(|subtree| FlatTree::from_subtree(subtree, version, &mut span_data_table)),
161 has_global_spans: ExpnGlobals {
162 serialize: version >= version::HAS_GLOBAL_SPANS,
163 def_site,
164 call_site,
165 mixed_site,
166 },
167 span_data_table: if proc_macro.process.rust_analyzer_spans() {
168 serialize_span_data_index_map(&span_data_table)
169 } else {
170 Vec::new()
171 },
172 },
173 lib: proc_macro.dylib_path.to_path_buf().into(),
174 env,
175 current_dir: Some(current_dir),
176 })));
177
178 let response_payload = run_request(&proc_macro.process, task, callback)?;
179
180 match response_payload {
181 BidirectionalMessage::Response(Response::ExpandMacro(it)) => Ok(it
182 .map(|tree| {
183 let mut expanded = FlatTree::to_subtree_resolved(tree, version, &span_data_table);
184 if proc_macro.needs_fixup_change() {
185 proc_macro.change_fixup_to_match_old_server(&mut expanded);
186 }
187 expanded
188 })
189 .map_err(|msg| msg.0)),
190 BidirectionalMessage::Response(Response::ExpandMacroExtended(it)) => Ok(it
191 .map(|resp| {
192 let mut expanded = FlatTree::to_subtree_resolved(
193 resp.tree,
194 version,
195 &deserialize_span_data_index_map(&resp.span_data_table),
196 );
197 if proc_macro.needs_fixup_change() {
198 proc_macro.change_fixup_to_match_old_server(&mut expanded);
199 }
200 expanded
201 })
202 .map_err(|msg| msg.0)),
203 _ => Err(ServerError { message: "unexpected response".to_owned(), io: None }),
204 }
205}
206
207fn run_request(
208 srv: &ProcMacroServerProcess,
209 msg: BidirectionalMessage,
210 callback: SubCallback<'_>,
211) -> Result<BidirectionalMessage, ServerError> {
212 if let Some(err) = srv.exited() {
213 return Err(err.clone());
214 }
215
216 match srv.use_postcard() {
217 true => srv.run_bidirectional::<PostcardProtocol>(msg, callback),
218 false => Err(ServerError {
219 message: "bidirectional messaging does not support JSON".to_owned(),
220 io: None,
221 }),
222 }
223}
224
225pub fn reject_subrequests(req: SubRequest) -> Result<SubResponse, ServerError> {
226 Err(ServerError { message: format!("{req:?} sub-request not supported here"), io: None })
227}
src/tools/rust-analyzer/crates/proc-macro-api/src/bidirectional_protocol/msg.rs created+91
......@@ -0,0 +1,91 @@
1//! Bidirectional protocol messages
2
3use paths::Utf8PathBuf;
4use serde::{Deserialize, Serialize};
5
6use crate::{
7 ProcMacroKind,
8 legacy_protocol::msg::{FlatTree, Message, PanicMessage, ServerConfig},
9};
10
11#[derive(Debug, Serialize, Deserialize)]
12pub enum SubRequest {
13 SourceText { file_id: u32, start: u32, end: u32 },
14}
15
16#[derive(Debug, Serialize, Deserialize)]
17pub enum SubResponse {
18 SourceTextResult { text: Option<String> },
19}
20
21#[derive(Debug, Serialize, Deserialize)]
22pub enum BidirectionalMessage {
23 Request(Request),
24 Response(Response),
25 SubRequest(SubRequest),
26 SubResponse(SubResponse),
27}
28
29#[derive(Debug, Serialize, Deserialize)]
30pub enum Request {
31 ListMacros { dylib_path: Utf8PathBuf },
32 ExpandMacro(Box<ExpandMacro>),
33 ApiVersionCheck {},
34 SetConfig(ServerConfig),
35}
36
37#[derive(Debug, Serialize, Deserialize)]
38pub enum Response {
39 ListMacros(Result<Vec<(String, ProcMacroKind)>, String>),
40 ExpandMacro(Result<FlatTree, PanicMessage>),
41 ApiVersionCheck(u32),
42 SetConfig(ServerConfig),
43 ExpandMacroExtended(Result<ExpandMacroExtended, PanicMessage>),
44}
45
46#[derive(Debug, Serialize, Deserialize)]
47pub struct ExpandMacro {
48 pub lib: Utf8PathBuf,
49 pub env: Vec<(String, String)>,
50 pub current_dir: Option<String>,
51 #[serde(flatten)]
52 pub data: ExpandMacroData,
53}
54
55#[derive(Debug, Serialize, Deserialize)]
56pub struct ExpandMacroExtended {
57 pub tree: FlatTree,
58 pub span_data_table: Vec<u32>,
59}
60
61#[derive(Debug, Serialize, Deserialize)]
62pub struct ExpandMacroData {
63 pub macro_body: FlatTree,
64 pub macro_name: String,
65 pub attributes: Option<FlatTree>,
66 #[serde(skip_serializing_if = "ExpnGlobals::skip_serializing_if")]
67 #[serde(default)]
68 pub has_global_spans: ExpnGlobals,
69
70 #[serde(skip_serializing_if = "Vec::is_empty")]
71 #[serde(default)]
72 pub span_data_table: Vec<u32>,
73}
74
75#[derive(Clone, Copy, Default, Debug, Serialize, Deserialize)]
76pub struct ExpnGlobals {
77 #[serde(skip_serializing)]
78 #[serde(default)]
79 pub serialize: bool,
80 pub def_site: usize,
81 pub call_site: usize,
82 pub mixed_site: usize,
83}
84
85impl ExpnGlobals {
86 fn skip_serializing_if(&self) -> bool {
87 !self.serialize
88 }
89}
90
91impl Message for BidirectionalMessage {}
src/tools/rust-analyzer/crates/proc-macro-api/src/codec.rs deleted-12
......@@ -1,12 +0,0 @@
1//! Protocol codec
2
3use std::io;
4
5use serde::de::DeserializeOwned;
6
7use crate::framing::Framing;
8
9pub trait Codec: Framing {
10 fn encode<T: serde::Serialize>(msg: &T) -> io::Result<Self::Buf>;
11 fn decode<T: DeserializeOwned>(buf: &mut Self::Buf) -> io::Result<T>;
12}
src/tools/rust-analyzer/crates/proc-macro-api/src/framing.rs deleted-14
......@@ -1,14 +0,0 @@
1//! Protocol framing
2
3use std::io::{self, BufRead, Write};
4
5pub trait Framing {
6 type Buf: Default;
7
8 fn read<'a, R: BufRead>(
9 inp: &mut R,
10 buf: &'a mut Self::Buf,
11 ) -> io::Result<Option<&'a mut Self::Buf>>;
12
13 fn write<W: Write>(out: &mut W, buf: &Self::Buf) -> io::Result<()>;
14}
src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol.rs+11-17
......@@ -1,8 +1,6 @@
11//! The initial proc-macro-srv protocol, soon to be deprecated.
22
3pub mod json;
43pub mod msg;
5pub mod postcard;
64
75use std::{
86 io::{BufRead, Write},
......@@ -14,17 +12,14 @@ use span::Span;
1412
1513use crate::{
1614 ProcMacro, ProcMacroKind, ServerError,
17 codec::Codec,
18 legacy_protocol::{
19 json::JsonProtocol,
20 msg::{
21 ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response,
22 ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map,
23 flat::serialize_span_data_index_map,
24 },
25 postcard::PostcardProtocol,
15 legacy_protocol::msg::{
16 ExpandMacro, ExpandMacroData, ExpnGlobals, FlatTree, Message, Request, Response,
17 ServerConfig, SpanDataIndexMap, deserialize_span_data_index_map,
18 flat::serialize_span_data_index_map,
2619 },
2720 process::ProcMacroServerProcess,
21 transport::codec::Codec,
22 transport::codec::{json::JsonProtocol, postcard::PostcardProtocol},
2823 version,
2924};
3025
......@@ -82,15 +77,14 @@ pub(crate) fn find_proc_macros(
8277
8378pub(crate) fn expand(
8479 proc_macro: &ProcMacro,
85 subtree: tt::SubtreeView<'_, Span>,
86 attr: Option<tt::SubtreeView<'_, Span>>,
80 subtree: tt::SubtreeView<'_>,
81 attr: Option<tt::SubtreeView<'_>>,
8782 env: Vec<(String, String)>,
8883 def_site: Span,
8984 call_site: Span,
9085 mixed_site: Span,
9186 current_dir: String,
92) -> Result<Result<tt::TopSubtree<span::SpanData<span::SyntaxContext>>, String>, crate::ServerError>
93{
87) -> Result<Result<tt::TopSubtree, String>, crate::ServerError> {
9488 let version = proc_macro.process.version();
9589 let mut span_data_table = SpanDataIndexMap::default();
9690 let def_site = span_data_table.insert_full(def_site).0;
......@@ -155,9 +149,9 @@ fn send_task(srv: &ProcMacroServerProcess, req: Request) -> Result<Response, Ser
155149 }
156150
157151 if srv.use_postcard() {
158 srv.send_task(send_request::<PostcardProtocol>, req)
152 srv.send_task::<_, _, PostcardProtocol>(send_request::<PostcardProtocol>, req)
159153 } else {
160 srv.send_task(send_request::<JsonProtocol>, req)
154 srv.send_task::<_, _, JsonProtocol>(send_request::<JsonProtocol>, req)
161155 }
162156}
163157
src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/json.rs deleted-58
......@@ -1,58 +0,0 @@
1//! Protocol functions for json.
2use std::io::{self, BufRead, Write};
3
4use serde::{Serialize, de::DeserializeOwned};
5
6use crate::{codec::Codec, framing::Framing};
7
8pub struct JsonProtocol;
9
10impl Framing for JsonProtocol {
11 type Buf = String;
12
13 fn read<'a, R: BufRead>(
14 inp: &mut R,
15 buf: &'a mut String,
16 ) -> io::Result<Option<&'a mut String>> {
17 loop {
18 buf.clear();
19
20 inp.read_line(buf)?;
21 buf.pop(); // Remove trailing '\n'
22
23 if buf.is_empty() {
24 return Ok(None);
25 }
26
27 // Some ill behaved macro try to use stdout for debugging
28 // We ignore it here
29 if !buf.starts_with('{') {
30 tracing::error!("proc-macro tried to print : {}", buf);
31 continue;
32 }
33
34 return Ok(Some(buf));
35 }
36 }
37
38 fn write<W: Write>(out: &mut W, buf: &String) -> io::Result<()> {
39 tracing::debug!("> {}", buf);
40 out.write_all(buf.as_bytes())?;
41 out.write_all(b"\n")?;
42 out.flush()
43 }
44}
45
46impl Codec for JsonProtocol {
47 fn encode<T: Serialize>(msg: &T) -> io::Result<String> {
48 Ok(serde_json::to_string(msg)?)
49 }
50
51 fn decode<T: DeserializeOwned>(buf: &mut String) -> io::Result<T> {
52 let mut deserializer = serde_json::Deserializer::from_str(buf);
53 // Note that some proc-macro generate very deep syntax tree
54 // We have to disable the current limit of serde here
55 deserializer.disable_recursion_limit();
56 Ok(T::deserialize(&mut deserializer)?)
57 }
58}
src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg.rs+16-17
......@@ -8,7 +8,7 @@ use paths::Utf8PathBuf;
88use serde::de::DeserializeOwned;
99use serde_derive::{Deserialize, Serialize};
1010
11use crate::{ProcMacroKind, codec::Codec};
11use crate::{Codec, ProcMacroKind};
1212
1313/// Represents requests sent from the client to the proc-macro-srv.
1414#[derive(Debug, Serialize, Deserialize)]
......@@ -172,7 +172,7 @@ impl Message for Response {}
172172
173173#[cfg(test)]
174174mod tests {
175 use intern::{Symbol, sym};
175 use intern::Symbol;
176176 use span::{
177177 Edition, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext, TextRange, TextSize,
178178 };
......@@ -185,7 +185,7 @@ mod tests {
185185
186186 use super::*;
187187
188 fn fixture_token_tree_top_many_none() -> TopSubtree<Span> {
188 fn fixture_token_tree_top_many_none() -> TopSubtree {
189189 let anchor = SpanAnchor {
190190 file_id: span::EditionedFileId::new(
191191 span::FileId::from_raw(0xe4e4e),
......@@ -232,16 +232,15 @@ mod tests {
232232 }
233233 .into(),
234234 );
235 builder.push(Leaf::Literal(Literal {
236 symbol: Symbol::intern("Foo"),
237 span: Span {
235 builder.push(Leaf::Literal(Literal::new_no_suffix(
236 "Foo",
237 Span {
238238 range: TextRange::at(TextSize::new(10), TextSize::of("\"Foo\"")),
239239 anchor,
240240 ctx: SyntaxContext::root(Edition::CURRENT),
241241 },
242 kind: tt::LitKind::Str,
243 suffix: None,
244 }));
242 tt::LitKind::Str,
243 )));
245244 builder.push(Leaf::Punct(Punct {
246245 char: '@',
247246 span: Span {
......@@ -267,16 +266,16 @@ mod tests {
267266 ctx: SyntaxContext::root(Edition::CURRENT),
268267 },
269268 );
270 builder.push(Leaf::Literal(Literal {
271 symbol: sym::INTEGER_0,
272 span: Span {
269 builder.push(Leaf::Literal(Literal::new(
270 "0",
271 Span {
273272 range: TextRange::at(TextSize::new(16), TextSize::of("0u32")),
274273 anchor,
275274 ctx: SyntaxContext::root(Edition::CURRENT),
276275 },
277 kind: tt::LitKind::Integer,
278 suffix: Some(sym::u32),
279 }));
276 tt::LitKind::Integer,
277 "u32",
278 )));
280279 builder.close(Span {
281280 range: TextRange::at(TextSize::new(20), TextSize::of(']')),
282281 anchor,
......@@ -292,7 +291,7 @@ mod tests {
292291 builder.build()
293292 }
294293
295 fn fixture_token_tree_top_empty_none() -> TopSubtree<Span> {
294 fn fixture_token_tree_top_empty_none() -> TopSubtree {
296295 let anchor = SpanAnchor {
297296 file_id: span::EditionedFileId::new(
298297 span::FileId::from_raw(0xe4e4e),
......@@ -318,7 +317,7 @@ mod tests {
318317 builder.build()
319318 }
320319
321 fn fixture_token_tree_top_empty_brace() -> TopSubtree<Span> {
320 fn fixture_token_tree_top_empty_brace() -> TopSubtree {
322321 let anchor = SpanAnchor {
323322 file_id: span::EditionedFileId::new(
324323 span::FileId::from_raw(0xe4e4e),
src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/msg/flat.rs+29-29
......@@ -123,7 +123,7 @@ struct IdentRepr {
123123
124124impl FlatTree {
125125 pub fn from_subtree(
126 subtree: tt::SubtreeView<'_, Span>,
126 subtree: tt::SubtreeView<'_>,
127127 version: u32,
128128 span_data_table: &mut SpanDataIndexMap,
129129 ) -> FlatTree {
......@@ -168,7 +168,7 @@ impl FlatTree {
168168 self,
169169 version: u32,
170170 span_data_table: &SpanDataIndexMap,
171 ) -> tt::TopSubtree<Span> {
171 ) -> tt::TopSubtree {
172172 Reader::<Span> {
173173 subtree: if version >= ENCODE_CLOSE_SPAN_VERSION {
174174 read_vec(self.subtree, SubtreeRepr::read_with_close_span)
......@@ -486,16 +486,16 @@ struct Writer<'a, 'span, S: SpanTransformer, W> {
486486 text: Vec<String>,
487487}
488488
489impl<'a, T: SpanTransformer> Writer<'a, '_, T, tt::iter::TtIter<'a, T::Span>> {
490 fn write_subtree(&mut self, root: tt::SubtreeView<'a, T::Span>) {
489impl<'a, T: SpanTransformer<Span = span::Span>> Writer<'a, '_, T, tt::iter::TtIter<'a>> {
490 fn write_subtree(&mut self, root: tt::SubtreeView<'a>) {
491491 let subtree = root.top_subtree();
492 self.enqueue(subtree, root.iter());
492 self.enqueue(&subtree, root.iter());
493493 while let Some((idx, len, subtree)) = self.work.pop_front() {
494494 self.subtree(idx, len, subtree);
495495 }
496496 }
497497
498 fn subtree(&mut self, idx: usize, n_tt: usize, subtree: tt::iter::TtIter<'a, T::Span>) {
498 fn subtree(&mut self, idx: usize, n_tt: usize, subtree: tt::iter::TtIter<'a>) {
499499 let mut first_tt = self.token_tree.len();
500500 self.token_tree.resize(first_tt + n_tt, !0);
501501
......@@ -504,7 +504,7 @@ impl<'a, T: SpanTransformer> Writer<'a, '_, T, tt::iter::TtIter<'a, T::Span>> {
504504 for child in subtree {
505505 let idx_tag = match child {
506506 tt::iter::TtElement::Subtree(subtree, subtree_iter) => {
507 let idx = self.enqueue(subtree, subtree_iter);
507 let idx = self.enqueue(&subtree, subtree_iter);
508508 idx << 2
509509 }
510510 tt::iter::TtElement::Leaf(leaf) => match leaf {
......@@ -512,9 +512,14 @@ impl<'a, T: SpanTransformer> Writer<'a, '_, T, tt::iter::TtIter<'a, T::Span>> {
512512 let idx = self.literal.len() as u32;
513513 let id = self.token_id_of(lit.span);
514514 let (text, suffix) = if self.version >= EXTENDED_LEAF_DATA {
515 let (text, suffix) = lit.text_and_suffix();
515516 (
516 self.intern(lit.symbol.as_str()),
517 lit.suffix.as_ref().map(|s| self.intern(s.as_str())).unwrap_or(!0),
517 self.intern_owned(text.to_owned()),
518 if suffix.is_empty() {
519 !0
520 } else {
521 self.intern_owned(suffix.to_owned())
522 },
518523 )
519524 } else {
520525 (self.intern_owned(format!("{lit}")), !0)
......@@ -549,11 +554,11 @@ impl<'a, T: SpanTransformer> Writer<'a, '_, T, tt::iter::TtIter<'a, T::Span>> {
549554 let idx = self.ident.len() as u32;
550555 let id = self.token_id_of(ident.span);
551556 let text = if self.version >= EXTENDED_LEAF_DATA {
552 self.intern(ident.sym.as_str())
557 self.intern_owned(ident.sym.as_str().to_owned())
553558 } else if ident.is_raw.yes() {
554559 self.intern_owned(format!("r#{}", ident.sym.as_str(),))
555560 } else {
556 self.intern(ident.sym.as_str())
561 self.intern_owned(ident.sym.as_str().to_owned())
557562 };
558563 self.ident.push(IdentRepr { id, text, is_raw: ident.is_raw.yes() });
559564 (idx << 2) | 0b11
......@@ -565,11 +570,7 @@ impl<'a, T: SpanTransformer> Writer<'a, '_, T, tt::iter::TtIter<'a, T::Span>> {
565570 }
566571 }
567572
568 fn enqueue(
569 &mut self,
570 subtree: &'a tt::Subtree<T::Span>,
571 contents: tt::iter::TtIter<'a, T::Span>,
572 ) -> u32 {
573 fn enqueue(&mut self, subtree: &tt::Subtree, contents: tt::iter::TtIter<'a>) -> u32 {
573574 let idx = self.subtree.len();
574575 let open = self.token_id_of(subtree.delimiter.open);
575576 let close = self.token_id_of(subtree.delimiter.close);
......@@ -586,6 +587,7 @@ impl<'a, T: SpanTransformer, U> Writer<'a, '_, T, U> {
586587 T::token_id_of(self.span_data_table, span)
587588 }
588589
590 #[cfg(feature = "sysroot-abi")]
589591 pub(crate) fn intern(&mut self, text: &'a str) -> u32 {
590592 let table = &mut self.text;
591593 *self.string_table.entry(text.into()).or_insert_with(|| {
......@@ -739,9 +741,9 @@ struct Reader<'span, S: SpanTransformer> {
739741 span_data_table: &'span S::Table,
740742}
741743
742impl<T: SpanTransformer> Reader<'_, T> {
743 pub(crate) fn read_subtree(self) -> tt::TopSubtree<T::Span> {
744 let mut res: Vec<Option<(tt::Delimiter<T::Span>, Vec<tt::TokenTree<T::Span>>)>> =
744impl<T: SpanTransformer<Span = span::Span>> Reader<'_, T> {
745 pub(crate) fn read_subtree(self) -> tt::TopSubtree {
746 let mut res: Vec<Option<(tt::Delimiter, Vec<tt::TokenTree>)>> =
745747 vec![None; self.subtree.len()];
746748 let read_span = |id| T::span_for_token_id(self.span_data_table, id);
747749 for i in (0..self.subtree.len()).rev() {
......@@ -774,10 +776,10 @@ impl<T: SpanTransformer> Reader<'_, T> {
774776 let span = read_span(repr.id);
775777 s.push(
776778 tt::Leaf::Literal(if self.version >= EXTENDED_LEAF_DATA {
777 tt::Literal {
778 symbol: Symbol::intern(text),
779 tt::Literal::new(
780 text,
779781 span,
780 kind: match u16::to_le_bytes(repr.kind) {
782 match u16::to_le_bytes(repr.kind) {
781783 [0, _] => Err(()),
782784 [1, _] => Byte,
783785 [2, _] => Char,
......@@ -791,14 +793,12 @@ impl<T: SpanTransformer> Reader<'_, T> {
791793 [10, r] => CStrRaw(r),
792794 _ => unreachable!(),
793795 },
794 suffix: if repr.suffix != !0 {
795 Some(Symbol::intern(
796 self.text[repr.suffix as usize].as_str(),
797 ))
796 if repr.suffix != !0 {
797 self.text[repr.suffix as usize].as_str()
798798 } else {
799 None
799 ""
800800 },
801 }
801 )
802802 } else {
803803 tt::token_to_literal(text, span)
804804 })
......@@ -844,7 +844,7 @@ impl<T: SpanTransformer> Reader<'_, T> {
844844
845845 let (delimiter, mut res) = res[0].take().unwrap();
846846 res.insert(0, tt::TokenTree::Subtree(tt::Subtree { delimiter, len: res.len() as u32 }));
847 tt::TopSubtree(res.into_boxed_slice())
847 tt::TopSubtree::from_serialized(res)
848848 }
849849}
850850
src/tools/rust-analyzer/crates/proc-macro-api/src/legacy_protocol/postcard.rs deleted-40
......@@ -1,40 +0,0 @@
1//! Postcard encode and decode implementations.
2
3use std::io::{self, BufRead, Write};
4
5use serde::{Serialize, de::DeserializeOwned};
6
7use crate::{codec::Codec, framing::Framing};
8
9pub struct PostcardProtocol;
10
11impl Framing for PostcardProtocol {
12 type Buf = Vec<u8>;
13
14 fn read<'a, R: BufRead>(
15 inp: &mut R,
16 buf: &'a mut Vec<u8>,
17 ) -> io::Result<Option<&'a mut Vec<u8>>> {
18 buf.clear();
19 let n = inp.read_until(0, buf)?;
20 if n == 0 {
21 return Ok(None);
22 }
23 Ok(Some(buf))
24 }
25
26 fn write<W: Write>(out: &mut W, buf: &Vec<u8>) -> io::Result<()> {
27 out.write_all(buf)?;
28 out.flush()
29 }
30}
31
32impl Codec for PostcardProtocol {
33 fn encode<T: Serialize>(msg: &T) -> io::Result<Vec<u8>> {
34 postcard::to_allocvec_cobs(msg).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
35 }
36
37 fn decode<T: DeserializeOwned>(buf: &mut Self::Buf) -> io::Result<T> {
38 postcard::from_bytes_cobs(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
39 }
40}
src/tools/rust-analyzer/crates/proc-macro-api/src/lib.rs+19-27
......@@ -16,18 +16,18 @@
1616#[cfg(feature = "in-rust-tree")]
1717extern crate rustc_driver as _;
1818
19mod codec;
20mod framing;
19pub mod bidirectional_protocol;
2120pub mod legacy_protocol;
2221mod process;
22pub mod transport;
2323
2424use paths::{AbsPath, AbsPathBuf};
2525use semver::Version;
2626use span::{ErasedFileAstId, FIXUP_ERASED_FILE_AST_ID_MARKER, Span};
2727use std::{fmt, io, sync::Arc, time::SystemTime};
2828
29pub use crate::codec::Codec;
30use crate::process::ProcMacroServerProcess;
29pub use crate::transport::codec::Codec;
30use crate::{bidirectional_protocol::SubCallback, process::ProcMacroServerProcess};
3131
3232/// The versions of the server protocol
3333pub mod version {
......@@ -142,9 +142,13 @@ impl ProcMacroClient {
142142 }
143143
144144 /// Loads a proc-macro dylib into the server process returning a list of `ProcMacro`s loaded.
145 pub fn load_dylib(&self, dylib: MacroDylib) -> Result<Vec<ProcMacro>, ServerError> {
145 pub fn load_dylib(
146 &self,
147 dylib: MacroDylib,
148 callback: Option<SubCallback<'_>>,
149 ) -> Result<Vec<ProcMacro>, ServerError> {
146150 let _p = tracing::info_span!("ProcMacroServer::load_dylib").entered();
147 let macros = self.process.find_proc_macros(&dylib.path)?;
151 let macros = self.process.find_proc_macros(&dylib.path, callback)?;
148152
149153 let dylib_path = Arc::new(dylib.path);
150154 let dylib_last_modified = std::fs::metadata(dylib_path.as_path())
......@@ -188,44 +192,31 @@ impl ProcMacro {
188192 }
189193
190194 /// On some server versions, the fixup ast id is different than ours. So change it to match.
191 fn change_fixup_to_match_old_server(&self, tt: &mut tt::TopSubtree<Span>) {
195 fn change_fixup_to_match_old_server(&self, tt: &mut tt::TopSubtree) {
192196 const OLD_FIXUP_AST_ID: ErasedFileAstId = ErasedFileAstId::from_raw(!0 - 1);
193 let change_ast_id = |ast_id: &mut ErasedFileAstId| {
197 tt.change_every_ast_id(|ast_id| {
194198 if *ast_id == FIXUP_ERASED_FILE_AST_ID_MARKER {
195199 *ast_id = OLD_FIXUP_AST_ID;
196200 } else if *ast_id == OLD_FIXUP_AST_ID {
197201 // Swap between them, that means no collision plus the change can be reversed by doing itself.
198202 *ast_id = FIXUP_ERASED_FILE_AST_ID_MARKER;
199203 }
200 };
201
202 for tt in &mut tt.0 {
203 match tt {
204 tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident { span, .. }))
205 | tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal { span, .. }))
206 | tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { span, .. })) => {
207 change_ast_id(&mut span.anchor.ast_id);
208 }
209 tt::TokenTree::Subtree(subtree) => {
210 change_ast_id(&mut subtree.delimiter.open.anchor.ast_id);
211 change_ast_id(&mut subtree.delimiter.close.anchor.ast_id);
212 }
213 }
214 }
204 });
215205 }
216206
217207 /// Expands the procedural macro by sending an expansion request to the server.
218208 /// This includes span information and environmental context.
219209 pub fn expand(
220210 &self,
221 subtree: tt::SubtreeView<'_, Span>,
222 attr: Option<tt::SubtreeView<'_, Span>>,
211 subtree: tt::SubtreeView<'_>,
212 attr: Option<tt::SubtreeView<'_>>,
223213 env: Vec<(String, String)>,
224214 def_site: Span,
225215 call_site: Span,
226216 mixed_site: Span,
227217 current_dir: String,
228 ) -> Result<Result<tt::TopSubtree<Span>, String>, ServerError> {
218 callback: Option<SubCallback<'_>>,
219 ) -> Result<Result<tt::TopSubtree, String>, ServerError> {
229220 let (mut subtree, mut attr) = (subtree, attr);
230221 let (mut subtree_changed, mut attr_changed);
231222 if self.needs_fixup_change() {
......@@ -240,7 +231,7 @@ impl ProcMacro {
240231 }
241232 }
242233
243 legacy_protocol::expand(
234 self.process.expand(
244235 self,
245236 subtree,
246237 attr,
......@@ -249,6 +240,7 @@ impl ProcMacro {
249240 call_site,
250241 mixed_site,
251242 current_dir,
243 callback,
252244 )
253245 }
254246}
src/tools/rust-analyzer/crates/proc-macro-api/src/process.rs+129-49
......@@ -9,10 +9,12 @@ use std::{
99
1010use paths::AbsPath;
1111use semver::Version;
12use span::Span;
1213use stdx::JodChild;
1314
1415use crate::{
15 ProcMacroKind, ServerError,
16 Codec, ProcMacro, ProcMacroKind, ServerError,
17 bidirectional_protocol::{self, SubCallback, msg::BidirectionalMessage, reject_subrequests},
1618 legacy_protocol::{self, SpanMode},
1719 version,
1820};
......@@ -33,6 +35,7 @@ pub(crate) struct ProcMacroServerProcess {
3335pub(crate) enum Protocol {
3436 LegacyJson { mode: SpanMode },
3537 LegacyPostcard { mode: SpanMode },
38 BidirectionalPostcardPrototype { mode: SpanMode },
3639}
3740
3841/// Maintains the state of the proc-macro server process.
......@@ -62,6 +65,10 @@ impl ProcMacroServerProcess {
6265 && has_working_format_flag
6366 {
6467 &[
68 (
69 Some("bidirectional-postcard-prototype"),
70 Protocol::BidirectionalPostcardPrototype { mode: SpanMode::Id },
71 ),
6572 (Some("postcard-legacy"), Protocol::LegacyPostcard { mode: SpanMode::Id }),
6673 (Some("json-legacy"), Protocol::LegacyJson { mode: SpanMode::Id }),
6774 ]
......@@ -84,7 +91,7 @@ impl ProcMacroServerProcess {
8491 };
8592 let mut srv = create_srv()?;
8693 tracing::info!("sending proc-macro server version check");
87 match srv.version_check() {
94 match srv.version_check(Some(&mut reject_subrequests)) {
8895 Ok(v) if v > version::CURRENT_API_VERSION => {
8996 #[allow(clippy::disallowed_methods)]
9097 let process_version = Command::new(process_path)
......@@ -102,12 +109,13 @@ impl ProcMacroServerProcess {
102109 tracing::info!("Proc-macro server version: {v}");
103110 srv.version = v;
104111 if srv.version >= version::RUST_ANALYZER_SPAN_SUPPORT
105 && let Ok(new_mode) = srv.enable_rust_analyzer_spans()
112 && let Ok(new_mode) =
113 srv.enable_rust_analyzer_spans(Some(&mut reject_subrequests))
106114 {
107115 match &mut srv.protocol {
108 Protocol::LegacyJson { mode } | Protocol::LegacyPostcard { mode } => {
109 *mode = new_mode
110 }
116 Protocol::LegacyJson { mode }
117 | Protocol::LegacyPostcard { mode }
118 | Protocol::BidirectionalPostcardPrototype { mode } => *mode = new_mode,
111119 }
112120 }
113121 tracing::info!("Proc-macro server protocol: {:?}", srv.protocol);
......@@ -143,22 +151,36 @@ impl ProcMacroServerProcess {
143151 match self.protocol {
144152 Protocol::LegacyJson { mode } => mode == SpanMode::RustAnalyzer,
145153 Protocol::LegacyPostcard { mode } => mode == SpanMode::RustAnalyzer,
154 Protocol::BidirectionalPostcardPrototype { mode } => mode == SpanMode::RustAnalyzer,
146155 }
147156 }
148157
149158 /// Checks the API version of the running proc-macro server.
150 fn version_check(&self) -> Result<u32, ServerError> {
159 fn version_check(&self, callback: Option<SubCallback<'_>>) -> Result<u32, ServerError> {
151160 match self.protocol {
152 Protocol::LegacyJson { .. } => legacy_protocol::version_check(self),
153 Protocol::LegacyPostcard { .. } => legacy_protocol::version_check(self),
161 Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => {
162 legacy_protocol::version_check(self)
163 }
164 Protocol::BidirectionalPostcardPrototype { .. } => {
165 let cb = callback.expect("callback required for bidirectional protocol");
166 bidirectional_protocol::version_check(self, cb)
167 }
154168 }
155169 }
156170
157171 /// Enable support for rust-analyzer span mode if the server supports it.
158 fn enable_rust_analyzer_spans(&self) -> Result<SpanMode, ServerError> {
172 fn enable_rust_analyzer_spans(
173 &self,
174 callback: Option<SubCallback<'_>>,
175 ) -> Result<SpanMode, ServerError> {
159176 match self.protocol {
160 Protocol::LegacyJson { .. } => legacy_protocol::enable_rust_analyzer_spans(self),
161 Protocol::LegacyPostcard { .. } => legacy_protocol::enable_rust_analyzer_spans(self),
177 Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => {
178 legacy_protocol::enable_rust_analyzer_spans(self)
179 }
180 Protocol::BidirectionalPostcardPrototype { .. } => {
181 let cb = callback.expect("callback required for bidirectional protocol");
182 bidirectional_protocol::enable_rust_analyzer_spans(self, cb)
183 }
162184 }
163185 }
164186
......@@ -166,30 +188,70 @@ impl ProcMacroServerProcess {
166188 pub(crate) fn find_proc_macros(
167189 &self,
168190 dylib_path: &AbsPath,
191 callback: Option<SubCallback<'_>>,
169192 ) -> Result<Result<Vec<(String, ProcMacroKind)>, String>, ServerError> {
170193 match self.protocol {
171 Protocol::LegacyJson { .. } => legacy_protocol::find_proc_macros(self, dylib_path),
172 Protocol::LegacyPostcard { .. } => legacy_protocol::find_proc_macros(self, dylib_path),
194 Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => {
195 legacy_protocol::find_proc_macros(self, dylib_path)
196 }
197 Protocol::BidirectionalPostcardPrototype { .. } => {
198 let cb = callback.expect("callback required for bidirectional protocol");
199 bidirectional_protocol::find_proc_macros(self, dylib_path, cb)
200 }
201 }
202 }
203
204 pub(crate) fn expand(
205 &self,
206 proc_macro: &ProcMacro,
207 subtree: tt::SubtreeView<'_>,
208 attr: Option<tt::SubtreeView<'_>>,
209 env: Vec<(String, String)>,
210 def_site: Span,
211 call_site: Span,
212 mixed_site: Span,
213 current_dir: String,
214 callback: Option<SubCallback<'_>>,
215 ) -> Result<Result<tt::TopSubtree, String>, ServerError> {
216 match self.protocol {
217 Protocol::LegacyJson { .. } | Protocol::LegacyPostcard { .. } => {
218 legacy_protocol::expand(
219 proc_macro,
220 subtree,
221 attr,
222 env,
223 def_site,
224 call_site,
225 mixed_site,
226 current_dir,
227 )
228 }
229 Protocol::BidirectionalPostcardPrototype { .. } => bidirectional_protocol::expand(
230 proc_macro,
231 subtree,
232 attr,
233 env,
234 def_site,
235 call_site,
236 mixed_site,
237 current_dir,
238 callback.expect("callback required for bidirectional protocol"),
239 ),
173240 }
174241 }
175242
176 pub(crate) fn send_task<Request, Response, Buf>(
243 pub(crate) fn send_task<Request, Response, C: Codec>(
177244 &self,
178 serialize_req: impl FnOnce(
245 send: impl FnOnce(
179246 &mut dyn Write,
180247 &mut dyn BufRead,
181248 Request,
182 &mut Buf,
249 &mut C::Buf,
183250 ) -> Result<Option<Response>, ServerError>,
184251 req: Request,
185 ) -> Result<Response, ServerError>
186 where
187 Buf: Default,
188 {
189 let state = &mut *self.state.lock().unwrap();
190 let mut buf = Buf::default();
191 serialize_req(&mut state.stdin, &mut state.stdout, req, &mut buf)
192 .and_then(|res| {
252 ) -> Result<Response, ServerError> {
253 self.with_locked_io::<C, _>(|writer, reader, buf| {
254 send(writer, reader, req, buf).and_then(|res| {
193255 res.ok_or_else(|| {
194256 let message = "proc-macro server did not respond with data".to_owned();
195257 ServerError {
......@@ -201,33 +263,51 @@ impl ProcMacroServerProcess {
201263 }
202264 })
203265 })
204 .map_err(|e| {
205 if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) {
206 match state.process.child.try_wait() {
207 Ok(None) | Err(_) => e,
208 Ok(Some(status)) => {
209 let mut msg = String::new();
210 if !status.success()
211 && let Some(stderr) = state.process.child.stderr.as_mut()
212 {
213 _ = stderr.read_to_string(&mut msg);
214 }
215 let server_error = ServerError {
216 message: format!(
217 "proc-macro server exited with {status}{}{msg}",
218 if msg.is_empty() { "" } else { ": " }
219 ),
220 io: None,
221 };
222 // `AssertUnwindSafe` is fine here, we already correct initialized
223 // server_error at this point.
224 self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone()
266 })
267 }
268
269 pub(crate) fn with_locked_io<C: Codec, R>(
270 &self,
271 f: impl FnOnce(&mut dyn Write, &mut dyn BufRead, &mut C::Buf) -> Result<R, ServerError>,
272 ) -> Result<R, ServerError> {
273 let state = &mut *self.state.lock().unwrap();
274 let mut buf = C::Buf::default();
275
276 f(&mut state.stdin, &mut state.stdout, &mut buf).map_err(|e| {
277 if e.io.as_ref().map(|it| it.kind()) == Some(io::ErrorKind::BrokenPipe) {
278 match state.process.child.try_wait() {
279 Ok(None) | Err(_) => e,
280 Ok(Some(status)) => {
281 let mut msg = String::new();
282 if !status.success()
283 && let Some(stderr) = state.process.child.stderr.as_mut()
284 {
285 _ = stderr.read_to_string(&mut msg);
225286 }
287 let server_error = ServerError {
288 message: format!(
289 "proc-macro server exited with {status}{}{msg}",
290 if msg.is_empty() { "" } else { ": " }
291 ),
292 io: None,
293 };
294 self.exited.get_or_init(|| AssertUnwindSafe(server_error)).0.clone()
226295 }
227 } else {
228 e
229296 }
230 })
297 } else {
298 e
299 }
300 })
301 }
302
303 pub(crate) fn run_bidirectional<C: Codec>(
304 &self,
305 initial: BidirectionalMessage,
306 callback: SubCallback<'_>,
307 ) -> Result<BidirectionalMessage, ServerError> {
308 self.with_locked_io::<C, _>(|writer, reader, buf| {
309 bidirectional_protocol::run_conversation::<C>(writer, reader, buf, initial, callback)
310 })
231311 }
232312}
233313
src/tools/rust-analyzer/crates/proc-macro-api/src/transport.rs created+3
......@@ -0,0 +1,3 @@
1//! Contains construct for transport of messages.
2pub mod codec;
3pub mod framing;
src/tools/rust-analyzer/crates/proc-macro-api/src/transport/codec.rs created+15
......@@ -0,0 +1,15 @@
1//! Protocol codec
2
3use std::io;
4
5use serde::de::DeserializeOwned;
6
7use crate::transport::framing::Framing;
8
9pub mod json;
10pub mod postcard;
11
12pub trait Codec: Framing {
13 fn encode<T: serde::Serialize>(msg: &T) -> io::Result<Self::Buf>;
14 fn decode<T: DeserializeOwned>(buf: &mut Self::Buf) -> io::Result<T>;
15}
src/tools/rust-analyzer/crates/proc-macro-api/src/transport/codec/json.rs created+58
......@@ -0,0 +1,58 @@
1//! Protocol functions for json.
2use std::io::{self, BufRead, Write};
3
4use serde::{Serialize, de::DeserializeOwned};
5
6use crate::{Codec, transport::framing::Framing};
7
8pub struct JsonProtocol;
9
10impl Framing for JsonProtocol {
11 type Buf = String;
12
13 fn read<'a, R: BufRead + ?Sized>(
14 inp: &mut R,
15 buf: &'a mut String,
16 ) -> io::Result<Option<&'a mut String>> {
17 loop {
18 buf.clear();
19
20 inp.read_line(buf)?;
21 buf.pop(); // Remove trailing '\n'
22
23 if buf.is_empty() {
24 return Ok(None);
25 }
26
27 // Some ill behaved macro try to use stdout for debugging
28 // We ignore it here
29 if !buf.starts_with('{') {
30 tracing::error!("proc-macro tried to print : {}", buf);
31 continue;
32 }
33
34 return Ok(Some(buf));
35 }
36 }
37
38 fn write<W: Write + ?Sized>(out: &mut W, buf: &String) -> io::Result<()> {
39 tracing::debug!("> {}", buf);
40 out.write_all(buf.as_bytes())?;
41 out.write_all(b"\n")?;
42 out.flush()
43 }
44}
45
46impl Codec for JsonProtocol {
47 fn encode<T: Serialize>(msg: &T) -> io::Result<String> {
48 Ok(serde_json::to_string(msg)?)
49 }
50
51 fn decode<T: DeserializeOwned>(buf: &mut String) -> io::Result<T> {
52 let mut deserializer = serde_json::Deserializer::from_str(buf);
53 // Note that some proc-macro generate very deep syntax tree
54 // We have to disable the current limit of serde here
55 deserializer.disable_recursion_limit();
56 Ok(T::deserialize(&mut deserializer)?)
57 }
58}
src/tools/rust-analyzer/crates/proc-macro-api/src/transport/codec/postcard.rs created+40
......@@ -0,0 +1,40 @@
1//! Postcard encode and decode implementations.
2
3use std::io::{self, BufRead, Write};
4
5use serde::{Serialize, de::DeserializeOwned};
6
7use crate::{Codec, transport::framing::Framing};
8
9pub struct PostcardProtocol;
10
11impl Framing for PostcardProtocol {
12 type Buf = Vec<u8>;
13
14 fn read<'a, R: BufRead + ?Sized>(
15 inp: &mut R,
16 buf: &'a mut Vec<u8>,
17 ) -> io::Result<Option<&'a mut Vec<u8>>> {
18 buf.clear();
19 let n = inp.read_until(0, buf)?;
20 if n == 0 {
21 return Ok(None);
22 }
23 Ok(Some(buf))
24 }
25
26 fn write<W: Write + ?Sized>(out: &mut W, buf: &Vec<u8>) -> io::Result<()> {
27 out.write_all(buf)?;
28 out.flush()
29 }
30}
31
32impl Codec for PostcardProtocol {
33 fn encode<T: Serialize>(msg: &T) -> io::Result<Vec<u8>> {
34 postcard::to_allocvec_cobs(msg).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
35 }
36
37 fn decode<T: DeserializeOwned>(buf: &mut Self::Buf) -> io::Result<T> {
38 postcard::from_bytes_cobs(buf).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))
39 }
40}
src/tools/rust-analyzer/crates/proc-macro-api/src/transport/framing.rs created+14
......@@ -0,0 +1,14 @@
1//! Protocol framing
2
3use std::io::{self, BufRead, Write};
4
5pub trait Framing {
6 type Buf: Default + Send + Sync;
7
8 fn read<'a, R: BufRead + ?Sized>(
9 inp: &mut R,
10 buf: &'a mut Self::Buf,
11 ) -> io::Result<Option<&'a mut Self::Buf>>;
12
13 fn write<W: Write + ?Sized>(out: &mut W, buf: &Self::Buf) -> io::Result<()>;
14}
src/tools/rust-analyzer/crates/proc-macro-srv-cli/Cargo.toml-1
......@@ -13,7 +13,6 @@ publish = false
1313[dependencies]
1414proc-macro-srv.workspace = true
1515proc-macro-api.workspace = true
16tt.workspace = true
1716postcard.workspace = true
1817clap = {version = "4.5.42", default-features = false, features = ["std"]}
1918
src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main.rs+12-1
......@@ -52,11 +52,16 @@ fn main() -> std::io::Result<()> {
5252enum ProtocolFormat {
5353 JsonLegacy,
5454 PostcardLegacy,
55 BidirectionalPostcardPrototype,
5556}
5657
5758impl ValueEnum for ProtocolFormat {
5859 fn value_variants<'a>() -> &'a [Self] {
59 &[ProtocolFormat::JsonLegacy, ProtocolFormat::PostcardLegacy]
60 &[
61 ProtocolFormat::JsonLegacy,
62 ProtocolFormat::PostcardLegacy,
63 ProtocolFormat::BidirectionalPostcardPrototype,
64 ]
6065 }
6166
6267 fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
......@@ -65,12 +70,18 @@ impl ValueEnum for ProtocolFormat {
6570 ProtocolFormat::PostcardLegacy => {
6671 Some(clap::builder::PossibleValue::new("postcard-legacy"))
6772 }
73 ProtocolFormat::BidirectionalPostcardPrototype => {
74 Some(clap::builder::PossibleValue::new("bidirectional-postcard-prototype"))
75 }
6876 }
6977 }
7078 fn from_str(input: &str, _ignore_case: bool) -> Result<Self, String> {
7179 match input {
7280 "json-legacy" => Ok(ProtocolFormat::JsonLegacy),
7381 "postcard-legacy" => Ok(ProtocolFormat::PostcardLegacy),
82 "bidirectional-postcard-prototype" => {
83 Ok(ProtocolFormat::BidirectionalPostcardPrototype)
84 }
7485 _ => Err(format!("unknown protocol format: {input}")),
7586 }
7687 }
src/tools/rust-analyzer/crates/proc-macro-srv-cli/src/main_loop.rs+262-32
......@@ -1,24 +1,21 @@
11//! The main loop of the proc-macro server.
2use std::io;
3
42use proc_macro_api::{
53 Codec,
6 legacy_protocol::{
7 json::JsonProtocol,
8 msg::{
9 self, ExpandMacroData, ExpnGlobals, Message, SpanMode, SpanTransformer,
10 deserialize_span_data_index_map, serialize_span_data_index_map,
11 },
12 postcard::PostcardProtocol,
13 },
4 bidirectional_protocol::msg as bidirectional,
5 legacy_protocol::msg as legacy,
6 transport::codec::{json::JsonProtocol, postcard::PostcardProtocol},
147 version::CURRENT_API_VERSION,
158};
9use std::io;
10
11use legacy::Message;
12
1613use proc_macro_srv::{EnvSnapshot, SpanId};
1714
1815use crate::ProtocolFormat;
1916struct SpanTrans;
2017
21impl SpanTransformer for SpanTrans {
18impl legacy::SpanTransformer for SpanTrans {
2219 type Table = ();
2320 type Span = SpanId;
2421 fn token_id_of(
......@@ -39,9 +36,232 @@ pub(crate) fn run(format: ProtocolFormat) -> io::Result<()> {
3936 match format {
4037 ProtocolFormat::JsonLegacy => run_::<JsonProtocol>(),
4138 ProtocolFormat::PostcardLegacy => run_::<PostcardProtocol>(),
39 ProtocolFormat::BidirectionalPostcardPrototype => run_new::<PostcardProtocol>(),
4240 }
4341}
4442
43fn run_new<C: Codec>() -> io::Result<()> {
44 fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind {
45 match kind {
46 proc_macro_srv::ProcMacroKind::CustomDerive => {
47 proc_macro_api::ProcMacroKind::CustomDerive
48 }
49 proc_macro_srv::ProcMacroKind::Bang => proc_macro_api::ProcMacroKind::Bang,
50 proc_macro_srv::ProcMacroKind::Attr => proc_macro_api::ProcMacroKind::Attr,
51 }
52 }
53
54 let mut buf = C::Buf::default();
55 let mut stdin = io::stdin();
56 let mut stdout = io::stdout();
57
58 let env_snapshot = EnvSnapshot::default();
59 let srv = proc_macro_srv::ProcMacroSrv::new(&env_snapshot);
60
61 let mut span_mode = legacy::SpanMode::Id;
62
63 'outer: loop {
64 let req_opt =
65 bidirectional::BidirectionalMessage::read::<_, C>(&mut stdin.lock(), &mut buf)?;
66 let Some(req) = req_opt else {
67 break 'outer;
68 };
69
70 match req {
71 bidirectional::BidirectionalMessage::Request(request) => match request {
72 bidirectional::Request::ListMacros { dylib_path } => {
73 let res = srv.list_macros(&dylib_path).map(|macros| {
74 macros
75 .into_iter()
76 .map(|(name, kind)| (name, macro_kind_to_api(kind)))
77 .collect()
78 });
79
80 send_response::<C>(&stdout, bidirectional::Response::ListMacros(res))?;
81 }
82
83 bidirectional::Request::ApiVersionCheck {} => {
84 // bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION).write::<_, C>(stdout)
85 send_response::<C>(
86 &stdout,
87 bidirectional::Response::ApiVersionCheck(CURRENT_API_VERSION),
88 )?;
89 }
90
91 bidirectional::Request::SetConfig(config) => {
92 span_mode = config.span_mode;
93 send_response::<C>(&stdout, bidirectional::Response::SetConfig(config))?;
94 }
95 bidirectional::Request::ExpandMacro(task) => {
96 handle_expand::<C>(&srv, &mut stdin, &mut stdout, &mut buf, span_mode, *task)?;
97 }
98 },
99 _ => continue,
100 }
101 }
102
103 Ok(())
104}
105
106fn handle_expand<C: Codec>(
107 srv: &proc_macro_srv::ProcMacroSrv<'_>,
108 stdin: &io::Stdin,
109 stdout: &io::Stdout,
110 buf: &mut C::Buf,
111 span_mode: legacy::SpanMode,
112 task: bidirectional::ExpandMacro,
113) -> io::Result<()> {
114 match span_mode {
115 legacy::SpanMode::Id => handle_expand_id::<C>(srv, stdout, task),
116 legacy::SpanMode::RustAnalyzer => handle_expand_ra::<C>(srv, stdin, stdout, buf, task),
117 }
118}
119
120fn handle_expand_id<C: Codec>(
121 srv: &proc_macro_srv::ProcMacroSrv<'_>,
122 stdout: &io::Stdout,
123 task: bidirectional::ExpandMacro,
124) -> io::Result<()> {
125 let bidirectional::ExpandMacro { lib, env, current_dir, data } = task;
126 let bidirectional::ExpandMacroData {
127 macro_body,
128 macro_name,
129 attributes,
130 has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. },
131 ..
132 } = data;
133
134 let def_site = SpanId(def_site as u32);
135 let call_site = SpanId(call_site as u32);
136 let mixed_site = SpanId(mixed_site as u32);
137
138 let macro_body =
139 macro_body.to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b);
140 let attributes = attributes
141 .map(|it| it.to_tokenstream_unresolved::<SpanTrans>(CURRENT_API_VERSION, |_, b| b));
142
143 let res = srv
144 .expand(
145 lib,
146 &env,
147 current_dir,
148 &macro_name,
149 macro_body,
150 attributes,
151 def_site,
152 call_site,
153 mixed_site,
154 None,
155 )
156 .map(|it| {
157 legacy::FlatTree::from_tokenstream_raw::<SpanTrans>(it, call_site, CURRENT_API_VERSION)
158 })
159 .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default()));
160
161 send_response::<C>(&stdout, bidirectional::Response::ExpandMacro(res))
162}
163
164struct ProcMacroClientHandle<'a, C: Codec> {
165 stdin: &'a io::Stdin,
166 stdout: &'a io::Stdout,
167 buf: &'a mut C::Buf,
168}
169
170impl<C: Codec> proc_macro_srv::ProcMacroClientInterface for ProcMacroClientHandle<'_, C> {
171 fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String> {
172 let req = bidirectional::BidirectionalMessage::SubRequest(
173 bidirectional::SubRequest::SourceText { file_id, start, end },
174 );
175
176 if req.write::<_, C>(&mut self.stdout.lock()).is_err() {
177 return None;
178 }
179
180 let msg = match bidirectional::BidirectionalMessage::read::<_, C>(
181 &mut self.stdin.lock(),
182 self.buf,
183 ) {
184 Ok(Some(msg)) => msg,
185 _ => return None,
186 };
187
188 match msg {
189 bidirectional::BidirectionalMessage::SubResponse(
190 bidirectional::SubResponse::SourceTextResult { text },
191 ) => text,
192 _ => None,
193 }
194 }
195}
196
197fn handle_expand_ra<C: Codec>(
198 srv: &proc_macro_srv::ProcMacroSrv<'_>,
199 stdin: &io::Stdin,
200 stdout: &io::Stdout,
201 buf: &mut C::Buf,
202 task: bidirectional::ExpandMacro,
203) -> io::Result<()> {
204 let bidirectional::ExpandMacro {
205 lib,
206 env,
207 current_dir,
208 data:
209 bidirectional::ExpandMacroData {
210 macro_body,
211 macro_name,
212 attributes,
213 has_global_spans: bidirectional::ExpnGlobals { def_site, call_site, mixed_site, .. },
214 span_data_table,
215 },
216 } = task;
217
218 let mut span_data_table = legacy::deserialize_span_data_index_map(&span_data_table);
219
220 let def_site = span_data_table[def_site];
221 let call_site = span_data_table[call_site];
222 let mixed_site = span_data_table[mixed_site];
223
224 let macro_body =
225 macro_body.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| {
226 srv.join_spans(a, b).unwrap_or(b)
227 });
228
229 let attributes = attributes.map(|it| {
230 it.to_tokenstream_resolved(CURRENT_API_VERSION, &span_data_table, |a, b| {
231 srv.join_spans(a, b).unwrap_or(b)
232 })
233 });
234
235 let res = srv
236 .expand(
237 lib,
238 &env,
239 current_dir,
240 &macro_name,
241 macro_body,
242 attributes,
243 def_site,
244 call_site,
245 mixed_site,
246 Some(&mut ProcMacroClientHandle::<C> { stdin, stdout, buf }),
247 )
248 .map(|it| {
249 (
250 legacy::FlatTree::from_tokenstream(
251 it,
252 CURRENT_API_VERSION,
253 call_site,
254 &mut span_data_table,
255 ),
256 legacy::serialize_span_data_index_map(&span_data_table),
257 )
258 })
259 .map(|(tree, span_data_table)| bidirectional::ExpandMacroExtended { tree, span_data_table })
260 .map_err(|e| legacy::PanicMessage(e.into_string().unwrap_or_default()));
261
262 send_response::<C>(&stdout, bidirectional::Response::ExpandMacroExtended(res))
263}
264
45265fn run_<C: Codec>() -> io::Result<()> {
46266 fn macro_kind_to_api(kind: proc_macro_srv::ProcMacroKind) -> proc_macro_api::ProcMacroKind {
47267 match kind {
......@@ -54,38 +274,38 @@ fn run_<C: Codec>() -> io::Result<()> {
54274 }
55275
56276 let mut buf = C::Buf::default();
57 let mut read_request = || msg::Request::read::<_, C>(&mut io::stdin().lock(), &mut buf);
58 let write_response = |msg: msg::Response| msg.write::<_, C>(&mut io::stdout().lock());
277 let mut read_request = || legacy::Request::read::<_, C>(&mut io::stdin().lock(), &mut buf);
278 let write_response = |msg: legacy::Response| msg.write::<_, C>(&mut io::stdout().lock());
59279
60280 let env = EnvSnapshot::default();
61281 let srv = proc_macro_srv::ProcMacroSrv::new(&env);
62282
63 let mut span_mode = SpanMode::Id;
283 let mut span_mode = legacy::SpanMode::Id;
64284
65285 while let Some(req) = read_request()? {
66286 let res = match req {
67 msg::Request::ListMacros { dylib_path } => {
68 msg::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| {
287 legacy::Request::ListMacros { dylib_path } => {
288 legacy::Response::ListMacros(srv.list_macros(&dylib_path).map(|macros| {
69289 macros.into_iter().map(|(name, kind)| (name, macro_kind_to_api(kind))).collect()
70290 }))
71291 }
72 msg::Request::ExpandMacro(task) => {
73 let msg::ExpandMacro {
292 legacy::Request::ExpandMacro(task) => {
293 let legacy::ExpandMacro {
74294 lib,
75295 env,
76296 current_dir,
77297 data:
78 ExpandMacroData {
298 legacy::ExpandMacroData {
79299 macro_body,
80300 macro_name,
81301 attributes,
82302 has_global_spans:
83 ExpnGlobals { serialize: _, def_site, call_site, mixed_site },
303 legacy::ExpnGlobals { serialize: _, def_site, call_site, mixed_site },
84304 span_data_table,
85305 },
86306 } = *task;
87307 match span_mode {
88 SpanMode::Id => msg::Response::ExpandMacro({
308 legacy::SpanMode::Id => legacy::Response::ExpandMacro({
89309 let def_site = SpanId(def_site as u32);
90310 let call_site = SpanId(call_site as u32);
91311 let mixed_site = SpanId(mixed_site as u32);
......@@ -106,19 +326,21 @@ fn run_<C: Codec>() -> io::Result<()> {
106326 def_site,
107327 call_site,
108328 mixed_site,
329 None,
109330 )
110331 .map(|it| {
111 msg::FlatTree::from_tokenstream_raw::<SpanTrans>(
332 legacy::FlatTree::from_tokenstream_raw::<SpanTrans>(
112333 it,
113334 call_site,
114335 CURRENT_API_VERSION,
115336 )
116337 })
117338 .map_err(|e| e.into_string().unwrap_or_default())
118 .map_err(msg::PanicMessage)
339 .map_err(legacy::PanicMessage)
119340 }),
120 SpanMode::RustAnalyzer => msg::Response::ExpandMacroExtended({
121 let mut span_data_table = deserialize_span_data_index_map(&span_data_table);
341 legacy::SpanMode::RustAnalyzer => legacy::Response::ExpandMacroExtended({
342 let mut span_data_table =
343 legacy::deserialize_span_data_index_map(&span_data_table);
122344
123345 let def_site = span_data_table[def_site];
124346 let call_site = span_data_table[call_site];
......@@ -146,31 +368,34 @@ fn run_<C: Codec>() -> io::Result<()> {
146368 def_site,
147369 call_site,
148370 mixed_site,
371 None,
149372 )
150373 .map(|it| {
151374 (
152 msg::FlatTree::from_tokenstream(
375 legacy::FlatTree::from_tokenstream(
153376 it,
154377 CURRENT_API_VERSION,
155378 call_site,
156379 &mut span_data_table,
157380 ),
158 serialize_span_data_index_map(&span_data_table),
381 legacy::serialize_span_data_index_map(&span_data_table),
159382 )
160383 })
161 .map(|(tree, span_data_table)| msg::ExpandMacroExtended {
384 .map(|(tree, span_data_table)| legacy::ExpandMacroExtended {
162385 tree,
163386 span_data_table,
164387 })
165388 .map_err(|e| e.into_string().unwrap_or_default())
166 .map_err(msg::PanicMessage)
389 .map_err(legacy::PanicMessage)
167390 }),
168391 }
169392 }
170 msg::Request::ApiVersionCheck {} => msg::Response::ApiVersionCheck(CURRENT_API_VERSION),
171 msg::Request::SetConfig(config) => {
393 legacy::Request::ApiVersionCheck {} => {
394 legacy::Response::ApiVersionCheck(CURRENT_API_VERSION)
395 }
396 legacy::Request::SetConfig(config) => {
172397 span_mode = config.span_mode;
173 msg::Response::SetConfig(config)
398 legacy::Response::SetConfig(config)
174399 }
175400 };
176401 write_response(res)?
......@@ -178,3 +403,8 @@ fn run_<C: Codec>() -> io::Result<()> {
178403
179404 Ok(())
180405}
406
407fn send_response<C: Codec>(stdout: &io::Stdout, resp: bidirectional::Response) -> io::Result<()> {
408 let resp = bidirectional::BidirectionalMessage::Response(resp);
409 resp.write::<_, C>(&mut stdout.lock())
410}
src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib.rs+6-5
......@@ -12,8 +12,8 @@ use object::Object;
1212use paths::{Utf8Path, Utf8PathBuf};
1313
1414use crate::{
15 PanicMessage, ProcMacroKind, ProcMacroSrvSpan, dylib::proc_macros::ProcMacros,
16 token_stream::TokenStream,
15 PanicMessage, ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan,
16 dylib::proc_macros::ProcMacros, token_stream::TokenStream,
1717};
1818
1919pub(crate) struct Expander {
......@@ -37,7 +37,7 @@ impl Expander {
3737 Ok(Expander { inner: library, modified_time })
3838 }
3939
40 pub(crate) fn expand<S: ProcMacroSrvSpan>(
40 pub(crate) fn expand<'a, S: ProcMacroSrvSpan + 'a>(
4141 &self,
4242 macro_name: &str,
4343 macro_body: TokenStream<S>,
......@@ -45,13 +45,14 @@ impl Expander {
4545 def_site: S,
4646 call_site: S,
4747 mixed_site: S,
48 callback: Option<ProcMacroClientHandle<'_>>,
4849 ) -> Result<TokenStream<S>, PanicMessage>
4950 where
50 <S::Server as bridge::server::Types>::TokenStream: Default,
51 <S::Server<'a> as bridge::server::Types>::TokenStream: Default,
5152 {
5253 self.inner
5354 .proc_macros
54 .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site)
55 .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site, callback)
5556 }
5657
5758 pub(crate) fn list_macros(&self) -> impl Iterator<Item = (&str, ProcMacroKind)> {
src/tools/rust-analyzer/crates/proc-macro-srv/src/dylib/proc_macros.rs+5-6
......@@ -1,9 +1,7 @@
11//! Proc macro ABI
2
2use crate::{ProcMacroClientHandle, ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream};
33use proc_macro::bridge;
44
5use crate::{ProcMacroKind, ProcMacroSrvSpan, token_stream::TokenStream};
6
75#[repr(transparent)]
86pub(crate) struct ProcMacros([bridge::client::ProcMacro]);
97
......@@ -22,6 +20,7 @@ impl ProcMacros {
2220 def_site: S,
2321 call_site: S,
2422 mixed_site: S,
23 callback: Option<ProcMacroClientHandle<'_>>,
2524 ) -> Result<TokenStream<S>, crate::PanicMessage> {
2625 let parsed_attributes = attribute.unwrap_or_default();
2726
......@@ -32,7 +31,7 @@ impl ProcMacros {
3231 {
3332 let res = client.run(
3433 &bridge::server::SameThread,
35 S::make_server(call_site, def_site, mixed_site),
34 S::make_server(call_site, def_site, mixed_site, callback),
3635 macro_body,
3736 cfg!(debug_assertions),
3837 );
......@@ -41,7 +40,7 @@ impl ProcMacros {
4140 bridge::client::ProcMacro::Bang { name, client } if *name == macro_name => {
4241 let res = client.run(
4342 &bridge::server::SameThread,
44 S::make_server(call_site, def_site, mixed_site),
43 S::make_server(call_site, def_site, mixed_site, callback),
4544 macro_body,
4645 cfg!(debug_assertions),
4746 );
......@@ -50,7 +49,7 @@ impl ProcMacros {
5049 bridge::client::ProcMacro::Attr { name, client } if *name == macro_name => {
5150 let res = client.run(
5251 &bridge::server::SameThread,
53 S::make_server(call_site, def_site, mixed_site),
52 S::make_server(call_site, def_site, mixed_site, callback),
5453 parsed_attributes,
5554 macro_body,
5655 cfg!(debug_assertions),
src/tools/rust-analyzer/crates/proc-macro-srv/src/lib.rs+36-9
......@@ -91,6 +91,12 @@ impl<'env> ProcMacroSrv<'env> {
9191 }
9292}
9393
94pub type ProcMacroClientHandle<'a> = &'a mut (dyn ProcMacroClientInterface + Sync + Send);
95
96pub trait ProcMacroClientInterface {
97 fn source_text(&mut self, file_id: u32, start: u32, end: u32) -> Option<String>;
98}
99
94100const EXPANDER_STACK_SIZE: usize = 8 * 1024 * 1024;
95101
96102impl ProcMacroSrv<'_> {
......@@ -105,6 +111,7 @@ impl ProcMacroSrv<'_> {
105111 def_site: S,
106112 call_site: S,
107113 mixed_site: S,
114 callback: Option<ProcMacroClientHandle<'_>>,
108115 ) -> Result<token_stream::TokenStream<S>, PanicMessage> {
109116 let snapped_env = self.env;
110117 let expander = self.expander(lib.as_ref()).map_err(|err| PanicMessage {
......@@ -120,8 +127,10 @@ impl ProcMacroSrv<'_> {
120127 .stack_size(EXPANDER_STACK_SIZE)
121128 .name(macro_name.to_owned())
122129 .spawn_scoped(s, move || {
123 expander
124 .expand(macro_name, macro_body, attribute, def_site, call_site, mixed_site)
130 expander.expand(
131 macro_name, macro_body, attribute, def_site, call_site, mixed_site,
132 callback,
133 )
125134 });
126135 match thread.unwrap().join() {
127136 Ok(res) => res,
......@@ -169,30 +178,48 @@ impl ProcMacroSrv<'_> {
169178}
170179
171180pub trait ProcMacroSrvSpan: Copy + Send + Sync {
172 type Server: proc_macro::bridge::server::Server<TokenStream = crate::token_stream::TokenStream<Self>>;
173 fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server;
181 type Server<'a>: proc_macro::bridge::server::Server<TokenStream = crate::token_stream::TokenStream<Self>>;
182 fn make_server<'a>(
183 call_site: Self,
184 def_site: Self,
185 mixed_site: Self,
186 callback: Option<ProcMacroClientHandle<'a>>,
187 ) -> Self::Server<'a>;
174188}
175189
176190impl ProcMacroSrvSpan for SpanId {
177 type Server = server_impl::token_id::SpanIdServer;
178
179 fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server {
191 type Server<'a> = server_impl::token_id::SpanIdServer<'a>;
192
193 fn make_server<'a>(
194 call_site: Self,
195 def_site: Self,
196 mixed_site: Self,
197 callback: Option<ProcMacroClientHandle<'a>>,
198 ) -> Self::Server<'a> {
180199 Self::Server {
181200 call_site,
182201 def_site,
183202 mixed_site,
203 callback,
184204 tracked_env_vars: Default::default(),
185205 tracked_paths: Default::default(),
186206 }
187207 }
188208}
209
189210impl ProcMacroSrvSpan for Span {
190 type Server = server_impl::rust_analyzer_span::RaSpanServer;
191 fn make_server(call_site: Self, def_site: Self, mixed_site: Self) -> Self::Server {
211 type Server<'a> = server_impl::rust_analyzer_span::RaSpanServer<'a>;
212 fn make_server<'a>(
213 call_site: Self,
214 def_site: Self,
215 mixed_site: Self,
216 callback: Option<ProcMacroClientHandle<'a>>,
217 ) -> Self::Server<'a> {
192218 Self::Server {
193219 call_site,
194220 def_site,
195221 mixed_site,
222 callback,
196223 tracked_env_vars: Default::default(),
197224 tracked_paths: Default::default(),
198225 }
src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs+15-10
......@@ -14,13 +14,14 @@ use proc_macro::bridge::server;
1414use span::{FIXUP_ERASED_FILE_AST_ID_MARKER, Span, TextRange, TextSize};
1515
1616use crate::{
17 ProcMacroClientHandle,
1718 bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree},
1819 server_impl::literal_from_str,
1920};
2021
2122pub struct FreeFunctions;
2223
23pub struct RaSpanServer {
24pub struct RaSpanServer<'a> {
2425 // FIXME: Report this back to the caller to track as dependencies
2526 pub tracked_env_vars: HashMap<Box<str>, Option<Box<str>>>,
2627 // FIXME: Report this back to the caller to track as dependencies
......@@ -28,16 +29,17 @@ pub struct RaSpanServer {
2829 pub call_site: Span,
2930 pub def_site: Span,
3031 pub mixed_site: Span,
32 pub callback: Option<ProcMacroClientHandle<'a>>,
3133}
3234
33impl server::Types for RaSpanServer {
35impl server::Types for RaSpanServer<'_> {
3436 type FreeFunctions = FreeFunctions;
3537 type TokenStream = crate::token_stream::TokenStream<Span>;
3638 type Span = Span;
3739 type Symbol = Symbol;
3840}
3941
40impl server::FreeFunctions for RaSpanServer {
42impl server::FreeFunctions for RaSpanServer<'_> {
4143 fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
4244 None
4345 }
......@@ -58,7 +60,7 @@ impl server::FreeFunctions for RaSpanServer {
5860 }
5961}
6062
61impl server::TokenStream for RaSpanServer {
63impl server::TokenStream for RaSpanServer<'_> {
6264 fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
6365 stream.is_empty()
6466 }
......@@ -121,7 +123,7 @@ impl server::TokenStream for RaSpanServer {
121123 }
122124}
123125
124impl server::Span for RaSpanServer {
126impl server::Span for RaSpanServer<'_> {
125127 fn debug(&mut self, span: Self::Span) -> String {
126128 format!("{:?}", span)
127129 }
......@@ -149,9 +151,12 @@ impl server::Span for RaSpanServer {
149151 ///
150152 /// See PR:
151153 /// https://github.com/rust-lang/rust/pull/55780
152 fn source_text(&mut self, _span: Self::Span) -> Option<String> {
153 // FIXME requires db, needs special handling wrt fixup spans
154 None
154 fn source_text(&mut self, span: Self::Span) -> Option<String> {
155 let file_id = span.anchor.file_id;
156 let start: u32 = span.range.start().into();
157 let end: u32 = span.range.end().into();
158
159 self.callback.as_mut()?.source_text(file_id.file_id().index(), start, end)
155160 }
156161
157162 fn parent(&mut self, _span: Self::Span) -> Option<Self::Span> {
......@@ -269,14 +274,14 @@ impl server::Span for RaSpanServer {
269274 }
270275}
271276
272impl server::Symbol for RaSpanServer {
277impl server::Symbol for RaSpanServer<'_> {
273278 fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
274279 // FIXME: nfc-normalize and validate idents
275280 Ok(<Self as server::Server>::intern_symbol(string))
276281 }
277282}
278283
279impl server::Server for RaSpanServer {
284impl server::Server for RaSpanServer<'_> {
280285 fn globals(&mut self) -> ExpnGlobals<Self::Span> {
281286 ExpnGlobals {
282287 def_site: self.def_site,
src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs+9-7
......@@ -9,6 +9,7 @@ use intern::Symbol;
99use proc_macro::bridge::server;
1010
1111use crate::{
12 ProcMacroClientHandle,
1213 bridge::{Diagnostic, ExpnGlobals, Literal, TokenTree},
1314 server_impl::literal_from_str,
1415};
......@@ -26,7 +27,7 @@ type Span = SpanId;
2627
2728pub struct FreeFunctions;
2829
29pub struct SpanIdServer {
30pub struct SpanIdServer<'a> {
3031 // FIXME: Report this back to the caller to track as dependencies
3132 pub tracked_env_vars: HashMap<Box<str>, Option<Box<str>>>,
3233 // FIXME: Report this back to the caller to track as dependencies
......@@ -34,16 +35,17 @@ pub struct SpanIdServer {
3435 pub call_site: Span,
3536 pub def_site: Span,
3637 pub mixed_site: Span,
38 pub callback: Option<ProcMacroClientHandle<'a>>,
3739}
3840
39impl server::Types for SpanIdServer {
41impl server::Types for SpanIdServer<'_> {
4042 type FreeFunctions = FreeFunctions;
4143 type TokenStream = crate::token_stream::TokenStream<Span>;
4244 type Span = Span;
4345 type Symbol = Symbol;
4446}
4547
46impl server::FreeFunctions for SpanIdServer {
48impl server::FreeFunctions for SpanIdServer<'_> {
4749 fn injected_env_var(&mut self, _: &str) -> Option<std::string::String> {
4850 None
4951 }
......@@ -61,7 +63,7 @@ impl server::FreeFunctions for SpanIdServer {
6163 fn emit_diagnostic(&mut self, _: Diagnostic<Self::Span>) {}
6264}
6365
64impl server::TokenStream for SpanIdServer {
66impl server::TokenStream for SpanIdServer<'_> {
6567 fn is_empty(&mut self, stream: &Self::TokenStream) -> bool {
6668 stream.is_empty()
6769 }
......@@ -118,7 +120,7 @@ impl server::TokenStream for SpanIdServer {
118120 }
119121}
120122
121impl server::Span for SpanIdServer {
123impl server::Span for SpanIdServer<'_> {
122124 fn debug(&mut self, span: Self::Span) -> String {
123125 format!("{:?}", span.0)
124126 }
......@@ -185,14 +187,14 @@ impl server::Span for SpanIdServer {
185187 }
186188}
187189
188impl server::Symbol for SpanIdServer {
190impl server::Symbol for SpanIdServer<'_> {
189191 fn normalize_and_validate_ident(&mut self, string: &str) -> Result<Self::Symbol, ()> {
190192 // FIXME: nfc-normalize and validate idents
191193 Ok(<Self as server::Server>::intern_symbol(string))
192194 }
193195}
194196
195impl server::Server for SpanIdServer {
197impl server::Server for SpanIdServer<'_> {
196198 fn globals(&mut self) -> ExpnGlobals<Self::Span> {
197199 ExpnGlobals {
198200 def_site: self.def_site,
src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/utils.rs+5-3
......@@ -59,8 +59,9 @@ fn assert_expand_impl(
5959 let input_ts_string = format!("{input_ts:?}");
6060 let attr_ts_string = attr_ts.as_ref().map(|it| format!("{it:?}"));
6161
62 let res =
63 expander.expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site).unwrap();
62 let res = expander
63 .expand(macro_name, input_ts, attr_ts, def_site, call_site, mixed_site, None)
64 .unwrap();
6465 expect.assert_eq(&format!(
6566 "{input_ts_string}{}{}{}",
6667 if attr_ts_string.is_some() { "\n\n" } else { "" },
......@@ -91,7 +92,8 @@ fn assert_expand_impl(
9192 let fixture_string = format!("{fixture:?}");
9293 let attr_string = attr.as_ref().map(|it| format!("{it:?}"));
9394
94 let res = expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site).unwrap();
95 let res =
96 expander.expand(macro_name, fixture, attr, def_site, call_site, mixed_site, None).unwrap();
9597 expect_spanned.assert_eq(&format!(
9698 "{fixture_string}{}{}{}",
9799 if attr_string.is_some() { "\n\n" } else { "" },
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs+22-16
......@@ -354,11 +354,10 @@ impl flags::AnalysisStats {
354354 self.run_term_search(&workspace, db, &vfs, &file_ids, verbosity);
355355 }
356356
357 hir::clear_tls_solver_cache();
358 unsafe { hir::collect_ty_garbage() };
359
360357 let db = host.raw_database_mut();
361358 db.trigger_lru_eviction();
359 hir::clear_tls_solver_cache();
360 unsafe { hir::collect_ty_garbage() };
362361
363362 let total_span = analysis_sw.elapsed();
364363 eprintln!("{:<20} {total_span}", "Total:");
......@@ -693,21 +692,24 @@ impl flags::AnalysisStats {
693692 let mut sw = self.stop_watch();
694693 let mut all = 0;
695694 let mut fail = 0;
696 for &body_id in bodies {
695 for &body in bodies {
697696 bar.set_message(move || {
698 format!("mir lowering: {}", full_name(db, body_id, body_id.module(db)))
697 format!("mir lowering: {}", full_name(db, body, body.module(db)))
699698 });
700699 bar.inc(1);
701 if matches!(body_id, DefWithBody::Variant(_)) {
700 if matches!(body, DefWithBody::Variant(_)) {
702701 continue;
703702 }
704 let module = body_id.module(db);
705 if !self.should_process(db, body_id, module) {
703 let module = body.module(db);
704 if !self.should_process(db, body, module) {
706705 continue;
707706 }
708707
709708 all += 1;
710 let Err(e) = db.mir_body(body_id.into()) else {
709 let Ok(body_id) = body.try_into() else {
710 continue;
711 };
712 let Err(e) = db.mir_body(body_id) else {
711713 continue;
712714 };
713715 if verbosity.is_spammy() {
......@@ -716,7 +718,7 @@ impl flags::AnalysisStats {
716718 .into_iter()
717719 .rev()
718720 .filter_map(|it| it.name(db))
719 .chain(Some(body_id.name(db).unwrap_or_else(Name::missing)))
721 .chain(Some(body.name(db).unwrap_or_else(Name::missing)))
720722 .map(|it| it.display(db, Edition::LATEST).to_string())
721723 .join("::");
722724 bar.println(format!("Mir body for {full_name} failed due {e:?}"));
......@@ -747,11 +749,12 @@ impl flags::AnalysisStats {
747749
748750 if self.parallel {
749751 let mut inference_sw = self.stop_watch();
752 let bodies = bodies.iter().filter_map(|&body| body.try_into().ok()).collect::<Vec<_>>();
750753 bodies
751754 .par_iter()
752755 .map_with(db.clone(), |snap, &body| {
753 snap.body(body.into());
754 InferenceResult::for_body(snap, body.into());
756 snap.body(body);
757 InferenceResult::for_body(snap, body);
755758 })
756759 .count();
757760 eprintln!("{:<20} {}", "Parallel Inference:", inference_sw.elapsed());
......@@ -769,6 +772,7 @@ impl flags::AnalysisStats {
769772 let mut num_pat_type_mismatches = 0;
770773 let mut panics = 0;
771774 for &body_id in bodies {
775 let Ok(body_def_id) = body_id.try_into() else { continue };
772776 let name = body_id.name(db).unwrap_or_else(Name::missing);
773777 let module = body_id.module(db);
774778 let display_target = module.krate(db).to_display_target(db);
......@@ -807,9 +811,9 @@ impl flags::AnalysisStats {
807811 bar.println(msg());
808812 }
809813 bar.set_message(msg);
810 let body = db.body(body_id.into());
814 let body = db.body(body_def_id);
811815 let inference_result =
812 catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_id.into())));
816 catch_unwind(AssertUnwindSafe(|| InferenceResult::for_body(db, body_def_id)));
813817 let inference_result = match inference_result {
814818 Ok(inference_result) => inference_result,
815819 Err(p) => {
......@@ -826,7 +830,7 @@ impl flags::AnalysisStats {
826830 }
827831 };
828832 // This query is LRU'd, so actually calling it will skew the timing results.
829 let sm = || db.body_with_source_map(body_id.into()).1;
833 let sm = || db.body_with_source_map(body_def_id).1;
830834
831835 // region:expressions
832836 let (previous_exprs, previous_unknown, previous_partially_unknown) =
......@@ -1081,6 +1085,7 @@ impl flags::AnalysisStats {
10811085 let mut sw = self.stop_watch();
10821086 bar.tick();
10831087 for &body_id in bodies {
1088 let Ok(body_def_id) = body_id.try_into() else { continue };
10841089 let module = body_id.module(db);
10851090 if !self.should_process(db, body_id, module) {
10861091 continue;
......@@ -1114,7 +1119,7 @@ impl flags::AnalysisStats {
11141119 bar.println(msg());
11151120 }
11161121 bar.set_message(msg);
1117 db.body(body_id.into());
1122 db.body(body_def_id);
11181123 bar.inc(1);
11191124 }
11201125
......@@ -1188,6 +1193,7 @@ impl flags::AnalysisStats {
11881193 style_lints: false,
11891194 term_search_fuel: 400,
11901195 term_search_borrowck: true,
1196 show_rename_conflicts: true,
11911197 },
11921198 ide::AssistResolveStrategy::All,
11931199 analysis.editioned_file_id_to_vfs(file_id),
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/rustc_tests.rs+1-1
......@@ -185,7 +185,7 @@ impl Tester {
185185
186186 if !worker.is_finished() {
187187 // attempt to cancel the worker, won't work for chalk hangs unfortunately
188 self.host.request_cancellation();
188 self.host.trigger_garbage_collection();
189189 }
190190 worker.join().and_then(identity)
191191 });
src/tools/rust-analyzer/crates/rust-analyzer/src/cli/ssr.rs+1-1
......@@ -68,7 +68,7 @@ impl flags::Search {
6868 match_finder.add_search_pattern(pattern)?;
6969 }
7070 if let Some(debug_snippet) = &self.debug {
71 for &root in ide_db::symbol_index::LocalRoots::get(db).roots(db).iter() {
71 for &root in ide_db::LocalRoots::get(db).roots(db).iter() {
7272 let sr = db.source_root(root).source_root(db);
7373 for file_id in sr.iter() {
7474 for debug_info in match_finder.debug_where_text_equal(
src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs+46-11
......@@ -98,13 +98,6 @@ config_data! {
9898 /// Code's `files.watcherExclude`.
9999 files_exclude | files_excludeDirs: Vec<Utf8PathBuf> = vec![],
100100
101 /// This config controls the frequency in which rust-analyzer will perform its internal Garbage
102 /// Collection. It is specified in revisions, roughly equivalent to number of changes. The default
103 /// is 1000.
104 ///
105 /// Setting a smaller value may help limit peak memory usage at the expense of speed.
106 gc_frequency: usize = 1000,
107
108101 /// If this is `true`, when "Goto Implementations" and in "Implementations" lens, are triggered on a `struct` or `enum` or `union`, we filter out trait implementations that originate from `derive`s above the type.
109102 gotoImplementations_filterAdjacentDerives: bool = false,
110103
......@@ -732,6 +725,9 @@ config_data! {
732725 ///
733726 /// E.g. `use ::std::io::Read;`.
734727 imports_prefixExternPrelude: bool = false,
728
729 /// Whether to warn when a rename will cause conflicts (change the meaning of the code).
730 rename_showConflicts: bool = true,
735731 }
736732}
737733
......@@ -908,8 +904,24 @@ config_data! {
908904 /// This config takes a map of crate names with the exported proc-macro names to ignore as values.
909905 procMacro_ignored: FxHashMap<Box<str>, Box<[Box<str>]>> = FxHashMap::default(),
910906
907 /// Subcommand used for bench runnables instead of `bench`.
908 runnables_bench_command: String = "bench".to_owned(),
909 /// Override the command used for bench runnables.
910 /// The first element of the array should be the program to execute (for example, `cargo`).
911 ///
912 /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
913 /// replace the package name, target option (such as `--bin` or `--example`), the target name and
914 /// the test name (name of test function or test mod path).
915 runnables_bench_overrideCommand: Option<Vec<String>> = None,
911916 /// Command to be executed instead of 'cargo' for runnables.
912917 runnables_command: Option<String> = None,
918 /// Override the command used for bench runnables.
919 /// The first element of the array should be the program to execute (for example, `cargo`).
920 ///
921 /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
922 /// replace the package name, target option (such as `--bin` or `--example`), the target name and
923 /// the test name (name of test function or test mod path).
924 runnables_doctest_overrideCommand: Option<Vec<String>> = None,
913925 /// Additional arguments to be passed to cargo for runnables such as
914926 /// tests or binaries. For example, it may be `--release`.
915927 runnables_extraArgs: Vec<String> = vec![],
......@@ -921,6 +933,15 @@ config_data! {
921933 /// they will end up being interpreted as options to
922934 /// [`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).
923935 runnables_extraTestBinaryArgs: Vec<String> = vec!["--nocapture".to_owned()],
936 /// Subcommand used for test runnables instead of `test`.
937 runnables_test_command: String = "test".to_owned(),
938 /// Override the command used for test runnables.
939 /// The first element of the array should be the program to execute (for example, `cargo`).
940 ///
941 /// Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
942 /// replace the package name, target option (such as `--bin` or `--example`), the target name and
943 /// the test name (name of test function or test mod path).
944 runnables_test_overrideCommand: Option<Vec<String>> = None,
924945
925946 /// Path to the Cargo.toml of the rust compiler workspace, for usage in rustc_private
926947 /// projects, or "discover" to try to automatically find it if the `rustc-dev` component
......@@ -1572,6 +1593,16 @@ pub struct RunnablesConfig {
15721593 pub cargo_extra_args: Vec<String>,
15731594 /// Additional arguments for the binary being run, if it is a test or benchmark.
15741595 pub extra_test_binary_args: Vec<String>,
1596 /// Subcommand used for doctest runnables instead of `test`.
1597 pub test_command: String,
1598 /// Override the command used for test runnables.
1599 pub test_override_command: Option<Vec<String>>,
1600 /// Subcommand used for doctest runnables instead of `bench`.
1601 pub bench_command: String,
1602 /// Override the command used for bench runnables.
1603 pub bench_override_command: Option<Vec<String>>,
1604 /// Override the command used for doctest runnables.
1605 pub doc_test_override_command: Option<Vec<String>>,
15751606}
15761607
15771608/// Configuration for workspace symbol search requests.
......@@ -1709,10 +1740,6 @@ impl Config {
17091740 &self.caps
17101741 }
17111742
1712 pub fn gc_freq(&self) -> usize {
1713 *self.gc_frequency()
1714 }
1715
17161743 pub fn assist(&self, source_root: Option<SourceRootId>) -> AssistConfig {
17171744 AssistConfig {
17181745 snippet_cap: self.snippet_cap(),
......@@ -1731,6 +1758,7 @@ impl Config {
17311758 ExprFillDefaultDef::Underscore => ExprFillDefaultMode::Underscore,
17321759 },
17331760 prefer_self_ty: *self.assist_preferSelf(source_root),
1761 show_rename_conflicts: *self.rename_showConflicts(source_root),
17341762 }
17351763 }
17361764
......@@ -1739,6 +1767,7 @@ impl Config {
17391767 prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
17401768 prefer_prelude: self.imports_preferPrelude(source_root).to_owned(),
17411769 prefer_absolute: self.imports_prefixExternPrelude(source_root).to_owned(),
1770 show_conflicts: *self.rename_showConflicts(source_root),
17421771 }
17431772 }
17441773
......@@ -1838,6 +1867,7 @@ impl Config {
18381867 style_lints: self.diagnostics_styleLints_enable(source_root).to_owned(),
18391868 term_search_fuel: self.assist_termSearch_fuel(source_root).to_owned() as u64,
18401869 term_search_borrowck: self.assist_termSearch_borrowcheck(source_root).to_owned(),
1870 show_rename_conflicts: *self.rename_showConflicts(source_root),
18411871 }
18421872 }
18431873
......@@ -2499,6 +2529,11 @@ impl Config {
24992529 override_cargo: self.runnables_command(source_root).clone(),
25002530 cargo_extra_args: self.runnables_extraArgs(source_root).clone(),
25012531 extra_test_binary_args: self.runnables_extraTestBinaryArgs(source_root).clone(),
2532 test_command: self.runnables_test_command(source_root).clone(),
2533 test_override_command: self.runnables_test_overrideCommand(source_root).clone(),
2534 bench_command: self.runnables_bench_command(source_root).clone(),
2535 bench_override_command: self.runnables_bench_overrideCommand(source_root).clone(),
2536 doc_test_override_command: self.runnables_doctest_overrideCommand(source_root).clone(),
25022537 }
25032538 }
25042539
src/tools/rust-analyzer/crates/rust-analyzer/src/flycheck.rs+4-4
......@@ -147,13 +147,13 @@ pub(crate) struct FlycheckHandle {
147147 sender: Sender<StateChange>,
148148 _thread: stdx::thread::JoinHandle,
149149 id: usize,
150 generation: AtomicUsize,
150 generation: Arc<AtomicUsize>,
151151}
152152
153153impl FlycheckHandle {
154154 pub(crate) fn spawn(
155155 id: usize,
156 generation: DiagnosticsGeneration,
156 generation: Arc<AtomicUsize>,
157157 sender: Sender<FlycheckMessage>,
158158 config: FlycheckConfig,
159159 sysroot_root: Option<AbsPathBuf>,
......@@ -163,7 +163,7 @@ impl FlycheckHandle {
163163 ) -> FlycheckHandle {
164164 let actor = FlycheckActor::new(
165165 id,
166 generation,
166 generation.load(Ordering::Relaxed),
167167 sender,
168168 config,
169169 sysroot_root,
......@@ -176,7 +176,7 @@ impl FlycheckHandle {
176176 stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker, format!("Flycheck{id}"))
177177 .spawn(move || actor.run(receiver))
178178 .expect("failed to spawn thread");
179 FlycheckHandle { id, generation: generation.into(), sender, _thread: thread }
179 FlycheckHandle { id, generation, sender, _thread: thread }
180180 }
181181
182182 /// Schedule a re-start of the cargo check worker to do a workspace wide check.
src/tools/rust-analyzer/crates/rust-analyzer/src/global_state.rs+9-17
......@@ -15,7 +15,7 @@ use hir::ChangeWithProcMacros;
1515use ide::{Analysis, AnalysisHost, Cancellable, FileId, SourceRootId};
1616use ide_db::{
1717 MiniCore,
18 base_db::{Crate, ProcMacroPaths, SourceDatabase},
18 base_db::{Crate, ProcMacroPaths, SourceDatabase, salsa::Revision},
1919};
2020use itertools::Itertools;
2121use load_cargo::SourceRootConfig;
......@@ -193,15 +193,14 @@ pub(crate) struct GlobalState {
193193 /// which will usually end up causing a bunch of incorrect diagnostics on startup.
194194 pub(crate) incomplete_crate_graph: bool,
195195
196 pub(crate) revisions_until_next_gc: usize,
197
198196 pub(crate) minicore: MiniCoreRustAnalyzerInternalOnly,
197 pub(crate) last_gc_revision: Revision,
199198}
200199
201200// FIXME: This should move to the VFS once the rewrite is done.
202201#[derive(Debug, Clone, Default)]
203202pub(crate) struct MiniCoreRustAnalyzerInternalOnly {
204 pub(crate) minicore_text: Option<String>,
203 pub(crate) minicore_text: Option<Arc<str>>,
205204}
206205
207206/// An immutable snapshot of the world's state at a point in time.
......@@ -258,6 +257,8 @@ impl GlobalState {
258257
259258 let (discover_sender, discover_receiver) = unbounded();
260259
260 let last_gc_revision = analysis_host.raw_database().nonce_and_revision().1;
261
261262 let mut this = GlobalState {
262263 sender,
263264 req_queue: ReqQueue::default(),
......@@ -321,8 +322,7 @@ impl GlobalState {
321322 incomplete_crate_graph: false,
322323
323324 minicore: MiniCoreRustAnalyzerInternalOnly::default(),
324
325 revisions_until_next_gc: config.gc_freq(),
325 last_gc_revision,
326326 };
327327 // Apply any required database inputs from the config.
328328 this.update_configuration(config);
......@@ -347,11 +347,11 @@ impl GlobalState {
347347
348348 let (change, modified_rust_files, workspace_structure_change) =
349349 self.cancellation_pool.scoped(|s| {
350 // start cancellation in parallel, this will kick off lru eviction
350 // start cancellation in parallel,
351351 // allowing us to do meaningful work while waiting
352352 let analysis_host = AssertUnwindSafe(&mut self.analysis_host);
353353 s.spawn(thread::ThreadIntent::LatencySensitive, || {
354 { analysis_host }.0.request_cancellation()
354 { analysis_host }.0.trigger_cancellation()
355355 });
356356
357357 // downgrade to read lock to allow more readers while we are normalizing text
......@@ -440,14 +440,6 @@ impl GlobalState {
440440
441441 self.analysis_host.apply_change(change);
442442
443 if self.revisions_until_next_gc == 0 {
444 // SAFETY: Just changed some database inputs, all queries were canceled.
445 unsafe { hir::collect_ty_garbage() };
446 self.revisions_until_next_gc = self.config.gc_freq();
447 } else {
448 self.revisions_until_next_gc -= 1;
449 }
450
451443 if !modified_ratoml_files.is_empty()
452444 || !self.config.same_source_root_parent_map(&self.local_roots_parent_map)
453445 {
......@@ -741,7 +733,7 @@ impl GlobalState {
741733
742734impl Drop for GlobalState {
743735 fn drop(&mut self) {
744 self.analysis_host.request_cancellation();
736 self.analysis_host.trigger_cancellation();
745737 }
746738}
747739
src/tools/rust-analyzer/crates/rust-analyzer/src/handlers/request.rs+5-1
......@@ -808,7 +808,11 @@ pub(crate) fn handle_will_rename_files(
808808 }
809809 })
810810 .filter_map(|(file_id, new_name)| {
811 snap.analysis.will_rename_file(file_id?, &new_name).ok()?
811 let file_id = file_id?;
812 let source_root = snap.analysis.source_root_id(file_id).ok();
813 snap.analysis
814 .will_rename_file(file_id, &new_name, &snap.config.rename(source_root))
815 .ok()?
812816 })
813817 .collect();
814818
src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs+1
......@@ -363,6 +363,7 @@ fn integrated_diagnostics_benchmark() {
363363 prefer_absolute: false,
364364 term_search_fuel: 400,
365365 term_search_borrowck: true,
366 show_rename_conflicts: true,
366367 };
367368 host.analysis()
368369 .full_diagnostics(&diagnostics_config, ide::AssistResolveStrategy::None, file_id)
src/tools/rust-analyzer/crates/rust-analyzer/src/lsp/to_proto.rs+37-16
......@@ -1561,6 +1561,9 @@ pub(crate) fn runnable(
15611561
15621562 let target = spec.target.clone();
15631563
1564 let override_command =
1565 CargoTargetSpec::override_command(snap, Some(spec.clone()), &runnable.kind);
1566
15641567 let (cargo_args, executable_args) = CargoTargetSpec::runnable_args(
15651568 snap,
15661569 Some(spec.clone()),
......@@ -1576,23 +1579,41 @@ pub(crate) fn runnable(
15761579 let label = runnable.label(Some(&target));
15771580 let location = location_link(snap, None, runnable.nav)?;
15781581
1579 Ok(Some(lsp_ext::Runnable {
1580 label,
1581 location: Some(location),
1582 kind: lsp_ext::RunnableKind::Cargo,
1583 args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
1584 workspace_root: Some(workspace_root.into()),
1585 override_cargo: config.override_cargo,
1586 cargo_args,
1587 cwd: cwd.into(),
1588 executable_args,
1589 environment: spec
1590 .sysroot_root
1591 .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
1592 .into_iter()
1593 .collect(),
1582 let environment = spec
1583 .sysroot_root
1584 .map(|root| ("RUSTC_TOOLCHAIN".to_owned(), root.to_string()))
1585 .into_iter()
1586 .collect();
1587
1588 Ok(match override_command {
1589 Some(override_command) => match override_command.split_first() {
1590 Some((program, args)) => Some(lsp_ext::Runnable {
1591 label,
1592 location: Some(location),
1593 kind: lsp_ext::RunnableKind::Shell,
1594 args: lsp_ext::RunnableArgs::Shell(lsp_ext::ShellRunnableArgs {
1595 environment,
1596 cwd: cwd.into(),
1597 program: program.to_string(),
1598 args: args.to_vec(),
1599 }),
1600 }),
1601 _ => None,
1602 },
1603 None => Some(lsp_ext::Runnable {
1604 label,
1605 location: Some(location),
1606 kind: lsp_ext::RunnableKind::Cargo,
1607 args: lsp_ext::RunnableArgs::Cargo(lsp_ext::CargoRunnableArgs {
1608 workspace_root: Some(workspace_root.into()),
1609 override_cargo: config.override_cargo,
1610 cargo_args,
1611 cwd: cwd.into(),
1612 executable_args,
1613 environment,
1614 }),
15941615 }),
1595 }))
1616 })
15961617 }
15971618 Some(TargetSpec::ProjectJson(spec)) => {
15981619 let label = runnable.label(Some(&spec.label));
src/tools/rust-analyzer/crates/rust-analyzer/src/main_loop.rs+14-3
......@@ -9,7 +9,7 @@ use std::{
99};
1010
1111use crossbeam_channel::{Receiver, never, select};
12use ide_db::base_db::{SourceDatabase, VfsPath, salsa::Database as _};
12use ide_db::base_db::{SourceDatabase, VfsPath};
1313use lsp_server::{Connection, Notification, Request};
1414use lsp_types::{TextDocumentIdentifier, notification::Notification as _};
1515use stdx::thread::ThreadIntent;
......@@ -383,7 +383,7 @@ impl GlobalState {
383383 ));
384384 }
385385 PrimeCachesProgress::End { cancelled } => {
386 self.analysis_host.raw_database_mut().trigger_lru_eviction();
386 self.analysis_host.trigger_garbage_collection();
387387 self.prime_caches_queue.op_completed(());
388388 if cancelled {
389389 self.prime_caches_queue
......@@ -535,6 +535,16 @@ impl GlobalState {
535535 if project_or_mem_docs_changed && self.config.test_explorer() {
536536 self.update_tests();
537537 }
538
539 let current_revision = self.analysis_host.raw_database().nonce_and_revision().1;
540 // no work is currently being done, now we can block a bit and clean up our garbage
541 if self.task_pool.handle.is_empty()
542 && self.fmt_pool.handle.is_empty()
543 && current_revision != self.last_gc_revision
544 {
545 self.analysis_host.trigger_garbage_collection();
546 self.last_gc_revision = current_revision;
547 }
538548 }
539549
540550 self.cleanup_discover_handles();
......@@ -907,7 +917,8 @@ impl GlobalState {
907917 // Not a lot of bad can happen from mistakenly identifying `minicore`, so proceed with that.
908918 self.minicore.minicore_text = contents
909919 .as_ref()
910 .and_then(|contents| String::from_utf8(contents.clone()).ok());
920 .and_then(|contents| str::from_utf8(contents).ok())
921 .map(triomphe::Arc::from);
911922 }
912923
913924 let path = VfsPath::from(path);
src/tools/rust-analyzer/crates/rust-analyzer/src/reload.rs+4-3
......@@ -13,7 +13,7 @@
1313//! project is currently loading and we don't have a full project model, we
1414//! still want to respond to various requests.
1515// FIXME: This is a mess that needs some untangling work
16use std::{iter, mem};
16use std::{iter, mem, sync::atomic::AtomicUsize};
1717
1818use hir::{ChangeWithProcMacros, ProcMacrosBuilder, db::DefDatabase};
1919use ide_db::{
......@@ -866,12 +866,13 @@ impl GlobalState {
866866 let invocation_strategy = config.invocation_strategy();
867867 let next_gen =
868868 self.flycheck.iter().map(FlycheckHandle::generation).max().unwrap_or_default() + 1;
869 let generation = Arc::new(AtomicUsize::new(next_gen));
869870
870871 self.flycheck = match invocation_strategy {
871872 crate::flycheck::InvocationStrategy::Once => {
872873 vec![FlycheckHandle::spawn(
873874 0,
874 next_gen,
875 generation.clone(),
875876 sender.clone(),
876877 config,
877878 None,
......@@ -915,7 +916,7 @@ impl GlobalState {
915916 .map(|(id, (root, manifest_path, target_dir), sysroot_root)| {
916917 FlycheckHandle::spawn(
917918 id,
918 next_gen,
919 generation.clone(),
919920 sender.clone(),
920921 config.clone(),
921922 sysroot_root,
src/tools/rust-analyzer/crates/rust-analyzer/src/target_spec.rs+55-6
......@@ -123,7 +123,7 @@ impl CargoTargetSpec {
123123
124124 match kind {
125125 RunnableKind::Test { test_id, attr } => {
126 cargo_args.push("test".to_owned());
126 cargo_args.push(config.test_command);
127127 executable_args.push(test_id.to_string());
128128 if let TestId::Path(_) = test_id {
129129 executable_args.push("--exact".to_owned());
......@@ -134,12 +134,12 @@ impl CargoTargetSpec {
134134 }
135135 }
136136 RunnableKind::TestMod { path } => {
137 cargo_args.push("test".to_owned());
137 cargo_args.push(config.test_command);
138138 executable_args.push(path.clone());
139139 executable_args.extend(extra_test_binary_args);
140140 }
141141 RunnableKind::Bench { test_id } => {
142 cargo_args.push("bench".to_owned());
142 cargo_args.push(config.bench_command);
143143 executable_args.push(test_id.to_string());
144144 if let TestId::Path(_) = test_id {
145145 executable_args.push("--exact".to_owned());
......@@ -154,10 +154,12 @@ impl CargoTargetSpec {
154154 }
155155 RunnableKind::Bin => {
156156 let subcommand = match spec {
157 Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => "test",
158 _ => "run",
157 Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => {
158 config.test_command
159 }
160 _ => "run".to_owned(),
159161 };
160 cargo_args.push(subcommand.to_owned());
162 cargo_args.push(subcommand);
161163 }
162164 }
163165
......@@ -206,6 +208,53 @@ impl CargoTargetSpec {
206208 (cargo_args, executable_args)
207209 }
208210
211 pub(crate) fn override_command(
212 snap: &GlobalStateSnapshot,
213 spec: Option<CargoTargetSpec>,
214 kind: &RunnableKind,
215 ) -> Option<Vec<String>> {
216 let config = snap.config.runnables(None);
217 let (args, test_name) = match kind {
218 RunnableKind::Test { test_id, .. } => {
219 (config.test_override_command, Some(test_id.to_string()))
220 }
221 RunnableKind::TestMod { path } => (config.test_override_command, Some(path.clone())),
222 RunnableKind::Bench { test_id } => {
223 (config.bench_override_command, Some(test_id.to_string()))
224 }
225 RunnableKind::DocTest { test_id } => {
226 (config.doc_test_override_command, Some(test_id.to_string()))
227 }
228 RunnableKind::Bin => match spec {
229 Some(CargoTargetSpec { target_kind: TargetKind::Test, .. }) => {
230 (config.test_override_command, None)
231 }
232 _ => (None, None),
233 },
234 };
235 let test_name = test_name.unwrap_or_default();
236
237 let target_arg = |kind| match kind {
238 TargetKind::Bin => "--bin",
239 TargetKind::Test => "--test",
240 TargetKind::Bench => "--bench",
241 TargetKind::Example => "--example",
242 TargetKind::Lib { .. } => "--lib",
243 TargetKind::BuildScript | TargetKind::Other => "",
244 };
245
246 let replace_placeholders = |arg: String| match &spec {
247 Some(spec) => arg
248 .replace("${package}", &spec.package)
249 .replace("${target_arg}", target_arg(spec.target_kind))
250 .replace("${target}", &spec.target)
251 .replace("${test_name}", &test_name),
252 _ => arg,
253 };
254
255 args.map(|args| args.into_iter().map(replace_placeholders).collect())
256 }
257
209258 pub(crate) fn push_to(self, buf: &mut Vec<String>, kind: &RunnableKind) {
210259 buf.push("--package".to_owned());
211260 buf.push(self.package);
src/tools/rust-analyzer/crates/rust-analyzer/src/task_pool.rs+4
......@@ -43,6 +43,10 @@ impl<T> TaskPool<T> {
4343 pub(crate) fn len(&self) -> usize {
4444 self.pool.len()
4545 }
46
47 pub(crate) fn is_empty(&self) -> bool {
48 self.pool.is_empty()
49 }
4650}
4751
4852/// `DeferredTaskQueue` holds deferred tasks.
src/tools/rust-analyzer/crates/span/src/ast_id.rs+45-2
......@@ -603,8 +603,9 @@ impl AstIdMap {
603603 // After all, the block will then contain the *outer* item, so we allocate
604604 // an ID for it anyway.
605605 let mut blocks = Vec::new();
606 let mut curr_layer = vec![(node.clone(), None)];
607 let mut next_layer = vec![];
606 let mut curr_layer = Vec::with_capacity(32);
607 curr_layer.push((node.clone(), None));
608 let mut next_layer = Vec::with_capacity(32);
608609 while !curr_layer.is_empty() {
609610 curr_layer.drain(..).for_each(|(node, parent_idx)| {
610611 let mut preorder = node.preorder();
......@@ -776,6 +777,48 @@ impl AstIdMap {
776777 }
777778}
778779
780#[cfg(not(no_salsa_async_drops))]
781impl Drop for AstIdMap {
782 fn drop(&mut self) {
783 let arena = std::mem::take(&mut self.arena);
784 let ptr_map = std::mem::take(&mut self.ptr_map);
785 let id_map = std::mem::take(&mut self.id_map);
786 static AST_ID_MAP_DROP_THREAD: std::sync::OnceLock<
787 std::sync::mpsc::Sender<(
788 Arena<(SyntaxNodePtr, ErasedFileAstId)>,
789 hashbrown::HashTable<ArenaId>,
790 hashbrown::HashTable<ArenaId>,
791 )>,
792 > = std::sync::OnceLock::new();
793 AST_ID_MAP_DROP_THREAD
794 .get_or_init(|| {
795 let (sender, receiver) = std::sync::mpsc::channel::<(
796 Arena<(SyntaxNodePtr, ErasedFileAstId)>,
797 hashbrown::HashTable<ArenaId>,
798 hashbrown::HashTable<ArenaId>,
799 )>();
800 std::thread::Builder::new()
801 .name("AstIdMapDropper".to_owned())
802 .spawn(move || {
803 loop {
804 // block on a receive
805 _ = receiver.recv();
806 // then drain the entire channel
807 while receiver.try_recv().is_ok() {}
808 // and sleep for a bit
809 std::thread::sleep(std::time::Duration::from_millis(100));
810 }
811 // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock.
812 // otherwise this thread will constantly wake up and sleep again.
813 })
814 .unwrap();
815 sender
816 })
817 .send((arena, ptr_map, id_map))
818 .unwrap();
819 }
820}
821
779822#[inline]
780823fn hash_ptr(ptr: &SyntaxNodePtr) -> u64 {
781824 FxBuildHasher.hash_one(ptr)
src/tools/rust-analyzer/crates/span/src/lib.rs+7-11
......@@ -24,8 +24,6 @@ pub use syntax::Edition;
2424pub use text_size::{TextRange, TextSize};
2525pub use vfs::FileId;
2626
27pub type Span = SpanData<SyntaxContext>;
28
2927impl Span {
3028 pub fn cover(self, other: Span) -> Span {
3129 if self.anchor != other.anchor {
......@@ -61,13 +59,17 @@ impl Span {
6159 }
6260 Some(Span { range: self.range.cover(other.range), anchor: other.anchor, ctx: other.ctx })
6361 }
62
63 pub fn eq_ignoring_ctx(self, other: Self) -> bool {
64 self.anchor == other.anchor && self.range == other.range
65 }
6466}
6567
6668/// Spans represent a region of code, used by the IDE to be able link macro inputs and outputs
6769/// together. Positions in spans are relative to some [`SpanAnchor`] to make them more incremental
6870/// friendly.
6971#[derive(Clone, Copy, PartialEq, Eq, Hash)]
70pub struct SpanData<Ctx> {
72pub struct Span {
7173 /// The text range of this span, relative to the anchor.
7274 /// We need the anchor for incrementality, as storing absolute ranges will require
7375 /// recomputation on every change in a file at all times.
......@@ -75,10 +77,10 @@ pub struct SpanData<Ctx> {
7577 /// The anchor this span is relative to.
7678 pub anchor: SpanAnchor,
7779 /// The syntax context of the span.
78 pub ctx: Ctx,
80 pub ctx: SyntaxContext,
7981}
8082
81impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
83impl fmt::Debug for Span {
8284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
8385 if f.alternate() {
8486 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
......@@ -98,12 +100,6 @@ impl<Ctx: fmt::Debug> fmt::Debug for SpanData<Ctx> {
98100 }
99101}
100102
101impl<Ctx: Copy> SpanData<Ctx> {
102 pub fn eq_ignoring_ctx(self, other: Self) -> bool {
103 self.anchor == other.anchor && self.range == other.range
104 }
105}
106
107103impl fmt::Display for Span {
108104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109105 fmt::Debug::fmt(&self.anchor.file_id.file_id().index(), f)?;
src/tools/rust-analyzer/crates/span/src/map.rs+34-45
......@@ -6,24 +6,21 @@ use std::{fmt, hash::Hash};
66use stdx::{always, itertools::Itertools};
77
88use crate::{
9 EditionedFileId, ErasedFileAstId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SpanData,
10 SyntaxContext, TextRange, TextSize,
9 EditionedFileId, ErasedFileAstId, ROOT_ERASED_FILE_AST_ID, Span, SpanAnchor, SyntaxContext,
10 TextRange, TextSize,
1111};
1212
1313/// Maps absolute text ranges for the corresponding file to the relevant span data.
1414#[derive(Debug, PartialEq, Eq, Clone, Hash)]
15pub struct SpanMap<S> {
15pub struct SpanMap {
1616 /// The offset stored here is the *end* of the node.
17 spans: Vec<(TextSize, SpanData<S>)>,
17 spans: Vec<(TextSize, Span)>,
1818 /// Index of the matched macro arm on successful expansion for declarative macros.
1919 // FIXME: Does it make sense to have this here?
2020 pub matched_arm: Option<u32>,
2121}
2222
23impl<S> SpanMap<S>
24where
25 SpanData<S>: Copy,
26{
23impl SpanMap {
2724 /// Creates a new empty [`SpanMap`].
2825 pub fn empty() -> Self {
2926 Self { spans: Vec::new(), matched_arm: None }
......@@ -40,7 +37,7 @@ where
4037 }
4138
4239 /// Pushes a new span onto the [`SpanMap`].
43 pub fn push(&mut self, offset: TextSize, span: SpanData<S>) {
40 pub fn push(&mut self, offset: TextSize, span: Span) {
4441 if cfg!(debug_assertions)
4542 && let Some(&(last_offset, _)) = self.spans.last()
4643 {
......@@ -57,11 +54,8 @@ where
5754 /// Note this does a linear search through the entire backing vector.
5855 pub fn ranges_with_span_exact(
5956 &self,
60 span: SpanData<S>,
61 ) -> impl Iterator<Item = (TextRange, S)> + '_
62 where
63 S: Copy,
64 {
57 span: Span,
58 ) -> impl Iterator<Item = (TextRange, SyntaxContext)> + '_ {
6559 self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
6660 if !s.eq_ignoring_ctx(span) {
6761 return None;
......@@ -74,10 +68,10 @@ where
7468 /// Returns all [`TextRange`]s whose spans contain the given span.
7569 ///
7670 /// Note this does a linear search through the entire backing vector.
77 pub fn ranges_with_span(&self, span: SpanData<S>) -> impl Iterator<Item = (TextRange, S)> + '_
78 where
79 S: Copy,
80 {
71 pub fn ranges_with_span(
72 &self,
73 span: Span,
74 ) -> impl Iterator<Item = (TextRange, SyntaxContext)> + '_ {
8175 self.spans.iter().enumerate().filter_map(move |(idx, &(end, s))| {
8276 if s.anchor != span.anchor {
8377 return None;
......@@ -91,28 +85,28 @@ where
9185 }
9286
9387 /// Returns the span at the given position.
94 pub fn span_at(&self, offset: TextSize) -> SpanData<S> {
88 pub fn span_at(&self, offset: TextSize) -> Span {
9589 let entry = self.spans.partition_point(|&(it, _)| it <= offset);
9690 self.spans[entry].1
9791 }
9892
9993 /// Returns the spans associated with the given range.
10094 /// In other words, this will return all spans that correspond to all offsets within the given range.
101 pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = SpanData<S>> + '_ {
95 pub fn spans_for_range(&self, range: TextRange) -> impl Iterator<Item = Span> + '_ {
10296 let (start, end) = (range.start(), range.end());
10397 let start_entry = self.spans.partition_point(|&(it, _)| it <= start);
10498 let end_entry = self.spans[start_entry..].partition_point(|&(it, _)| it <= end); // FIXME: this might be wrong?
10599 self.spans[start_entry..][..end_entry].iter().map(|&(_, s)| s)
106100 }
107101
108 pub fn iter(&self) -> impl Iterator<Item = (TextSize, SpanData<S>)> + '_ {
102 pub fn iter(&self) -> impl Iterator<Item = (TextSize, Span)> + '_ {
109103 self.spans.iter().copied()
110104 }
111105
112106 /// Merges this span map with another span map, where `other` is inserted at (and replaces) `other_range`.
113107 ///
114108 /// The length of the replacement node needs to be `other_size`.
115 pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap<S>) {
109 pub fn merge(&mut self, other_range: TextRange, other_size: TextSize, other: &SpanMap) {
116110 // I find the following diagram helpful to illustrate the bounds and why we use `<` or `<=`:
117111 // --------------------------------------------------------------------
118112 // 1 3 5 6 7 10 11 <-- offsets we store
......@@ -157,39 +151,34 @@ where
157151}
158152
159153#[cfg(not(no_salsa_async_drops))]
160impl<S> Drop for SpanMap<S> {
154impl Drop for SpanMap {
161155 fn drop(&mut self) {
162 struct SendPtr(*mut [()]);
163 unsafe impl Send for SendPtr {}
156 let spans = std::mem::take(&mut self.spans);
164157 static SPAN_MAP_DROP_THREAD: std::sync::OnceLock<
165 std::sync::mpsc::Sender<(SendPtr, fn(SendPtr))>,
158 std::sync::mpsc::Sender<Vec<(TextSize, Span)>>,
166159 > = std::sync::OnceLock::new();
160
167161 SPAN_MAP_DROP_THREAD
168162 .get_or_init(|| {
169 let (sender, receiver) = std::sync::mpsc::channel::<(SendPtr, fn(SendPtr))>();
163 let (sender, receiver) = std::sync::mpsc::channel::<Vec<(TextSize, Span)>>();
170164 std::thread::Builder::new()
171165 .name("SpanMapDropper".to_owned())
172 .spawn(move || receiver.iter().for_each(|(b, drop)| drop(b)))
166 .spawn(move || {
167 loop {
168 // block on a receive
169 _ = receiver.recv();
170 // then drain the entire channel
171 while receiver.try_recv().is_ok() {}
172 // and sleep for a bit
173 std::thread::sleep(std::time::Duration::from_millis(100));
174 }
175 // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock.
176 // otherwise this thread will constantly wake up and sleep again.
177 })
173178 .unwrap();
174179 sender
175180 })
176 .send((
177 unsafe {
178 SendPtr(std::mem::transmute::<*mut [(TextSize, SpanData<S>)], *mut [()]>(
179 Box::<[(TextSize, SpanData<S>)]>::into_raw(
180 std::mem::take(&mut self.spans).into_boxed_slice(),
181 ),
182 ))
183 },
184 |b: SendPtr| {
185 _ = unsafe {
186 Box::from_raw(std::mem::transmute::<
187 *mut [()],
188 *mut [(TextSize, SpanData<S>)],
189 >(b.0))
190 }
191 },
192 ))
181 .send(spans)
193182 .unwrap();
194183 }
195184}
src/tools/rust-analyzer/crates/stdx/src/lib.rs+14
......@@ -76,6 +76,20 @@ impl<T, U, V> TupleExt for (T, U, V) {
7676 }
7777}
7878
79impl<T> TupleExt for &T
80where
81 T: TupleExt + Copy,
82{
83 type Head = T::Head;
84 type Tail = T::Tail;
85 fn head(self) -> Self::Head {
86 (*self).head()
87 }
88 fn tail(self) -> Self::Tail {
89 (*self).tail()
90 }
91}
92
7993pub fn to_lower_snake_case(s: &str) -> String {
8094 to_snake_case(s, char::to_lowercase)
8195}
src/tools/rust-analyzer/crates/stdx/src/thread/pool.rs+2-1
......@@ -66,7 +66,6 @@ impl Pool {
6666 job.requested_intent.apply_to_current_thread();
6767 current_intent = job.requested_intent;
6868 }
69 extant_tasks.fetch_add(1, Ordering::SeqCst);
7069 // discard the panic, we should've logged the backtrace already
7170 drop(panic::catch_unwind(job.f));
7271 extant_tasks.fetch_sub(1, Ordering::SeqCst);
......@@ -93,6 +92,7 @@ impl Pool {
9392 });
9493
9594 let job = Job { requested_intent: intent, f };
95 self.extant_tasks.fetch_add(1, Ordering::SeqCst);
9696 self.job_sender.send(job).unwrap();
9797 }
9898
......@@ -147,6 +147,7 @@ impl<'scope> Scope<'_, 'scope> {
147147 >(f)
148148 },
149149 };
150 self.pool.extant_tasks.fetch_add(1, Ordering::SeqCst);
150151 self.pool.job_sender.send(job).unwrap();
151152 }
152153}
src/tools/rust-analyzer/crates/syntax-bridge/src/lib.rs+118-154
......@@ -9,7 +9,7 @@ use std::{collections::VecDeque, fmt, hash::Hash};
99
1010use intern::Symbol;
1111use rustc_hash::{FxHashMap, FxHashSet};
12use span::{Edition, SpanAnchor, SpanData, SpanMap};
12use span::{Edition, Span, SpanAnchor, SpanMap, SyntaxContext};
1313use stdx::{format_to, never};
1414use syntax::{
1515 AstToken, Parse, PreorderWithTokens, SmolStr, SyntaxElement,
......@@ -29,21 +29,18 @@ pub use ::parser::TopEntryPoint;
2929#[cfg(test)]
3030mod tests;
3131
32pub trait SpanMapper<S> {
33 fn span_for(&self, range: TextRange) -> S;
32pub trait SpanMapper {
33 fn span_for(&self, range: TextRange) -> Span;
3434}
3535
36impl<S> SpanMapper<SpanData<S>> for SpanMap<S>
37where
38 SpanData<S>: Copy,
39{
40 fn span_for(&self, range: TextRange) -> SpanData<S> {
36impl SpanMapper for SpanMap {
37 fn span_for(&self, range: TextRange) -> Span {
4138 self.span_at(range.start())
4239 }
4340}
4441
45impl<S: Copy, SM: SpanMapper<S>> SpanMapper<S> for &SM {
46 fn span_for(&self, range: TextRange) -> S {
42impl<SM: SpanMapper> SpanMapper for &SM {
43 fn span_for(&self, range: TextRange) -> Span {
4744 SM::span_for(self, range)
4845 }
4946}
......@@ -69,7 +66,7 @@ pub mod dummy_test_span_utils {
6966
7067 pub struct DummyTestSpanMap;
7168
72 impl SpanMapper<Span> for DummyTestSpanMap {
69 impl SpanMapper for DummyTestSpanMap {
7370 fn span_for(&self, range: syntax::TextRange) -> Span {
7471 Span {
7572 range,
......@@ -97,15 +94,14 @@ pub enum DocCommentDesugarMode {
9794
9895/// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
9996/// subtree's spans.
100pub fn syntax_node_to_token_tree<Ctx, SpanMap>(
97pub fn syntax_node_to_token_tree<SpanMap>(
10198 node: &SyntaxNode,
10299 map: SpanMap,
103 span: SpanData<Ctx>,
100 span: Span,
104101 mode: DocCommentDesugarMode,
105) -> tt::TopSubtree<SpanData<Ctx>>
102) -> tt::TopSubtree
106103where
107 SpanData<Ctx>: Copy + fmt::Debug,
108 SpanMap: SpanMapper<SpanData<Ctx>>,
104 SpanMap: SpanMapper,
109105{
110106 let mut c =
111107 Converter::new(node, map, Default::default(), Default::default(), span, mode, |_, _| {
......@@ -117,22 +113,18 @@ where
117113/// Converts a syntax tree to a [`tt::Subtree`] using the provided span map to populate the
118114/// subtree's spans. Additionally using the append and remove parameters, the additional tokens can
119115/// be injected or hidden from the output.
120pub fn syntax_node_to_token_tree_modified<Ctx, SpanMap, OnEvent>(
116pub fn syntax_node_to_token_tree_modified<SpanMap, OnEvent>(
121117 node: &SyntaxNode,
122118 map: SpanMap,
123 append: FxHashMap<SyntaxElement, Vec<tt::Leaf<SpanData<Ctx>>>>,
119 append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
124120 remove: FxHashSet<SyntaxElement>,
125 call_site: SpanData<Ctx>,
121 call_site: Span,
126122 mode: DocCommentDesugarMode,
127123 on_enter: OnEvent,
128) -> tt::TopSubtree<SpanData<Ctx>>
124) -> tt::TopSubtree
129125where
130 SpanMap: SpanMapper<SpanData<Ctx>>,
131 SpanData<Ctx>: Copy + fmt::Debug,
132 OnEvent: FnMut(
133 &mut PreorderWithTokens,
134 &WalkEvent<SyntaxElement>,
135 ) -> (bool, Vec<tt::Leaf<SpanData<Ctx>>>),
126 SpanMap: SpanMapper,
127 OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
136128{
137129 let mut c = Converter::new(node, map, append, remove, call_site, mode, on_enter);
138130 convert_tokens(&mut c)
......@@ -152,13 +144,13 @@ where
152144
153145/// Converts a [`tt::Subtree`] back to a [`SyntaxNode`].
154146/// The produced `SpanMap` contains a mapping from the syntax nodes offsets to the subtree's spans.
155pub fn token_tree_to_syntax_node<Ctx>(
156 tt: &tt::TopSubtree<SpanData<Ctx>>,
147pub fn token_tree_to_syntax_node(
148 tt: &tt::TopSubtree,
157149 entry_point: parser::TopEntryPoint,
158 span_to_edition: &mut dyn FnMut(Ctx) -> Edition,
159) -> (Parse<SyntaxNode>, SpanMap<Ctx>)
150 span_to_edition: &mut dyn FnMut(SyntaxContext) -> Edition,
151) -> (Parse<SyntaxNode>, SpanMap)
160152where
161 Ctx: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash,
153 SyntaxContext: Copy + fmt::Debug + PartialEq + PartialEq + Eq + Hash,
162154{
163155 let buffer = tt.view().strip_invisible();
164156 let parser_input = to_parser_input(buffer, span_to_edition);
......@@ -183,16 +175,12 @@ where
183175
184176/// Convert a string to a `TokenTree`. The spans of the subtree will be anchored to the provided
185177/// anchor with the given context.
186pub fn parse_to_token_tree<Ctx>(
178pub fn parse_to_token_tree(
187179 edition: Edition,
188180 anchor: SpanAnchor,
189 ctx: Ctx,
181 ctx: SyntaxContext,
190182 text: &str,
191) -> Option<tt::TopSubtree<SpanData<Ctx>>>
192where
193 SpanData<Ctx>: Copy + fmt::Debug,
194 Ctx: Copy,
195{
183) -> Option<tt::TopSubtree> {
196184 let lexed = parser::LexedStr::new(edition, text);
197185 if lexed.errors().next().is_some() {
198186 return None;
......@@ -203,14 +191,11 @@ where
203191}
204192
205193/// Convert a string to a `TokenTree`. The passed span will be used for all spans of the produced subtree.
206pub fn parse_to_token_tree_static_span<S>(
194pub fn parse_to_token_tree_static_span(
207195 edition: Edition,
208 span: S,
196 span: Span,
209197 text: &str,
210) -> Option<tt::TopSubtree<S>>
211where
212 S: Copy + fmt::Debug,
213{
198) -> Option<tt::TopSubtree> {
214199 let lexed = parser::LexedStr::new(edition, text);
215200 if lexed.errors().next().is_some() {
216201 return None;
......@@ -220,10 +205,9 @@ where
220205 Some(convert_tokens(&mut conv))
221206}
222207
223fn convert_tokens<S, C>(conv: &mut C) -> tt::TopSubtree<S>
208fn convert_tokens<C>(conv: &mut C) -> tt::TopSubtree
224209where
225 C: TokenConverter<S>,
226 S: Copy + fmt::Debug,
210 C: TokenConverter,
227211 C::Token: fmt::Debug,
228212{
229213 let mut builder =
......@@ -239,7 +223,7 @@ where
239223 spacing: _,
240224 })) => {
241225 let found_expected_delimiter =
242 builder.expected_delimiters().enumerate().find(|(_, delim)| match delim.kind {
226 builder.expected_delimiters().enumerate().find(|(_, delim)| match delim {
243227 tt::DelimiterKind::Parenthesis => char == ')',
244228 tt::DelimiterKind::Brace => char == '}',
245229 tt::DelimiterKind::Bracket => char == ']',
......@@ -273,13 +257,11 @@ where
273257 }
274258 kind if kind.is_punct() && kind != UNDERSCORE => {
275259 let found_expected_delimiter =
276 builder.expected_delimiters().enumerate().find(|(_, delim)| {
277 match delim.kind {
278 tt::DelimiterKind::Parenthesis => kind == T![')'],
279 tt::DelimiterKind::Brace => kind == T!['}'],
280 tt::DelimiterKind::Bracket => kind == T![']'],
281 tt::DelimiterKind::Invisible => false,
282 }
260 builder.expected_delimiters().enumerate().find(|(_, delim)| match delim {
261 tt::DelimiterKind::Parenthesis => kind == T![')'],
262 tt::DelimiterKind::Brace => kind == T!['}'],
263 tt::DelimiterKind::Bracket => kind == T![']'],
264 tt::DelimiterKind::Invisible => false,
283265 });
284266
285267 // Current token is a closing delimiter that we expect, fix up the closing span
......@@ -327,7 +309,7 @@ where
327309 .into()
328310 };
329311 }
330 let leaf: tt::Leaf<_> = match kind {
312 let leaf: tt::Leaf = match kind {
331313 k if k.is_any_identifier() => {
332314 let text = token.to_text(conv);
333315 tt::Ident::new(&text, conv.span_for(abs_range)).into()
......@@ -435,11 +417,11 @@ pub fn desugar_doc_comment_text(text: &str, mode: DocCommentDesugarMode) -> (Sym
435417 }
436418}
437419
438fn convert_doc_comment<S: Copy>(
420fn convert_doc_comment(
439421 token: &syntax::SyntaxToken,
440 span: S,
422 span: Span,
441423 mode: DocCommentDesugarMode,
442 builder: &mut tt::TopSubtreeBuilder<S>,
424 builder: &mut tt::TopSubtreeBuilder,
443425) {
444426 let Some(comment) = ast::Comment::cast(token.clone()) else { return };
445427 let Some(doc) = comment.kind().doc else { return };
......@@ -460,7 +442,7 @@ fn convert_doc_comment<S: Copy>(
460442 text = &text[0..text.len() - 2];
461443 }
462444 let (text, kind) = desugar_doc_comment_text(text, mode);
463 let lit = tt::Literal { symbol: text, span, kind, suffix: None };
445 let lit = tt::Literal { text_and_suffix: text, span, kind, suffix_len: 0 };
464446
465447 tt::Leaf::from(lit)
466448 };
......@@ -479,92 +461,84 @@ fn convert_doc_comment<S: Copy>(
479461}
480462
481463/// A raw token (straight from lexer) converter
482struct RawConverter<'a, Ctx> {
464struct RawConverter<'a> {
483465 lexed: parser::LexedStr<'a>,
484466 pos: usize,
485467 anchor: SpanAnchor,
486 ctx: Ctx,
468 ctx: SyntaxContext,
487469 mode: DocCommentDesugarMode,
488470}
489471/// A raw token (straight from lexer) converter that gives every token the same span.
490struct StaticRawConverter<'a, S> {
472struct StaticRawConverter<'a> {
491473 lexed: parser::LexedStr<'a>,
492474 pos: usize,
493 span: S,
475 span: Span,
494476 mode: DocCommentDesugarMode,
495477}
496478
497trait SrcToken<Ctx, S> {
479trait SrcToken<Ctx> {
498480 fn kind(&self, ctx: &Ctx) -> SyntaxKind;
499481
500482 fn to_char(&self, ctx: &Ctx) -> Option<char>;
501483
502484 fn to_text(&self, ctx: &Ctx) -> SmolStr;
503485
504 fn as_leaf(&self) -> Option<&tt::Leaf<S>> {
486 fn as_leaf(&self) -> Option<&tt::Leaf> {
505487 None
506488 }
507489}
508490
509trait TokenConverter<S>: Sized {
510 type Token: SrcToken<Self, S>;
491trait TokenConverter: Sized {
492 type Token: SrcToken<Self>;
511493
512494 fn convert_doc_comment(
513495 &self,
514496 token: &Self::Token,
515 span: S,
516 builder: &mut tt::TopSubtreeBuilder<S>,
497 span: Span,
498 builder: &mut tt::TopSubtreeBuilder,
517499 );
518500
519501 fn bump(&mut self) -> Option<(Self::Token, TextRange)>;
520502
521503 fn peek(&self) -> Option<Self::Token>;
522504
523 fn span_for(&self, range: TextRange) -> S;
505 fn span_for(&self, range: TextRange) -> Span;
524506
525 fn call_site(&self) -> S;
507 fn call_site(&self) -> Span;
526508}
527509
528impl<S, Ctx> SrcToken<RawConverter<'_, Ctx>, S> for usize {
529 fn kind(&self, ctx: &RawConverter<'_, Ctx>) -> SyntaxKind {
510impl SrcToken<RawConverter<'_>> for usize {
511 fn kind(&self, ctx: &RawConverter<'_>) -> SyntaxKind {
530512 ctx.lexed.kind(*self)
531513 }
532514
533 fn to_char(&self, ctx: &RawConverter<'_, Ctx>) -> Option<char> {
515 fn to_char(&self, ctx: &RawConverter<'_>) -> Option<char> {
534516 ctx.lexed.text(*self).chars().next()
535517 }
536518
537 fn to_text(&self, ctx: &RawConverter<'_, Ctx>) -> SmolStr {
519 fn to_text(&self, ctx: &RawConverter<'_>) -> SmolStr {
538520 ctx.lexed.text(*self).into()
539521 }
540522}
541523
542impl<S: Copy> SrcToken<StaticRawConverter<'_, S>, S> for usize {
543 fn kind(&self, ctx: &StaticRawConverter<'_, S>) -> SyntaxKind {
524impl SrcToken<StaticRawConverter<'_>> for usize {
525 fn kind(&self, ctx: &StaticRawConverter<'_>) -> SyntaxKind {
544526 ctx.lexed.kind(*self)
545527 }
546528
547 fn to_char(&self, ctx: &StaticRawConverter<'_, S>) -> Option<char> {
529 fn to_char(&self, ctx: &StaticRawConverter<'_>) -> Option<char> {
548530 ctx.lexed.text(*self).chars().next()
549531 }
550532
551 fn to_text(&self, ctx: &StaticRawConverter<'_, S>) -> SmolStr {
533 fn to_text(&self, ctx: &StaticRawConverter<'_>) -> SmolStr {
552534 ctx.lexed.text(*self).into()
553535 }
554536}
555537
556impl<Ctx: Copy> TokenConverter<SpanData<Ctx>> for RawConverter<'_, Ctx>
557where
558 SpanData<Ctx>: Copy,
559{
538impl TokenConverter for RawConverter<'_> {
560539 type Token = usize;
561540
562 fn convert_doc_comment(
563 &self,
564 &token: &usize,
565 span: SpanData<Ctx>,
566 builder: &mut tt::TopSubtreeBuilder<SpanData<Ctx>>,
567 ) {
541 fn convert_doc_comment(&self, &token: &usize, span: Span, builder: &mut tt::TopSubtreeBuilder) {
568542 let text = self.lexed.text(token);
569543 convert_doc_comment(&doc_comment(text), span, self.mode, builder);
570544 }
......@@ -588,22 +562,19 @@ where
588562 Some(self.pos)
589563 }
590564
591 fn span_for(&self, range: TextRange) -> SpanData<Ctx> {
592 SpanData { range, anchor: self.anchor, ctx: self.ctx }
565 fn span_for(&self, range: TextRange) -> Span {
566 Span { range, anchor: self.anchor, ctx: self.ctx }
593567 }
594568
595 fn call_site(&self) -> SpanData<Ctx> {
596 SpanData { range: TextRange::empty(0.into()), anchor: self.anchor, ctx: self.ctx }
569 fn call_site(&self) -> Span {
570 Span { range: TextRange::empty(0.into()), anchor: self.anchor, ctx: self.ctx }
597571 }
598572}
599573
600impl<S> TokenConverter<S> for StaticRawConverter<'_, S>
601where
602 S: Copy,
603{
574impl TokenConverter for StaticRawConverter<'_> {
604575 type Token = usize;
605576
606 fn convert_doc_comment(&self, &token: &usize, span: S, builder: &mut tt::TopSubtreeBuilder<S>) {
577 fn convert_doc_comment(&self, &token: &usize, span: Span, builder: &mut tt::TopSubtreeBuilder) {
607578 let text = self.lexed.text(token);
608579 convert_doc_comment(&doc_comment(text), span, self.mode, builder);
609580 }
......@@ -627,40 +598,40 @@ where
627598 Some(self.pos)
628599 }
629600
630 fn span_for(&self, _: TextRange) -> S {
601 fn span_for(&self, _: TextRange) -> Span {
631602 self.span
632603 }
633604
634 fn call_site(&self) -> S {
605 fn call_site(&self) -> Span {
635606 self.span
636607 }
637608}
638609
639struct Converter<SpanMap, S, OnEvent> {
610struct Converter<SpanMap, OnEvent> {
640611 current: Option<SyntaxToken>,
641 current_leaves: VecDeque<tt::Leaf<S>>,
612 current_leaves: VecDeque<tt::Leaf>,
642613 preorder: PreorderWithTokens,
643614 range: TextRange,
644615 punct_offset: Option<(SyntaxToken, TextSize)>,
645616 /// Used to make the emitted text ranges in the spans relative to the span anchor.
646617 map: SpanMap,
647 append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
618 append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
648619 remove: FxHashSet<SyntaxElement>,
649 call_site: S,
620 call_site: Span,
650621 mode: DocCommentDesugarMode,
651622 on_event: OnEvent,
652623}
653624
654impl<SpanMap, S, OnEvent> Converter<SpanMap, S, OnEvent>
625impl<SpanMap, OnEvent> Converter<SpanMap, OnEvent>
655626where
656 OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf<S>>),
627 OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
657628{
658629 fn new(
659630 node: &SyntaxNode,
660631 map: SpanMap,
661 append: FxHashMap<SyntaxElement, Vec<tt::Leaf<S>>>,
632 append: FxHashMap<SyntaxElement, Vec<tt::Leaf>>,
662633 remove: FxHashSet<SyntaxElement>,
663 call_site: S,
634 call_site: Span,
664635 mode: DocCommentDesugarMode,
665636 on_enter: OnEvent,
666637 ) -> Self {
......@@ -720,13 +691,13 @@ where
720691}
721692
722693#[derive(Debug)]
723enum SynToken<S> {
694enum SynToken {
724695 Ordinary(SyntaxToken),
725696 Punct { token: SyntaxToken, offset: usize },
726 Leaf(tt::Leaf<S>),
697 Leaf(tt::Leaf),
727698}
728699
729impl<S> SynToken<S> {
700impl SynToken {
730701 fn token(&self) -> &SyntaxToken {
731702 match self {
732703 SynToken::Ordinary(it) | SynToken::Punct { token: it, offset: _ } => it,
......@@ -735,8 +706,8 @@ impl<S> SynToken<S> {
735706 }
736707}
737708
738impl<SpanMap, S, OnEvent> SrcToken<Converter<SpanMap, S, OnEvent>, S> for SynToken<S> {
739 fn kind(&self, _ctx: &Converter<SpanMap, S, OnEvent>) -> SyntaxKind {
709impl<SpanMap, OnEvent> SrcToken<Converter<SpanMap, OnEvent>> for SynToken {
710 fn kind(&self, _ctx: &Converter<SpanMap, OnEvent>) -> SyntaxKind {
740711 match self {
741712 SynToken::Ordinary(token) => token.kind(),
742713 SynToken::Punct { token, offset: i } => {
......@@ -748,14 +719,14 @@ impl<SpanMap, S, OnEvent> SrcToken<Converter<SpanMap, S, OnEvent>, S> for SynTok
748719 }
749720 }
750721 }
751 fn to_char(&self, _ctx: &Converter<SpanMap, S, OnEvent>) -> Option<char> {
722 fn to_char(&self, _ctx: &Converter<SpanMap, OnEvent>) -> Option<char> {
752723 match self {
753724 SynToken::Ordinary(_) => None,
754725 SynToken::Punct { token: it, offset: i } => it.text().chars().nth(*i),
755726 SynToken::Leaf(_) => None,
756727 }
757728 }
758 fn to_text(&self, _ctx: &Converter<SpanMap, S, OnEvent>) -> SmolStr {
729 fn to_text(&self, _ctx: &Converter<SpanMap, OnEvent>) -> SmolStr {
759730 match self {
760731 SynToken::Ordinary(token) | SynToken::Punct { token, offset: _ } => token.text().into(),
761732 SynToken::Leaf(_) => {
......@@ -764,7 +735,7 @@ impl<SpanMap, S, OnEvent> SrcToken<Converter<SpanMap, S, OnEvent>, S> for SynTok
764735 }
765736 }
766737 }
767 fn as_leaf(&self) -> Option<&tt::Leaf<S>> {
738 fn as_leaf(&self) -> Option<&tt::Leaf> {
768739 match self {
769740 SynToken::Ordinary(_) | SynToken::Punct { .. } => None,
770741 SynToken::Leaf(it) => Some(it),
......@@ -772,18 +743,17 @@ impl<SpanMap, S, OnEvent> SrcToken<Converter<SpanMap, S, OnEvent>, S> for SynTok
772743 }
773744}
774745
775impl<S, SpanMap, OnEvent> TokenConverter<S> for Converter<SpanMap, S, OnEvent>
746impl<SpanMap, OnEvent> TokenConverter for Converter<SpanMap, OnEvent>
776747where
777 S: Copy,
778 SpanMap: SpanMapper<S>,
779 OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf<S>>),
748 SpanMap: SpanMapper,
749 OnEvent: FnMut(&mut PreorderWithTokens, &WalkEvent<SyntaxElement>) -> (bool, Vec<tt::Leaf>),
780750{
781 type Token = SynToken<S>;
751 type Token = SynToken;
782752 fn convert_doc_comment(
783753 &self,
784754 token: &Self::Token,
785 span: S,
786 builder: &mut tt::TopSubtreeBuilder<S>,
755 span: Span,
756 builder: &mut tt::TopSubtreeBuilder,
787757 ) {
788758 convert_doc_comment(token.token(), span, self.mode, builder);
789759 }
......@@ -847,30 +817,24 @@ where
847817 Some(token)
848818 }
849819
850 fn span_for(&self, range: TextRange) -> S {
820 fn span_for(&self, range: TextRange) -> Span {
851821 self.map.span_for(range)
852822 }
853 fn call_site(&self) -> S {
823 fn call_site(&self) -> Span {
854824 self.call_site
855825 }
856826}
857827
858struct TtTreeSink<'a, Ctx>
859where
860 SpanData<Ctx>: Copy,
861{
828struct TtTreeSink<'a> {
862829 buf: String,
863 cursor: Cursor<'a, SpanData<Ctx>>,
830 cursor: Cursor<'a>,
864831 text_pos: TextSize,
865832 inner: SyntaxTreeBuilder,
866 token_map: SpanMap<Ctx>,
833 token_map: SpanMap,
867834}
868835
869impl<'a, Ctx> TtTreeSink<'a, Ctx>
870where
871 SpanData<Ctx>: Copy,
872{
873 fn new(cursor: Cursor<'a, SpanData<Ctx>>) -> Self {
836impl<'a> TtTreeSink<'a> {
837 fn new(cursor: Cursor<'a>) -> Self {
874838 TtTreeSink {
875839 buf: String::new(),
876840 cursor,
......@@ -880,7 +844,7 @@ where
880844 }
881845 }
882846
883 fn finish(mut self) -> (Parse<SyntaxNode>, SpanMap<Ctx>) {
847 fn finish(mut self) -> (Parse<SyntaxNode>, SpanMap) {
884848 self.token_map.finish();
885849 (self.inner.finish(), self.token_map)
886850 }
......@@ -898,21 +862,15 @@ fn delim_to_str(d: tt::DelimiterKind, closing: bool) -> Option<&'static str> {
898862 Some(&texts[idx..texts.len() - (1 - idx)])
899863}
900864
901impl<Ctx> TtTreeSink<'_, Ctx>
902where
903 SpanData<Ctx>: Copy + fmt::Debug,
904 Ctx: PartialEq,
905{
865impl TtTreeSink<'_> {
906866 /// Parses a float literal as if it was a one to two name ref nodes with a dot inbetween.
907867 /// This occurs when a float literal is used as a field access.
908868 fn float_split(&mut self, has_pseudo_dot: bool) {
909 let (text, span) = match self.cursor.token_tree() {
910 Some(tt::TokenTree::Leaf(tt::Leaf::Literal(tt::Literal {
911 symbol: text,
912 span,
913 kind: tt::LitKind::Float,
914 suffix: _,
915 }))) => (text.as_str(), *span),
869 let token_tree = self.cursor.token_tree();
870 let (text, span) = match &token_tree {
871 Some(tt::TokenTree::Leaf(tt::Leaf::Literal(
872 lit @ tt::Literal { span, kind: tt::LitKind::Float, .. },
873 ))) => (lit.text(), *span),
916874 tt => unreachable!("{tt:?}"),
917875 };
918876 // FIXME: Span splitting
......@@ -971,9 +929,15 @@ where
971929 self.buf.push_str("r#");
972930 self.text_pos += TextSize::of("r#");
973931 }
974 let r = (ident.sym.as_str(), ident.span);
932 let text = ident.sym.as_str();
933 self.buf += text;
934 self.text_pos += TextSize::of(text);
935 combined_span = match combined_span {
936 None => Some(ident.span),
937 Some(prev_span) => Some(Self::merge_spans(prev_span, ident.span)),
938 };
975939 self.cursor.bump();
976 r
940 continue 'tokens;
977941 }
978942 tt::Leaf::Punct(punct) => {
979943 assert!(punct.char.is_ascii());
......@@ -1053,10 +1017,10 @@ where
10531017 self.inner.error(error, self.text_pos)
10541018 }
10551019
1056 fn merge_spans(a: SpanData<Ctx>, b: SpanData<Ctx>) -> SpanData<Ctx> {
1020 fn merge_spans(a: Span, b: Span) -> Span {
10571021 // We don't do what rustc does exactly, rustc does something clever when the spans have different syntax contexts
10581022 // but this runs afoul of our separation between `span` and `hir-expand`.
1059 SpanData {
1023 Span {
10601024 range: if a.ctx == b.ctx && a.anchor == b.anchor {
10611025 TextRange::new(
10621026 std::cmp::min(a.range.start(), b.range.start()),
src/tools/rust-analyzer/crates/syntax-bridge/src/tests.rs+3-3
......@@ -30,15 +30,15 @@ fn check_punct_spacing(fixture: &str) {
3030 })
3131 .collect();
3232
33 let mut cursor = Cursor::new(&subtree.0);
33 let mut cursor = Cursor::new(subtree.as_token_trees());
3434 while !cursor.eof() {
3535 while let Some(token_tree) = cursor.token_tree() {
3636 if let tt::TokenTree::Leaf(Leaf::Punct(Punct {
3737 spacing, span: Span { range, .. }, ..
3838 })) = token_tree
39 && let Some(expected) = annotations.remove(range)
39 && let Some(expected) = annotations.remove(&range)
4040 {
41 assert_eq!(expected, *spacing);
41 assert_eq!(expected, spacing);
4242 }
4343 cursor.bump();
4444 }
src/tools/rust-analyzer/crates/syntax-bridge/src/to_parser_input.rs+5-8
......@@ -1,16 +1,13 @@
11//! Convert macro-by-example tokens which are specific to macro expansion into a
22//! format that works for our parser.
33
4use std::fmt;
5use std::hash::Hash;
6
74use rustc_hash::FxHashMap;
8use span::{Edition, SpanData};
5use span::{Edition, SyntaxContext};
96use syntax::{SyntaxKind, SyntaxKind::*, T};
107
11pub fn to_parser_input<Ctx: Copy + fmt::Debug + PartialEq + Eq + Hash>(
12 buffer: tt::TokenTreesView<'_, SpanData<Ctx>>,
13 span_to_edition: &mut dyn FnMut(Ctx) -> Edition,
8pub fn to_parser_input(
9 buffer: tt::TokenTreesView<'_>,
10 span_to_edition: &mut dyn FnMut(SyntaxContext) -> Edition,
1411) -> parser::Input {
1512 let mut res = parser::Input::with_capacity(buffer.len());
1613
......@@ -55,7 +52,7 @@ pub fn to_parser_input<Ctx: Copy + fmt::Debug + PartialEq + Eq + Hash>(
5552 };
5653 res.push(kind, ctx_edition(lit.span.ctx));
5754
58 if kind == FLOAT_NUMBER && !lit.symbol.as_str().ends_with('.') {
55 if kind == FLOAT_NUMBER && !lit.text().ends_with('.') {
5956 // Tag the token as joint if it is float with a fractional part
6057 // we use this jointness to inform the parser about what token split
6158 // event to emit when we encounter a float literal in a field access
src/tools/rust-analyzer/crates/syntax/fuzz/Cargo.toml-1
......@@ -10,7 +10,6 @@ cargo-fuzz = true
1010
1111[dependencies]
1212syntax = { path = "..", version = "0.0.0" }
13text-edit = { path = "../../text-edit", version = "0.0.0" }
1413libfuzzer-sys = "0.4.5"
1514
1615# Prevent this from interfering with workspaces
src/tools/rust-analyzer/crates/syntax/rust.ungram+4-1
......@@ -438,7 +438,10 @@ FormatArgsExpr =
438438 ')'
439439
440440FormatArgsArg =
441 (Name '=')? Expr
441 arg_name:FormatArgsArgName? Expr
442
443FormatArgsArgName =
444 '=' // This also has a name, but it's any token and we can't put it here
442445
443446MacroExpr =
444447 MacroCall
src/tools/rust-analyzer/crates/syntax/src/ast/generated/nodes.rs+44-6
......@@ -639,10 +639,16 @@ impl ForType {
639639pub struct FormatArgsArg {
640640 pub(crate) syntax: SyntaxNode,
641641}
642impl ast::HasName for FormatArgsArg {}
643642impl FormatArgsArg {
643 #[inline]
644 pub fn arg_name(&self) -> Option<FormatArgsArgName> { support::child(&self.syntax) }
644645 #[inline]
645646 pub fn expr(&self) -> Option<Expr> { support::child(&self.syntax) }
647}
648pub struct FormatArgsArgName {
649 pub(crate) syntax: SyntaxNode,
650}
651impl FormatArgsArgName {
646652 #[inline]
647653 pub fn eq_token(&self) -> Option<SyntaxToken> { support::token(&self.syntax, T![=]) }
648654}
......@@ -3722,6 +3728,38 @@ impl fmt::Debug for FormatArgsArg {
37223728 f.debug_struct("FormatArgsArg").field("syntax", &self.syntax).finish()
37233729 }
37243730}
3731impl AstNode for FormatArgsArgName {
3732 #[inline]
3733 fn kind() -> SyntaxKind
3734 where
3735 Self: Sized,
3736 {
3737 FORMAT_ARGS_ARG_NAME
3738 }
3739 #[inline]
3740 fn can_cast(kind: SyntaxKind) -> bool { kind == FORMAT_ARGS_ARG_NAME }
3741 #[inline]
3742 fn cast(syntax: SyntaxNode) -> Option<Self> {
3743 if Self::can_cast(syntax.kind()) { Some(Self { syntax }) } else { None }
3744 }
3745 #[inline]
3746 fn syntax(&self) -> &SyntaxNode { &self.syntax }
3747}
3748impl hash::Hash for FormatArgsArgName {
3749 fn hash<H: hash::Hasher>(&self, state: &mut H) { self.syntax.hash(state); }
3750}
3751impl Eq for FormatArgsArgName {}
3752impl PartialEq for FormatArgsArgName {
3753 fn eq(&self, other: &Self) -> bool { self.syntax == other.syntax }
3754}
3755impl Clone for FormatArgsArgName {
3756 fn clone(&self) -> Self { Self { syntax: self.syntax.clone() } }
3757}
3758impl fmt::Debug for FormatArgsArgName {
3759 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
3760 f.debug_struct("FormatArgsArgName").field("syntax", &self.syntax).finish()
3761 }
3762}
37253763impl AstNode for FormatArgsExpr {
37263764 #[inline]
37273765 fn kind() -> SyntaxKind
......@@ -8947,7 +8985,6 @@ impl AstNode for AnyHasName {
89478985 | CONST_PARAM
89488986 | ENUM
89498987 | FN
8950 | FORMAT_ARGS_ARG
89518988 | IDENT_PAT
89528989 | MACRO_DEF
89538990 | MACRO_RULES
......@@ -9006,10 +9043,6 @@ impl From<Fn> for AnyHasName {
90069043 #[inline]
90079044 fn from(node: Fn) -> AnyHasName { AnyHasName { syntax: node.syntax } }
90089045}
9009impl From<FormatArgsArg> for AnyHasName {
9010 #[inline]
9011 fn from(node: FormatArgsArg) -> AnyHasName { AnyHasName { syntax: node.syntax } }
9012}
90139046impl From<IdentPat> for AnyHasName {
90149047 #[inline]
90159048 fn from(node: IdentPat) -> AnyHasName { AnyHasName { syntax: node.syntax } }
......@@ -9541,6 +9574,11 @@ impl std::fmt::Display for FormatArgsArg {
95419574 std::fmt::Display::fmt(self.syntax(), f)
95429575 }
95439576}
9577impl std::fmt::Display for FormatArgsArgName {
9578 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
9579 std::fmt::Display::fmt(self.syntax(), f)
9580 }
9581}
95449582impl std::fmt::Display for FormatArgsExpr {
95459583 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95469584 std::fmt::Display::fmt(self.syntax(), f)
src/tools/rust-analyzer/crates/syntax/src/ast/node_ext.rs+20-12
......@@ -447,24 +447,23 @@ impl ast::UseTreeList {
447447
448448impl ast::Impl {
449449 pub fn self_ty(&self) -> Option<ast::Type> {
450 match self.target() {
451 (Some(t), None) | (_, Some(t)) => Some(t),
452 _ => None,
453 }
450 self.target().1
454451 }
455452
456453 pub fn trait_(&self) -> Option<ast::Type> {
457 match self.target() {
458 (Some(t), Some(_)) => Some(t),
459 _ => None,
460 }
454 self.target().0
461455 }
462456
463457 fn target(&self) -> (Option<ast::Type>, Option<ast::Type>) {
464 let mut types = support::children(self.syntax());
465 let first = types.next();
466 let second = types.next();
467 (first, second)
458 let mut types = support::children(self.syntax()).peekable();
459 let for_kw = self.for_token();
460 let trait_ = types.next_if(|trait_: &ast::Type| {
461 for_kw.is_some_and(|for_kw| {
462 trait_.syntax().text_range().start() < for_kw.text_range().start()
463 })
464 });
465 let self_ty = types.next();
466 (trait_, self_ty)
468467 }
469468
470469 pub fn for_trait_name_ref(name_ref: &ast::NameRef) -> Option<ast::Impl> {
......@@ -1118,6 +1117,15 @@ impl From<ast::AssocItem> for ast::AnyHasAttrs {
11181117 }
11191118}
11201119
1120impl ast::FormatArgsArgName {
1121 /// This is not a [`ast::Name`], because the name may be a keyword.
1122 pub fn name(&self) -> SyntaxToken {
1123 let name = self.syntax.first_token().unwrap();
1124 assert!(name.kind().is_any_identifier());
1125 name
1126 }
1127}
1128
11211129impl ast::OrPat {
11221130 pub fn leading_pipe(&self) -> Option<SyntaxToken> {
11231131 self.syntax
src/tools/rust-analyzer/crates/syntax/src/lib.rs+12-1
......@@ -218,7 +218,18 @@ impl<T> Drop for Parse<T> {
218218 let (sender, receiver) = std::sync::mpsc::channel::<GreenNode>();
219219 std::thread::Builder::new()
220220 .name("ParseNodeDropper".to_owned())
221 .spawn(move || receiver.iter().for_each(drop))
221 .spawn(move || {
222 loop {
223 // block on a receive
224 _ = receiver.recv();
225 // then drain the entire channel
226 while receiver.try_recv().is_ok() {}
227 // and sleep for a bit
228 std::thread::sleep(std::time::Duration::from_millis(100));
229 }
230 // why do this over just a `receiver.iter().for_each(drop)`? To reduce contention on the channel lock.
231 // otherwise this thread will constantly wake up and sleep again.
232 })
222233 .unwrap();
223234 sender
224235 })
src/tools/rust-analyzer/crates/test-fixture/Cargo.toml-1
......@@ -14,7 +14,6 @@ test-utils.workspace = true
1414tt.workspace = true
1515cfg.workspace = true
1616base-db.workspace = true
17rustc-hash.workspace = true
1817span.workspace = true
1918stdx.workspace = true
2019intern.workspace = true
src/tools/rust-analyzer/crates/test-fixture/src/lib.rs+36-21
......@@ -738,6 +738,7 @@ struct IdentityProcMacroExpander;
738738impl ProcMacroExpander for IdentityProcMacroExpander {
739739 fn expand(
740740 &self,
741 _: &dyn SourceDatabase,
741742 subtree: &TopSubtree,
742743 _: Option<&TopSubtree>,
743744 _: &Env,
......@@ -760,6 +761,7 @@ struct Issue18089ProcMacroExpander;
760761impl ProcMacroExpander for Issue18089ProcMacroExpander {
761762 fn expand(
762763 &self,
764 _: &dyn SourceDatabase,
763765 subtree: &TopSubtree,
764766 _: Option<&TopSubtree>,
765767 _: &Env,
......@@ -768,7 +770,7 @@ impl ProcMacroExpander for Issue18089ProcMacroExpander {
768770 _: Span,
769771 _: String,
770772 ) -> Result<TopSubtree, ProcMacroExpansionError> {
771 let tt::TokenTree::Leaf(macro_name) = &subtree.0[2] else {
773 let Some(tt::TtElement::Leaf(macro_name)) = subtree.iter().nth(1) else {
772774 return Err(ProcMacroExpansionError::Panic("incorrect input".to_owned()));
773775 };
774776 Ok(quote! { call_site =>
......@@ -795,6 +797,7 @@ struct AttributeInputReplaceProcMacroExpander;
795797impl ProcMacroExpander for AttributeInputReplaceProcMacroExpander {
796798 fn expand(
797799 &self,
800 _: &dyn SourceDatabase,
798801 _: &TopSubtree,
799802 attrs: Option<&TopSubtree>,
800803 _: &Env,
......@@ -818,6 +821,7 @@ struct Issue18840ProcMacroExpander;
818821impl ProcMacroExpander for Issue18840ProcMacroExpander {
819822 fn expand(
820823 &self,
824 _: &dyn SourceDatabase,
821825 fn_: &TopSubtree,
822826 _: Option<&TopSubtree>,
823827 _: &Env,
......@@ -833,13 +837,14 @@ impl ProcMacroExpander for Issue18840ProcMacroExpander {
833837 // ```
834838
835839 // The span that was created by the fixup infra.
836 let fixed_up_span = fn_.token_trees().flat_tokens()[5].first_span();
840 let mut iter = fn_.iter();
841 iter.nth(2);
842 let (_, mut fn_body) = iter.expect_subtree().unwrap();
843 let fixed_up_span = fn_body.nth(1).unwrap().first_span();
837844 let mut result =
838845 quote! {fixed_up_span => ::core::compile_error! { "my cool compile_error!" } };
839846 // Make it so we won't remove the top subtree when reversing fixups.
840 let top_subtree_delimiter_mut = result.top_subtree_delimiter_mut();
841 top_subtree_delimiter_mut.open = def_site;
842 top_subtree_delimiter_mut.close = def_site;
847 result.set_top_subtree_delimiter_span(tt::DelimSpan::from_single(def_site));
843848 Ok(result)
844849 }
845850
......@@ -853,6 +858,7 @@ struct MirrorProcMacroExpander;
853858impl ProcMacroExpander for MirrorProcMacroExpander {
854859 fn expand(
855860 &self,
861 _: &dyn SourceDatabase,
856862 input: &TopSubtree,
857863 _: Option<&TopSubtree>,
858864 _: &Env,
......@@ -891,6 +897,7 @@ struct ShortenProcMacroExpander;
891897impl ProcMacroExpander for ShortenProcMacroExpander {
892898 fn expand(
893899 &self,
900 _: &dyn SourceDatabase,
894901 input: &TopSubtree,
895902 _: Option<&TopSubtree>,
896903 _: &Env,
......@@ -899,20 +906,22 @@ impl ProcMacroExpander for ShortenProcMacroExpander {
899906 _: Span,
900907 _: String,
901908 ) -> Result<TopSubtree, ProcMacroExpansionError> {
902 let mut result = input.0.clone();
903 for it in &mut result {
904 if let TokenTree::Leaf(leaf) = it {
905 modify_leaf(leaf)
909 let mut result = input.clone();
910 for (idx, it) in input.as_token_trees().iter_flat_tokens().enumerate() {
911 if let TokenTree::Leaf(mut leaf) = it {
912 modify_leaf(&mut leaf);
913 result.set_token(idx, leaf);
906914 }
907915 }
908 return Ok(tt::TopSubtree(result));
916 return Ok(result);
909917
910918 fn modify_leaf(leaf: &mut Leaf) {
911919 match leaf {
912920 Leaf::Literal(it) => {
913921 // XXX Currently replaces any literals with an empty string, but supporting
914922 // "shortening" other literals would be nice.
915 it.symbol = Symbol::empty();
923 it.text_and_suffix = Symbol::empty();
924 it.suffix_len = 0;
916925 }
917926 Leaf::Punct(_) => {}
918927 Leaf::Ident(it) => {
......@@ -933,6 +942,7 @@ struct Issue17479ProcMacroExpander;
933942impl ProcMacroExpander for Issue17479ProcMacroExpander {
934943 fn expand(
935944 &self,
945 _: &dyn SourceDatabase,
936946 subtree: &TopSubtree,
937947 _: Option<&TopSubtree>,
938948 _: &Env,
......@@ -941,10 +951,11 @@ impl ProcMacroExpander for Issue17479ProcMacroExpander {
941951 _: Span,
942952 _: String,
943953 ) -> Result<TopSubtree, ProcMacroExpansionError> {
944 let TokenTree::Leaf(Leaf::Literal(lit)) = &subtree.0[1] else {
954 let mut iter = subtree.iter();
955 let Some(TtElement::Leaf(tt::Leaf::Literal(lit))) = iter.next() else {
945956 return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
946957 };
947 let symbol = &lit.symbol;
958 let symbol = Symbol::intern(lit.text());
948959 let span = lit.span;
949960 Ok(quote! { span =>
950961 #symbol()
......@@ -962,6 +973,7 @@ struct Issue18898ProcMacroExpander;
962973impl ProcMacroExpander for Issue18898ProcMacroExpander {
963974 fn expand(
964975 &self,
976 _: &dyn SourceDatabase,
965977 subtree: &TopSubtree,
966978 _: Option<&TopSubtree>,
967979 _: &Env,
......@@ -972,10 +984,8 @@ impl ProcMacroExpander for Issue18898ProcMacroExpander {
972984 ) -> Result<TopSubtree, ProcMacroExpansionError> {
973985 let span = subtree
974986 .token_trees()
975 .flat_tokens()
976 .last()
977 .ok_or_else(|| ProcMacroExpansionError::Panic("malformed input".to_owned()))?
978 .first_span();
987 .last_span()
988 .ok_or_else(|| ProcMacroExpansionError::Panic("malformed input".to_owned()))?;
979989 let overly_long_subtree = quote! {span =>
980990 {
981991 let a = 5;
......@@ -1017,6 +1027,7 @@ struct DisallowCfgProcMacroExpander;
10171027impl ProcMacroExpander for DisallowCfgProcMacroExpander {
10181028 fn expand(
10191029 &self,
1030 _: &dyn SourceDatabase,
10201031 subtree: &TopSubtree,
10211032 _: Option<&TopSubtree>,
10221033 _: &Env,
......@@ -1025,7 +1036,7 @@ impl ProcMacroExpander for DisallowCfgProcMacroExpander {
10251036 _: Span,
10261037 _: String,
10271038 ) -> Result<TopSubtree, ProcMacroExpansionError> {
1028 for tt in subtree.token_trees().flat_tokens() {
1039 for tt in subtree.token_trees().iter_flat_tokens() {
10291040 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = tt
10301041 && (ident.sym == sym::cfg || ident.sym == sym::cfg_attr)
10311042 {
......@@ -1048,6 +1059,7 @@ struct GenerateSuffixedTypeProcMacroExpander;
10481059impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
10491060 fn expand(
10501061 &self,
1062 _: &dyn SourceDatabase,
10511063 subtree: &TopSubtree,
10521064 _attrs: Option<&TopSubtree>,
10531065 _env: &Env,
......@@ -1056,20 +1068,23 @@ impl ProcMacroExpander for GenerateSuffixedTypeProcMacroExpander {
10561068 _mixed_site: Span,
10571069 _current_dir: String,
10581070 ) -> Result<TopSubtree, ProcMacroExpansionError> {
1059 let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[1] else {
1071 let mut iter = subtree.iter();
1072 let Some(TtElement::Leaf(tt::Leaf::Ident(ident))) = iter.next() else {
10601073 return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
10611074 };
10621075
10631076 let ident = match ident.sym.as_str() {
10641077 "struct" => {
1065 let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[2] else {
1078 let Some(TtElement::Leaf(tt::Leaf::Ident(ident))) = iter.next() else {
10661079 return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
10671080 };
10681081 ident
10691082 }
10701083
10711084 "enum" => {
1072 let TokenTree::Leaf(Leaf::Ident(ident)) = &subtree.0[4] else {
1085 iter.next();
1086 let (_, mut iter) = iter.expect_subtree().unwrap();
1087 let Some(TtElement::Leaf(tt::Leaf::Ident(ident))) = iter.next() else {
10731088 return Err(ProcMacroExpansionError::Panic("incorrect Input".into()));
10741089 };
10751090 ident
src/tools/rust-analyzer/crates/tt/Cargo.toml+3
......@@ -15,7 +15,10 @@ doctest = false
1515[dependencies]
1616arrayvec.workspace = true
1717text-size.workspace = true
18rustc-hash.workspace = true
19indexmap.workspace = true
1820
21span = { path = "../span", version = "0.0", default-features = false }
1922stdx.workspace = true
2023intern.workspace = true
2124ra-ap-rustc_lexer.workspace = true
src/tools/rust-analyzer/crates/tt/src/buffer.rs+26-17
......@@ -1,16 +1,16 @@
11//! Stateful iteration over token trees.
22//!
33//! We use this as the source of tokens for parser.
4use crate::{Leaf, Subtree, TokenTree, TokenTreesView};
4use crate::{Leaf, Subtree, TokenTree, TokenTreesView, dispatch_ref};
55
6pub struct Cursor<'a, Span> {
7 buffer: &'a [TokenTree<Span>],
6pub struct Cursor<'a> {
7 buffer: TokenTreesView<'a>,
88 index: usize,
99 subtrees_stack: Vec<usize>,
1010}
1111
12impl<'a, Span: Copy> Cursor<'a, Span> {
13 pub fn new(buffer: &'a [TokenTree<Span>]) -> Self {
12impl<'a> Cursor<'a> {
13 pub fn new(buffer: TokenTreesView<'a>) -> Self {
1414 Self { buffer, index: 0, subtrees_stack: Vec::new() }
1515 }
1616
......@@ -23,16 +23,22 @@ impl<'a, Span: Copy> Cursor<'a, Span> {
2323 self.subtrees_stack.is_empty()
2424 }
2525
26 fn last_subtree(&self) -> Option<(usize, &'a Subtree<Span>)> {
26 fn at(&self, idx: usize) -> Option<TokenTree> {
27 dispatch_ref! {
28 match self.buffer.repr => tt => Some(tt.get(idx)?.to_api(self.buffer.span_parts))
29 }
30 }
31
32 fn last_subtree(&self) -> Option<(usize, Subtree)> {
2733 self.subtrees_stack.last().map(|&subtree_idx| {
28 let TokenTree::Subtree(subtree) = &self.buffer[subtree_idx] else {
34 let Some(TokenTree::Subtree(subtree)) = self.at(subtree_idx) else {
2935 panic!("subtree pointing to non-subtree");
3036 };
3137 (subtree_idx, subtree)
3238 })
3339 }
3440
35 pub fn end(&mut self) -> &'a Subtree<Span> {
41 pub fn end(&mut self) -> Subtree {
3642 let (last_subtree_idx, last_subtree) =
3743 self.last_subtree().expect("called `Cursor::end()` without an open subtree");
3844 // +1 because `Subtree.len` excludes the subtree itself.
......@@ -46,14 +52,14 @@ impl<'a, Span: Copy> Cursor<'a, Span> {
4652 }
4753
4854 /// Returns the `TokenTree` at the cursor if it is not at the end of a subtree.
49 pub fn token_tree(&self) -> Option<&'a TokenTree<Span>> {
55 pub fn token_tree(&self) -> Option<TokenTree> {
5056 if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
5157 // +1 because `Subtree.len` excludes the subtree itself.
5258 if last_subtree_idx + last_subtree.usize_len() + 1 == self.index {
5359 return None;
5460 }
5561 }
56 self.buffer.get(self.index)
62 self.at(self.index)
5763 }
5864
5965 /// Bump the cursor, and enters a subtree if it is on one.
......@@ -66,7 +72,7 @@ impl<'a, Span: Copy> Cursor<'a, Span> {
6672 "called `Cursor::bump()` when at the end of a subtree"
6773 );
6874 }
69 if let TokenTree::Subtree(_) = self.buffer[self.index] {
75 if let Some(TokenTree::Subtree(_)) = self.at(self.index) {
7076 self.subtrees_stack.push(self.index);
7177 }
7278 self.index += 1;
......@@ -81,13 +87,13 @@ impl<'a, Span: Copy> Cursor<'a, Span> {
8187 }
8288 }
8389 // +1 because `Subtree.len` excludes the subtree itself.
84 if let TokenTree::Subtree(_) = self.buffer[self.index] {
90 if let Some(TokenTree::Subtree(_)) = self.at(self.index) {
8591 self.subtrees_stack.push(self.index);
8692 }
8793 self.index += 1;
8894 }
8995
90 pub fn peek_two_leaves(&self) -> Option<[&'a Leaf<Span>; 2]> {
96 pub fn peek_two_leaves(&self) -> Option<[Leaf; 2]> {
9197 if let Some((last_subtree_idx, last_subtree)) = self.last_subtree() {
9298 // +1 because `Subtree.len` excludes the subtree itself.
9399 let last_end = last_subtree_idx + last_subtree.usize_len() + 1;
......@@ -95,14 +101,17 @@ impl<'a, Span: Copy> Cursor<'a, Span> {
95101 return None;
96102 }
97103 }
98 self.buffer.get(self.index..self.index + 2).and_then(|it| match it {
99 [TokenTree::Leaf(a), TokenTree::Leaf(b)] => Some([a, b]),
104 self.at(self.index).zip(self.at(self.index + 1)).and_then(|it| match it {
105 (TokenTree::Leaf(a), TokenTree::Leaf(b)) => Some([a, b]),
100106 _ => None,
101107 })
102108 }
103109
104 pub fn crossed(&self) -> TokenTreesView<'a, Span> {
110 pub fn crossed(&self) -> TokenTreesView<'a> {
105111 assert!(self.is_root());
106 TokenTreesView::new(&self.buffer[..self.index])
112 TokenTreesView {
113 repr: self.buffer.repr.get(..self.index).unwrap(),
114 span_parts: self.buffer.span_parts,
115 }
107116 }
108117}
src/tools/rust-analyzer/crates/tt/src/iter.rs+91-60
......@@ -5,58 +5,62 @@ use std::fmt;
55
66use arrayvec::ArrayVec;
77use intern::sym;
8use span::Span;
89
9use crate::{Ident, Leaf, MAX_GLUED_PUNCT_LEN, Punct, Spacing, Subtree, TokenTree, TokenTreesView};
10use crate::{
11 Ident, Leaf, MAX_GLUED_PUNCT_LEN, Punct, Spacing, Subtree, TokenTree, TokenTreesReprRef,
12 TokenTreesView, dispatch_ref,
13};
1014
1115#[derive(Clone)]
12pub struct TtIter<'a, S> {
13 inner: std::slice::Iter<'a, TokenTree<S>>,
16pub struct TtIter<'a> {
17 inner: TokenTreesView<'a>,
1418}
1519
16impl<S: Copy + fmt::Debug> fmt::Debug for TtIter<'_, S> {
20impl fmt::Debug for TtIter<'_> {
1721 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1822 f.debug_struct("TtIter").field("remaining", &self.remaining()).finish()
1923 }
2024}
2125
2226#[derive(Clone, Copy)]
23pub struct TtIterSavepoint<'a, S>(&'a [TokenTree<S>]);
27pub struct TtIterSavepoint<'a>(TokenTreesView<'a>);
2428
25impl<'a, S: Copy> TtIterSavepoint<'a, S> {
26 pub fn remaining(self) -> TokenTreesView<'a, S> {
27 TokenTreesView::new(self.0)
29impl<'a> TtIterSavepoint<'a> {
30 pub fn remaining(self) -> TokenTreesView<'a> {
31 self.0
2832 }
2933}
3034
31impl<'a, S: Copy> TtIter<'a, S> {
32 pub(crate) fn new(tt: &'a [TokenTree<S>]) -> TtIter<'a, S> {
33 TtIter { inner: tt.iter() }
35impl<'a> TtIter<'a> {
36 pub(crate) fn new(tt: TokenTreesView<'a>) -> TtIter<'a> {
37 TtIter { inner: tt }
3438 }
3539
3640 pub fn expect_char(&mut self, char: char) -> Result<(), ()> {
3741 match self.next() {
38 Some(TtElement::Leaf(&Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()),
42 Some(TtElement::Leaf(Leaf::Punct(Punct { char: c, .. }))) if c == char => Ok(()),
3943 _ => Err(()),
4044 }
4145 }
4246
4347 pub fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
4448 match self.next() {
45 Some(TtElement::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(c) => {
49 Some(TtElement::Leaf(Leaf::Punct(Punct { char: c, .. }))) if chars.contains(&c) => {
4650 Ok(())
4751 }
4852 _ => Err(()),
4953 }
5054 }
5155
52 pub fn expect_subtree(&mut self) -> Result<(&'a Subtree<S>, TtIter<'a, S>), ()> {
56 pub fn expect_subtree(&mut self) -> Result<(Subtree, TtIter<'a>), ()> {
5357 match self.next() {
5458 Some(TtElement::Subtree(subtree, iter)) => Ok((subtree, iter)),
5559 _ => Err(()),
5660 }
5761 }
5862
59 pub fn expect_leaf(&mut self) -> Result<&'a Leaf<S>, ()> {
63 pub fn expect_leaf(&mut self) -> Result<Leaf, ()> {
6064 match self.next() {
6165 Some(TtElement::Leaf(it)) => Ok(it),
6266 _ => Err(()),
......@@ -77,30 +81,30 @@ impl<'a, S: Copy> TtIter<'a, S> {
7781 }
7882 }
7983
80 pub fn expect_ident(&mut self) -> Result<&'a Ident<S>, ()> {
84 pub fn expect_ident(&mut self) -> Result<Ident, ()> {
8185 match self.expect_leaf()? {
8286 Leaf::Ident(it) if it.sym != sym::underscore => Ok(it),
8387 _ => Err(()),
8488 }
8589 }
8690
87 pub fn expect_ident_or_underscore(&mut self) -> Result<&'a Ident<S>, ()> {
91 pub fn expect_ident_or_underscore(&mut self) -> Result<Ident, ()> {
8892 match self.expect_leaf()? {
8993 Leaf::Ident(it) => Ok(it),
9094 _ => Err(()),
9195 }
9296 }
9397
94 pub fn expect_literal(&mut self) -> Result<&'a Leaf<S>, ()> {
98 pub fn expect_literal(&mut self) -> Result<Leaf, ()> {
9599 let it = self.expect_leaf()?;
96 match it {
100 match &it {
97101 Leaf::Literal(_) => Ok(it),
98102 Leaf::Ident(ident) if ident.sym == sym::true_ || ident.sym == sym::false_ => Ok(it),
99103 _ => Err(()),
100104 }
101105 }
102106
103 pub fn expect_single_punct(&mut self) -> Result<&'a Punct<S>, ()> {
107 pub fn expect_single_punct(&mut self) -> Result<Punct, ()> {
104108 match self.expect_leaf()? {
105109 Leaf::Punct(it) => Ok(it),
106110 _ => Err(()),
......@@ -111,8 +115,8 @@ impl<'a, S: Copy> TtIter<'a, S> {
111115 ///
112116 /// This method currently may return a single quotation, which is part of lifetime ident and
113117 /// conceptually not a punct in the context of mbe. Callers should handle this.
114 pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct<S>, MAX_GLUED_PUNCT_LEN>, ()> {
115 let TtElement::Leaf(&Leaf::Punct(first)) = self.next().ok_or(())? else {
118 pub fn expect_glued_punct(&mut self) -> Result<ArrayVec<Punct, MAX_GLUED_PUNCT_LEN>, ()> {
119 let TtElement::Leaf(Leaf::Punct(first)) = self.next().ok_or(())? else {
116120 return Err(());
117121 };
118122
......@@ -140,8 +144,8 @@ impl<'a, S: Copy> TtIter<'a, S> {
140144 let _ = self.next().unwrap();
141145 let _ = self.next().unwrap();
142146 res.push(first);
143 res.push(*second);
144 res.push(*third.unwrap());
147 res.push(second);
148 res.push(third.unwrap());
145149 }
146150 ('-' | '!' | '*' | '/' | '&' | '%' | '^' | '+' | '<' | '=' | '>' | '|', '=', _)
147151 | ('-' | '=' | '>', '>', _)
......@@ -153,7 +157,7 @@ impl<'a, S: Copy> TtIter<'a, S> {
153157 | ('|', '|', _) => {
154158 let _ = self.next().unwrap();
155159 res.push(first);
156 res.push(*second);
160 res.push(second);
157161 }
158162 _ => res.push(first),
159163 }
......@@ -161,16 +165,20 @@ impl<'a, S: Copy> TtIter<'a, S> {
161165 }
162166
163167 /// This method won't check for subtrees, so the nth token tree may not be the nth sibling of the current tree.
164 fn peek_n(&self, n: usize) -> Option<&'a TokenTree<S>> {
165 self.inner.as_slice().get(n)
168 fn peek_n(&self, n: usize) -> Option<TokenTree> {
169 dispatch_ref! {
170 match self.inner.repr => tt => Some(tt.get(n)?.to_api(self.inner.span_parts))
171 }
166172 }
167173
168 pub fn peek(&self) -> Option<TtElement<'a, S>> {
169 match self.inner.as_slice().first()? {
174 pub fn peek(&self) -> Option<TtElement<'a>> {
175 match self.peek_n(0)? {
170176 TokenTree::Leaf(leaf) => Some(TtElement::Leaf(leaf)),
171177 TokenTree::Subtree(subtree) => {
172 let nested_iter =
173 TtIter { inner: self.inner.as_slice()[1..][..subtree.usize_len()].iter() };
178 let nested_repr = self.inner.repr.get(1..subtree.usize_len() + 1).unwrap();
179 let nested_iter = TtIter {
180 inner: TokenTreesView { repr: nested_repr, span_parts: self.inner.span_parts },
181 };
174182 Some(TtElement::Subtree(subtree, nested_iter))
175183 }
176184 }
......@@ -181,30 +189,55 @@ impl<'a, S: Copy> TtIter<'a, S> {
181189 self.inner.len() == 0
182190 }
183191
184 pub fn next_span(&self) -> Option<S> {
185 Some(self.inner.as_slice().first()?.first_span())
192 pub fn next_span(&self) -> Option<Span> {
193 Some(self.peek()?.first_span())
186194 }
187195
188 pub fn remaining(&self) -> TokenTreesView<'a, S> {
189 TokenTreesView::new(self.inner.as_slice())
196 pub fn remaining(&self) -> TokenTreesView<'a> {
197 self.inner
190198 }
191199
192200 /// **Warning**: This advances `skip` **flat** token trees, subtrees account for children+1!
193201 pub fn flat_advance(&mut self, skip: usize) {
194 self.inner = self.inner.as_slice()[skip..].iter();
202 self.inner.repr = self.inner.repr.get(skip..).unwrap();
195203 }
196204
197 pub fn savepoint(&self) -> TtIterSavepoint<'a, S> {
198 TtIterSavepoint(self.inner.as_slice())
205 pub fn savepoint(&self) -> TtIterSavepoint<'a> {
206 TtIterSavepoint(self.inner)
199207 }
200208
201 pub fn from_savepoint(&self, savepoint: TtIterSavepoint<'a, S>) -> TokenTreesView<'a, S> {
202 let len = (self.inner.as_slice().as_ptr() as usize - savepoint.0.as_ptr() as usize)
203 / size_of::<TokenTree<S>>();
204 TokenTreesView::new(&savepoint.0[..len])
209 pub fn from_savepoint(&self, savepoint: TtIterSavepoint<'a>) -> TokenTreesView<'a> {
210 let len = match (self.inner.repr, savepoint.0.repr) {
211 (
212 TokenTreesReprRef::SpanStorage32(this),
213 TokenTreesReprRef::SpanStorage32(savepoint),
214 ) => {
215 (this.as_ptr() as usize - savepoint.as_ptr() as usize)
216 / size_of::<crate::storage::TokenTree<crate::storage::SpanStorage32>>()
217 }
218 (
219 TokenTreesReprRef::SpanStorage64(this),
220 TokenTreesReprRef::SpanStorage64(savepoint),
221 ) => {
222 (this.as_ptr() as usize - savepoint.as_ptr() as usize)
223 / size_of::<crate::storage::TokenTree<crate::storage::SpanStorage64>>()
224 }
225 (
226 TokenTreesReprRef::SpanStorage96(this),
227 TokenTreesReprRef::SpanStorage96(savepoint),
228 ) => {
229 (this.as_ptr() as usize - savepoint.as_ptr() as usize)
230 / size_of::<crate::storage::TokenTree<crate::storage::SpanStorage96>>()
231 }
232 _ => panic!("savepoint did not originate from this TtIter"),
233 };
234 TokenTreesView {
235 repr: savepoint.0.repr.get(..len).unwrap(),
236 span_parts: savepoint.0.span_parts,
237 }
205238 }
206239
207 pub fn next_as_view(&mut self) -> Option<TokenTreesView<'a, S>> {
240 pub fn next_as_view(&mut self) -> Option<TokenTreesView<'a>> {
208241 let savepoint = self.savepoint();
209242 self.next()?;
210243 Some(self.from_savepoint(savepoint))
......@@ -212,12 +245,12 @@ impl<'a, S: Copy> TtIter<'a, S> {
212245}
213246
214247#[derive(Clone)]
215pub enum TtElement<'a, S> {
216 Leaf(&'a Leaf<S>),
217 Subtree(&'a Subtree<S>, TtIter<'a, S>),
248pub enum TtElement<'a> {
249 Leaf(Leaf),
250 Subtree(Subtree, TtIter<'a>),
218251}
219252
220impl<S: Copy + fmt::Debug> fmt::Debug for TtElement<'_, S> {
253impl fmt::Debug for TtElement<'_> {
221254 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
222255 match self {
223256 Self::Leaf(leaf) => f.debug_tuple("Leaf").field(leaf).finish(),
......@@ -228,9 +261,9 @@ impl<S: Copy + fmt::Debug> fmt::Debug for TtElement<'_, S> {
228261 }
229262}
230263
231impl<S: Copy> TtElement<'_, S> {
264impl TtElement<'_> {
232265 #[inline]
233 pub fn first_span(&self) -> S {
266 pub fn first_span(&self) -> Span {
234267 match self {
235268 TtElement::Leaf(it) => *it.span(),
236269 TtElement::Subtree(it, _) => it.delimiter.open,
......@@ -238,17 +271,15 @@ impl<S: Copy> TtElement<'_, S> {
238271 }
239272}
240273
241impl<'a, S> Iterator for TtIter<'a, S> {
242 type Item = TtElement<'a, S>;
274impl<'a> Iterator for TtIter<'a> {
275 type Item = TtElement<'a>;
243276 fn next(&mut self) -> Option<Self::Item> {
244 match self.inner.next()? {
245 TokenTree::Leaf(leaf) => Some(TtElement::Leaf(leaf)),
246 TokenTree::Subtree(subtree) => {
247 let nested_iter =
248 TtIter { inner: self.inner.as_slice()[..subtree.usize_len()].iter() };
249 self.inner = self.inner.as_slice()[subtree.usize_len()..].iter();
250 Some(TtElement::Subtree(subtree, nested_iter))
251 }
252 }
277 let result = self.peek()?;
278 let skip = match &result {
279 TtElement::Leaf(_) => 1,
280 TtElement::Subtree(subtree, _) => subtree.usize_len() + 1,
281 };
282 self.inner.repr = self.inner.repr.get(skip..).unwrap();
283 Some(result)
253284 }
254285}
src/tools/rust-analyzer/crates/tt/src/lib.rs+391-479
......@@ -15,16 +15,23 @@ extern crate rustc_lexer;
1515
1616pub mod buffer;
1717pub mod iter;
18mod storage;
1819
19use std::fmt;
20use std::{fmt, slice::SliceIndex};
2021
22use arrayvec::ArrayString;
2123use buffer::Cursor;
2224use intern::Symbol;
23use iter::{TtElement, TtIter};
2425use stdx::{impl_from, itertools::Itertools as _};
2526
27pub use span::Span;
2628pub use text_size::{TextRange, TextSize};
2729
30use crate::storage::{CompressedSpanPart, SpanStorage};
31
32pub use self::iter::{TtElement, TtIter};
33pub use self::storage::{TopSubtree, TopSubtreeBuilder};
34
2835pub const MAX_GLUED_PUNCT_LEN: usize = 3;
2936
3037#[derive(Clone, PartialEq, Debug)]
......@@ -77,13 +84,13 @@ pub enum LitKind {
7784}
7885
7986#[derive(Debug, Clone, PartialEq, Eq, Hash)]
80pub enum TokenTree<S = u32> {
81 Leaf(Leaf<S>),
82 Subtree(Subtree<S>),
87pub enum TokenTree {
88 Leaf(Leaf),
89 Subtree(Subtree),
8390}
84impl_from!(Leaf<S>, Subtree<S> for TokenTree);
85impl<S: Copy> TokenTree<S> {
86 pub fn first_span(&self) -> S {
91impl_from!(Leaf, Subtree for TokenTree);
92impl TokenTree {
93 pub fn first_span(&self) -> Span {
8794 match self {
8895 TokenTree::Leaf(l) => *l.span(),
8996 TokenTree::Subtree(s) => s.delimiter.open,
......@@ -92,14 +99,14 @@ impl<S: Copy> TokenTree<S> {
9299}
93100
94101#[derive(Debug, Clone, PartialEq, Eq, Hash)]
95pub enum Leaf<S> {
96 Literal(Literal<S>),
97 Punct(Punct<S>),
98 Ident(Ident<S>),
102pub enum Leaf {
103 Literal(Literal),
104 Punct(Punct),
105 Ident(Ident),
99106}
100107
101impl<S> Leaf<S> {
102 pub fn span(&self) -> &S {
108impl Leaf {
109 pub fn span(&self) -> &Span {
103110 match self {
104111 Leaf::Literal(it) => &it.span,
105112 Leaf::Punct(it) => &it.span,
......@@ -107,282 +114,120 @@ impl<S> Leaf<S> {
107114 }
108115 }
109116}
110impl_from!(Literal<S>, Punct<S>, Ident<S> for Leaf);
117impl_from!(Literal, Punct, Ident for Leaf);
111118
112#[derive(Debug, Clone, PartialEq, Eq, Hash)]
113pub struct Subtree<S> {
114 pub delimiter: Delimiter<S>,
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct Subtree {
121 pub delimiter: Delimiter,
115122 /// Number of following token trees that belong to this subtree, excluding this subtree.
116123 pub len: u32,
117124}
118125
119impl<S> Subtree<S> {
126impl Subtree {
120127 pub fn usize_len(&self) -> usize {
121128 self.len as usize
122129 }
123130}
124131
125#[derive(Clone, PartialEq, Eq, Hash)]
126pub struct TopSubtree<S>(pub Box<[TokenTree<S>]>);
127
128impl<S: Copy> TopSubtree<S> {
129 pub fn empty(span: DelimSpan<S>) -> Self {
130 Self(Box::new([TokenTree::Subtree(Subtree {
131 delimiter: Delimiter::invisible_delim_spanned(span),
132 len: 0,
133 })]))
134 }
135
136 pub fn invisible_from_leaves<const N: usize>(delim_span: S, leaves: [Leaf<S>; N]) -> Self {
137 let mut builder = TopSubtreeBuilder::new(Delimiter::invisible_spanned(delim_span));
138 builder.extend(leaves);
139 builder.build()
140 }
141
142 pub fn from_token_trees(delimiter: Delimiter<S>, token_trees: TokenTreesView<'_, S>) -> Self {
143 let mut builder = TopSubtreeBuilder::new(delimiter);
144 builder.extend_with_tt(token_trees);
145 builder.build()
146 }
147
148 pub fn from_subtree(subtree: SubtreeView<'_, S>) -> Self {
149 Self(subtree.0.into())
150 }
151
152 pub fn view(&self) -> SubtreeView<'_, S> {
153 SubtreeView::new(&self.0)
154 }
155
156 pub fn iter(&self) -> TtIter<'_, S> {
157 self.view().iter()
158 }
159
160 pub fn top_subtree(&self) -> &Subtree<S> {
161 self.view().top_subtree()
162 }
163
164 pub fn top_subtree_delimiter_mut(&mut self) -> &mut Delimiter<S> {
165 let TokenTree::Subtree(subtree) = &mut self.0[0] else {
166 unreachable!("the first token tree is always the top subtree");
167 };
168 &mut subtree.delimiter
169 }
170
171 pub fn token_trees(&self) -> TokenTreesView<'_, S> {
172 self.view().token_trees()
173 }
174}
175
176#[derive(Debug, Clone, PartialEq, Eq, Hash)]
177pub struct TopSubtreeBuilder<S> {
178 unclosed_subtree_indices: Vec<usize>,
179 token_trees: Vec<TokenTree<S>>,
180 last_closed_subtree: Option<usize>,
181}
182
183impl<S: Copy> TopSubtreeBuilder<S> {
184 pub fn new(top_delimiter: Delimiter<S>) -> Self {
185 let mut result = Self {
186 unclosed_subtree_indices: Vec::new(),
187 token_trees: Vec::new(),
188 last_closed_subtree: None,
189 };
190 let top_subtree = TokenTree::Subtree(Subtree { delimiter: top_delimiter, len: 0 });
191 result.token_trees.push(top_subtree);
192 result
193 }
194
195 pub fn open(&mut self, delimiter_kind: DelimiterKind, open_span: S) {
196 self.unclosed_subtree_indices.push(self.token_trees.len());
197 self.token_trees.push(TokenTree::Subtree(Subtree {
198 delimiter: Delimiter {
199 open: open_span,
200 close: open_span, // Will be overwritten on close.
201 kind: delimiter_kind,
202 },
203 len: 0,
204 }));
205 }
206
207 pub fn close(&mut self, close_span: S) {
208 let last_unclosed_index = self
209 .unclosed_subtree_indices
210 .pop()
211 .expect("attempt to close a `tt::Subtree` when none is open");
212 let subtree_len = (self.token_trees.len() - last_unclosed_index - 1) as u32;
213 let TokenTree::Subtree(subtree) = &mut self.token_trees[last_unclosed_index] else {
214 unreachable!("unclosed token tree is always a subtree");
215 };
216 subtree.len = subtree_len;
217 subtree.delimiter.close = close_span;
218 self.last_closed_subtree = Some(last_unclosed_index);
219 }
220
221 /// You cannot call this consecutively, it will only work once after close.
222 pub fn remove_last_subtree_if_invisible(&mut self) {
223 let Some(last_subtree_idx) = self.last_closed_subtree else { return };
224 if let TokenTree::Subtree(Subtree {
225 delimiter: Delimiter { kind: DelimiterKind::Invisible, .. },
226 ..
227 }) = self.token_trees[last_subtree_idx]
228 {
229 self.token_trees.remove(last_subtree_idx);
230 self.last_closed_subtree = None;
231 }
232 }
233
234 pub fn push(&mut self, leaf: Leaf<S>) {
235 self.token_trees.push(TokenTree::Leaf(leaf));
236 }
237
238 pub fn extend(&mut self, leaves: impl IntoIterator<Item = Leaf<S>>) {
239 self.token_trees.extend(leaves.into_iter().map(TokenTree::Leaf));
240 }
241
242 /// This does not check the token trees are valid, beware!
243 pub fn extend_tt_dangerous(&mut self, tt: impl IntoIterator<Item = TokenTree<S>>) {
244 self.token_trees.extend(tt);
245 }
246
247 pub fn extend_with_tt(&mut self, tt: TokenTreesView<'_, S>) {
248 self.token_trees.extend(tt.0.iter().cloned());
249 }
250
251 /// Like [`Self::extend_with_tt()`], but makes sure the new tokens will never be
252 /// joint with whatever comes after them.
253 pub fn extend_with_tt_alone(&mut self, tt: TokenTreesView<'_, S>) {
254 if let Some((last, before_last)) = tt.0.split_last() {
255 self.token_trees.reserve(tt.0.len());
256 self.token_trees.extend(before_last.iter().cloned());
257 let last = if let TokenTree::Leaf(Leaf::Punct(last)) = last {
258 let mut last = *last;
259 last.spacing = Spacing::Alone;
260 TokenTree::Leaf(Leaf::Punct(last))
261 } else {
262 last.clone()
263 };
264 self.token_trees.push(last);
132#[rust_analyzer::macro_style(braces)]
133macro_rules! dispatch_ref {
134 (
135 match $scrutinee:expr => $tt:ident => $body:expr
136 ) => {
137 match $scrutinee {
138 $crate::TokenTreesReprRef::SpanStorage32($tt) => $body,
139 $crate::TokenTreesReprRef::SpanStorage64($tt) => $body,
140 $crate::TokenTreesReprRef::SpanStorage96($tt) => $body,
265141 }
266 }
267
268 pub fn expected_delimiters(&self) -> impl Iterator<Item = &Delimiter<S>> {
269 self.unclosed_subtree_indices.iter().rev().map(|&subtree_idx| {
270 let TokenTree::Subtree(subtree) = &self.token_trees[subtree_idx] else {
271 unreachable!("unclosed token tree is always a subtree")
272 };
273 &subtree.delimiter
274 })
275 }
142 };
143}
144use dispatch_ref;
276145
277 /// Builds, and remove the top subtree if it has only one subtree child.
278 pub fn build_skip_top_subtree(mut self) -> TopSubtree<S> {
279 let top_tts = TokenTreesView::new(&self.token_trees[1..]);
280 match top_tts.try_into_subtree() {
281 Some(_) => {
282 assert!(
283 self.unclosed_subtree_indices.is_empty(),
284 "attempt to build an unbalanced `TopSubtreeBuilder`"
285 );
286 TopSubtree(self.token_trees.drain(1..).collect())
146#[derive(Clone, Copy)]
147enum TokenTreesReprRef<'a> {
148 SpanStorage32(&'a [crate::storage::TokenTree<crate::storage::SpanStorage32>]),
149 SpanStorage64(&'a [crate::storage::TokenTree<crate::storage::SpanStorage64>]),
150 SpanStorage96(&'a [crate::storage::TokenTree<crate::storage::SpanStorage96>]),
151}
152
153impl<'a> TokenTreesReprRef<'a> {
154 #[inline]
155 fn get<I>(&self, index: I) -> Option<Self>
156 where
157 I: SliceIndex<
158 [crate::storage::TokenTree<crate::storage::SpanStorage32>],
159 Output = [crate::storage::TokenTree<crate::storage::SpanStorage32>],
160 >,
161 I: SliceIndex<
162 [crate::storage::TokenTree<crate::storage::SpanStorage64>],
163 Output = [crate::storage::TokenTree<crate::storage::SpanStorage64>],
164 >,
165 I: SliceIndex<
166 [crate::storage::TokenTree<crate::storage::SpanStorage96>],
167 Output = [crate::storage::TokenTree<crate::storage::SpanStorage96>],
168 >,
169 {
170 Some(match self {
171 TokenTreesReprRef::SpanStorage32(tt) => {
172 TokenTreesReprRef::SpanStorage32(tt.get(index)?)
287173 }
288 None => self.build(),
289 }
290 }
291
292 pub fn build(mut self) -> TopSubtree<S> {
293 assert!(
294 self.unclosed_subtree_indices.is_empty(),
295 "attempt to build an unbalanced `TopSubtreeBuilder`"
296 );
297 let total_len = self.token_trees.len() as u32;
298 let TokenTree::Subtree(top_subtree) = &mut self.token_trees[0] else {
299 unreachable!("first token tree is always a subtree");
300 };
301 top_subtree.len = total_len - 1;
302 TopSubtree(self.token_trees.into_boxed_slice())
303 }
304
305 pub fn restore_point(&self) -> SubtreeBuilderRestorePoint {
306 SubtreeBuilderRestorePoint {
307 unclosed_subtree_indices_len: self.unclosed_subtree_indices.len(),
308 token_trees_len: self.token_trees.len(),
309 last_closed_subtree: self.last_closed_subtree,
310 }
311 }
312
313 pub fn restore(&mut self, restore_point: SubtreeBuilderRestorePoint) {
314 self.unclosed_subtree_indices.truncate(restore_point.unclosed_subtree_indices_len);
315 self.token_trees.truncate(restore_point.token_trees_len);
316 self.last_closed_subtree = restore_point.last_closed_subtree;
174 TokenTreesReprRef::SpanStorage64(tt) => {
175 TokenTreesReprRef::SpanStorage64(tt.get(index)?)
176 }
177 TokenTreesReprRef::SpanStorage96(tt) => {
178 TokenTreesReprRef::SpanStorage96(tt.get(index)?)
179 }
180 })
317181 }
318182}
319183
320184#[derive(Clone, Copy)]
321pub struct SubtreeBuilderRestorePoint {
322 unclosed_subtree_indices_len: usize,
323 token_trees_len: usize,
324 last_closed_subtree: Option<usize>,
185pub struct TokenTreesView<'a> {
186 repr: TokenTreesReprRef<'a>,
187 span_parts: &'a [CompressedSpanPart],
325188}
326189
327#[derive(Clone, Copy)]
328pub struct TokenTreesView<'a, S>(&'a [TokenTree<S>]);
329
330impl<'a, S: Copy> TokenTreesView<'a, S> {
331 pub fn new(tts: &'a [TokenTree<S>]) -> Self {
332 if cfg!(debug_assertions) {
333 tts.iter().enumerate().for_each(|(idx, tt)| {
334 if let TokenTree::Subtree(tt) = &tt {
335 // `<` and not `<=` because `Subtree.len` does not include the subtree node itself.
336 debug_assert!(
337 idx + tt.usize_len() < tts.len(),
338 "`TokenTreeView::new()` was given a cut-in-half list"
339 );
340 }
341 });
342 }
343 Self(tts)
190impl<'a> TokenTreesView<'a> {
191 pub fn empty() -> Self {
192 Self { repr: TokenTreesReprRef::SpanStorage32(&[]), span_parts: &[] }
344193 }
345194
346 pub fn iter(&self) -> TtIter<'a, S> {
347 TtIter::new(self.0)
195 pub fn iter(&self) -> TtIter<'a> {
196 TtIter::new(*self)
348197 }
349198
350 pub fn cursor(&self) -> Cursor<'a, S> {
351 Cursor::new(self.0)
199 pub fn cursor(&self) -> Cursor<'a> {
200 Cursor::new(*self)
352201 }
353202
354203 pub fn len(&self) -> usize {
355 self.0.len()
204 dispatch_ref! {
205 match self.repr => tt => tt.len()
206 }
356207 }
357208
358209 pub fn is_empty(&self) -> bool {
359 self.0.is_empty()
210 self.len() == 0
360211 }
361212
362 pub fn try_into_subtree(self) -> Option<SubtreeView<'a, S>> {
363 if let Some(TokenTree::Subtree(subtree)) = self.0.first()
364 && subtree.usize_len() == (self.0.len() - 1)
365 {
366 return Some(SubtreeView::new(self.0));
367 }
368 None
213 pub fn try_into_subtree(self) -> Option<SubtreeView<'a>> {
214 let is_subtree = dispatch_ref! {
215 match self.repr => tt => matches!(
216 tt.first(),
217 Some(crate::storage::TokenTree::Subtree { len, .. }) if (*len as usize) == (tt.len() - 1)
218 )
219 };
220 if is_subtree { Some(SubtreeView(self)) } else { None }
369221 }
370222
371 pub fn strip_invisible(self) -> TokenTreesView<'a, S> {
223 pub fn strip_invisible(self) -> TokenTreesView<'a> {
372224 self.try_into_subtree().map(|subtree| subtree.strip_invisible()).unwrap_or(self)
373225 }
374226
375 /// This returns a **flat** structure of tokens (subtrees will be represented by a single node
376 /// preceding their children), so it isn't suited for most use cases, only for matching leaves
377 /// at the beginning/end with no subtrees before them. If you need a structured pass, use [`TtIter`].
378 pub fn flat_tokens(&self) -> &'a [TokenTree<S>] {
379 self.0
380 }
381
382227 pub fn split(
383228 self,
384 mut split_fn: impl FnMut(TtElement<'a, S>) -> bool,
385 ) -> impl Iterator<Item = TokenTreesView<'a, S>> {
229 mut split_fn: impl FnMut(TtElement<'a>) -> bool,
230 ) -> impl Iterator<Item = TokenTreesView<'a>> {
386231 let mut subtree_iter = self.iter();
387232 let mut need_to_yield_even_if_empty = true;
388233
......@@ -404,9 +249,29 @@ impl<'a, S: Copy> TokenTreesView<'a, S> {
404249 Some(result)
405250 })
406251 }
252
253 pub fn first_span(&self) -> Option<Span> {
254 Some(dispatch_ref! {
255 match self.repr => tt => tt.first()?.first_span().span(self.span_parts)
256 })
257 }
258
259 pub fn last_span(&self) -> Option<Span> {
260 Some(dispatch_ref! {
261 match self.repr => tt => tt.last()?.last_span().span(self.span_parts)
262 })
263 }
264
265 pub fn iter_flat_tokens(self) -> impl ExactSizeIterator<Item = TokenTree> + use<'a> {
266 (0..self.len()).map(move |idx| {
267 dispatch_ref! {
268 match self.repr => tt => tt[idx].to_api(self.span_parts)
269 }
270 })
271 }
407272}
408273
409impl<S: fmt::Debug + Copy> fmt::Debug for TokenTreesView<'_, S> {
274impl fmt::Debug for TokenTreesView<'_> {
410275 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
411276 let mut iter = self.iter();
412277 while let Some(tt) = iter.next() {
......@@ -419,14 +284,14 @@ impl<S: fmt::Debug + Copy> fmt::Debug for TokenTreesView<'_, S> {
419284 }
420285}
421286
422impl<S: Copy> fmt::Display for TokenTreesView<'_, S> {
287impl fmt::Display for TokenTreesView<'_> {
423288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
424289 return token_trees_display(f, self.iter());
425290
426 fn subtree_display<S>(
427 subtree: &Subtree<S>,
291 fn subtree_display(
292 subtree: &Subtree,
428293 f: &mut fmt::Formatter<'_>,
429 iter: TtIter<'_, S>,
294 iter: TtIter<'_>,
430295 ) -> fmt::Result {
431296 let (l, r) = match subtree.delimiter.kind {
432297 DelimiterKind::Parenthesis => ("(", ")"),
......@@ -440,7 +305,7 @@ impl<S: Copy> fmt::Display for TokenTreesView<'_, S> {
440305 Ok(())
441306 }
442307
443 fn token_trees_display<S>(f: &mut fmt::Formatter<'_>, iter: TtIter<'_, S>) -> fmt::Result {
308 fn token_trees_display(f: &mut fmt::Formatter<'_>, iter: TtIter<'_>) -> fmt::Result {
444309 let mut needs_space = false;
445310 for child in iter {
446311 if needs_space {
......@@ -451,11 +316,11 @@ impl<S: Copy> fmt::Display for TokenTreesView<'_, S> {
451316 match child {
452317 TtElement::Leaf(Leaf::Punct(p)) => {
453318 needs_space = p.spacing == Spacing::Alone;
454 fmt::Display::fmt(p, f)?;
319 fmt::Display::fmt(&p, f)?;
455320 }
456 TtElement::Leaf(leaf) => fmt::Display::fmt(leaf, f)?,
321 TtElement::Leaf(leaf) => fmt::Display::fmt(&leaf, f)?,
457322 TtElement::Subtree(subtree, subtree_iter) => {
458 subtree_display(subtree, f, subtree_iter)?
323 subtree_display(&subtree, f, subtree_iter)?
459324 }
460325 }
461326 }
......@@ -466,70 +331,80 @@ impl<S: Copy> fmt::Display for TokenTreesView<'_, S> {
466331
467332#[derive(Clone, Copy)]
468333// Invariant: always starts with `Subtree` that covers the entire thing.
469pub struct SubtreeView<'a, S>(&'a [TokenTree<S>]);
334pub struct SubtreeView<'a>(TokenTreesView<'a>);
470335
471impl<'a, S: Copy> SubtreeView<'a, S> {
472 pub fn new(tts: &'a [TokenTree<S>]) -> Self {
473 if cfg!(debug_assertions) {
474 let TokenTree::Subtree(subtree) = &tts[0] else {
475 panic!("first token tree must be a subtree in `SubtreeView`");
476 };
477 assert_eq!(
478 subtree.usize_len(),
479 tts.len() - 1,
480 "subtree must cover the entire `SubtreeView`"
481 );
482 }
483 Self(tts)
484 }
485
486 pub fn as_token_trees(self) -> TokenTreesView<'a, S> {
487 TokenTreesView::new(self.0)
336impl<'a> SubtreeView<'a> {
337 pub fn as_token_trees(self) -> TokenTreesView<'a> {
338 self.0
488339 }
489340
490 pub fn iter(&self) -> TtIter<'a, S> {
491 TtIter::new(&self.0[1..])
341 pub fn iter(&self) -> TtIter<'a> {
342 self.token_trees().iter()
492343 }
493344
494 pub fn top_subtree(&self) -> &'a Subtree<S> {
495 let TokenTree::Subtree(subtree) = &self.0[0] else {
496 unreachable!("the first token tree is always the top subtree");
497 };
498 subtree
345 pub fn top_subtree(&self) -> Subtree {
346 dispatch_ref! {
347 match self.0.repr => tt => {
348 let crate::storage::TokenTree::Subtree { len, delim_kind, open_span, close_span } =
349 &tt[0]
350 else {
351 unreachable!("the first token tree is always the top subtree");
352 };
353 Subtree {
354 delimiter: Delimiter {
355 open: open_span.span(self.0.span_parts),
356 close: close_span.span(self.0.span_parts),
357 kind: *delim_kind,
358 },
359 len: *len,
360 }
361 }
362 }
499363 }
500364
501 pub fn strip_invisible(&self) -> TokenTreesView<'a, S> {
365 pub fn strip_invisible(&self) -> TokenTreesView<'a> {
502366 if self.top_subtree().delimiter.kind == DelimiterKind::Invisible {
503 TokenTreesView::new(&self.0[1..])
367 self.token_trees()
504368 } else {
505 TokenTreesView::new(self.0)
369 self.0
506370 }
507371 }
508372
509 pub fn token_trees(&self) -> TokenTreesView<'a, S> {
510 TokenTreesView::new(&self.0[1..])
373 pub fn token_trees(&self) -> TokenTreesView<'a> {
374 let repr = match self.0.repr {
375 TokenTreesReprRef::SpanStorage32(token_trees) => {
376 TokenTreesReprRef::SpanStorage32(&token_trees[1..])
377 }
378 TokenTreesReprRef::SpanStorage64(token_trees) => {
379 TokenTreesReprRef::SpanStorage64(&token_trees[1..])
380 }
381 TokenTreesReprRef::SpanStorage96(token_trees) => {
382 TokenTreesReprRef::SpanStorage96(&token_trees[1..])
383 }
384 };
385 TokenTreesView { repr, ..self.0 }
511386 }
512387}
513388
514impl<S: fmt::Debug + Copy> fmt::Debug for SubtreeView<'_, S> {
389impl fmt::Debug for SubtreeView<'_> {
515390 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
516 fmt::Debug::fmt(&TokenTreesView(self.0), f)
391 fmt::Debug::fmt(&self.0, f)
517392 }
518393}
519394
520impl<S: Copy> fmt::Display for SubtreeView<'_, S> {
395impl fmt::Display for SubtreeView<'_> {
521396 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
522 fmt::Display::fmt(&TokenTreesView(self.0), f)
397 fmt::Display::fmt(&self.0, f)
523398 }
524399}
525400
526401#[derive(Debug, Copy, Clone, PartialEq)]
527pub struct DelimSpan<S> {
528 pub open: S,
529 pub close: S,
402pub struct DelimSpan {
403 pub open: Span,
404 pub close: Span,
530405}
531406
532impl<Span: Copy> DelimSpan<Span> {
407impl DelimSpan {
533408 pub fn from_single(sp: Span) -> Self {
534409 DelimSpan { open: sp, close: sp }
535410 }
......@@ -539,22 +414,22 @@ impl<Span: Copy> DelimSpan<Span> {
539414 }
540415}
541416#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
542pub struct Delimiter<S> {
543 pub open: S,
544 pub close: S,
417pub struct Delimiter {
418 pub open: Span,
419 pub close: Span,
545420 pub kind: DelimiterKind,
546421}
547422
548impl<S: Copy> Delimiter<S> {
549 pub const fn invisible_spanned(span: S) -> Self {
423impl Delimiter {
424 pub const fn invisible_spanned(span: Span) -> Self {
550425 Delimiter { open: span, close: span, kind: DelimiterKind::Invisible }
551426 }
552427
553 pub const fn invisible_delim_spanned(span: DelimSpan<S>) -> Self {
428 pub const fn invisible_delim_spanned(span: DelimSpan) -> Self {
554429 Delimiter { open: span.open, close: span.close, kind: DelimiterKind::Invisible }
555430 }
556431
557 pub fn delim_span(&self) -> DelimSpan<S> {
432 pub fn delim_span(&self) -> DelimSpan {
558433 DelimSpan { open: self.open, close: self.close }
559434 }
560435}
......@@ -568,18 +443,57 @@ pub enum DelimiterKind {
568443}
569444
570445#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571pub struct Literal<S> {
572 // escaped
573 pub symbol: Symbol,
574 pub span: S,
446pub struct Literal {
447 /// Escaped, text then suffix concatenated.
448 pub text_and_suffix: Symbol,
449 pub span: Span,
575450 pub kind: LitKind,
576 pub suffix: Option<Symbol>,
451 pub suffix_len: u8,
452}
453
454impl Literal {
455 #[inline]
456 pub fn text_and_suffix(&self) -> (&str, &str) {
457 let text_and_suffix = self.text_and_suffix.as_str();
458 text_and_suffix.split_at(text_and_suffix.len() - usize::from(self.suffix_len))
459 }
460
461 #[inline]
462 pub fn text(&self) -> &str {
463 self.text_and_suffix().0
464 }
465
466 #[inline]
467 pub fn suffix(&self) -> &str {
468 self.text_and_suffix().1
469 }
470
471 pub fn new(text: &str, span: Span, kind: LitKind, suffix: &str) -> Self {
472 const MAX_INLINE_CAPACITY: usize = 30;
473 let text_and_suffix = if suffix.is_empty() {
474 Symbol::intern(text)
475 } else if (text.len() + suffix.len()) < MAX_INLINE_CAPACITY {
476 let mut text_and_suffix = ArrayString::<MAX_INLINE_CAPACITY>::new();
477 text_and_suffix.push_str(text);
478 text_and_suffix.push_str(suffix);
479 Symbol::intern(&text_and_suffix)
480 } else {
481 let mut text_and_suffix = String::with_capacity(text.len() + suffix.len());
482 text_and_suffix.push_str(text);
483 text_and_suffix.push_str(suffix);
484 Symbol::intern(&text_and_suffix)
485 };
486
487 Self { text_and_suffix, span, kind, suffix_len: suffix.len().try_into().unwrap() }
488 }
489
490 #[inline]
491 pub fn new_no_suffix(text: &str, span: Span, kind: LitKind) -> Self {
492 Self { text_and_suffix: Symbol::intern(text), span, kind, suffix_len: 0 }
493 }
577494}
578495
579pub fn token_to_literal<S>(text: &str, span: S) -> Literal<S>
580where
581 S: Copy,
582{
496pub fn token_to_literal(text: &str, span: Span) -> Literal {
583497 use rustc_lexer::LiteralKind;
584498
585499 let token = rustc_lexer::tokenize(text, rustc_lexer::FrontmatterAllowed::No).next_tuple();
......@@ -588,12 +502,7 @@ where
588502 ..
589503 },)) = token
590504 else {
591 return Literal {
592 span,
593 symbol: Symbol::intern(text),
594 kind: LitKind::Err(()),
595 suffix: None,
596 };
505 return Literal::new_no_suffix(text, span, LitKind::Err(()));
597506 };
598507
599508 let (kind, start_offset, end_offset) = match kind {
......@@ -624,27 +533,22 @@ where
624533 let (lit, suffix) = text.split_at(suffix_start as usize);
625534 let lit = &lit[start_offset..lit.len() - end_offset];
626535 let suffix = match suffix {
627 "" | "_" => None,
536 "" | "_" => "",
628537 // ill-suffixed literals
629538 _ if !matches!(kind, LitKind::Integer | LitKind::Float | LitKind::Err(_)) => {
630 return Literal {
631 span,
632 symbol: Symbol::intern(text),
633 kind: LitKind::Err(()),
634 suffix: None,
635 };
539 return Literal::new_no_suffix(text, span, LitKind::Err(()));
636540 }
637 suffix => Some(Symbol::intern(suffix)),
541 suffix => suffix,
638542 };
639543
640 Literal { span, symbol: Symbol::intern(lit), kind, suffix }
544 Literal::new(lit, span, kind, suffix)
641545}
642546
643547#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
644pub struct Punct<S> {
548pub struct Punct {
645549 pub char: char,
646550 pub spacing: Spacing,
647 pub span: S,
551 pub span: Span,
648552}
649553
650554/// Indicates whether a token can join with the following token to form a
......@@ -709,25 +613,25 @@ pub enum Spacing {
709613
710614/// Identifier or keyword.
711615#[derive(Debug, Clone, PartialEq, Eq, Hash)]
712pub struct Ident<S> {
616pub struct Ident {
713617 pub sym: Symbol,
714 pub span: S,
618 pub span: Span,
715619 pub is_raw: IdentIsRaw,
716620}
717621
718impl<S> Ident<S> {
719 pub fn new(text: &str, span: S) -> Self {
622impl Ident {
623 pub fn new(text: &str, span: Span) -> Self {
720624 // let raw_stripped = IdentIsRaw::split_from_symbol(text.as_ref());
721625 let (is_raw, text) = IdentIsRaw::split_from_symbol(text);
722626 Ident { sym: Symbol::intern(text), span, is_raw }
723627 }
724628}
725629
726fn print_debug_subtree<S: fmt::Debug>(
630fn print_debug_subtree(
727631 f: &mut fmt::Formatter<'_>,
728 subtree: &Subtree<S>,
632 subtree: &Subtree,
729633 level: usize,
730 iter: TtIter<'_, S>,
634 iter: TtIter<'_>,
731635) -> fmt::Result {
732636 let align = " ".repeat(level);
733637
......@@ -751,25 +655,14 @@ fn print_debug_subtree<S: fmt::Debug>(
751655 Ok(())
752656}
753657
754fn print_debug_token<S: fmt::Debug>(
755 f: &mut fmt::Formatter<'_>,
756 level: usize,
757 tt: TtElement<'_, S>,
758) -> fmt::Result {
658fn print_debug_token(f: &mut fmt::Formatter<'_>, level: usize, tt: TtElement<'_>) -> fmt::Result {
759659 let align = " ".repeat(level);
760660
761661 match tt {
762662 TtElement::Leaf(leaf) => match leaf {
763663 Leaf::Literal(lit) => {
764 write!(
765 f,
766 "{}LITERAL {:?} {}{} {:#?}",
767 align,
768 lit.kind,
769 lit.symbol,
770 lit.suffix.as_ref().map(|it| it.as_str()).unwrap_or(""),
771 lit.span
772 )?;
664 let (text, suffix) = lit.text_and_suffix();
665 write!(f, "{}LITERAL {:?} {}{} {:#?}", align, lit.kind, text, suffix, lit.span)?;
773666 }
774667 Leaf::Punct(punct) => {
775668 write!(
......@@ -793,26 +686,26 @@ fn print_debug_token<S: fmt::Debug>(
793686 }
794687 },
795688 TtElement::Subtree(subtree, subtree_iter) => {
796 print_debug_subtree(f, subtree, level, subtree_iter)?;
689 print_debug_subtree(f, &subtree, level, subtree_iter)?;
797690 }
798691 }
799692
800693 Ok(())
801694}
802695
803impl<S: fmt::Debug + Copy> fmt::Debug for TopSubtree<S> {
696impl fmt::Debug for TopSubtree {
804697 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
805698 fmt::Debug::fmt(&self.view(), f)
806699 }
807700}
808701
809impl<S: fmt::Display + Copy> fmt::Display for TopSubtree<S> {
702impl fmt::Display for TopSubtree {
810703 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
811704 fmt::Display::fmt(&self.view(), f)
812705 }
813706}
814707
815impl<S> fmt::Display for Leaf<S> {
708impl fmt::Display for Leaf {
816709 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
817710 match self {
818711 Leaf::Ident(it) => fmt::Display::fmt(it, f),
......@@ -822,155 +715,88 @@ impl<S> fmt::Display for Leaf<S> {
822715 }
823716}
824717
825impl<S> fmt::Display for Ident<S> {
718impl fmt::Display for Ident {
826719 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
827720 fmt::Display::fmt(&self.is_raw.as_str(), f)?;
828721 fmt::Display::fmt(&self.sym, f)
829722 }
830723}
831724
832impl<S> fmt::Display for Literal<S> {
725impl fmt::Display for Literal {
833726 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
727 let (text, suffix) = self.text_and_suffix();
834728 match self.kind {
835 LitKind::Byte => write!(f, "b'{}'", self.symbol),
836 LitKind::Char => write!(f, "'{}'", self.symbol),
837 LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", self.symbol),
838 LitKind::Str => write!(f, "\"{}\"", self.symbol),
839 LitKind::ByteStr => write!(f, "b\"{}\"", self.symbol),
840 LitKind::CStr => write!(f, "c\"{}\"", self.symbol),
729 LitKind::Byte => write!(f, "b'{}'", text),
730 LitKind::Char => write!(f, "'{}'", text),
731 LitKind::Integer | LitKind::Float | LitKind::Err(_) => write!(f, "{}", text),
732 LitKind::Str => write!(f, "\"{}\"", text),
733 LitKind::ByteStr => write!(f, "b\"{}\"", text),
734 LitKind::CStr => write!(f, "c\"{}\"", text),
841735 LitKind::StrRaw(num_of_hashes) => {
842736 let num_of_hashes = num_of_hashes as usize;
843 write!(
844 f,
845 r#"r{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
846 "",
847 text = self.symbol
848 )
737 write!(f, r#"r{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#, "", text = text)
849738 }
850739 LitKind::ByteStrRaw(num_of_hashes) => {
851740 let num_of_hashes = num_of_hashes as usize;
852 write!(
853 f,
854 r#"br{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
855 "",
856 text = self.symbol
857 )
741 write!(f, r#"br{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#, "", text = text)
858742 }
859743 LitKind::CStrRaw(num_of_hashes) => {
860744 let num_of_hashes = num_of_hashes as usize;
861 write!(
862 f,
863 r#"cr{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#,
864 "",
865 text = self.symbol
866 )
745 write!(f, r#"cr{0:#<num_of_hashes$}"{text}"{0:#<num_of_hashes$}"#, "", text = text)
867746 }
868747 }?;
869 if let Some(suffix) = &self.suffix {
870 write!(f, "{suffix}")?;
871 }
748 write!(f, "{suffix}")?;
872749 Ok(())
873750 }
874751}
875752
876impl<S> fmt::Display for Punct<S> {
753impl fmt::Display for Punct {
877754 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
878755 fmt::Display::fmt(&self.char, f)
879756 }
880757}
881758
882impl<S> Subtree<S> {
759impl Subtree {
883760 /// Count the number of tokens recursively
884761 pub fn count(&self) -> usize {
885762 self.usize_len()
886763 }
887764}
888765
889impl<S> TopSubtree<S> {
890 /// A simple line string used for debugging
891 pub fn subtree_as_debug_string(&self, subtree_idx: usize) -> String {
892 fn debug_subtree<S>(
893 output: &mut String,
894 subtree: &Subtree<S>,
895 iter: &mut std::slice::Iter<'_, TokenTree<S>>,
896 ) {
897 let delim = match subtree.delimiter.kind {
898 DelimiterKind::Brace => ("{", "}"),
899 DelimiterKind::Bracket => ("[", "]"),
900 DelimiterKind::Parenthesis => ("(", ")"),
901 DelimiterKind::Invisible => ("$", "$"),
902 };
903
904 output.push_str(delim.0);
905 let mut last = None;
906 let mut idx = 0;
907 while idx < subtree.len {
908 let child = iter.next().unwrap();
909 debug_token_tree(output, child, last, iter);
910 last = Some(child);
911 idx += 1;
912 }
913
914 output.push_str(delim.1);
915 }
916
917 fn debug_token_tree<S>(
918 output: &mut String,
919 tt: &TokenTree<S>,
920 last: Option<&TokenTree<S>>,
921 iter: &mut std::slice::Iter<'_, TokenTree<S>>,
922 ) {
923 match tt {
924 TokenTree::Leaf(it) => {
925 let s = match it {
926 Leaf::Literal(it) => it.symbol.to_string(),
927 Leaf::Punct(it) => it.char.to_string(),
928 Leaf::Ident(it) => format!("{}{}", it.is_raw.as_str(), it.sym),
929 };
930 match (it, last) {
931 (Leaf::Ident(_), Some(&TokenTree::Leaf(Leaf::Ident(_)))) => {
932 output.push(' ');
933 output.push_str(&s);
934 }
935 (Leaf::Punct(_), Some(TokenTree::Leaf(Leaf::Punct(punct)))) => {
936 if punct.spacing == Spacing::Alone {
937 output.push(' ');
938 output.push_str(&s);
939 } else {
940 output.push_str(&s);
941 }
942 }
943 _ => output.push_str(&s),
944 }
945 }
946 TokenTree::Subtree(it) => debug_subtree(output, it, iter),
947 }
948 }
766pub fn pretty(tkns: TokenTreesView<'_>) -> String {
767 return dispatch_ref! {
768 match tkns.repr => tt => pretty_impl(tt)
769 };
949770
950 let mut res = String::new();
951 debug_token_tree(
952 &mut res,
953 &self.0[subtree_idx],
954 None,
955 &mut self.0[subtree_idx + 1..].iter(),
956 );
957 res
958 }
959}
771 use crate::storage::TokenTree;
960772
961pub fn pretty<S>(mut tkns: &[TokenTree<S>]) -> String {
962 fn tokentree_to_text<S>(tkn: &TokenTree<S>, tkns: &mut &[TokenTree<S>]) -> String {
773 fn tokentree_to_text<S: SpanStorage>(tkn: &TokenTree<S>, tkns: &mut &[TokenTree<S>]) -> String {
963774 match tkn {
964 TokenTree::Leaf(Leaf::Ident(ident)) => {
965 format!("{}{}", ident.is_raw.as_str(), ident.sym)
775 TokenTree::Ident { sym, is_raw, .. } => format!("{}{}", is_raw.as_str(), sym),
776 &TokenTree::Literal { ref text_and_suffix, kind, suffix_len, span: _ } => {
777 format!(
778 "{}",
779 Literal {
780 text_and_suffix: text_and_suffix.clone(),
781 span: Span {
782 range: TextRange::empty(TextSize::new(0)),
783 anchor: span::SpanAnchor {
784 file_id: span::EditionedFileId::from_raw(0),
785 ast_id: span::FIXUP_ERASED_FILE_AST_ID_MARKER
786 },
787 ctx: span::SyntaxContext::root(span::Edition::Edition2015)
788 },
789 kind,
790 suffix_len
791 }
792 )
966793 }
967 TokenTree::Leaf(Leaf::Literal(literal)) => format!("{literal}"),
968 TokenTree::Leaf(Leaf::Punct(punct)) => format!("{}", punct.char),
969 TokenTree::Subtree(subtree) => {
970 let (subtree_content, rest) = tkns.split_at(subtree.usize_len());
971 let content = pretty(subtree_content);
794 TokenTree::Punct { char, .. } => format!("{}", char),
795 TokenTree::Subtree { len, delim_kind, .. } => {
796 let (subtree_content, rest) = tkns.split_at(*len as usize);
797 let content = pretty_impl(subtree_content);
972798 *tkns = rest;
973 let (open, close) = match subtree.delimiter.kind {
799 let (open, close) = match *delim_kind {
974800 DelimiterKind::Brace => ("{", "}"),
975801 DelimiterKind::Bracket => ("[", "]"),
976802 DelimiterKind::Parenthesis => ("(", ")"),
......@@ -981,18 +807,104 @@ pub fn pretty<S>(mut tkns: &[TokenTree<S>]) -> String {
981807 }
982808 }
983809
984 let mut last = String::new();
985 let mut last_to_joint = true;
810 fn pretty_impl<S: SpanStorage>(mut tkns: &[TokenTree<S>]) -> String {
811 let mut last = String::new();
812 let mut last_to_joint = true;
813
814 while let Some((tkn, rest)) = tkns.split_first() {
815 tkns = rest;
816 last = [last, tokentree_to_text(tkn, &mut tkns)].join(if last_to_joint {
817 ""
818 } else {
819 " "
820 });
821 last_to_joint = false;
822 if let TokenTree::Punct { spacing, .. } = tkn
823 && *spacing == Spacing::Joint
824 {
825 last_to_joint = true;
826 }
827 }
828 last
829 }
830}
831
832#[derive(Debug)]
833pub enum TransformTtAction<'a> {
834 Keep,
835 ReplaceWith(TokenTreesView<'a>),
836}
837
838impl TransformTtAction<'_> {
839 #[inline]
840 pub fn remove() -> Self {
841 Self::ReplaceWith(TokenTreesView::empty())
842 }
843}
844
845/// This function takes a token tree, and calls `callback` with each token tree in it.
846/// Then it does what the callback says: keeps the tt or replaces it with a (possibly empty)
847/// tts view.
848pub fn transform_tt<'b>(
849 tt: &mut TopSubtree,
850 mut callback: impl FnMut(TokenTree) -> TransformTtAction<'b>,
851) {
852 let mut tt_vec = tt.as_token_trees().iter_flat_tokens().collect::<Vec<_>>();
853
854 // We need to keep a stack of the currently open subtrees, because we need to update
855 // them if we change the number of items in them.
856 let mut subtrees_stack = Vec::new();
857 let mut i = 0;
858 while i < tt_vec.len() {
859 'pop_finished_subtrees: while let Some(&subtree_idx) = subtrees_stack.last() {
860 let TokenTree::Subtree(subtree) = &tt_vec[subtree_idx] else {
861 unreachable!("non-subtree on subtrees stack");
862 };
863 if i >= subtree_idx + 1 + subtree.usize_len() {
864 subtrees_stack.pop();
865 } else {
866 break 'pop_finished_subtrees;
867 }
868 }
869
870 let current = match &tt_vec[i] {
871 TokenTree::Leaf(leaf) => TokenTree::Leaf(match leaf {
872 Leaf::Literal(leaf) => Leaf::Literal(leaf.clone()),
873 Leaf::Punct(leaf) => Leaf::Punct(*leaf),
874 Leaf::Ident(leaf) => Leaf::Ident(leaf.clone()),
875 }),
876 TokenTree::Subtree(subtree) => TokenTree::Subtree(*subtree),
877 };
878 let action = callback(current);
879 match action {
880 TransformTtAction::Keep => {
881 // This cannot be shared with the replaced case, because then we may push the same subtree
882 // twice, and will update it twice which will lead to errors.
883 if let TokenTree::Subtree(_) = &tt_vec[i] {
884 subtrees_stack.push(i);
885 }
986886
987 while let Some((tkn, rest)) = tkns.split_first() {
988 tkns = rest;
989 last = [last, tokentree_to_text(tkn, &mut tkns)].join(if last_to_joint { "" } else { " " });
990 last_to_joint = false;
991 if let TokenTree::Leaf(Leaf::Punct(punct)) = tkn
992 && punct.spacing == Spacing::Joint
993 {
994 last_to_joint = true;
887 i += 1;
888 }
889 TransformTtAction::ReplaceWith(replacement) => {
890 let old_len = 1 + match &tt_vec[i] {
891 TokenTree::Leaf(_) => 0,
892 TokenTree::Subtree(subtree) => subtree.usize_len(),
893 };
894 let len_diff = replacement.len() as i64 - old_len as i64;
895 tt_vec.splice(i..i + old_len, replacement.iter_flat_tokens());
896 // Skip the newly inserted replacement, we don't want to visit it.
897 i += replacement.len();
898
899 for &subtree_idx in &subtrees_stack {
900 let TokenTree::Subtree(subtree) = &mut tt_vec[subtree_idx] else {
901 unreachable!("non-subtree on subtrees stack");
902 };
903 subtree.len = (i64::from(subtree.len) + len_diff).try_into().unwrap();
904 }
905 }
995906 }
996907 }
997 last
908
909 *tt = TopSubtree::from_serialized(tt_vec);
998910}
src/tools/rust-analyzer/crates/tt/src/storage.rs created+992
......@@ -0,0 +1,992 @@
1//! Spans are memory heavy, and we have a lot of token trees. Storing them straight
2//! will waste a lot of memory. So instead we implement a clever compression mechanism:
3//!
4//! A `TopSubtree` has a list of [`CompressedSpanPart`], which are the parts of a span
5//! that tend to be shared between tokens - namely, without the range. The main list
6//! of token trees is kept in one of three versions, where we use the smallest version
7//! we can for this tree:
8//!
9//! 1. In the most common version a span is just a `u32`. The bits are divided as follows:
10//! there are 4 bits that index into the [`CompressedSpanPart`] list. 20 bits
11//! store the range start, and 8 bits store the range length. In experiments,
12//! this accounts for 75%-85% of the spans.
13//! 2. In the second version a span is 64 bits. 32 bits for the range start, 16 bits
14//! for the range length, and 16 bits for the span parts index. This is used in
15//! less than 2% of all `TopSubtree`s, but they account for 15%-25% of the spans:
16//! those are mostly token tree munchers, that generate a lot of `SyntaxContext`s
17//! (because they recurse a lot), which is why they can't fit in the first version,
18//! and tend to generate a lot of code.
19//! 3. The third version is practically unused; 65,535 bytes for a token and 65,535
20//! unique span parts is more than enough for everybody. However, someone may still
21//! create a macro that requires more, therefore we have this version as a backup:
22//! it uses 96 bits, 32 for each of the range start, length and span parts index.
23
24use std::fmt;
25
26use intern::Symbol;
27use rustc_hash::FxBuildHasher;
28use span::{Span, SpanAnchor, SyntaxContext, TextRange, TextSize};
29
30use crate::{
31 DelimSpan, DelimiterKind, IdentIsRaw, LitKind, Spacing, SubtreeView, TokenTreesReprRef,
32 TokenTreesView, TtIter, dispatch_ref,
33};
34
35#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
36pub(crate) struct CompressedSpanPart {
37 pub(crate) anchor: SpanAnchor,
38 pub(crate) ctx: SyntaxContext,
39}
40
41impl CompressedSpanPart {
42 #[inline]
43 fn from_span(span: &Span) -> Self {
44 Self { anchor: span.anchor, ctx: span.ctx }
45 }
46
47 #[inline]
48 fn recombine(&self, range: TextRange) -> Span {
49 Span { range, anchor: self.anchor, ctx: self.ctx }
50 }
51}
52
53pub(crate) trait SpanStorage: Copy {
54 fn can_hold(text_range: TextRange, span_parts_index: usize) -> bool;
55
56 fn new(text_range: TextRange, span_parts_index: usize) -> Self;
57
58 fn text_range(&self) -> TextRange;
59
60 fn span_parts_index(&self) -> usize;
61
62 #[inline]
63 fn span(&self, span_parts: &[CompressedSpanPart]) -> Span {
64 span_parts[self.span_parts_index()].recombine(self.text_range())
65 }
66}
67
68#[inline]
69const fn n_bits_mask(n: u32) -> u32 {
70 (1 << n) - 1
71}
72
73#[derive(Clone, Copy, PartialEq, Eq, Hash)]
74pub(crate) struct SpanStorage32(u32);
75
76impl SpanStorage32 {
77 const SPAN_PARTS_BIT: u32 = 4;
78 const LEN_BITS: u32 = 8;
79 const OFFSET_BITS: u32 = 20;
80}
81
82const _: () = assert!(
83 (SpanStorage32::SPAN_PARTS_BIT + SpanStorage32::LEN_BITS + SpanStorage32::OFFSET_BITS)
84 == u32::BITS
85);
86
87impl SpanStorage for SpanStorage32 {
88 #[inline]
89 fn can_hold(text_range: TextRange, span_parts_index: usize) -> bool {
90 let offset = u32::from(text_range.start());
91 let len = u32::from(text_range.len());
92 let span_parts_index = span_parts_index as u32;
93
94 offset <= n_bits_mask(Self::OFFSET_BITS)
95 && len <= n_bits_mask(Self::LEN_BITS)
96 && span_parts_index <= n_bits_mask(Self::SPAN_PARTS_BIT)
97 }
98
99 #[inline]
100 fn new(text_range: TextRange, span_parts_index: usize) -> Self {
101 let offset = u32::from(text_range.start());
102 let len = u32::from(text_range.len());
103 let span_parts_index = span_parts_index as u32;
104
105 debug_assert!(offset <= n_bits_mask(Self::OFFSET_BITS));
106 debug_assert!(len <= n_bits_mask(Self::LEN_BITS));
107 debug_assert!(span_parts_index <= n_bits_mask(Self::SPAN_PARTS_BIT));
108
109 Self(
110 (offset << (Self::LEN_BITS + Self::SPAN_PARTS_BIT))
111 | (len << Self::SPAN_PARTS_BIT)
112 | span_parts_index,
113 )
114 }
115
116 #[inline]
117 fn text_range(&self) -> TextRange {
118 let offset = TextSize::new(self.0 >> (Self::SPAN_PARTS_BIT + Self::LEN_BITS));
119 let len = TextSize::new((self.0 >> Self::SPAN_PARTS_BIT) & n_bits_mask(Self::LEN_BITS));
120 TextRange::at(offset, len)
121 }
122
123 #[inline]
124 fn span_parts_index(&self) -> usize {
125 (self.0 & n_bits_mask(Self::SPAN_PARTS_BIT)) as usize
126 }
127}
128
129impl fmt::Debug for SpanStorage32 {
130 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
131 f.debug_struct("SpanStorage32")
132 .field("text_range", &self.text_range())
133 .field("span_parts_index", &self.span_parts_index())
134 .finish()
135 }
136}
137
138#[derive(Clone, Copy, PartialEq, Eq, Hash)]
139pub(crate) struct SpanStorage64 {
140 offset: u32,
141 len_and_parts: u32,
142}
143
144impl SpanStorage64 {
145 const SPAN_PARTS_BIT: u32 = 16;
146 const LEN_BITS: u32 = 16;
147}
148
149const _: () = assert!((SpanStorage64::SPAN_PARTS_BIT + SpanStorage64::LEN_BITS) == u32::BITS);
150
151impl SpanStorage for SpanStorage64 {
152 #[inline]
153 fn can_hold(text_range: TextRange, span_parts_index: usize) -> bool {
154 let len = u32::from(text_range.len());
155 let span_parts_index = span_parts_index as u32;
156
157 len <= n_bits_mask(Self::LEN_BITS) && span_parts_index <= n_bits_mask(Self::SPAN_PARTS_BIT)
158 }
159
160 #[inline]
161 fn new(text_range: TextRange, span_parts_index: usize) -> Self {
162 let offset = u32::from(text_range.start());
163 let len = u32::from(text_range.len());
164 let span_parts_index = span_parts_index as u32;
165
166 debug_assert!(len <= n_bits_mask(Self::LEN_BITS));
167 debug_assert!(span_parts_index <= n_bits_mask(Self::SPAN_PARTS_BIT));
168
169 Self { offset, len_and_parts: (len << Self::SPAN_PARTS_BIT) | span_parts_index }
170 }
171
172 #[inline]
173 fn text_range(&self) -> TextRange {
174 let offset = TextSize::new(self.offset);
175 let len = TextSize::new(self.len_and_parts >> Self::SPAN_PARTS_BIT);
176 TextRange::at(offset, len)
177 }
178
179 #[inline]
180 fn span_parts_index(&self) -> usize {
181 (self.len_and_parts & n_bits_mask(Self::SPAN_PARTS_BIT)) as usize
182 }
183}
184
185impl fmt::Debug for SpanStorage64 {
186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
187 f.debug_struct("SpanStorage64")
188 .field("text_range", &self.text_range())
189 .field("span_parts_index", &self.span_parts_index())
190 .finish()
191 }
192}
193
194impl From<SpanStorage32> for SpanStorage64 {
195 #[inline]
196 fn from(value: SpanStorage32) -> Self {
197 SpanStorage64::new(value.text_range(), value.span_parts_index())
198 }
199}
200
201#[derive(Clone, Copy, PartialEq, Eq, Hash)]
202pub(crate) struct SpanStorage96 {
203 offset: u32,
204 len: u32,
205 parts: u32,
206}
207
208impl SpanStorage for SpanStorage96 {
209 #[inline]
210 fn can_hold(_text_range: TextRange, _span_parts_index: usize) -> bool {
211 true
212 }
213
214 #[inline]
215 fn new(text_range: TextRange, span_parts_index: usize) -> Self {
216 let offset = u32::from(text_range.start());
217 let len = u32::from(text_range.len());
218 let span_parts_index = span_parts_index as u32;
219
220 Self { offset, len, parts: span_parts_index }
221 }
222
223 #[inline]
224 fn text_range(&self) -> TextRange {
225 let offset = TextSize::new(self.offset);
226 let len = TextSize::new(self.len);
227 TextRange::at(offset, len)
228 }
229
230 #[inline]
231 fn span_parts_index(&self) -> usize {
232 self.parts as usize
233 }
234}
235
236impl fmt::Debug for SpanStorage96 {
237 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
238 f.debug_struct("SpanStorage96")
239 .field("text_range", &self.text_range())
240 .field("span_parts_index", &self.span_parts_index())
241 .finish()
242 }
243}
244
245impl From<SpanStorage32> for SpanStorage96 {
246 #[inline]
247 fn from(value: SpanStorage32) -> Self {
248 SpanStorage96::new(value.text_range(), value.span_parts_index())
249 }
250}
251
252impl From<SpanStorage64> for SpanStorage96 {
253 #[inline]
254 fn from(value: SpanStorage64) -> Self {
255 SpanStorage96::new(value.text_range(), value.span_parts_index())
256 }
257}
258
259// We don't use structs or enum nesting here to save padding.
260#[derive(Debug, Clone, PartialEq, Eq, Hash)]
261pub(crate) enum TokenTree<S> {
262 Literal { text_and_suffix: Symbol, span: S, kind: LitKind, suffix_len: u8 },
263 Punct { char: char, spacing: Spacing, span: S },
264 Ident { sym: Symbol, span: S, is_raw: IdentIsRaw },
265 Subtree { len: u32, delim_kind: DelimiterKind, open_span: S, close_span: S },
266}
267
268impl<S: SpanStorage> TokenTree<S> {
269 #[inline]
270 pub(crate) fn first_span(&self) -> &S {
271 match self {
272 TokenTree::Literal { span, .. } => span,
273 TokenTree::Punct { span, .. } => span,
274 TokenTree::Ident { span, .. } => span,
275 TokenTree::Subtree { open_span, .. } => open_span,
276 }
277 }
278
279 #[inline]
280 pub(crate) fn last_span(&self) -> &S {
281 match self {
282 TokenTree::Literal { span, .. } => span,
283 TokenTree::Punct { span, .. } => span,
284 TokenTree::Ident { span, .. } => span,
285 TokenTree::Subtree { close_span, .. } => close_span,
286 }
287 }
288
289 #[inline]
290 pub(crate) fn to_api(&self, span_parts: &[CompressedSpanPart]) -> crate::TokenTree {
291 match self {
292 TokenTree::Literal { text_and_suffix, span, kind, suffix_len } => {
293 crate::TokenTree::Leaf(crate::Leaf::Literal(crate::Literal {
294 text_and_suffix: text_and_suffix.clone(),
295 span: span.span(span_parts),
296 kind: *kind,
297 suffix_len: *suffix_len,
298 }))
299 }
300 TokenTree::Punct { char, spacing, span } => {
301 crate::TokenTree::Leaf(crate::Leaf::Punct(crate::Punct {
302 char: *char,
303 spacing: *spacing,
304 span: span.span(span_parts),
305 }))
306 }
307 TokenTree::Ident { sym, span, is_raw } => {
308 crate::TokenTree::Leaf(crate::Leaf::Ident(crate::Ident {
309 sym: sym.clone(),
310 span: span.span(span_parts),
311 is_raw: *is_raw,
312 }))
313 }
314 TokenTree::Subtree { len, delim_kind, open_span, close_span } => {
315 crate::TokenTree::Subtree(crate::Subtree {
316 delimiter: crate::Delimiter {
317 open: open_span.span(span_parts),
318 close: close_span.span(span_parts),
319 kind: *delim_kind,
320 },
321 len: *len,
322 })
323 }
324 }
325 }
326
327 #[inline]
328 fn convert<U: From<S>>(self) -> TokenTree<U> {
329 match self {
330 TokenTree::Literal { text_and_suffix, span, kind, suffix_len } => {
331 TokenTree::Literal { text_and_suffix, span: span.into(), kind, suffix_len }
332 }
333 TokenTree::Punct { char, spacing, span } => {
334 TokenTree::Punct { char, spacing, span: span.into() }
335 }
336 TokenTree::Ident { sym, span, is_raw } => {
337 TokenTree::Ident { sym, span: span.into(), is_raw }
338 }
339 TokenTree::Subtree { len, delim_kind, open_span, close_span } => TokenTree::Subtree {
340 len,
341 delim_kind,
342 open_span: open_span.into(),
343 close_span: close_span.into(),
344 },
345 }
346 }
347}
348
349// This is used a lot, make sure it doesn't grow unintentionally.
350const _: () = {
351 assert!(size_of::<TokenTree<SpanStorage32>>() == 16);
352 assert!(size_of::<TokenTree<SpanStorage64>>() == 24);
353 assert!(size_of::<TokenTree<SpanStorage96>>() == 32);
354};
355
356#[rust_analyzer::macro_style(braces)]
357macro_rules! dispatch {
358 (
359 match $scrutinee:expr => $tt:ident => $body:expr
360 ) => {
361 match $scrutinee {
362 TopSubtreeRepr::SpanStorage32($tt) => $body,
363 TopSubtreeRepr::SpanStorage64($tt) => $body,
364 TopSubtreeRepr::SpanStorage96($tt) => $body,
365 }
366 };
367}
368
369#[derive(Debug, Clone, PartialEq, Eq, Hash)]
370pub(crate) enum TopSubtreeRepr {
371 SpanStorage32(Box<[TokenTree<SpanStorage32>]>),
372 SpanStorage64(Box<[TokenTree<SpanStorage64>]>),
373 SpanStorage96(Box<[TokenTree<SpanStorage96>]>),
374}
375
376#[derive(Clone, PartialEq, Eq, Hash)]
377pub struct TopSubtree {
378 repr: TopSubtreeRepr,
379 span_parts: Box<[CompressedSpanPart]>,
380}
381
382impl TopSubtree {
383 pub fn empty(span: DelimSpan) -> Self {
384 Self {
385 repr: TopSubtreeRepr::SpanStorage96(Box::new([TokenTree::Subtree {
386 len: 0,
387 delim_kind: DelimiterKind::Invisible,
388 open_span: SpanStorage96::new(span.open.range, 0),
389 close_span: SpanStorage96::new(span.close.range, 1),
390 }])),
391 span_parts: Box::new([
392 CompressedSpanPart::from_span(&span.open),
393 CompressedSpanPart::from_span(&span.close),
394 ]),
395 }
396 }
397
398 pub fn invisible_from_leaves<const N: usize>(
399 delim_span: Span,
400 leaves: [crate::Leaf; N],
401 ) -> Self {
402 let mut builder = TopSubtreeBuilder::new(crate::Delimiter::invisible_spanned(delim_span));
403 builder.extend(leaves);
404 builder.build()
405 }
406
407 pub fn from_token_trees(delimiter: crate::Delimiter, token_trees: TokenTreesView<'_>) -> Self {
408 let mut builder = TopSubtreeBuilder::new(delimiter);
409 builder.extend_with_tt(token_trees);
410 builder.build()
411 }
412
413 pub fn from_serialized(tt: Vec<crate::TokenTree>) -> Self {
414 let mut tt = tt.into_iter();
415 let Some(crate::TokenTree::Subtree(top_subtree)) = tt.next() else {
416 panic!("first must always come the top subtree")
417 };
418 let mut builder = TopSubtreeBuilder::new(top_subtree.delimiter);
419 for tt in tt {
420 builder.push_token_tree(tt);
421 }
422 builder.build()
423 }
424
425 pub fn from_subtree(subtree: SubtreeView<'_>) -> Self {
426 let mut builder = TopSubtreeBuilder::new(subtree.top_subtree().delimiter);
427 builder.extend_with_tt(subtree.token_trees());
428 builder.build()
429 }
430
431 pub fn view(&self) -> SubtreeView<'_> {
432 let repr = match &self.repr {
433 TopSubtreeRepr::SpanStorage32(token_trees) => {
434 TokenTreesReprRef::SpanStorage32(token_trees)
435 }
436 TopSubtreeRepr::SpanStorage64(token_trees) => {
437 TokenTreesReprRef::SpanStorage64(token_trees)
438 }
439 TopSubtreeRepr::SpanStorage96(token_trees) => {
440 TokenTreesReprRef::SpanStorage96(token_trees)
441 }
442 };
443 SubtreeView(TokenTreesView { repr, span_parts: &self.span_parts })
444 }
445
446 pub fn iter(&self) -> TtIter<'_> {
447 self.view().iter()
448 }
449
450 pub fn top_subtree(&self) -> crate::Subtree {
451 self.view().top_subtree()
452 }
453
454 pub fn set_top_subtree_delimiter_kind(&mut self, kind: DelimiterKind) {
455 dispatch! {
456 match &mut self.repr => tt => {
457 let TokenTree::Subtree { delim_kind, .. } = &mut tt[0] else {
458 unreachable!("the first token tree is always the top subtree");
459 };
460 *delim_kind = kind;
461 }
462 }
463 }
464
465 fn ensure_can_hold(&mut self, range: TextRange) {
466 fn can_hold<S: SpanStorage>(_: &[TokenTree<S>], range: TextRange) -> bool {
467 S::can_hold(range, 0)
468 }
469 let can_hold = dispatch! {
470 match &self.repr => tt => can_hold(tt, range)
471 };
472 if can_hold {
473 return;
474 }
475
476 // Otherwise, we do something very junky: recreate the entire tree. Hopefully this should be rare.
477 let mut builder = TopSubtreeBuilder::new(self.top_subtree().delimiter);
478 builder.extend_with_tt(self.token_trees());
479 builder.ensure_can_hold(range, 0);
480 *self = builder.build();
481 }
482
483 pub fn set_top_subtree_delimiter_span(&mut self, span: DelimSpan) {
484 self.ensure_can_hold(span.open.range);
485 self.ensure_can_hold(span.close.range);
486 fn do_it<S: SpanStorage>(tt: &mut [TokenTree<S>], span: DelimSpan) {
487 let TokenTree::Subtree { open_span, close_span, .. } = &mut tt[0] else {
488 unreachable!()
489 };
490 *open_span = S::new(span.open.range, 0);
491 *close_span = S::new(span.close.range, 0);
492 }
493 dispatch! {
494 match &mut self.repr => tt => do_it(tt, span)
495 }
496 self.span_parts[0] = CompressedSpanPart::from_span(&span.open);
497 self.span_parts[1] = CompressedSpanPart::from_span(&span.close);
498 }
499
500 /// Note: this cannot change spans.
501 pub fn set_token(&mut self, idx: usize, leaf: crate::Leaf) {
502 fn do_it<S: SpanStorage>(
503 tt: &mut [TokenTree<S>],
504 idx: usize,
505 span_parts: &[CompressedSpanPart],
506 leaf: crate::Leaf,
507 ) {
508 assert!(
509 !matches!(tt[idx], TokenTree::Subtree { .. }),
510 "`TopSubtree::set_token()` must be called on a leaf"
511 );
512 let existing_span_compressed = *tt[idx].first_span();
513 let existing_span = existing_span_compressed.span(span_parts);
514 assert_eq!(
515 *leaf.span(),
516 existing_span,
517 "`TopSubtree::set_token()` cannot change spans"
518 );
519 match leaf {
520 crate::Leaf::Literal(leaf) => {
521 tt[idx] = TokenTree::Literal {
522 text_and_suffix: leaf.text_and_suffix,
523 span: existing_span_compressed,
524 kind: leaf.kind,
525 suffix_len: leaf.suffix_len,
526 }
527 }
528 crate::Leaf::Punct(leaf) => {
529 tt[idx] = TokenTree::Punct {
530 char: leaf.char,
531 spacing: leaf.spacing,
532 span: existing_span_compressed,
533 }
534 }
535 crate::Leaf::Ident(leaf) => {
536 tt[idx] = TokenTree::Ident {
537 sym: leaf.sym,
538 span: existing_span_compressed,
539 is_raw: leaf.is_raw,
540 }
541 }
542 }
543 }
544 dispatch! {
545 match &mut self.repr => tt => do_it(tt, idx, &self.span_parts, leaf)
546 }
547 }
548
549 pub fn token_trees(&self) -> TokenTreesView<'_> {
550 self.view().token_trees()
551 }
552
553 pub fn as_token_trees(&self) -> TokenTreesView<'_> {
554 self.view().as_token_trees()
555 }
556
557 pub fn change_every_ast_id(&mut self, mut callback: impl FnMut(&mut span::ErasedFileAstId)) {
558 for span_part in &mut self.span_parts {
559 callback(&mut span_part.anchor.ast_id);
560 }
561 }
562}
563
564#[rust_analyzer::macro_style(braces)]
565macro_rules! dispatch_builder {
566 (
567 match $scrutinee:expr => $tt:ident => $body:expr
568 ) => {
569 match $scrutinee {
570 TopSubtreeBuilderRepr::SpanStorage32($tt) => $body,
571 TopSubtreeBuilderRepr::SpanStorage64($tt) => $body,
572 TopSubtreeBuilderRepr::SpanStorage96($tt) => $body,
573 }
574 };
575}
576
577#[derive(Debug, Clone, PartialEq, Eq, Hash)]
578enum TopSubtreeBuilderRepr {
579 SpanStorage32(Vec<TokenTree<SpanStorage32>>),
580 SpanStorage64(Vec<TokenTree<SpanStorage64>>),
581 SpanStorage96(Vec<TokenTree<SpanStorage96>>),
582}
583
584type FxIndexSet<K> = indexmap::IndexSet<K, FxBuildHasher>;
585
586/// In any tree, the first two subtree parts are reserved for the top subtree.
587///
588/// We do it because `TopSubtree` exposes an API to modify the top subtree, therefore it's more convenient
589/// this way, and it's unlikely to affect memory usage.
590const RESERVED_SPAN_PARTS_LEN: usize = 2;
591
592#[derive(Debug, Clone)]
593pub struct TopSubtreeBuilder {
594 unclosed_subtree_indices: Vec<usize>,
595 token_trees: TopSubtreeBuilderRepr,
596 span_parts: FxIndexSet<CompressedSpanPart>,
597 last_closed_subtree: Option<usize>,
598 /// We need to keep those because they are not inside `span_parts`, see [`RESERVED_SPAN_PARTS_LEN`].
599 top_subtree_spans: DelimSpan,
600}
601
602impl TopSubtreeBuilder {
603 pub fn new(top_delimiter: crate::Delimiter) -> Self {
604 let mut result = Self {
605 unclosed_subtree_indices: Vec::new(),
606 token_trees: TopSubtreeBuilderRepr::SpanStorage32(Vec::new()),
607 span_parts: FxIndexSet::default(),
608 last_closed_subtree: None,
609 top_subtree_spans: top_delimiter.delim_span(),
610 };
611 result.ensure_can_hold(top_delimiter.open.range, 0);
612 result.ensure_can_hold(top_delimiter.close.range, 1);
613 fn push_first<S: SpanStorage>(tt: &mut Vec<TokenTree<S>>, top_delimiter: crate::Delimiter) {
614 tt.push(TokenTree::Subtree {
615 len: 0,
616 delim_kind: top_delimiter.kind,
617 open_span: S::new(top_delimiter.open.range, 0),
618 close_span: S::new(top_delimiter.close.range, 1),
619 });
620 }
621 dispatch_builder! {
622 match &mut result.token_trees => tt => push_first(tt, top_delimiter)
623 }
624 result
625 }
626
627 fn span_part_index(&mut self, part: CompressedSpanPart) -> usize {
628 self.span_parts.insert_full(part).0 + RESERVED_SPAN_PARTS_LEN
629 }
630
631 fn switch_repr<T: SpanStorage, U: From<T>>(repr: &mut Vec<TokenTree<T>>) -> Vec<TokenTree<U>> {
632 let repr = std::mem::take(repr);
633 repr.into_iter().map(|tt| tt.convert()).collect()
634 }
635
636 /// Ensures we have a representation that can hold these values.
637 fn ensure_can_hold(&mut self, text_range: TextRange, span_parts_index: usize) {
638 match &mut self.token_trees {
639 TopSubtreeBuilderRepr::SpanStorage32(token_trees) => {
640 if SpanStorage32::can_hold(text_range, span_parts_index) {
641 // Can hold.
642 } else if SpanStorage64::can_hold(text_range, span_parts_index) {
643 self.token_trees =
644 TopSubtreeBuilderRepr::SpanStorage64(Self::switch_repr(token_trees));
645 } else {
646 self.token_trees =
647 TopSubtreeBuilderRepr::SpanStorage96(Self::switch_repr(token_trees));
648 }
649 }
650 TopSubtreeBuilderRepr::SpanStorage64(token_trees) => {
651 if SpanStorage64::can_hold(text_range, span_parts_index) {
652 // Can hold.
653 } else {
654 self.token_trees =
655 TopSubtreeBuilderRepr::SpanStorage96(Self::switch_repr(token_trees));
656 }
657 }
658 TopSubtreeBuilderRepr::SpanStorage96(_) => {
659 // Can hold anything.
660 }
661 }
662 }
663
664 /// Not to be exposed, this assumes the subtree's children will be filled in immediately.
665 fn push_subtree(&mut self, subtree: crate::Subtree) {
666 let open_span_parts_index =
667 self.span_part_index(CompressedSpanPart::from_span(&subtree.delimiter.open));
668 self.ensure_can_hold(subtree.delimiter.open.range, open_span_parts_index);
669 let close_span_parts_index =
670 self.span_part_index(CompressedSpanPart::from_span(&subtree.delimiter.close));
671 self.ensure_can_hold(subtree.delimiter.close.range, close_span_parts_index);
672 fn do_it<S: SpanStorage>(
673 tt: &mut Vec<TokenTree<S>>,
674 open_span_parts_index: usize,
675 close_span_parts_index: usize,
676 subtree: crate::Subtree,
677 ) {
678 let open_span = S::new(subtree.delimiter.open.range, open_span_parts_index);
679 let close_span = S::new(subtree.delimiter.close.range, close_span_parts_index);
680 tt.push(TokenTree::Subtree {
681 len: subtree.len,
682 delim_kind: subtree.delimiter.kind,
683 open_span,
684 close_span,
685 });
686 }
687 dispatch_builder! {
688 match &mut self.token_trees => tt => do_it(tt, open_span_parts_index, close_span_parts_index, subtree)
689 }
690 }
691
692 pub fn open(&mut self, delimiter_kind: DelimiterKind, open_span: Span) {
693 let span_parts_index = self.span_part_index(CompressedSpanPart::from_span(&open_span));
694 self.ensure_can_hold(open_span.range, span_parts_index);
695 fn do_it<S: SpanStorage>(
696 token_trees: &mut Vec<TokenTree<S>>,
697 delimiter_kind: DelimiterKind,
698 range: TextRange,
699 span_parts_index: usize,
700 ) -> usize {
701 let open_span = S::new(range, span_parts_index);
702 token_trees.push(TokenTree::Subtree {
703 len: 0,
704 delim_kind: delimiter_kind,
705 open_span,
706 close_span: open_span, // Will be overwritten on close.
707 });
708 token_trees.len() - 1
709 }
710 let subtree_idx = dispatch_builder! {
711 match &mut self.token_trees => tt => do_it(tt, delimiter_kind, open_span.range, span_parts_index)
712 };
713 self.unclosed_subtree_indices.push(subtree_idx);
714 }
715
716 pub fn close(&mut self, close_span: Span) {
717 let span_parts_index = self.span_part_index(CompressedSpanPart::from_span(&close_span));
718 let range = close_span.range;
719 self.ensure_can_hold(range, span_parts_index);
720
721 let last_unclosed_index = self
722 .unclosed_subtree_indices
723 .pop()
724 .expect("attempt to close a `tt::Subtree` when none is open");
725 fn do_it<S: SpanStorage>(
726 token_trees: &mut [TokenTree<S>],
727 last_unclosed_index: usize,
728 range: TextRange,
729 span_parts_index: usize,
730 ) {
731 let token_trees_len = token_trees.len();
732 let TokenTree::Subtree { len, delim_kind: _, open_span: _, close_span } =
733 &mut token_trees[last_unclosed_index]
734 else {
735 unreachable!("unclosed token tree is always a subtree");
736 };
737 *len = (token_trees_len - last_unclosed_index - 1) as u32;
738 *close_span = S::new(range, span_parts_index);
739 }
740 dispatch_builder! {
741 match &mut self.token_trees => tt => do_it(tt, last_unclosed_index, range, span_parts_index)
742 }
743 self.last_closed_subtree = Some(last_unclosed_index);
744 }
745
746 /// You cannot call this consecutively, it will only work once after close.
747 pub fn remove_last_subtree_if_invisible(&mut self) {
748 let Some(last_subtree_idx) = self.last_closed_subtree else { return };
749 fn do_it<S: SpanStorage>(tt: &mut Vec<TokenTree<S>>, last_subtree_idx: usize) {
750 if let TokenTree::Subtree { delim_kind: DelimiterKind::Invisible, .. } =
751 tt[last_subtree_idx]
752 {
753 tt.remove(last_subtree_idx);
754 }
755 }
756 dispatch_builder! {
757 match &mut self.token_trees => tt => do_it(tt, last_subtree_idx)
758 }
759 self.last_closed_subtree = None;
760 }
761
762 fn push_literal(&mut self, leaf: crate::Literal) {
763 let span_parts_index = self.span_part_index(CompressedSpanPart::from_span(&leaf.span));
764 let range = leaf.span.range;
765 self.ensure_can_hold(range, span_parts_index);
766 fn do_it<S: SpanStorage>(
767 tt: &mut Vec<TokenTree<S>>,
768 range: TextRange,
769 span_parts_index: usize,
770 leaf: crate::Literal,
771 ) {
772 tt.push(TokenTree::Literal {
773 text_and_suffix: leaf.text_and_suffix,
774 span: S::new(range, span_parts_index),
775 kind: leaf.kind,
776 suffix_len: leaf.suffix_len,
777 })
778 }
779 dispatch_builder! {
780 match &mut self.token_trees => tt => do_it(tt, range, span_parts_index, leaf)
781 }
782 }
783
784 fn push_punct(&mut self, leaf: crate::Punct) {
785 let span_parts_index = self.span_part_index(CompressedSpanPart::from_span(&leaf.span));
786 let range = leaf.span.range;
787 self.ensure_can_hold(range, span_parts_index);
788 fn do_it<S: SpanStorage>(
789 tt: &mut Vec<TokenTree<S>>,
790 range: TextRange,
791 span_parts_index: usize,
792 leaf: crate::Punct,
793 ) {
794 tt.push(TokenTree::Punct {
795 char: leaf.char,
796 spacing: leaf.spacing,
797 span: S::new(range, span_parts_index),
798 })
799 }
800 dispatch_builder! {
801 match &mut self.token_trees => tt => do_it(tt, range, span_parts_index, leaf)
802 }
803 }
804
805 fn push_ident(&mut self, leaf: crate::Ident) {
806 let span_parts_index = self.span_part_index(CompressedSpanPart::from_span(&leaf.span));
807 let range = leaf.span.range;
808 self.ensure_can_hold(range, span_parts_index);
809 fn do_it<S: SpanStorage>(
810 tt: &mut Vec<TokenTree<S>>,
811 range: TextRange,
812 span_parts_index: usize,
813 leaf: crate::Ident,
814 ) {
815 tt.push(TokenTree::Ident {
816 sym: leaf.sym,
817 span: S::new(range, span_parts_index),
818 is_raw: leaf.is_raw,
819 })
820 }
821 dispatch_builder! {
822 match &mut self.token_trees => tt => do_it(tt, range, span_parts_index, leaf)
823 }
824 }
825
826 pub fn push(&mut self, leaf: crate::Leaf) {
827 match leaf {
828 crate::Leaf::Literal(leaf) => self.push_literal(leaf),
829 crate::Leaf::Punct(leaf) => self.push_punct(leaf),
830 crate::Leaf::Ident(leaf) => self.push_ident(leaf),
831 }
832 }
833
834 fn push_token_tree(&mut self, tt: crate::TokenTree) {
835 match tt {
836 crate::TokenTree::Leaf(leaf) => self.push(leaf),
837 crate::TokenTree::Subtree(subtree) => self.push_subtree(subtree),
838 }
839 }
840
841 pub fn extend(&mut self, leaves: impl IntoIterator<Item = crate::Leaf>) {
842 leaves.into_iter().for_each(|leaf| self.push(leaf));
843 }
844
845 pub fn extend_with_tt(&mut self, tt: TokenTreesView<'_>) {
846 fn do_it<S: SpanStorage>(
847 this: &mut TopSubtreeBuilder,
848 tt: &[TokenTree<S>],
849 span_parts: &[CompressedSpanPart],
850 ) {
851 for tt in tt {
852 this.push_token_tree(tt.to_api(span_parts));
853 }
854 }
855 dispatch_ref! {
856 match tt.repr => tt_repr => do_it(self, tt_repr, tt.span_parts)
857 }
858 }
859
860 /// Like [`Self::extend_with_tt()`], but makes sure the new tokens will never be
861 /// joint with whatever comes after them.
862 pub fn extend_with_tt_alone(&mut self, tt: TokenTreesView<'_>) {
863 self.extend_with_tt(tt);
864 fn do_it<S: SpanStorage>(tt: &mut [TokenTree<S>]) {
865 if let Some(TokenTree::Punct { spacing, .. }) = tt.last_mut() {
866 *spacing = Spacing::Alone;
867 }
868 }
869 if !tt.is_empty() {
870 dispatch_builder! {
871 match &mut self.token_trees => tt => do_it(tt)
872 }
873 }
874 }
875
876 pub fn expected_delimiters(&self) -> impl Iterator<Item = DelimiterKind> {
877 self.unclosed_subtree_indices.iter().rev().map(|&subtree_idx| {
878 dispatch_builder! {
879 match &self.token_trees => tt => {
880 let TokenTree::Subtree { delim_kind, .. } = tt[subtree_idx] else {
881 unreachable!("unclosed token tree is always a subtree")
882 };
883 delim_kind
884 }
885 }
886 })
887 }
888
889 /// Builds, and remove the top subtree if it has only one subtree child.
890 pub fn build_skip_top_subtree(mut self) -> TopSubtree {
891 fn remove_first_if_needed<S: SpanStorage>(
892 tt: &mut Vec<TokenTree<S>>,
893 top_delim_span: &mut DelimSpan,
894 span_parts: &FxIndexSet<CompressedSpanPart>,
895 ) {
896 let tt_len = tt.len();
897 let Some(TokenTree::Subtree { len, open_span, close_span, .. }) = tt.get_mut(1) else {
898 return;
899 };
900 if (*len as usize) != (tt_len - 2) {
901 // Subtree does not cover the whole tree (minus 2; itself, and the top span).
902 return;
903 }
904
905 // Now we need to adjust the spans, because we assume that the first two spans are always reserved.
906 let top_open_span = span_parts
907 .get_index(open_span.span_parts_index() - RESERVED_SPAN_PARTS_LEN)
908 .unwrap()
909 .recombine(open_span.text_range());
910 let top_close_span = span_parts
911 .get_index(close_span.span_parts_index() - RESERVED_SPAN_PARTS_LEN)
912 .unwrap()
913 .recombine(close_span.text_range());
914 *top_delim_span = DelimSpan { open: top_open_span, close: top_close_span };
915 // Can't remove the top spans from the map, as maybe they're used by other things as well.
916 // Now we need to reencode the spans, because their parts index changed:
917 *open_span = S::new(open_span.text_range(), 0);
918 *close_span = S::new(close_span.text_range(), 1);
919
920 tt.remove(0);
921 }
922 dispatch_builder! {
923 match &mut self.token_trees => tt => remove_first_if_needed(tt, &mut self.top_subtree_spans, &self.span_parts)
924 }
925 self.build()
926 }
927
928 pub fn build(mut self) -> TopSubtree {
929 assert!(
930 self.unclosed_subtree_indices.is_empty(),
931 "attempt to build an unbalanced `TopSubtreeBuilder`"
932 );
933 fn finish_top_len<S: SpanStorage>(tt: &mut [TokenTree<S>]) {
934 let total_len = tt.len() as u32;
935 let TokenTree::Subtree { len, .. } = &mut tt[0] else {
936 unreachable!("first token tree is always a subtree");
937 };
938 *len = total_len - 1;
939 }
940 dispatch_builder! {
941 match &mut self.token_trees => tt => finish_top_len(tt)
942 }
943
944 let span_parts = [
945 CompressedSpanPart::from_span(&self.top_subtree_spans.open),
946 CompressedSpanPart::from_span(&self.top_subtree_spans.close),
947 ]
948 .into_iter()
949 .chain(self.span_parts.iter().copied())
950 .collect();
951
952 let repr = match self.token_trees {
953 TopSubtreeBuilderRepr::SpanStorage32(tt) => {
954 TopSubtreeRepr::SpanStorage32(tt.into_boxed_slice())
955 }
956 TopSubtreeBuilderRepr::SpanStorage64(tt) => {
957 TopSubtreeRepr::SpanStorage64(tt.into_boxed_slice())
958 }
959 TopSubtreeBuilderRepr::SpanStorage96(tt) => {
960 TopSubtreeRepr::SpanStorage96(tt.into_boxed_slice())
961 }
962 };
963
964 TopSubtree { repr, span_parts }
965 }
966
967 pub fn restore_point(&self) -> SubtreeBuilderRestorePoint {
968 let token_trees_len = dispatch_builder! {
969 match &self.token_trees => tt => tt.len()
970 };
971 SubtreeBuilderRestorePoint {
972 unclosed_subtree_indices_len: self.unclosed_subtree_indices.len(),
973 token_trees_len,
974 last_closed_subtree: self.last_closed_subtree,
975 }
976 }
977
978 pub fn restore(&mut self, restore_point: SubtreeBuilderRestorePoint) {
979 self.unclosed_subtree_indices.truncate(restore_point.unclosed_subtree_indices_len);
980 dispatch_builder! {
981 match &mut self.token_trees => tt => tt.truncate(restore_point.token_trees_len)
982 }
983 self.last_closed_subtree = restore_point.last_closed_subtree;
984 }
985}
986
987#[derive(Clone, Copy)]
988pub struct SubtreeBuilderRestorePoint {
989 unclosed_subtree_indices_len: usize,
990 token_trees_len: usize,
991 last_closed_subtree: Option<usize>,
992}
src/tools/rust-analyzer/docs/book/src/configuration_generated.md+57-11
......@@ -635,17 +635,6 @@ Default: `"client"`
635635Controls file watching implementation.
636636
637637
638## rust-analyzer.gc.frequency {#gc.frequency}
639
640Default: `1000`
641
642This config controls the frequency in which rust-analyzer will perform its internal Garbage
643Collection. It is specified in revisions, roughly equivalent to number of changes. The default
644is 1000.
645
646Setting a smaller value may help limit peak memory usage at the expense of speed.
647
648
649638## rust-analyzer.gotoImplementations.filterAdjacentDerives {#gotoImplementations.filterAdjacentDerives}
650639
651640Default: `false`
......@@ -1352,6 +1341,32 @@ Default: `false`
13521341Exclude tests from find-all-references and call-hierarchy.
13531342
13541343
1344## rust-analyzer.rename.showConflicts {#rename.showConflicts}
1345
1346Default: `true`
1347
1348Whether to warn when a rename will cause conflicts (change the meaning of the code).
1349
1350
1351## rust-analyzer.runnables.bench.command {#runnables.bench.command}
1352
1353Default: `"bench"`
1354
1355Subcommand used for bench runnables instead of `bench`.
1356
1357
1358## rust-analyzer.runnables.bench.overrideCommand {#runnables.bench.overrideCommand}
1359
1360Default: `null`
1361
1362Override the command used for bench runnables.
1363The first element of the array should be the program to execute (for example, `cargo`).
1364
1365Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
1366replace the package name, target option (such as `--bin` or `--example`), the target name and
1367the test name (name of test function or test mod path).
1368
1369
13551370## rust-analyzer.runnables.command {#runnables.command}
13561371
13571372Default: `null`
......@@ -1359,6 +1374,18 @@ Default: `null`
13591374Command to be executed instead of 'cargo' for runnables.
13601375
13611376
1377## rust-analyzer.runnables.doctest.overrideCommand {#runnables.doctest.overrideCommand}
1378
1379Default: `null`
1380
1381Override the command used for bench runnables.
1382The first element of the array should be the program to execute (for example, `cargo`).
1383
1384Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
1385replace the package name, target option (such as `--bin` or `--example`), the target name and
1386the test name (name of test function or test mod path).
1387
1388
13621389## rust-analyzer.runnables.extraArgs {#runnables.extraArgs}
13631390
13641391Default: `[]`
......@@ -1385,6 +1412,25 @@ they will end up being interpreted as options to
13851412[`rustc`’s built-in test harness (“libtest”)](https://doc.rust-lang.org/rustc/tests/index.html#cli-arguments).
13861413
13871414
1415## rust-analyzer.runnables.test.command {#runnables.test.command}
1416
1417Default: `"test"`
1418
1419Subcommand used for test runnables instead of `test`.
1420
1421
1422## rust-analyzer.runnables.test.overrideCommand {#runnables.test.overrideCommand}
1423
1424Default: `null`
1425
1426Override the command used for test runnables.
1427The first element of the array should be the program to execute (for example, `cargo`).
1428
1429Use the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically
1430replace the package name, target option (such as `--bin` or `--example`), the target name and
1431the test name (name of test function or test mod path).
1432
1433
13881434## rust-analyzer.rustc.source {#rustc.source}
13891435
13901436Default: `null`
src/tools/rust-analyzer/docs/book/src/contributing/architecture.md+1-1
......@@ -10,7 +10,7 @@ See also these implementation-related blog posts:
1010
1111* <https://rust-analyzer.github.io/blog/2019/11/13/find-usages.html>
1212* <https://rust-analyzer.github.io/blog/2020/07/20/three-architectures-for-responsive-ide.html>
13* <https://rust-analyzer.github.io/blog/2020/09/16/challeging-LR-parsing.html>
13* <https://rust-analyzer.github.io/blog/2020/09/16/challenging-LR-parsing.html>
1414* <https://rust-analyzer.github.io/blog/2020/09/28/how-to-make-a-light-bulb.html>
1515* <https://rust-analyzer.github.io/blog/2020/10/24/introducing-ungrammar.html>
1616
src/tools/rust-analyzer/editors/code/package.json+78-11
......@@ -1632,17 +1632,6 @@
16321632 }
16331633 }
16341634 },
1635 {
1636 "title": "Gc",
1637 "properties": {
1638 "rust-analyzer.gc.frequency": {
1639 "markdownDescription": "This config controls the frequency in which rust-analyzer will perform its internal Garbage\nCollection. It is specified in revisions, roughly equivalent to number of changes. The default\nis 1000.\n\nSetting a smaller value may help limit peak memory usage at the expense of speed.",
1640 "default": 1000,
1641 "type": "integer",
1642 "minimum": 0
1643 }
1644 }
1645 },
16461635 {
16471636 "title": "Goto Implementations",
16481637 "properties": {
......@@ -2827,6 +2816,42 @@
28272816 }
28282817 }
28292818 },
2819 {
2820 "title": "Rename",
2821 "properties": {
2822 "rust-analyzer.rename.showConflicts": {
2823 "markdownDescription": "Whether to warn when a rename will cause conflicts (change the meaning of the code).",
2824 "default": true,
2825 "type": "boolean"
2826 }
2827 }
2828 },
2829 {
2830 "title": "Runnables",
2831 "properties": {
2832 "rust-analyzer.runnables.bench.command": {
2833 "markdownDescription": "Subcommand used for bench runnables instead of `bench`.",
2834 "default": "bench",
2835 "type": "string"
2836 }
2837 }
2838 },
2839 {
2840 "title": "Runnables",
2841 "properties": {
2842 "rust-analyzer.runnables.bench.overrideCommand": {
2843 "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).",
2844 "default": null,
2845 "type": [
2846 "null",
2847 "array"
2848 ],
2849 "items": {
2850 "type": "string"
2851 }
2852 }
2853 }
2854 },
28302855 {
28312856 "title": "Runnables",
28322857 "properties": {
......@@ -2840,6 +2865,22 @@
28402865 }
28412866 }
28422867 },
2868 {
2869 "title": "Runnables",
2870 "properties": {
2871 "rust-analyzer.runnables.doctest.overrideCommand": {
2872 "markdownDescription": "Override the command used for bench runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).",
2873 "default": null,
2874 "type": [
2875 "null",
2876 "array"
2877 ],
2878 "items": {
2879 "type": "string"
2880 }
2881 }
2882 }
2883 },
28432884 {
28442885 "title": "Runnables",
28452886 "properties": {
......@@ -2868,6 +2909,32 @@
28682909 }
28692910 }
28702911 },
2912 {
2913 "title": "Runnables",
2914 "properties": {
2915 "rust-analyzer.runnables.test.command": {
2916 "markdownDescription": "Subcommand used for test runnables instead of `test`.",
2917 "default": "test",
2918 "type": "string"
2919 }
2920 }
2921 },
2922 {
2923 "title": "Runnables",
2924 "properties": {
2925 "rust-analyzer.runnables.test.overrideCommand": {
2926 "markdownDescription": "Override the command used for test runnables.\nThe first element of the array should be the program to execute (for example, `cargo`).\n\nUse the placeholders `${package}`, `${target_arg}`, `${target}`, `${test_name}` to dynamically\nreplace the package name, target option (such as `--bin` or `--example`), the target name and\nthe test name (name of test function or test mod path).",
2927 "default": null,
2928 "type": [
2929 "null",
2930 "array"
2931 ],
2932 "items": {
2933 "type": "string"
2934 }
2935 }
2936 }
2937 },
28712938 {
28722939 "title": "Rustc",
28732940 "properties": {
src/tools/rust-analyzer/editors/code/src/bootstrap.ts+8-3
......@@ -1,7 +1,7 @@
11import * as vscode from "vscode";
22import * as os from "os";
33import type { Config } from "./config";
4import { type Env, log, spawnAsync } from "./util";
4import { type Env, log, RUST_TOOLCHAIN_FILES, spawnAsync } from "./util";
55import type { PersistentState } from "./persistent_state";
66import { exec } from "child_process";
77import { TextDecoder } from "node:util";
......@@ -59,8 +59,12 @@ async function getServer(
5959 // otherwise check if there is a toolchain override for the current vscode workspace
6060 // and if the toolchain of this override has a rust-analyzer component
6161 // if so, use the rust-analyzer component
62 const toolchainUri = vscode.Uri.joinPath(workspaceFolder.uri, "rust-toolchain.toml");
63 if (await hasToolchainFileWithRaDeclared(toolchainUri)) {
62 // Check both rust-toolchain.toml and rust-toolchain files
63 for (const toolchainFile of RUST_TOOLCHAIN_FILES) {
64 const toolchainUri = vscode.Uri.joinPath(workspaceFolder.uri, toolchainFile);
65 if (!(await hasToolchainFileWithRaDeclared(toolchainUri))) {
66 continue;
67 }
6468 const res = await spawnAsync("rustup", ["which", "rust-analyzer"], {
6569 env: { ...process.env },
6670 cwd: workspaceFolder.uri.fsPath,
......@@ -71,6 +75,7 @@ async function getServer(
7175 res.stdout.trim(),
7276 raVersionResolver,
7377 );
78 break;
7479 }
7580 }
7681 }
src/tools/rust-analyzer/editors/code/src/client.ts+16-9
......@@ -30,17 +30,24 @@ export async function createClient(
3030 },
3131 async configuration(
3232 params: lc.ConfigurationParams,
33 token: vscode.CancellationToken,
34 next: lc.ConfigurationRequest.HandlerSignature,
33 _token: vscode.CancellationToken,
34 _next: lc.ConfigurationRequest.HandlerSignature,
3535 ) {
36 const resp = await next(params, token);
37 if (resp && Array.isArray(resp)) {
38 return resp.map((val) => {
39 return prepareVSCodeConfig(val);
40 });
41 } else {
42 return resp;
36 // The rust-analyzer LSP only ever asks for the "rust-analyzer"
37 // section, so we only need to support that. Instead of letting
38 // the vscode-languageclient handle it, use the `cfg` property
39 // in the config.
40 if (
41 params.items.length !== 1 ||
42 params.items[0]?.section !== "rust-analyzer" ||
43 params.items[0]?.scopeUri !== undefined
44 ) {
45 return new lc.ResponseError(
46 lc.ErrorCodes.InvalidParams,
47 'Only the "rust-analyzer" config section is supported.',
48 );
4349 }
50 return [prepareVSCodeConfig(config.cfg)];
4451 },
4552 },
4653 async handleDiagnostics(
src/tools/rust-analyzer/editors/code/src/ctx.ts+53-1
......@@ -1,10 +1,11 @@
11import * as vscode from "vscode";
2import type * as lc from "vscode-languageclient/node";
2import * as lc from "vscode-languageclient/node";
33import * as ra from "./lsp_ext";
44
55import { Config, prepareVSCodeConfig } from "./config";
66import { createClient } from "./client";
77import {
8 findRustToolchainFiles,
89 isCargoTomlEditor,
910 isDocumentInWorkspace,
1011 isRustDocument,
......@@ -266,6 +267,17 @@ export class Ctx implements RustAnalyzerExtensionApi {
266267 this.outputChannel!.show();
267268 }),
268269 );
270 this.pushClientCleanup(
271 this._client.onNotification(
272 lc.ShowMessageNotification.type,
273 async (params: lc.ShowMessageParams) => {
274 // When an MSRV warning is detected and a rust-toolchain file exists,
275 // show an additional message with actionable guidance about adding
276 // the rust-analyzer component.
277 await handleMsrvWarning(params.message);
278 },
279 ),
280 );
269281 }
270282 return this._client;
271283 }
......@@ -592,3 +604,43 @@ export interface Disposable {
592604
593605// eslint-disable-next-line @typescript-eslint/no-explicit-any
594606export type Cmd = (...args: any[]) => unknown;
607
608/**
609 * Pattern to detect MSRV warning messages from the rust-analyzer server.
610 */
611const MSRV_WARNING_PATTERN = /using an outdated toolchain version.*rust-analyzer only supports/is;
612
613/**
614 * Handles the MSRV warning by checking for rust-toolchain files and showing
615 * an enhanced message if found.
616 */
617export async function handleMsrvWarning(message: string): Promise<boolean> {
618 if (!MSRV_WARNING_PATTERN.test(message)) {
619 return false;
620 }
621
622 const toolchainFiles = await findRustToolchainFiles();
623 if (toolchainFiles.length === 0) {
624 return false;
625 }
626
627 const openFile = "Open rust-toolchain file";
628 const result = await vscode.window.showWarningMessage(
629 "Your workspace uses a rust-toolchain file with a toolchain too old for the extension shipped rust-analyzer to work properly. " +
630 "Consider adding the rust-analyzer component to the toolchain file to use a compatible rust-analyzer version. " +
631 "Add the following to your rust-toolchain file's `[toolchain]` section:\n" +
632 'components = ["rust-analyzer"]',
633 { modal: true },
634 openFile,
635 );
636
637 if (result === openFile) {
638 const fileToOpen = toolchainFiles[0];
639 if (fileToOpen) {
640 const document = await vscode.workspace.openTextDocument(fileToOpen);
641 await vscode.window.showTextDocument(document);
642 }
643 }
644
645 return true;
646}
src/tools/rust-analyzer/editors/code/src/util.ts+25
......@@ -328,3 +328,28 @@ export function normalizeDriveLetter(path: string, isWindowsOS: boolean = isWind
328328
329329 return path;
330330}
331
332export const RUST_TOOLCHAIN_FILES = ["rust-toolchain.toml", "rust-toolchain"] as const;
333
334export async function findRustToolchainFiles(): Promise<vscode.Uri[]> {
335 const found: vscode.Uri[] = [];
336 const workspaceFolders = vscode.workspace.workspaceFolders;
337 if (!workspaceFolders) {
338 return found;
339 }
340
341 for (const folder of workspaceFolders) {
342 for (const filename of RUST_TOOLCHAIN_FILES) {
343 const toolchainUri = vscode.Uri.joinPath(folder.uri, filename);
344 try {
345 await vscode.workspace.fs.stat(toolchainUri);
346 found.push(toolchainUri);
347 // Only add the first toolchain file found per workspace folder
348 break;
349 } catch {
350 // File doesn't exist, continue
351 }
352 }
353 }
354 return found;
355}
src/tools/rust-analyzer/rust-version+1-1
......@@ -1 +1 @@
10208ee09be465f69005a7a12c28d5eccac7d5f34
1e7d44143a12a526488e4f0c0d7ea8e62a4fe9354
tests/mir-opt/building/match/deref-patterns/string.foo.PreCodegen.after.mir+11-9
......@@ -7,10 +7,11 @@ fn foo(_1: Option<String>) -> i32 {
77 let mut _3: isize;
88 let mut _4: &std::string::String;
99 let mut _5: &str;
10 let mut _6: bool;
11 let _7: std::option::Option<std::string::String>;
10 let mut _6: &str;
11 let mut _7: bool;
12 let _8: std::option::Option<std::string::String>;
1213 scope 1 {
13 debug s => _7;
14 debug s => _8;
1415 }
1516
1617 bb0: {
......@@ -26,11 +27,12 @@ fn foo(_1: Option<String>) -> i32 {
2627 }
2728
2829 bb2: {
29 _6 = <str as PartialEq>::eq(copy _5, const "a") -> [return: bb3, unwind unreachable];
30 _6 = &(*_5);
31 _7 = <str as PartialEq>::eq(copy _6, const "a") -> [return: bb3, unwind unreachable];
3032 }
3133
3234 bb3: {
33 switchInt(move _6) -> [0: bb5, otherwise: bb4];
35 switchInt(move _7) -> [0: bb5, otherwise: bb4];
3436 }
3537
3638 bb4: {
......@@ -39,15 +41,15 @@ fn foo(_1: Option<String>) -> i32 {
3941 }
4042
4143 bb5: {
42 StorageLive(_7);
44 StorageLive(_8);
4345 _2 = const false;
44 _7 = move _1;
46 _8 = move _1;
4547 _0 = const 4321_i32;
46 drop(_7) -> [return: bb6, unwind unreachable];
48 drop(_8) -> [return: bb6, unwind unreachable];
4749 }
4850
4951 bb6: {
50 StorageDead(_7);
52 StorageDead(_8);
5153 goto -> bb7;
5254 }
5355
tests/mir-opt/building/match/deref-patterns/string.rs+2-1
......@@ -1,7 +1,8 @@
11// skip-filecheck
22//@ compile-flags: -Z mir-opt-level=0 -C panic=abort
33
4#![feature(string_deref_patterns)]
4#![feature(deref_patterns)]
5#![expect(incomplete_features)]
56#![crate_type = "lib"]
67
78// EMIT_MIR string.foo.PreCodegen.after.mir
tests/run-make/apple-deployment-target/rmake.rs+2-3
......@@ -169,9 +169,8 @@ fn main() {
169169
170170 // Test that all binaries in rlibs produced by `rustc` have the same version.
171171 // Regression test for https://github.com/rust-lang/rust/issues/128419.
172 let sysroot = rustc().print("sysroot").run().stdout_utf8();
173 let target_sysroot = path(sysroot.trim()).join("lib/rustlib").join(target()).join("lib");
174 let rlibs = shallow_find_files(&target_sysroot, |path| has_extension(path, "rlib"));
172 let sysroot_libs_dir = rustc().print("target-libdir").target(target()).run().stdout_utf8();
173 let rlibs = shallow_find_files(sysroot_libs_dir.trim(), |path| has_extension(path, "rlib"));
175174
176175 let output = cmd("otool").arg("-l").args(rlibs).run().stdout_utf8();
177176 let re = regex::Regex::new(r"(minos|version) ([0-9.]*)").unwrap();
tests/run-make/cdylib-dylib-linkage/rmake.rs+5-6
......@@ -16,24 +16,23 @@ use run_make_support::{
1616fn main() {
1717 rustc().arg("-Cprefer-dynamic").input("bar.rs").run();
1818 rustc().input("foo.rs").run();
19 let sysroot = rustc().print("sysroot").run().stdout_utf8();
20 let sysroot = sysroot.trim();
21 let target_sysroot = path(sysroot).join("lib/rustlib").join(target()).join("lib");
19 let sysroot_libs_dir = rustc().print("target-libdir").target(target()).run().stdout_utf8();
20 let sysroot_libs_dir = sysroot_libs_dir.trim();
2221 if is_windows_msvc() {
23 let mut libs = shallow_find_files(&target_sysroot, |path| {
22 let mut libs = shallow_find_files(sysroot_libs_dir, |path| {
2423 has_prefix(path, "libstd-") && has_suffix(path, ".dll.lib")
2524 });
2625 libs.push(path(msvc_import_dynamic_lib_name("foo")));
2726 libs.push(path(msvc_import_dynamic_lib_name("bar")));
2827 cc().input("foo.c").args(&libs).out_exe("foo").run();
2928 } else {
30 let stdlibs = shallow_find_files(&target_sysroot, |path| {
29 let stdlibs = shallow_find_files(sysroot_libs_dir, |path| {
3130 has_extension(path, dynamic_lib_extension()) && filename_contains(path, "std")
3231 });
3332 cc().input("foo.c")
3433 .args(&[dynamic_lib_name("foo"), dynamic_lib_name("bar")])
3534 .arg(stdlibs.get(0).unwrap())
36 .library_search_path(&target_sysroot)
35 .library_search_path(sysroot_libs_dir)
3736 .output(bin_name("foo"))
3837 .run();
3938 }
tests/run-make/libstd-no-protected/rmake.rs+2-4
......@@ -15,10 +15,8 @@ type SymbolTable<'data> = run_make_support::object::read::elf::SymbolTable<'data
1515
1616fn main() {
1717 // Find libstd-...rlib
18 let sysroot = rustc().print("sysroot").run().stdout_utf8();
19 let sysroot = sysroot.trim();
20 let target_sysroot = path(sysroot).join("lib/rustlib").join(target()).join("lib");
21 let mut libs = shallow_find_files(&target_sysroot, |path| {
18 let sysroot_libs_dir = rustc().print("target-libdir").target(target()).run().stdout_utf8();
19 let mut libs = shallow_find_files(sysroot_libs_dir.trim(), |path| {
2220 has_prefix(path, "libstd-") && has_suffix(path, ".rlib")
2321 });
2422 assert_eq!(libs.len(), 1);
tests/run-make/sysroot-crates-are-unstable/rmake.rs+2-2
......@@ -44,8 +44,8 @@ fn check_crate_is_unstable(cr: &Crate) {
4444}
4545
4646fn get_unstable_sysroot_crates() -> Vec<Crate> {
47 let sysroot = PathBuf::from(rustc().print("sysroot").run().stdout_utf8().trim());
48 let sysroot_libs_dir = sysroot.join("lib").join("rustlib").join(target()).join("lib");
47 let sysroot_libs_dir =
48 PathBuf::from(rustc().print("target-libdir").target(target()).run().stdout_utf8().trim());
4949 println!("Sysroot libs dir: {sysroot_libs_dir:?}");
5050
5151 // Generate a list of all library crates in the sysroot.
tests/ui/README.md-6
......@@ -380,12 +380,6 @@ These tests use the unstable command line option `query-dep-graph` to examine th
380380
381381Tests for `#[deprecated]` attribute and `deprecated_in_future` internal lint.
382382
383## `tests/ui/deref-patterns/`: `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`
384
385Tests for `#![feature(deref_patterns)]` and `#![feature(string_deref_patterns)]`. See [Deref patterns | The Unstable book](https://doc.rust-lang.org/nightly/unstable-book/language-features/deref-patterns.html).
386
387**FIXME**: May have some overlap with `tests/ui/pattern/deref-patterns`.
388
389383## `tests/ui/derived-errors/`: Derived Error Messages
390384
391385Tests for quality of diagnostics involving suppression of cascading errors in some cases to avoid overwhelming the user.
tests/ui/check-cfg/target_feature.stderr+1
......@@ -424,6 +424,7 @@ LL | cfg!(target_feature = "_UNEXPECTED_VALUE");
424424`zkn`
425425`zknd`
426426`zkne`
427`zkne_or_zknd`
427428`zknh`
428429`zkr`
429430`zks`
tests/ui/deref-patterns/basic.rs deleted-17
......@@ -1,17 +0,0 @@
1//@ run-pass
2//@ check-run-results
3#![feature(string_deref_patterns)]
4
5fn main() {
6 test(Some(String::from("42")));
7 test(Some(String::new()));
8 test(None);
9}
10
11fn test(o: Option<String>) {
12 match o {
13 Some("42") => println!("the answer"),
14 Some(_) => println!("something else?"),
15 None => println!("nil"),
16 }
17}
tests/ui/deref-patterns/basic.run.stdout deleted-3
......@@ -1,3 +0,0 @@
1the answer
2something else?
3nil
tests/ui/deref-patterns/default-infer.rs deleted-9
......@@ -1,9 +0,0 @@
1//@ check-pass
2#![feature(string_deref_patterns)]
3
4fn main() {
5 match <_ as Default>::default() {
6 "" => (),
7 _ => unreachable!(),
8 }
9}
tests/ui/deref-patterns/gate.rs deleted-7
......@@ -1,7 +0,0 @@
1// gate-test-string_deref_patterns
2fn main() {
3 match String::new() {
4 "" | _ => {}
5 //~^ ERROR mismatched types
6 }
7}
tests/ui/deref-patterns/gate.stderr deleted-11
......@@ -1,11 +0,0 @@
1error[E0308]: mismatched types
2 --> $DIR/gate.rs:4:9
3 |
4LL | match String::new() {
5 | ------------- this expression has type `String`
6LL | "" | _ => {}
7 | ^^ expected `String`, found `&str`
8
9error: aborting due to 1 previous error
10
11For more information about this error, try `rustc --explain E0308`.
tests/ui/deref-patterns/refs.rs deleted-18
......@@ -1,18 +0,0 @@
1//@ check-pass
2#![feature(string_deref_patterns)]
3
4fn foo(s: &String) -> i32 {
5 match *s {
6 "a" => 42,
7 _ => -1,
8 }
9}
10
11fn bar(s: Option<&&&&String>) -> i32 {
12 match s {
13 Some(&&&&"&&&&") => 1,
14 _ => -1,
15 }
16}
17
18fn main() {}
tests/ui/pattern/deref-patterns/basic.rs created+18
......@@ -0,0 +1,18 @@
1//@ run-pass
2//@ check-run-results
3#![feature(deref_patterns)]
4#![expect(incomplete_features)]
5
6fn main() {
7 test(Some(String::from("42")));
8 test(Some(String::new()));
9 test(None);
10}
11
12fn test(o: Option<String>) {
13 match o {
14 Some("42") => println!("the answer"),
15 Some(_) => println!("something else?"),
16 None => println!("nil"),
17 }
18}
tests/ui/pattern/deref-patterns/basic.run.stdout created+3
......@@ -0,0 +1,3 @@
1the answer
2something else?
3nil
tests/ui/pattern/deref-patterns/default-infer.rs created+10
......@@ -0,0 +1,10 @@
1//@ check-pass
2#![feature(deref_patterns)]
3#![expect(incomplete_features)]
4
5fn main() {
6 match <_ as Default>::default() {
7 "" => (),
8 _ => unreachable!(),
9 }
10}
tests/ui/pattern/deref-patterns/refs.rs created+19
......@@ -0,0 +1,19 @@
1//@ check-pass
2#![feature(deref_patterns)]
3#![expect(incomplete_features)]
4
5fn foo(s: &String) -> i32 {
6 match *s {
7 "a" => 42,
8 _ => -1,
9 }
10}
11
12fn bar(s: Option<&&&&String>) -> i32 {
13 match s {
14 Some(&&&&"&&&&") => 1,
15 _ => -1,
16 }
17}
18
19fn main() {}