mirror of
https://github.com/rust-lang/rust.git
synced 2026-04-27 18:57:42 +03:00
Auto merge of #141278 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer` r? `@ghost`
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
contact_links:
|
||||
- name: Questions regarding rust-analyzer
|
||||
url: https://github.com/rust-lang/rust-analyzer/discussions
|
||||
about: Please ask and answer questions here instead of opening an issue
|
||||
@@ -12,5 +12,3 @@ Troubleshooting guide: https://rust-analyzer.github.io/book/troubleshooting.html
|
||||
|
||||
Please try to provide information which will help us to fix the issue faster. Minimal reproducible examples with few dependencies are especially lovely <3.
|
||||
-->
|
||||
|
||||
This is a serious regression in nightly and it's important to fix it before the next release.
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
---
|
||||
name: Support Question
|
||||
about: A question regarding functionality of rust-analyzer.
|
||||
title: ''
|
||||
labels: 'C-support'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
+6
-6
@@ -18,9 +18,9 @@ jobs:
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
run: |
|
||||
rustup update --no-self-update stable
|
||||
rustup default stable
|
||||
rustup component add --toolchain stable rust-src
|
||||
rustup update --no-self-update beta
|
||||
rustup default beta
|
||||
rustup component add --toolchain beta rust-src
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
@@ -61,9 +61,9 @@ jobs:
|
||||
steps:
|
||||
- name: Install Rust toolchain
|
||||
run: |
|
||||
rustup update --no-self-update stable
|
||||
rustup default stable
|
||||
rustup component add --toolchain stable rust-src
|
||||
rustup update --no-self-update beta
|
||||
rustup default beta
|
||||
rustup component add --toolchain beta rust-src
|
||||
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
@@ -61,9 +61,9 @@ checksum = "ace50bade8e6234aa140d9a2f552bbee1db4d353f69b8217bc503490fc1a9f26"
|
||||
|
||||
[[package]]
|
||||
name = "backtrace"
|
||||
version = "0.3.74"
|
||||
version = "0.3.75"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8d82cb332cdfaed17ae235a638438ac4d4839913cc2af585c3c6746e8f8bee1a"
|
||||
checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002"
|
||||
dependencies = [
|
||||
"addr2line",
|
||||
"cfg-if",
|
||||
@@ -80,6 +80,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"cfg",
|
||||
"dashmap",
|
||||
"indexmap",
|
||||
"intern",
|
||||
"la-arena 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"query-group-macro",
|
||||
@@ -316,9 +317,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28"
|
||||
|
||||
[[package]]
|
||||
name = "ctrlc"
|
||||
version = "3.4.5"
|
||||
version = "3.4.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "90eeab0aa92f3f9b4e87f258c72b139c207d251f9cbc1080a0086b86a8870dd3"
|
||||
checksum = "46f93780a459b7d656ef7f071fe699c4d3d2cb201c4b24d085b6ddc505276e73"
|
||||
dependencies = [
|
||||
"nix",
|
||||
"windows-sys 0.59.0",
|
||||
@@ -472,9 +473,9 @@ checksum = "0ce7134b9999ecaf8bcd65542e436736ef32ddca1b3e06094cb6ec5755203b80"
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.1.0"
|
||||
version = "1.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "11faaf5a5236997af9848be0bef4db95824b1d534ebc64d0f0c6cf3e67bd38dc"
|
||||
checksum = "7ced92e76e966ca2fd84c8f7aa01a4aea65b0eb6648d72f7c8f3e2764a67fece"
|
||||
dependencies = [
|
||||
"crc32fast",
|
||||
"miniz_oxide",
|
||||
@@ -1010,9 +1011,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "indexmap"
|
||||
version = "2.8.0"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058"
|
||||
checksum = "cea70ddb795996207ad57735b50c5982d8844f38ba9ee5f1aedcfb708a2aa11e"
|
||||
dependencies = [
|
||||
"equivalent",
|
||||
"hashbrown 0.15.2",
|
||||
@@ -1123,12 +1124,12 @@ checksum = "d750af042f7ef4f724306de029d18836c26c1765a54a6a3f094cbd23a7267ffa"
|
||||
|
||||
[[package]]
|
||||
name = "libloading"
|
||||
version = "0.8.6"
|
||||
version = "0.8.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fc2f4eb4bc735547cfed7c0a4922cbd04a4655978c09b54f1f7b228750664c34"
|
||||
checksum = "6a793df0d7afeac54f95b471d3af7f0d4fb975699f972341a4b76988d49cdf0c"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"windows-targets 0.52.6",
|
||||
"windows-targets 0.53.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1358,9 +1359,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "nix"
|
||||
version = "0.29.0"
|
||||
version = "0.30.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46"
|
||||
checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"cfg-if",
|
||||
@@ -1640,14 +1641,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "process-wrap"
|
||||
version = "8.2.0"
|
||||
version = "8.2.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "d35f4dc9988d1326b065b4def5e950c3ed727aa03e3151b86cc9e2aec6b03f54"
|
||||
checksum = "a3ef4f2f0422f23a82ec9f628ea2acd12871c81a9362b02c43c1aa86acfc3ba1"
|
||||
dependencies = [
|
||||
"indexmap",
|
||||
"nix",
|
||||
"tracing",
|
||||
"windows 0.59.0",
|
||||
"windows 0.61.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1749,9 +1750,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_abi"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "912228bd8ed3beff1f6f9e5e2d4b37c0827ba3e2070060bf3858a311d0e29e30"
|
||||
checksum = "c33b8fa229789975647ca5426be432c7c327ebde89ab15889928185dbcee3230"
|
||||
dependencies = [
|
||||
"bitflags 2.9.0",
|
||||
"ra-ap-rustc_hashes",
|
||||
@@ -1761,18 +1762,18 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_hashes"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba520764daf057a9d963fa769f4762eaf87ac5d4900ae76195eeead64cd35afd"
|
||||
checksum = "0d68a3e389927002f552938a90b04787f6435f55b46fc5691360470d1cb2e99d"
|
||||
dependencies = [
|
||||
"rustc-stable-hash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b76b5f9ee55f2d0e5a65bea23f6d738893349ce8d3d17a6720933e647ab04978"
|
||||
checksum = "32502273df2838d0ca13f1c67e2a48feef940e591f9771869f07e2db2acede53"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index_macros",
|
||||
"smallvec",
|
||||
@@ -1780,9 +1781,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_index_macros"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddd972eb1face2fcaa0d94c01d97862fb955b5561d4f5932003bce8a6cadd8c6"
|
||||
checksum = "8a32f081864ae34c7ae6634edfa7a95ab9260ba85015e8b1d347580eda79d14f"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -1791,9 +1792,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_lexer"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ba3a9876456fb2521097deef33ddeac1c18260c8eafb68054d986f8b9d6ce9fa"
|
||||
checksum = "ed34c51974718c5bd90d876d1364d9725159fc8030c2382b9cb837034152ed68"
|
||||
dependencies = [
|
||||
"memchr",
|
||||
"unicode-properties",
|
||||
@@ -1802,9 +1803,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_parse_format"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8e85de58dfcc60a5f9d5ec0157a657e3f84abd8f22c8a0c4d707cfb42c9011f4"
|
||||
checksum = "ff0440e5d27facbf4ff13ea651e48c2f6e360b3dbfc56251b41d60719b965fb8"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_lexer",
|
||||
"rustc-literal-escaper",
|
||||
@@ -1812,9 +1813,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "ra-ap-rustc_pattern_analysis"
|
||||
version = "0.110.0"
|
||||
version = "0.113.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ceadf9db550db67deff7eff2e2765109b860c9d7e5bdfca144863020289c823d"
|
||||
checksum = "a6056efa57aba3aa0cc69a0bf1a8281624c23ad25b05748d11ebcd4668037bfc"
|
||||
dependencies = [
|
||||
"ra-ap-rustc_index",
|
||||
"rustc-hash 2.1.1",
|
||||
@@ -2228,6 +2229,7 @@ version = "0.0.0"
|
||||
dependencies = [
|
||||
"backtrace",
|
||||
"crossbeam-channel",
|
||||
"crossbeam-utils",
|
||||
"itertools 0.14.0",
|
||||
"jod-thread",
|
||||
"libc",
|
||||
@@ -2750,12 +2752,24 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows"
|
||||
version = "0.59.0"
|
||||
version = "0.61.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f919aee0a93304be7f62e8e5027811bbba96bcb1de84d6618be56e43f8a32a1"
|
||||
checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
|
||||
dependencies = [
|
||||
"windows-core 0.59.0",
|
||||
"windows-targets 0.53.0",
|
||||
"windows-collections",
|
||||
"windows-core 0.61.0",
|
||||
"windows-future",
|
||||
"windows-link",
|
||||
"windows-numerics",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-collections"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2773,15 +2787,25 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-core"
|
||||
version = "0.59.0"
|
||||
version = "0.61.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "810ce18ed2112484b0d4e15d022e5f598113e220c53e373fb31e67e21670c1ce"
|
||||
checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
|
||||
dependencies = [
|
||||
"windows-implement 0.59.0",
|
||||
"windows-interface 0.59.0",
|
||||
"windows-result 0.3.1",
|
||||
"windows-strings 0.3.1",
|
||||
"windows-targets 0.53.0",
|
||||
"windows-implement 0.60.0",
|
||||
"windows-interface 0.59.1",
|
||||
"windows-link",
|
||||
"windows-result 0.3.2",
|
||||
"windows-strings 0.4.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-future"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2797,9 +2821,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-implement"
|
||||
version = "0.59.0"
|
||||
version = "0.60.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "83577b051e2f49a058c308f17f273b570a6a758386fc291b5f6a934dd84e48c1"
|
||||
checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2819,9 +2843,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-interface"
|
||||
version = "0.59.0"
|
||||
version = "0.59.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "cb26fd936d991781ea39e87c3a27285081e3c0da5ca0fcbc02d368cc6f52ff01"
|
||||
checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -2830,9 +2854,19 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-link"
|
||||
version = "0.1.0"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6dccfd733ce2b1753b03b6d3c65edf020262ea35e20ccdf3e288043e6dd620e3"
|
||||
checksum = "76840935b766e1b0a05c0066835fb9ec80071d4c09a16f6bd5f7e655e3c14c38"
|
||||
|
||||
[[package]]
|
||||
name = "windows-numerics"
|
||||
version = "0.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
|
||||
dependencies = [
|
||||
"windows-core 0.61.0",
|
||||
"windows-link",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
@@ -2845,9 +2879,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-result"
|
||||
version = "0.3.1"
|
||||
version = "0.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "06374efe858fab7e4f881500e6e86ec8bc28f9462c47e5a9941a0142ad86b189"
|
||||
checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
@@ -2864,9 +2898,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "windows-strings"
|
||||
version = "0.3.1"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "87fa48cc5d406560701792be122a10132491cff9d0aeb23583cc2dcafc847319"
|
||||
checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
|
||||
dependencies = [
|
||||
"windows-link",
|
||||
]
|
||||
@@ -3230,17 +3264,14 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "zip"
|
||||
version = "2.4.2"
|
||||
version = "3.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "fabe6324e908f85a1c52063ce7aa26b68dcb7eb6dbc83a2d148403c9bc3eba50"
|
||||
checksum = "12598812502ed0105f607f941c386f43d441e00148fce9dec3ca5ffb0bde9308"
|
||||
dependencies = [
|
||||
"arbitrary",
|
||||
"crc32fast",
|
||||
"crossbeam-utils",
|
||||
"displaydoc",
|
||||
"flate2",
|
||||
"indexmap",
|
||||
"memchr",
|
||||
"thiserror 2.0.12",
|
||||
"time",
|
||||
]
|
||||
|
||||
@@ -85,11 +85,11 @@ vfs-notify = { path = "./crates/vfs-notify", version = "0.0.0" }
|
||||
vfs = { path = "./crates/vfs", version = "0.0.0" }
|
||||
edition = { path = "./crates/edition", version = "0.0.0" }
|
||||
|
||||
ra-ap-rustc_lexer = { version = "0.110", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.110", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.110", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.110", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.110", default-features = false }
|
||||
ra-ap-rustc_lexer = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_parse_format = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_index = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_abi = { version = "0.113", default-features = false }
|
||||
ra-ap-rustc_pattern_analysis = { version = "0.113", default-features = false }
|
||||
|
||||
# local crates that aren't published to crates.io. These should not have versions.
|
||||
|
||||
@@ -132,7 +132,10 @@ pulldown-cmark-to-cmark = "10.0.4"
|
||||
pulldown-cmark = { version = "0.9.6", default-features = false }
|
||||
rayon = "1.10.0"
|
||||
rowan = "=0.15.15"
|
||||
salsa = { version = "0.21.1", default-features = false, features = ["rayon","salsa_unstable"] }
|
||||
salsa = { version = "0.21.1", default-features = false, features = [
|
||||
"rayon",
|
||||
"salsa_unstable",
|
||||
] }
|
||||
salsa-macros = "0.21.1"
|
||||
semver = "1.0.26"
|
||||
serde = { version = "1.0.219" }
|
||||
|
||||
@@ -21,6 +21,7 @@ rustc-hash.workspace = true
|
||||
triomphe.workspace = true
|
||||
semver.workspace = true
|
||||
tracing.workspace = true
|
||||
indexmap.workspace = true
|
||||
|
||||
# local deps
|
||||
cfg.workspace = true
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
use dashmap::mapref::entry::Entry;
|
||||
use intern::Symbol;
|
||||
use la_arena::{Arena, Idx, RawIdx};
|
||||
use rustc_hash::{FxHashMap, FxHashSet, FxHasher};
|
||||
use rustc_hash::{FxBuildHasher, FxHashMap, FxHashSet, FxHasher};
|
||||
use salsa::{Durability, Setter};
|
||||
use span::Edition;
|
||||
use triomphe::Arc;
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
pub type ProcMacroPaths = FxHashMap<CrateBuilderId, Result<(String, AbsPathBuf), String>>;
|
||||
|
||||
type FxIndexSet<T> = indexmap::IndexSet<T, FxBuildHasher>;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
|
||||
pub struct SourceRootId(pub u32);
|
||||
|
||||
@@ -474,7 +476,9 @@ pub fn add_dep(
|
||||
}
|
||||
|
||||
pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
|
||||
let mut all_crates = Vec::with_capacity(self.arena.len());
|
||||
// For some reason in some repositories we have duplicate crates, so we use a set and not `Vec`.
|
||||
// We use an `IndexSet` because the list needs to be topologically sorted.
|
||||
let mut all_crates = FxIndexSet::with_capacity_and_hasher(self.arena.len(), FxBuildHasher);
|
||||
let mut visited = FxHashMap::default();
|
||||
let mut visited_root_files = FxHashSet::default();
|
||||
|
||||
@@ -494,9 +498,11 @@ pub fn set_in_db(self, db: &mut dyn RootQueryDb) -> CratesIdMap {
|
||||
);
|
||||
}
|
||||
|
||||
if **old_all_crates != *all_crates {
|
||||
if old_all_crates.len() != all_crates.len()
|
||||
|| old_all_crates.iter().any(|&krate| !all_crates.contains(&krate))
|
||||
{
|
||||
db.set_all_crates_with_durability(
|
||||
Arc::new(all_crates.into_boxed_slice()),
|
||||
Arc::new(Vec::from_iter(all_crates).into_boxed_slice()),
|
||||
Durability::MEDIUM,
|
||||
);
|
||||
}
|
||||
@@ -509,7 +515,7 @@ fn go(
|
||||
crates_map: &CratesMap,
|
||||
visited: &mut FxHashMap<CrateBuilderId, Crate>,
|
||||
visited_root_files: &mut FxHashSet<FileId>,
|
||||
all_crates: &mut Vec<Crate>,
|
||||
all_crates: &mut FxIndexSet<Crate>,
|
||||
source: CrateBuilderId,
|
||||
) -> Crate {
|
||||
if let Some(&crate_id) = visited.get(&source) {
|
||||
@@ -597,7 +603,7 @@ fn go(
|
||||
input
|
||||
}
|
||||
};
|
||||
all_crates.push(crate_input);
|
||||
all_crates.insert(crate_input);
|
||||
visited.insert(source, crate_input);
|
||||
crate_input
|
||||
}
|
||||
|
||||
@@ -24,8 +24,8 @@
|
||||
item_tree::{AttrOwner, ItemTree},
|
||||
lang_item::{self, LangItem},
|
||||
nameres::{
|
||||
DefMap, LocalDefMap,
|
||||
assoc::{ImplItems, TraitItems},
|
||||
crate_def_map,
|
||||
diagnostics::DefDiagnostics,
|
||||
},
|
||||
signatures::{
|
||||
@@ -111,16 +111,6 @@ pub trait DefDatabase: InternDatabase + ExpandDatabase + SourceDatabase {
|
||||
#[salsa::invoke(ItemTree::block_item_tree_query)]
|
||||
fn block_item_tree(&self, block_id: BlockId) -> Arc<ItemTree>;
|
||||
|
||||
#[salsa::invoke(DefMap::crate_local_def_map_query)]
|
||||
fn crate_local_def_map(&self, krate: Crate) -> (Arc<DefMap>, Arc<LocalDefMap>);
|
||||
|
||||
#[salsa::invoke(DefMap::crate_def_map_query)]
|
||||
fn crate_def_map(&self, krate: Crate) -> Arc<DefMap>;
|
||||
|
||||
/// Computes the block-level `DefMap`.
|
||||
#[salsa::invoke(DefMap::block_def_map_query)]
|
||||
fn block_def_map(&self, block: BlockId) -> Arc<DefMap>;
|
||||
|
||||
/// Turns a MacroId into a MacroDefId, describing the macro's definition post name resolution.
|
||||
#[salsa::invoke(macro_def)]
|
||||
fn macro_def(&self, m: MacroId) -> MacroDefId;
|
||||
@@ -363,7 +353,7 @@ fn include_macro_invoc(
|
||||
db: &dyn DefDatabase,
|
||||
krate: Crate,
|
||||
) -> Arc<[(MacroCallId, EditionedFileId)]> {
|
||||
db.crate_def_map(krate)
|
||||
crate_def_map(db, krate)
|
||||
.modules
|
||||
.values()
|
||||
.flat_map(|m| m.scope.iter_macro_invoc())
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
use smallvec::SmallVec;
|
||||
use span::{Edition, SyntaxContext};
|
||||
use syntax::{AstPtr, SyntaxNodePtr, ast};
|
||||
use triomphe::Arc;
|
||||
use tt::TextRange;
|
||||
|
||||
use crate::{
|
||||
@@ -30,7 +29,7 @@
|
||||
Array, AsmOperand, Binding, BindingId, Expr, ExprId, ExprOrPatId, Label, LabelId, Pat,
|
||||
PatId, RecordFieldPat, Statement,
|
||||
},
|
||||
nameres::DefMap,
|
||||
nameres::{DefMap, block_def_map},
|
||||
type_ref::{LifetimeRef, LifetimeRefId, PathId, TypeRef, TypeRefId},
|
||||
};
|
||||
|
||||
@@ -225,8 +224,8 @@ impl ExpressionStore {
|
||||
pub fn blocks<'a>(
|
||||
&'a self,
|
||||
db: &'a dyn DefDatabase,
|
||||
) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + 'a {
|
||||
self.block_scopes.iter().map(move |&block| (block, db.block_def_map(block)))
|
||||
) -> impl Iterator<Item = (BlockId, &'a DefMap)> + 'a {
|
||||
self.block_scopes.iter().map(move |&block| (block, block_def_map(db, block)))
|
||||
}
|
||||
|
||||
pub fn walk_bindings_in_pat(&self, pat_id: PatId, mut f: impl FnMut(BindingId)) {
|
||||
@@ -299,17 +298,16 @@ pub fn walk_child_exprs(&self, expr_id: ExprId, mut f: impl FnMut(ExprId)) {
|
||||
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
|
||||
AsmOperand::In { expr, .. }
|
||||
| AsmOperand::Out { expr: Some(expr), .. }
|
||||
| AsmOperand::InOut { expr, .. } => f(*expr),
|
||||
| AsmOperand::InOut { expr, .. }
|
||||
| AsmOperand::Const(expr)
|
||||
| AsmOperand::Label(expr) => f(*expr),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
f(*in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
f(*out_expr);
|
||||
}
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. }
|
||||
| AsmOperand::Const(_)
|
||||
| AsmOperand::Label(_)
|
||||
| AsmOperand::Sym(_) => (),
|
||||
AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
|
||||
}),
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
f(*condition);
|
||||
@@ -436,17 +434,16 @@ pub fn walk_child_exprs_without_pats(&self, expr_id: ExprId, mut f: impl FnMut(E
|
||||
Expr::InlineAsm(it) => it.operands.iter().for_each(|(_, op)| match op {
|
||||
AsmOperand::In { expr, .. }
|
||||
| AsmOperand::Out { expr: Some(expr), .. }
|
||||
| AsmOperand::InOut { expr, .. } => f(*expr),
|
||||
| AsmOperand::InOut { expr, .. }
|
||||
| AsmOperand::Const(expr)
|
||||
| AsmOperand::Label(expr) => f(*expr),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
f(*in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
f(*out_expr);
|
||||
}
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. }
|
||||
| AsmOperand::Const(_)
|
||||
| AsmOperand::Label(_)
|
||||
| AsmOperand::Sym(_) => (),
|
||||
AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
|
||||
}),
|
||||
Expr::If { condition, then_branch, else_branch } => {
|
||||
f(*condition);
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
item_scope::BuiltinShadowMode,
|
||||
item_tree::FieldsShape,
|
||||
lang_item::LangItem,
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs},
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs, block_def_map},
|
||||
type_ref::{
|
||||
ArrayType, ConstRef, FnType, LifetimeRef, LifetimeRefId, Mutability, PathId, Rawness,
|
||||
RefType, TraitBoundModifier, TraitRef, TypeBound, TypeRef, TypeRefId, UseArgRef,
|
||||
@@ -436,8 +436,8 @@ pub struct ExprCollector<'db> {
|
||||
db: &'db dyn DefDatabase,
|
||||
cfg_options: &'db CfgOptions,
|
||||
expander: Expander,
|
||||
def_map: Arc<DefMap>,
|
||||
local_def_map: Arc<LocalDefMap>,
|
||||
def_map: &'db DefMap,
|
||||
local_def_map: &'db LocalDefMap,
|
||||
module: ModuleId,
|
||||
pub store: ExpressionStoreBuilder,
|
||||
pub(crate) source_map: ExpressionStoreSourceMap,
|
||||
@@ -544,7 +544,7 @@ pub fn new(
|
||||
current_file_id: HirFileId,
|
||||
) -> ExprCollector<'_> {
|
||||
let (def_map, local_def_map) = module.local_def_map(db);
|
||||
let expander = Expander::new(db, current_file_id, &def_map);
|
||||
let expander = Expander::new(db, current_file_id, def_map);
|
||||
ExprCollector {
|
||||
db,
|
||||
cfg_options: module.krate().cfg_options(db),
|
||||
@@ -1947,7 +1947,7 @@ fn collect_macro_call<T, U>(
|
||||
let resolver = |path: &_| {
|
||||
self.def_map
|
||||
.resolve_path(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
self.db,
|
||||
module,
|
||||
path,
|
||||
@@ -2163,12 +2163,12 @@ fn collect_block_(
|
||||
};
|
||||
|
||||
let (module, def_map) =
|
||||
match block_id.map(|block_id| (self.db.block_def_map(block_id), block_id)) {
|
||||
match block_id.map(|block_id| (block_def_map(self.db, block_id), block_id)) {
|
||||
Some((def_map, block_id)) => {
|
||||
self.store.block_scopes.push(block_id);
|
||||
(def_map.module_id(DefMap::ROOT), def_map)
|
||||
}
|
||||
None => (self.module, self.def_map.clone()),
|
||||
None => (self.module, self.def_map),
|
||||
};
|
||||
let prev_def_map = mem::replace(&mut self.def_map, def_map);
|
||||
let prev_local_module = mem::replace(&mut self.module, module);
|
||||
@@ -2247,7 +2247,7 @@ fn collect_pat(&mut self, pat: ast::Pat, binding_list: &mut BindingList) -> PatI
|
||||
// This could also be a single-segment path pattern. To
|
||||
// decide that, we need to try resolving the name.
|
||||
let (resolved, _) = self.def_map.resolve_path(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
self.db,
|
||||
self.module.local_id,
|
||||
&name.clone().into(),
|
||||
|
||||
@@ -232,6 +232,14 @@ pub(super) fn lower_path(
|
||||
.with_borrow_mut(|map| map.extend(ast_segments.into_iter().zip(ast_segments_offset..)));
|
||||
}
|
||||
|
||||
if let Some(last_segment_args @ Some(GenericArgs { has_self_type: true, .. })) =
|
||||
generic_args.last_mut()
|
||||
{
|
||||
// Well-formed code cannot have `<T as Trait>` without an associated item after,
|
||||
// and this causes panics in hir-ty lowering.
|
||||
*last_segment_args = None;
|
||||
}
|
||||
|
||||
let mod_path = Interned::new(ModPath::from_segments(kind, segments));
|
||||
if type_anchor.is_none() && generic_args.is_empty() {
|
||||
return Some(Path::BarePath(mod_path));
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
use test_fixture::WithFixture;
|
||||
|
||||
use crate::{
|
||||
db::DefDatabase,
|
||||
expr_store::{
|
||||
ExpressionStore,
|
||||
lower::{
|
||||
@@ -14,13 +13,15 @@
|
||||
path::Path,
|
||||
pretty,
|
||||
},
|
||||
nameres::crate_def_map,
|
||||
test_db::TestDB,
|
||||
};
|
||||
|
||||
fn lower_path(path: ast::Path) -> (TestDB, ExpressionStore, Option<Path>) {
|
||||
let (db, file_id) = TestDB::with_single_file("");
|
||||
let krate = db.fetch_test_crate();
|
||||
let mut ctx = ExprCollector::new(&db, db.crate_def_map(krate).root_module_id(), file_id.into());
|
||||
let mut ctx =
|
||||
ExprCollector::new(&db, crate_def_map(&db, krate).root_module_id(), file_id.into());
|
||||
let lowered_path = ctx.lower_path(path, &mut ExprCollector::impl_trait_allocator);
|
||||
let store = ctx.store.finish();
|
||||
(db, store, lowered_path)
|
||||
|
||||
@@ -324,11 +324,13 @@ mod tests {
|
||||
use test_fixture::WithFixture;
|
||||
use test_utils::{assert_eq_text, extract_offset};
|
||||
|
||||
use crate::{FunctionId, ModuleDefId, db::DefDatabase, test_db::TestDB};
|
||||
use crate::{
|
||||
FunctionId, ModuleDefId, db::DefDatabase, nameres::crate_def_map, test_db::TestDB,
|
||||
};
|
||||
|
||||
fn find_function(db: &TestDB, file_id: FileId) -> FunctionId {
|
||||
let krate = db.test_crate();
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(db, krate);
|
||||
|
||||
let module = crate_def_map.modules_for_file(db, file_id).next().unwrap();
|
||||
let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
mod block;
|
||||
|
||||
use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, test_db::TestDB};
|
||||
use crate::{DefWithBodyId, ModuleDefId, hir::MatchArm, nameres::crate_def_map, test_db::TestDB};
|
||||
use expect_test::{Expect, expect};
|
||||
use la_arena::RawIdx;
|
||||
use test_fixture::WithFixture;
|
||||
use triomphe::Arc;
|
||||
|
||||
use super::super::*;
|
||||
|
||||
@@ -11,7 +12,7 @@ fn lower(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> (TestDB, Arc<Body>,
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
let mut fn_def = None;
|
||||
'outer: for (_, module) in def_map.modules() {
|
||||
for decl in module.scope.declarations() {
|
||||
|
||||
@@ -189,8 +189,8 @@ fn f() {
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
BlockId(3801) in BlockRelativeModuleId { block: Some(BlockId(3800)), local_id: Idx::<ModuleData>(1) }
|
||||
BlockId(3800) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
BlockId(3c01) in BlockRelativeModuleId { block: Some(BlockId(3c00)), local_id: Idx::<ModuleData>(1) }
|
||||
BlockId(3c00) in BlockRelativeModuleId { block: None, local_id: Idx::<ModuleData>(0) }
|
||||
crate scope
|
||||
"#]],
|
||||
);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use crate::{
|
||||
GenericDefId, ModuleDefId,
|
||||
expr_store::pretty::{print_function, print_struct},
|
||||
nameres::crate_def_map,
|
||||
test_db::TestDB,
|
||||
};
|
||||
use expect_test::{Expect, expect};
|
||||
@@ -12,7 +13,7 @@ fn lower_and_print(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expe
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
let mut defs = vec![];
|
||||
for (_, module) in def_map.modules() {
|
||||
for decl in module.scope.declarations() {
|
||||
|
||||
@@ -52,7 +52,7 @@ pub fn find_path(
|
||||
ignore_local_imports,
|
||||
is_std_item: item_module.krate().data(db).origin.is_lang(),
|
||||
from,
|
||||
from_def_map: &from.def_map(db),
|
||||
from_def_map: from.def_map(db),
|
||||
fuel: Cell::new(FIND_PATH_FUEL),
|
||||
},
|
||||
item,
|
||||
@@ -691,7 +691,7 @@ fn check_found_path_(
|
||||
let (def_map, local_def_map) = module.local_def_map(&db);
|
||||
let resolved = def_map
|
||||
.resolve_path(
|
||||
&local_def_map,
|
||||
local_def_map,
|
||||
&db,
|
||||
module.local_id,
|
||||
&mod_path,
|
||||
|
||||
@@ -297,7 +297,8 @@ enum ArgRef<'a> {
|
||||
unfinished_literal.clear();
|
||||
}
|
||||
|
||||
let span = parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
|
||||
let span =
|
||||
parser.arg_places.get(placeholder_index).and_then(|s| to_span(s.clone()));
|
||||
placeholder_index += 1;
|
||||
|
||||
let position_span = to_span(position_span);
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
AssocItemId, AttrDefId, Complete, FxIndexMap, ModuleDefId, ModuleId, TraitId,
|
||||
db::DefDatabase,
|
||||
item_scope::{ImportOrExternCrate, ItemInNs},
|
||||
nameres::DefMap,
|
||||
nameres::{DefMap, crate_def_map},
|
||||
visibility::Visibility,
|
||||
};
|
||||
|
||||
@@ -129,7 +129,7 @@ pub fn import_info_for(&self, item: ItemInNs) -> Option<&[ImportInfo]> {
|
||||
fn collect_import_map(db: &dyn DefDatabase, krate: Crate) -> ImportMapIndex {
|
||||
let _p = tracing::info_span!("collect_import_map").entered();
|
||||
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(db, krate);
|
||||
let mut map = FxIndexMap::default();
|
||||
|
||||
// We look only into modules that are public(ly reexported), starting with the crate root.
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
use crate::{
|
||||
AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
|
||||
StaticId, StructId, TraitId, TypeAliasId, UnionId, db::DefDatabase, expr_store::path::Path,
|
||||
nameres::crate_def_map,
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
@@ -90,7 +91,7 @@ pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangIt
|
||||
|
||||
let mut lang_items = LangItems::default();
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(db, krate);
|
||||
|
||||
for (_, module_data) in crate_def_map.modules() {
|
||||
for impl_def in module_data.scope.impls() {
|
||||
@@ -209,7 +210,7 @@ pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option
|
||||
|
||||
let mut traits = Vec::new();
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(db, krate);
|
||||
|
||||
for (_, module_data) in crate_def_map.modules() {
|
||||
for def in module_data.scope.declarations() {
|
||||
|
||||
@@ -92,7 +92,7 @@
|
||||
Const, Enum, ExternCrate, Function, Impl, ItemTreeId, ItemTreeNode, Macro2, MacroRules,
|
||||
Static, Struct, Trait, TraitAlias, TypeAlias, Union, Use, Variant,
|
||||
},
|
||||
nameres::LocalDefMap,
|
||||
nameres::{LocalDefMap, block_def_map, crate_def_map, crate_local_def_map},
|
||||
signatures::VariantFields,
|
||||
};
|
||||
|
||||
@@ -324,12 +324,13 @@ pub struct CrateRootModuleId {
|
||||
}
|
||||
|
||||
impl CrateRootModuleId {
|
||||
pub fn def_map(&self, db: &dyn DefDatabase) -> Arc<DefMap> {
|
||||
db.crate_def_map(self.krate)
|
||||
pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
|
||||
crate_def_map(db, self.krate)
|
||||
}
|
||||
|
||||
pub(crate) fn local_def_map(&self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
|
||||
db.crate_local_def_map(self.krate)
|
||||
pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
|
||||
let def_map = crate_local_def_map(db, self.krate);
|
||||
(def_map.def_map(db), def_map.local(db))
|
||||
}
|
||||
|
||||
pub fn krate(self) -> Crate {
|
||||
@@ -390,26 +391,29 @@ pub struct ModuleId {
|
||||
}
|
||||
|
||||
impl ModuleId {
|
||||
pub fn def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
|
||||
pub fn def_map(self, db: &dyn DefDatabase) -> &DefMap {
|
||||
match self.block {
|
||||
Some(block) => db.block_def_map(block),
|
||||
None => db.crate_def_map(self.krate),
|
||||
Some(block) => block_def_map(db, block),
|
||||
None => crate_def_map(db, self.krate),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (Arc<DefMap>, Arc<LocalDefMap>) {
|
||||
pub(crate) fn local_def_map(self, db: &dyn DefDatabase) -> (&DefMap, &LocalDefMap) {
|
||||
match self.block {
|
||||
Some(block) => (db.block_def_map(block), self.only_local_def_map(db)),
|
||||
None => db.crate_local_def_map(self.krate),
|
||||
Some(block) => (block_def_map(db, block), self.only_local_def_map(db)),
|
||||
None => {
|
||||
let def_map = crate_local_def_map(db, self.krate);
|
||||
(def_map.def_map(db), def_map.local(db))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> Arc<LocalDefMap> {
|
||||
db.crate_local_def_map(self.krate).1
|
||||
pub(crate) fn only_local_def_map(self, db: &dyn DefDatabase) -> &LocalDefMap {
|
||||
crate_local_def_map(db, self.krate).local(db)
|
||||
}
|
||||
|
||||
pub fn crate_def_map(self, db: &dyn DefDatabase) -> Arc<DefMap> {
|
||||
db.crate_def_map(self.krate)
|
||||
pub fn crate_def_map(self, db: &dyn DefDatabase) -> &DefMap {
|
||||
crate_def_map(db, self.krate)
|
||||
}
|
||||
|
||||
pub fn krate(self) -> Crate {
|
||||
@@ -701,6 +705,16 @@ pub enum AssocItemId {
|
||||
// casting them, and somehow making the constructors private, which would be annoying.
|
||||
impl_from!(FunctionId, ConstId, TypeAliasId for AssocItemId);
|
||||
|
||||
impl From<AssocItemId> for ModuleDefId {
|
||||
fn from(item: AssocItemId) -> Self {
|
||||
match item {
|
||||
AssocItemId::FunctionId(f) => f.into(),
|
||||
AssocItemId::ConstId(c) => c.into(),
|
||||
AssocItemId::TypeAliasId(t) => t.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialOrd, Ord, Clone, Copy, PartialEq, Eq, Hash, salsa_macros::Supertype)]
|
||||
pub enum GenericDefId {
|
||||
AdtId(AdtId),
|
||||
|
||||
+2
-2
@@ -454,13 +454,13 @@ fn test_concat_expand() {
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {}
|
||||
|
||||
fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', '\0'); }
|
||||
fn main() { concat!("fo", "o", 0, r#""bar""#, "\n", false, '"', -4, - 4, '\0'); }
|
||||
"##,
|
||||
expect![[r##"
|
||||
#[rustc_builtin_macro]
|
||||
macro_rules! concat {}
|
||||
|
||||
fn main() { "foo0\"bar\"\nfalse\"\u{0}"; }
|
||||
fn main() { "foo0\"bar\"\nfalse\"-4-4\u{0}"; }
|
||||
"##]],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -39,7 +39,7 @@
|
||||
use crate::{
|
||||
AdtId, Lookup, ModuleDefId,
|
||||
db::DefDatabase,
|
||||
nameres::{DefMap, ModuleSource},
|
||||
nameres::{DefMap, ModuleSource, crate_def_map},
|
||||
src::HasSource,
|
||||
test_db::TestDB,
|
||||
tt::TopSubtree,
|
||||
@@ -49,7 +49,7 @@
|
||||
fn check_errors(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
let errors = def_map
|
||||
.modules()
|
||||
.flat_map(|module| module.1.scope.all_macro_calls())
|
||||
@@ -113,7 +113,7 @@ fn resolve(
|
||||
|
||||
let (body, sm) = db.body_with_source_map(body);
|
||||
if let Some(it) =
|
||||
body.blocks(db).find_map(|block| resolve(db, &block.1, ast_id, ast_ptr))
|
||||
body.blocks(db).find_map(|block| resolve(db, block.1, ast_id, ast_ptr))
|
||||
{
|
||||
return Some(it);
|
||||
}
|
||||
@@ -127,7 +127,7 @@ fn resolve(
|
||||
|
||||
let db = TestDB::with_files_extra_proc_macros(ra_fixture, extra_proc_macros);
|
||||
let krate = db.fetch_test_crate();
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
let local_id = DefMap::ROOT;
|
||||
let source = def_map[local_id].definition_source(&db);
|
||||
let source_file = match source.value {
|
||||
@@ -142,7 +142,7 @@ fn resolve(
|
||||
let ast_id = db.ast_id_map(source.file_id).ast_id(¯o_call_node);
|
||||
let ast_id = InFile::new(source.file_id, ast_id);
|
||||
let ptr = InFile::new(source.file_id, AstPtr::new(¯o_call_node));
|
||||
let macro_call_id = resolve(&db, &def_map, ast_id, ptr)
|
||||
let macro_call_id = resolve(&db, def_map, ast_id, ptr)
|
||||
.unwrap_or_else(|| panic!("unable to find semantic macro call {macro_call_node}"));
|
||||
let expansion_result = db.parse_macro_expansion(macro_call_id);
|
||||
expansions.push((macro_call_node.clone(), expansion_result));
|
||||
@@ -380,8 +380,4 @@ fn expand(
|
||||
panic!("got invalid macro input: {:?}", parse.errors());
|
||||
}
|
||||
}
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
other.as_any().type_id() == std::any::TypeId::of::<Self>()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -112,6 +112,18 @@ pub struct LocalDefMap {
|
||||
extern_prelude: FxIndexMap<Name, (CrateRootModuleId, Option<ExternCrateId>)>,
|
||||
}
|
||||
|
||||
impl std::hash::Hash for LocalDefMap {
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
let LocalDefMap { extern_prelude } = self;
|
||||
extern_prelude.len().hash(state);
|
||||
for (name, (crate_root, extern_crate)) in extern_prelude {
|
||||
name.hash(state);
|
||||
crate_root.hash(state);
|
||||
extern_crate.hash(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl LocalDefMap {
|
||||
pub(crate) const EMPTY: &Self =
|
||||
&Self { extern_prelude: FxIndexMap::with_hasher(rustc_hash::FxBuildHasher) };
|
||||
@@ -250,7 +262,7 @@ struct BlockRelativeModuleId {
|
||||
}
|
||||
|
||||
impl BlockRelativeModuleId {
|
||||
fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> Arc<DefMap> {
|
||||
fn def_map(self, db: &dyn DefDatabase, krate: Crate) -> &DefMap {
|
||||
self.into_module(krate).def_map(db)
|
||||
}
|
||||
|
||||
@@ -358,6 +370,87 @@ pub struct ModuleData {
|
||||
pub scope: ItemScope,
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn crate_def_map(db: &dyn DefDatabase, crate_id: Crate) -> &DefMap {
|
||||
crate_local_def_map(db, crate_id).def_map(db)
|
||||
}
|
||||
|
||||
#[allow(unused_lifetimes)]
|
||||
mod __ {
|
||||
use super::*;
|
||||
#[salsa_macros::tracked]
|
||||
pub(crate) struct DefMapPair<'db> {
|
||||
#[tracked]
|
||||
#[return_ref]
|
||||
pub(crate) def_map: DefMap,
|
||||
#[return_ref]
|
||||
pub(crate) local: LocalDefMap,
|
||||
}
|
||||
}
|
||||
pub(crate) use __::DefMapPair;
|
||||
|
||||
#[salsa_macros::tracked(return_ref)]
|
||||
pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
|
||||
let krate = crate_id.data(db);
|
||||
let _p = tracing::info_span!(
|
||||
"crate_def_map_query",
|
||||
name=?crate_id
|
||||
.extra_data(db)
|
||||
.display_name
|
||||
.as_ref()
|
||||
.map(|it| it.crate_name().to_smolstr())
|
||||
.unwrap_or_default()
|
||||
)
|
||||
.entered();
|
||||
|
||||
let module_data = ModuleData::new(
|
||||
ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
|
||||
Visibility::Public,
|
||||
);
|
||||
|
||||
let def_map =
|
||||
DefMap::empty(crate_id, Arc::new(DefMapCrateData::new(krate.edition)), module_data, None);
|
||||
let (def_map, local_def_map) = collector::collect_defs(
|
||||
db,
|
||||
def_map,
|
||||
TreeId::new(krate.root_file_id(db).into(), None),
|
||||
None,
|
||||
);
|
||||
|
||||
DefMapPair::new(db, def_map, local_def_map)
|
||||
}
|
||||
|
||||
#[salsa_macros::tracked(return_ref)]
|
||||
pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
|
||||
let BlockLoc { ast_id, module } = block_id.lookup(db);
|
||||
|
||||
let visibility = Visibility::Module(
|
||||
ModuleId { krate: module.krate, local_id: DefMap::ROOT, block: module.block },
|
||||
VisibilityExplicitness::Implicit,
|
||||
);
|
||||
let module_data =
|
||||
ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
|
||||
|
||||
let local_def_map = crate_local_def_map(db, module.krate);
|
||||
let def_map = DefMap::empty(
|
||||
module.krate,
|
||||
local_def_map.def_map(db).data.clone(),
|
||||
module_data,
|
||||
Some(BlockInfo {
|
||||
block: block_id,
|
||||
parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
|
||||
}),
|
||||
);
|
||||
|
||||
let (def_map, _) = collector::collect_defs(
|
||||
db,
|
||||
def_map,
|
||||
TreeId::new(ast_id.file_id, Some(block_id)),
|
||||
Some(local_def_map.local(db)),
|
||||
);
|
||||
def_map
|
||||
}
|
||||
|
||||
impl DefMap {
|
||||
/// The module id of a crate or block root.
|
||||
pub const ROOT: LocalModuleId = LocalModuleId::from_raw(la_arena::RawIdx::from_u32(0));
|
||||
@@ -366,77 +459,6 @@ pub fn edition(&self) -> Edition {
|
||||
self.data.edition
|
||||
}
|
||||
|
||||
pub(crate) fn crate_def_map_query(db: &dyn DefDatabase, crate_id: Crate) -> Arc<DefMap> {
|
||||
db.crate_local_def_map(crate_id).0
|
||||
}
|
||||
|
||||
pub(crate) fn crate_local_def_map_query(
|
||||
db: &dyn DefDatabase,
|
||||
crate_id: Crate,
|
||||
) -> (Arc<DefMap>, Arc<LocalDefMap>) {
|
||||
let krate = crate_id.data(db);
|
||||
let _p = tracing::info_span!(
|
||||
"crate_def_map_query",
|
||||
name=?crate_id
|
||||
.extra_data(db)
|
||||
.display_name
|
||||
.as_ref()
|
||||
.map(|it| it.crate_name().to_smolstr())
|
||||
.unwrap_or_default()
|
||||
)
|
||||
.entered();
|
||||
|
||||
let module_data = ModuleData::new(
|
||||
ModuleOrigin::CrateRoot { definition: krate.root_file_id(db) },
|
||||
Visibility::Public,
|
||||
);
|
||||
|
||||
let def_map = DefMap::empty(
|
||||
crate_id,
|
||||
Arc::new(DefMapCrateData::new(krate.edition)),
|
||||
module_data,
|
||||
None,
|
||||
);
|
||||
let (def_map, local_def_map) = collector::collect_defs(
|
||||
db,
|
||||
def_map,
|
||||
TreeId::new(krate.root_file_id(db).into(), None),
|
||||
None,
|
||||
);
|
||||
|
||||
(Arc::new(def_map), Arc::new(local_def_map))
|
||||
}
|
||||
|
||||
pub(crate) fn block_def_map_query(db: &dyn DefDatabase, block_id: BlockId) -> Arc<DefMap> {
|
||||
let BlockLoc { ast_id, module } = block_id.lookup(db);
|
||||
|
||||
let visibility = Visibility::Module(
|
||||
ModuleId { krate: module.krate, local_id: Self::ROOT, block: module.block },
|
||||
VisibilityExplicitness::Implicit,
|
||||
);
|
||||
let module_data =
|
||||
ModuleData::new(ModuleOrigin::BlockExpr { block: ast_id, id: block_id }, visibility);
|
||||
|
||||
let (crate_map, crate_local_map) = db.crate_local_def_map(module.krate);
|
||||
let def_map = DefMap::empty(
|
||||
module.krate,
|
||||
crate_map.data.clone(),
|
||||
module_data,
|
||||
Some(BlockInfo {
|
||||
block: block_id,
|
||||
parent: BlockRelativeModuleId { block: module.block, local_id: module.local_id },
|
||||
}),
|
||||
);
|
||||
|
||||
let (def_map, _) = collector::collect_defs(
|
||||
db,
|
||||
def_map,
|
||||
TreeId::new(ast_id.file_id, Some(block_id)),
|
||||
Some(crate_local_map),
|
||||
);
|
||||
Arc::new(def_map)
|
||||
}
|
||||
|
||||
fn empty(
|
||||
krate: Crate,
|
||||
crate_data: Arc<DefMapCrateData>,
|
||||
@@ -595,7 +617,7 @@ pub fn dump(&self, db: &dyn DefDatabase) -> String {
|
||||
go(&mut buf, db, current_map, "block scope", Self::ROOT);
|
||||
buf.push('\n');
|
||||
arc = block.parent.def_map(db, self.krate);
|
||||
current_map = &arc;
|
||||
current_map = arc;
|
||||
}
|
||||
go(&mut buf, db, current_map, "crate", Self::ROOT);
|
||||
return buf;
|
||||
@@ -628,7 +650,7 @@ pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
|
||||
while let Some(block) = current_map.block {
|
||||
format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
|
||||
arc = block.parent.def_map(db, self.krate);
|
||||
current_map = &arc;
|
||||
current_map = arc;
|
||||
}
|
||||
|
||||
format_to!(buf, "crate scope\n");
|
||||
@@ -708,7 +730,7 @@ pub(crate) fn with_ancestor_maps<T>(
|
||||
let mut block = self.block;
|
||||
while let Some(block_info) = block {
|
||||
let parent = block_info.parent.def_map(db, self.krate);
|
||||
if let Some(it) = f(&parent, block_info.parent.local_id) {
|
||||
if let Some(it) = f(parent, block_info.parent.local_id) {
|
||||
return Some(it);
|
||||
}
|
||||
block = parent.block;
|
||||
|
||||
@@ -66,6 +66,15 @@ pub fn method_by_name(&self, name: &Name) -> Option<FunctionId> {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn assoc_item_by_name(&self, name: &Name) -> Option<AssocItemId> {
|
||||
self.items.iter().find_map(|&(ref item_name, item)| match item {
|
||||
AssocItemId::FunctionId(_) if item_name == name => Some(item),
|
||||
AssocItemId::TypeAliasId(_) if item_name == name => Some(item),
|
||||
AssocItemId::ConstId(_) if item_name == name => Some(item),
|
||||
_ => None,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
|
||||
self.macro_calls.iter().flat_map(|it| it.iter()).copied()
|
||||
}
|
||||
@@ -108,8 +117,8 @@ pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCa
|
||||
struct AssocItemCollector<'a> {
|
||||
db: &'a dyn DefDatabase,
|
||||
module_id: ModuleId,
|
||||
def_map: Arc<DefMap>,
|
||||
local_def_map: Arc<LocalDefMap>,
|
||||
def_map: &'a DefMap,
|
||||
local_def_map: &'a LocalDefMap,
|
||||
diagnostics: Vec<DefDiagnostic>,
|
||||
container: ItemContainerId,
|
||||
|
||||
@@ -174,7 +183,7 @@ fn collect_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocIte
|
||||
let ast_id_with_path = AstIdWithPath { path: attr.path.clone(), ast_id };
|
||||
|
||||
match self.def_map.resolve_attr_macro(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
self.db,
|
||||
self.module_id.local_id,
|
||||
ast_id_with_path,
|
||||
@@ -246,7 +255,7 @@ fn record_item(&mut self, item_tree: &ItemTree, tree_id: TreeId, item: AssocItem
|
||||
let resolver = |path: &_| {
|
||||
self.def_map
|
||||
.resolve_path(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
self.db,
|
||||
self.module_id.local_id,
|
||||
path,
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
AdtId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
|
||||
AdtId, AssocItemId, AstId, AstIdWithPath, ConstLoc, CrateRootModuleId, EnumLoc, ExternBlockLoc,
|
||||
ExternCrateId, ExternCrateLoc, FunctionId, FunctionLoc, ImplLoc, Intern, ItemContainerId,
|
||||
LocalModuleId, Lookup, Macro2Id, Macro2Loc, MacroExpander, MacroId, MacroRulesId,
|
||||
MacroRulesLoc, MacroRulesLocFlags, ModuleDefId, ModuleId, ProcMacroId, ProcMacroLoc, StaticLoc,
|
||||
@@ -43,9 +43,10 @@
|
||||
nameres::{
|
||||
BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, ModuleData, ModuleOrigin, ResolveMode,
|
||||
attr_resolution::{attr_macro_as_call_id, derive_macro_as_call_id},
|
||||
crate_def_map,
|
||||
diagnostics::DefDiagnostic,
|
||||
mod_resolution::ModDir,
|
||||
path_resolution::ReachedFixedPoint,
|
||||
path_resolution::{ReachedFixedPoint, ResolvePathResult},
|
||||
proc_macro::{ProcMacroDef, ProcMacroKind, parse_macro_name_and_helper_attrs},
|
||||
sub_namespace_match,
|
||||
},
|
||||
@@ -61,7 +62,7 @@ pub(super) fn collect_defs(
|
||||
db: &dyn DefDatabase,
|
||||
def_map: DefMap,
|
||||
tree_id: TreeId,
|
||||
crate_local_def_map: Option<Arc<LocalDefMap>>,
|
||||
crate_local_def_map: Option<&LocalDefMap>,
|
||||
) -> (DefMap, LocalDefMap) {
|
||||
let krate = &def_map.krate.data(db);
|
||||
let cfg_options = def_map.krate.cfg_options(db);
|
||||
@@ -216,7 +217,7 @@ struct DefCollector<'a> {
|
||||
def_map: DefMap,
|
||||
local_def_map: LocalDefMap,
|
||||
/// Set only in case of blocks.
|
||||
crate_local_def_map: Option<Arc<LocalDefMap>>,
|
||||
crate_local_def_map: Option<&'a LocalDefMap>,
|
||||
// The dependencies of the current crate, including optional deps like `test`.
|
||||
deps: FxHashMap<Name, BuiltDependency>,
|
||||
glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, Visibility, GlobId)>>,
|
||||
@@ -533,7 +534,7 @@ fn inject_prelude(&mut self) {
|
||||
);
|
||||
|
||||
let (per_ns, _) = self.def_map.resolve_path(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
DefMap::ROOT,
|
||||
&path,
|
||||
@@ -556,7 +557,7 @@ fn inject_prelude(&mut self) {
|
||||
}
|
||||
|
||||
fn local_def_map(&mut self) -> &LocalDefMap {
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map)
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map)
|
||||
}
|
||||
|
||||
/// Adds a definition of procedural macro `name` to the root module.
|
||||
@@ -688,7 +689,7 @@ fn define_macro_def(
|
||||
let vis = self
|
||||
.def_map
|
||||
.resolve_visibility(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
module_id,
|
||||
vis,
|
||||
@@ -731,7 +732,7 @@ fn import_macros_from_extern_crate(
|
||||
names: Option<Vec<Name>>,
|
||||
extern_crate: Option<ExternCrateId>,
|
||||
) {
|
||||
let def_map = self.db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(self.db, krate);
|
||||
// `#[macro_use]` brings macros into macro_use prelude. Yes, even non-`macro_rules!`
|
||||
// macros.
|
||||
let root_scope = &def_map[DefMap::ROOT].scope;
|
||||
@@ -811,32 +812,35 @@ fn resolve_import(&self, module_id: LocalModuleId, import: &Import) -> PartialRe
|
||||
let _p = tracing::info_span!("resolve_import", import_path = %import.path.display(self.db, Edition::LATEST))
|
||||
.entered();
|
||||
tracing::debug!("resolving import: {:?} ({:?})", import, self.def_map.data.edition);
|
||||
let res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
ResolveMode::Import,
|
||||
module_id,
|
||||
&import.path,
|
||||
BuiltinShadowMode::Module,
|
||||
None, // An import may resolve to any kind of macro.
|
||||
);
|
||||
let ResolvePathResult { resolved_def, segment_index, reached_fixedpoint, prefix_info } =
|
||||
self.def_map.resolve_path_fp_with_macro(
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
ResolveMode::Import,
|
||||
module_id,
|
||||
&import.path,
|
||||
BuiltinShadowMode::Module,
|
||||
None, // An import may resolve to any kind of macro.
|
||||
);
|
||||
|
||||
let def = res.resolved_def;
|
||||
if res.reached_fixedpoint == ReachedFixedPoint::No || def.is_none() {
|
||||
if reached_fixedpoint == ReachedFixedPoint::No
|
||||
|| resolved_def.is_none()
|
||||
|| segment_index.is_some()
|
||||
{
|
||||
return PartialResolvedImport::Unresolved;
|
||||
}
|
||||
|
||||
if res.prefix_info.differing_crate {
|
||||
if prefix_info.differing_crate {
|
||||
return PartialResolvedImport::Resolved(
|
||||
def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
||||
resolved_def.filter_visibility(|v| matches!(v, Visibility::Public)),
|
||||
);
|
||||
}
|
||||
|
||||
// Check whether all namespaces are resolved.
|
||||
if def.is_full() {
|
||||
PartialResolvedImport::Resolved(def)
|
||||
if resolved_def.is_full() {
|
||||
PartialResolvedImport::Resolved(resolved_def)
|
||||
} else {
|
||||
PartialResolvedImport::Indeterminate(def)
|
||||
PartialResolvedImport::Indeterminate(resolved_def)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -849,7 +853,7 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
|
||||
let vis = self
|
||||
.def_map
|
||||
.resolve_visibility(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
module_id,
|
||||
&directive.import.visibility,
|
||||
@@ -986,6 +990,43 @@ fn record_resolved_import(&mut self, directive: &ImportDirective) {
|
||||
Some(ImportOrExternCrate::Glob(glob)),
|
||||
);
|
||||
}
|
||||
Some(ModuleDefId::TraitId(it)) => {
|
||||
// FIXME: Implement this correctly
|
||||
// We can't actually call `trait_items`, the reason being that if macro calls
|
||||
// occur, they will call back into the def map which we might be computing right
|
||||
// now resulting in a cycle.
|
||||
// To properly implement this, trait item collection needs to be done in def map
|
||||
// collection...
|
||||
let resolutions = if true {
|
||||
vec![]
|
||||
} else {
|
||||
self.db
|
||||
.trait_items(it)
|
||||
.items
|
||||
.iter()
|
||||
.map(|&(ref name, variant)| {
|
||||
let res = match variant {
|
||||
AssocItemId::FunctionId(it) => {
|
||||
PerNs::values(it.into(), vis, None)
|
||||
}
|
||||
AssocItemId::ConstId(it) => {
|
||||
PerNs::values(it.into(), vis, None)
|
||||
}
|
||||
AssocItemId::TypeAliasId(it) => {
|
||||
PerNs::types(it.into(), vis, None)
|
||||
}
|
||||
};
|
||||
(Some(name.clone()), res)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
};
|
||||
self.update(
|
||||
module_id,
|
||||
&resolutions,
|
||||
vis,
|
||||
Some(ImportOrExternCrate::Glob(glob)),
|
||||
);
|
||||
}
|
||||
Some(d) => {
|
||||
tracing::debug!("glob import {:?} from non-module/enum {:?}", import, d);
|
||||
}
|
||||
@@ -1240,7 +1281,7 @@ enum Resolved {
|
||||
};
|
||||
let resolver = |path: &_| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
directive.module_id,
|
||||
@@ -1307,7 +1348,7 @@ enum Resolved {
|
||||
);
|
||||
// Record its helper attributes.
|
||||
if def_id.krate != self.def_map.krate {
|
||||
let def_map = self.db.crate_def_map(def_id.krate);
|
||||
let def_map = crate_def_map(self.db, def_id.krate);
|
||||
if let Some(helpers) = def_map.data.exported_derives.get(&def_id) {
|
||||
self.def_map
|
||||
.derive_helpers_in_scope
|
||||
@@ -1553,7 +1594,7 @@ fn finish(mut self) -> (DefMap, LocalDefMap) {
|
||||
self.def_map.krate,
|
||||
|path| {
|
||||
let resolved_res = self.def_map.resolve_path_fp_with_macro(
|
||||
self.crate_local_def_map.as_deref().unwrap_or(&self.local_def_map),
|
||||
self.crate_local_def_map.unwrap_or(&self.local_def_map),
|
||||
self.db,
|
||||
ResolveMode::Other,
|
||||
directive.module_id,
|
||||
@@ -1702,11 +1743,8 @@ fn collect(&mut self, items: &[ModItem], container: ItemContainerId) {
|
||||
|
||||
let module = self.def_collector.def_map.module_id(module_id);
|
||||
let def_map = &mut self.def_collector.def_map;
|
||||
let local_def_map = self
|
||||
.def_collector
|
||||
.crate_local_def_map
|
||||
.as_deref()
|
||||
.unwrap_or(&self.def_collector.local_def_map);
|
||||
let local_def_map =
|
||||
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map);
|
||||
|
||||
match item {
|
||||
ModItem::Mod(m) => self.collect_module(m, &attrs),
|
||||
@@ -2133,10 +2171,7 @@ fn push_child_module(
|
||||
let def_map = &mut self.def_collector.def_map;
|
||||
let vis = def_map
|
||||
.resolve_visibility(
|
||||
self.def_collector
|
||||
.crate_local_def_map
|
||||
.as_deref()
|
||||
.unwrap_or(&self.def_collector.local_def_map),
|
||||
self.def_collector.crate_local_def_map.unwrap_or(&self.def_collector.local_def_map),
|
||||
self.def_collector.db,
|
||||
self.module_id,
|
||||
visibility,
|
||||
|
||||
@@ -17,14 +17,17 @@
|
||||
name::Name,
|
||||
};
|
||||
use span::Edition;
|
||||
use triomphe::Arc;
|
||||
use stdx::TupleExt;
|
||||
|
||||
use crate::{
|
||||
AdtId, LocalModuleId, ModuleDefId,
|
||||
db::DefDatabase,
|
||||
item_scope::{BUILTIN_SCOPE, ImportOrExternCrate},
|
||||
item_tree::FieldsShape,
|
||||
nameres::{BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, sub_namespace_match},
|
||||
nameres::{
|
||||
BlockInfo, BuiltinShadowMode, DefMap, LocalDefMap, MacroSubNs, crate_def_map,
|
||||
sub_namespace_match,
|
||||
},
|
||||
per_ns::PerNs,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
};
|
||||
@@ -44,6 +47,7 @@ pub(super) enum ReachedFixedPoint {
|
||||
#[derive(Debug, Clone)]
|
||||
pub(super) struct ResolvePathResult {
|
||||
pub(super) resolved_def: PerNs,
|
||||
/// The index of the last resolved segment, or `None` if the full path has been resolved.
|
||||
pub(super) segment_index: Option<usize>,
|
||||
pub(super) reached_fixedpoint: ReachedFixedPoint,
|
||||
pub(super) prefix_info: ResolvePathResultPrefixInfo,
|
||||
@@ -173,7 +177,6 @@ pub(super) fn resolve_path_fp_with_macro(
|
||||
return result;
|
||||
}
|
||||
|
||||
let mut arc;
|
||||
let mut current_map = self;
|
||||
|
||||
let mut merge = |new: ResolvePathResult| {
|
||||
@@ -195,8 +198,7 @@ pub(super) fn resolve_path_fp_with_macro(
|
||||
Some(block) if original_module == Self::ROOT => {
|
||||
// Block modules "inherit" names from its parent module.
|
||||
original_module = block.parent.local_id;
|
||||
arc = block.parent.def_map(db, current_map.krate);
|
||||
current_map = &arc;
|
||||
current_map = block.parent.def_map(db, current_map.krate);
|
||||
}
|
||||
// Proper (non-block) modules, including those in block `DefMap`s, don't.
|
||||
_ => {
|
||||
@@ -204,8 +206,7 @@ pub(super) fn resolve_path_fp_with_macro(
|
||||
// A module inside a block. Do not resolve items declared in upper blocks, but we do need to get
|
||||
// the prelude items (which are not inserted into blocks because they can be overridden there).
|
||||
original_module = Self::ROOT;
|
||||
arc = db.crate_def_map(self.krate);
|
||||
current_map = &arc;
|
||||
current_map = crate_def_map(db, self.krate);
|
||||
|
||||
let new = current_map.resolve_path_fp_in_all_preludes(
|
||||
local_def_map,
|
||||
@@ -253,7 +254,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
||||
cov_mark::hit!(macro_dollar_crate_self);
|
||||
PerNs::types(self.crate_root().into(), Visibility::Public, None)
|
||||
} else {
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(db, krate);
|
||||
let module = def_map.module_id(Self::ROOT);
|
||||
cov_mark::hit!(macro_dollar_crate_other);
|
||||
PerNs::types(module.into(), Visibility::Public, None)
|
||||
@@ -312,7 +313,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
||||
// Adjust `local_id` to `self`, i.e. the nearest non-block module.
|
||||
if def_map.module_id(local_id).is_block_module() {
|
||||
(ext, local_id) = adjust_to_nearest_non_block_module(db, def_map, local_id);
|
||||
def_map = &ext;
|
||||
def_map = ext;
|
||||
}
|
||||
|
||||
// Go up the module tree but skip block modules as `super` always refers to the
|
||||
@@ -325,7 +326,7 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
||||
if def_map.module_id(local_id).is_block_module() {
|
||||
(ext, local_id) =
|
||||
adjust_to_nearest_non_block_module(db, def_map, local_id);
|
||||
def_map = &ext;
|
||||
def_map = ext;
|
||||
}
|
||||
} else {
|
||||
stdx::always!(def_map.block.is_none());
|
||||
@@ -364,7 +365,15 @@ pub(super) fn resolve_path_fp_with_macro_single(
|
||||
},
|
||||
};
|
||||
|
||||
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
|
||||
self.resolve_remaining_segments(
|
||||
db,
|
||||
mode,
|
||||
segments,
|
||||
curr_per_ns,
|
||||
path,
|
||||
shadow,
|
||||
original_module,
|
||||
)
|
||||
}
|
||||
|
||||
/// Resolves a path only in the preludes, without accounting for item scopes.
|
||||
@@ -413,7 +422,15 @@ pub(super) fn resolve_path_fp_in_all_preludes(
|
||||
}
|
||||
};
|
||||
|
||||
self.resolve_remaining_segments(segments, curr_per_ns, path, db, shadow, original_module)
|
||||
self.resolve_remaining_segments(
|
||||
db,
|
||||
mode,
|
||||
segments,
|
||||
curr_per_ns,
|
||||
path,
|
||||
shadow,
|
||||
original_module,
|
||||
)
|
||||
}
|
||||
|
||||
/// 2018-style absolute path -- only extern prelude
|
||||
@@ -441,10 +458,11 @@ fn resolve_path_abs<'a>(
|
||||
|
||||
fn resolve_remaining_segments<'a>(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
mode: ResolveMode,
|
||||
mut segments: impl Iterator<Item = (usize, &'a Name)>,
|
||||
mut curr_per_ns: PerNs,
|
||||
path: &ModPath,
|
||||
db: &dyn DefDatabase,
|
||||
shadow: BuiltinShadowMode,
|
||||
original_module: LocalModuleId,
|
||||
) -> ResolvePathResult {
|
||||
@@ -465,6 +483,7 @@ fn resolve_remaining_segments<'a>(
|
||||
curr_per_ns = match curr.def {
|
||||
ModuleDefId::ModuleId(module) => {
|
||||
if module.krate != self.krate {
|
||||
// FIXME: Inefficient
|
||||
let path = ModPath::from_segments(
|
||||
PathKind::SELF,
|
||||
path.segments()[i..].iter().cloned(),
|
||||
@@ -478,7 +497,7 @@ fn resolve_remaining_segments<'a>(
|
||||
let resolution = defp_map.resolve_path_fp_with_macro(
|
||||
LocalDefMap::EMPTY,
|
||||
db,
|
||||
ResolveMode::Other,
|
||||
mode,
|
||||
module.local_id,
|
||||
&path,
|
||||
shadow,
|
||||
@@ -553,6 +572,44 @@ fn resolve_remaining_segments<'a>(
|
||||
),
|
||||
};
|
||||
}
|
||||
def @ ModuleDefId::TraitId(t) if mode == ResolveMode::Import => {
|
||||
// FIXME: Implement this correctly
|
||||
// We can't actually call `trait_items`, the reason being that if macro calls
|
||||
// occur, they will call back into the def map which we might be computing right
|
||||
// now resulting in a cycle.
|
||||
// To properly implement this, trait item collection needs to be done in def map
|
||||
// collection...
|
||||
let item =
|
||||
if true { None } else { db.trait_items(t).assoc_item_by_name(segment) };
|
||||
return match item {
|
||||
Some(item) => ResolvePathResult::new(
|
||||
match item {
|
||||
crate::AssocItemId::FunctionId(function_id) => PerNs::values(
|
||||
function_id.into(),
|
||||
curr.vis,
|
||||
curr.import.and_then(|it| it.import_or_glob()),
|
||||
),
|
||||
crate::AssocItemId::ConstId(const_id) => PerNs::values(
|
||||
const_id.into(),
|
||||
curr.vis,
|
||||
curr.import.and_then(|it| it.import_or_glob()),
|
||||
),
|
||||
crate::AssocItemId::TypeAliasId(type_alias_id) => {
|
||||
PerNs::types(type_alias_id.into(), curr.vis, curr.import)
|
||||
}
|
||||
},
|
||||
ReachedFixedPoint::Yes,
|
||||
segments.next().map(TupleExt::head),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
),
|
||||
None => ResolvePathResult::new(
|
||||
PerNs::types(def, curr.vis, curr.import),
|
||||
ReachedFixedPoint::Yes,
|
||||
Some(i),
|
||||
ResolvePathResultPrefixInfo::default(),
|
||||
),
|
||||
};
|
||||
}
|
||||
s => {
|
||||
// could be an inherent method call in UFCS form
|
||||
// (`Struct::method`), or some other kind of associated item
|
||||
@@ -715,7 +772,7 @@ fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
|
||||
} else {
|
||||
// Extend lifetime
|
||||
keep = prelude.def_map(db);
|
||||
&keep
|
||||
keep
|
||||
};
|
||||
def_map[prelude.local_id].scope.get(name)
|
||||
} else {
|
||||
@@ -725,25 +782,23 @@ fn resolve_in_prelude(&self, db: &dyn DefDatabase, name: &Name) -> PerNs {
|
||||
}
|
||||
|
||||
/// Given a block module, returns its nearest non-block module and the `DefMap` it belongs to.
|
||||
fn adjust_to_nearest_non_block_module(
|
||||
db: &dyn DefDatabase,
|
||||
def_map: &DefMap,
|
||||
fn adjust_to_nearest_non_block_module<'db>(
|
||||
db: &'db dyn DefDatabase,
|
||||
def_map: &'db DefMap,
|
||||
mut local_id: LocalModuleId,
|
||||
) -> (Arc<DefMap>, LocalModuleId) {
|
||||
) -> (&'db DefMap, LocalModuleId) {
|
||||
// INVARIANT: `local_id` in `def_map` must be a block module.
|
||||
stdx::always!(def_map.module_id(local_id).is_block_module());
|
||||
|
||||
let mut ext;
|
||||
// This needs to be a local variable due to our mighty lifetime.
|
||||
let mut def_map = def_map;
|
||||
loop {
|
||||
let BlockInfo { parent, .. } = def_map.block.expect("block module without parent module");
|
||||
|
||||
ext = parent.def_map(db, def_map.krate);
|
||||
def_map = &ext;
|
||||
def_map = parent.def_map(db, def_map.krate);
|
||||
local_id = parent.local_id;
|
||||
if !parent.is_block_module() {
|
||||
return (ext, local_id);
|
||||
return (def_map, local_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,20 +7,25 @@
|
||||
use base_db::RootQueryDb;
|
||||
use expect_test::{Expect, expect};
|
||||
use test_fixture::WithFixture;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{db::DefDatabase, nameres::DefMap, test_db::TestDB};
|
||||
use crate::{
|
||||
nameres::{DefMap, crate_def_map},
|
||||
test_db::TestDB,
|
||||
};
|
||||
|
||||
fn compute_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> Arc<DefMap> {
|
||||
fn compute_crate_def_map(
|
||||
#[rust_analyzer::rust_fixture] ra_fixture: &str,
|
||||
cb: impl FnOnce(&DefMap),
|
||||
) {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
let krate = db.fetch_test_crate();
|
||||
db.crate_def_map(krate)
|
||||
cb(crate_def_map(&db, krate));
|
||||
}
|
||||
|
||||
fn render_crate_def_map(#[rust_analyzer::rust_fixture] ra_fixture: &str) -> String {
|
||||
let db = TestDB::with_files(ra_fixture);
|
||||
let krate = db.fetch_test_crate();
|
||||
db.crate_def_map(krate).dump(&db)
|
||||
crate_def_map(&db, krate).dump(&db)
|
||||
}
|
||||
|
||||
fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expect: Expect) {
|
||||
|
||||
@@ -7,24 +7,37 @@
|
||||
use test_fixture::WithFixture;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{AdtId, ModuleDefId, db::DefDatabase, nameres::tests::TestDB};
|
||||
use crate::{
|
||||
AdtId, ModuleDefId,
|
||||
db::DefDatabase,
|
||||
nameres::{crate_def_map, tests::TestDB},
|
||||
};
|
||||
|
||||
fn check_def_map_is_not_recomputed(ra_fixture_initial: &str, ra_fixture_change: &str) {
|
||||
fn check_def_map_is_not_recomputed(
|
||||
#[rust_analyzer::rust_fixture] ra_fixture_initial: &str,
|
||||
#[rust_analyzer::rust_fixture] ra_fixture_change: &str,
|
||||
) {
|
||||
let (mut db, pos) = TestDB::with_position(ra_fixture_initial);
|
||||
let krate = db.fetch_test_crate();
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
db.crate_def_map(krate);
|
||||
crate_def_map(&db, krate);
|
||||
});
|
||||
assert!(format!("{events:?}").contains("crate_def_map"), "{events:#?}")
|
||||
assert!(
|
||||
format!("{events:?}").contains("crate_local_def_map"),
|
||||
"no crate def map computed:\n{events:#?}",
|
||||
)
|
||||
}
|
||||
db.set_file_text(pos.file_id.file_id(&db), ra_fixture_change);
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
db.crate_def_map(krate);
|
||||
crate_def_map(&db, krate);
|
||||
});
|
||||
assert!(!format!("{events:?}").contains("crate_def_map"), "{events:#?}")
|
||||
assert!(
|
||||
!format!("{events:?}").contains("crate_local_def_map"),
|
||||
"crate def map invalidated:\n{events:#?}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,7 +57,7 @@ pub fn foo() {}
|
||||
);
|
||||
|
||||
for &krate in db.all_crates().iter() {
|
||||
db.crate_def_map(krate);
|
||||
crate_def_map(&db, krate);
|
||||
}
|
||||
|
||||
let all_crates_before = db.all_crates();
|
||||
@@ -94,11 +107,11 @@ pub fn foo() {}
|
||||
|
||||
let events = db.log_executed(|| {
|
||||
for &krate in db.all_crates().iter() {
|
||||
db.crate_def_map(krate);
|
||||
crate_def_map(&db, krate);
|
||||
}
|
||||
});
|
||||
let invalidated_def_maps =
|
||||
events.iter().filter(|event| event.contains("crate_def_map")).count();
|
||||
events.iter().filter(|event| event.contains("crate_local_def_map")).count();
|
||||
assert_eq!(invalidated_def_maps, 1, "{events:#?}")
|
||||
}
|
||||
|
||||
@@ -330,7 +343,7 @@ fn quux() { 1$0 }
|
||||
let krate = db.test_crate();
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 4);
|
||||
});
|
||||
@@ -352,7 +365,7 @@ fn quux() { 92 }
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 4);
|
||||
});
|
||||
@@ -403,7 +416,7 @@ impl Tr for () {}
|
||||
|
||||
{
|
||||
let events = db.log_executed(|| {
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(&db, krate);
|
||||
let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
|
||||
assert_eq!(module_data.scope.resolutions().count(), 8);
|
||||
assert_eq!(module_data.scope.impls().count(), 1);
|
||||
|
||||
@@ -736,7 +736,7 @@ macro_rules! foo {
|
||||
|
||||
#[test]
|
||||
fn macro_dollar_crate_is_correct_in_derive_meta() {
|
||||
let map = compute_crate_def_map(
|
||||
compute_crate_def_map(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
//- /main.rs crate:main deps:lib
|
||||
@@ -753,13 +753,13 @@ macro_rules! foo {
|
||||
|
||||
pub use core::clone::Clone;
|
||||
"#,
|
||||
|map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
|
||||
);
|
||||
assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn expand_derive() {
|
||||
let map = compute_crate_def_map(
|
||||
compute_crate_def_map(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::Copy;
|
||||
@@ -775,8 +775,8 @@ fn expand_derive() {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
|map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2),
|
||||
);
|
||||
assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 2);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -803,7 +803,7 @@ pub trait Clone {}
|
||||
fn builtin_derive_with_unresolved_attributes_fall_back() {
|
||||
// Tests that we still resolve derives after ignoring an unresolved attribute.
|
||||
cov_mark::check!(unresolved_attribute_fallback);
|
||||
let map = compute_crate_def_map(
|
||||
compute_crate_def_map(
|
||||
r#"
|
||||
//- /main.rs crate:main deps:core
|
||||
use core::{Clone, derive};
|
||||
@@ -818,8 +818,8 @@ fn builtin_derive_with_unresolved_attributes_fall_back() {
|
||||
#[rustc_builtin_macro]
|
||||
pub macro Clone {}
|
||||
"#,
|
||||
|map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
|
||||
);
|
||||
assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -1096,7 +1096,7 @@ pub fn derive_macro_2(_item: TokenStream) -> TokenStream {
|
||||
"#,
|
||||
);
|
||||
let krate = *db.all_crates().last().expect("no crate graph present");
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
|
||||
assert_eq!(def_map.data.exported_derives.len(), 1);
|
||||
match def_map.data.exported_derives.values().next() {
|
||||
@@ -1446,7 +1446,7 @@ fn proc_attr(a: TokenStream, b: TokenStream) -> TokenStream { a }
|
||||
"#,
|
||||
);
|
||||
let krate = *db.all_crates().last().expect("no crate graph present");
|
||||
let def_map = db.crate_def_map(krate);
|
||||
let def_map = crate_def_map(&db, krate);
|
||||
|
||||
let root_module = &def_map[DefMap::ROOT].scope;
|
||||
assert!(
|
||||
@@ -1544,7 +1544,7 @@ macro_rules! foo {
|
||||
|
||||
#[test]
|
||||
fn macro_sub_namespace() {
|
||||
let map = compute_crate_def_map(
|
||||
compute_crate_def_map(
|
||||
r#"
|
||||
//- minicore: derive, clone
|
||||
macro_rules! Clone { () => {} }
|
||||
@@ -1553,8 +1553,8 @@ macro_rules! derive { () => {} }
|
||||
#[derive(Clone)]
|
||||
struct S;
|
||||
"#,
|
||||
|map| assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1),
|
||||
);
|
||||
assert_eq!(map.modules[DefMap::ROOT].scope.impls().len(), 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -839,6 +839,7 @@ fn circular_mods() {
|
||||
#[path = "./foo.rs"]
|
||||
mod foo;
|
||||
"#,
|
||||
|_| (),
|
||||
);
|
||||
|
||||
compute_crate_def_map(
|
||||
@@ -852,6 +853,7 @@ fn circular_mods() {
|
||||
#[path = "./foo.rs"]
|
||||
mod foo;
|
||||
"#,
|
||||
|_| (),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -894,3 +896,149 @@ fn cfg_in_module_file() {
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn invalid_imports() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs
|
||||
mod module;
|
||||
|
||||
use self::module::S::new;
|
||||
use self::module::unresolved;
|
||||
use self::module::C::const_based;
|
||||
use self::module::Enum::Variant::NoAssoc;
|
||||
|
||||
//- /module.rs
|
||||
pub struct S;
|
||||
impl S {
|
||||
pub fn new() {}
|
||||
}
|
||||
pub const C: () = ();
|
||||
pub enum Enum {
|
||||
Variant,
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
NoAssoc: _
|
||||
const_based: _
|
||||
module: t
|
||||
new: _
|
||||
unresolved: _
|
||||
|
||||
crate::module
|
||||
C: v
|
||||
Enum: t
|
||||
S: t v
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_item_imports_same_crate() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs
|
||||
mod module;
|
||||
|
||||
use self::module::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
|
||||
|
||||
//- /module.rs
|
||||
macro_rules! m {
|
||||
($name:ident) => { const $name: () = (); };
|
||||
}
|
||||
pub trait Trait {
|
||||
type AssocType;
|
||||
const ASSOC_CONST: ();
|
||||
fn method(&self);
|
||||
m!(MACRO_CONST);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
ASSOC_CONST: _
|
||||
AssocType: _
|
||||
MACRO_CONST: _
|
||||
method: _
|
||||
module: t
|
||||
|
||||
crate::module
|
||||
Trait: t
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs
|
||||
mod module;
|
||||
|
||||
use self::module::Trait::*;
|
||||
|
||||
//- /module.rs
|
||||
macro_rules! m {
|
||||
($name:ident) => { const $name: () = (); };
|
||||
}
|
||||
pub trait Trait {
|
||||
type AssocType;
|
||||
const ASSOC_CONST: ();
|
||||
fn method(&self);
|
||||
m!(MACRO_CONST);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
module: t
|
||||
|
||||
crate::module
|
||||
Trait: t
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_item_imports_differing_crate() {
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs deps:lib crate:main
|
||||
use lib::Trait::{AssocType, ASSOC_CONST, MACRO_CONST, method};
|
||||
|
||||
//- /lib.rs crate:lib
|
||||
macro_rules! m {
|
||||
($name:ident) => { const $name: () = (); };
|
||||
}
|
||||
pub trait Trait {
|
||||
type AssocType;
|
||||
const ASSOC_CONST: ();
|
||||
fn method(&self);
|
||||
m!(MACRO_CONST);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
ASSOC_CONST: _
|
||||
AssocType: _
|
||||
MACRO_CONST: _
|
||||
method: _
|
||||
"#]],
|
||||
);
|
||||
check(
|
||||
r#"
|
||||
//- /main.rs deps:lib crate:main
|
||||
use lib::Trait::*;
|
||||
|
||||
//- /lib.rs crate:lib
|
||||
macro_rules! m {
|
||||
($name:ident) => { const $name: () = (); };
|
||||
}
|
||||
pub trait Trait {
|
||||
type AssocType;
|
||||
const ASSOC_CONST: ();
|
||||
fn method(&self);
|
||||
m!(MACRO_CONST);
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
crate
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -34,30 +34,30 @@
|
||||
item_scope::{BUILTIN_SCOPE, BuiltinShadowMode, ImportOrExternCrate, ImportOrGlob, ItemScope},
|
||||
item_tree::ImportAlias,
|
||||
lang_item::LangItemTarget,
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo},
|
||||
nameres::{DefMap, LocalDefMap, MacroSubNs, ResolvePathResultPrefixInfo, block_def_map},
|
||||
per_ns::PerNs,
|
||||
type_ref::LifetimeRef,
|
||||
visibility::{RawVisibility, Visibility},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Resolver {
|
||||
pub struct Resolver<'db> {
|
||||
/// The stack of scopes, where the inner-most scope is the last item.
|
||||
///
|
||||
/// When using, you generally want to process the scopes in reverse order,
|
||||
/// there's `scopes` *method* for that.
|
||||
scopes: Vec<Scope>,
|
||||
module_scope: ModuleItemMap,
|
||||
scopes: Vec<Scope<'db>>,
|
||||
module_scope: ModuleItemMap<'db>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct ModuleItemMap {
|
||||
def_map: Arc<DefMap>,
|
||||
local_def_map: Arc<LocalDefMap>,
|
||||
struct ModuleItemMap<'db> {
|
||||
def_map: &'db DefMap,
|
||||
local_def_map: &'db LocalDefMap,
|
||||
module_id: LocalModuleId,
|
||||
}
|
||||
|
||||
impl fmt::Debug for ModuleItemMap {
|
||||
impl fmt::Debug for ModuleItemMap<'_> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ModuleItemMap").field("module_id", &self.module_id).finish()
|
||||
}
|
||||
@@ -80,9 +80,9 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Scope {
|
||||
enum Scope<'db> {
|
||||
/// All the items and imported names of a module
|
||||
BlockScope(ModuleItemMap),
|
||||
BlockScope(ModuleItemMap<'db>),
|
||||
/// Brings the generic parameters of an item into scope as well as the `Self` type alias /
|
||||
/// generic for ADTs and impls.
|
||||
GenericParams { def: GenericDefId, params: Arc<GenericParams> },
|
||||
@@ -133,7 +133,7 @@ pub enum LifetimeNs {
|
||||
LifetimeParam(LifetimeParamId),
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
impl<'db> Resolver<'db> {
|
||||
/// Resolve known trait from std, like `std::futures::Future`
|
||||
pub fn resolve_known_trait(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<TraitId> {
|
||||
let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
|
||||
@@ -580,7 +580,7 @@ pub fn names_in_scope(
|
||||
for scope in self.scopes() {
|
||||
scope.process_names(&mut res, db);
|
||||
}
|
||||
let ModuleItemMap { ref def_map, module_id, ref local_def_map } = self.module_scope;
|
||||
let ModuleItemMap { def_map, module_id, local_def_map } = self.module_scope;
|
||||
// FIXME: should we provide `self` here?
|
||||
// f(
|
||||
// Name::self_param(),
|
||||
@@ -842,14 +842,14 @@ pub fn rename_will_conflict_with_renamed(
|
||||
#[must_use]
|
||||
pub fn update_to_inner_scope(
|
||||
&mut self,
|
||||
db: &dyn DefDatabase,
|
||||
db: &'db dyn DefDatabase,
|
||||
owner: DefWithBodyId,
|
||||
expr_id: ExprId,
|
||||
) -> UpdateGuard {
|
||||
#[inline(always)]
|
||||
fn append_expr_scope(
|
||||
db: &dyn DefDatabase,
|
||||
resolver: &mut Resolver,
|
||||
fn append_expr_scope<'db>(
|
||||
db: &'db dyn DefDatabase,
|
||||
resolver: &mut Resolver<'db>,
|
||||
owner: DefWithBodyId,
|
||||
expr_scopes: &Arc<ExprScopes>,
|
||||
scope_id: ScopeId,
|
||||
@@ -863,7 +863,7 @@ fn append_expr_scope(
|
||||
scope_id,
|
||||
}));
|
||||
if let Some(block) = expr_scopes.block(scope_id) {
|
||||
let def_map = db.block_def_map(block);
|
||||
let def_map = block_def_map(db, block);
|
||||
let local_def_map = block.lookup(db).module.only_local_def_map(db);
|
||||
resolver.scopes.push(Scope::BlockScope(ModuleItemMap {
|
||||
def_map,
|
||||
@@ -945,8 +945,8 @@ fn hygiene_info(
|
||||
|
||||
pub struct UpdateGuard(usize);
|
||||
|
||||
impl Resolver {
|
||||
fn scopes(&self) -> impl Iterator<Item = &Scope> {
|
||||
impl<'db> Resolver<'db> {
|
||||
fn scopes(&self) -> impl Iterator<Item = &Scope<'db>> {
|
||||
self.scopes.iter().rev()
|
||||
}
|
||||
|
||||
@@ -970,12 +970,12 @@ fn resolve_module_path(
|
||||
fn item_scope_(&self) -> (&DefMap, &LocalDefMap, LocalModuleId) {
|
||||
self.scopes()
|
||||
.find_map(|scope| match scope {
|
||||
Scope::BlockScope(m) => Some((&*m.def_map, &*m.local_def_map, m.module_id)),
|
||||
Scope::BlockScope(m) => Some((m.def_map, m.local_def_map, m.module_id)),
|
||||
_ => None,
|
||||
})
|
||||
.unwrap_or((
|
||||
&self.module_scope.def_map,
|
||||
&self.module_scope.local_def_map,
|
||||
self.module_scope.def_map,
|
||||
self.module_scope.local_def_map,
|
||||
self.module_scope.module_id,
|
||||
))
|
||||
}
|
||||
@@ -992,8 +992,8 @@ pub enum ScopeDef {
|
||||
Label(LabelId),
|
||||
}
|
||||
|
||||
impl Scope {
|
||||
fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
|
||||
impl<'db> Scope<'db> {
|
||||
fn process_names(&self, acc: &mut ScopeNames, db: &'db dyn DefDatabase) {
|
||||
match self {
|
||||
Scope::BlockScope(m) => {
|
||||
m.def_map[m.module_id].scope.entries().for_each(|(name, def)| {
|
||||
@@ -1047,7 +1047,11 @@ fn process_names(&self, acc: &mut ScopeNames, db: &dyn DefDatabase) {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn resolver_for_expr(db: &dyn DefDatabase, owner: DefWithBodyId, expr_id: ExprId) -> Resolver {
|
||||
pub fn resolver_for_expr(
|
||||
db: &dyn DefDatabase,
|
||||
owner: DefWithBodyId,
|
||||
expr_id: ExprId,
|
||||
) -> Resolver<'_> {
|
||||
let r = owner.resolver(db);
|
||||
let scopes = db.expr_scopes(owner);
|
||||
let scope_id = scopes.scope_for(expr_id);
|
||||
@@ -1058,25 +1062,25 @@ pub fn resolver_for_scope(
|
||||
db: &dyn DefDatabase,
|
||||
owner: DefWithBodyId,
|
||||
scope_id: Option<ScopeId>,
|
||||
) -> Resolver {
|
||||
) -> Resolver<'_> {
|
||||
let r = owner.resolver(db);
|
||||
let scopes = db.expr_scopes(owner);
|
||||
resolver_for_scope_(db, scopes, scope_id, r, owner)
|
||||
}
|
||||
|
||||
fn resolver_for_scope_(
|
||||
db: &dyn DefDatabase,
|
||||
fn resolver_for_scope_<'db>(
|
||||
db: &'db dyn DefDatabase,
|
||||
scopes: Arc<ExprScopes>,
|
||||
scope_id: Option<ScopeId>,
|
||||
mut r: Resolver,
|
||||
mut r: Resolver<'db>,
|
||||
owner: DefWithBodyId,
|
||||
) -> Resolver {
|
||||
) -> Resolver<'db> {
|
||||
let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
|
||||
r.scopes.reserve(scope_chain.len());
|
||||
|
||||
for scope in scope_chain.into_iter().rev() {
|
||||
if let Some(block) = scopes.block(scope) {
|
||||
let def_map = db.block_def_map(block);
|
||||
let def_map = block_def_map(db, block);
|
||||
let local_def_map = block.lookup(db).module.only_local_def_map(db);
|
||||
r = r.push_block_scope(def_map, local_def_map);
|
||||
// FIXME: This adds as many module scopes as there are blocks, but resolving in each
|
||||
@@ -1092,18 +1096,26 @@ fn resolver_for_scope_(
|
||||
r
|
||||
}
|
||||
|
||||
impl Resolver {
|
||||
fn push_scope(mut self, scope: Scope) -> Resolver {
|
||||
impl<'db> Resolver<'db> {
|
||||
fn push_scope(mut self, scope: Scope<'db>) -> Resolver<'db> {
|
||||
self.scopes.push(scope);
|
||||
self
|
||||
}
|
||||
|
||||
fn push_generic_params_scope(self, db: &dyn DefDatabase, def: GenericDefId) -> Resolver {
|
||||
fn push_generic_params_scope(
|
||||
self,
|
||||
db: &'db dyn DefDatabase,
|
||||
def: GenericDefId,
|
||||
) -> Resolver<'db> {
|
||||
let params = db.generic_params(def);
|
||||
self.push_scope(Scope::GenericParams { def, params })
|
||||
}
|
||||
|
||||
fn push_block_scope(self, def_map: Arc<DefMap>, local_def_map: Arc<LocalDefMap>) -> Resolver {
|
||||
fn push_block_scope(
|
||||
self,
|
||||
def_map: &'db DefMap,
|
||||
local_def_map: &'db LocalDefMap,
|
||||
) -> Resolver<'db> {
|
||||
self.push_scope(Scope::BlockScope(ModuleItemMap {
|
||||
def_map,
|
||||
local_def_map,
|
||||
@@ -1116,19 +1128,19 @@ fn push_expr_scope(
|
||||
owner: DefWithBodyId,
|
||||
expr_scopes: Arc<ExprScopes>,
|
||||
scope_id: ScopeId,
|
||||
) -> Resolver {
|
||||
) -> Resolver<'db> {
|
||||
self.push_scope(Scope::ExprScope(ExprScope { owner, expr_scopes, scope_id }))
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleItemMap {
|
||||
impl<'db> ModuleItemMap<'db> {
|
||||
fn resolve_path_in_value_ns(
|
||||
&self,
|
||||
db: &dyn DefDatabase,
|
||||
db: &'db dyn DefDatabase,
|
||||
path: &ModPath,
|
||||
) -> Option<(ResolveValueResult, ResolvePathResultPrefixInfo)> {
|
||||
let (module_def, unresolved_idx, prefix_info) = self.def_map.resolve_path_locally(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
db,
|
||||
self.module_id,
|
||||
path,
|
||||
@@ -1167,7 +1179,7 @@ fn resolve_path_in_type_ns(
|
||||
) -> Option<(TypeNs, Option<usize>, Option<ImportOrExternCrate>, ResolvePathResultPrefixInfo)>
|
||||
{
|
||||
let (module_def, idx, prefix_info) = self.def_map.resolve_path_locally(
|
||||
&self.local_def_map,
|
||||
self.local_def_map,
|
||||
db,
|
||||
self.module_id,
|
||||
path,
|
||||
@@ -1263,11 +1275,11 @@ fn add_local(&mut self, name: &Name, binding: BindingId) {
|
||||
|
||||
pub trait HasResolver: Copy {
|
||||
/// Builds a resolver for type references inside this def.
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver;
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_>;
|
||||
}
|
||||
|
||||
impl HasResolver for ModuleId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
let (mut def_map, local_def_map) = self.local_def_map(db);
|
||||
let mut module_id = self.local_id;
|
||||
|
||||
@@ -1289,21 +1301,17 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
let mut resolver = Resolver {
|
||||
scopes: Vec::with_capacity(modules.len()),
|
||||
module_scope: ModuleItemMap {
|
||||
def_map,
|
||||
local_def_map: local_def_map.clone(),
|
||||
module_id,
|
||||
},
|
||||
module_scope: ModuleItemMap { def_map, local_def_map, module_id },
|
||||
};
|
||||
for def_map in modules.into_iter().rev() {
|
||||
resolver = resolver.push_block_scope(def_map, local_def_map.clone());
|
||||
resolver = resolver.push_block_scope(def_map, local_def_map);
|
||||
}
|
||||
resolver
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for CrateRootModuleId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
let (def_map, local_def_map) = self.local_def_map(db);
|
||||
Resolver {
|
||||
scopes: vec![],
|
||||
@@ -1313,75 +1321,75 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for TraitId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for TraitAliasId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Into<AdtId> + Copy> HasResolver for T {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
let def = self.into();
|
||||
def.module(db).resolver(db).push_generic_params_scope(db, def.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for FunctionId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for ConstId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for StaticId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for TypeAliasId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for ImplId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for ExternBlockId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
// Same as parent's
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for ExternCrateId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for UseId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for DefWithBodyId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
match self {
|
||||
DefWithBodyId::ConstId(c) => c.resolver(db),
|
||||
DefWithBodyId::FunctionId(f) => f.resolver(db),
|
||||
@@ -1392,7 +1400,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for ItemContainerId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
match self {
|
||||
ItemContainerId::ModuleId(it) => it.resolver(db),
|
||||
ItemContainerId::TraitId(it) => it.resolver(db),
|
||||
@@ -1403,7 +1411,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for GenericDefId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
match self {
|
||||
GenericDefId::FunctionId(inner) => inner.resolver(db),
|
||||
GenericDefId::AdtId(adt) => adt.resolver(db),
|
||||
@@ -1418,13 +1426,13 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for EnumVariantId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
self.lookup(db).parent.resolver(db)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for VariantId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
match self {
|
||||
VariantId::EnumVariantId(it) => it.resolver(db),
|
||||
VariantId::StructId(it) => it.resolver(db),
|
||||
@@ -1434,7 +1442,7 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for MacroId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
match self {
|
||||
MacroId::Macro2Id(it) => it.resolver(db),
|
||||
MacroId::MacroRulesId(it) => it.resolver(db),
|
||||
@@ -1444,29 +1452,29 @@ fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
}
|
||||
|
||||
impl HasResolver for Macro2Id {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for ProcMacroId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl HasResolver for MacroRulesId {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver {
|
||||
fn resolver(self, db: &dyn DefDatabase) -> Resolver<'_> {
|
||||
lookup_resolver(db, self)
|
||||
}
|
||||
}
|
||||
|
||||
fn lookup_resolver<'db>(
|
||||
db: &(dyn DefDatabase + 'db),
|
||||
fn lookup_resolver(
|
||||
db: &dyn DefDatabase,
|
||||
lookup: impl Lookup<
|
||||
Database = dyn DefDatabase,
|
||||
Data = impl ItemTreeLoc<Container = impl HasResolver>,
|
||||
>,
|
||||
) -> Resolver {
|
||||
) -> Resolver<'_> {
|
||||
lookup.lookup(db).container().resolver(db)
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
use crate::{
|
||||
LocalModuleId, Lookup, ModuleDefId, ModuleId,
|
||||
db::DefDatabase,
|
||||
nameres::{DefMap, ModuleSource},
|
||||
nameres::{DefMap, ModuleSource, block_def_map, crate_def_map},
|
||||
src::HasSource,
|
||||
};
|
||||
|
||||
@@ -133,7 +133,7 @@ pub(crate) fn fetch_test_crate(&self) -> Crate {
|
||||
|
||||
pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
|
||||
for &krate in self.relevant_crates(file_id).iter() {
|
||||
let crate_def_map = self.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(self, krate);
|
||||
for (local_id, data) in crate_def_map.modules() {
|
||||
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
|
||||
return crate_def_map.module_id(local_id);
|
||||
@@ -146,16 +146,16 @@ pub(crate) fn module_for_file(&self, file_id: FileId) -> ModuleId {
|
||||
pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
|
||||
let file_module = self.module_for_file(position.file_id.file_id(self));
|
||||
let mut def_map = file_module.def_map(self);
|
||||
let module = self.mod_at_position(&def_map, position);
|
||||
let module = self.mod_at_position(def_map, position);
|
||||
|
||||
def_map = match self.block_at_position(&def_map, position) {
|
||||
def_map = match self.block_at_position(def_map, position) {
|
||||
Some(it) => it,
|
||||
None => return def_map.module_id(module),
|
||||
};
|
||||
loop {
|
||||
let new_map = self.block_at_position(&def_map, position);
|
||||
let new_map = self.block_at_position(def_map, position);
|
||||
match new_map {
|
||||
Some(new_block) if !Arc::ptr_eq(&new_block, &def_map) => {
|
||||
Some(new_block) if !std::ptr::eq(&new_block, &def_map) => {
|
||||
def_map = new_block;
|
||||
}
|
||||
_ => {
|
||||
@@ -206,7 +206,7 @@ fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModu
|
||||
res
|
||||
}
|
||||
|
||||
fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
|
||||
fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<&DefMap> {
|
||||
// Find the smallest (innermost) function in `def_map` containing the cursor.
|
||||
let mut size = None;
|
||||
let mut fn_def = None;
|
||||
@@ -263,7 +263,7 @@ fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<
|
||||
let mut containing_blocks =
|
||||
scopes.scope_chain(Some(scope)).filter_map(|scope| scopes.block(scope));
|
||||
|
||||
if let Some(block) = containing_blocks.next().map(|block| self.block_def_map(block)) {
|
||||
if let Some(block) = containing_blocks.next().map(|block| block_def_map(self, block)) {
|
||||
return Some(block);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ pub enum Visibility {
|
||||
impl Visibility {
|
||||
pub fn resolve(
|
||||
db: &dyn DefDatabase,
|
||||
resolver: &crate::resolver::Resolver,
|
||||
resolver: &crate::resolver::Resolver<'_>,
|
||||
raw_vis: &RawVisibility,
|
||||
) -> Self {
|
||||
// we fall back to public visibility (i.e. fail open) if the path can't be resolved
|
||||
@@ -50,7 +50,7 @@ pub fn is_visible_from(self, db: &dyn DefDatabase, from_module: ModuleId) -> boo
|
||||
return false;
|
||||
}
|
||||
let def_map = from_module.def_map(db);
|
||||
Self::is_visible_from_def_map_(db, &def_map, to_module, from_module.local_id)
|
||||
Self::is_visible_from_def_map_(db, def_map, to_module, from_module.local_id)
|
||||
}
|
||||
|
||||
pub(crate) fn is_visible_from_def_map(
|
||||
@@ -116,7 +116,7 @@ fn is_visible_from_def_map_(
|
||||
match def_map.parent() {
|
||||
Some(module) => {
|
||||
parent_arc = module.def_map(db);
|
||||
def_map = &*parent_arc;
|
||||
def_map = parent_arc;
|
||||
from_module = module.local_id;
|
||||
}
|
||||
// Reached the root module, nothing left to check.
|
||||
@@ -257,7 +257,7 @@ pub(crate) fn type_alias_visibility_query(db: &dyn DefDatabase, def: TypeAliasId
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver, trait_id: TraitId) -> Visibility {
|
||||
fn trait_vis(db: &dyn DefDatabase, resolver: &Resolver<'_>, trait_id: TraitId) -> Visibility {
|
||||
let ItemLoc { id: tree_id, .. } = trait_id.lookup(db);
|
||||
let item_tree = tree_id.item_tree(db);
|
||||
let tr_def = &item_tree[tree_id.value];
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
//! A higher level attributes based on TokenTree, with also some shortcuts.
|
||||
use std::iter;
|
||||
use std::{borrow::Cow, fmt, ops};
|
||||
|
||||
use base_db::Crate;
|
||||
@@ -122,16 +123,15 @@ pub fn merge(&self, other: Self) -> Self {
|
||||
(None, entries @ Some(_)) => Self { entries },
|
||||
(Some(entries), None) => Self { entries: Some(entries.clone()) },
|
||||
(Some(a), Some(b)) => {
|
||||
let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1) as u32;
|
||||
let last_ast_index = a.slice.last().map_or(0, |it| it.id.ast_index() + 1);
|
||||
let items = a
|
||||
.slice
|
||||
.iter()
|
||||
.cloned()
|
||||
.chain(b.slice.iter().map(|it| {
|
||||
let mut it = it.clone();
|
||||
it.id.id = (it.id.ast_index() as u32 + last_ast_index)
|
||||
| ((it.id.cfg_attr_index().unwrap_or(0) as u32)
|
||||
<< AttrId::AST_INDEX_BITS);
|
||||
let id = it.id.ast_index() + last_ast_index;
|
||||
it.id = AttrId::new(id, it.id.is_inner_attr());
|
||||
it
|
||||
}))
|
||||
.collect::<Vec<_>>();
|
||||
@@ -175,25 +175,20 @@ pub struct AttrId {
|
||||
// FIXME: This only handles a single level of cfg_attr nesting
|
||||
// that is `#[cfg_attr(all(), cfg_attr(all(), cfg(any())))]` breaks again
|
||||
impl AttrId {
|
||||
const CFG_ATTR_BITS: usize = 7;
|
||||
const AST_INDEX_MASK: usize = 0x00FF_FFFF;
|
||||
const AST_INDEX_BITS: usize = Self::AST_INDEX_MASK.count_ones() as usize;
|
||||
const CFG_ATTR_SET_BITS: u32 = 1 << 31;
|
||||
const INNER_ATTR_SET_BIT: u32 = 1 << 31;
|
||||
|
||||
pub fn new(id: usize, is_inner: bool) -> Self {
|
||||
assert!(id <= !Self::INNER_ATTR_SET_BIT as usize);
|
||||
let id = id as u32;
|
||||
Self { id: if is_inner { id | Self::INNER_ATTR_SET_BIT } else { id } }
|
||||
}
|
||||
|
||||
pub fn ast_index(&self) -> usize {
|
||||
self.id as usize & Self::AST_INDEX_MASK
|
||||
(self.id & !Self::INNER_ATTR_SET_BIT) as usize
|
||||
}
|
||||
|
||||
pub fn cfg_attr_index(&self) -> Option<usize> {
|
||||
if self.id & Self::CFG_ATTR_SET_BITS == 0 {
|
||||
None
|
||||
} else {
|
||||
Some(self.id as usize >> Self::AST_INDEX_BITS)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn with_cfg_attr(self, idx: usize) -> AttrId {
|
||||
AttrId { id: self.id | ((idx as u32) << Self::AST_INDEX_BITS) | Self::CFG_ATTR_SET_BITS }
|
||||
pub fn is_inner_attr(&self) -> bool {
|
||||
self.id & Self::INNER_ATTR_SET_BIT != 0
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,10 +328,7 @@ pub fn expand_cfg_attr(
|
||||
None => return smallvec![self.clone()],
|
||||
};
|
||||
let index = self.id;
|
||||
let attrs = parts
|
||||
.enumerate()
|
||||
.take(1 << AttrId::CFG_ATTR_BITS)
|
||||
.filter_map(|(idx, attr)| Attr::from_tt(db, attr, index.with_cfg_attr(idx)));
|
||||
let attrs = parts.filter_map(|attr| Attr::from_tt(db, attr, index));
|
||||
|
||||
let cfg = TopSubtree::from_token_trees(subtree.top_subtree().delimiter, cfg);
|
||||
let cfg = CfgExpr::parse(&cfg);
|
||||
@@ -467,13 +459,18 @@ fn unescape(s: &str) -> Option<Cow<'_, str>> {
|
||||
pub fn collect_attrs(
|
||||
owner: &dyn ast::HasAttrs,
|
||||
) -> impl Iterator<Item = (AttrId, Either<ast::Attr, ast::Comment>)> {
|
||||
let inner_attrs = inner_attributes(owner.syntax()).into_iter().flatten();
|
||||
let outer_attrs =
|
||||
ast::AttrDocCommentIter::from_syntax_node(owner.syntax()).filter(|el| match el {
|
||||
let inner_attrs =
|
||||
inner_attributes(owner.syntax()).into_iter().flatten().zip(iter::repeat(true));
|
||||
let outer_attrs = ast::AttrDocCommentIter::from_syntax_node(owner.syntax())
|
||||
.filter(|el| match el {
|
||||
Either::Left(attr) => attr.kind().is_outer(),
|
||||
Either::Right(comment) => comment.is_outer(),
|
||||
});
|
||||
outer_attrs.chain(inner_attrs).enumerate().map(|(id, attr)| (AttrId { id: id as u32 }, attr))
|
||||
})
|
||||
.zip(iter::repeat(false));
|
||||
outer_attrs
|
||||
.chain(inner_attrs)
|
||||
.enumerate()
|
||||
.map(|(id, (attr, is_inner))| (AttrId::new(id, is_inner), attr))
|
||||
}
|
||||
|
||||
fn inner_attributes(
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
//! Builtin derives.
|
||||
|
||||
use either::Either;
|
||||
use intern::sym;
|
||||
use itertools::{Itertools, izip};
|
||||
use parser::SyntaxKind;
|
||||
@@ -1179,10 +1180,10 @@ fn coerce_pointee_expand(
|
||||
};
|
||||
new_predicates.push(
|
||||
make::where_pred(
|
||||
make::ty_path(make::path_from_segments(
|
||||
Either::Right(make::ty_path(make::path_from_segments(
|
||||
[make::path_segment(new_bounds_target)],
|
||||
false,
|
||||
)),
|
||||
))),
|
||||
new_bounds,
|
||||
)
|
||||
.clone_for_update(),
|
||||
@@ -1245,7 +1246,9 @@ fn coerce_pointee_expand(
|
||||
substitute_type_in_bound(ty, &pointee_param_name.text(), ADDED_PARAM)
|
||||
})
|
||||
});
|
||||
new_predicates.push(make::where_pred(pred_target, new_bounds).clone_for_update());
|
||||
new_predicates.push(
|
||||
make::where_pred(Either::Right(pred_target), new_bounds).clone_for_update(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1260,10 +1263,10 @@ fn coerce_pointee_expand(
|
||||
// Find the `#[pointee]` parameter and add an `Unsize<__S>` bound to it.
|
||||
where_clause.add_predicate(
|
||||
make::where_pred(
|
||||
make::ty_path(make::path_from_segments(
|
||||
Either::Right(make::ty_path(make::path_from_segments(
|
||||
[make::path_segment(make::name_ref(&pointee_param_name.text()))],
|
||||
false,
|
||||
)),
|
||||
))),
|
||||
[make::type_bound(make::ty_path(make::path_from_segments(
|
||||
[
|
||||
make::path_segment(make::name_ref("core")),
|
||||
|
||||
@@ -452,7 +452,10 @@ fn concat_expand(
|
||||
Some(_) => (),
|
||||
None => span = Some(s),
|
||||
};
|
||||
for (i, mut t) in tt.iter().enumerate() {
|
||||
|
||||
let mut i = 0;
|
||||
let mut iter = tt.iter();
|
||||
while let Some(mut t) = iter.next() {
|
||||
// FIXME: hack on top of a hack: `$e:expr` captures get surrounded in parentheses
|
||||
// to ensure the right parsing order, so skip the parentheses here. Ideally we'd
|
||||
// implement rustc's model. cc https://github.com/rust-lang/rust-analyzer/pull/10623
|
||||
@@ -504,10 +507,40 @@ fn concat_expand(
|
||||
record_span(id.span);
|
||||
}
|
||||
TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
|
||||
// handle negative numbers
|
||||
TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 0 && punct.char == '-' => {
|
||||
let t = match iter.next() {
|
||||
Some(t) => t,
|
||||
None => {
|
||||
err.get_or_insert(ExpandError::other(
|
||||
call_site,
|
||||
"unexpected end of input after '-'",
|
||||
));
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
match t {
|
||||
TtElement::Leaf(tt::Leaf::Literal(it))
|
||||
if matches!(it.kind, tt::LitKind::Integer | tt::LitKind::Float) =>
|
||||
{
|
||||
format_to!(text, "-{}", it.symbol.as_str());
|
||||
record_span(punct.span.cover(it.span));
|
||||
}
|
||||
_ => {
|
||||
err.get_or_insert(ExpandError::other(
|
||||
call_site,
|
||||
"expected integer or floating pointer number after '-'",
|
||||
));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
err.get_or_insert(ExpandError::other(call_site, "unexpected token"));
|
||||
}
|
||||
}
|
||||
i += 1;
|
||||
}
|
||||
let span = span.unwrap_or_else(|| tt.top_subtree().delimiter.open);
|
||||
ExpandResult { value: quote!(span =>#text), err }
|
||||
|
||||
@@ -19,18 +19,8 @@ pub enum ProcMacroKind {
|
||||
Attr,
|
||||
}
|
||||
|
||||
pub trait AsAny: Any {
|
||||
fn as_any(&self) -> &dyn Any;
|
||||
}
|
||||
|
||||
impl<T: Any> AsAny for T {
|
||||
fn as_any(&self) -> &dyn Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// A proc-macro expander implementation.
|
||||
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + AsAny {
|
||||
pub trait ProcMacroExpander: fmt::Debug + Send + Sync + RefUnwindSafe + Any {
|
||||
/// Run the expander with the given input subtree, optional attribute input subtree (for
|
||||
/// [`ProcMacroKind::Attr`]), environment variables, and span information.
|
||||
fn expand(
|
||||
@@ -44,7 +34,9 @@ fn expand(
|
||||
current_dir: String,
|
||||
) -> Result<tt::TopSubtree, ProcMacroExpansionError>;
|
||||
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool;
|
||||
fn eq_dyn(&self, other: &dyn ProcMacroExpander) -> bool {
|
||||
other.type_id() == self.type_id()
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq for dyn ProcMacroExpander {
|
||||
|
||||
@@ -91,7 +91,7 @@ fn from(value: MirEvalError) -> Self {
|
||||
|
||||
pub(crate) fn path_to_const<'g>(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
path: &Path,
|
||||
mode: ParamLoweringMode,
|
||||
args: impl FnOnce() -> &'g Generics,
|
||||
|
||||
@@ -480,7 +480,7 @@ struct FilterMapNextChecker {
|
||||
}
|
||||
|
||||
impl FilterMapNextChecker {
|
||||
fn new(resolver: &hir_def::resolver::Resolver, db: &dyn HirDatabase) -> Self {
|
||||
fn new(resolver: &hir_def::resolver::Resolver<'_>, db: &dyn HirDatabase) -> Self {
|
||||
// Find and store the FunctionIds for Iterator::filter_map and Iterator::next
|
||||
let (next_function_id, filter_map_function_id) = match LangItem::IteratorNext
|
||||
.resolve_function(db, resolver.krate())
|
||||
|
||||
@@ -73,7 +73,7 @@ pub(crate) struct MatchCheckCtx<'db> {
|
||||
|
||||
impl<'db> MatchCheckCtx<'db> {
|
||||
pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
|
||||
let def_map = db.crate_def_map(module.krate());
|
||||
let def_map = module.crate_def_map(db);
|
||||
let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
|
||||
Self { module, body, db, exhaustive_patterns }
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
use hir_def::{
|
||||
AdtId, DefWithBodyId, FieldId, FunctionId, VariantId,
|
||||
expr_store::{Body, path::Path},
|
||||
hir::{Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
|
||||
hir::{AsmOperand, Expr, ExprId, ExprOrPatId, Pat, PatId, Statement, UnaryOp},
|
||||
resolver::{HasResolver, ResolveValueResult, Resolver, ValueNs},
|
||||
signatures::StaticFlags,
|
||||
type_ref::Rawness,
|
||||
@@ -131,28 +131,28 @@ pub fn unsafe_operations(
|
||||
visitor.walk_expr(current);
|
||||
}
|
||||
|
||||
struct UnsafeVisitor<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
infer: &'a InferenceResult,
|
||||
body: &'a Body,
|
||||
resolver: Resolver,
|
||||
struct UnsafeVisitor<'db> {
|
||||
db: &'db dyn HirDatabase,
|
||||
infer: &'db InferenceResult,
|
||||
body: &'db Body,
|
||||
resolver: Resolver<'db>,
|
||||
def: DefWithBodyId,
|
||||
inside_unsafe_block: InsideUnsafeBlock,
|
||||
inside_assignment: bool,
|
||||
inside_union_destructure: bool,
|
||||
callback: &'a mut dyn FnMut(UnsafeDiagnostic),
|
||||
callback: &'db mut dyn FnMut(UnsafeDiagnostic),
|
||||
def_target_features: TargetFeatures,
|
||||
// FIXME: This needs to be the edition of the span of each call.
|
||||
edition: Edition,
|
||||
}
|
||||
|
||||
impl<'a> UnsafeVisitor<'a> {
|
||||
impl<'db> UnsafeVisitor<'db> {
|
||||
fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
infer: &'a InferenceResult,
|
||||
body: &'a Body,
|
||||
db: &'db dyn HirDatabase,
|
||||
infer: &'db InferenceResult,
|
||||
body: &'db Body,
|
||||
def: DefWithBodyId,
|
||||
unsafe_expr_cb: &'a mut dyn FnMut(UnsafeDiagnostic),
|
||||
unsafe_expr_cb: &'db mut dyn FnMut(UnsafeDiagnostic),
|
||||
) -> Self {
|
||||
let resolver = def.resolver(db);
|
||||
let def_target_features = match def {
|
||||
@@ -199,6 +199,17 @@ fn check_call(&mut self, node: ExprId, func: FunctionId) {
|
||||
}
|
||||
}
|
||||
|
||||
fn with_inside_unsafe_block<R>(
|
||||
&mut self,
|
||||
inside_unsafe_block: InsideUnsafeBlock,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let old = mem::replace(&mut self.inside_unsafe_block, inside_unsafe_block);
|
||||
let result = f(self);
|
||||
self.inside_unsafe_block = old;
|
||||
result
|
||||
}
|
||||
|
||||
fn walk_pats_top(&mut self, pats: impl Iterator<Item = PatId>, parent_expr: ExprId) {
|
||||
let guard = self.resolver.update_to_inner_scope(self.db, self.def, parent_expr);
|
||||
pats.for_each(|pat| self.walk_pat(pat));
|
||||
@@ -303,7 +314,29 @@ fn walk_expr(&mut self, current: ExprId) {
|
||||
self.walk_pats_top(std::iter::once(target), current);
|
||||
self.inside_assignment = old_inside_assignment;
|
||||
}
|
||||
Expr::InlineAsm(_) => self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm),
|
||||
Expr::InlineAsm(asm) => {
|
||||
self.on_unsafe_op(current.into(), UnsafetyReason::InlineAsm);
|
||||
asm.operands.iter().for_each(|(_, op)| match op {
|
||||
AsmOperand::In { expr, .. }
|
||||
| AsmOperand::Out { expr: Some(expr), .. }
|
||||
| AsmOperand::InOut { expr, .. }
|
||||
| AsmOperand::Const(expr) => self.walk_expr(*expr),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
self.walk_expr(*in_expr);
|
||||
if let Some(out_expr) = out_expr {
|
||||
self.walk_expr(*out_expr);
|
||||
}
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. } | AsmOperand::Sym(_) => (),
|
||||
AsmOperand::Label(expr) => {
|
||||
// Inline asm labels are considered safe even when inside unsafe blocks.
|
||||
self.with_inside_unsafe_block(InsideUnsafeBlock::No, |this| {
|
||||
this.walk_expr(*expr)
|
||||
});
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
// rustc allows union assignment to propagate through field accesses and casts.
|
||||
Expr::Cast { .. } => self.inside_assignment = inside_assignment,
|
||||
Expr::Field { .. } => {
|
||||
@@ -317,17 +350,16 @@ fn walk_expr(&mut self, current: ExprId) {
|
||||
}
|
||||
}
|
||||
Expr::Unsafe { statements, .. } => {
|
||||
let old_inside_unsafe_block =
|
||||
mem::replace(&mut self.inside_unsafe_block, InsideUnsafeBlock::Yes);
|
||||
self.walk_pats_top(
|
||||
statements.iter().filter_map(|statement| match statement {
|
||||
&Statement::Let { pat, .. } => Some(pat),
|
||||
_ => None,
|
||||
}),
|
||||
current,
|
||||
);
|
||||
self.body.walk_child_exprs_without_pats(current, |child| self.walk_expr(child));
|
||||
self.inside_unsafe_block = old_inside_unsafe_block;
|
||||
self.with_inside_unsafe_block(InsideUnsafeBlock::Yes, |this| {
|
||||
this.walk_pats_top(
|
||||
statements.iter().filter_map(|statement| match statement {
|
||||
&Statement::Let { pat, .. } => Some(pat),
|
||||
_ => None,
|
||||
}),
|
||||
current,
|
||||
);
|
||||
this.body.walk_child_exprs_without_pats(current, |child| this.walk_expr(child));
|
||||
});
|
||||
return;
|
||||
}
|
||||
Expr::Block { statements, .. } | Expr::Async { statements, .. } => {
|
||||
|
||||
@@ -9,8 +9,8 @@
|
||||
};
|
||||
use chalk_solve::rust_ir::InlineBound;
|
||||
use hir_def::{
|
||||
AssocItemId, ConstId, FunctionId, GenericDefId, HasModule, TraitId, TypeAliasId,
|
||||
lang_item::LangItem, signatures::TraitFlags,
|
||||
AssocItemId, ConstId, CrateRootModuleId, FunctionId, GenericDefId, HasModule, TraitId,
|
||||
TypeAliasId, lang_item::LangItem, signatures::TraitFlags,
|
||||
};
|
||||
use rustc_hash::FxHashSet;
|
||||
use smallvec::SmallVec;
|
||||
@@ -343,7 +343,7 @@ fn dyn_compatibility_violation_for_assoc_item<F>(
|
||||
})
|
||||
}
|
||||
AssocItemId::TypeAliasId(it) => {
|
||||
let def_map = db.crate_def_map(trait_.krate(db));
|
||||
let def_map = CrateRootModuleId::from(trait_.krate(db)).def_map(db);
|
||||
if def_map.is_unstable_feature_enabled(&intern::sym::generic_associated_type_extended) {
|
||||
ControlFlow::Continue(())
|
||||
} else {
|
||||
|
||||
@@ -594,16 +594,16 @@ fn index(&self, b: BindingId) -> &Ty {
|
||||
|
||||
/// The inference context contains all information needed during type inference.
|
||||
#[derive(Clone, Debug)]
|
||||
pub(crate) struct InferenceContext<'a> {
|
||||
pub(crate) db: &'a dyn HirDatabase,
|
||||
pub(crate) struct InferenceContext<'db> {
|
||||
pub(crate) db: &'db dyn HirDatabase,
|
||||
pub(crate) owner: DefWithBodyId,
|
||||
pub(crate) body: &'a Body,
|
||||
pub(crate) body: &'db Body,
|
||||
/// Generally you should not resolve things via this resolver. Instead create a TyLoweringContext
|
||||
/// and resolve the path via its methods. This will ensure proper error reporting.
|
||||
pub(crate) resolver: Resolver,
|
||||
pub(crate) resolver: Resolver<'db>,
|
||||
generic_def: GenericDefId,
|
||||
generics: OnceCell<Generics>,
|
||||
table: unify::InferenceTable<'a>,
|
||||
table: unify::InferenceTable<'db>,
|
||||
/// The traits in scope, disregarding block modules. This is used for caching purposes.
|
||||
traits_in_scope: FxHashSet<TraitId>,
|
||||
pub(crate) result: InferenceResult,
|
||||
@@ -695,12 +695,12 @@ enum ImplTraitReplacingMode {
|
||||
TypeAlias,
|
||||
}
|
||||
|
||||
impl<'a> InferenceContext<'a> {
|
||||
impl<'db> InferenceContext<'db> {
|
||||
fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
body: &'a Body,
|
||||
resolver: Resolver,
|
||||
body: &'db Body,
|
||||
resolver: Resolver<'db>,
|
||||
) -> Self {
|
||||
let trait_env = db.trait_environment_for_body(owner);
|
||||
InferenceContext {
|
||||
|
||||
@@ -61,7 +61,7 @@ impl<'a> InferenceTyLoweringContext<'a> {
|
||||
#[inline]
|
||||
pub(super) fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
resolver: &'a Resolver,
|
||||
resolver: &'a Resolver<'_>,
|
||||
store: &'a ExpressionStore,
|
||||
diagnostics: &'a Diagnostics,
|
||||
source: InferenceTyDiagnosticSource,
|
||||
|
||||
@@ -959,8 +959,8 @@ fn infer_expr_inner(
|
||||
}
|
||||
Expr::OffsetOf(_) => TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(Interner),
|
||||
Expr::InlineAsm(asm) => {
|
||||
let mut check_expr_asm_operand = |expr, is_input: bool| {
|
||||
let ty = self.infer_expr_no_expect(expr, ExprIsRead::Yes);
|
||||
let check_expr_asm_operand = |this: &mut Self, expr, is_input: bool| {
|
||||
let ty = this.infer_expr_no_expect(expr, ExprIsRead::Yes);
|
||||
|
||||
// If this is an input value, we require its type to be fully resolved
|
||||
// at this point. This allows us to provide helpful coercions which help
|
||||
@@ -970,18 +970,18 @@ fn infer_expr_inner(
|
||||
// allows them to be inferred based on how they are used later in the
|
||||
// function.
|
||||
if is_input {
|
||||
let ty = self.resolve_ty_shallow(&ty);
|
||||
let ty = this.resolve_ty_shallow(&ty);
|
||||
match ty.kind(Interner) {
|
||||
TyKind::FnDef(def, parameters) => {
|
||||
let fnptr_ty = TyKind::Function(
|
||||
CallableSig::from_def(self.db, *def, parameters).to_fn_ptr(),
|
||||
CallableSig::from_def(this.db, *def, parameters).to_fn_ptr(),
|
||||
)
|
||||
.intern(Interner);
|
||||
_ = self.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
|
||||
_ = this.coerce(Some(expr), &ty, &fnptr_ty, CoerceNever::Yes);
|
||||
}
|
||||
TyKind::Ref(mutbl, _, base_ty) => {
|
||||
let ptr_ty = TyKind::Raw(*mutbl, base_ty.clone()).intern(Interner);
|
||||
_ = self.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
|
||||
_ = this.coerce(Some(expr), &ty, &ptr_ty, CoerceNever::Yes);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
@@ -990,22 +990,28 @@ fn infer_expr_inner(
|
||||
|
||||
let diverge = asm.options.contains(AsmOptions::NORETURN);
|
||||
asm.operands.iter().for_each(|(_, operand)| match *operand {
|
||||
AsmOperand::In { expr, .. } => check_expr_asm_operand(expr, true),
|
||||
AsmOperand::In { expr, .. } => check_expr_asm_operand(self, expr, true),
|
||||
AsmOperand::Out { expr: Some(expr), .. } | AsmOperand::InOut { expr, .. } => {
|
||||
check_expr_asm_operand(expr, false)
|
||||
check_expr_asm_operand(self, expr, false)
|
||||
}
|
||||
AsmOperand::Out { expr: None, .. } => (),
|
||||
AsmOperand::SplitInOut { in_expr, out_expr, .. } => {
|
||||
check_expr_asm_operand(in_expr, true);
|
||||
check_expr_asm_operand(self, in_expr, true);
|
||||
if let Some(out_expr) = out_expr {
|
||||
check_expr_asm_operand(out_expr, false);
|
||||
check_expr_asm_operand(self, out_expr, false);
|
||||
}
|
||||
}
|
||||
// FIXME
|
||||
AsmOperand::Label(_) => (),
|
||||
// FIXME
|
||||
AsmOperand::Const(_) => (),
|
||||
// FIXME
|
||||
AsmOperand::Label(expr) => {
|
||||
self.infer_expr(
|
||||
expr,
|
||||
&Expectation::HasType(self.result.standard_types.unit.clone()),
|
||||
ExprIsRead::No,
|
||||
);
|
||||
}
|
||||
AsmOperand::Const(expr) => {
|
||||
self.infer_expr(expr, &Expectation::None, ExprIsRead::No);
|
||||
}
|
||||
// FIXME: `sym` should report for things that are not functions or statics.
|
||||
AsmOperand::Sym(_) => (),
|
||||
});
|
||||
if diverge {
|
||||
|
||||
@@ -42,7 +42,6 @@
|
||||
use hir_expand::name::Name;
|
||||
use la_arena::{Arena, ArenaMap};
|
||||
use rustc_hash::FxHashSet;
|
||||
use rustc_pattern_analysis::Captures;
|
||||
use stdx::{impl_from, never};
|
||||
use triomphe::{Arc, ThinArc};
|
||||
|
||||
@@ -151,10 +150,10 @@ pub(crate) fn for_fn_ret() -> LifetimeElisionKind {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TyLoweringContext<'a> {
|
||||
pub db: &'a dyn HirDatabase,
|
||||
resolver: &'a Resolver,
|
||||
store: &'a ExpressionStore,
|
||||
pub struct TyLoweringContext<'db> {
|
||||
pub db: &'db dyn HirDatabase,
|
||||
resolver: &'db Resolver<'db>,
|
||||
store: &'db ExpressionStore,
|
||||
def: GenericDefId,
|
||||
generics: OnceCell<Generics>,
|
||||
in_binders: DebruijnIndex,
|
||||
@@ -170,11 +169,11 @@ pub struct TyLoweringContext<'a> {
|
||||
lifetime_elision: LifetimeElisionKind,
|
||||
}
|
||||
|
||||
impl<'a> TyLoweringContext<'a> {
|
||||
impl<'db> TyLoweringContext<'db> {
|
||||
pub fn new(
|
||||
db: &'a dyn HirDatabase,
|
||||
resolver: &'a Resolver,
|
||||
store: &'a ExpressionStore,
|
||||
db: &'db dyn HirDatabase,
|
||||
resolver: &'db Resolver<'db>,
|
||||
store: &'db ExpressionStore,
|
||||
def: GenericDefId,
|
||||
lifetime_elision: LifetimeElisionKind,
|
||||
) -> Self {
|
||||
@@ -1176,13 +1175,13 @@ fn generic_predicates_filtered_by<F>(
|
||||
|
||||
/// Generate implicit `: Sized` predicates for all generics that has no `?Sized` bound.
|
||||
/// Exception is Self of a trait def.
|
||||
fn implicitly_sized_clauses<'a, 'subst: 'a>(
|
||||
db: &dyn HirDatabase,
|
||||
fn implicitly_sized_clauses<'db, 'a, 'subst: 'a>(
|
||||
db: &'db dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
explicitly_unsized_tys: &'a FxHashSet<Ty>,
|
||||
substitution: &'subst Substitution,
|
||||
resolver: &Resolver,
|
||||
) -> Option<impl Iterator<Item = WhereClause> + Captures<'a> + Captures<'subst>> {
|
||||
resolver: &Resolver<'db>,
|
||||
) -> Option<impl Iterator<Item = WhereClause>> {
|
||||
let sized_trait = LangItem::Sized.resolve_trait(db, resolver.krate()).map(to_chalk_trait_id)?;
|
||||
|
||||
let trait_self_idx = trait_self_param_idx(db, def);
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
use hir_def::{
|
||||
AssocItemId, BlockId, ConstId, FunctionId, HasModule, ImplId, ItemContainerId, Lookup,
|
||||
ModuleId, TraitId,
|
||||
nameres::{DefMap, assoc::ImplItems},
|
||||
nameres::{DefMap, assoc::ImplItems, block_def_map, crate_def_map},
|
||||
signatures::{ConstFlags, EnumFlags, FnFlags, StructFlags, TraitFlags, TypeAliasFlags},
|
||||
};
|
||||
use hir_expand::name::Name;
|
||||
@@ -152,7 +152,7 @@ pub(crate) fn trait_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate) ->
|
||||
let _p = tracing::info_span!("trait_impls_in_crate_query", ?krate).entered();
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
Self::collect_def_map(db, &mut impls, &db.crate_def_map(krate));
|
||||
Self::collect_def_map(db, &mut impls, crate_def_map(db, krate));
|
||||
|
||||
Arc::new(Self::finish(impls))
|
||||
}
|
||||
@@ -164,7 +164,7 @@ pub(crate) fn trait_impls_in_block_query(
|
||||
let _p = tracing::info_span!("trait_impls_in_block_query").entered();
|
||||
let mut impls = FxHashMap::default();
|
||||
|
||||
Self::collect_def_map(db, &mut impls, &db.block_def_map(block));
|
||||
Self::collect_def_map(db, &mut impls, block_def_map(db, block));
|
||||
|
||||
if impls.is_empty() { None } else { Some(Arc::new(Self::finish(impls))) }
|
||||
}
|
||||
@@ -214,7 +214,7 @@ fn collect_def_map(db: &dyn HirDatabase, map: &mut TraitFpMapCollector, def_map:
|
||||
for konst in module_data.scope.unnamed_consts() {
|
||||
let body = db.body(konst.into());
|
||||
for (_, block_def_map) in body.blocks(db) {
|
||||
Self::collect_def_map(db, map, &block_def_map);
|
||||
Self::collect_def_map(db, map, block_def_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -280,8 +280,8 @@ pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: Crate)
|
||||
let _p = tracing::info_span!("inherent_impls_in_crate_query", ?krate).entered();
|
||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||
|
||||
let crate_def_map = db.crate_def_map(krate);
|
||||
impls.collect_def_map(db, &crate_def_map);
|
||||
let crate_def_map = crate_def_map(db, krate);
|
||||
impls.collect_def_map(db, crate_def_map);
|
||||
impls.shrink_to_fit();
|
||||
|
||||
Arc::new(impls)
|
||||
@@ -294,8 +294,8 @@ pub(crate) fn inherent_impls_in_block_query(
|
||||
let _p = tracing::info_span!("inherent_impls_in_block_query").entered();
|
||||
let mut impls = Self { map: FxHashMap::default(), invalid_impls: Vec::default() };
|
||||
|
||||
let block_def_map = db.block_def_map(block);
|
||||
impls.collect_def_map(db, &block_def_map);
|
||||
let block_def_map = block_def_map(db, block);
|
||||
impls.collect_def_map(db, block_def_map);
|
||||
impls.shrink_to_fit();
|
||||
|
||||
if impls.map.is_empty() && impls.invalid_impls.is_empty() {
|
||||
@@ -337,7 +337,7 @@ fn collect_def_map(&mut self, db: &dyn HirDatabase, def_map: &DefMap) {
|
||||
for konst in module_data.scope.unnamed_consts() {
|
||||
let body = db.body(konst.into());
|
||||
for (_, block_def_map) in body.blocks(db) {
|
||||
self.collect_def_map(db, &block_def_map);
|
||||
self.collect_def_map(db, block_def_map);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1399,7 +1399,7 @@ fn iterate_inherent_methods(
|
||||
)?;
|
||||
}
|
||||
|
||||
block = db.block_def_map(block_id).parent().and_then(|module| module.containing_block());
|
||||
block = block_def_map(db, block_id).parent().and_then(|module| module.containing_block());
|
||||
}
|
||||
|
||||
for krate in def_crates {
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
use chalk_ir::TyKind;
|
||||
use hir_def::{
|
||||
CrateRootModuleId,
|
||||
builtin_type::{BuiltinInt, BuiltinUint},
|
||||
resolver::HasResolver,
|
||||
};
|
||||
@@ -153,7 +154,7 @@ pub(super) fn detect_and_redirect_special_function(
|
||||
) -> Result<Option<FunctionId>> {
|
||||
// `PanicFmt` is redirected to `ConstPanicFmt`
|
||||
if let Some(LangItem::PanicFmt) = self.db.lang_attr(def.into()) {
|
||||
let resolver = self.db.crate_def_map(self.crate_id).crate_root().resolver(self.db);
|
||||
let resolver = CrateRootModuleId::from(self.crate_id).resolver(self.db);
|
||||
|
||||
let Some(const_panic_fmt) =
|
||||
LangItem::ConstPanicFmt.resolve_function(self.db, resolver.krate())
|
||||
|
||||
@@ -68,16 +68,16 @@ struct DropScope {
|
||||
locals: Vec<LocalId>,
|
||||
}
|
||||
|
||||
struct MirLowerCtx<'a> {
|
||||
struct MirLowerCtx<'db> {
|
||||
result: MirBody,
|
||||
owner: DefWithBodyId,
|
||||
current_loop_blocks: Option<LoopBlocks>,
|
||||
labeled_loop_blocks: FxHashMap<LabelId, LoopBlocks>,
|
||||
discr_temp: Option<Place>,
|
||||
db: &'a dyn HirDatabase,
|
||||
body: &'a Body,
|
||||
infer: &'a InferenceResult,
|
||||
resolver: Resolver,
|
||||
db: &'db dyn HirDatabase,
|
||||
body: &'db Body,
|
||||
infer: &'db InferenceResult,
|
||||
resolver: Resolver<'db>,
|
||||
drop_scopes: Vec<DropScope>,
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
SourceRoot, SourceRootId, SourceRootInput,
|
||||
};
|
||||
|
||||
use hir_def::{ModuleId, db::DefDatabase};
|
||||
use hir_def::{ModuleId, db::DefDatabase, nameres::crate_def_map};
|
||||
use hir_expand::EditionedFileId;
|
||||
use rustc_hash::FxHashMap;
|
||||
use salsa::{AsDynDatabase, Durability};
|
||||
@@ -118,7 +118,7 @@ impl TestDB {
|
||||
pub(crate) fn module_for_file_opt(&self, file_id: impl Into<FileId>) -> Option<ModuleId> {
|
||||
let file_id = file_id.into();
|
||||
for &krate in self.relevant_crates(file_id).iter() {
|
||||
let crate_def_map = self.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(self, krate);
|
||||
for (local_id, data) in crate_def_map.modules() {
|
||||
if data.origin.file_id().map(|file_id| file_id.file_id(self)) == Some(file_id) {
|
||||
return Some(crate_def_map.module_id(local_id));
|
||||
@@ -137,7 +137,7 @@ pub(crate) fn extract_annotations(
|
||||
) -> FxHashMap<EditionedFileId, Vec<(TextRange, String)>> {
|
||||
let mut files = Vec::new();
|
||||
for &krate in self.all_crates().iter() {
|
||||
let crate_def_map = self.crate_def_map(krate);
|
||||
let crate_def_map = crate_def_map(self, krate);
|
||||
for (module_id, _) in crate_def_map.modules() {
|
||||
let file_id = crate_def_map[module_id].origin.file_id();
|
||||
files.extend(file_id)
|
||||
|
||||
@@ -132,7 +132,7 @@ fn check_impl(
|
||||
None => continue,
|
||||
};
|
||||
let def_map = module.def_map(&db);
|
||||
visit_module(&db, &def_map, module.local_id, &mut |it| {
|
||||
visit_module(&db, def_map, module.local_id, &mut |it| {
|
||||
let def = match it {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
@@ -391,7 +391,7 @@ fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
|
||||
let def_map = module.def_map(&db);
|
||||
|
||||
let mut defs: Vec<(DefWithBodyId, Crate)> = Vec::new();
|
||||
visit_module(&db, &def_map, module.local_id, &mut |it| {
|
||||
visit_module(&db, def_map, module.local_id, &mut |it| {
|
||||
let def = match it {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
@@ -504,7 +504,7 @@ fn visit_scope(
|
||||
fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(ModuleDefId)) {
|
||||
for (_, def_map) in body.blocks(db) {
|
||||
for (mod_id, _) in def_map.modules() {
|
||||
visit_module(db, &def_map, mod_id, cb);
|
||||
visit_module(db, def_map, mod_id, cb);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -570,7 +570,7 @@ fn main() {
|
||||
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
db.infer(match def {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
@@ -609,7 +609,7 @@ fn main() {
|
||||
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
db.infer(match def {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::EnumVariantId(it) => it.into(),
|
||||
|
||||
@@ -20,7 +20,7 @@ fn check_closure_captures(#[rust_analyzer::rust_fixture] ra_fixture: &str, expec
|
||||
let def_map = module.def_map(&db);
|
||||
|
||||
let mut defs = Vec::new();
|
||||
visit_module(&db, &def_map, module.local_id, &mut |it| defs.push(it));
|
||||
visit_module(&db, def_map, module.local_id, &mut |it| defs.push(it));
|
||||
|
||||
let mut captures_info = Vec::new();
|
||||
for def in defs {
|
||||
|
||||
@@ -19,7 +19,7 @@ fn foo() -> i32 {
|
||||
let events = db.log_executed(|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
if let ModuleDefId::FunctionId(it) = def {
|
||||
db.infer(it.into());
|
||||
}
|
||||
@@ -41,7 +41,7 @@ fn foo() -> i32 {
|
||||
let events = db.log_executed(|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
if let ModuleDefId::FunctionId(it) = def {
|
||||
db.infer(it.into());
|
||||
}
|
||||
@@ -70,7 +70,7 @@ fn baz() -> i32 {
|
||||
let events = db.log_executed(|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
if let ModuleDefId::FunctionId(it) = def {
|
||||
db.infer(it.into());
|
||||
}
|
||||
@@ -97,7 +97,7 @@ fn baz() -> i32 {
|
||||
let events = db.log_executed(|| {
|
||||
let module = db.module_for_file(pos.file_id.file_id(&db));
|
||||
let crate_def_map = module.def_map(&db);
|
||||
visit_module(&db, &crate_def_map, module.local_id, &mut |def| {
|
||||
visit_module(&db, crate_def_map, module.local_id, &mut |def| {
|
||||
if let ModuleDefId::FunctionId(it) = def {
|
||||
db.infer(it.into());
|
||||
}
|
||||
|
||||
@@ -1505,6 +1505,10 @@ fn main() {
|
||||
!119..120 'o': i32
|
||||
293..294 'o': i32
|
||||
308..317 'thread_id': usize
|
||||
!314..320 'OffPtr': usize
|
||||
!333..338 'OffFn': usize
|
||||
!354..355 '0': i32
|
||||
!371..382 'MEM_RELEASE': usize
|
||||
"#]],
|
||||
)
|
||||
}
|
||||
|
||||
@@ -3902,3 +3902,66 @@ fn main() {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn regression_19734() {
|
||||
check_infer(
|
||||
r#"
|
||||
trait Foo {
|
||||
type Gat<'o>;
|
||||
}
|
||||
|
||||
trait Bar {
|
||||
fn baz() -> <Self::Xyz as Foo::Gat<'_>>;
|
||||
}
|
||||
|
||||
fn foo<T: Bar>() {
|
||||
T::baz();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
110..127 '{ ...z(); }': ()
|
||||
116..122 'T::baz': fn baz<T>() -> <{unknown} as Foo>::Gat<'?>
|
||||
116..124 'T::baz()': Foo::Gat<'?, {unknown}>
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asm_const_label() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: asm
|
||||
const fn bar() -> i32 { 123 }
|
||||
fn baz(s: &str) {}
|
||||
|
||||
fn foo() {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"mov eax, {}",
|
||||
"jmp {}",
|
||||
const bar(),
|
||||
label {
|
||||
baz("hello");
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
22..29 '{ 123 }': i32
|
||||
24..27 '123': i32
|
||||
37..38 's': &'? str
|
||||
46..48 '{}': ()
|
||||
!0..68 'builti...");},)': ()
|
||||
!40..43 'bar': fn bar() -> i32
|
||||
!40..45 'bar()': i32
|
||||
!51..66 '{baz("hello");}': ()
|
||||
!52..55 'baz': fn baz(&'? str)
|
||||
!52..64 'baz("hello")': ()
|
||||
!56..63 '"hello"': &'static str
|
||||
59..257 '{ ... } }': ()
|
||||
65..255 'unsafe... }': ()
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4884,3 +4884,22 @@ async fn baz<T: AsyncFnOnce(u32) -> i32>(c: T) {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn import_trait_items() {
|
||||
check_infer(
|
||||
r#"
|
||||
//- minicore: default
|
||||
use core::default::Default::default;
|
||||
fn main() {
|
||||
let a: i32 = default();
|
||||
}
|
||||
"#,
|
||||
expect![[r#"
|
||||
47..78 '{ ...t(); }': ()
|
||||
57..58 'a': i32
|
||||
66..73 'default': {unknown}
|
||||
66..75 'default()': i32
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
@@ -984,7 +984,7 @@ fn check(#[rust_analyzer::rust_fixture] ra_fixture: &str, expected: Expect) {
|
||||
let mut defs: Vec<GenericDefId> = Vec::new();
|
||||
let module = db.module_for_file_opt(file_id.file_id(&db)).unwrap();
|
||||
let def_map = module.def_map(&db);
|
||||
crate::tests::visit_module(&db, &def_map, module.local_id, &mut |it| {
|
||||
crate::tests::visit_module(&db, def_map, module.local_id, &mut |it| {
|
||||
defs.push(match it {
|
||||
ModuleDefId::FunctionId(it) => it.into(),
|
||||
ModuleDefId::AdtId(it) => it.into(),
|
||||
|
||||
@@ -105,11 +105,12 @@ fn attr_id(self) -> AttrDefId {
|
||||
/// Resolves the item `link` points to in the scope of `def`.
|
||||
pub fn resolve_doc_path_on(
|
||||
db: &dyn HirDatabase,
|
||||
def: impl HasAttrs,
|
||||
def: impl HasAttrs + Copy,
|
||||
link: &str,
|
||||
ns: Option<Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<DocLinkDef> {
|
||||
resolve_doc_path_on_(db, link, def.attr_id(), ns)
|
||||
resolve_doc_path_on_(db, link, def.attr_id(), ns, is_inner_doc)
|
||||
}
|
||||
|
||||
fn resolve_doc_path_on_(
|
||||
@@ -117,9 +118,18 @@ fn resolve_doc_path_on_(
|
||||
link: &str,
|
||||
attr_id: AttrDefId,
|
||||
ns: Option<Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<DocLinkDef> {
|
||||
let resolver = match attr_id {
|
||||
AttrDefId::ModuleId(it) => it.resolver(db),
|
||||
AttrDefId::ModuleId(it) => {
|
||||
if is_inner_doc {
|
||||
it.resolver(db)
|
||||
} else if let Some(parent) = Module::from(it).parent(db) {
|
||||
parent.id.resolver(db)
|
||||
} else {
|
||||
it.resolver(db)
|
||||
}
|
||||
}
|
||||
AttrDefId::FieldId(it) => it.parent.resolver(db),
|
||||
AttrDefId::AdtId(it) => it.resolver(db),
|
||||
AttrDefId::FunctionId(it) => it.resolver(db),
|
||||
@@ -160,7 +170,7 @@ fn resolve_doc_path_on_(
|
||||
|
||||
fn resolve_assoc_or_field(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: Resolver,
|
||||
resolver: Resolver<'_>,
|
||||
path: ModPath,
|
||||
name: Name,
|
||||
ns: Option<Namespace>,
|
||||
@@ -248,7 +258,7 @@ fn resolve_assoc_item(
|
||||
|
||||
fn resolve_impl_trait_item(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: Resolver,
|
||||
resolver: Resolver<'_>,
|
||||
ty: &Type,
|
||||
name: &Name,
|
||||
ns: Option<Namespace>,
|
||||
|
||||
@@ -97,7 +97,8 @@
|
||||
diagnostics::*,
|
||||
has_source::HasSource,
|
||||
semantics::{
|
||||
PathResolution, Semantics, SemanticsImpl, SemanticsScope, TypeInfo, VisibleTraits,
|
||||
PathResolution, PathResolutionPerNs, Semantics, SemanticsImpl, SemanticsScope, TypeInfo,
|
||||
VisibleTraits,
|
||||
},
|
||||
};
|
||||
|
||||
@@ -119,7 +120,7 @@
|
||||
find_path::PrefixKind,
|
||||
import_map,
|
||||
lang_item::LangItem,
|
||||
nameres::{DefMap, ModuleSource},
|
||||
nameres::{DefMap, ModuleSource, crate_def_map},
|
||||
per_ns::Namespace,
|
||||
type_ref::{Mutability, TypeRef},
|
||||
visibility::Visibility,
|
||||
@@ -227,7 +228,7 @@ pub fn root_module(self) -> Module {
|
||||
}
|
||||
|
||||
pub fn modules(self, db: &dyn HirDatabase) -> Vec<Module> {
|
||||
let def_map = db.crate_def_map(self.id);
|
||||
let def_map = crate_def_map(db, self.id);
|
||||
def_map.modules().map(|(id, _)| def_map.module_id(id).into()).collect()
|
||||
}
|
||||
|
||||
@@ -528,7 +529,7 @@ pub fn krate(self) -> Crate {
|
||||
/// might be missing `krate`. This can happen if a module's file is not included
|
||||
/// in the module tree of any target in `Cargo.toml`.
|
||||
pub fn crate_root(self, db: &dyn HirDatabase) -> Module {
|
||||
let def_map = db.crate_def_map(self.id.krate());
|
||||
let def_map = crate_def_map(db, self.id.krate());
|
||||
Module { id: def_map.crate_root().into() }
|
||||
}
|
||||
|
||||
@@ -2468,7 +2469,7 @@ pub fn as_proc_macro(self, db: &dyn HirDatabase) -> Option<Macro> {
|
||||
{
|
||||
return None;
|
||||
}
|
||||
let def_map = db.crate_def_map(HasModule::krate(&self.id, db));
|
||||
let def_map = crate_def_map(db, HasModule::krate(&self.id, db));
|
||||
def_map.fn_as_proc_macro(self.id).map(|id| Macro { id: id.into() })
|
||||
}
|
||||
|
||||
@@ -4015,8 +4016,7 @@ pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<
|
||||
if let builtin @ Some(_) = Self::builtin(name) {
|
||||
return builtin;
|
||||
}
|
||||
let idx = db
|
||||
.crate_def_map(krate.id)
|
||||
let idx = crate_def_map(db, krate.id)
|
||||
.registered_attrs()
|
||||
.iter()
|
||||
.position(|it| it.as_str() == name)? as u32;
|
||||
@@ -4031,7 +4031,7 @@ fn builtin(name: &str) -> Option<Self> {
|
||||
pub fn name(&self, db: &dyn HirDatabase) -> Name {
|
||||
match self.krate {
|
||||
Some(krate) => Name::new_symbol_root(
|
||||
db.crate_def_map(krate).registered_attrs()[self.idx as usize].clone(),
|
||||
crate_def_map(db, krate).registered_attrs()[self.idx as usize].clone(),
|
||||
),
|
||||
None => Name::new_symbol_root(Symbol::intern(
|
||||
hir_expand::inert_attr_macro::INERT_ATTRIBUTES[self.idx as usize].name,
|
||||
@@ -4059,14 +4059,14 @@ impl ToolModule {
|
||||
pub(crate) fn by_name(db: &dyn HirDatabase, krate: Crate, name: &str) -> Option<Self> {
|
||||
let krate = krate.id;
|
||||
let idx =
|
||||
db.crate_def_map(krate).registered_tools().iter().position(|it| it.as_str() == name)?
|
||||
crate_def_map(db, krate).registered_tools().iter().position(|it| it.as_str() == name)?
|
||||
as u32;
|
||||
Some(ToolModule { krate, idx })
|
||||
}
|
||||
|
||||
pub fn name(&self, db: &dyn HirDatabase) -> Name {
|
||||
Name::new_symbol_root(
|
||||
db.crate_def_map(self.krate).registered_tools()[self.idx as usize].clone(),
|
||||
crate_def_map(db, self.krate).registered_tools()[self.idx as usize].clone(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -4488,7 +4488,7 @@ pub fn as_builtin_derive_path(self, db: &dyn HirDatabase) -> Option<InMacroFile<
|
||||
MacroCallKind::Derive { ast_id, derive_attr_index, derive_index, .. } => {
|
||||
let module_id = self.id.lookup(db).container;
|
||||
(
|
||||
db.crate_def_map(module_id.krate())[module_id.local_id]
|
||||
crate_def_map(db, module_id.krate())[module_id.local_id]
|
||||
.scope
|
||||
.derive_macro_invoc(ast_id, derive_attr_index)?,
|
||||
derive_index,
|
||||
@@ -4530,7 +4530,7 @@ pub struct TraitRef {
|
||||
impl TraitRef {
|
||||
pub(crate) fn new_with_resolver(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
trait_ref: hir_ty::TraitRef,
|
||||
) -> TraitRef {
|
||||
let env = resolver
|
||||
@@ -4752,13 +4752,13 @@ pub struct Type {
|
||||
}
|
||||
|
||||
impl Type {
|
||||
pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver, ty: Ty) -> Type {
|
||||
pub(crate) fn new_with_resolver(db: &dyn HirDatabase, resolver: &Resolver<'_>, ty: Ty) -> Type {
|
||||
Type::new_with_resolver_inner(db, resolver, ty)
|
||||
}
|
||||
|
||||
pub(crate) fn new_with_resolver_inner(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
ty: Ty,
|
||||
) -> Type {
|
||||
let environment = resolver
|
||||
@@ -6400,7 +6400,7 @@ pub fn resolve_absolute_path<'a, I: Iterator<Item = Symbol> + Clone + 'a>(
|
||||
})
|
||||
.filter_map(|&krate| {
|
||||
let segments = segments.clone();
|
||||
let mut def_map = db.crate_def_map(krate);
|
||||
let mut def_map = crate_def_map(db, krate);
|
||||
let mut module = &def_map[DefMap::ROOT];
|
||||
let mut segments = segments.with_position().peekable();
|
||||
while let Some((_, segment)) = segments.next_if(|&(position, _)| {
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
DefWithBodyId, FunctionId, MacroId, StructId, TraitId, VariantId,
|
||||
expr_store::{Body, ExprOrPatSource, path::Path},
|
||||
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
|
||||
nameres::ModuleOrigin,
|
||||
nameres::{ModuleOrigin, crate_def_map},
|
||||
resolver::{self, HasResolver, Resolver, TypeNs},
|
||||
type_ref::Mutability,
|
||||
};
|
||||
@@ -103,6 +103,26 @@ pub(crate) fn in_type_ns(&self) -> Option<TypeNs> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
|
||||
pub struct PathResolutionPerNs {
|
||||
pub type_ns: Option<PathResolution>,
|
||||
pub value_ns: Option<PathResolution>,
|
||||
pub macro_ns: Option<PathResolution>,
|
||||
}
|
||||
|
||||
impl PathResolutionPerNs {
|
||||
pub fn new(
|
||||
type_ns: Option<PathResolution>,
|
||||
value_ns: Option<PathResolution>,
|
||||
macro_ns: Option<PathResolution>,
|
||||
) -> Self {
|
||||
PathResolutionPerNs { type_ns, value_ns, macro_ns }
|
||||
}
|
||||
pub fn any(&self) -> Option<PathResolution> {
|
||||
self.type_ns.or(self.value_ns).or(self.macro_ns)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct TypeInfo {
|
||||
/// The original type of the expression or pattern.
|
||||
@@ -341,7 +361,7 @@ pub fn find_parent_file(&self, file_id: HirFileId) -> Option<InFile<SyntaxNode>>
|
||||
match file_id {
|
||||
HirFileId::FileId(file_id) => {
|
||||
let module = self.file_to_module_defs(file_id.file_id(self.db)).next()?;
|
||||
let def_map = self.db.crate_def_map(module.krate().id);
|
||||
let def_map = crate_def_map(self.db, module.krate().id);
|
||||
match def_map[module.id.local_id].origin {
|
||||
ModuleOrigin::CrateRoot { .. } => None,
|
||||
ModuleOrigin::File { declaration, declaration_tree_id, .. } => {
|
||||
@@ -1606,6 +1626,10 @@ pub fn resolve_path(&self, path: &ast::Path) -> Option<PathResolution> {
|
||||
self.resolve_path_with_subst(path).map(|(it, _)| it)
|
||||
}
|
||||
|
||||
pub fn resolve_path_per_ns(&self, path: &ast::Path) -> Option<PathResolutionPerNs> {
|
||||
self.analyze(path.syntax())?.resolve_hir_path_per_ns(self.db, path)
|
||||
}
|
||||
|
||||
pub fn resolve_path_with_subst(
|
||||
&self,
|
||||
path: &ast::Path,
|
||||
@@ -1711,13 +1735,13 @@ pub fn body_for(&self, node: InFile<&SyntaxNode>) -> Option<DefWithBody> {
|
||||
}
|
||||
|
||||
/// Returns none if the file of the node is not part of a crate.
|
||||
fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
|
||||
fn analyze(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
|
||||
let node = self.find_file(node);
|
||||
self.analyze_impl(node, None, true)
|
||||
}
|
||||
|
||||
/// Returns none if the file of the node is not part of a crate.
|
||||
fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer> {
|
||||
fn analyze_no_infer(&self, node: &SyntaxNode) -> Option<SourceAnalyzer<'db>> {
|
||||
let node = self.find_file(node);
|
||||
self.analyze_impl(node, None, false)
|
||||
}
|
||||
@@ -1726,7 +1750,7 @@ fn analyze_with_offset_no_infer(
|
||||
&self,
|
||||
node: &SyntaxNode,
|
||||
offset: TextSize,
|
||||
) -> Option<SourceAnalyzer> {
|
||||
) -> Option<SourceAnalyzer<'db>> {
|
||||
let node = self.find_file(node);
|
||||
self.analyze_impl(node, Some(offset), false)
|
||||
}
|
||||
@@ -1737,7 +1761,7 @@ fn analyze_impl(
|
||||
offset: Option<TextSize>,
|
||||
// replace this, just make the inference result a `LazyCell`
|
||||
infer_body: bool,
|
||||
) -> Option<SourceAnalyzer> {
|
||||
) -> Option<SourceAnalyzer<'db>> {
|
||||
let _p = tracing::info_span!("SemanticsImpl::analyze_impl").entered();
|
||||
|
||||
let container = self.with_ctx(|ctx| ctx.find_container(node))?;
|
||||
@@ -1984,13 +2008,13 @@ fn find_root(node: &SyntaxNode) -> SyntaxNode {
|
||||
/// Note that if you are wondering "what does this specific existing name mean?",
|
||||
/// you'd better use the `resolve_` family of methods.
|
||||
#[derive(Debug)]
|
||||
pub struct SemanticsScope<'a> {
|
||||
pub db: &'a dyn HirDatabase,
|
||||
pub struct SemanticsScope<'db> {
|
||||
pub db: &'db dyn HirDatabase,
|
||||
file_id: HirFileId,
|
||||
resolver: Resolver,
|
||||
resolver: Resolver<'db>,
|
||||
}
|
||||
|
||||
impl SemanticsScope<'_> {
|
||||
impl<'db> SemanticsScope<'db> {
|
||||
pub fn module(&self) -> Module {
|
||||
Module { id: self.resolver.module() }
|
||||
}
|
||||
@@ -2006,7 +2030,7 @@ pub fn containing_function(&self) -> Option<Function> {
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn resolver(&self) -> &Resolver {
|
||||
pub(crate) fn resolver(&self) -> &Resolver<'db> {
|
||||
&self.resolver
|
||||
}
|
||||
|
||||
@@ -2133,7 +2157,7 @@ fn deref(&self) -> &Self::Target {
|
||||
struct RenameConflictsVisitor<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
resolver: Resolver,
|
||||
resolver: Resolver<'a>,
|
||||
body: &'a Body,
|
||||
to_be_renamed: BindingId,
|
||||
new_name: Symbol,
|
||||
|
||||
@@ -96,6 +96,7 @@
|
||||
keys::{self, Key},
|
||||
},
|
||||
hir::{BindingId, Expr, LabelId},
|
||||
nameres::{block_def_map, crate_def_map},
|
||||
};
|
||||
use hir_expand::{
|
||||
EditionedFileId, ExpansionInfo, HirFileId, InMacroFile, MacroCallId, attrs::AttrId,
|
||||
@@ -180,7 +181,7 @@ impl SourceToDefCtx<'_, '_> {
|
||||
|
||||
for &crate_id in self.db.relevant_crates(file).iter() {
|
||||
// Note: `mod` declarations in block modules cannot be supported here
|
||||
let crate_def_map = self.db.crate_def_map(crate_id);
|
||||
let crate_def_map = crate_def_map(self.db, crate_id);
|
||||
let n_mods = mods.len();
|
||||
let modules = |file| {
|
||||
crate_def_map
|
||||
@@ -226,7 +227,7 @@ pub(super) fn module_to_def(&mut self, src: InFile<&ast::Module>) -> Option<Modu
|
||||
let parent_module = match parent_declaration {
|
||||
Some(Either::Right(parent_block)) => self
|
||||
.block_to_def(parent_block.as_ref())
|
||||
.map(|block| self.db.block_def_map(block).root_module_id()),
|
||||
.map(|block| block_def_map(self.db, block).root_module_id()),
|
||||
Some(Either::Left(parent_declaration)) => {
|
||||
self.module_to_def(parent_declaration.as_ref())
|
||||
}
|
||||
|
||||
@@ -10,7 +10,9 @@
|
||||
use crate::{
|
||||
Adt, AssocItem, BindingMode, BuiltinAttr, BuiltinType, Callable, Const, DeriveHelper, Field,
|
||||
Function, GenericSubstitution, Local, Macro, ModuleDef, Static, Struct, ToolModule, Trait,
|
||||
TraitAlias, TupleField, Type, TypeAlias, Variant, db::HirDatabase, semantics::PathResolution,
|
||||
TraitAlias, TupleField, Type, TypeAlias, Variant,
|
||||
db::HirDatabase,
|
||||
semantics::{PathResolution, PathResolutionPerNs},
|
||||
};
|
||||
use either::Either;
|
||||
use hir_def::{
|
||||
@@ -24,7 +26,7 @@
|
||||
},
|
||||
hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
|
||||
lang_item::LangItem,
|
||||
nameres::MacroSubNs,
|
||||
nameres::{MacroSubNs, crate_def_map},
|
||||
resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope},
|
||||
type_ref::{Mutability, TypeRefId},
|
||||
};
|
||||
@@ -57,9 +59,9 @@
|
||||
/// `SourceAnalyzer` is a convenience wrapper which exposes HIR API in terms of
|
||||
/// original source files. It should not be used inside the HIR itself.
|
||||
#[derive(Debug)]
|
||||
pub(crate) struct SourceAnalyzer {
|
||||
pub(crate) struct SourceAnalyzer<'db> {
|
||||
pub(crate) file_id: HirFileId,
|
||||
pub(crate) resolver: Resolver,
|
||||
pub(crate) resolver: Resolver<'db>,
|
||||
pub(crate) body_or_sig: Option<BodyOrSig>,
|
||||
}
|
||||
|
||||
@@ -85,32 +87,32 @@ pub(crate) enum BodyOrSig {
|
||||
},
|
||||
}
|
||||
|
||||
impl SourceAnalyzer {
|
||||
impl<'db> SourceAnalyzer<'db> {
|
||||
pub(crate) fn new_for_body(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
node: InFile<&SyntaxNode>,
|
||||
offset: Option<TextSize>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
Self::new_for_body_(db, def, node, offset, Some(db.infer(def)))
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_body_no_infer(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
node: InFile<&SyntaxNode>,
|
||||
offset: Option<TextSize>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
Self::new_for_body_(db, def, node, offset, None)
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_body_(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
def: DefWithBodyId,
|
||||
node @ InFile { file_id, .. }: InFile<&SyntaxNode>,
|
||||
offset: Option<TextSize>,
|
||||
infer: Option<Arc<InferenceResult>>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
let (body, source_map) = db.body_with_source_map(def);
|
||||
let scopes = db.expr_scopes(def);
|
||||
let scope = match offset {
|
||||
@@ -134,11 +136,11 @@ pub(crate) fn new_for_body_(
|
||||
}
|
||||
|
||||
pub(crate) fn new_generic_def(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
def: GenericDefId,
|
||||
InFile { file_id, .. }: InFile<&SyntaxNode>,
|
||||
_offset: Option<TextSize>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
let (_params, store, source_map) = db.generic_params_and_store_and_source_map(def);
|
||||
let resolver = def.resolver(db);
|
||||
SourceAnalyzer {
|
||||
@@ -149,11 +151,11 @@ pub(crate) fn new_generic_def(
|
||||
}
|
||||
|
||||
pub(crate) fn new_variant_body(
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
def: VariantId,
|
||||
InFile { file_id, .. }: InFile<&SyntaxNode>,
|
||||
_offset: Option<TextSize>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
let (fields, source_map) = db.variant_fields_with_source_map(def);
|
||||
let resolver = def.resolver(db);
|
||||
SourceAnalyzer {
|
||||
@@ -168,9 +170,9 @@ pub(crate) fn new_variant_body(
|
||||
}
|
||||
|
||||
pub(crate) fn new_for_resolver(
|
||||
resolver: Resolver,
|
||||
resolver: Resolver<'db>,
|
||||
node: InFile<&SyntaxNode>,
|
||||
) -> SourceAnalyzer {
|
||||
) -> SourceAnalyzer<'db> {
|
||||
SourceAnalyzer { resolver, body_or_sig: None, file_id: node.file_id }
|
||||
}
|
||||
|
||||
@@ -220,7 +222,7 @@ pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCal
|
||||
self.store_sm()?.expansion(node)
|
||||
}
|
||||
|
||||
fn trait_environment(&self, db: &dyn HirDatabase) -> Arc<TraitEnvironment> {
|
||||
fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
|
||||
self.body_().map(|(def, ..)| def).map_or_else(
|
||||
|| TraitEnvironment::empty(self.resolver.krate()),
|
||||
|def| db.trait_environment_for_body(def),
|
||||
@@ -259,7 +261,7 @@ pub(crate) fn expr_adjustments(&self, expr: &ast::Expr) -> Option<&[Adjustment]>
|
||||
infer.expr_adjustments.get(&expr_id).map(|v| &**v)
|
||||
}
|
||||
|
||||
pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
|
||||
pub(crate) fn type_of_type(&self, db: &'db dyn HirDatabase, ty: &ast::Type) -> Option<Type> {
|
||||
let type_ref = self.type_id(ty)?;
|
||||
let ty = TyLoweringContext::new(
|
||||
db,
|
||||
@@ -277,7 +279,7 @@ pub(crate) fn type_of_type(&self, db: &dyn HirDatabase, ty: &ast::Type) -> Optio
|
||||
|
||||
pub(crate) fn type_of_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
expr: &ast::Expr,
|
||||
) -> Option<(Type, Option<Type>)> {
|
||||
let expr_id = self.expr_id(expr.clone())?;
|
||||
@@ -293,7 +295,7 @@ pub(crate) fn type_of_expr(
|
||||
|
||||
pub(crate) fn type_of_pat(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
pat: &ast::Pat,
|
||||
) -> Option<(Type, Option<Type>)> {
|
||||
let expr_or_pat_id = self.pat_id(pat)?;
|
||||
@@ -316,7 +318,7 @@ pub(crate) fn type_of_pat(
|
||||
|
||||
pub(crate) fn type_of_binding_in_pat(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
pat: &ast::IdentPat,
|
||||
) -> Option<Type> {
|
||||
let binding_id = self.binding_id_of_pat(pat)?;
|
||||
@@ -328,7 +330,7 @@ pub(crate) fn type_of_binding_in_pat(
|
||||
|
||||
pub(crate) fn type_of_self(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
_param: &ast::SelfParam,
|
||||
) -> Option<Type> {
|
||||
let binding = self.body()?.self_param?;
|
||||
@@ -338,7 +340,7 @@ pub(crate) fn type_of_self(
|
||||
|
||||
pub(crate) fn binding_mode_of_pat(
|
||||
&self,
|
||||
_db: &dyn HirDatabase,
|
||||
_db: &'db dyn HirDatabase,
|
||||
pat: &ast::IdentPat,
|
||||
) -> Option<BindingMode> {
|
||||
let id = self.pat_id(&pat.clone().into())?;
|
||||
@@ -353,7 +355,7 @@ pub(crate) fn binding_mode_of_pat(
|
||||
}
|
||||
pub(crate) fn pattern_adjustments(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
pat: &ast::Pat,
|
||||
) -> Option<SmallVec<[Type; 1]>> {
|
||||
let pat_id = self.pat_id(pat)?;
|
||||
@@ -370,7 +372,7 @@ pub(crate) fn pattern_adjustments(
|
||||
|
||||
pub(crate) fn resolve_method_call_as_callable(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Callable> {
|
||||
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
|
||||
@@ -384,7 +386,7 @@ pub(crate) fn resolve_method_call_as_callable(
|
||||
|
||||
pub(crate) fn resolve_method_call(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<Function> {
|
||||
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
|
||||
@@ -395,7 +397,7 @@ pub(crate) fn resolve_method_call(
|
||||
|
||||
pub(crate) fn resolve_method_call_fallback(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
call: &ast::MethodCallExpr,
|
||||
) -> Option<(Either<Function, Field>, Option<GenericSubstitution>)> {
|
||||
let expr_id = self.expr_id(call.clone().into())?.as_expr()?;
|
||||
@@ -419,7 +421,7 @@ pub(crate) fn resolve_method_call_fallback(
|
||||
|
||||
pub(crate) fn resolve_expr_as_callable(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
call: &ast::Expr,
|
||||
) -> Option<Callable> {
|
||||
let (orig, adjusted) = self.type_of_expr(db, &call.clone())?;
|
||||
@@ -441,7 +443,7 @@ fn field_subst(
|
||||
&self,
|
||||
field_expr: ExprId,
|
||||
infer: &InferenceResult,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
) -> Option<GenericSubstitution> {
|
||||
let body = self.store()?;
|
||||
if let Expr::Field { expr: object_expr, name: _ } = body[field_expr] {
|
||||
@@ -457,7 +459,7 @@ fn field_subst(
|
||||
|
||||
pub(crate) fn resolve_field_fallback(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
field: &ast::FieldExpr,
|
||||
) -> Option<(Either<Either<Field, TupleField>, Function>, Option<GenericSubstitution>)> {
|
||||
let (def, ..) = self.body_()?;
|
||||
@@ -490,7 +492,7 @@ pub(crate) fn resolve_field_fallback(
|
||||
|
||||
pub(crate) fn resolve_range_pat(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
range_pat: &ast::RangePat,
|
||||
) -> Option<StructId> {
|
||||
let path: ModPath = match (range_pat.op_kind()?, range_pat.start(), range_pat.end()) {
|
||||
@@ -509,7 +511,7 @@ pub(crate) fn resolve_range_pat(
|
||||
|
||||
pub(crate) fn resolve_range_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
range_expr: &ast::RangeExpr,
|
||||
) -> Option<StructId> {
|
||||
let path: ModPath = match (range_expr.op_kind()?, range_expr.start(), range_expr.end()) {
|
||||
@@ -529,7 +531,7 @@ pub(crate) fn resolve_range_expr(
|
||||
|
||||
pub(crate) fn resolve_await_to_poll(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
await_expr: &ast::AwaitExpr,
|
||||
) -> Option<FunctionId> {
|
||||
let mut ty = self.ty_of_expr(await_expr.expr()?)?.clone();
|
||||
@@ -566,7 +568,7 @@ pub(crate) fn resolve_await_to_poll(
|
||||
|
||||
pub(crate) fn resolve_prefix_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
prefix_expr: &ast::PrefixExpr,
|
||||
) -> Option<FunctionId> {
|
||||
let (op_trait, op_fn) = match prefix_expr.op_kind()? {
|
||||
@@ -608,7 +610,7 @@ pub(crate) fn resolve_prefix_expr(
|
||||
|
||||
pub(crate) fn resolve_index_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
index_expr: &ast::IndexExpr,
|
||||
) -> Option<FunctionId> {
|
||||
let base_ty = self.ty_of_expr(index_expr.base()?)?;
|
||||
@@ -640,7 +642,7 @@ pub(crate) fn resolve_index_expr(
|
||||
|
||||
pub(crate) fn resolve_bin_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
binop_expr: &ast::BinExpr,
|
||||
) -> Option<FunctionId> {
|
||||
let op = binop_expr.op_kind()?;
|
||||
@@ -661,7 +663,7 @@ pub(crate) fn resolve_bin_expr(
|
||||
|
||||
pub(crate) fn resolve_try_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
try_expr: &ast::TryExpr,
|
||||
) -> Option<FunctionId> {
|
||||
let ty = self.ty_of_expr(try_expr.expr()?)?;
|
||||
@@ -680,7 +682,7 @@ pub(crate) fn resolve_try_expr(
|
||||
|
||||
pub(crate) fn resolve_record_field(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
field: &ast::RecordExprField,
|
||||
) -> Option<(Field, Option<Local>, Type, GenericSubstitution)> {
|
||||
let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
|
||||
@@ -724,7 +726,7 @@ pub(crate) fn resolve_record_field(
|
||||
|
||||
pub(crate) fn resolve_record_pat_field(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
field: &ast::RecordPatField,
|
||||
) -> Option<(Field, Type, GenericSubstitution)> {
|
||||
let field_name = field.field_name()?.as_name();
|
||||
@@ -745,14 +747,14 @@ pub(crate) fn resolve_record_pat_field(
|
||||
|
||||
pub(crate) fn resolve_macro_call(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
macro_call: InFile<&ast::MacroCall>,
|
||||
) -> Option<Macro> {
|
||||
let bs = self.store_sm()?;
|
||||
bs.expansion(macro_call).and_then(|it| {
|
||||
// FIXME: Block def maps
|
||||
let def = it.lookup(db).def;
|
||||
db.crate_def_map(def.krate)
|
||||
crate_def_map(db, def.krate)
|
||||
.macro_def_to_macro_id
|
||||
.get(&def.kind.erased_ast_id())
|
||||
.map(|it| (*it).into())
|
||||
@@ -761,7 +763,7 @@ pub(crate) fn resolve_macro_call(
|
||||
|
||||
pub(crate) fn resolve_bind_pat_to_const(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
pat: &ast::IdentPat,
|
||||
) -> Option<ModuleDef> {
|
||||
let expr_or_pat_id = self.pat_id(&pat.clone().into())?;
|
||||
@@ -795,7 +797,7 @@ pub(crate) fn resolve_use_type_arg(&self, name: &ast::NameRef) -> Option<crate::
|
||||
|
||||
pub(crate) fn resolve_offset_of_field(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
name_ref: &ast::NameRef,
|
||||
) -> Option<(Either<crate::Variant, crate::Field>, GenericSubstitution)> {
|
||||
let offset_of_expr = ast::OffsetOfExpr::cast(name_ref.syntax().parent()?)?;
|
||||
@@ -867,7 +869,7 @@ pub(crate) fn resolve_offset_of_field(
|
||||
|
||||
pub(crate) fn resolve_path(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
path: &ast::Path,
|
||||
) -> Option<(PathResolution, Option<GenericSubstitution>)> {
|
||||
let parent = path.syntax().parent();
|
||||
@@ -1159,7 +1161,9 @@ pub(crate) fn resolve_path(
|
||||
prefer_value_ns,
|
||||
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
|
||||
Some(&store),
|
||||
)?;
|
||||
false,
|
||||
)
|
||||
.any()?;
|
||||
let subst = (|| {
|
||||
let parent = parent()?;
|
||||
let ty = if let Some(expr) = ast::Expr::cast(parent.clone()) {
|
||||
@@ -1209,9 +1213,29 @@ pub(crate) fn resolve_path(
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn record_literal_missing_fields(
|
||||
pub(crate) fn resolve_hir_path_per_ns(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
path: &ast::Path,
|
||||
) -> Option<PathResolutionPerNs> {
|
||||
let mut collector = ExprCollector::new(db, self.resolver.module(), self.file_id);
|
||||
let hir_path =
|
||||
collector.lower_path(path.clone(), &mut ExprCollector::impl_trait_error_allocator)?;
|
||||
let store = collector.store.finish();
|
||||
Some(resolve_hir_path_(
|
||||
db,
|
||||
&self.resolver,
|
||||
&hir_path,
|
||||
false,
|
||||
name_hygiene(db, InFile::new(self.file_id, path.syntax())),
|
||||
Some(&store),
|
||||
true,
|
||||
))
|
||||
}
|
||||
|
||||
pub(crate) fn record_literal_missing_fields(
|
||||
&self,
|
||||
db: &'db dyn HirDatabase,
|
||||
literal: &ast::RecordExpr,
|
||||
) -> Option<Vec<(Field, Type)>> {
|
||||
let body = self.store()?;
|
||||
@@ -1234,7 +1258,7 @@ pub(crate) fn record_literal_missing_fields(
|
||||
|
||||
pub(crate) fn record_pattern_missing_fields(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
pattern: &ast::RecordPat,
|
||||
) -> Option<Vec<(Field, Type)>> {
|
||||
let body = self.store()?;
|
||||
@@ -1251,7 +1275,7 @@ pub(crate) fn record_pattern_missing_fields(
|
||||
|
||||
fn missing_fields(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
substs: &Substitution,
|
||||
variant: VariantId,
|
||||
missing_fields: Vec<LocalFieldId>,
|
||||
@@ -1270,7 +1294,7 @@ fn missing_fields(
|
||||
|
||||
pub(crate) fn expand(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
macro_call: InFile<&ast::MacroCall>,
|
||||
) -> Option<MacroCallId> {
|
||||
self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| {
|
||||
@@ -1288,7 +1312,7 @@ pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<Vari
|
||||
|
||||
pub(crate) fn is_unsafe_macro_call_expr(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
macro_expr: InFile<&ast::MacroExpr>,
|
||||
) -> bool {
|
||||
if let Some((def, body, sm, Some(infer))) = self.body_() {
|
||||
@@ -1313,7 +1337,7 @@ pub(crate) fn is_unsafe_macro_call_expr(
|
||||
|
||||
pub(crate) fn resolve_offset_in_format_args(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
format_args: InFile<&ast::FormatArgsExpr>,
|
||||
offset: TextSize,
|
||||
) -> Option<(TextRange, Option<PathResolution>)> {
|
||||
@@ -1384,7 +1408,7 @@ pub(crate) fn as_asm_parts(
|
||||
|
||||
fn resolve_impl_method_or_trait_def(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
func: FunctionId,
|
||||
substs: Substitution,
|
||||
) -> FunctionId {
|
||||
@@ -1393,7 +1417,7 @@ fn resolve_impl_method_or_trait_def(
|
||||
|
||||
fn resolve_impl_method_or_trait_def_with_subst(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
func: FunctionId,
|
||||
substs: Substitution,
|
||||
) -> (FunctionId, Substitution) {
|
||||
@@ -1407,7 +1431,7 @@ fn resolve_impl_method_or_trait_def_with_subst(
|
||||
|
||||
fn resolve_impl_const_or_trait_def_with_subst(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
const_id: ConstId,
|
||||
subs: Substitution,
|
||||
) -> (ConstId, Substitution) {
|
||||
@@ -1421,7 +1445,7 @@ fn resolve_impl_const_or_trait_def_with_subst(
|
||||
|
||||
fn lang_trait_fn(
|
||||
&self,
|
||||
db: &dyn HirDatabase,
|
||||
db: &'db dyn HirDatabase,
|
||||
lang_trait: LangItem,
|
||||
method_name: &Name,
|
||||
) -> Option<(TraitId, FunctionId)> {
|
||||
@@ -1527,18 +1551,18 @@ fn adjust(
|
||||
#[inline]
|
||||
pub(crate) fn resolve_hir_path(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
path: &Path,
|
||||
hygiene: HygieneId,
|
||||
store: Option<&ExpressionStore>,
|
||||
) -> Option<PathResolution> {
|
||||
resolve_hir_path_(db, resolver, path, false, hygiene, store)
|
||||
resolve_hir_path_(db, resolver, path, false, hygiene, store, false).any()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub(crate) fn resolve_hir_path_as_attr_macro(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
path: &Path,
|
||||
) -> Option<Macro> {
|
||||
resolver
|
||||
@@ -1549,12 +1573,13 @@ pub(crate) fn resolve_hir_path_as_attr_macro(
|
||||
|
||||
fn resolve_hir_path_(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
path: &Path,
|
||||
prefer_value_ns: bool,
|
||||
hygiene: HygieneId,
|
||||
store: Option<&ExpressionStore>,
|
||||
) -> Option<PathResolution> {
|
||||
resolve_per_ns: bool,
|
||||
) -> PathResolutionPerNs {
|
||||
let types = || {
|
||||
let (ty, unresolved) = match path.type_anchor() {
|
||||
Some(type_ref) => resolver.generic_def().and_then(|def| {
|
||||
@@ -1635,14 +1660,36 @@ fn resolve_hir_path_(
|
||||
.map(|(def, _)| PathResolution::Def(ModuleDef::Macro(def.into())))
|
||||
};
|
||||
|
||||
if prefer_value_ns { values().or_else(types) } else { types().or_else(values) }
|
||||
.or_else(items)
|
||||
.or_else(macros)
|
||||
if resolve_per_ns {
|
||||
PathResolutionPerNs {
|
||||
type_ns: types().or_else(items),
|
||||
value_ns: values(),
|
||||
macro_ns: macros(),
|
||||
}
|
||||
} else {
|
||||
let res = if prefer_value_ns {
|
||||
values()
|
||||
.map(|value_ns| PathResolutionPerNs::new(None, Some(value_ns), None))
|
||||
.unwrap_or_else(|| PathResolutionPerNs::new(types(), None, None))
|
||||
} else {
|
||||
types()
|
||||
.map(|type_ns| PathResolutionPerNs::new(Some(type_ns), None, None))
|
||||
.unwrap_or_else(|| PathResolutionPerNs::new(None, values(), None))
|
||||
};
|
||||
|
||||
if res.any().is_some() {
|
||||
res
|
||||
} else if let Some(type_ns) = items() {
|
||||
PathResolutionPerNs::new(Some(type_ns), None, None)
|
||||
} else {
|
||||
PathResolutionPerNs::new(None, None, macros())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_hir_value_path(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
body_owner: Option<DefWithBodyId>,
|
||||
path: &Path,
|
||||
hygiene: HygieneId,
|
||||
@@ -1680,7 +1727,7 @@ fn resolve_hir_value_path(
|
||||
/// then we know that `foo` in `my::foo::Bar` refers to the module, not the function.
|
||||
fn resolve_hir_path_qualifier(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
resolver: &Resolver<'_>,
|
||||
path: &Path,
|
||||
store: &ExpressionStore,
|
||||
) -> Option<PathResolution> {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
use either::Either;
|
||||
use syntax::{
|
||||
ast::{
|
||||
self, AstNode, HasName, HasTypeBounds,
|
||||
@@ -30,10 +31,11 @@ pub(crate) fn move_bounds_to_where_clause(
|
||||
) -> Option<()> {
|
||||
let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
|
||||
|
||||
let mut type_params = type_param_list.type_or_const_params();
|
||||
let mut type_params = type_param_list.generic_params();
|
||||
if type_params.all(|p| match p {
|
||||
ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(),
|
||||
ast::TypeOrConstParam::Const(_) => true,
|
||||
ast::GenericParam::TypeParam(t) => t.type_bound_list().is_none(),
|
||||
ast::GenericParam::LifetimeParam(l) => l.type_bound_list().is_none(),
|
||||
ast::GenericParam::ConstParam(_) => true,
|
||||
}) {
|
||||
return None;
|
||||
}
|
||||
@@ -53,20 +55,23 @@ pub(crate) fn move_bounds_to_where_clause(
|
||||
match parent {
|
||||
ast::Fn(it) => it.get_or_create_where_clause(),
|
||||
ast::Trait(it) => it.get_or_create_where_clause(),
|
||||
ast::TraitAlias(it) => it.get_or_create_where_clause(),
|
||||
ast::Impl(it) => it.get_or_create_where_clause(),
|
||||
ast::Enum(it) => it.get_or_create_where_clause(),
|
||||
ast::Struct(it) => it.get_or_create_where_clause(),
|
||||
ast::TypeAlias(it) => it.get_or_create_where_clause(),
|
||||
_ => return,
|
||||
}
|
||||
};
|
||||
|
||||
for toc_param in type_param_list.type_or_const_params() {
|
||||
let type_param = match toc_param {
|
||||
ast::TypeOrConstParam::Type(x) => x,
|
||||
ast::TypeOrConstParam::Const(_) => continue,
|
||||
for generic_param in type_param_list.generic_params() {
|
||||
let param: &dyn HasTypeBounds = match &generic_param {
|
||||
ast::GenericParam::TypeParam(t) => t,
|
||||
ast::GenericParam::LifetimeParam(l) => l,
|
||||
ast::GenericParam::ConstParam(_) => continue,
|
||||
};
|
||||
if let Some(tbl) = type_param.type_bound_list() {
|
||||
if let Some(predicate) = build_predicate(type_param) {
|
||||
if let Some(tbl) = param.type_bound_list() {
|
||||
if let Some(predicate) = build_predicate(generic_param) {
|
||||
where_clause.add_predicate(predicate)
|
||||
}
|
||||
tbl.remove()
|
||||
@@ -76,9 +81,23 @@ pub(crate) fn move_bounds_to_where_clause(
|
||||
)
|
||||
}
|
||||
|
||||
fn build_predicate(param: ast::TypeParam) -> Option<ast::WherePred> {
|
||||
let path = make::ext::ident_path(¶m.name()?.syntax().to_string());
|
||||
let predicate = make::where_pred(make::ty_path(path), param.type_bound_list()?.bounds());
|
||||
fn build_predicate(param: ast::GenericParam) -> Option<ast::WherePred> {
|
||||
let target = match ¶m {
|
||||
ast::GenericParam::TypeParam(t) => {
|
||||
Either::Right(make::ty_path(make::ext::ident_path(&t.name()?.to_string())))
|
||||
}
|
||||
ast::GenericParam::LifetimeParam(l) => Either::Left(l.lifetime()?),
|
||||
ast::GenericParam::ConstParam(_) => return None,
|
||||
};
|
||||
let predicate = make::where_pred(
|
||||
target,
|
||||
match param {
|
||||
ast::GenericParam::TypeParam(t) => t.type_bound_list()?,
|
||||
ast::GenericParam::LifetimeParam(l) => l.type_bound_list()?,
|
||||
ast::GenericParam::ConstParam(_) => return None,
|
||||
}
|
||||
.bounds(),
|
||||
);
|
||||
Some(predicate.clone_for_update())
|
||||
}
|
||||
|
||||
@@ -123,4 +142,13 @@ fn move_bounds_to_where_clause_tuple_struct() {
|
||||
r#"struct Pair<T>(T, T) where T: u32;"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn move_bounds_to_where_clause_trait() {
|
||||
check_assist(
|
||||
move_bounds_to_where_clause,
|
||||
r#"trait T<'a: 'static, $0T: u32> {}"#,
|
||||
r#"trait T<'a, T> where 'a: 'static, T: u32 {}"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
use std::collections::hash_map::Entry;
|
||||
|
||||
use hir::{FileRange, InFile, InRealFile, Module, ModuleSource};
|
||||
use hir::{
|
||||
FileRange, InFile, InRealFile, Module, ModuleDef, ModuleSource, PathResolution,
|
||||
PathResolutionPerNs,
|
||||
};
|
||||
use ide_db::text_edit::TextRange;
|
||||
use ide_db::{
|
||||
FxHashMap, RootDatabase,
|
||||
@@ -77,22 +80,17 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
};
|
||||
|
||||
// Get the actual definition associated with this use item.
|
||||
let res = match ctx.sema.resolve_path(&path) {
|
||||
Some(x) => x,
|
||||
None => {
|
||||
let res = match ctx.sema.resolve_path_per_ns(&path) {
|
||||
Some(x) if x.any().is_some() => x,
|
||||
Some(_) | None => {
|
||||
return None;
|
||||
}
|
||||
};
|
||||
|
||||
let def = match res {
|
||||
hir::PathResolution::Def(d) => Definition::from(d),
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
if u.star_token().is_some() {
|
||||
// Check if any of the children of this module are used
|
||||
let def_mod = match def {
|
||||
Definition::Module(module) => module,
|
||||
let def_mod = match res.type_ns {
|
||||
Some(PathResolution::Def(ModuleDef::Module(module))) => module,
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
@@ -105,21 +103,13 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
})
|
||||
.any(|d| used_once_in_scope(ctx, d, u.rename(), scope))
|
||||
{
|
||||
return Some(u);
|
||||
Some(u)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
} else if let Definition::Trait(ref t) = def {
|
||||
// If the trait or any item is used.
|
||||
if !std::iter::once((def, u.rename()))
|
||||
.chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
|
||||
.any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
|
||||
{
|
||||
return Some(u);
|
||||
}
|
||||
} else if !used_once_in_scope(ctx, def, u.rename(), scope) {
|
||||
return Some(u);
|
||||
} else {
|
||||
is_path_per_ns_unused_in_scope(ctx, &u, scope, &res).then_some(u)
|
||||
}
|
||||
|
||||
None
|
||||
})
|
||||
.peekable();
|
||||
|
||||
@@ -141,6 +131,52 @@ pub(crate) fn remove_unused_imports(acc: &mut Assists, ctx: &AssistContext<'_>)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_path_per_ns_unused_in_scope(
|
||||
ctx: &AssistContext<'_>,
|
||||
u: &ast::UseTree,
|
||||
scope: &mut Vec<SearchScope>,
|
||||
path: &PathResolutionPerNs,
|
||||
) -> bool {
|
||||
if let Some(PathResolution::Def(ModuleDef::Trait(ref t))) = path.type_ns {
|
||||
if is_trait_unused_in_scope(ctx, u, scope, t) {
|
||||
let path = [path.value_ns, path.macro_ns];
|
||||
is_path_unused_in_scope(ctx, u, scope, &path)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
} else {
|
||||
let path = [path.type_ns, path.value_ns, path.macro_ns];
|
||||
is_path_unused_in_scope(ctx, u, scope, &path)
|
||||
}
|
||||
}
|
||||
|
||||
fn is_path_unused_in_scope(
|
||||
ctx: &AssistContext<'_>,
|
||||
u: &ast::UseTree,
|
||||
scope: &mut Vec<SearchScope>,
|
||||
path: &[Option<PathResolution>],
|
||||
) -> bool {
|
||||
!path
|
||||
.iter()
|
||||
.filter_map(|path| *path)
|
||||
.filter_map(|res| match res {
|
||||
PathResolution::Def(d) => Some(Definition::from(d)),
|
||||
_ => None,
|
||||
})
|
||||
.any(|def| used_once_in_scope(ctx, def, u.rename(), scope))
|
||||
}
|
||||
|
||||
fn is_trait_unused_in_scope(
|
||||
ctx: &AssistContext<'_>,
|
||||
u: &ast::UseTree,
|
||||
scope: &mut Vec<SearchScope>,
|
||||
t: &hir::Trait,
|
||||
) -> bool {
|
||||
!std::iter::once((Definition::Trait(*t), u.rename()))
|
||||
.chain(t.items(ctx.db()).into_iter().map(|item| (item.into(), None)))
|
||||
.any(|(d, rename)| used_once_in_scope(ctx, d, rename, scope))
|
||||
}
|
||||
|
||||
fn used_once_in_scope(
|
||||
ctx: &AssistContext<'_>,
|
||||
def: Definition,
|
||||
@@ -1009,6 +1045,112 @@ fn test(_: Bar) {
|
||||
let a = ();
|
||||
a.quxx();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_unused_macro() {
|
||||
check_assist(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- /foo.rs crate:foo
|
||||
#[macro_export]
|
||||
macro_rules! m { () => {} }
|
||||
|
||||
//- /main.rs crate:main deps:foo
|
||||
use foo::m;$0
|
||||
fn main() {}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {}
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist_not_applicable(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- /foo.rs crate:foo
|
||||
#[macro_export]
|
||||
macro_rules! m { () => {} }
|
||||
|
||||
//- /main.rs crate:main deps:foo
|
||||
use foo::m;$0
|
||||
fn main() {
|
||||
m!();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist_not_applicable(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- /foo.rs crate:foo
|
||||
#[macro_export]
|
||||
macro_rules! m { () => {} }
|
||||
|
||||
//- /bar.rs crate:bar deps:foo
|
||||
pub use foo::m;
|
||||
fn m() {}
|
||||
|
||||
|
||||
//- /main.rs crate:main deps:bar
|
||||
use bar::m;$0
|
||||
fn main() {
|
||||
m!();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_conflict_derive_macro() {
|
||||
check_assist_not_applicable(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
//- /bar.rs crate:bar
|
||||
pub use proc_macros::DeriveIdentity;
|
||||
pub trait DeriveIdentity {}
|
||||
|
||||
//- /main.rs crate:main deps:bar
|
||||
$0use bar::DeriveIdentity;$0
|
||||
#[derive(DeriveIdentity)]
|
||||
struct S;
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist_not_applicable(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
//- /bar.rs crate:bar
|
||||
pub use proc_macros::DeriveIdentity;
|
||||
pub fn DeriveIdentity() {}
|
||||
|
||||
//- /main.rs crate:main deps:bar
|
||||
$0use bar::DeriveIdentity;$0
|
||||
#[derive(DeriveIdentity)]
|
||||
struct S;
|
||||
"#,
|
||||
);
|
||||
|
||||
check_assist_not_applicable(
|
||||
remove_unused_imports,
|
||||
r#"
|
||||
//- proc_macros: derive_identity
|
||||
//- minicore: derive
|
||||
//- /bar.rs crate:bar
|
||||
pub use proc_macros::DeriveIdentity;
|
||||
pub fn DeriveIdentity() {}
|
||||
|
||||
//- /main.rs crate:main deps:bar
|
||||
$0use bar::DeriveIdentity;$0
|
||||
fn main() {
|
||||
DeriveIdentity();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
+156
@@ -0,0 +1,156 @@
|
||||
use ide_db::assists::AssistId;
|
||||
use syntax::{
|
||||
AstNode,
|
||||
ast::{self, GenericArg, HasGenericArgs},
|
||||
};
|
||||
|
||||
use crate::{AssistContext, Assists};
|
||||
|
||||
// Assist: unwrap_type_to_generic_arg
|
||||
//
|
||||
// This assist unwraps a type into its generic type argument.
|
||||
//
|
||||
// ```
|
||||
// fn foo() -> $0Option<i32> {
|
||||
// todo!()
|
||||
// }
|
||||
// ```
|
||||
// ->
|
||||
// ```
|
||||
// fn foo() -> i32 {
|
||||
// todo!()
|
||||
// }
|
||||
// ```
|
||||
pub(crate) fn unwrap_type_to_generic_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
||||
let path_type = ctx.find_node_at_offset::<ast::PathType>()?;
|
||||
let path = path_type.path()?;
|
||||
let segment = path.segment()?;
|
||||
let args_list = segment.generic_arg_list()?;
|
||||
|
||||
let mut generic_arg = None;
|
||||
|
||||
for arg in args_list.generic_args() {
|
||||
match arg {
|
||||
GenericArg::ConstArg(_) | GenericArg::LifetimeArg(_) => (),
|
||||
GenericArg::TypeArg(arg) if generic_arg.is_none() => {
|
||||
generic_arg = Some(arg);
|
||||
}
|
||||
_ => return None,
|
||||
}
|
||||
}
|
||||
|
||||
let generic_arg = generic_arg?;
|
||||
|
||||
acc.add(
|
||||
AssistId::refactor_extract("unwrap_type_to_generic_arg"),
|
||||
format!("Unwrap type to type argument {generic_arg}"),
|
||||
path_type.syntax().text_range(),
|
||||
|builder| {
|
||||
let mut editor = builder.make_editor(path_type.syntax());
|
||||
editor.replace(path_type.syntax(), generic_arg.syntax());
|
||||
|
||||
builder.add_file_edits(ctx.vfs_file_id(), editor);
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::tests::{check_assist, check_assist_not_applicable};
|
||||
|
||||
#[test]
|
||||
fn test_unwrap_type_to_generic_arg() {
|
||||
check_assist(
|
||||
unwrap_type_to_generic_arg,
|
||||
r#"
|
||||
//- minicore: option
|
||||
fn foo() -> $0Option<i32> {
|
||||
todo!()
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn foo() -> i32 {
|
||||
todo!()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_type_to_generic_arg_not_applicable_for_non_generic_arg_list() {
|
||||
check_assist_not_applicable(
|
||||
unwrap_type_to_generic_arg,
|
||||
r#"
|
||||
fn foo() -> $0i32 {}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_type_to_generic_arg_not_applicable_for_multiple_generic_args() {
|
||||
check_assist_not_applicable(
|
||||
unwrap_type_to_generic_arg,
|
||||
r#"
|
||||
//- minicore: result
|
||||
fn foo() -> $0Result<i32, ()> {
|
||||
todo!()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_type_to_generic_arg_with_lifetime_and_const() {
|
||||
check_assist(
|
||||
unwrap_type_to_generic_arg,
|
||||
r#"
|
||||
enum Foo<'a, T, const N: usize> {
|
||||
Bar(T),
|
||||
Baz(&'a [T; N]),
|
||||
}
|
||||
|
||||
fn test<'a>() -> $0Foo<'a, i32, 3> {
|
||||
todo!()
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
enum Foo<'a, T, const N: usize> {
|
||||
Bar(T),
|
||||
Baz(&'a [T; N]),
|
||||
}
|
||||
|
||||
fn test<'a>() -> i32 {
|
||||
todo!()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn unwrap_type_to_generic_arg_in_let_stmt() {
|
||||
check_assist(
|
||||
unwrap_type_to_generic_arg,
|
||||
r#"
|
||||
enum Foo<T> {
|
||||
Bar(T),
|
||||
Baz,
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let foo: $0Foo<i32> = todo!();
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
enum Foo<T> {
|
||||
Bar(T),
|
||||
Baz,
|
||||
}
|
||||
|
||||
fn test() {
|
||||
let foo: i32 = todo!();
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -229,6 +229,7 @@ mod handlers {
|
||||
mod unwrap_block;
|
||||
mod unwrap_return_type;
|
||||
mod unwrap_tuple;
|
||||
mod unwrap_type_to_generic_arg;
|
||||
mod wrap_return_type;
|
||||
mod wrap_unwrap_cfg_attr;
|
||||
|
||||
@@ -369,6 +370,7 @@ pub(crate) fn all() -> &'static [Handler] {
|
||||
unwrap_block::unwrap_block,
|
||||
unwrap_return_type::unwrap_return_type,
|
||||
unwrap_tuple::unwrap_tuple,
|
||||
unwrap_type_to_generic_arg::unwrap_type_to_generic_arg,
|
||||
wrap_return_type::wrap_return_type,
|
||||
wrap_unwrap_cfg_attr::wrap_unwrap_cfg_attr,
|
||||
|
||||
|
||||
@@ -3481,6 +3481,23 @@ fn main() {
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_unwrap_type_to_generic_arg() {
|
||||
check_doc_test(
|
||||
"unwrap_type_to_generic_arg",
|
||||
r#####"
|
||||
fn foo() -> $0Option<i32> {
|
||||
todo!()
|
||||
}
|
||||
"#####,
|
||||
r#####"
|
||||
fn foo() -> i32 {
|
||||
todo!()
|
||||
}
|
||||
"#####,
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn doctest_wrap_return_type_in_option() {
|
||||
check_doc_test(
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
const CARGO_DEFINED_VARS: &[(&str, &str)] = &[
|
||||
("CARGO", "Path to the cargo binary performing the build"),
|
||||
("CARGO_MANIFEST_DIR", "The directory containing the manifest of your package"),
|
||||
("CARGO_MANIFEST_PATH", "The path to the manifest of your package"),
|
||||
("CARGO_PKG_VERSION", "The full version of your package"),
|
||||
("CARGO_PKG_VERSION_MAJOR", "The major version of your package"),
|
||||
("CARGO_PKG_VERSION_MINOR", "The minor version of your package"),
|
||||
|
||||
@@ -311,6 +311,8 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
|
||||
|
||||
let mut prefix = String::new();
|
||||
|
||||
let mut found_ref_or_deref = false;
|
||||
|
||||
while let Some(parent_deref_element) =
|
||||
resulting_element.syntax().parent().and_then(ast::PrefixExpr::cast)
|
||||
{
|
||||
@@ -318,27 +320,26 @@ fn include_references(initial_element: &ast::Expr) -> (ast::Expr, String) {
|
||||
break;
|
||||
}
|
||||
|
||||
found_ref_or_deref = true;
|
||||
resulting_element = ast::Expr::from(parent_deref_element);
|
||||
|
||||
prefix.insert(0, '*');
|
||||
}
|
||||
|
||||
if let Some(first_ref_expr) = resulting_element.syntax().parent().and_then(ast::RefExpr::cast) {
|
||||
if let Some(expr) = first_ref_expr.expr() {
|
||||
resulting_element = expr;
|
||||
}
|
||||
while let Some(parent_ref_element) =
|
||||
resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
|
||||
{
|
||||
found_ref_or_deref = true;
|
||||
let exclusive = parent_ref_element.mut_token().is_some();
|
||||
resulting_element = ast::Expr::from(parent_ref_element);
|
||||
|
||||
while let Some(parent_ref_element) =
|
||||
resulting_element.syntax().parent().and_then(ast::RefExpr::cast)
|
||||
{
|
||||
let exclusive = parent_ref_element.mut_token().is_some();
|
||||
resulting_element = ast::Expr::from(parent_ref_element);
|
||||
prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
|
||||
}
|
||||
|
||||
prefix.insert_str(0, if exclusive { "&mut " } else { "&" });
|
||||
}
|
||||
} else {
|
||||
// If we do not find any ref expressions, restore
|
||||
if !found_ref_or_deref {
|
||||
// If we do not find any ref/deref expressions, restore
|
||||
// all the progress of tree climbing
|
||||
prefix.clear();
|
||||
resulting_element = initial_element.clone();
|
||||
}
|
||||
|
||||
|
||||
@@ -883,9 +883,10 @@ fn classify_name_ref(
|
||||
},
|
||||
ast::MethodCallExpr(method) => {
|
||||
let receiver = find_opt_node_in_file(original_file, method.receiver());
|
||||
let has_parens = has_parens(&method);
|
||||
let kind = NameRefKind::DotAccess(DotAccess {
|
||||
receiver_ty: receiver.as_ref().and_then(|it| sema.type_of_expr(it)),
|
||||
kind: DotAccessKind::Method { has_parens: method.arg_list().is_some_and(|it| it.l_paren_token().is_some()) },
|
||||
kind: DotAccessKind::Method { has_parens },
|
||||
receiver,
|
||||
ctx: DotAccessExprCtx { in_block_expr: is_in_block(method.syntax()), in_breakable: is_in_breakable(method.syntax()) }
|
||||
});
|
||||
@@ -1372,7 +1373,7 @@ fn classify_name_ref(
|
||||
}
|
||||
}
|
||||
|
||||
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
|
||||
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
@@ -1401,7 +1402,7 @@ fn classify_name_ref(
|
||||
match parent {
|
||||
ast::PathType(it) => make_path_kind_type(it.into()),
|
||||
ast::PathExpr(it) => {
|
||||
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::can_cast(it.kind()));
|
||||
path_ctx.has_call_parens = it.syntax().parent().is_some_and(|it| ast::CallExpr::cast(it).is_some_and(|it| has_parens(&it)));
|
||||
|
||||
make_path_kind_expr(it.into())
|
||||
},
|
||||
@@ -1559,6 +1560,30 @@ fn classify_name_ref(
|
||||
Some((NameRefContext { nameref, kind: NameRefKind::Path(path_ctx) }, qualifier_ctx))
|
||||
}
|
||||
|
||||
/// When writing in the middle of some code the following situation commonly occurs (`|` denotes the cursor):
|
||||
/// ```ignore
|
||||
/// value.method|
|
||||
/// (1, 2, 3)
|
||||
/// ```
|
||||
/// Here, we want to complete the method parentheses & arguments (if the corresponding settings are on),
|
||||
/// but the thing is parsed as a method call with parentheses. Therefore we use heuristics: if the parentheses
|
||||
/// are on the next line, consider them non-existent.
|
||||
fn has_parens(node: &dyn HasArgList) -> bool {
|
||||
let Some(arg_list) = node.arg_list() else { return false };
|
||||
if arg_list.l_paren_token().is_none() {
|
||||
return false;
|
||||
}
|
||||
let prev_siblings = iter::successors(arg_list.syntax().prev_sibling_or_token(), |it| {
|
||||
it.prev_sibling_or_token()
|
||||
});
|
||||
prev_siblings
|
||||
.take_while(|syntax| syntax.kind().is_trivia())
|
||||
.filter_map(|syntax| {
|
||||
syntax.into_token().filter(|token| token.kind() == SyntaxKind::WHITESPACE)
|
||||
})
|
||||
.all(|whitespace| !whitespace.text().contains('\n'))
|
||||
}
|
||||
|
||||
fn pattern_context_for(
|
||||
sema: &Semantics<'_, RootDatabase>,
|
||||
original_file: &SyntaxNode,
|
||||
|
||||
@@ -2126,3 +2126,70 @@ fn main() {
|
||||
"#]],
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn call_parens_with_newline() {
|
||||
check_edit(
|
||||
"foo",
|
||||
r#"
|
||||
fn foo(v: i32) {}
|
||||
|
||||
fn bar() {
|
||||
foo$0
|
||||
()
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn foo(v: i32) {}
|
||||
|
||||
fn bar() {
|
||||
foo(${1:v});$0
|
||||
()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
check_edit(
|
||||
"foo",
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self, v: i32) {}
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
Foo.foo$0
|
||||
()
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
struct Foo;
|
||||
impl Foo {
|
||||
fn foo(&self, v: i32) {}
|
||||
}
|
||||
|
||||
fn bar() {
|
||||
Foo.foo(${1:v});$0
|
||||
()
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn dbg_too_many_asterisks() {
|
||||
check_edit(
|
||||
"dbg",
|
||||
r#"
|
||||
fn main() {
|
||||
let x = &42;
|
||||
let y = *x.$0;
|
||||
}
|
||||
"#,
|
||||
r#"
|
||||
fn main() {
|
||||
let x = &42;
|
||||
let y = dbg!(*x);
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
// FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
|
||||
|
||||
use crate::RootDatabase;
|
||||
use crate::documentation::{Documentation, HasDocs};
|
||||
use crate::documentation::{DocsRangeMap, Documentation, HasDocs};
|
||||
use crate::famous_defs::FamousDefs;
|
||||
use arrayvec::ArrayVec;
|
||||
use either::Either;
|
||||
@@ -21,7 +21,7 @@
|
||||
use span::Edition;
|
||||
use stdx::{format_to, impl_from};
|
||||
use syntax::{
|
||||
SyntaxKind, SyntaxNode, SyntaxToken,
|
||||
SyntaxKind, SyntaxNode, SyntaxToken, TextSize,
|
||||
ast::{self, AstNode},
|
||||
match_ast,
|
||||
};
|
||||
@@ -210,29 +210,40 @@ pub fn docs(
|
||||
famous_defs: Option<&FamousDefs<'_, '_>>,
|
||||
display_target: DisplayTarget,
|
||||
) -> Option<Documentation> {
|
||||
self.docs_with_rangemap(db, famous_defs, display_target).map(|(docs, _)| docs)
|
||||
}
|
||||
|
||||
pub fn docs_with_rangemap(
|
||||
&self,
|
||||
db: &RootDatabase,
|
||||
famous_defs: Option<&FamousDefs<'_, '_>>,
|
||||
display_target: DisplayTarget,
|
||||
) -> Option<(Documentation, Option<DocsRangeMap>)> {
|
||||
let docs = match self {
|
||||
Definition::Macro(it) => it.docs(db),
|
||||
Definition::Field(it) => it.docs(db),
|
||||
Definition::Module(it) => it.docs(db),
|
||||
Definition::Crate(it) => it.docs(db),
|
||||
Definition::Function(it) => it.docs(db),
|
||||
Definition::Adt(it) => it.docs(db),
|
||||
Definition::Variant(it) => it.docs(db),
|
||||
Definition::Const(it) => it.docs(db),
|
||||
Definition::Static(it) => it.docs(db),
|
||||
Definition::Trait(it) => it.docs(db),
|
||||
Definition::TraitAlias(it) => it.docs(db),
|
||||
Definition::Macro(it) => it.docs_with_rangemap(db),
|
||||
Definition::Field(it) => it.docs_with_rangemap(db),
|
||||
Definition::Module(it) => it.docs_with_rangemap(db),
|
||||
Definition::Crate(it) => it.docs_with_rangemap(db),
|
||||
Definition::Function(it) => it.docs_with_rangemap(db),
|
||||
Definition::Adt(it) => it.docs_with_rangemap(db),
|
||||
Definition::Variant(it) => it.docs_with_rangemap(db),
|
||||
Definition::Const(it) => it.docs_with_rangemap(db),
|
||||
Definition::Static(it) => it.docs_with_rangemap(db),
|
||||
Definition::Trait(it) => it.docs_with_rangemap(db),
|
||||
Definition::TraitAlias(it) => it.docs_with_rangemap(db),
|
||||
Definition::TypeAlias(it) => {
|
||||
it.docs(db).or_else(|| {
|
||||
it.docs_with_rangemap(db).or_else(|| {
|
||||
// docs are missing, try to fall back to the docs of the aliased item.
|
||||
let adt = it.ty(db).as_adt()?;
|
||||
let docs = adt.docs(db)?;
|
||||
let docs = format!(
|
||||
"*This is the documentation for* `{}`\n\n{}",
|
||||
adt.display(db, display_target),
|
||||
docs.as_str()
|
||||
let (docs, range_map) = adt.docs_with_rangemap(db)?;
|
||||
let header_docs = format!(
|
||||
"*This is the documentation for* `{}`\n\n",
|
||||
adt.display(db, display_target)
|
||||
);
|
||||
Some(Documentation::new(docs))
|
||||
let offset = TextSize::new(header_docs.len() as u32);
|
||||
let range_map = range_map.shift_docstring_line_range(offset);
|
||||
let docs = header_docs + docs.as_str();
|
||||
Some((Documentation::new(docs), range_map))
|
||||
})
|
||||
}
|
||||
Definition::BuiltinType(it) => {
|
||||
@@ -241,17 +252,17 @@ pub fn docs(
|
||||
let primitive_mod =
|
||||
format!("prim_{}", it.name().display(fd.0.db, display_target.edition));
|
||||
let doc_owner = find_std_module(fd, &primitive_mod, display_target.edition)?;
|
||||
doc_owner.docs(fd.0.db)
|
||||
doc_owner.docs_with_rangemap(fd.0.db)
|
||||
})
|
||||
}
|
||||
Definition::BuiltinLifetime(StaticLifetime) => None,
|
||||
Definition::Local(_) => None,
|
||||
Definition::SelfType(impl_def) => {
|
||||
impl_def.self_ty(db).as_adt().map(|adt| adt.docs(db))?
|
||||
impl_def.self_ty(db).as_adt().map(|adt| adt.docs_with_rangemap(db))?
|
||||
}
|
||||
Definition::GenericParam(_) => None,
|
||||
Definition::Label(_) => None,
|
||||
Definition::ExternCrateDecl(it) => it.docs(db),
|
||||
Definition::ExternCrateDecl(it) => it.docs_with_rangemap(db),
|
||||
|
||||
Definition::BuiltinAttr(it) => {
|
||||
let name = it.name(db);
|
||||
@@ -276,7 +287,8 @@ pub fn docs(
|
||||
name_value_str
|
||||
);
|
||||
}
|
||||
Some(Documentation::new(docs.replace('*', "\\*")))
|
||||
|
||||
return Some((Documentation::new(docs.replace('*', "\\*")), None));
|
||||
}
|
||||
Definition::ToolModule(_) => None,
|
||||
Definition::DeriveHelper(_) => None,
|
||||
@@ -291,8 +303,9 @@ pub fn docs(
|
||||
let trait_ = assoc.implemented_trait(db)?;
|
||||
let name = Some(assoc.name(db)?);
|
||||
let item = trait_.items(db).into_iter().find(|it| it.name(db) == name)?;
|
||||
item.docs(db)
|
||||
item.docs_with_rangemap(db)
|
||||
})
|
||||
.map(|(docs, range_map)| (docs, Some(range_map)))
|
||||
}
|
||||
|
||||
pub fn label(&self, db: &RootDatabase, display_target: DisplayTarget) -> String {
|
||||
|
||||
@@ -34,11 +34,13 @@ fn from(Documentation(string): Documentation) -> Self {
|
||||
|
||||
pub trait HasDocs: HasAttrs {
|
||||
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation>;
|
||||
fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)>;
|
||||
fn resolve_doc_path(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
link: &str,
|
||||
ns: Option<hir::Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<hir::DocLinkDef>;
|
||||
}
|
||||
/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
|
||||
@@ -53,7 +55,7 @@ pub struct DocsRangeMap {
|
||||
|
||||
impl DocsRangeMap {
|
||||
/// Maps a [`TextRange`] relative to the documentation string back to its AST range
|
||||
pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
|
||||
pub fn map(&self, range: TextRange) -> Option<(InFile<TextRange>, AttrId)> {
|
||||
let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
|
||||
let (line_docs_range, idx, original_line_src_range) = self.mapping[found];
|
||||
if !line_docs_range.contains_range(range) {
|
||||
@@ -71,7 +73,7 @@ pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
|
||||
text_range.end() + original_line_src_range.start() + relative_range.start(),
|
||||
string.syntax().text_range().len().min(range.len()),
|
||||
);
|
||||
Some(InFile { file_id, value: range })
|
||||
Some((InFile { file_id, value: range }, idx))
|
||||
}
|
||||
Either::Right(comment) => {
|
||||
let text_range = comment.syntax().text_range();
|
||||
@@ -82,10 +84,22 @@ pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
|
||||
+ relative_range.start(),
|
||||
text_range.len().min(range.len()),
|
||||
);
|
||||
Some(InFile { file_id, value: range })
|
||||
Some((InFile { file_id, value: range }, idx))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn shift_docstring_line_range(self, offset: TextSize) -> DocsRangeMap {
|
||||
let mapping = self
|
||||
.mapping
|
||||
.into_iter()
|
||||
.map(|(buf_offset, id, base_offset)| {
|
||||
let buf_offset = buf_offset.checked_add(offset).unwrap();
|
||||
(buf_offset, id, base_offset)
|
||||
})
|
||||
.collect_vec();
|
||||
DocsRangeMap { source_map: self.source_map, mapping }
|
||||
}
|
||||
}
|
||||
|
||||
pub fn docs_with_rangemap(
|
||||
@@ -161,13 +175,20 @@ impl HasDocs for hir::$def {
|
||||
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
|
||||
docs_from_attrs(&self.attrs(db)).map(Documentation)
|
||||
}
|
||||
fn docs_with_rangemap(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<(Documentation, DocsRangeMap)> {
|
||||
docs_with_rangemap(db, &self.attrs(db))
|
||||
}
|
||||
fn resolve_doc_path(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
link: &str,
|
||||
ns: Option<hir::Namespace>
|
||||
ns: Option<hir::Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<hir::DocLinkDef> {
|
||||
resolve_doc_path_on(db, self, link, ns)
|
||||
resolve_doc_path_on(db, self, link, ns, is_inner_doc)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
@@ -184,13 +205,21 @@ impl HasDocs for hir::$variant {
|
||||
fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
|
||||
hir::$enum::$variant(self).docs(db)
|
||||
}
|
||||
|
||||
fn docs_with_rangemap(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
) -> Option<(Documentation, DocsRangeMap)> {
|
||||
hir::$enum::$variant(self).docs_with_rangemap(db)
|
||||
}
|
||||
fn resolve_doc_path(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
link: &str,
|
||||
ns: Option<hir::Namespace>
|
||||
ns: Option<hir::Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<hir::DocLinkDef> {
|
||||
hir::$enum::$variant(self).resolve_doc_path(db, link, ns)
|
||||
hir::$enum::$variant(self).resolve_doc_path(db, link, ns, is_inner_doc)
|
||||
}
|
||||
}
|
||||
)*};
|
||||
@@ -207,16 +236,25 @@ fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
|
||||
}
|
||||
}
|
||||
|
||||
fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
|
||||
match self {
|
||||
hir::AssocItem::Function(it) => it.docs_with_rangemap(db),
|
||||
hir::AssocItem::Const(it) => it.docs_with_rangemap(db),
|
||||
hir::AssocItem::TypeAlias(it) => it.docs_with_rangemap(db),
|
||||
}
|
||||
}
|
||||
|
||||
fn resolve_doc_path(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
link: &str,
|
||||
ns: Option<hir::Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<hir::DocLinkDef> {
|
||||
match self {
|
||||
hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns),
|
||||
hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns),
|
||||
hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns),
|
||||
hir::AssocItem::Function(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
|
||||
hir::AssocItem::Const(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
|
||||
hir::AssocItem::TypeAlias(it) => it.resolve_doc_path(db, link, ns, is_inner_doc),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -238,13 +276,36 @@ fn docs(self, db: &dyn HirDatabase) -> Option<Documentation> {
|
||||
}
|
||||
.map(Documentation::new)
|
||||
}
|
||||
|
||||
fn docs_with_rangemap(self, db: &dyn HirDatabase) -> Option<(Documentation, DocsRangeMap)> {
|
||||
let crate_docs = docs_with_rangemap(db, &self.resolved_crate(db)?.root_module().attrs(db));
|
||||
let decl_docs = docs_with_rangemap(db, &self.attrs(db));
|
||||
match (decl_docs, crate_docs) {
|
||||
(None, None) => None,
|
||||
(Some(decl_docs), None) => Some(decl_docs),
|
||||
(None, Some(crate_docs)) => Some(crate_docs),
|
||||
(
|
||||
Some((Documentation(mut decl_docs), mut decl_range_map)),
|
||||
Some((Documentation(crate_docs), crate_range_map)),
|
||||
) => {
|
||||
decl_docs.push('\n');
|
||||
decl_docs.push('\n');
|
||||
let offset = TextSize::new(decl_docs.len() as u32);
|
||||
decl_docs += &crate_docs;
|
||||
let crate_range_map = crate_range_map.shift_docstring_line_range(offset);
|
||||
decl_range_map.mapping.extend(crate_range_map.mapping);
|
||||
Some((Documentation(decl_docs), decl_range_map))
|
||||
}
|
||||
}
|
||||
}
|
||||
fn resolve_doc_path(
|
||||
self,
|
||||
db: &dyn HirDatabase,
|
||||
link: &str,
|
||||
ns: Option<hir::Namespace>,
|
||||
is_inner_doc: bool,
|
||||
) -> Option<hir::DocLinkDef> {
|
||||
resolve_doc_path_on(db, self, link, ns)
|
||||
resolve_doc_path_on(db, self, link, ns, is_inner_doc)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,12 +2,10 @@
|
||||
//! sometimes is counter productive when, for example, the first goto definition
|
||||
//! request takes longer to compute. This module implements prepopulation of
|
||||
//! various caches, it's not really advanced at the moment.
|
||||
mod topologic_sort;
|
||||
|
||||
use std::time::Duration;
|
||||
use std::panic::AssertUnwindSafe;
|
||||
|
||||
use hir::{Symbol, db::DefDatabase};
|
||||
use itertools::Itertools;
|
||||
use rustc_hash::FxHashMap;
|
||||
use salsa::{Cancelled, Database};
|
||||
|
||||
use crate::{
|
||||
@@ -35,59 +33,114 @@ pub fn parallel_prime_caches(
|
||||
) {
|
||||
let _p = tracing::info_span!("parallel_prime_caches").entered();
|
||||
|
||||
let mut crates_to_prime = {
|
||||
// FIXME: We already have the crate list topologically sorted (but without the things
|
||||
// `TopologicalSortIter` gives us). Maybe there is a way to avoid using it and rip it out
|
||||
// of the codebase?
|
||||
let mut builder = topologic_sort::TopologicalSortIter::builder();
|
||||
|
||||
for &crate_id in db.all_crates().iter() {
|
||||
builder.add(crate_id, crate_id.data(db).dependencies.iter().map(|d| d.crate_id));
|
||||
}
|
||||
|
||||
builder.build()
|
||||
};
|
||||
|
||||
enum ParallelPrimeCacheWorkerProgress {
|
||||
BeginCrate { crate_id: Crate, crate_name: Symbol },
|
||||
EndCrate { crate_id: Crate },
|
||||
BeginCrateDefMap { crate_id: Crate, crate_name: Symbol },
|
||||
EndCrateDefMap { crate_id: Crate },
|
||||
EndCrateImportMap,
|
||||
EndModuleSymbols,
|
||||
Cancelled(Cancelled),
|
||||
}
|
||||
|
||||
// We split off def map computation from other work,
|
||||
// as the def map is the relevant one. Once the defmaps are computed
|
||||
// the project is ready to go, the other indices are just nice to have for some IDE features.
|
||||
#[derive(PartialOrd, Ord, PartialEq, Eq, Copy, Clone)]
|
||||
enum PrimingPhase {
|
||||
DefMap,
|
||||
ImportMap,
|
||||
CrateSymbols,
|
||||
}
|
||||
// The setup here is a bit complicated. We try to make best use of compute resources.
|
||||
// The idea is that if we have a def map available to compute, we should do that first.
|
||||
// This is because def map is a dependency of both import map and symbols. So if we have
|
||||
// e.g. a def map and a symbols, if we compute the def map we can, after it completes,
|
||||
// compute the def maps of dependencies, the existing symbols and the symbols of the
|
||||
// new crate, all in parallel. But if we compute the symbols, after that we will only
|
||||
// have the def map to compute, and the rest of the CPU cores will rest, which is not
|
||||
// good.
|
||||
// However, it's better to compute symbols/import map than to compute a def map that
|
||||
// isn't ready yet, because one of its dependencies hasn't yet completed its def map.
|
||||
// Such def map will just block on the dependency, which is just wasted time. So better
|
||||
// to compute the symbols/import map of an already computed def map in that time.
|
||||
|
||||
let (work_sender, progress_receiver) = {
|
||||
let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
|
||||
let (work_sender, work_receiver) = crossbeam_channel::unbounded();
|
||||
let prime_caches_worker = move |db: RootDatabase| {
|
||||
while let Ok((crate_id, crate_name, kind)) = work_receiver.recv() {
|
||||
progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
|
||||
|
||||
let cancelled = Cancelled::catch(|| match kind {
|
||||
PrimingPhase::DefMap => _ = db.crate_def_map(crate_id),
|
||||
PrimingPhase::ImportMap => _ = db.import_map(crate_id),
|
||||
PrimingPhase::CrateSymbols => _ = db.crate_symbols(crate_id.into()),
|
||||
});
|
||||
|
||||
match cancelled {
|
||||
Ok(()) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?,
|
||||
Err(cancelled) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
|
||||
}
|
||||
let (reverse_deps, mut to_be_done_deps) = {
|
||||
let all_crates = db.all_crates();
|
||||
let to_be_done_deps = all_crates
|
||||
.iter()
|
||||
.map(|&krate| (krate, krate.data(db).dependencies.len() as u32))
|
||||
.collect::<FxHashMap<_, _>>();
|
||||
let mut reverse_deps =
|
||||
all_crates.iter().map(|&krate| (krate, Vec::new())).collect::<FxHashMap<_, _>>();
|
||||
for &krate in &*all_crates {
|
||||
for dep in &krate.data(db).dependencies {
|
||||
reverse_deps.get_mut(&dep.crate_id).unwrap().push(krate);
|
||||
}
|
||||
}
|
||||
(reverse_deps, to_be_done_deps)
|
||||
};
|
||||
|
||||
Ok::<_, crossbeam_channel::SendError<_>>(())
|
||||
};
|
||||
let (def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver) = {
|
||||
let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
|
||||
let (def_map_work_sender, def_map_work_receiver) = crossbeam_channel::unbounded();
|
||||
let (import_map_work_sender, import_map_work_receiver) = crossbeam_channel::unbounded();
|
||||
let (symbols_work_sender, symbols_work_receiver) = crossbeam_channel::unbounded();
|
||||
let prime_caches_worker =
|
||||
move |db: RootDatabase| {
|
||||
let handle_def_map = |crate_id, crate_name| {
|
||||
progress_sender.send(ParallelPrimeCacheWorkerProgress::BeginCrateDefMap {
|
||||
crate_id,
|
||||
crate_name,
|
||||
})?;
|
||||
|
||||
let cancelled = Cancelled::catch(|| _ = hir::crate_def_map(&db, crate_id));
|
||||
|
||||
match cancelled {
|
||||
Ok(()) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id })?,
|
||||
Err(cancelled) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
|
||||
}
|
||||
|
||||
Ok::<_, crossbeam_channel::SendError<_>>(())
|
||||
};
|
||||
let handle_import_map = |crate_id| {
|
||||
let cancelled = Cancelled::catch(|| _ = db.import_map(crate_id));
|
||||
|
||||
match cancelled {
|
||||
Ok(()) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::EndCrateImportMap)?,
|
||||
Err(cancelled) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
|
||||
}
|
||||
|
||||
Ok::<_, crossbeam_channel::SendError<_>>(())
|
||||
};
|
||||
let handle_symbols = |module| {
|
||||
let cancelled =
|
||||
Cancelled::catch(AssertUnwindSafe(|| _ = db.module_symbols(module)));
|
||||
|
||||
match cancelled {
|
||||
Ok(()) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::EndModuleSymbols)?,
|
||||
Err(cancelled) => progress_sender
|
||||
.send(ParallelPrimeCacheWorkerProgress::Cancelled(cancelled))?,
|
||||
}
|
||||
|
||||
Ok::<_, crossbeam_channel::SendError<_>>(())
|
||||
};
|
||||
|
||||
loop {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
||||
// Biased because we want to prefer def maps.
|
||||
crossbeam_channel::select_biased! {
|
||||
recv(def_map_work_receiver) -> work => {
|
||||
let Ok((crate_id, crate_name)) = work else { break };
|
||||
handle_def_map(crate_id, crate_name)?;
|
||||
}
|
||||
recv(import_map_work_receiver) -> work => {
|
||||
let Ok(crate_id) = work else { break };
|
||||
handle_import_map(crate_id)?;
|
||||
}
|
||||
recv(symbols_work_receiver) -> work => {
|
||||
let Ok(module) = work else { break };
|
||||
handle_symbols(module)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok::<_, crossbeam_channel::SendError<_>>(())
|
||||
};
|
||||
|
||||
for id in 0..num_worker_threads {
|
||||
stdx::thread::Builder::new(
|
||||
@@ -103,138 +156,121 @@ enum PrimingPhase {
|
||||
.expect("failed to spawn thread");
|
||||
}
|
||||
|
||||
(work_sender, progress_receiver)
|
||||
(def_map_work_sender, import_map_work_sender, symbols_work_sender, progress_receiver)
|
||||
};
|
||||
|
||||
let crates_total = crates_to_prime.pending();
|
||||
let mut crates_done = 0;
|
||||
let crate_def_maps_total = db.all_crates().len();
|
||||
let mut crate_def_maps_done = 0;
|
||||
let (mut crate_import_maps_total, mut crate_import_maps_done) = (0usize, 0usize);
|
||||
let (mut module_symbols_total, mut module_symbols_done) = (0usize, 0usize);
|
||||
|
||||
// an index map is used to preserve ordering so we can sort the progress report in order of
|
||||
// "longest crate to index" first
|
||||
let mut crates_currently_indexing =
|
||||
FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
|
||||
|
||||
let mut additional_phases = vec![];
|
||||
|
||||
while crates_done < crates_total {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
||||
for krate in &mut crates_to_prime {
|
||||
let name = krate.extra_data(db).display_name.as_deref().cloned().unwrap_or_else(|| {
|
||||
Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize)
|
||||
});
|
||||
let origin = &krate.data(db).origin;
|
||||
if origin.is_lang() {
|
||||
additional_phases.push((krate, name.clone(), PrimingPhase::ImportMap));
|
||||
} else if origin.is_local() {
|
||||
// Compute the symbol search index.
|
||||
// This primes the cache for `ide_db::symbol_index::world_symbols()`.
|
||||
//
|
||||
// We do this for workspace crates only (members of local_roots), because doing it
|
||||
// for all dependencies could be *very* unnecessarily slow in a large project.
|
||||
//
|
||||
// FIXME: We should do it unconditionally if the configuration is set to default to
|
||||
// searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
|
||||
// would need to pipe that configuration information down here.
|
||||
additional_phases.push((krate, name.clone(), PrimingPhase::CrateSymbols));
|
||||
}
|
||||
|
||||
work_sender.send((krate, name, PrimingPhase::DefMap)).ok();
|
||||
for (&krate, &to_be_done_deps) in &to_be_done_deps {
|
||||
if to_be_done_deps != 0 {
|
||||
continue;
|
||||
}
|
||||
|
||||
// recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
|
||||
// is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
|
||||
// if this thread exits, and closes the work channel.
|
||||
let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
|
||||
Ok(p) => p,
|
||||
Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
|
||||
continue;
|
||||
}
|
||||
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
|
||||
// all our workers have exited, mark us as finished and exit
|
||||
cb(ParallelPrimeCachesProgress {
|
||||
crates_currently_indexing: vec![],
|
||||
crates_done,
|
||||
crates_total: crates_done,
|
||||
work_type: "Indexing",
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
match worker_progress {
|
||||
ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
|
||||
crates_currently_indexing.insert(crate_id, crate_name);
|
||||
}
|
||||
ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
|
||||
crates_currently_indexing.swap_remove(&crate_id);
|
||||
crates_to_prime.mark_done(crate_id);
|
||||
crates_done += 1;
|
||||
}
|
||||
ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
|
||||
// Cancelled::throw should probably be public
|
||||
std::panic::resume_unwind(Box::new(cancelled));
|
||||
}
|
||||
};
|
||||
let name = crate_name(db, krate);
|
||||
def_map_work_sender.send((krate, name)).ok();
|
||||
}
|
||||
|
||||
while crate_def_maps_done < crate_def_maps_total
|
||||
|| crate_import_maps_done < crate_import_maps_total
|
||||
|| module_symbols_done < module_symbols_total
|
||||
{
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
||||
let progress = ParallelPrimeCachesProgress {
|
||||
crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
|
||||
crates_done,
|
||||
crates_total,
|
||||
crates_done: crate_def_maps_done,
|
||||
crates_total: crate_def_maps_total,
|
||||
work_type: "Indexing",
|
||||
};
|
||||
|
||||
cb(progress);
|
||||
}
|
||||
|
||||
let mut crates_done = 0;
|
||||
let crates_total = additional_phases.len();
|
||||
for w in additional_phases.into_iter().sorted_by_key(|&(_, _, phase)| phase) {
|
||||
work_sender.send(w).ok();
|
||||
}
|
||||
|
||||
while crates_done < crates_total {
|
||||
db.unwind_if_revision_cancelled();
|
||||
|
||||
// recv_timeout is somewhat a hack, we need a way to from this thread check to see if the current salsa revision
|
||||
// is cancelled on a regular basis. workers will only exit if they are processing a task that is cancelled, or
|
||||
// if this thread exits, and closes the work channel.
|
||||
let worker_progress = match progress_receiver.recv_timeout(Duration::from_millis(10)) {
|
||||
// Biased to prefer progress updates (and because it's faster).
|
||||
let progress = match progress_receiver.recv() {
|
||||
Ok(p) => p,
|
||||
Err(crossbeam_channel::RecvTimeoutError::Timeout) => {
|
||||
continue;
|
||||
}
|
||||
Err(crossbeam_channel::RecvTimeoutError::Disconnected) => {
|
||||
Err(crossbeam_channel::RecvError) => {
|
||||
// all our workers have exited, mark us as finished and exit
|
||||
cb(ParallelPrimeCachesProgress {
|
||||
crates_currently_indexing: vec![],
|
||||
crates_done,
|
||||
crates_total: crates_done,
|
||||
work_type: "Populating symbols",
|
||||
crates_done: crate_def_maps_done,
|
||||
crates_total: crate_def_maps_done,
|
||||
work_type: "Done",
|
||||
});
|
||||
return;
|
||||
}
|
||||
};
|
||||
match worker_progress {
|
||||
ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name } => {
|
||||
|
||||
match progress {
|
||||
ParallelPrimeCacheWorkerProgress::BeginCrateDefMap { crate_id, crate_name } => {
|
||||
crates_currently_indexing.insert(crate_id, crate_name);
|
||||
}
|
||||
ParallelPrimeCacheWorkerProgress::EndCrate { crate_id } => {
|
||||
ParallelPrimeCacheWorkerProgress::EndCrateDefMap { crate_id } => {
|
||||
crates_currently_indexing.swap_remove(&crate_id);
|
||||
crates_done += 1;
|
||||
crate_def_maps_done += 1;
|
||||
|
||||
// Fire ready dependencies.
|
||||
for &dep in &reverse_deps[&crate_id] {
|
||||
let to_be_done = to_be_done_deps.get_mut(&dep).unwrap();
|
||||
*to_be_done -= 1;
|
||||
if *to_be_done == 0 {
|
||||
let dep_name = crate_name(db, dep);
|
||||
def_map_work_sender.send((dep, dep_name)).ok();
|
||||
}
|
||||
}
|
||||
|
||||
if crate_def_maps_done == crate_def_maps_total {
|
||||
cb(ParallelPrimeCachesProgress {
|
||||
crates_currently_indexing: vec![],
|
||||
crates_done: crate_def_maps_done,
|
||||
crates_total: crate_def_maps_done,
|
||||
work_type: "Collecting Symbols",
|
||||
});
|
||||
}
|
||||
|
||||
let origin = &crate_id.data(db).origin;
|
||||
if origin.is_lang() {
|
||||
crate_import_maps_total += 1;
|
||||
import_map_work_sender.send(crate_id).ok();
|
||||
} else if origin.is_local() {
|
||||
// Compute the symbol search index.
|
||||
// This primes the cache for `ide_db::symbol_index::world_symbols()`.
|
||||
//
|
||||
// We do this for workspace crates only (members of local_roots), because doing it
|
||||
// for all dependencies could be *very* unnecessarily slow in a large project.
|
||||
//
|
||||
// FIXME: We should do it unconditionally if the configuration is set to default to
|
||||
// searching dependencies (rust-analyzer.workspace.symbol.search.scope), but we
|
||||
// would need to pipe that configuration information down here.
|
||||
let modules = hir::Crate::from(crate_id).modules(db);
|
||||
module_symbols_total += modules.len();
|
||||
for module in modules {
|
||||
symbols_work_sender.send(module).ok();
|
||||
}
|
||||
}
|
||||
}
|
||||
ParallelPrimeCacheWorkerProgress::EndCrateImportMap => crate_import_maps_done += 1,
|
||||
ParallelPrimeCacheWorkerProgress::EndModuleSymbols => module_symbols_done += 1,
|
||||
ParallelPrimeCacheWorkerProgress::Cancelled(cancelled) => {
|
||||
// Cancelled::throw should probably be public
|
||||
std::panic::resume_unwind(Box::new(cancelled));
|
||||
}
|
||||
};
|
||||
|
||||
let progress = ParallelPrimeCachesProgress {
|
||||
crates_currently_indexing: crates_currently_indexing.values().cloned().collect(),
|
||||
crates_done,
|
||||
crates_total,
|
||||
work_type: "Populating symbols",
|
||||
};
|
||||
|
||||
cb(progress);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn crate_name(db: &RootDatabase, krate: Crate) -> Symbol {
|
||||
krate
|
||||
.extra_data(db)
|
||||
.display_name
|
||||
.as_deref()
|
||||
.cloned()
|
||||
.unwrap_or_else(|| Symbol::integer(salsa::plumbing::AsId::as_id(&krate).as_u32() as usize))
|
||||
}
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
//! helper data structure to schedule work for parallel prime caches.
|
||||
use std::{collections::VecDeque, hash::Hash};
|
||||
|
||||
use crate::FxHashMap;
|
||||
|
||||
pub(crate) struct TopologicSortIterBuilder<T> {
|
||||
nodes: FxHashMap<T, Entry<T>>,
|
||||
}
|
||||
|
||||
// this implementation has different bounds on T than would be implied by #[derive(Default)]
|
||||
impl<T> Default for TopologicSortIterBuilder<T>
|
||||
where
|
||||
T: Copy + Eq + PartialEq + Hash,
|
||||
{
|
||||
fn default() -> Self {
|
||||
Self { nodes: Default::default() }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TopologicSortIterBuilder<T>
|
||||
where
|
||||
T: Copy + Eq + PartialEq + Hash,
|
||||
{
|
||||
fn get_or_create_entry(&mut self, item: T) -> &mut Entry<T> {
|
||||
self.nodes.entry(item).or_default()
|
||||
}
|
||||
|
||||
pub(crate) fn add(&mut self, item: T, predecessors: impl IntoIterator<Item = T>) {
|
||||
let mut num_predecessors = 0;
|
||||
|
||||
for predecessor in predecessors.into_iter() {
|
||||
self.get_or_create_entry(predecessor).successors.push(item);
|
||||
num_predecessors += 1;
|
||||
}
|
||||
|
||||
let entry = self.get_or_create_entry(item);
|
||||
entry.num_predecessors += num_predecessors;
|
||||
}
|
||||
|
||||
pub(crate) fn build(self) -> TopologicalSortIter<T> {
|
||||
let ready = self
|
||||
.nodes
|
||||
.iter()
|
||||
.filter_map(
|
||||
|(item, entry)| if entry.num_predecessors == 0 { Some(*item) } else { None },
|
||||
)
|
||||
.collect();
|
||||
|
||||
TopologicalSortIter { nodes: self.nodes, ready }
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct TopologicalSortIter<T> {
|
||||
ready: VecDeque<T>,
|
||||
nodes: FxHashMap<T, Entry<T>>,
|
||||
}
|
||||
|
||||
impl<T> TopologicalSortIter<T>
|
||||
where
|
||||
T: Copy + Eq + PartialEq + Hash,
|
||||
{
|
||||
pub(crate) fn builder() -> TopologicSortIterBuilder<T> {
|
||||
TopologicSortIterBuilder::default()
|
||||
}
|
||||
|
||||
pub(crate) fn pending(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
pub(crate) fn mark_done(&mut self, item: T) {
|
||||
let entry = self.nodes.remove(&item).expect("invariant: unknown item marked as done");
|
||||
|
||||
for successor in entry.successors {
|
||||
let succ_entry = self
|
||||
.nodes
|
||||
.get_mut(&successor)
|
||||
.expect("invariant: unknown successor referenced by entry");
|
||||
|
||||
succ_entry.num_predecessors -= 1;
|
||||
if succ_entry.num_predecessors == 0 {
|
||||
self.ready.push_back(successor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Iterator for TopologicalSortIter<T> {
|
||||
type Item = T;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.ready.pop_front()
|
||||
}
|
||||
}
|
||||
|
||||
struct Entry<T> {
|
||||
successors: Vec<T>,
|
||||
num_predecessors: usize,
|
||||
}
|
||||
|
||||
impl<T> Default for Entry<T> {
|
||||
fn default() -> Self {
|
||||
Self { successors: Default::default(), num_predecessors: 0 }
|
||||
}
|
||||
}
|
||||
@@ -390,11 +390,6 @@ pub fn source_edit_from_references(
|
||||
let mut edited_ranges = Vec::new();
|
||||
for &FileReference { range, ref name, .. } in references {
|
||||
let name_range = name.text_range();
|
||||
if name_range.len() != range.len() {
|
||||
// This usage comes from a different token kind that was downmapped to a NameLike in a macro
|
||||
// Renaming this will most likely break things syntax-wise
|
||||
continue;
|
||||
}
|
||||
let has_emitted_edit = match name {
|
||||
// if the ranges differ then the node is inside a macro call, we can't really attempt
|
||||
// to make special rewrites like shorthand syntax and such, so just rename the node in
|
||||
|
||||
@@ -14,6 +14,7 @@ pub(crate) fn await_outside_of_async(
|
||||
format!("`await` is used inside {}, which is not an `async` context", d.location),
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -12,6 +12,7 @@ pub(crate) fn bad_rtn(ctx: &DiagnosticsContext<'_>, d: &hir::BadRtn) -> Diagnost
|
||||
"return type notation not allowed in this position yet",
|
||||
d.rtn.map(Into::into),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -19,6 +19,7 @@ pub(crate) fn break_outside_of_loop(
|
||||
message,
|
||||
d.expr.map(|it| it.into()),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
-2
@@ -15,7 +15,6 @@ pub(crate) fn elided_lifetimes_in_path(
|
||||
"implicit elided lifetime not allowed here",
|
||||
d.generics_or_segment.map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
} else {
|
||||
Diagnostic::new_with_syntax_node_ptr(
|
||||
ctx,
|
||||
@@ -23,7 +22,6 @@ pub(crate) fn elided_lifetimes_in_path(
|
||||
"hidden lifetime parameters in types are deprecated",
|
||||
d.generics_or_segment.map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@ pub(crate) fn expected_function(
|
||||
format!("expected function, found {}", d.found.display(ctx.sema.db, ctx.display_target)),
|
||||
d.call.map(|it| it.into()),
|
||||
)
|
||||
.experimental()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -21,6 +21,7 @@ pub(crate) fn generic_args_prohibited(
|
||||
describe_reason(d.reason),
|
||||
d.args.map(Into::into),
|
||||
)
|
||||
.stable()
|
||||
.with_fixes(fixes(ctx, d))
|
||||
}
|
||||
|
||||
|
||||
@@ -33,6 +33,7 @@ pub(crate) fn inactive_code(
|
||||
message,
|
||||
ctx.sema.diagnostics_display_range(d.node),
|
||||
)
|
||||
.stable()
|
||||
.with_unused(true);
|
||||
Some(res)
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ pub(crate) fn incoherent_impl(ctx: &DiagnosticsContext<'_>, d: &hir::IncoherentI
|
||||
"cannot define inherent `impl` for foreign type".to_owned(),
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -29,6 +29,7 @@ pub(crate) fn incorrect_case(ctx: &DiagnosticsContext<'_>, d: &hir::IncorrectCas
|
||||
),
|
||||
InFile::new(d.file, d.ident.into()),
|
||||
)
|
||||
.stable()
|
||||
.with_fixes(fixes(ctx, d))
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,6 @@ pub(crate) fn incorrect_generics_len(
|
||||
message,
|
||||
d.generics_or_segment.map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
+1
@@ -28,6 +28,7 @@ pub(crate) fn incorrect_generics_order(
|
||||
message,
|
||||
d.provided_arg.map(Into::into),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -100,7 +100,7 @@ pub(crate) fn invalid_cast(ctx: &DiagnosticsContext<'_>, d: &hir::InvalidCast) -
|
||||
// "cannot cast to a pointer of an unknown kind".to_owned(),
|
||||
// ),
|
||||
};
|
||||
Diagnostic::new(code, message, display_range)
|
||||
Diagnostic::new(code, message, display_range).stable()
|
||||
}
|
||||
|
||||
// Diagnostic: cast-to-unsized
|
||||
@@ -113,6 +113,7 @@ pub(crate) fn cast_to_unsized(ctx: &DiagnosticsContext<'_>, d: &hir::CastToUnsiz
|
||||
format_ty!(ctx, "cast to unsized type: `{}`", d.cast_ty),
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -15,6 +15,7 @@ pub(crate) fn invalid_derive_target(
|
||||
"`derive` may only be applied to `struct`s, `enum`s and `union`s",
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -19,6 +19,7 @@ pub(crate) fn macro_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroError) ->
|
||||
d.message.clone(),
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
// Diagnostic: macro-def-error
|
||||
@@ -33,6 +34,7 @@ pub(crate) fn macro_def_error(ctx: &DiagnosticsContext<'_>, d: &hir::MacroDefErr
|
||||
d.message.clone(),
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -14,6 +14,7 @@ pub(crate) fn malformed_derive(
|
||||
"malformed derive input, derive attributes are of the form `#[derive(Derive1, Derive2, ...)]`",
|
||||
display_range,
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -26,6 +26,7 @@ pub(crate) fn mismatched_tuple_struct_pat_arg_count(
|
||||
message,
|
||||
invalid_args_range(ctx, d.expr_or_pat, d.expected, d.found),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
// Diagnostic: mismatched-arg-count
|
||||
@@ -42,6 +43,7 @@ pub(crate) fn mismatched_arg_count(
|
||||
message,
|
||||
invalid_args_range(ctx, d.call_expr, d.expected, d.found),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
fn invalid_args_range(
|
||||
|
||||
@@ -47,6 +47,7 @@ pub(crate) fn missing_fields(ctx: &DiagnosticsContext<'_>, d: &hir::MissingField
|
||||
);
|
||||
|
||||
Diagnostic::new_with_syntax_node_ptr(ctx, DiagnosticCode::RustcHardError("E0063"), message, ptr)
|
||||
.stable()
|
||||
.with_fixes(fixes(ctx, d))
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@ pub(crate) fn missing_lifetime(
|
||||
"missing lifetime specifier",
|
||||
d.generics_or_segment.map(Into::into),
|
||||
)
|
||||
.experimental()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -13,6 +13,7 @@ pub(crate) fn missing_match_arms(
|
||||
format!("missing match arm: {}", d.uncovered_patterns),
|
||||
d.scrutinee_expr.map(Into::into),
|
||||
)
|
||||
.stable()
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -23,6 +23,7 @@ pub(crate) fn missing_unsafe(ctx: &DiagnosticsContext<'_>, d: &hir::MissingUnsaf
|
||||
format!("{operation} is unsafe and requires an unsafe function or block"),
|
||||
d.node.map(|it| it.into()),
|
||||
)
|
||||
.stable()
|
||||
.with_fixes(fixes(ctx, d))
|
||||
}
|
||||
|
||||
@@ -893,4 +894,25 @@ fn main() {
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn asm_label() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
//- minicore: asm
|
||||
fn foo() {
|
||||
unsafe {
|
||||
core::arch::asm!(
|
||||
"jmp {}",
|
||||
label {
|
||||
let p = 0xDEADBEAF as *mut u8;
|
||||
*p = 3;
|
||||
// ^^ error: dereference of raw pointer is unsafe and requires an unsafe function or block
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ pub(crate) fn moved_out_of_ref(ctx: &DiagnosticsContext<'_>, d: &hir::MovedOutOf
|
||||
format!("cannot move `{}` out of reference", d.ty.display(ctx.sema.db, ctx.display_target)),
|
||||
d.span,
|
||||
)
|
||||
.experimental() // spans are broken, and I'm not sure how precise we can detect copy types
|
||||
// spans are broken, and I'm not sure how precise we can detect copy types
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
@@ -55,6 +55,7 @@ pub(crate) fn need_mut(ctx: &DiagnosticsContext<'_>, d: &hir::NeedMut) -> Option
|
||||
),
|
||||
span,
|
||||
)
|
||||
.stable()
|
||||
.with_fixes(fixes),
|
||||
)
|
||||
}
|
||||
@@ -94,7 +95,7 @@ pub(crate) fn unused_mut(ctx: &DiagnosticsContext<'_>, d: &hir::UnusedMut) -> Op
|
||||
"variable does not need to be mutable",
|
||||
ast,
|
||||
)
|
||||
.experimental() // Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive.
|
||||
// Not supporting `#[allow(unused_mut)]` in proc macros leads to false positive, hence not stable.
|
||||
.with_fixes(fixes),
|
||||
)
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user