diff options
82 files changed, 1745 insertions, 694 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml index 889ada401..ece1fd364 100644 --- a/.github/workflows/release.yaml +++ b/.github/workflows/release.yaml | |||
@@ -15,8 +15,8 @@ env: | |||
15 | RUSTUP_MAX_RETRIES: 10 | 15 | RUSTUP_MAX_RETRIES: 10 |
16 | 16 | ||
17 | jobs: | 17 | jobs: |
18 | dist-windows: | 18 | dist-x86_64-pc-windows-msvc: |
19 | name: dist (Windows) | 19 | name: dist (x86_64-pc-windows-msvc) |
20 | runs-on: windows-latest | 20 | runs-on: windows-latest |
21 | env: | 21 | env: |
22 | RA_TARGET: x86_64-pc-windows-msvc | 22 | RA_TARGET: x86_64-pc-windows-msvc |
@@ -45,11 +45,41 @@ jobs: | |||
45 | - name: Upload artifacts | 45 | - name: Upload artifacts |
46 | uses: actions/upload-artifact@v1 | 46 | uses: actions/upload-artifact@v1 |
47 | with: | 47 | with: |
48 | name: dist-windows-latest | 48 | name: dist-x86_64-pc-windows-msvc |
49 | path: ./dist | 49 | path: ./dist |
50 | 50 | ||
51 | dist-ubuntu: | 51 | dist-aarch64-pc-windows-msvc: |
52 | name: dist (Ubuntu 16.04) | 52 | name: dist (aarch64-pc-windows-msvc) |
53 | runs-on: windows-latest | ||
54 | env: | ||
55 | RA_TARGET: aarch64-pc-windows-msvc | ||
56 | |||
57 | steps: | ||
58 | - name: Checkout repository | ||
59 | uses: actions/checkout@v2 | ||
60 | |||
61 | - name: Rename existing rust toolchain | ||
62 | run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old | ||
63 | |||
64 | - name: Install Rust toolchain | ||
65 | uses: actions-rs/toolchain@v1 | ||
66 | with: | ||
67 | toolchain: stable | ||
68 | target: aarch64-pc-windows-msvc | ||
69 | profile: minimal | ||
70 | override: true | ||
71 | |||
72 | - name: Dist | ||
73 | run: cargo xtask dist | ||
74 | |||
75 | - name: Upload artifacts | ||
76 | uses: actions/upload-artifact@v1 | ||
77 | with: | ||
78 | name: dist-aarch64-pc-windows-msvc | ||
79 | path: ./dist | ||
80 | |||
81 | dist-x86_64-unknown-linux-gnu: | ||
82 | name: dist (x86_64-unknown-linux-gnu) | ||
53 | runs-on: ubuntu-16.04 | 83 | runs-on: ubuntu-16.04 |
54 | env: | 84 | env: |
55 | RA_TARGET: x86_64-unknown-linux-gnu | 85 | RA_TARGET: x86_64-unknown-linux-gnu |
@@ -85,11 +115,11 @@ jobs: | |||
85 | - name: Upload artifacts | 115 | - name: Upload artifacts |
86 | uses: actions/upload-artifact@v1 | 116 | uses: actions/upload-artifact@v1 |
87 | with: | 117 | with: |
88 | name: dist-ubuntu-16.04 | 118 | name: dist-x86_64-unknown-linux-gnu |
89 | path: ./dist | 119 | path: ./dist |
90 | 120 | ||
91 | dist-macos-latest: | 121 | dist-x86_64-apple-darwin: |
92 | name: dist (MacOS latest) | 122 | name: dist (x86_64-apple-darwin) |
93 | runs-on: macos-latest | 123 | runs-on: macos-latest |
94 | env: | 124 | env: |
95 | RA_TARGET: x86_64-apple-darwin | 125 | RA_TARGET: x86_64-apple-darwin |
@@ -111,12 +141,12 @@ jobs: | |||
111 | - name: Upload artifacts | 141 | - name: Upload artifacts |
112 | uses: actions/upload-artifact@v1 | 142 | uses: actions/upload-artifact@v1 |
113 | with: | 143 | with: |
114 | name: dist-macos-latest | 144 | name: dist-x86_64-apple-darwin |
115 | path: ./dist | 145 | path: ./dist |
116 | 146 | ||
117 | dist-macos-11: | 147 | dist-aarch64-apple-darwin: |
118 | name: dist (MacOS 11.0) | 148 | name: dist (aarch64-apple-darwin) |
119 | runs-on: macos-11.0 | 149 | runs-on: macos-latest |
120 | env: | 150 | env: |
121 | RA_TARGET: aarch64-apple-darwin | 151 | RA_TARGET: aarch64-apple-darwin |
122 | 152 | ||
@@ -133,18 +163,18 @@ jobs: | |||
133 | override: true | 163 | override: true |
134 | 164 | ||
135 | - name: Dist | 165 | - name: Dist |
136 | run: cargo xtask dist | 166 | run: SDKROOT=$(xcrun -sdk macosx11.0 --show-sdk-path) MACOSX_DEPLOYMENT_TARGET=$(xcrun -sdk macosx11.0 --show-sdk-platform-version) cargo xtask dist |
137 | 167 | ||
138 | - name: Upload artifacts | 168 | - name: Upload artifacts |
139 | uses: actions/upload-artifact@v1 | 169 | uses: actions/upload-artifact@v1 |
140 | with: | 170 | with: |
141 | name: dist-macos-11.0 | 171 | name: dist-aarch64-apple-darwin |
142 | path: ./dist | 172 | path: ./dist |
143 | 173 | ||
144 | publish: | 174 | publish: |
145 | name: publish | 175 | name: publish |
146 | runs-on: ubuntu-16.04 | 176 | runs-on: ubuntu-16.04 |
147 | needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11'] | 177 | needs: ['dist-x86_64-pc-windows-msvc', 'dist-aarch64-pc-windows-msvc', 'dist-x86_64-unknown-linux-gnu', 'dist-x86_64-apple-darwin', 'dist-aarch64-apple-darwin'] |
148 | steps: | 178 | steps: |
149 | - name: Install Nodejs | 179 | - name: Install Nodejs |
150 | uses: actions/setup-node@v1 | 180 | uses: actions/setup-node@v1 |
@@ -165,19 +195,23 @@ jobs: | |||
165 | 195 | ||
166 | - uses: actions/download-artifact@v1 | 196 | - uses: actions/download-artifact@v1 |
167 | with: | 197 | with: |
168 | name: dist-macos-11.0 | 198 | name: dist-aarch64-apple-darwin |
199 | path: dist | ||
200 | - uses: actions/download-artifact@v1 | ||
201 | with: | ||
202 | name: dist-x86_64-apple-darwin | ||
169 | path: dist | 203 | path: dist |
170 | - uses: actions/download-artifact@v1 | 204 | - uses: actions/download-artifact@v1 |
171 | with: | 205 | with: |
172 | name: dist-macos-latest | 206 | name: dist-x86_64-unknown-linux-gnu |
173 | path: dist | 207 | path: dist |
174 | - uses: actions/download-artifact@v1 | 208 | - uses: actions/download-artifact@v1 |
175 | with: | 209 | with: |
176 | name: dist-ubuntu-16.04 | 210 | name: dist-x86_64-pc-windows-msvc |
177 | path: dist | 211 | path: dist |
178 | - uses: actions/download-artifact@v1 | 212 | - uses: actions/download-artifact@v1 |
179 | with: | 213 | with: |
180 | name: dist-windows-latest | 214 | name: dist-aarch64-pc-windows-msvc |
181 | path: dist | 215 | path: dist |
182 | - run: ls -al ./dist | 216 | - run: ls -al ./dist |
183 | 217 | ||
diff --git a/Cargo.lock b/Cargo.lock index 4aaee3ab1..fe45f9dec 100644 --- a/Cargo.lock +++ b/Cargo.lock | |||
@@ -2,9 +2,9 @@ | |||
2 | # It is not intended for manual editing. | 2 | # It is not intended for manual editing. |
3 | [[package]] | 3 | [[package]] |
4 | name = "addr2line" | 4 | name = "addr2line" |
5 | version = "0.14.0" | 5 | version = "0.14.1" |
6 | source = "registry+https://github.com/rust-lang/crates.io-index" | 6 | source = "registry+https://github.com/rust-lang/crates.io-index" |
7 | checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423" | 7 | checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" |
8 | dependencies = [ | 8 | dependencies = [ |
9 | "gimli", | 9 | "gimli", |
10 | ] | 10 | ] |
@@ -132,7 +132,7 @@ version = "0.12.0" | |||
132 | source = "registry+https://github.com/rust-lang/crates.io-index" | 132 | source = "registry+https://github.com/rust-lang/crates.io-index" |
133 | checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" | 133 | checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345" |
134 | dependencies = [ | 134 | dependencies = [ |
135 | "semver 0.11.0", | 135 | "semver", |
136 | "serde", | 136 | "serde", |
137 | "serde_json", | 137 | "serde_json", |
138 | ] | 138 | ] |
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" | |||
168 | 168 | ||
169 | [[package]] | 169 | [[package]] |
170 | name = "chalk-derive" | 170 | name = "chalk-derive" |
171 | version = "0.45.0" | 171 | version = "0.47.0" |
172 | source = "registry+https://github.com/rust-lang/crates.io-index" | 172 | source = "registry+https://github.com/rust-lang/crates.io-index" |
173 | checksum = "ec7dacf94958d1a930b95d049d9443860859af59eadc77849392093eb577bcee" | 173 | checksum = "3f00f6342a387edc822002d36a381e117afcac9f744951ff75fbf4a218edea5c" |
174 | dependencies = [ | 174 | dependencies = [ |
175 | "proc-macro2", | 175 | "proc-macro2", |
176 | "quote", | 176 | "quote", |
@@ -180,9 +180,9 @@ dependencies = [ | |||
180 | 180 | ||
181 | [[package]] | 181 | [[package]] |
182 | name = "chalk-ir" | 182 | name = "chalk-ir" |
183 | version = "0.45.0" | 183 | version = "0.47.0" |
184 | source = "registry+https://github.com/rust-lang/crates.io-index" | 184 | source = "registry+https://github.com/rust-lang/crates.io-index" |
185 | checksum = "a1a5b38ede247def17da87f4badb62396a5753db6048e2011d3089d8b3796c67" | 185 | checksum = "c686e69913591ae753e5526e73cbee39db3d9b0a92cc9078ab780cabf1c70aa9" |
186 | dependencies = [ | 186 | dependencies = [ |
187 | "bitflags", | 187 | "bitflags", |
188 | "chalk-derive", | 188 | "chalk-derive", |
@@ -191,9 +191,9 @@ dependencies = [ | |||
191 | 191 | ||
192 | [[package]] | 192 | [[package]] |
193 | name = "chalk-recursive" | 193 | name = "chalk-recursive" |
194 | version = "0.45.0" | 194 | version = "0.47.0" |
195 | source = "registry+https://github.com/rust-lang/crates.io-index" | 195 | source = "registry+https://github.com/rust-lang/crates.io-index" |
196 | checksum = "7a18db146d7a023edc20ad094e8c2284451f7888719645004979617d1f17c041" | 196 | checksum = "310fdcac0340dab4163b766baa8067266e3b909108d1ac1b5246c033bde63975" |
197 | dependencies = [ | 197 | dependencies = [ |
198 | "chalk-derive", | 198 | "chalk-derive", |
199 | "chalk-ir", | 199 | "chalk-ir", |
@@ -204,9 +204,9 @@ dependencies = [ | |||
204 | 204 | ||
205 | [[package]] | 205 | [[package]] |
206 | name = "chalk-solve" | 206 | name = "chalk-solve" |
207 | version = "0.45.0" | 207 | version = "0.47.0" |
208 | source = "registry+https://github.com/rust-lang/crates.io-index" | 208 | source = "registry+https://github.com/rust-lang/crates.io-index" |
209 | checksum = "7f73e0de04a0f394e47ed8118e00541bcf681d7c3c2ef500fa743eb4cf3a4850" | 209 | checksum = "c3c3252116111c3548f1164ab8d98c67c49848b3bde10dd11b650fd023e91c72" |
210 | dependencies = [ | 210 | dependencies = [ |
211 | "chalk-derive", | 211 | "chalk-derive", |
212 | "chalk-ir", | 212 | "chalk-ir", |
@@ -488,19 +488,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
488 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" | 488 | checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" |
489 | 489 | ||
490 | [[package]] | 490 | [[package]] |
491 | name = "generator" | ||
492 | version = "0.6.23" | ||
493 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
494 | checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc" | ||
495 | dependencies = [ | ||
496 | "cc", | ||
497 | "libc", | ||
498 | "log", | ||
499 | "rustc_version", | ||
500 | "winapi 0.3.9", | ||
501 | ] | ||
502 | |||
503 | [[package]] | ||
504 | name = "gimli" | 491 | name = "gimli" |
505 | version = "0.23.0" | 492 | version = "0.23.0" |
506 | source = "registry+https://github.com/rust-lang/crates.io-index" | 493 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -834,19 +821,6 @@ dependencies = [ | |||
834 | ] | 821 | ] |
835 | 822 | ||
836 | [[package]] | 823 | [[package]] |
837 | name = "loom" | ||
838 | version = "0.3.6" | ||
839 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
840 | checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed" | ||
841 | dependencies = [ | ||
842 | "cfg-if 0.1.10", | ||
843 | "generator", | ||
844 | "scoped-tls", | ||
845 | "serde", | ||
846 | "serde_json", | ||
847 | ] | ||
848 | |||
849 | [[package]] | ||
850 | name = "lsp-server" | 824 | name = "lsp-server" |
851 | version = "0.5.0" | 825 | version = "0.5.0" |
852 | source = "registry+https://github.com/rust-lang/crates.io-index" | 826 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1394,9 +1368,9 @@ dependencies = [ | |||
1394 | 1368 | ||
1395 | [[package]] | 1369 | [[package]] |
1396 | name = "rustc-ap-rustc_lexer" | 1370 | name = "rustc-ap-rustc_lexer" |
1397 | version = "695.0.0" | 1371 | version = "697.0.0" |
1398 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1372 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1399 | checksum = "390bad134705b0bff02cd9541ac66df751a91c3cc734c3369cd6151ca269caed" | 1373 | checksum = "67adbe260a0a11910624d6d28c0304fcf7b063e666682111005c83b09f73429d" |
1400 | dependencies = [ | 1374 | dependencies = [ |
1401 | "unicode-xid", | 1375 | "unicode-xid", |
1402 | ] | 1376 | ] |
@@ -1414,15 +1388,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index" | |||
1414 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" | 1388 | checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" |
1415 | 1389 | ||
1416 | [[package]] | 1390 | [[package]] |
1417 | name = "rustc_version" | ||
1418 | version = "0.2.3" | ||
1419 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1420 | checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" | ||
1421 | dependencies = [ | ||
1422 | "semver 0.9.0", | ||
1423 | ] | ||
1424 | |||
1425 | [[package]] | ||
1426 | name = "ryu" | 1391 | name = "ryu" |
1427 | version = "1.0.5" | 1392 | version = "1.0.5" |
1428 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1393 | source = "registry+https://github.com/rust-lang/crates.io-index" |
@@ -1480,31 +1445,16 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" | |||
1480 | 1445 | ||
1481 | [[package]] | 1446 | [[package]] |
1482 | name = "semver" | 1447 | name = "semver" |
1483 | version = "0.9.0" | ||
1484 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1485 | checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" | ||
1486 | dependencies = [ | ||
1487 | "semver-parser 0.7.0", | ||
1488 | ] | ||
1489 | |||
1490 | [[package]] | ||
1491 | name = "semver" | ||
1492 | version = "0.11.0" | 1448 | version = "0.11.0" |
1493 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1449 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1494 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" | 1450 | checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6" |
1495 | dependencies = [ | 1451 | dependencies = [ |
1496 | "semver-parser 0.10.1", | 1452 | "semver-parser", |
1497 | "serde", | 1453 | "serde", |
1498 | ] | 1454 | ] |
1499 | 1455 | ||
1500 | [[package]] | 1456 | [[package]] |
1501 | name = "semver-parser" | 1457 | name = "semver-parser" |
1502 | version = "0.7.0" | ||
1503 | source = "registry+https://github.com/rust-lang/crates.io-index" | ||
1504 | checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" | ||
1505 | |||
1506 | [[package]] | ||
1507 | name = "semver-parser" | ||
1508 | version = "0.10.1" | 1458 | version = "0.10.1" |
1509 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1459 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1510 | checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" | 1460 | checksum = "42ef146c2ad5e5f4b037cd6ce2ebb775401729b19a82040c1beac9d36c7d1428" |
@@ -1566,12 +1516,11 @@ dependencies = [ | |||
1566 | 1516 | ||
1567 | [[package]] | 1517 | [[package]] |
1568 | name = "sharded-slab" | 1518 | name = "sharded-slab" |
1569 | version = "0.1.0" | 1519 | version = "0.1.1" |
1570 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1520 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1571 | checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127" | 1521 | checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3" |
1572 | dependencies = [ | 1522 | dependencies = [ |
1573 | "lazy_static", | 1523 | "lazy_static", |
1574 | "loom", | ||
1575 | ] | 1524 | ] |
1576 | 1525 | ||
1577 | [[package]] | 1526 | [[package]] |
@@ -1582,9 +1531,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" | |||
1582 | 1531 | ||
1583 | [[package]] | 1532 | [[package]] |
1584 | name = "smallvec" | 1533 | name = "smallvec" |
1585 | version = "1.5.1" | 1534 | version = "1.6.0" |
1586 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1535 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1587 | checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75" | 1536 | checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0" |
1588 | 1537 | ||
1589 | [[package]] | 1538 | [[package]] |
1590 | name = "smol_str" | 1539 | name = "smol_str" |
@@ -1615,9 +1564,9 @@ version = "0.0.0" | |||
1615 | 1564 | ||
1616 | [[package]] | 1565 | [[package]] |
1617 | name = "syn" | 1566 | name = "syn" |
1618 | version = "1.0.56" | 1567 | version = "1.0.57" |
1619 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1620 | checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72" | 1569 | checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6" |
1621 | dependencies = [ | 1570 | dependencies = [ |
1622 | "proc-macro2", | 1571 | "proc-macro2", |
1623 | "quote", | 1572 | "quote", |
@@ -1826,15 +1775,16 @@ dependencies = [ | |||
1826 | 1775 | ||
1827 | [[package]] | 1776 | [[package]] |
1828 | name = "tracing-tree" | 1777 | name = "tracing-tree" |
1829 | version = "0.1.6" | 1778 | version = "0.1.7" |
1830 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1831 | checksum = "43aac8afb493b08e1e1904956f7407c1e671b9c83b26a17e1bd83d6a3520e350" | 1780 | checksum = "023e80cdb7c8468b7aade1d756afa2acbe2ae0a6142a25ec664b5239d6ef2794" |
1832 | dependencies = [ | 1781 | dependencies = [ |
1833 | "ansi_term", | 1782 | "ansi_term", |
1834 | "atty", | 1783 | "atty", |
1835 | "chrono", | 1784 | "chrono", |
1836 | "termcolor", | 1785 | "termcolor", |
1837 | "tracing", | 1786 | "tracing", |
1787 | "tracing-log", | ||
1838 | "tracing-subscriber", | 1788 | "tracing-subscriber", |
1839 | ] | 1789 | ] |
1840 | 1790 | ||
@@ -1854,9 +1804,9 @@ checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" | |||
1854 | 1804 | ||
1855 | [[package]] | 1805 | [[package]] |
1856 | name = "ungrammar" | 1806 | name = "ungrammar" |
1857 | version = "1.5.0" | 1807 | version = "1.6.0" |
1858 | source = "registry+https://github.com/rust-lang/crates.io-index" | 1808 | source = "registry+https://github.com/rust-lang/crates.io-index" |
1859 | checksum = "c11bffada52edc8f2a56160b286ea4640acf90ffcb21bded361ccb8ed43a1457" | 1809 | checksum = "f96cc1b6938f7c548fbcc630bac5c896ae77a130909829ab18b8eab78c51b7ee" |
1860 | 1810 | ||
1861 | [[package]] | 1811 | [[package]] |
1862 | name = "unicase" | 1812 | name = "unicase" |
diff --git a/crates/assists/src/handlers/early_return.rs b/crates/assists/src/handlers/early_return.rs index 7bcc318a9..2c48f32bf 100644 --- a/crates/assists/src/handlers/early_return.rs +++ b/crates/assists/src/handlers/early_return.rs | |||
@@ -69,7 +69,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext) | |||
69 | 69 | ||
70 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; | 70 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; |
71 | 71 | ||
72 | if parent_block.expr()? != if_expr.clone().into() { | 72 | if parent_block.tail_expr()? != if_expr.clone().into() { |
73 | return None; | 73 | return None; |
74 | } | 74 | } |
75 | 75 | ||
diff --git a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs index 030b9cd0c..6f35a061c 100644 --- a/crates/assists/src/handlers/extract_struct_from_enum_variant.rs +++ b/crates/assists/src/handlers/extract_struct_from_enum_variant.rs | |||
@@ -117,10 +117,14 @@ fn existing_definition(db: &RootDatabase, variant_name: &ast::Name, variant: &Va | |||
117 | .into_iter() | 117 | .into_iter() |
118 | .filter(|(_, def)| match def { | 118 | .filter(|(_, def)| match def { |
119 | // only check type-namespace | 119 | // only check type-namespace |
120 | hir::ScopeDef::ModuleDef(def) => matches!(def, | 120 | hir::ScopeDef::ModuleDef(def) => matches!( |
121 | ModuleDef::Module(_) | ModuleDef::Adt(_) | | 121 | def, |
122 | ModuleDef::Variant(_) | ModuleDef::Trait(_) | | 122 | ModuleDef::Module(_) |
123 | ModuleDef::TypeAlias(_) | ModuleDef::BuiltinType(_) | 123 | | ModuleDef::Adt(_) |
124 | | ModuleDef::Variant(_) | ||
125 | | ModuleDef::Trait(_) | ||
126 | | ModuleDef::TypeAlias(_) | ||
127 | | ModuleDef::BuiltinType(_) | ||
124 | ), | 128 | ), |
125 | _ => false, | 129 | _ => false, |
126 | }) | 130 | }) |
diff --git a/crates/assists/src/handlers/extract_variable.rs b/crates/assists/src/handlers/extract_variable.rs index 9957012fe..291809205 100644 --- a/crates/assists/src/handlers/extract_variable.rs +++ b/crates/assists/src/handlers/extract_variable.rs | |||
@@ -139,7 +139,7 @@ impl Anchor { | |||
139 | fn from(to_extract: &ast::Expr) -> Option<Anchor> { | 139 | fn from(to_extract: &ast::Expr) -> Option<Anchor> { |
140 | to_extract.syntax().ancestors().find_map(|node| { | 140 | to_extract.syntax().ancestors().find_map(|node| { |
141 | if let Some(expr) = | 141 | if let Some(expr) = |
142 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) | 142 | node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.tail_expr()) |
143 | { | 143 | { |
144 | if expr.syntax() == &node { | 144 | if expr.syntax() == &node { |
145 | mark::hit!(test_extract_var_last_expr); | 145 | mark::hit!(test_extract_var_last_expr); |
diff --git a/crates/assists/src/handlers/infer_function_return_type.rs b/crates/assists/src/handlers/infer_function_return_type.rs index aa584eb03..f499cdfdc 100644 --- a/crates/assists/src/handlers/infer_function_return_type.rs +++ b/crates/assists/src/handlers/infer_function_return_type.rs | |||
@@ -89,7 +89,7 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla | |||
89 | let body = closure.body()?; | 89 | let body = closure.body()?; |
90 | let body_start = body.syntax().first_token()?.text_range().start(); | 90 | let body_start = body.syntax().first_token()?.text_range().start(); |
91 | let (tail_expr, wrap_expr) = match body { | 91 | let (tail_expr, wrap_expr) = match body { |
92 | ast::Expr::BlockExpr(block) => (block.expr()?, false), | 92 | ast::Expr::BlockExpr(block) => (block.tail_expr()?, false), |
93 | body => (body, true), | 93 | body => (body, true), |
94 | }; | 94 | }; |
95 | 95 | ||
@@ -101,7 +101,7 @@ fn extract_tail(ctx: &AssistContext) -> Option<(FnType, ast::Expr, InsertOrRepla | |||
101 | let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; | 101 | let action = ret_ty_to_action(func.ret_type(), rparen_pos)?; |
102 | 102 | ||
103 | let body = func.body()?; | 103 | let body = func.body()?; |
104 | let tail_expr = body.expr()?; | 104 | let tail_expr = body.tail_expr()?; |
105 | 105 | ||
106 | let ret_range_end = body.l_curly_token()?.text_range().start(); | 106 | let ret_range_end = body.l_curly_token()?.text_range().start(); |
107 | let ret_range = TextRange::new(rparen_pos, ret_range_end); | 107 | let ret_range = TextRange::new(rparen_pos, ret_range_end); |
diff --git a/crates/assists/src/handlers/inline_function.rs b/crates/assists/src/handlers/inline_function.rs new file mode 100644 index 000000000..6e351bdcd --- /dev/null +++ b/crates/assists/src/handlers/inline_function.rs | |||
@@ -0,0 +1,202 @@ | |||
1 | use ast::make; | ||
2 | use hir::{HasSource, PathResolution}; | ||
3 | use syntax::{ | ||
4 | ast::{self, edit::AstNodeEdit, ArgListOwner}, | ||
5 | AstNode, | ||
6 | }; | ||
7 | use test_utils::mark; | ||
8 | |||
9 | use crate::{ | ||
10 | assist_context::{AssistContext, Assists}, | ||
11 | AssistId, AssistKind, | ||
12 | }; | ||
13 | |||
14 | // Assist: inline_function | ||
15 | // | ||
16 | // Inlines a function body. | ||
17 | // | ||
18 | // ``` | ||
19 | // fn add(a: u32, b: u32) -> u32 { a + b } | ||
20 | // fn main() { | ||
21 | // let x = add<|>(1, 2); | ||
22 | // } | ||
23 | // ``` | ||
24 | // -> | ||
25 | // ``` | ||
26 | // fn add(a: u32, b: u32) -> u32 { a + b } | ||
27 | // fn main() { | ||
28 | // let x = { | ||
29 | // let a = 1; | ||
30 | // let b = 2; | ||
31 | // a + b | ||
32 | // }; | ||
33 | // } | ||
34 | // ``` | ||
35 | pub(crate) fn inline_function(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
36 | let path_expr: ast::PathExpr = ctx.find_node_at_offset()?; | ||
37 | let call = path_expr.syntax().parent().and_then(ast::CallExpr::cast)?; | ||
38 | let path = path_expr.path()?; | ||
39 | |||
40 | let function = match ctx.sema.resolve_path(&path)? { | ||
41 | PathResolution::Def(hir::ModuleDef::Function(f)) => f, | ||
42 | _ => return None, | ||
43 | }; | ||
44 | |||
45 | let function_source = function.source(ctx.db())?; | ||
46 | let arguments: Vec<_> = call.arg_list()?.args().collect(); | ||
47 | let parameters = function_parameter_patterns(&function_source.value)?; | ||
48 | |||
49 | if arguments.len() != parameters.len() { | ||
50 | // Can't inline the function because they've passed the wrong number of | ||
51 | // arguments to this function | ||
52 | mark::hit!(inline_function_incorrect_number_of_arguments); | ||
53 | return None; | ||
54 | } | ||
55 | |||
56 | let new_bindings = parameters.into_iter().zip(arguments); | ||
57 | |||
58 | let body = function_source.value.body()?; | ||
59 | |||
60 | acc.add( | ||
61 | AssistId("inline_function", AssistKind::RefactorInline), | ||
62 | format!("Inline `{}`", path), | ||
63 | call.syntax().text_range(), | ||
64 | |builder| { | ||
65 | let mut statements: Vec<ast::Stmt> = Vec::new(); | ||
66 | |||
67 | for (pattern, value) in new_bindings { | ||
68 | statements.push(make::let_stmt(pattern, Some(value)).into()); | ||
69 | } | ||
70 | |||
71 | statements.extend(body.statements()); | ||
72 | |||
73 | let original_indentation = call.indent_level(); | ||
74 | let replacement = make::block_expr(statements, body.tail_expr()) | ||
75 | .reset_indent() | ||
76 | .indent(original_indentation); | ||
77 | |||
78 | builder.replace_ast(ast::Expr::CallExpr(call), ast::Expr::BlockExpr(replacement)); | ||
79 | }, | ||
80 | ) | ||
81 | } | ||
82 | |||
83 | fn function_parameter_patterns(value: &ast::Fn) -> Option<Vec<ast::Pat>> { | ||
84 | let mut patterns = Vec::new(); | ||
85 | |||
86 | for param in value.param_list()?.params() { | ||
87 | let pattern = param.pat()?; | ||
88 | patterns.push(pattern); | ||
89 | } | ||
90 | |||
91 | Some(patterns) | ||
92 | } | ||
93 | |||
94 | #[cfg(test)] | ||
95 | mod tests { | ||
96 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
97 | |||
98 | use super::*; | ||
99 | |||
100 | #[test] | ||
101 | fn no_args_or_return_value_gets_inlined_without_block() { | ||
102 | check_assist( | ||
103 | inline_function, | ||
104 | r#" | ||
105 | fn foo() { println!("Hello, World!"); } | ||
106 | fn main() { | ||
107 | fo<|>o(); | ||
108 | } | ||
109 | "#, | ||
110 | r#" | ||
111 | fn foo() { println!("Hello, World!"); } | ||
112 | fn main() { | ||
113 | { | ||
114 | println!("Hello, World!"); | ||
115 | }; | ||
116 | } | ||
117 | "#, | ||
118 | ); | ||
119 | } | ||
120 | |||
121 | #[test] | ||
122 | fn args_with_side_effects() { | ||
123 | check_assist( | ||
124 | inline_function, | ||
125 | r#" | ||
126 | fn foo(name: String) { println!("Hello, {}!", name); } | ||
127 | fn main() { | ||
128 | foo<|>(String::from("Michael")); | ||
129 | } | ||
130 | "#, | ||
131 | r#" | ||
132 | fn foo(name: String) { println!("Hello, {}!", name); } | ||
133 | fn main() { | ||
134 | { | ||
135 | let name = String::from("Michael"); | ||
136 | println!("Hello, {}!", name); | ||
137 | }; | ||
138 | } | ||
139 | "#, | ||
140 | ); | ||
141 | } | ||
142 | |||
143 | #[test] | ||
144 | fn method_inlining_isnt_supported() { | ||
145 | check_assist_not_applicable( | ||
146 | inline_function, | ||
147 | r" | ||
148 | struct Foo; | ||
149 | impl Foo { fn bar(&self) {} } | ||
150 | |||
151 | fn main() { Foo.bar<|>(); } | ||
152 | ", | ||
153 | ); | ||
154 | } | ||
155 | |||
156 | #[test] | ||
157 | fn not_applicable_when_incorrect_number_of_parameters_are_provided() { | ||
158 | mark::check!(inline_function_incorrect_number_of_arguments); | ||
159 | check_assist_not_applicable( | ||
160 | inline_function, | ||
161 | r#" | ||
162 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
163 | fn main() { let x = add<|>(42); } | ||
164 | "#, | ||
165 | ); | ||
166 | } | ||
167 | |||
168 | #[test] | ||
169 | fn function_with_multiple_statements() { | ||
170 | check_assist( | ||
171 | inline_function, | ||
172 | r#" | ||
173 | fn foo(a: u32, b: u32) -> u32 { | ||
174 | let x = a + b; | ||
175 | let y = x - b; | ||
176 | x * y | ||
177 | } | ||
178 | |||
179 | fn main() { | ||
180 | let x = foo<|>(1, 2); | ||
181 | } | ||
182 | "#, | ||
183 | r#" | ||
184 | fn foo(a: u32, b: u32) -> u32 { | ||
185 | let x = a + b; | ||
186 | let y = x - b; | ||
187 | x * y | ||
188 | } | ||
189 | |||
190 | fn main() { | ||
191 | let x = { | ||
192 | let a = 1; | ||
193 | let b = 2; | ||
194 | let x = a + b; | ||
195 | let y = x - b; | ||
196 | x * y | ||
197 | }; | ||
198 | } | ||
199 | "#, | ||
200 | ); | ||
201 | } | ||
202 | } | ||
diff --git a/crates/assists/src/handlers/move_guard.rs b/crates/assists/src/handlers/move_guard.rs index eaffd80ce..4318ca6dc 100644 --- a/crates/assists/src/handlers/move_guard.rs +++ b/crates/assists/src/handlers/move_guard.rs | |||
@@ -98,7 +98,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
98 | let mut replace_node = None; | 98 | let mut replace_node = None; |
99 | let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { | 99 | let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone()).or_else(|| { |
100 | let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; | 100 | let block_expr = BlockExpr::cast(arm_body.syntax().clone())?; |
101 | if let Expr::IfExpr(e) = block_expr.expr()? { | 101 | if let Expr::IfExpr(e) = block_expr.tail_expr()? { |
102 | replace_node = Some(block_expr.syntax().clone()); | 102 | replace_node = Some(block_expr.syntax().clone()); |
103 | Some(e) | 103 | Some(e) |
104 | } else { | 104 | } else { |
@@ -128,7 +128,7 @@ pub(crate) fn move_arm_cond_to_match_guard(acc: &mut Assists, ctx: &AssistContex | |||
128 | |edit| { | 128 | |edit| { |
129 | let then_only_expr = then_block.statements().next().is_none(); | 129 | let then_only_expr = then_block.statements().next().is_none(); |
130 | 130 | ||
131 | match &then_block.expr() { | 131 | match &then_block.tail_expr() { |
132 | Some(then_expr) if then_only_expr => { | 132 | Some(then_expr) if then_only_expr => { |
133 | edit.replace(replace_node.text_range(), then_expr.syntax().text()) | 133 | edit.replace(replace_node.text_range(), then_expr.syntax().text()) |
134 | } | 134 | } |
diff --git a/crates/assists/src/handlers/extract_assignment.rs b/crates/assists/src/handlers/pull_assignment_up.rs index 281cf5d24..63b662fad 100644 --- a/crates/assists/src/handlers/extract_assignment.rs +++ b/crates/assists/src/handlers/pull_assignment_up.rs | |||
@@ -1,4 +1,3 @@ | |||
1 | use hir::AsName; | ||
2 | use syntax::{ | 1 | use syntax::{ |
3 | ast::{self, edit::AstNodeEdit, make}, | 2 | ast::{self, edit::AstNodeEdit, make}, |
4 | AstNode, | 3 | AstNode, |
@@ -10,9 +9,9 @@ use crate::{ | |||
10 | AssistId, AssistKind, | 9 | AssistId, AssistKind, |
11 | }; | 10 | }; |
12 | 11 | ||
13 | // Assist: extract_assignment | 12 | // Assist: pull_assignment_up |
14 | // | 13 | // |
15 | // Extracts variable assigment to outside an if or match statement. | 14 | // Extracts variable assignment to outside an if or match statement. |
16 | // | 15 | // |
17 | // ``` | 16 | // ``` |
18 | // fn main() { | 17 | // fn main() { |
@@ -37,16 +36,24 @@ use crate::{ | |||
37 | // }; | 36 | // }; |
38 | // } | 37 | // } |
39 | // ``` | 38 | // ``` |
40 | pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 39 | pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
41 | let name = ctx.find_node_at_offset::<ast::NameRef>()?.as_name(); | 40 | let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?; |
41 | let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment { | ||
42 | assign_expr.lhs()? | ||
43 | } else { | ||
44 | return None; | ||
45 | }; | ||
42 | 46 | ||
43 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { | 47 | let (old_stmt, new_stmt) = if let Some(if_expr) = ctx.find_node_at_offset::<ast::IfExpr>() { |
44 | ( | 48 | ( |
45 | ast::Expr::cast(if_expr.syntax().to_owned())?, | 49 | ast::Expr::cast(if_expr.syntax().to_owned())?, |
46 | exprify_if(&if_expr, &name)?.indent(if_expr.indent_level()), | 50 | exprify_if(&if_expr, &ctx.sema, &name_expr)?.indent(if_expr.indent_level()), |
47 | ) | 51 | ) |
48 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { | 52 | } else if let Some(match_expr) = ctx.find_node_at_offset::<ast::MatchExpr>() { |
49 | (ast::Expr::cast(match_expr.syntax().to_owned())?, exprify_match(&match_expr, &name)?) | 53 | ( |
54 | ast::Expr::cast(match_expr.syntax().to_owned())?, | ||
55 | exprify_match(&match_expr, &ctx.sema, &name_expr)?, | ||
56 | ) | ||
50 | } else { | 57 | } else { |
51 | return None; | 58 | return None; |
52 | }; | 59 | }; |
@@ -54,22 +61,26 @@ pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Optio | |||
54 | let expr_stmt = make::expr_stmt(new_stmt); | 61 | let expr_stmt = make::expr_stmt(new_stmt); |
55 | 62 | ||
56 | acc.add( | 63 | acc.add( |
57 | AssistId("extract_assignment", AssistKind::RefactorExtract), | 64 | AssistId("pull_assignment_up", AssistKind::RefactorExtract), |
58 | "Extract assignment", | 65 | "Pull assignment up", |
59 | old_stmt.syntax().text_range(), | 66 | old_stmt.syntax().text_range(), |
60 | move |edit| { | 67 | move |edit| { |
61 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name, expr_stmt)); | 68 | edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt)); |
62 | }, | 69 | }, |
63 | ) | 70 | ) |
64 | } | 71 | } |
65 | 72 | ||
66 | fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::Expr> { | 73 | fn exprify_match( |
74 | match_expr: &ast::MatchExpr, | ||
75 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
76 | name: &ast::Expr, | ||
77 | ) -> Option<ast::Expr> { | ||
67 | let new_arm_list = match_expr | 78 | let new_arm_list = match_expr |
68 | .match_arm_list()? | 79 | .match_arm_list()? |
69 | .arms() | 80 | .arms() |
70 | .map(|arm| { | 81 | .map(|arm| { |
71 | if let ast::Expr::BlockExpr(block) = arm.expr()? { | 82 | if let ast::Expr::BlockExpr(block) = arm.expr()? { |
72 | let new_block = exprify_block(&block, name)?.indent(block.indent_level()); | 83 | let new_block = exprify_block(&block, sema, name)?.indent(block.indent_level()); |
73 | Some(arm.replace_descendant(block, new_block)) | 84 | Some(arm.replace_descendant(block, new_block)) |
74 | } else { | 85 | } else { |
75 | None | 86 | None |
@@ -82,22 +93,32 @@ fn exprify_match(match_expr: &ast::MatchExpr, name: &hir::Name) -> Option<ast::E | |||
82 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) | 93 | Some(make::expr_match(match_expr.expr()?, new_arm_list)) |
83 | } | 94 | } |
84 | 95 | ||
85 | fn exprify_if(statement: &ast::IfExpr, name: &hir::Name) -> Option<ast::Expr> { | 96 | fn exprify_if( |
86 | let then_branch = exprify_block(&statement.then_branch()?, name)?; | 97 | statement: &ast::IfExpr, |
98 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
99 | name: &ast::Expr, | ||
100 | ) -> Option<ast::Expr> { | ||
101 | let then_branch = exprify_block(&statement.then_branch()?, sema, name)?; | ||
87 | let else_branch = match statement.else_branch()? { | 102 | let else_branch = match statement.else_branch()? { |
88 | ast::ElseBranch::Block(ref block) => ast::ElseBranch::Block(exprify_block(block, name)?), | 103 | ast::ElseBranch::Block(ref block) => { |
104 | ast::ElseBranch::Block(exprify_block(block, sema, name)?) | ||
105 | } | ||
89 | ast::ElseBranch::IfExpr(expr) => { | 106 | ast::ElseBranch::IfExpr(expr) => { |
90 | mark::hit!(test_extract_assigment_chained_if); | 107 | mark::hit!(test_pull_assignment_up_chained_if); |
91 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( | 108 | ast::ElseBranch::IfExpr(ast::IfExpr::cast( |
92 | exprify_if(&expr, name)?.syntax().to_owned(), | 109 | exprify_if(&expr, sema, name)?.syntax().to_owned(), |
93 | )?) | 110 | )?) |
94 | } | 111 | } |
95 | }; | 112 | }; |
96 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) | 113 | Some(make::expr_if(statement.condition()?, then_branch, Some(else_branch))) |
97 | } | 114 | } |
98 | 115 | ||
99 | fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockExpr> { | 116 | fn exprify_block( |
100 | if block.expr().is_some() { | 117 | block: &ast::BlockExpr, |
118 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
119 | name: &ast::Expr, | ||
120 | ) -> Option<ast::BlockExpr> { | ||
121 | if block.tail_expr().is_some() { | ||
101 | return None; | 122 | return None; |
102 | } | 123 | } |
103 | 124 | ||
@@ -106,8 +127,7 @@ fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockE | |||
106 | 127 | ||
107 | if let ast::Stmt::ExprStmt(stmt) = stmt { | 128 | if let ast::Stmt::ExprStmt(stmt) = stmt { |
108 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { | 129 | if let ast::Expr::BinExpr(expr) = stmt.expr()? { |
109 | if expr.op_kind()? == ast::BinOp::Assignment | 130 | if expr.op_kind()? == ast::BinOp::Assignment && is_equivalent(sema, &expr.lhs()?, name) |
110 | && &expr.lhs()?.name_ref()?.as_name() == name | ||
111 | { | 131 | { |
112 | // The last statement in the block is an assignment to the name we want | 132 | // The last statement in the block is an assignment to the name we want |
113 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); | 133 | return Some(make::block_expr(stmts, Some(expr.rhs()?))); |
@@ -117,6 +137,29 @@ fn exprify_block(block: &ast::BlockExpr, name: &hir::Name) -> Option<ast::BlockE | |||
117 | None | 137 | None |
118 | } | 138 | } |
119 | 139 | ||
140 | fn is_equivalent( | ||
141 | sema: &hir::Semantics<ide_db::RootDatabase>, | ||
142 | expr0: &ast::Expr, | ||
143 | expr1: &ast::Expr, | ||
144 | ) -> bool { | ||
145 | match (expr0, expr1) { | ||
146 | (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => { | ||
147 | mark::hit!(test_pull_assignment_up_field_assignment); | ||
148 | sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1) | ||
149 | } | ||
150 | (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => { | ||
151 | let path0 = path0.path(); | ||
152 | let path1 = path1.path(); | ||
153 | if let (Some(path0), Some(path1)) = (path0, path1) { | ||
154 | sema.resolve_path(&path0) == sema.resolve_path(&path1) | ||
155 | } else { | ||
156 | false | ||
157 | } | ||
158 | } | ||
159 | _ => false, | ||
160 | } | ||
161 | } | ||
162 | |||
120 | #[cfg(test)] | 163 | #[cfg(test)] |
121 | mod tests { | 164 | mod tests { |
122 | use super::*; | 165 | use super::*; |
@@ -124,9 +167,9 @@ mod tests { | |||
124 | use crate::tests::{check_assist, check_assist_not_applicable}; | 167 | use crate::tests::{check_assist, check_assist_not_applicable}; |
125 | 168 | ||
126 | #[test] | 169 | #[test] |
127 | fn test_extract_assignment_if() { | 170 | fn test_pull_assignment_up_if() { |
128 | check_assist( | 171 | check_assist( |
129 | extract_assigment, | 172 | pull_assignment_up, |
130 | r#" | 173 | r#" |
131 | fn foo() { | 174 | fn foo() { |
132 | let mut a = 1; | 175 | let mut a = 1; |
@@ -151,9 +194,9 @@ fn foo() { | |||
151 | } | 194 | } |
152 | 195 | ||
153 | #[test] | 196 | #[test] |
154 | fn test_extract_assignment_match() { | 197 | fn test_pull_assignment_up_match() { |
155 | check_assist( | 198 | check_assist( |
156 | extract_assigment, | 199 | pull_assignment_up, |
157 | r#" | 200 | r#" |
158 | fn foo() { | 201 | fn foo() { |
159 | let mut a = 1; | 202 | let mut a = 1; |
@@ -190,9 +233,9 @@ fn foo() { | |||
190 | } | 233 | } |
191 | 234 | ||
192 | #[test] | 235 | #[test] |
193 | fn test_extract_assignment_not_last_not_applicable() { | 236 | fn test_pull_assignment_up_not_last_not_applicable() { |
194 | check_assist_not_applicable( | 237 | check_assist_not_applicable( |
195 | extract_assigment, | 238 | pull_assignment_up, |
196 | r#" | 239 | r#" |
197 | fn foo() { | 240 | fn foo() { |
198 | let mut a = 1; | 241 | let mut a = 1; |
@@ -208,10 +251,10 @@ fn foo() { | |||
208 | } | 251 | } |
209 | 252 | ||
210 | #[test] | 253 | #[test] |
211 | fn test_extract_assignment_chained_if() { | 254 | fn test_pull_assignment_up_chained_if() { |
212 | mark::check!(test_extract_assigment_chained_if); | 255 | mark::check!(test_pull_assignment_up_chained_if); |
213 | check_assist( | 256 | check_assist( |
214 | extract_assigment, | 257 | pull_assignment_up, |
215 | r#" | 258 | r#" |
216 | fn foo() { | 259 | fn foo() { |
217 | let mut a = 1; | 260 | let mut a = 1; |
@@ -240,9 +283,9 @@ fn foo() { | |||
240 | } | 283 | } |
241 | 284 | ||
242 | #[test] | 285 | #[test] |
243 | fn test_extract_assigment_retains_stmts() { | 286 | fn test_pull_assignment_up_retains_stmts() { |
244 | check_assist( | 287 | check_assist( |
245 | extract_assigment, | 288 | pull_assignment_up, |
246 | r#" | 289 | r#" |
247 | fn foo() { | 290 | fn foo() { |
248 | let mut a = 1; | 291 | let mut a = 1; |
@@ -271,9 +314,9 @@ fn foo() { | |||
271 | } | 314 | } |
272 | 315 | ||
273 | #[test] | 316 | #[test] |
274 | fn extract_assignment_let_stmt_not_applicable() { | 317 | fn pull_assignment_up_let_stmt_not_applicable() { |
275 | check_assist_not_applicable( | 318 | check_assist_not_applicable( |
276 | extract_assigment, | 319 | pull_assignment_up, |
277 | r#" | 320 | r#" |
278 | fn foo() { | 321 | fn foo() { |
279 | let mut a = 1; | 322 | let mut a = 1; |
@@ -288,9 +331,9 @@ fn foo() { | |||
288 | } | 331 | } |
289 | 332 | ||
290 | #[test] | 333 | #[test] |
291 | fn extract_assignment_if_missing_assigment_not_applicable() { | 334 | fn pull_assignment_up_if_missing_assigment_not_applicable() { |
292 | check_assist_not_applicable( | 335 | check_assist_not_applicable( |
293 | extract_assigment, | 336 | pull_assignment_up, |
294 | r#" | 337 | r#" |
295 | fn foo() { | 338 | fn foo() { |
296 | let mut a = 1; | 339 | let mut a = 1; |
@@ -303,9 +346,9 @@ fn foo() { | |||
303 | } | 346 | } |
304 | 347 | ||
305 | #[test] | 348 | #[test] |
306 | fn extract_assignment_match_missing_assigment_not_applicable() { | 349 | fn pull_assignment_up_match_missing_assigment_not_applicable() { |
307 | check_assist_not_applicable( | 350 | check_assist_not_applicable( |
308 | extract_assigment, | 351 | pull_assignment_up, |
309 | r#" | 352 | r#" |
310 | fn foo() { | 353 | fn foo() { |
311 | let mut a = 1; | 354 | let mut a = 1; |
@@ -322,4 +365,36 @@ fn foo() { | |||
322 | }"#, | 365 | }"#, |
323 | ) | 366 | ) |
324 | } | 367 | } |
368 | |||
369 | #[test] | ||
370 | fn test_pull_assignment_up_field_assignment() { | ||
371 | mark::check!(test_pull_assignment_up_field_assignment); | ||
372 | check_assist( | ||
373 | pull_assignment_up, | ||
374 | r#" | ||
375 | struct A(usize); | ||
376 | |||
377 | fn foo() { | ||
378 | let mut a = A(1); | ||
379 | |||
380 | if true { | ||
381 | <|>a.0 = 2; | ||
382 | } else { | ||
383 | a.0 = 3; | ||
384 | } | ||
385 | }"#, | ||
386 | r#" | ||
387 | struct A(usize); | ||
388 | |||
389 | fn foo() { | ||
390 | let mut a = A(1); | ||
391 | |||
392 | a.0 = if true { | ||
393 | 2 | ||
394 | } else { | ||
395 | 3 | ||
396 | }; | ||
397 | }"#, | ||
398 | ) | ||
399 | } | ||
325 | } | 400 | } |
diff --git a/crates/assists/src/handlers/replace_if_let_with_match.rs b/crates/assists/src/handlers/replace_if_let_with_match.rs index 4a355c66f..b67219222 100644 --- a/crates/assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -138,7 +138,7 @@ pub(crate) fn replace_match_with_if_let(acc: &mut Assists, ctx: &AssistContext) | |||
138 | }; | 138 | }; |
139 | let else_expr = match else_expr { | 139 | let else_expr = match else_expr { |
140 | ast::Expr::BlockExpr(block) | 140 | ast::Expr::BlockExpr(block) |
141 | if block.statements().count() == 0 && block.expr().is_none() => | 141 | if block.statements().count() == 0 && block.tail_expr().is_none() => |
142 | { | 142 | { |
143 | None | 143 | None |
144 | } | 144 | } |
diff --git a/crates/assists/src/handlers/wrap_return_type_in_result.rs b/crates/assists/src/handlers/wrap_return_type_in_result.rs index 59e5debb1..358b61046 100644 --- a/crates/assists/src/handlers/wrap_return_type_in_result.rs +++ b/crates/assists/src/handlers/wrap_return_type_in_result.rs | |||
@@ -98,7 +98,7 @@ impl TailReturnCollector { | |||
98 | } | 98 | } |
99 | 99 | ||
100 | // Browse tail expressions for each block | 100 | // Browse tail expressions for each block |
101 | if let Some(expr) = block_expr.expr() { | 101 | if let Some(expr) = block_expr.tail_expr() { |
102 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { | 102 | if let Some(last_exprs) = get_tail_expr_from_block(&expr) { |
103 | for last_expr in last_exprs { | 103 | for last_expr in last_exprs { |
104 | let last_expr = match last_expr { | 104 | let last_expr = match last_expr { |
@@ -170,7 +170,7 @@ impl TailReturnCollector { | |||
170 | } | 170 | } |
171 | 171 | ||
172 | fn collect_tail_exprs(&mut self, block: &BlockExpr) { | 172 | fn collect_tail_exprs(&mut self, block: &BlockExpr) { |
173 | if let Some(expr) = block.expr() { | 173 | if let Some(expr) = block.tail_expr() { |
174 | self.handle_exprs(&expr, true); | 174 | self.handle_exprs(&expr, true); |
175 | self.fetch_tail_exprs(&expr); | 175 | self.fetch_tail_exprs(&expr); |
176 | } | 176 | } |
@@ -206,7 +206,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
206 | Expr::IfExpr(if_expr) => { | 206 | Expr::IfExpr(if_expr) => { |
207 | let mut nodes = vec![]; | 207 | let mut nodes = vec![]; |
208 | for block in if_expr.blocks() { | 208 | for block in if_expr.blocks() { |
209 | if let Some(block_expr) = block.expr() { | 209 | if let Some(block_expr) = block.tail_expr() { |
210 | if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) { | 210 | if let Some(tail_exprs) = get_tail_expr_from_block(&block_expr) { |
211 | nodes.extend(tail_exprs); | 211 | nodes.extend(tail_exprs); |
212 | } | 212 | } |
@@ -228,7 +228,7 @@ fn get_tail_expr_from_block(expr: &Expr) -> Option<Vec<NodeType>> { | |||
228 | while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) | 228 | while_expr.syntax().last_child().map(|lc| vec![NodeType::Node(lc)]) |
229 | } | 229 | } |
230 | Expr::BlockExpr(block_expr) => { | 230 | Expr::BlockExpr(block_expr) => { |
231 | block_expr.expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())]) | 231 | block_expr.tail_expr().map(|lc| vec![NodeType::Node(lc.syntax().clone())]) |
232 | } | 232 | } |
233 | Expr::MatchExpr(match_expr) => { | 233 | Expr::MatchExpr(match_expr) => { |
234 | let arm_list = match_expr.match_arm_list()?; | 234 | let arm_list = match_expr.match_arm_list()?; |
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs index 212464f85..9c2a95735 100644 --- a/crates/assists/src/lib.rs +++ b/crates/assists/src/lib.rs | |||
@@ -116,7 +116,6 @@ mod handlers { | |||
116 | mod convert_integer_literal; | 116 | mod convert_integer_literal; |
117 | mod early_return; | 117 | mod early_return; |
118 | mod expand_glob_import; | 118 | mod expand_glob_import; |
119 | mod extract_assignment; | ||
120 | mod extract_module_to_file; | 119 | mod extract_module_to_file; |
121 | mod extract_struct_from_enum_variant; | 120 | mod extract_struct_from_enum_variant; |
122 | mod extract_variable; | 121 | mod extract_variable; |
@@ -125,13 +124,14 @@ mod handlers { | |||
125 | mod flip_binexpr; | 124 | mod flip_binexpr; |
126 | mod flip_comma; | 125 | mod flip_comma; |
127 | mod flip_trait_bound; | 126 | mod flip_trait_bound; |
128 | mod generate_derive; | ||
129 | mod generate_default_from_enum_variant; | 127 | mod generate_default_from_enum_variant; |
128 | mod generate_derive; | ||
130 | mod generate_from_impl_for_enum; | 129 | mod generate_from_impl_for_enum; |
131 | mod generate_function; | 130 | mod generate_function; |
132 | mod generate_impl; | 131 | mod generate_impl; |
133 | mod generate_new; | 132 | mod generate_new; |
134 | mod infer_function_return_type; | 133 | mod infer_function_return_type; |
134 | mod inline_function; | ||
135 | mod inline_local_variable; | 135 | mod inline_local_variable; |
136 | mod introduce_named_lifetime; | 136 | mod introduce_named_lifetime; |
137 | mod invert_if; | 137 | mod invert_if; |
@@ -139,6 +139,7 @@ mod handlers { | |||
139 | mod merge_match_arms; | 139 | mod merge_match_arms; |
140 | mod move_bounds; | 140 | mod move_bounds; |
141 | mod move_guard; | 141 | mod move_guard; |
142 | mod pull_assignment_up; | ||
142 | mod qualify_path; | 143 | mod qualify_path; |
143 | mod raw_string; | 144 | mod raw_string; |
144 | mod remove_dbg; | 145 | mod remove_dbg; |
@@ -168,7 +169,6 @@ mod handlers { | |||
168 | convert_integer_literal::convert_integer_literal, | 169 | convert_integer_literal::convert_integer_literal, |
169 | early_return::convert_to_guarded_return, | 170 | early_return::convert_to_guarded_return, |
170 | expand_glob_import::expand_glob_import, | 171 | expand_glob_import::expand_glob_import, |
171 | extract_assignment::extract_assigment, | ||
172 | extract_module_to_file::extract_module_to_file, | 172 | extract_module_to_file::extract_module_to_file, |
173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, | 173 | extract_struct_from_enum_variant::extract_struct_from_enum_variant, |
174 | extract_variable::extract_variable, | 174 | extract_variable::extract_variable, |
@@ -177,13 +177,14 @@ mod handlers { | |||
177 | flip_binexpr::flip_binexpr, | 177 | flip_binexpr::flip_binexpr, |
178 | flip_comma::flip_comma, | 178 | flip_comma::flip_comma, |
179 | flip_trait_bound::flip_trait_bound, | 179 | flip_trait_bound::flip_trait_bound, |
180 | generate_derive::generate_derive, | ||
181 | generate_default_from_enum_variant::generate_default_from_enum_variant, | 180 | generate_default_from_enum_variant::generate_default_from_enum_variant, |
181 | generate_derive::generate_derive, | ||
182 | generate_from_impl_for_enum::generate_from_impl_for_enum, | 182 | generate_from_impl_for_enum::generate_from_impl_for_enum, |
183 | generate_function::generate_function, | 183 | generate_function::generate_function, |
184 | generate_impl::generate_impl, | 184 | generate_impl::generate_impl, |
185 | generate_new::generate_new, | 185 | generate_new::generate_new, |
186 | infer_function_return_type::infer_function_return_type, | 186 | infer_function_return_type::infer_function_return_type, |
187 | inline_function::inline_function, | ||
187 | inline_local_variable::inline_local_variable, | 188 | inline_local_variable::inline_local_variable, |
188 | introduce_named_lifetime::introduce_named_lifetime, | 189 | introduce_named_lifetime::introduce_named_lifetime, |
189 | invert_if::invert_if, | 190 | invert_if::invert_if, |
@@ -192,6 +193,7 @@ mod handlers { | |||
192 | move_bounds::move_bounds_to_where_clause, | 193 | move_bounds::move_bounds_to_where_clause, |
193 | move_guard::move_arm_cond_to_match_guard, | 194 | move_guard::move_arm_cond_to_match_guard, |
194 | move_guard::move_guard_to_arm_body, | 195 | move_guard::move_guard_to_arm_body, |
196 | pull_assignment_up::pull_assignment_up, | ||
195 | qualify_path::qualify_path, | 197 | qualify_path::qualify_path, |
196 | raw_string::add_hash, | 198 | raw_string::add_hash, |
197 | raw_string::make_usual_string, | 199 | raw_string::make_usual_string, |
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs index b91a816e8..b15352cf3 100644 --- a/crates/assists/src/tests/generated.rs +++ b/crates/assists/src/tests/generated.rs | |||
@@ -238,35 +238,6 @@ fn qux(bar: Bar, baz: Baz) {} | |||
238 | } | 238 | } |
239 | 239 | ||
240 | #[test] | 240 | #[test] |
241 | fn doctest_extract_assignment() { | ||
242 | check_doc_test( | ||
243 | "extract_assignment", | ||
244 | r#####" | ||
245 | fn main() { | ||
246 | let mut foo = 6; | ||
247 | |||
248 | if true { | ||
249 | <|>foo = 5; | ||
250 | } else { | ||
251 | foo = 4; | ||
252 | } | ||
253 | } | ||
254 | "#####, | ||
255 | r#####" | ||
256 | fn main() { | ||
257 | let mut foo = 6; | ||
258 | |||
259 | foo = if true { | ||
260 | 5 | ||
261 | } else { | ||
262 | 4 | ||
263 | }; | ||
264 | } | ||
265 | "#####, | ||
266 | ) | ||
267 | } | ||
268 | |||
269 | #[test] | ||
270 | fn doctest_extract_module_to_file() { | 241 | fn doctest_extract_module_to_file() { |
271 | check_doc_test( | 242 | check_doc_test( |
272 | "extract_module_to_file", | 243 | "extract_module_to_file", |
@@ -560,6 +531,29 @@ fn foo() -> i32 { 42i32 } | |||
560 | } | 531 | } |
561 | 532 | ||
562 | #[test] | 533 | #[test] |
534 | fn doctest_inline_function() { | ||
535 | check_doc_test( | ||
536 | "inline_function", | ||
537 | r#####" | ||
538 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
539 | fn main() { | ||
540 | let x = add<|>(1, 2); | ||
541 | } | ||
542 | "#####, | ||
543 | r#####" | ||
544 | fn add(a: u32, b: u32) -> u32 { a + b } | ||
545 | fn main() { | ||
546 | let x = { | ||
547 | let a = 1; | ||
548 | let b = 2; | ||
549 | a + b | ||
550 | }; | ||
551 | } | ||
552 | "#####, | ||
553 | ) | ||
554 | } | ||
555 | |||
556 | #[test] | ||
563 | fn doctest_inline_local_variable() { | 557 | fn doctest_inline_local_variable() { |
564 | check_doc_test( | 558 | check_doc_test( |
565 | "inline_local_variable", | 559 | "inline_local_variable", |
@@ -767,6 +761,35 @@ fn handle(action: Action) { | |||
767 | } | 761 | } |
768 | 762 | ||
769 | #[test] | 763 | #[test] |
764 | fn doctest_pull_assignment_up() { | ||
765 | check_doc_test( | ||
766 | "pull_assignment_up", | ||
767 | r#####" | ||
768 | fn main() { | ||
769 | let mut foo = 6; | ||
770 | |||
771 | if true { | ||
772 | <|>foo = 5; | ||
773 | } else { | ||
774 | foo = 4; | ||
775 | } | ||
776 | } | ||
777 | "#####, | ||
778 | r#####" | ||
779 | fn main() { | ||
780 | let mut foo = 6; | ||
781 | |||
782 | foo = if true { | ||
783 | 5 | ||
784 | } else { | ||
785 | 4 | ||
786 | }; | ||
787 | } | ||
788 | "#####, | ||
789 | ) | ||
790 | } | ||
791 | |||
792 | #[test] | ||
770 | fn doctest_qualify_path() { | 793 | fn doctest_qualify_path() { |
771 | check_doc_test( | 794 | check_doc_test( |
772 | "qualify_path", | 795 | "qualify_path", |
diff --git a/crates/assists/src/utils.rs b/crates/assists/src/utils.rs index b05596446..8212cd129 100644 --- a/crates/assists/src/utils.rs +++ b/crates/assists/src/utils.rs | |||
@@ -37,7 +37,7 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | |||
37 | non_trivial_children.next().is_some() | 37 | non_trivial_children.next().is_some() |
38 | }; | 38 | }; |
39 | 39 | ||
40 | if let Some(expr) = block.expr() { | 40 | if let Some(expr) = block.tail_expr() { |
41 | if has_anything_else(expr.syntax()) { | 41 | if has_anything_else(expr.syntax()) { |
42 | return None; | 42 | return None; |
43 | } | 43 | } |
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs index 81a6d00e2..2f41a3f96 100644 --- a/crates/completion/src/completions/unqualified_path.rs +++ b/crates/completion/src/completions/unqualified_path.rs | |||
@@ -124,8 +124,8 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T | |||
124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding | 124 | // Note that having this flag set to `true` does not guarantee that the feature is enabled: your client needs to have the corredponding |
125 | // capability enabled. | 125 | // capability enabled. |
126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { | 126 | fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()> { |
127 | let _p = profile::span("fuzzy_completion"); | ||
128 | let potential_import_name = ctx.token.to_string(); | 127 | let potential_import_name = ctx.token.to_string(); |
128 | let _p = profile::span("fuzzy_completion").detail(|| potential_import_name.clone()); | ||
129 | 129 | ||
130 | if potential_import_name.len() < 2 { | 130 | if potential_import_name.len() < 2 { |
131 | return None; | 131 | return None; |
@@ -142,6 +142,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<() | |||
142 | Some(40), | 142 | Some(40), |
143 | potential_import_name, | 143 | potential_import_name, |
144 | true, | 144 | true, |
145 | true, | ||
145 | ) | 146 | ) |
146 | .filter_map(|import_candidate| { | 147 | .filter_map(|import_candidate| { |
147 | Some(match import_candidate { | 148 | Some(match import_candidate { |
diff --git a/crates/completion/src/context.rs b/crates/completion/src/context.rs index 41de324d8..f979697ab 100644 --- a/crates/completion/src/context.rs +++ b/crates/completion/src/context.rs | |||
@@ -458,7 +458,7 @@ impl<'a> CompletionContext<'a> { | |||
458 | } | 458 | } |
459 | if let Some(block) = ast::BlockExpr::cast(node) { | 459 | if let Some(block) = ast::BlockExpr::cast(node) { |
460 | return Some( | 460 | return Some( |
461 | block.expr().map(|e| e.syntax().text_range()) | 461 | block.tail_expr().map(|e| e.syntax().text_range()) |
462 | == Some(name_ref.syntax().text_range()), | 462 | == Some(name_ref.syntax().text_range()), |
463 | ); | 463 | ); |
464 | } | 464 | } |
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs index 62eccf475..cc1938333 100644 --- a/crates/hir/src/code_model.rs +++ b/crates/hir/src/code_model.rs | |||
@@ -5,9 +5,7 @@ use arrayvec::ArrayVec; | |||
5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; | 5 | use base_db::{CrateDisplayName, CrateId, Edition, FileId}; |
6 | use either::Either; | 6 | use either::Either; |
7 | use hir_def::{ | 7 | use hir_def::{ |
8 | adt::ReprKind, | 8 | adt::{ReprKind, StructKind, VariantData}, |
9 | adt::StructKind, | ||
10 | adt::VariantData, | ||
11 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
12 | expr::{BindingAnnotation, LabelId, Pat, PatId}, | 10 | expr::{BindingAnnotation, LabelId, Pat, PatId}, |
13 | import_map, | 11 | import_map, |
@@ -31,7 +29,7 @@ use hir_expand::{ | |||
31 | }; | 29 | }; |
32 | use hir_ty::{ | 30 | use hir_ty::{ |
33 | autoderef, | 31 | autoderef, |
34 | display::{HirDisplayError, HirFormatter}, | 32 | display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter}, |
35 | method_resolution, | 33 | method_resolution, |
36 | traits::{FnTrait, Solution, SolutionVariables}, | 34 | traits::{FnTrait, Solution, SolutionVariables}, |
37 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, | 35 | ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, |
@@ -745,6 +743,18 @@ impl Function { | |||
745 | db.function_data(self.id).name.clone() | 743 | db.function_data(self.id).name.clone() |
746 | } | 744 | } |
747 | 745 | ||
746 | /// Get this function's return type | ||
747 | pub fn ret_type(self, db: &dyn HirDatabase) -> Type { | ||
748 | let resolver = self.id.resolver(db.upcast()); | ||
749 | let ret_type = &db.function_data(self.id).ret_type; | ||
750 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | ||
751 | let environment = TraitEnvironment::lower(db, &resolver); | ||
752 | Type { | ||
753 | krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate, | ||
754 | ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment }, | ||
755 | } | ||
756 | } | ||
757 | |||
748 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { | 758 | pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { |
749 | if !db.function_data(self.id).has_self_param { | 759 | if !db.function_data(self.id).has_self_param { |
750 | return None; | 760 | return None; |
@@ -1278,6 +1288,18 @@ impl TypeParam { | |||
1278 | } | 1288 | } |
1279 | } | 1289 | } |
1280 | 1290 | ||
1291 | pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> { | ||
1292 | db.generic_predicates_for_param(self.id) | ||
1293 | .into_iter() | ||
1294 | .filter_map(|pred| match &pred.value { | ||
1295 | hir_ty::GenericPredicate::Implemented(trait_ref) => { | ||
1296 | Some(Trait::from(trait_ref.trait_)) | ||
1297 | } | ||
1298 | _ => None, | ||
1299 | }) | ||
1300 | .collect() | ||
1301 | } | ||
1302 | |||
1281 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { | 1303 | pub fn default(self, db: &dyn HirDatabase) -> Option<Type> { |
1282 | let params = db.generic_defaults(self.id.parent); | 1304 | let params = db.generic_defaults(self.id.parent); |
1283 | let local_idx = hir_ty::param_idx(db, self.id)?; | 1305 | let local_idx = hir_ty::param_idx(db, self.id)?; |
@@ -1293,6 +1315,20 @@ impl TypeParam { | |||
1293 | } | 1315 | } |
1294 | } | 1316 | } |
1295 | 1317 | ||
1318 | impl HirDisplay for TypeParam { | ||
1319 | fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { | ||
1320 | write!(f, "{}", self.name(f.db))?; | ||
1321 | let bounds = f.db.generic_predicates_for_param(self.id); | ||
1322 | let substs = Substs::type_params(f.db, self.id.parent); | ||
1323 | let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); | ||
1324 | if !(predicates.is_empty() || f.omit_verbose_types()) { | ||
1325 | write!(f, ": ")?; | ||
1326 | write_bounds_like_dyn_trait(&predicates, f)?; | ||
1327 | } | ||
1328 | Ok(()) | ||
1329 | } | ||
1330 | } | ||
1331 | |||
1296 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] | 1332 | #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] |
1297 | pub struct LifetimeParam { | 1333 | pub struct LifetimeParam { |
1298 | pub(crate) id: LifetimeParamId, | 1334 | pub(crate) id: LifetimeParamId, |
@@ -1331,6 +1367,12 @@ impl ConstParam { | |||
1331 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { | 1367 | pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef { |
1332 | self.id.parent.into() | 1368 | self.id.parent.into() |
1333 | } | 1369 | } |
1370 | |||
1371 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
1372 | let def = self.id.parent; | ||
1373 | let krate = def.module(db.upcast()).krate; | ||
1374 | Type::new(db, krate, def, db.const_param_ty(self.id)) | ||
1375 | } | ||
1334 | } | 1376 | } |
1335 | 1377 | ||
1336 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 1378 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
@@ -1600,9 +1642,10 @@ impl Type { | |||
1600 | } | 1642 | } |
1601 | 1643 | ||
1602 | pub fn is_fn(&self) -> bool { | 1644 | pub fn is_fn(&self) -> bool { |
1603 | matches!(&self.ty.value, | 1645 | matches!( |
1604 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(..), .. }) | | 1646 | &self.ty.value, |
1605 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { .. }, .. }) | 1647 | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnDef(..), .. }) |
1648 | | Ty::Apply(ApplicationTy { ctor: TypeCtor::FnPtr { .. }, .. }) | ||
1606 | ) | 1649 | ) |
1607 | } | 1650 | } |
1608 | 1651 | ||
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs index 6b79e7bad..9e6426b31 100644 --- a/crates/hir_def/src/attr.rs +++ b/crates/hir_def/src/attr.rs | |||
@@ -2,6 +2,7 @@ | |||
2 | 2 | ||
3 | use std::{ops, sync::Arc}; | 3 | use std::{ops, sync::Arc}; |
4 | 4 | ||
5 | use arena::map::ArenaMap; | ||
5 | use base_db::CrateId; | 6 | use base_db::CrateId; |
6 | use cfg::{CfgExpr, CfgOptions}; | 7 | use cfg::{CfgExpr, CfgOptions}; |
7 | use either::Either; | 8 | use either::Either; |
@@ -21,7 +22,8 @@ use crate::{ | |||
21 | nameres::ModuleSource, | 22 | nameres::ModuleSource, |
22 | path::{ModPath, PathKind}, | 23 | path::{ModPath, PathKind}, |
23 | src::HasChildSource, | 24 | src::HasChildSource, |
24 | AdtId, AttrDefId, GenericParamId, Lookup, | 25 | AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, |
26 | VariantId, | ||
25 | }; | 27 | }; |
26 | 28 | ||
27 | /// Holds documentation | 29 | /// Holds documentation |
@@ -210,16 +212,10 @@ impl Attrs { | |||
210 | } | 212 | } |
211 | } | 213 | } |
212 | AttrDefId::FieldId(it) => { | 214 | AttrDefId::FieldId(it) => { |
213 | let src = it.parent.child_source(db); | 215 | return db.fields_attrs(it.parent)[it.local_id].clone(); |
214 | match &src.value[it.local_id] { | ||
215 | Either::Left(_tuple) => RawAttrs::default(), | ||
216 | Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)), | ||
217 | } | ||
218 | } | 216 | } |
219 | AttrDefId::EnumVariantId(var_id) => { | 217 | AttrDefId::EnumVariantId(it) => { |
220 | let src = var_id.parent.child_source(db); | 218 | return db.variants_attrs(it.parent)[it.local_id].clone(); |
221 | let src = src.as_ref().map(|it| &it[var_id.local_id]); | ||
222 | RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) | ||
223 | } | 219 | } |
224 | AttrDefId::AdtId(it) => match it { | 220 | AttrDefId::AdtId(it) => match it { |
225 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), | 221 | AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db), |
@@ -259,6 +255,46 @@ impl Attrs { | |||
259 | raw_attrs.filter(db, def.krate(db)) | 255 | raw_attrs.filter(db, def.krate(db)) |
260 | } | 256 | } |
261 | 257 | ||
258 | pub(crate) fn variants_attrs_query( | ||
259 | db: &dyn DefDatabase, | ||
260 | e: EnumId, | ||
261 | ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> { | ||
262 | let krate = e.lookup(db).container.module(db).krate; | ||
263 | let src = e.child_source(db); | ||
264 | let mut res = ArenaMap::default(); | ||
265 | |||
266 | for (id, var) in src.value.iter() { | ||
267 | let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn AttrsOwner)) | ||
268 | .filter(db, krate); | ||
269 | |||
270 | res.insert(id, attrs) | ||
271 | } | ||
272 | |||
273 | Arc::new(res) | ||
274 | } | ||
275 | |||
276 | pub(crate) fn fields_attrs_query( | ||
277 | db: &dyn DefDatabase, | ||
278 | v: VariantId, | ||
279 | ) -> Arc<ArenaMap<LocalFieldId, Attrs>> { | ||
280 | let krate = v.module(db).krate; | ||
281 | let src = v.child_source(db); | ||
282 | let mut res = ArenaMap::default(); | ||
283 | |||
284 | for (id, fld) in src.value.iter() { | ||
285 | let attrs = match fld { | ||
286 | Either::Left(_tuple) => Attrs::default(), | ||
287 | Either::Right(record) => { | ||
288 | RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate) | ||
289 | } | ||
290 | }; | ||
291 | |||
292 | res.insert(id, attrs); | ||
293 | } | ||
294 | |||
295 | Arc::new(res) | ||
296 | } | ||
297 | |||
262 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { | 298 | pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> { |
263 | AttrQuery { attrs: self, key } | 299 | AttrQuery { attrs: self, key } |
264 | } | 300 | } |
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 17c72779b..6be1eaade 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs | |||
@@ -695,7 +695,7 @@ impl ExprCollector<'_> { | |||
695 | self.collect_stmts_items(block.statements()); | 695 | self.collect_stmts_items(block.statements()); |
696 | let statements = | 696 | let statements = |
697 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); | 697 | block.statements().filter_map(|s| self.collect_stmt(s)).flatten().collect(); |
698 | let tail = block.expr().map(|e| self.collect_expr(e)); | 698 | let tail = block.tail_expr().map(|e| self.collect_expr(e)); |
699 | self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) | 699 | self.alloc_expr(Expr::Block { statements, tail, label: None }, syntax_node_ptr) |
700 | } | 700 | } |
701 | 701 | ||
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs index d1a459066..d3bf5b34c 100644 --- a/crates/hir_def/src/db.rs +++ b/crates/hir_def/src/db.rs | |||
@@ -1,6 +1,7 @@ | |||
1 | //! Defines database & queries for name resolution. | 1 | //! Defines database & queries for name resolution. |
2 | use std::sync::Arc; | 2 | use std::sync::Arc; |
3 | 3 | ||
4 | use arena::map::ArenaMap; | ||
4 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; | 5 | use base_db::{salsa, CrateId, SourceDatabase, Upcast}; |
5 | use hir_expand::{db::AstDatabase, HirFileId}; | 6 | use hir_expand::{db::AstDatabase, HirFileId}; |
6 | use syntax::SmolStr; | 7 | use syntax::SmolStr; |
@@ -16,8 +17,8 @@ use crate::{ | |||
16 | lang_item::{LangItemTarget, LangItems}, | 17 | lang_item::{LangItemTarget, LangItems}, |
17 | nameres::CrateDefMap, | 18 | nameres::CrateDefMap, |
18 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, | 19 | AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc, |
19 | GenericDefId, ImplId, ImplLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc, | 20 | GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId, |
20 | TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, | 21 | StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId, |
21 | }; | 22 | }; |
22 | 23 | ||
23 | #[salsa::query_group(InternDatabaseStorage)] | 24 | #[salsa::query_group(InternDatabaseStorage)] |
@@ -92,6 +93,12 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> { | |||
92 | #[salsa::invoke(GenericParams::generic_params_query)] | 93 | #[salsa::invoke(GenericParams::generic_params_query)] |
93 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; | 94 | fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; |
94 | 95 | ||
96 | #[salsa::invoke(Attrs::variants_attrs_query)] | ||
97 | fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; | ||
98 | |||
99 | #[salsa::invoke(Attrs::fields_attrs_query)] | ||
100 | fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; | ||
101 | |||
95 | #[salsa::invoke(Attrs::attrs_query)] | 102 | #[salsa::invoke(Attrs::attrs_query)] |
96 | fn attrs(&self, def: AttrDefId) -> Attrs; | 103 | fn attrs(&self, def: AttrDefId) -> Attrs; |
97 | 104 | ||
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs index c71266dc0..ab3f059ce 100644 --- a/crates/hir_def/src/diagnostics.rs +++ b/crates/hir_def/src/diagnostics.rs | |||
@@ -133,6 +133,10 @@ impl Diagnostic for InactiveCode { | |||
133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that | 133 | // This diagnostic is shown when a procedural macro can not be found. This usually means that |
134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), | 134 | // procedural macro support is simply disabled (and hence is only a weak hint instead of an error), |
135 | // but can also indicate project setup problems. | 135 | // but can also indicate project setup problems. |
136 | // | ||
137 | // If you are seeing a lot of "proc macro not expanded" warnings, you can add this option to the | ||
138 | // `rust-analyzer.diagnostics.disabled` list to prevent them from showing. Alternatively you can | ||
139 | // enable support for procedural macros (see `rust-analyzer.procMacro.enable`). | ||
136 | #[derive(Debug, Clone, Eq, PartialEq)] | 140 | #[derive(Debug, Clone, Eq, PartialEq)] |
137 | pub struct UnresolvedProcMacro { | 141 | pub struct UnresolvedProcMacro { |
138 | pub file: HirFileId, | 142 | pub file: HirFileId, |
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs index 30b22f51d..e5368b293 100644 --- a/crates/hir_def/src/import_map.rs +++ b/crates/hir_def/src/import_map.rs | |||
@@ -7,9 +7,8 @@ use fst::{self, Streamer}; | |||
7 | use hir_expand::name::Name; | 7 | use hir_expand::name::Name; |
8 | use indexmap::{map::Entry, IndexMap}; | 8 | use indexmap::{map::Entry, IndexMap}; |
9 | use itertools::Itertools; | 9 | use itertools::Itertools; |
10 | use rustc_hash::{FxHashMap, FxHashSet, FxHasher}; | 10 | use rustc_hash::{FxHashSet, FxHasher}; |
11 | use smallvec::SmallVec; | 11 | use test_utils::mark; |
12 | use syntax::SmolStr; | ||
13 | 12 | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, | 14 | db::DefDatabase, item_scope::ItemInNs, visibility::Visibility, AssocItemId, ModuleDefId, |
@@ -25,6 +24,8 @@ pub struct ImportInfo { | |||
25 | pub path: ImportPath, | 24 | pub path: ImportPath, |
26 | /// The module containing this item. | 25 | /// The module containing this item. |
27 | pub container: ModuleId, | 26 | pub container: ModuleId, |
27 | /// Whether the import is a trait associated item or not. | ||
28 | pub is_trait_assoc_item: bool, | ||
28 | } | 29 | } |
29 | 30 | ||
30 | #[derive(Debug, Clone, Eq, PartialEq)] | 31 | #[derive(Debug, Clone, Eq, PartialEq)] |
@@ -64,10 +65,6 @@ pub struct ImportMap { | |||
64 | /// the index of the first one. | 65 | /// the index of the first one. |
65 | importables: Vec<ItemInNs>, | 66 | importables: Vec<ItemInNs>, |
66 | fst: fst::Map<Vec<u8>>, | 67 | fst: fst::Map<Vec<u8>>, |
67 | |||
68 | /// Maps names of associated items to the item's ID. Only includes items whose defining trait is | ||
69 | /// exported. | ||
70 | assoc_map: FxHashMap<SmolStr, SmallVec<[AssocItemId; 1]>>, | ||
71 | } | 68 | } |
72 | 69 | ||
73 | impl ImportMap { | 70 | impl ImportMap { |
@@ -108,14 +105,27 @@ impl ImportMap { | |||
108 | 105 | ||
109 | for item in per_ns.iter_items() { | 106 | for item in per_ns.iter_items() { |
110 | let path = mk_path(); | 107 | let path = mk_path(); |
108 | let path_len = path.len(); | ||
109 | let import_info = | ||
110 | ImportInfo { path, container: module, is_trait_assoc_item: false }; | ||
111 | |||
112 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
113 | import_map.collect_trait_assoc_items( | ||
114 | db, | ||
115 | tr, | ||
116 | matches!(item, ItemInNs::Types(_)), | ||
117 | &import_info, | ||
118 | ); | ||
119 | } | ||
120 | |||
111 | match import_map.map.entry(item) { | 121 | match import_map.map.entry(item) { |
112 | Entry::Vacant(entry) => { | 122 | Entry::Vacant(entry) => { |
113 | entry.insert(ImportInfo { path, container: module }); | 123 | entry.insert(import_info); |
114 | } | 124 | } |
115 | Entry::Occupied(mut entry) => { | 125 | Entry::Occupied(mut entry) => { |
116 | // If the new path is shorter, prefer that one. | 126 | // If the new path is shorter, prefer that one. |
117 | if path.len() < entry.get().path.len() { | 127 | if path_len < entry.get().path.len() { |
118 | *entry.get_mut() = ImportInfo { path, container: module }; | 128 | *entry.get_mut() = import_info; |
119 | } else { | 129 | } else { |
120 | continue; | 130 | continue; |
121 | } | 131 | } |
@@ -128,11 +138,6 @@ impl ImportMap { | |||
128 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { | 138 | if let Some(ModuleDefId::ModuleId(mod_id)) = item.as_module_def_id() { |
129 | worklist.push((mod_id, mk_path())); | 139 | worklist.push((mod_id, mk_path())); |
130 | } | 140 | } |
131 | |||
132 | // If we've added a path to a trait, add the trait's methods to the method map. | ||
133 | if let Some(ModuleDefId::TraitId(tr)) = item.as_module_def_id() { | ||
134 | import_map.collect_trait_methods(db, tr); | ||
135 | } | ||
136 | } | 141 | } |
137 | } | 142 | } |
138 | } | 143 | } |
@@ -153,12 +158,10 @@ impl ImportMap { | |||
153 | } | 158 | } |
154 | } | 159 | } |
155 | 160 | ||
156 | let start = last_batch_start; | 161 | let key = fst_path(&importables[last_batch_start].1.path); |
157 | last_batch_start = idx + 1; | 162 | builder.insert(key, last_batch_start as u64).unwrap(); |
158 | |||
159 | let key = fst_path(&importables[start].1.path); | ||
160 | 163 | ||
161 | builder.insert(key, start as u64).unwrap(); | 164 | last_batch_start = idx + 1; |
162 | } | 165 | } |
163 | 166 | ||
164 | import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | 167 | import_map.fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); |
@@ -176,10 +179,34 @@ impl ImportMap { | |||
176 | self.map.get(&item) | 179 | self.map.get(&item) |
177 | } | 180 | } |
178 | 181 | ||
179 | fn collect_trait_methods(&mut self, db: &dyn DefDatabase, tr: TraitId) { | 182 | fn collect_trait_assoc_items( |
180 | let data = db.trait_data(tr); | 183 | &mut self, |
181 | for (name, item) in data.items.iter() { | 184 | db: &dyn DefDatabase, |
182 | self.assoc_map.entry(name.to_string().into()).or_default().push(*item); | 185 | tr: TraitId, |
186 | is_type_in_ns: bool, | ||
187 | original_import_info: &ImportInfo, | ||
188 | ) { | ||
189 | for (assoc_item_name, item) in &db.trait_data(tr).items { | ||
190 | let module_def_id = match item { | ||
191 | AssocItemId::FunctionId(f) => ModuleDefId::from(*f), | ||
192 | AssocItemId::ConstId(c) => ModuleDefId::from(*c), | ||
193 | // cannot use associated type aliases directly: need a `<Struct as Trait>::TypeAlias` | ||
194 | // qualifier, ergo no need to store it for imports in import_map | ||
195 | AssocItemId::TypeAliasId(_) => { | ||
196 | mark::hit!(type_aliases_ignored); | ||
197 | continue; | ||
198 | } | ||
199 | }; | ||
200 | let assoc_item = if is_type_in_ns { | ||
201 | ItemInNs::Types(module_def_id) | ||
202 | } else { | ||
203 | ItemInNs::Values(module_def_id) | ||
204 | }; | ||
205 | |||
206 | let mut assoc_item_info = original_import_info.clone(); | ||
207 | assoc_item_info.path.segments.push(assoc_item_name.to_owned()); | ||
208 | assoc_item_info.is_trait_assoc_item = true; | ||
209 | self.map.insert(assoc_item, assoc_item_info); | ||
183 | } | 210 | } |
184 | } | 211 | } |
185 | } | 212 | } |
@@ -302,38 +329,38 @@ impl Query { | |||
302 | self.exclude_import_kinds.insert(import_kind); | 329 | self.exclude_import_kinds.insert(import_kind); |
303 | self | 330 | self |
304 | } | 331 | } |
305 | } | ||
306 | 332 | ||
307 | fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool { | 333 | fn import_matches(&self, import: &ImportInfo, enforce_lowercase: bool) -> bool { |
308 | let mut input = if query.name_only { | 334 | let mut input = if import.is_trait_assoc_item || self.name_only { |
309 | input_path.segments.last().unwrap().to_string() | 335 | import.path.segments.last().unwrap().to_string() |
310 | } else { | 336 | } else { |
311 | input_path.to_string() | 337 | import.path.to_string() |
312 | }; | 338 | }; |
313 | if enforce_lowercase || !query.case_sensitive { | 339 | if enforce_lowercase || !self.case_sensitive { |
314 | input.make_ascii_lowercase(); | 340 | input.make_ascii_lowercase(); |
315 | } | 341 | } |
316 | 342 | ||
317 | let query_string = | 343 | let query_string = |
318 | if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased }; | 344 | if !enforce_lowercase && self.case_sensitive { &self.query } else { &self.lowercased }; |
319 | 345 | ||
320 | match query.search_mode { | 346 | match self.search_mode { |
321 | SearchMode::Equals => &input == query_string, | 347 | SearchMode::Equals => &input == query_string, |
322 | SearchMode::Contains => input.contains(query_string), | 348 | SearchMode::Contains => input.contains(query_string), |
323 | SearchMode::Fuzzy => { | 349 | SearchMode::Fuzzy => { |
324 | let mut unchecked_query_chars = query_string.chars(); | 350 | let mut unchecked_query_chars = query_string.chars(); |
325 | let mut mismatching_query_char = unchecked_query_chars.next(); | 351 | let mut mismatching_query_char = unchecked_query_chars.next(); |
326 | 352 | ||
327 | for input_char in input.chars() { | 353 | for input_char in input.chars() { |
328 | match mismatching_query_char { | 354 | match mismatching_query_char { |
329 | None => return true, | 355 | None => return true, |
330 | Some(matching_query_char) if matching_query_char == input_char => { | 356 | Some(matching_query_char) if matching_query_char == input_char => { |
331 | mismatching_query_char = unchecked_query_chars.next(); | 357 | mismatching_query_char = unchecked_query_chars.next(); |
358 | } | ||
359 | _ => (), | ||
332 | } | 360 | } |
333 | _ => (), | ||
334 | } | 361 | } |
362 | mismatching_query_char.is_none() | ||
335 | } | 363 | } |
336 | mismatching_query_char.is_none() | ||
337 | } | 364 | } |
338 | } | 365 | } |
339 | } | 366 | } |
@@ -366,13 +393,13 @@ pub fn search_dependencies<'a>( | |||
366 | let import_map = &import_maps[indexed_value.index]; | 393 | let import_map = &import_maps[indexed_value.index]; |
367 | let importables = &import_map.importables[indexed_value.value as usize..]; | 394 | let importables = &import_map.importables[indexed_value.value as usize..]; |
368 | 395 | ||
369 | // Path shared by the importable items in this group. | 396 | let common_importable_data = &import_map.map[&importables[0]]; |
370 | let common_importables_path = &import_map.map[&importables[0]].path; | 397 | if !query.import_matches(common_importable_data, true) { |
371 | if !contains_query(&query, common_importables_path, true) { | ||
372 | continue; | 398 | continue; |
373 | } | 399 | } |
374 | 400 | ||
375 | let common_importables_path_fst = fst_path(common_importables_path); | 401 | // Path shared by the importable items in this group. |
402 | let common_importables_path_fst = fst_path(&common_importable_data.path); | ||
376 | // Add the items from this `ModPath` group. Those are all subsequent items in | 403 | // Add the items from this `ModPath` group. Those are all subsequent items in |
377 | // `importables` whose paths match `path`. | 404 | // `importables` whose paths match `path`. |
378 | let iter = importables | 405 | let iter = importables |
@@ -387,7 +414,7 @@ pub fn search_dependencies<'a>( | |||
387 | }) | 414 | }) |
388 | .filter(|item| { | 415 | .filter(|item| { |
389 | !query.case_sensitive // we've already checked the common importables path case-insensitively | 416 | !query.case_sensitive // we've already checked the common importables path case-insensitively |
390 | || contains_query(&query, &import_map.map[item].path, false) | 417 | || query.import_matches(&import_map.map[item], false) |
391 | }); | 418 | }); |
392 | res.extend(iter); | 419 | res.extend(iter); |
393 | 420 | ||
@@ -398,19 +425,6 @@ pub fn search_dependencies<'a>( | |||
398 | } | 425 | } |
399 | } | 426 | } |
400 | 427 | ||
401 | // Add all exported associated items whose names match the query (exactly). | ||
402 | for map in &import_maps { | ||
403 | if let Some(v) = map.assoc_map.get(&*query.query) { | ||
404 | res.extend(v.iter().map(|&assoc| { | ||
405 | ItemInNs::Types(match assoc { | ||
406 | AssocItemId::FunctionId(it) => it.into(), | ||
407 | AssocItemId::ConstId(it) => it.into(), | ||
408 | AssocItemId::TypeAliasId(it) => it.into(), | ||
409 | }) | ||
410 | })); | ||
411 | } | ||
412 | } | ||
413 | |||
414 | res | 428 | res |
415 | } | 429 | } |
416 | 430 | ||
@@ -432,9 +446,9 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> { | |||
432 | mod tests { | 446 | mod tests { |
433 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; | 447 | use base_db::{fixture::WithFixture, SourceDatabase, Upcast}; |
434 | use expect_test::{expect, Expect}; | 448 | use expect_test::{expect, Expect}; |
435 | use stdx::format_to; | 449 | use test_utils::mark; |
436 | 450 | ||
437 | use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup}; | 451 | use crate::{test_db::TestDB, AssocContainerId, Lookup}; |
438 | 452 | ||
439 | use super::*; | 453 | use super::*; |
440 | 454 | ||
@@ -451,46 +465,66 @@ mod tests { | |||
451 | 465 | ||
452 | let actual = search_dependencies(db.upcast(), krate, query) | 466 | let actual = search_dependencies(db.upcast(), krate, query) |
453 | .into_iter() | 467 | .into_iter() |
454 | .filter_map(|item| { | 468 | .filter_map(|dependency| { |
455 | let mark = match item { | 469 | let dependency_krate = dependency.krate(db.upcast())?; |
456 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | 470 | let dependency_imports = db.import_map(dependency_krate); |
457 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | 471 | |
458 | ItemInNs::Types(_) => "t", | 472 | let (path, mark) = match assoc_item_path(&db, &dependency_imports, dependency) { |
459 | ItemInNs::Values(_) => "v", | 473 | Some(assoc_item_path) => (assoc_item_path, "a"), |
460 | ItemInNs::Macros(_) => "m", | 474 | None => ( |
475 | dependency_imports.path_of(dependency)?.to_string(), | ||
476 | match dependency { | ||
477 | ItemInNs::Types(ModuleDefId::FunctionId(_)) | ||
478 | | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f", | ||
479 | ItemInNs::Types(_) => "t", | ||
480 | ItemInNs::Values(_) => "v", | ||
481 | ItemInNs::Macros(_) => "m", | ||
482 | }, | ||
483 | ), | ||
461 | }; | 484 | }; |
462 | item.krate(db.upcast()).map(|krate| { | 485 | |
463 | let map = db.import_map(krate); | 486 | Some(format!( |
464 | 487 | "{}::{} ({})\n", | |
465 | let path = match assoc_to_trait(&db, item) { | 488 | crate_graph[dependency_krate].display_name.as_ref()?, |
466 | Some(trait_) => { | 489 | path, |
467 | let mut full_path = map.path_of(trait_).unwrap().to_string(); | 490 | mark |
468 | if let ItemInNs::Types(ModuleDefId::FunctionId(function_id)) | 491 | )) |
469 | | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item | ||
470 | { | ||
471 | format_to!( | ||
472 | full_path, | ||
473 | "::{}", | ||
474 | FunctionData::fn_data_query(&db, function_id).name, | ||
475 | ); | ||
476 | } | ||
477 | full_path | ||
478 | } | ||
479 | None => map.path_of(item).unwrap().to_string(), | ||
480 | }; | ||
481 | |||
482 | format!( | ||
483 | "{}::{} ({})\n", | ||
484 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
485 | path, | ||
486 | mark | ||
487 | ) | ||
488 | }) | ||
489 | }) | 492 | }) |
490 | .collect::<String>(); | 493 | .collect::<String>(); |
491 | expect.assert_eq(&actual) | 494 | expect.assert_eq(&actual) |
492 | } | 495 | } |
493 | 496 | ||
497 | fn assoc_item_path( | ||
498 | db: &dyn DefDatabase, | ||
499 | dependency_imports: &ImportMap, | ||
500 | dependency: ItemInNs, | ||
501 | ) -> Option<String> { | ||
502 | let dependency_assoc_item_id = match dependency { | ||
503 | ItemInNs::Types(ModuleDefId::FunctionId(id)) | ||
504 | | ItemInNs::Values(ModuleDefId::FunctionId(id)) => AssocItemId::from(id), | ||
505 | ItemInNs::Types(ModuleDefId::ConstId(id)) | ||
506 | | ItemInNs::Values(ModuleDefId::ConstId(id)) => AssocItemId::from(id), | ||
507 | ItemInNs::Types(ModuleDefId::TypeAliasId(id)) | ||
508 | | ItemInNs::Values(ModuleDefId::TypeAliasId(id)) => AssocItemId::from(id), | ||
509 | _ => return None, | ||
510 | }; | ||
511 | |||
512 | let trait_ = assoc_to_trait(db, dependency)?; | ||
513 | if let ModuleDefId::TraitId(tr) = trait_.as_module_def_id()? { | ||
514 | let trait_data = db.trait_data(tr); | ||
515 | let assoc_item_name = | ||
516 | trait_data.items.iter().find_map(|(assoc_item_name, assoc_item_id)| { | ||
517 | if &dependency_assoc_item_id == assoc_item_id { | ||
518 | Some(assoc_item_name) | ||
519 | } else { | ||
520 | None | ||
521 | } | ||
522 | })?; | ||
523 | return Some(format!("{}::{}", dependency_imports.path_of(trait_)?, assoc_item_name)); | ||
524 | } | ||
525 | None | ||
526 | } | ||
527 | |||
494 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { | 528 | fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> { |
495 | let assoc: AssocItemId = match item { | 529 | let assoc: AssocItemId = match item { |
496 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { | 530 | ItemInNs::Types(it) | ItemInNs::Values(it) => match it { |
@@ -749,6 +783,37 @@ mod tests { | |||
749 | } | 783 | } |
750 | 784 | ||
751 | #[test] | 785 | #[test] |
786 | fn fuzzy_import_trait_and_assoc_items() { | ||
787 | mark::check!(type_aliases_ignored); | ||
788 | let ra_fixture = r#" | ||
789 | //- /main.rs crate:main deps:dep | ||
790 | //- /dep.rs crate:dep | ||
791 | pub mod fmt { | ||
792 | pub trait Display { | ||
793 | type FmtTypeAlias; | ||
794 | const FMT_CONST: bool; | ||
795 | |||
796 | fn format_function(); | ||
797 | fn format_method(&self); | ||
798 | } | ||
799 | } | ||
800 | "#; | ||
801 | |||
802 | check_search( | ||
803 | ra_fixture, | ||
804 | "main", | ||
805 | Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy), | ||
806 | expect![[r#" | ||
807 | dep::fmt (t) | ||
808 | dep::fmt::Display (t) | ||
809 | dep::fmt::Display::FMT_CONST (a) | ||
810 | dep::fmt::Display::format_function (a) | ||
811 | dep::fmt::Display::format_method (a) | ||
812 | "#]], | ||
813 | ); | ||
814 | } | ||
815 | |||
816 | #[test] | ||
752 | fn search_mode() { | 817 | fn search_mode() { |
753 | let ra_fixture = r#" | 818 | let ra_fixture = r#" |
754 | //- /main.rs crate:main deps:dep | 819 | //- /main.rs crate:main deps:dep |
@@ -784,8 +849,8 @@ mod tests { | |||
784 | dep::Fmt (v) | 849 | dep::Fmt (v) |
785 | dep::Fmt (m) | 850 | dep::Fmt (m) |
786 | dep::fmt::Display (t) | 851 | dep::fmt::Display (t) |
852 | dep::fmt::Display::fmt (a) | ||
787 | dep::format (f) | 853 | dep::format (f) |
788 | dep::fmt::Display::fmt (f) | ||
789 | "#]], | 854 | "#]], |
790 | ); | 855 | ); |
791 | 856 | ||
@@ -798,7 +863,7 @@ mod tests { | |||
798 | dep::Fmt (t) | 863 | dep::Fmt (t) |
799 | dep::Fmt (v) | 864 | dep::Fmt (v) |
800 | dep::Fmt (m) | 865 | dep::Fmt (m) |
801 | dep::fmt::Display::fmt (f) | 866 | dep::fmt::Display::fmt (a) |
802 | "#]], | 867 | "#]], |
803 | ); | 868 | ); |
804 | 869 | ||
@@ -812,7 +877,7 @@ mod tests { | |||
812 | dep::Fmt (v) | 877 | dep::Fmt (v) |
813 | dep::Fmt (m) | 878 | dep::Fmt (m) |
814 | dep::fmt::Display (t) | 879 | dep::fmt::Display (t) |
815 | dep::fmt::Display::fmt (f) | 880 | dep::fmt::Display::fmt (a) |
816 | "#]], | 881 | "#]], |
817 | ); | 882 | ); |
818 | } | 883 | } |
@@ -853,7 +918,7 @@ mod tests { | |||
853 | dep::Fmt (v) | 918 | dep::Fmt (v) |
854 | dep::Fmt (m) | 919 | dep::Fmt (m) |
855 | dep::fmt::Display (t) | 920 | dep::fmt::Display (t) |
856 | dep::fmt::Display::fmt (f) | 921 | dep::fmt::Display::fmt (a) |
857 | "#]], | 922 | "#]], |
858 | ); | 923 | ); |
859 | 924 | ||
@@ -866,7 +931,7 @@ mod tests { | |||
866 | dep::Fmt (t) | 931 | dep::Fmt (t) |
867 | dep::Fmt (v) | 932 | dep::Fmt (v) |
868 | dep::Fmt (m) | 933 | dep::Fmt (m) |
869 | dep::fmt::Display::fmt (f) | 934 | dep::fmt::Display::fmt (a) |
870 | "#]], | 935 | "#]], |
871 | ); | 936 | ); |
872 | } | 937 | } |
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs index 62ab3b2bd..2750e1c91 100644 --- a/crates/hir_def/src/item_scope.rs +++ b/crates/hir_def/src/item_scope.rs | |||
@@ -10,10 +10,9 @@ use once_cell::sync::Lazy; | |||
10 | use rustc_hash::{FxHashMap, FxHashSet}; | 10 | use rustc_hash::{FxHashMap, FxHashSet}; |
11 | use test_utils::mark; | 11 | use test_utils::mark; |
12 | 12 | ||
13 | use crate::ModuleId; | ||
14 | use crate::{ | 13 | use crate::{ |
15 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, | 14 | db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, HasModule, ImplId, |
16 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, TraitId, | 15 | LocalModuleId, Lookup, MacroDefId, ModuleDefId, ModuleId, TraitId, |
17 | }; | 16 | }; |
18 | 17 | ||
19 | #[derive(Copy, Clone)] | 18 | #[derive(Copy, Clone)] |
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs index a636ec77d..77017e4ea 100644 --- a/crates/hir_def/src/nameres/collector.rs +++ b/crates/hir_def/src/nameres/collector.rs | |||
@@ -13,7 +13,7 @@ use hir_expand::{ | |||
13 | builtin_macro::find_builtin_macro, | 13 | builtin_macro::find_builtin_macro, |
14 | name::{AsName, Name}, | 14 | name::{AsName, Name}, |
15 | proc_macro::ProcMacroExpander, | 15 | proc_macro::ProcMacroExpander, |
16 | HirFileId, MacroCallId, MacroDefId, MacroDefKind, | 16 | HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
17 | }; | 17 | }; |
18 | use hir_expand::{InFile, MacroCallLoc}; | 18 | use hir_expand::{InFile, MacroCallLoc}; |
19 | use rustc_hash::{FxHashMap, FxHashSet}; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
@@ -860,6 +860,37 @@ impl DefCollector<'_> { | |||
860 | } | 860 | } |
861 | 861 | ||
862 | fn finish(mut self) -> CrateDefMap { | 862 | fn finish(mut self) -> CrateDefMap { |
863 | // Emit diagnostics for all remaining unexpanded macros. | ||
864 | |||
865 | for directive in &self.unexpanded_macros { | ||
866 | let mut error = None; | ||
867 | directive.ast_id.as_call_id_with_errors( | ||
868 | self.db, | ||
869 | self.def_map.krate, | ||
870 | |path| { | ||
871 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | ||
872 | self.db, | ||
873 | ResolveMode::Other, | ||
874 | directive.module_id, | ||
875 | &path, | ||
876 | BuiltinShadowMode::Module, | ||
877 | ); | ||
878 | resolved_res.resolved_def.take_macros() | ||
879 | }, | ||
880 | &mut |e| { | ||
881 | error.get_or_insert(e); | ||
882 | }, | ||
883 | ); | ||
884 | |||
885 | if let Some(err) = error { | ||
886 | self.def_map.diagnostics.push(DefDiagnostic::macro_error( | ||
887 | directive.module_id, | ||
888 | MacroCallKind::FnLike(directive.ast_id.ast_id), | ||
889 | err.to_string(), | ||
890 | )); | ||
891 | } | ||
892 | } | ||
893 | |||
863 | // Emit diagnostics for all remaining unresolved imports. | 894 | // Emit diagnostics for all remaining unresolved imports. |
864 | 895 | ||
865 | // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't | 896 | // We'd like to avoid emitting a diagnostics avalanche when some `extern crate` doesn't |
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs index 7c77f6ce0..1923daca5 100644 --- a/crates/hir_expand/src/proc_macro.rs +++ b/crates/hir_expand/src/proc_macro.rs | |||
@@ -58,7 +58,7 @@ impl ProcMacroExpander { | |||
58 | } | 58 | } |
59 | 59 | ||
60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | 60 | fn eat_punct(cursor: &mut Cursor, c: char) -> bool { |
61 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() { | 61 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() { |
62 | if punct.char == c { | 62 | if punct.char == c { |
63 | *cursor = cursor.bump(); | 63 | *cursor = cursor.bump(); |
64 | return true; | 64 | return true; |
@@ -68,7 +68,7 @@ fn eat_punct(cursor: &mut Cursor, c: char) -> bool { | |||
68 | } | 68 | } |
69 | 69 | ||
70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | 70 | fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { |
71 | if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() { | 71 | if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() { |
72 | if Some(kind) == subtree.delimiter_kind() { | 72 | if Some(kind) == subtree.delimiter_kind() { |
73 | *cursor = cursor.bump_subtree(); | 73 | *cursor = cursor.bump_subtree(); |
74 | return true; | 74 | return true; |
@@ -78,7 +78,7 @@ fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool { | |||
78 | } | 78 | } |
79 | 79 | ||
80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | 80 | fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { |
81 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() { | 81 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() { |
82 | if t == ident.text.as_str() { | 82 | if t == ident.text.as_str() { |
83 | *cursor = cursor.bump(); | 83 | *cursor = cursor.bump(); |
84 | return true; | 84 | return true; |
@@ -88,7 +88,7 @@ fn eat_ident(cursor: &mut Cursor, t: &str) -> bool { | |||
88 | } | 88 | } |
89 | 89 | ||
90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | 90 | fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { |
91 | let buffer = TokenBuffer::new(&tt.token_trees); | 91 | let buffer = TokenBuffer::from_tokens(&tt.token_trees); |
92 | let mut p = buffer.begin(); | 92 | let mut p = buffer.begin(); |
93 | let mut result = tt::Subtree::default(); | 93 | let mut result = tt::Subtree::default(); |
94 | 94 | ||
@@ -106,7 +106,7 @@ fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> { | |||
106 | } | 106 | } |
107 | } | 107 | } |
108 | 108 | ||
109 | result.token_trees.push(curr.token_tree()?.clone()); | 109 | result.token_trees.push(curr.token_tree()?.cloned()); |
110 | p = curr.bump(); | 110 | p = curr.bump(); |
111 | } | 111 | } |
112 | 112 | ||
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml index 3d1778590..b0a453961 100644 --- a/crates/hir_ty/Cargo.toml +++ b/crates/hir_ty/Cargo.toml | |||
@@ -17,9 +17,9 @@ ena = "0.14.0" | |||
17 | log = "0.4.8" | 17 | log = "0.4.8" |
18 | rustc-hash = "1.1.0" | 18 | rustc-hash = "1.1.0" |
19 | scoped-tls = "1" | 19 | scoped-tls = "1" |
20 | chalk-solve = { version = "0.45", default-features = false } | 20 | chalk-solve = { version = "0.47", default-features = false } |
21 | chalk-ir = "0.45" | 21 | chalk-ir = "0.47" |
22 | chalk-recursive = "0.45" | 22 | chalk-recursive = "0.47" |
23 | 23 | ||
24 | stdx = { path = "../stdx", version = "0.0.0" } | 24 | stdx = { path = "../stdx", version = "0.0.0" } |
25 | hir_def = { path = "../hir_def", version = "0.0.0" } | 25 | hir_def = { path = "../hir_def", version = "0.0.0" } |
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs index 0e827a29e..e9e949c47 100644 --- a/crates/hir_ty/src/display.rs +++ b/crates/hir_ty/src/display.rs | |||
@@ -168,7 +168,7 @@ pub enum DisplayTarget { | |||
168 | 168 | ||
169 | impl DisplayTarget { | 169 | impl DisplayTarget { |
170 | fn is_source_code(&self) -> bool { | 170 | fn is_source_code(&self) -> bool { |
171 | matches!(self, Self::SourceCode {..}) | 171 | matches!(self, Self::SourceCode { .. }) |
172 | } | 172 | } |
173 | fn is_test(&self) -> bool { | 173 | fn is_test(&self) -> bool { |
174 | matches!(self, Self::Test) | 174 | matches!(self, Self::Test) |
@@ -595,7 +595,7 @@ impl HirDisplay for FnSig { | |||
595 | } | 595 | } |
596 | } | 596 | } |
597 | 597 | ||
598 | fn write_bounds_like_dyn_trait( | 598 | pub fn write_bounds_like_dyn_trait( |
599 | predicates: &[GenericPredicate], | 599 | predicates: &[GenericPredicate], |
600 | f: &mut HirFormatter, | 600 | f: &mut HirFormatter, |
601 | ) -> Result<(), HirDisplayError> { | 601 | ) -> Result<(), HirDisplayError> { |
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs index ea49d9f97..990f740b8 100644 --- a/crates/ide/src/display/short_label.rs +++ b/crates/ide/src/display/short_label.rs | |||
@@ -87,6 +87,17 @@ impl ShortLabel for ast::Variant { | |||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | impl ShortLabel for ast::ConstParam { | ||
91 | fn short_label(&self) -> Option<String> { | ||
92 | let mut buf = "const ".to_owned(); | ||
93 | buf.push_str(self.name()?.text().as_str()); | ||
94 | if let Some(type_ref) = self.ty() { | ||
95 | format_to!(buf, ": {}", type_ref.syntax()); | ||
96 | } | ||
97 | Some(buf) | ||
98 | } | ||
99 | } | ||
100 | |||
90 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> | 101 | fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String> |
91 | where | 102 | where |
92 | T: NameOwner + VisibilityOwner, | 103 | T: NameOwner + VisibilityOwner, |
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs index 2737c900f..f2ad95cb6 100644 --- a/crates/ide/src/hover.rs +++ b/crates/ide/src/hover.rs | |||
@@ -70,7 +70,7 @@ impl HoverConfig { | |||
70 | #[derive(Debug, Clone)] | 70 | #[derive(Debug, Clone)] |
71 | pub enum HoverAction { | 71 | pub enum HoverAction { |
72 | Runnable(Runnable), | 72 | Runnable(Runnable), |
73 | Implementaion(FilePosition), | 73 | Implementation(FilePosition), |
74 | GoToType(Vec<HoverGotoTypeData>), | 74 | GoToType(Vec<HoverGotoTypeData>), |
75 | } | 75 | } |
76 | 76 | ||
@@ -116,12 +116,13 @@ pub(crate) fn hover( | |||
116 | }; | 116 | }; |
117 | if let Some(definition) = definition { | 117 | if let Some(definition) = definition { |
118 | if let Some(markup) = hover_for_definition(db, definition) { | 118 | if let Some(markup) = hover_for_definition(db, definition) { |
119 | let markup = markup.as_str(); | ||
119 | let markup = if !markdown { | 120 | let markup = if !markdown { |
120 | remove_markdown(&markup.as_str()) | 121 | remove_markdown(markup) |
121 | } else if links_in_hover { | 122 | } else if links_in_hover { |
122 | rewrite_links(db, &markup.as_str(), &definition) | 123 | rewrite_links(db, markup, &definition) |
123 | } else { | 124 | } else { |
124 | remove_links(&markup.as_str()) | 125 | remove_links(markup) |
125 | }; | 126 | }; |
126 | res.markup = Markup::from(markup); | 127 | res.markup = Markup::from(markup); |
127 | if let Some(action) = show_implementations_action(db, definition) { | 128 | if let Some(action) = show_implementations_action(db, definition) { |
@@ -175,22 +176,24 @@ pub(crate) fn hover( | |||
175 | 176 | ||
176 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 177 | fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
177 | fn to_action(nav_target: NavigationTarget) -> HoverAction { | 178 | fn to_action(nav_target: NavigationTarget) -> HoverAction { |
178 | HoverAction::Implementaion(FilePosition { | 179 | HoverAction::Implementation(FilePosition { |
179 | file_id: nav_target.file_id, | 180 | file_id: nav_target.file_id, |
180 | offset: nav_target.focus_or_full_range().start(), | 181 | offset: nav_target.focus_or_full_range().start(), |
181 | }) | 182 | }) |
182 | } | 183 | } |
183 | 184 | ||
184 | match def { | 185 | let adt = match def { |
185 | Definition::ModuleDef(it) => match it { | 186 | Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), |
186 | ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)), | 187 | Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), |
187 | ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)), | 188 | Definition::SelfType(it) => it.target_ty(db).as_adt(), |
188 | ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)), | ||
189 | ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)), | ||
190 | _ => None, | ||
191 | }, | ||
192 | _ => None, | 189 | _ => None, |
190 | }?; | ||
191 | match adt { | ||
192 | Adt::Struct(it) => it.try_to_nav(db), | ||
193 | Adt::Union(it) => it.try_to_nav(db), | ||
194 | Adt::Enum(it) => it.try_to_nav(db), | ||
193 | } | 195 | } |
196 | .map(to_action) | ||
194 | } | 197 | } |
195 | 198 | ||
196 | fn runnable_action( | 199 | fn runnable_action( |
@@ -225,45 +228,46 @@ fn runnable_action( | |||
225 | } | 228 | } |
226 | 229 | ||
227 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { | 230 | fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> { |
228 | match def { | 231 | let mut targets: Vec<ModuleDef> = Vec::new(); |
229 | Definition::Local(it) => { | 232 | let mut push_new_def = |item: ModuleDef| { |
230 | let mut targets: Vec<ModuleDef> = Vec::new(); | 233 | if !targets.contains(&item) { |
231 | let mut push_new_def = |item: ModuleDef| { | 234 | targets.push(item); |
232 | if !targets.contains(&item) { | ||
233 | targets.push(item); | ||
234 | } | ||
235 | }; | ||
236 | |||
237 | it.ty(db).walk(db, |t| { | ||
238 | if let Some(adt) = t.as_adt() { | ||
239 | push_new_def(adt.into()); | ||
240 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
241 | push_new_def(trait_.into()); | ||
242 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
243 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
244 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
245 | push_new_def(trait_.into()); | ||
246 | } | ||
247 | }); | ||
248 | |||
249 | let targets = targets | ||
250 | .into_iter() | ||
251 | .filter_map(|it| { | ||
252 | Some(HoverGotoTypeData { | ||
253 | mod_path: render_path( | ||
254 | db, | ||
255 | it.module(db)?, | ||
256 | it.name(db).map(|name| name.to_string()), | ||
257 | ), | ||
258 | nav: it.try_to_nav(db)?, | ||
259 | }) | ||
260 | }) | ||
261 | .collect(); | ||
262 | |||
263 | Some(HoverAction::GoToType(targets)) | ||
264 | } | 235 | } |
265 | _ => None, | 236 | }; |
237 | |||
238 | if let Definition::TypeParam(it) = def { | ||
239 | it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into())); | ||
240 | } else { | ||
241 | let ty = match def { | ||
242 | Definition::Local(it) => it.ty(db), | ||
243 | Definition::ConstParam(it) => it.ty(db), | ||
244 | _ => return None, | ||
245 | }; | ||
246 | |||
247 | ty.walk(db, |t| { | ||
248 | if let Some(adt) = t.as_adt() { | ||
249 | push_new_def(adt.into()); | ||
250 | } else if let Some(trait_) = t.as_dyn_trait() { | ||
251 | push_new_def(trait_.into()); | ||
252 | } else if let Some(traits) = t.as_impl_traits(db) { | ||
253 | traits.into_iter().for_each(|it| push_new_def(it.into())); | ||
254 | } else if let Some(trait_) = t.as_associated_type_parent_trait(db) { | ||
255 | push_new_def(trait_.into()); | ||
256 | } | ||
257 | }); | ||
266 | } | 258 | } |
259 | |||
260 | let targets = targets | ||
261 | .into_iter() | ||
262 | .filter_map(|it| { | ||
263 | Some(HoverGotoTypeData { | ||
264 | mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())), | ||
265 | nav: it.try_to_nav(db)?, | ||
266 | }) | ||
267 | }) | ||
268 | .collect(); | ||
269 | |||
270 | Some(HoverAction::GoToType(targets)) | ||
267 | } | 271 | } |
268 | 272 | ||
269 | fn hover_markup( | 273 | fn hover_markup( |
@@ -370,10 +374,8 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> { | |||
370 | } | 374 | } |
371 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), | 375 | Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), |
372 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), | 376 | Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))), |
373 | Definition::TypeParam(_) | Definition::ConstParam(_) => { | 377 | Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))), |
374 | // FIXME: Hover for generic param | 378 | Definition::ConstParam(it) => from_def_source(db, it, None), |
375 | None | ||
376 | } | ||
377 | }; | 379 | }; |
378 | 380 | ||
379 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> | 381 | fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup> |
@@ -1393,7 +1395,7 @@ fn bar() { fo<|>o(); } | |||
1393 | r"unsafe trait foo<|>() {}", | 1395 | r"unsafe trait foo<|>() {}", |
1394 | expect![[r#" | 1396 | expect![[r#" |
1395 | [ | 1397 | [ |
1396 | Implementaion( | 1398 | Implementation( |
1397 | FilePosition { | 1399 | FilePosition { |
1398 | file_id: FileId( | 1400 | file_id: FileId( |
1399 | 0, | 1401 | 0, |
@@ -2105,7 +2107,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2105 | r#"trait foo<|>() {}"#, | 2107 | r#"trait foo<|>() {}"#, |
2106 | expect![[r#" | 2108 | expect![[r#" |
2107 | [ | 2109 | [ |
2108 | Implementaion( | 2110 | Implementation( |
2109 | FilePosition { | 2111 | FilePosition { |
2110 | file_id: FileId( | 2112 | file_id: FileId( |
2111 | 0, | 2113 | 0, |
@@ -2124,7 +2126,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2124 | r"struct foo<|>() {}", | 2126 | r"struct foo<|>() {}", |
2125 | expect![[r#" | 2127 | expect![[r#" |
2126 | [ | 2128 | [ |
2127 | Implementaion( | 2129 | Implementation( |
2128 | FilePosition { | 2130 | FilePosition { |
2129 | file_id: FileId( | 2131 | file_id: FileId( |
2130 | 0, | 2132 | 0, |
@@ -2143,7 +2145,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2143 | r#"union foo<|>() {}"#, | 2145 | r#"union foo<|>() {}"#, |
2144 | expect![[r#" | 2146 | expect![[r#" |
2145 | [ | 2147 | [ |
2146 | Implementaion( | 2148 | Implementation( |
2147 | FilePosition { | 2149 | FilePosition { |
2148 | file_id: FileId( | 2150 | file_id: FileId( |
2149 | 0, | 2151 | 0, |
@@ -2162,7 +2164,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2162 | r"enum foo<|>() { A, B }", | 2164 | r"enum foo<|>() { A, B }", |
2163 | expect![[r#" | 2165 | expect![[r#" |
2164 | [ | 2166 | [ |
2165 | Implementaion( | 2167 | Implementation( |
2166 | FilePosition { | 2168 | FilePosition { |
2167 | file_id: FileId( | 2169 | file_id: FileId( |
2168 | 0, | 2170 | 0, |
@@ -2176,6 +2178,25 @@ fn foo() { let bar = Bar; bar.fo<|>o(); } | |||
2176 | } | 2178 | } |
2177 | 2179 | ||
2178 | #[test] | 2180 | #[test] |
2181 | fn test_hover_self_has_impl_action() { | ||
2182 | check_actions( | ||
2183 | r#"struct foo where Self<|>:;"#, | ||
2184 | expect![[r#" | ||
2185 | [ | ||
2186 | Implementation( | ||
2187 | FilePosition { | ||
2188 | file_id: FileId( | ||
2189 | 0, | ||
2190 | ), | ||
2191 | offset: 7, | ||
2192 | }, | ||
2193 | ), | ||
2194 | ] | ||
2195 | "#]], | ||
2196 | ); | ||
2197 | } | ||
2198 | |||
2199 | #[test] | ||
2179 | fn test_hover_test_has_action() { | 2200 | fn test_hover_test_has_action() { |
2180 | check_actions( | 2201 | check_actions( |
2181 | r#" | 2202 | r#" |
@@ -3064,6 +3085,71 @@ fn main() { let s<|>t = test().get(); } | |||
3064 | } | 3085 | } |
3065 | 3086 | ||
3066 | #[test] | 3087 | #[test] |
3088 | fn test_hover_const_param_has_goto_type_action() { | ||
3089 | check_actions( | ||
3090 | r#" | ||
3091 | struct Bar; | ||
3092 | struct Foo<const BAR: Bar>; | ||
3093 | |||
3094 | impl<const BAR: Bar> Foo<BAR<|>> {} | ||
3095 | "#, | ||
3096 | expect![[r#" | ||
3097 | [ | ||
3098 | GoToType( | ||
3099 | [ | ||
3100 | HoverGotoTypeData { | ||
3101 | mod_path: "test::Bar", | ||
3102 | nav: NavigationTarget { | ||
3103 | file_id: FileId( | ||
3104 | 0, | ||
3105 | ), | ||
3106 | full_range: 0..11, | ||
3107 | focus_range: 7..10, | ||
3108 | name: "Bar", | ||
3109 | kind: Struct, | ||
3110 | description: "struct Bar", | ||
3111 | }, | ||
3112 | }, | ||
3113 | ], | ||
3114 | ), | ||
3115 | ] | ||
3116 | "#]], | ||
3117 | ); | ||
3118 | } | ||
3119 | |||
3120 | #[test] | ||
3121 | fn test_hover_type_param_has_goto_type_action() { | ||
3122 | check_actions( | ||
3123 | r#" | ||
3124 | trait Foo {} | ||
3125 | |||
3126 | fn foo<T: Foo>(t: T<|>){} | ||
3127 | "#, | ||
3128 | expect![[r#" | ||
3129 | [ | ||
3130 | GoToType( | ||
3131 | [ | ||
3132 | HoverGotoTypeData { | ||
3133 | mod_path: "test::Foo", | ||
3134 | nav: NavigationTarget { | ||
3135 | file_id: FileId( | ||
3136 | 0, | ||
3137 | ), | ||
3138 | full_range: 0..12, | ||
3139 | focus_range: 6..9, | ||
3140 | name: "Foo", | ||
3141 | kind: Trait, | ||
3142 | description: "trait Foo", | ||
3143 | }, | ||
3144 | }, | ||
3145 | ], | ||
3146 | ), | ||
3147 | ] | ||
3148 | "#]], | ||
3149 | ); | ||
3150 | } | ||
3151 | |||
3152 | #[test] | ||
3067 | fn hover_displays_normalized_crate_names() { | 3153 | fn hover_displays_normalized_crate_names() { |
3068 | check( | 3154 | check( |
3069 | r#" | 3155 | r#" |
@@ -3257,4 +3343,68 @@ fn foo() { | |||
3257 | "#]], | 3343 | "#]], |
3258 | ); | 3344 | ); |
3259 | } | 3345 | } |
3346 | |||
3347 | #[test] | ||
3348 | fn hover_type_param() { | ||
3349 | check( | ||
3350 | r#" | ||
3351 | struct Foo<T>(T); | ||
3352 | trait Copy {} | ||
3353 | trait Clone {} | ||
3354 | trait Sized {} | ||
3355 | impl<T: Copy + Clone> Foo<T<|>> where T: Sized {} | ||
3356 | "#, | ||
3357 | expect![[r#" | ||
3358 | *T* | ||
3359 | |||
3360 | ```rust | ||
3361 | T: Copy + Clone + Sized | ||
3362 | ``` | ||
3363 | "#]], | ||
3364 | ); | ||
3365 | check( | ||
3366 | r#" | ||
3367 | struct Foo<T>(T); | ||
3368 | impl<T> Foo<T<|>> {} | ||
3369 | "#, | ||
3370 | expect![[r#" | ||
3371 | *T* | ||
3372 | |||
3373 | ```rust | ||
3374 | T | ||
3375 | ``` | ||
3376 | "#]], | ||
3377 | ); | ||
3378 | // lifetimes aren't being substituted yet | ||
3379 | check( | ||
3380 | r#" | ||
3381 | struct Foo<T>(T); | ||
3382 | impl<T: 'static> Foo<T<|>> {} | ||
3383 | "#, | ||
3384 | expect![[r#" | ||
3385 | *T* | ||
3386 | |||
3387 | ```rust | ||
3388 | T: {error} | ||
3389 | ``` | ||
3390 | "#]], | ||
3391 | ); | ||
3392 | } | ||
3393 | |||
3394 | #[test] | ||
3395 | fn hover_const_param() { | ||
3396 | check( | ||
3397 | r#" | ||
3398 | struct Foo<const LEN: usize>; | ||
3399 | impl<const LEN: usize> Foo<LEN<|>> {} | ||
3400 | "#, | ||
3401 | expect![[r#" | ||
3402 | *LEN* | ||
3403 | |||
3404 | ```rust | ||
3405 | const LEN: usize | ||
3406 | ``` | ||
3407 | "#]], | ||
3408 | ); | ||
3409 | } | ||
3260 | } | 3410 | } |
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs index 0f4c2ca47..0782ab070 100644 --- a/crates/ide_db/src/imports_locator.rs +++ b/crates/ide_db/src/imports_locator.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! This module contains an import search funcionality that is provided to the assists module. | 1 | //! This module contains an import search funcionality that is provided to the assists module. |
2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. | 2 | //! Later, this should be moved away to a separate crate that is accessible from the assists module. |
3 | 3 | ||
4 | use hir::{import_map, Crate, MacroDef, ModuleDef, Semantics}; | 4 | use hir::{import_map, AsAssocItem, Crate, MacroDef, ModuleDef, Semantics}; |
5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; | 5 | use syntax::{ast, AstNode, SyntaxKind::NAME}; |
6 | 6 | ||
7 | use crate::{ | 7 | use crate::{ |
@@ -40,8 +40,9 @@ pub fn find_similar_imports<'a>( | |||
40 | krate: Crate, | 40 | krate: Crate, |
41 | limit: Option<usize>, | 41 | limit: Option<usize>, |
42 | fuzzy_search_string: String, | 42 | fuzzy_search_string: String, |
43 | ignore_assoc_items: bool, | ||
43 | name_only: bool, | 44 | name_only: bool, |
44 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | 45 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> + 'a { |
45 | let _p = profile::span("find_similar_imports"); | 46 | let _p = profile::span("find_similar_imports"); |
46 | 47 | ||
47 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) | 48 | let mut external_query = import_map::Query::new(fuzzy_search_string.clone()) |
@@ -57,7 +58,21 @@ pub fn find_similar_imports<'a>( | |||
57 | external_query = external_query.limit(limit); | 58 | external_query = external_query.limit(limit); |
58 | } | 59 | } |
59 | 60 | ||
60 | find_imports(sema, krate, local_query, external_query) | 61 | let db = sema.db; |
62 | find_imports(sema, krate, local_query, external_query).filter(move |import_candidate| { | ||
63 | if ignore_assoc_items { | ||
64 | match import_candidate { | ||
65 | Either::Left(ModuleDef::Function(function)) => function.as_assoc_item(db).is_none(), | ||
66 | Either::Left(ModuleDef::Const(const_)) => const_.as_assoc_item(db).is_none(), | ||
67 | Either::Left(ModuleDef::TypeAlias(type_alias)) => { | ||
68 | type_alias.as_assoc_item(db).is_none() | ||
69 | } | ||
70 | _ => true, | ||
71 | } | ||
72 | } else { | ||
73 | true | ||
74 | } | ||
75 | }) | ||
61 | } | 76 | } |
62 | 77 | ||
63 | fn find_imports<'a>( | 78 | fn find_imports<'a>( |
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs index ab5f87c48..fdc8844ce 100644 --- a/crates/mbe/src/mbe_expander/matcher.rs +++ b/crates/mbe/src/mbe_expander/matcher.rs | |||
@@ -309,7 +309,7 @@ impl<'a> TtIter<'a> { | |||
309 | } | 309 | } |
310 | } | 310 | } |
311 | 311 | ||
312 | let buffer = TokenBuffer::new(&self.inner.as_slice()); | 312 | let buffer = TokenBuffer::from_tokens(&self.inner.as_slice()); |
313 | let mut src = SubtreeTokenSource::new(&buffer); | 313 | let mut src = SubtreeTokenSource::new(&buffer); |
314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; | 314 | let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false }; |
315 | 315 | ||
@@ -336,11 +336,11 @@ impl<'a> TtIter<'a> { | |||
336 | err = Some(err!("no tokens consumed")); | 336 | err = Some(err!("no tokens consumed")); |
337 | } | 337 | } |
338 | let res = match res.len() { | 338 | let res = match res.len() { |
339 | 1 => Some(res[0].clone()), | 339 | 1 => Some(res[0].cloned()), |
340 | 0 => None, | 340 | 0 => None, |
341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { | 341 | _ => Some(tt::TokenTree::Subtree(tt::Subtree { |
342 | delimiter: None, | 342 | delimiter: None, |
343 | token_trees: res.into_iter().cloned().collect(), | 343 | token_trees: res.into_iter().map(|it| it.cloned()).collect(), |
344 | })), | 344 | })), |
345 | }; | 345 | }; |
346 | ExpandResult { value: res, err } | 346 | ExpandResult { value: res, err } |
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs index d10d4b70e..d7433bd35 100644 --- a/crates/mbe/src/subtree_source.rs +++ b/crates/mbe/src/subtree_source.rs | |||
@@ -1,129 +1,104 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use parser::{Token, TokenSource}; | 3 | use parser::{Token, TokenSource}; |
4 | use std::cell::{Cell, Ref, RefCell}; | ||
5 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 5 | use tt::buffer::TokenBuffer; |
7 | 6 | ||
8 | #[derive(Debug, Clone, Eq, PartialEq)] | 7 | #[derive(Debug, Clone, Eq, PartialEq)] |
9 | struct TtToken { | 8 | struct TtToken { |
10 | kind: SyntaxKind, | 9 | tt: Token, |
11 | is_joint_to_next: bool, | ||
12 | text: SmolStr, | 10 | text: SmolStr, |
13 | } | 11 | } |
14 | 12 | ||
15 | pub(crate) struct SubtreeTokenSource<'a> { | 13 | pub(crate) struct SubtreeTokenSource { |
16 | cached_cursor: Cell<Cursor<'a>>, | 14 | cached: Vec<TtToken>, |
17 | cached: RefCell<Vec<Option<TtToken>>>, | ||
18 | curr: (Token, usize), | 15 | curr: (Token, usize), |
19 | } | 16 | } |
20 | 17 | ||
21 | impl<'a> SubtreeTokenSource<'a> { | 18 | impl<'a> SubtreeTokenSource { |
22 | // Helper function used in test | 19 | // Helper function used in test |
23 | #[cfg(test)] | 20 | #[cfg(test)] |
24 | pub(crate) fn text(&self) -> SmolStr { | 21 | pub(crate) fn text(&self) -> SmolStr { |
25 | match *self.get(self.curr.1) { | 22 | match self.cached.get(self.curr.1) { |
26 | Some(ref tt) => tt.text.clone(), | 23 | Some(ref tt) => tt.text.clone(), |
27 | _ => SmolStr::new(""), | 24 | _ => SmolStr::new(""), |
28 | } | 25 | } |
29 | } | 26 | } |
30 | } | 27 | } |
31 | 28 | ||
32 | impl<'a> SubtreeTokenSource<'a> { | 29 | impl<'a> SubtreeTokenSource { |
33 | pub(crate) fn new(buffer: &'a TokenBuffer) -> SubtreeTokenSource<'a> { | 30 | pub(crate) fn new(buffer: &TokenBuffer) -> SubtreeTokenSource { |
34 | let cursor = buffer.begin(); | 31 | let mut current = buffer.begin(); |
32 | let mut cached = Vec::with_capacity(100); | ||
35 | 33 | ||
36 | let mut res = SubtreeTokenSource { | 34 | while !current.eof() { |
37 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | 35 | let cursor = current; |
38 | cached_cursor: Cell::new(cursor), | 36 | let tt = cursor.token_tree(); |
39 | cached: RefCell::new(Vec::with_capacity(10)), | ||
40 | }; | ||
41 | res.curr = (res.mk_token(0), 0); | ||
42 | res | ||
43 | } | ||
44 | 37 | ||
45 | fn mk_token(&self, pos: usize) -> Token { | 38 | // Check if it is lifetime |
46 | match *self.get(pos) { | 39 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = tt { |
47 | Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next }, | ||
48 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
49 | } | ||
50 | } | ||
51 | |||
52 | fn get(&self, pos: usize) -> Ref<Option<TtToken>> { | ||
53 | fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> { | ||
54 | let tkn = c.token_tree(); | ||
55 | |||
56 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn { | ||
57 | if punct.char == '\'' { | 40 | if punct.char == '\'' { |
58 | let next = c.bump(); | 41 | let next = cursor.bump(); |
59 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() { | 42 | if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = |
60 | let res_cursor = next.bump(); | 43 | next.token_tree() |
61 | let text = SmolStr::new("'".to_string() + &ident.to_string()); | 44 | { |
62 | 45 | let text = SmolStr::new("'".to_string() + &ident.text); | |
63 | return Some((res_cursor, text)); | 46 | cached.push(TtToken { |
47 | tt: Token { kind: LIFETIME_IDENT, is_jointed_to_next: false }, | ||
48 | text, | ||
49 | }); | ||
50 | current = next.bump(); | ||
51 | continue; | ||
64 | } else { | 52 | } else { |
65 | panic!("Next token must be ident : {:#?}", next.token_tree()); | 53 | panic!("Next token must be ident : {:#?}", next.token_tree()); |
66 | } | 54 | } |
67 | } | 55 | } |
68 | } | 56 | } |
69 | 57 | ||
70 | None | 58 | current = match tt { |
71 | } | 59 | Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => { |
72 | 60 | cached.push(convert_leaf(&leaf)); | |
73 | if pos < self.cached.borrow().len() { | 61 | cursor.bump() |
74 | return Ref::map(self.cached.borrow(), |c| &c[pos]); | ||
75 | } | ||
76 | |||
77 | { | ||
78 | let mut cached = self.cached.borrow_mut(); | ||
79 | while pos >= cached.len() { | ||
80 | let cursor = self.cached_cursor.get(); | ||
81 | if cursor.eof() { | ||
82 | cached.push(None); | ||
83 | continue; | ||
84 | } | 62 | } |
85 | 63 | Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => { | |
86 | if let Some((curr, text)) = is_lifetime(cursor) { | 64 | cached.push(convert_delim(subtree.delimiter_kind(), false)); |
87 | cached.push(Some(TtToken { | 65 | cursor.subtree().unwrap() |
88 | kind: LIFETIME_IDENT, | ||
89 | is_joint_to_next: false, | ||
90 | text, | ||
91 | })); | ||
92 | self.cached_cursor.set(curr); | ||
93 | continue; | ||
94 | } | 66 | } |
95 | 67 | None => { | |
96 | match cursor.token_tree() { | 68 | if let Some(subtree) = cursor.end() { |
97 | Some(tt::TokenTree::Leaf(leaf)) => { | 69 | cached.push(convert_delim(subtree.delimiter_kind(), true)); |
98 | cached.push(Some(convert_leaf(&leaf))); | 70 | cursor.bump() |
99 | self.cached_cursor.set(cursor.bump()); | 71 | } else { |
100 | } | 72 | continue; |
101 | Some(tt::TokenTree::Subtree(subtree)) => { | ||
102 | self.cached_cursor.set(cursor.subtree().unwrap()); | ||
103 | cached.push(Some(convert_delim(subtree.delimiter_kind(), false))); | ||
104 | } | ||
105 | None => { | ||
106 | if let Some(subtree) = cursor.end() { | ||
107 | cached.push(Some(convert_delim(subtree.delimiter_kind(), true))); | ||
108 | self.cached_cursor.set(cursor.bump()); | ||
109 | } | ||
110 | } | 73 | } |
111 | } | 74 | } |
112 | } | 75 | }; |
113 | } | 76 | } |
114 | 77 | ||
115 | Ref::map(self.cached.borrow(), |c| &c[pos]) | 78 | let mut res = SubtreeTokenSource { |
79 | curr: (Token { kind: EOF, is_jointed_to_next: false }, 0), | ||
80 | cached, | ||
81 | }; | ||
82 | res.curr = (res.token(0), 0); | ||
83 | res | ||
84 | } | ||
85 | |||
86 | fn token(&self, pos: usize) -> Token { | ||
87 | match self.cached.get(pos) { | ||
88 | Some(it) => it.tt, | ||
89 | None => Token { kind: EOF, is_jointed_to_next: false }, | ||
90 | } | ||
116 | } | 91 | } |
117 | } | 92 | } |
118 | 93 | ||
119 | impl<'a> TokenSource for SubtreeTokenSource<'a> { | 94 | impl<'a> TokenSource for SubtreeTokenSource { |
120 | fn current(&self) -> Token { | 95 | fn current(&self) -> Token { |
121 | self.curr.0 | 96 | self.curr.0 |
122 | } | 97 | } |
123 | 98 | ||
124 | /// Lookahead n token | 99 | /// Lookahead n token |
125 | fn lookahead_nth(&self, n: usize) -> Token { | 100 | fn lookahead_nth(&self, n: usize) -> Token { |
126 | self.mk_token(self.curr.1 + n) | 101 | self.token(self.curr.1 + n) |
127 | } | 102 | } |
128 | 103 | ||
129 | /// bump cursor to next token | 104 | /// bump cursor to next token |
@@ -131,13 +106,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> { | |||
131 | if self.current().kind == EOF { | 106 | if self.current().kind == EOF { |
132 | return; | 107 | return; |
133 | } | 108 | } |
134 | 109 | self.curr = (self.token(self.curr.1 + 1), self.curr.1 + 1); | |
135 | self.curr = (self.mk_token(self.curr.1 + 1), self.curr.1 + 1); | ||
136 | } | 110 | } |
137 | 111 | ||
138 | /// Is the current token a specified keyword? | 112 | /// Is the current token a specified keyword? |
139 | fn is_keyword(&self, kw: &str) -> bool { | 113 | fn is_keyword(&self, kw: &str) -> bool { |
140 | match *self.get(self.curr.1) { | 114 | match self.cached.get(self.curr.1) { |
141 | Some(ref t) => t.text == *kw, | 115 | Some(ref t) => t.text == *kw, |
142 | _ => false, | 116 | _ => false, |
143 | } | 117 | } |
@@ -155,7 +129,7 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
155 | let idx = closing as usize; | 129 | let idx = closing as usize; |
156 | let kind = kinds[idx]; | 130 | let kind = kinds[idx]; |
157 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; | 131 | let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; |
158 | TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) } | 132 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: SmolStr::new(text) } |
159 | } | 133 | } |
160 | 134 | ||
161 | fn convert_literal(l: &tt::Literal) -> TtToken { | 135 | fn convert_literal(l: &tt::Literal) -> TtToken { |
@@ -169,7 +143,7 @@ fn convert_literal(l: &tt::Literal) -> TtToken { | |||
169 | }) | 143 | }) |
170 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); | 144 | .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l)); |
171 | 145 | ||
172 | TtToken { kind, is_joint_to_next: false, text: l.text.clone() } | 146 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: l.text.clone() } |
173 | } | 147 | } |
174 | 148 | ||
175 | fn convert_ident(ident: &tt::Ident) -> TtToken { | 149 | fn convert_ident(ident: &tt::Ident) -> TtToken { |
@@ -180,7 +154,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken { | |||
180 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), | 154 | _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT), |
181 | }; | 155 | }; |
182 | 156 | ||
183 | TtToken { kind, is_joint_to_next: false, text: ident.text.clone() } | 157 | TtToken { tt: Token { kind, is_jointed_to_next: false }, text: ident.text.clone() } |
184 | } | 158 | } |
185 | 159 | ||
186 | fn convert_punct(p: tt::Punct) -> TtToken { | 160 | fn convert_punct(p: tt::Punct) -> TtToken { |
@@ -194,7 +168,7 @@ fn convert_punct(p: tt::Punct) -> TtToken { | |||
194 | let s: &str = p.char.encode_utf8(&mut buf); | 168 | let s: &str = p.char.encode_utf8(&mut buf); |
195 | SmolStr::new(s) | 169 | SmolStr::new(s) |
196 | }; | 170 | }; |
197 | TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text } | 171 | TtToken { tt: Token { kind, is_jointed_to_next: p.spacing == tt::Spacing::Joint }, text } |
198 | } | 172 | } |
199 | 173 | ||
200 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | 174 | fn convert_leaf(leaf: &tt::Leaf) -> TtToken { |
@@ -208,6 +182,7 @@ fn convert_leaf(leaf: &tt::Leaf) -> TtToken { | |||
208 | #[cfg(test)] | 182 | #[cfg(test)] |
209 | mod tests { | 183 | mod tests { |
210 | use super::{convert_literal, TtToken}; | 184 | use super::{convert_literal, TtToken}; |
185 | use parser::Token; | ||
211 | use syntax::{SmolStr, SyntaxKind}; | 186 | use syntax::{SmolStr, SyntaxKind}; |
212 | 187 | ||
213 | #[test] | 188 | #[test] |
@@ -218,8 +193,7 @@ mod tests { | |||
218 | text: SmolStr::new("-42.0") | 193 | text: SmolStr::new("-42.0") |
219 | }), | 194 | }), |
220 | TtToken { | 195 | TtToken { |
221 | kind: SyntaxKind::FLOAT_NUMBER, | 196 | tt: Token { kind: SyntaxKind::FLOAT_NUMBER, is_jointed_to_next: false }, |
222 | is_joint_to_next: false, | ||
223 | text: SmolStr::new("-42.0") | 197 | text: SmolStr::new("-42.0") |
224 | } | 198 | } |
225 | ); | 199 | ); |
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs index 265c0d63d..671036e1c 100644 --- a/crates/mbe/src/syntax_bridge.rs +++ b/crates/mbe/src/syntax_bridge.rs | |||
@@ -70,15 +70,12 @@ pub fn token_tree_to_syntax_node( | |||
70 | tt: &tt::Subtree, | 70 | tt: &tt::Subtree, |
71 | fragment_kind: FragmentKind, | 71 | fragment_kind: FragmentKind, |
72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { | 72 | ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { |
73 | let tmp; | 73 | let buffer = match tt { |
74 | let tokens = match tt { | 74 | tt::Subtree { delimiter: None, token_trees } => { |
75 | tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(), | 75 | TokenBuffer::from_tokens(token_trees.as_slice()) |
76 | _ => { | ||
77 | tmp = [tt.clone().into()]; | ||
78 | &tmp[..] | ||
79 | } | 76 | } |
77 | _ => TokenBuffer::from_subtree(tt), | ||
80 | }; | 78 | } |