aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock96
-rw-r--r--crates/base_db/src/input.rs14
-rw-r--r--crates/hir/src/display.rs2
-rw-r--r--crates/hir/src/lib.rs5
-rw-r--r--crates/hir/src/semantics.rs27
-rw-r--r--crates/hir/src/source_analyzer.rs20
-rw-r--r--crates/hir_def/src/attr.rs24
-rw-r--r--crates/hir_def/src/data.rs4
-rw-r--r--crates/hir_def/src/generics.rs20
-rw-r--r--crates/hir_def/src/intern.rs3
-rw-r--r--crates/hir_def/src/item_tree.rs38
-rw-r--r--crates/hir_def/src/item_tree/lower.rs13
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs4
-rw-r--r--crates/hir_def/src/lib.rs8
-rw-r--r--crates/hir_def/src/nameres/collector.rs2
-rw-r--r--crates/hir_def/src/path.rs9
-rw-r--r--crates/hir_def/src/path/lower.rs15
-rw-r--r--crates/hir_def/src/type_ref.rs18
-rw-r--r--crates/hir_expand/src/db.rs16
-rw-r--r--crates/hir_expand/src/hygiene.rs2
-rw-r--r--crates/hir_expand/src/lib.rs4
-rw-r--r--crates/hir_ty/Cargo.toml6
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs12
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs2
-rw-r--r--crates/hir_ty/src/display.rs7
-rw-r--r--crates/hir_ty/src/infer.rs25
-rw-r--r--crates/hir_ty/src/infer/expr.rs34
-rw-r--r--crates/hir_ty/src/infer/unify.rs7
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/ide/src/doc_links.rs6
-rw-r--r--crates/ide/src/hover.rs20
-rw-r--r--crates/ide/src/inlay_hints.rs4
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs148
-rw-r--r--crates/ide_assists/src/handlers/fix_visibility.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_getter.rs292
-rw-r--r--crates/ide_assists/src/handlers/generate_getter_mut.rs195
-rw-r--r--crates/ide_assists/src/lib.rs6
-rw-r--r--crates/ide_assists/src/tests.rs2
-rw-r--r--crates/ide_assists/src/tests/generated.rs10
-rw-r--r--crates/ide_completion/src/context.rs116
-rw-r--r--crates/ide_completion/src/lib.rs4
-rw-r--r--crates/ide_completion/src/render.rs7
-rw-r--r--crates/ide_db/src/call_info/tests.rs18
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/ty_filter.rs6
-rw-r--r--crates/mbe/src/lib.rs10
-rw-r--r--crates/mbe/src/syntax_bridge.rs83
-rw-r--r--crates/mbe/src/tests/expand.rs5
-rw-r--r--crates/mbe/src/token_map.rs85
-rw-r--r--crates/proc_macro_api/Cargo.toml2
-rw-r--r--crates/proc_macro_srv/Cargo.toml2
-rw-r--r--crates/proc_macro_srv/src/dylib.rs2
-rw-r--r--crates/proc_macro_srv/src/tests/fixtures/test_serialize_proc_macro.txt2
-rw-r--r--crates/project_model/src/cargo_workspace.rs36
-rw-r--r--crates/project_model/src/sysroot.rs4
-rw-r--r--crates/project_model/src/workspace.rs89
-rw-r--r--crates/rust-analyzer/src/bin/main.rs3
-rw-r--r--crates/rust-analyzer/src/config.rs19
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt11
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/handles_macro_location.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt7
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_incompatible_type_for_trait.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_mismatched_type.txt2
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt5
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_wrong_number_of_parameters.txt6
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt11
-rw-r--r--crates/rust-analyzer/src/global_state.rs1
-rw-r--r--crates/rust-analyzer/src/handlers.rs35
-rw-r--r--crates/rust-analyzer/src/main_loop.rs1
-rw-r--r--crates/rust-analyzer/src/reload.rs9
-rw-r--r--crates/rust-analyzer/src/to_proto.rs2
-rw-r--r--crates/syntax/Cargo.toml2
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs21
-rw-r--r--docs/user/manual.adoc10
-rw-r--r--editors/code/src/client.ts15
-rw-r--r--editors/code/src/config.ts2
-rw-r--r--editors/code/src/ctx.ts14
-rw-r--r--editors/code/src/main.ts81
-rw-r--r--editors/code/src/snippets.ts5
-rw-r--r--xtask/src/dist.rs8
-rw-r--r--xtask/src/tidy.rs1
83 files changed, 1170 insertions, 715 deletions
diff --git a/Cargo.lock b/Cargo.lock
index 76a26ea4e..557d5f5f3 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
4 4
5[[package]] 5[[package]]
6name = "addr2line" 6name = "addr2line"
7version = "0.14.1" 7version = "0.15.1"
8source = "registry+https://github.com/rust-lang/crates.io-index" 8source = "registry+https://github.com/rust-lang/crates.io-index"
9checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7" 9checksum = "03345e98af8f3d786b6d9f656ccfa6ac316d954e92bc4841f0bba20789d5fb5a"
10dependencies = [ 10dependencies = [
11 "gimli", 11 "gimli",
12] 12]
@@ -72,9 +72,9 @@ checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
72 72
73[[package]] 73[[package]]
74name = "backtrace" 74name = "backtrace"
75version = "0.3.58" 75version = "0.3.59"
76source = "registry+https://github.com/rust-lang/crates.io-index" 76source = "registry+https://github.com/rust-lang/crates.io-index"
77checksum = "88fb5a785d6b44fd9d6700935608639af1b8356de1e55d5f7c2740f4faa15d82" 77checksum = "4717cfcbfaa661a0fd48f8453951837ae7e8f81e481fbb136e3202d72805a744"
78dependencies = [ 78dependencies = [
79 "addr2line", 79 "addr2line",
80 "cc", 80 "cc",
@@ -169,9 +169,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
169 169
170[[package]] 170[[package]]
171name = "chalk-derive" 171name = "chalk-derive"
172version = "0.64.0" 172version = "0.67.0"
173source = "registry+https://github.com/rust-lang/crates.io-index" 173source = "registry+https://github.com/rust-lang/crates.io-index"
174checksum = "d9acf2a9eab79ae7d44cd77ad86a8b1569d7a5e6d9a7db4a0a57a7344dd82c24" 174checksum = "751a3cd9eeb24d7165e9f90daf1f10a23ffa16a7986f349027f8dfb60f51ee0c"
175dependencies = [ 175dependencies = [
176 "proc-macro2", 176 "proc-macro2",
177 "quote", 177 "quote",
@@ -181,9 +181,9 @@ dependencies = [
181 181
182[[package]] 182[[package]]
183name = "chalk-ir" 183name = "chalk-ir"
184version = "0.64.0" 184version = "0.67.0"
185source = "registry+https://github.com/rust-lang/crates.io-index" 185source = "registry+https://github.com/rust-lang/crates.io-index"
186checksum = "877661627f54ba3666a72943c43b326cb170d60899e50a8426111e7a657ff032" 186checksum = "4236da905504740d3f72cc8f0509aa01321cc236208e2c33b55eda2db74bc495"
187dependencies = [ 187dependencies = [
188 "bitflags", 188 "bitflags",
189 "chalk-derive", 189 "chalk-derive",
@@ -192,9 +192,9 @@ dependencies = [
192 192
193[[package]] 193[[package]]
194name = "chalk-recursive" 194name = "chalk-recursive"
195version = "0.64.0" 195version = "0.67.0"
196source = "registry+https://github.com/rust-lang/crates.io-index" 196source = "registry+https://github.com/rust-lang/crates.io-index"
197checksum = "072ffcf17243c2aa3e4b9ea6de3d29e7ef64cfdb0ceccaa431965070a1dc1475" 197checksum = "7d0b123fe45a34c4cd5cb329650a0d163525d2acbe9d754a4538d3340884002e"
198dependencies = [ 198dependencies = [
199 "chalk-derive", 199 "chalk-derive",
200 "chalk-ir", 200 "chalk-ir",
@@ -205,9 +205,9 @@ dependencies = [
205 205
206[[package]] 206[[package]]
207name = "chalk-solve" 207name = "chalk-solve"
208version = "0.64.0" 208version = "0.67.0"
209source = "registry+https://github.com/rust-lang/crates.io-index" 209source = "registry+https://github.com/rust-lang/crates.io-index"
210checksum = "97d4920c9ef2b26dd0b98ffdf070e27fa31e0b6f637463132083cee597e3d326" 210checksum = "9c54788f0ae3b38e2bb2266f395d462d988c64f92dbd55c68219908fd1ce7ddc"
211dependencies = [ 211dependencies = [
212 "chalk-derive", 212 "chalk-derive",
213 "chalk-ir", 213 "chalk-ir",
@@ -452,9 +452,9 @@ checksum = "e398fae362f4124bbe630d99519fb2d68a03e2e3a23b441028cdcdc4f4895687"
452 452
453[[package]] 453[[package]]
454name = "gimli" 454name = "gimli"
455version = "0.23.0" 455version = "0.24.0"
456source = "registry+https://github.com/rust-lang/crates.io-index" 456source = "registry+https://github.com/rust-lang/crates.io-index"
457checksum = "f6503fe142514ca4799d4c26297c4248239fe8838d827db6bd6065c6ed29a6ce" 457checksum = "0e4075386626662786ddb0ec9081e7c7eeb1ba31951f447ca780ef9f5d568189"
458 458
459[[package]] 459[[package]]
460name = "hashbrown" 460name = "hashbrown"
@@ -715,9 +715,9 @@ dependencies = [
715 715
716[[package]] 716[[package]]
717name = "inotify" 717name = "inotify"
718version = "0.9.2" 718version = "0.9.3"
719source = "registry+https://github.com/rust-lang/crates.io-index" 719source = "registry+https://github.com/rust-lang/crates.io-index"
720checksum = "d19f57db1baad9d09e43a3cd76dcf82ebdafd37d75c9498b87762dba77c93f15" 720checksum = "b031475cb1b103ee221afb806a23d35e0570bf7271d7588762ceba8127ed43b3"
721dependencies = [ 721dependencies = [
722 "bitflags", 722 "bitflags",
723 "inotify-sys", 723 "inotify-sys",
@@ -830,9 +830,9 @@ dependencies = [
830 830
831[[package]] 831[[package]]
832name = "lsp-types" 832name = "lsp-types"
833version = "0.89.0" 833version = "0.89.1"
834source = "registry+https://github.com/rust-lang/crates.io-index" 834source = "registry+https://github.com/rust-lang/crates.io-index"
835checksum = "07731ecd4ee0654728359a5b95e2a254c857876c04b85225496a35d60345daa7" 835checksum = "48b8a871b0a450bcec0e26d74a59583c8173cb9fb7d7f98889e18abb84838e0f"
836dependencies = [ 836dependencies = [
837 "bitflags", 837 "bitflags",
838 "serde", 838 "serde",
@@ -995,9 +995,9 @@ dependencies = [
995 995
996[[package]] 996[[package]]
997name = "object" 997name = "object"
998version = "0.23.0" 998version = "0.24.0"
999source = "registry+https://github.com/rust-lang/crates.io-index" 999source = "registry+https://github.com/rust-lang/crates.io-index"
1000checksum = "a9a7ab5d64814df0fe4a4b5ead45ed6c5f181ee3ff04ba344313a6c80446c5d4" 1000checksum = "1a5b3dd1c072ee7963717671d1ca129f1048fda25edea6b752bfc71ac8854170"
1001 1001
1002[[package]] 1002[[package]]
1003name = "once_cell" 1003name = "once_cell"
@@ -1124,9 +1124,9 @@ checksum = "dbf0c48bc1d91375ae5c3cd81e3722dff1abcf81a30960240640d223f59fe0e5"
1124 1124
1125[[package]] 1125[[package]]
1126name = "proc-macro2" 1126name = "proc-macro2"
1127version = "1.0.26" 1127version = "1.0.27"
1128source = "registry+https://github.com/rust-lang/crates.io-index" 1128source = "registry+https://github.com/rust-lang/crates.io-index"
1129checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" 1129checksum = "f0d8caf72986c1a598726adc988bb5984792ef84f5ee5aa50209145ee8077038"
1130dependencies = [ 1130dependencies = [
1131 "unicode-xid", 1131 "unicode-xid",
1132] 1132]
@@ -1235,9 +1235,9 @@ dependencies = [
1235 1235
1236[[package]] 1236[[package]]
1237name = "rayon" 1237name = "rayon"
1238version = "1.5.0" 1238version = "1.5.1"
1239source = "registry+https://github.com/rust-lang/crates.io-index" 1239source = "registry+https://github.com/rust-lang/crates.io-index"
1240checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" 1240checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90"
1241dependencies = [ 1241dependencies = [
1242 "autocfg", 1242 "autocfg",
1243 "crossbeam-deque", 1243 "crossbeam-deque",
@@ -1247,9 +1247,9 @@ dependencies = [
1247 1247
1248[[package]] 1248[[package]]
1249name = "rayon-core" 1249name = "rayon-core"
1250version = "1.9.0" 1250version = "1.9.1"
1251source = "registry+https://github.com/rust-lang/crates.io-index" 1251source = "registry+https://github.com/rust-lang/crates.io-index"
1252checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" 1252checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e"
1253dependencies = [ 1253dependencies = [
1254 "crossbeam-channel", 1254 "crossbeam-channel",
1255 "crossbeam-deque", 1255 "crossbeam-deque",
@@ -1260,18 +1260,18 @@ dependencies = [
1260 1260
1261[[package]] 1261[[package]]
1262name = "redox_syscall" 1262name = "redox_syscall"
1263version = "0.2.7" 1263version = "0.2.8"
1264source = "registry+https://github.com/rust-lang/crates.io-index" 1264source = "registry+https://github.com/rust-lang/crates.io-index"
1265checksum = "85dd92e586f7355c633911e11f77f3d12f04b1b1bd76a198bd34ae3af8341ef2" 1265checksum = "742739e41cd49414de871ea5e549afb7e2a3ac77b589bcbebe8c82fab37147fc"
1266dependencies = [ 1266dependencies = [
1267 "bitflags", 1267 "bitflags",
1268] 1268]
1269 1269
1270[[package]] 1270[[package]]
1271name = "regex" 1271name = "regex"
1272version = "1.5.3" 1272version = "1.5.4"
1273source = "registry+https://github.com/rust-lang/crates.io-index" 1273source = "registry+https://github.com/rust-lang/crates.io-index"
1274checksum = "ce5f1ceb7f74abbce32601642fcf8e8508a8a8991e0621c7d750295b9095702b" 1274checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
1275dependencies = [ 1275dependencies = [
1276 "regex-syntax", 1276 "regex-syntax",
1277] 1277]
@@ -1359,18 +1359,18 @@ dependencies = [
1359 1359
1360[[package]] 1360[[package]]
1361name = "rustc-ap-rustc_lexer" 1361name = "rustc-ap-rustc_lexer"
1362version = "716.0.0" 1362version = "720.0.0"
1363source = "registry+https://github.com/rust-lang/crates.io-index" 1363source = "registry+https://github.com/rust-lang/crates.io-index"
1364checksum = "12eac7554c1d3f49f105f14d53c0f3402220e875983113562701d8e597a0995c" 1364checksum = "a025b453b0ae85335336f991f920ca9af5c0dc851171cb9035a16cea5619e9b2"
1365dependencies = [ 1365dependencies = [
1366 "unicode-xid", 1366 "unicode-xid",
1367] 1367]
1368 1368
1369[[package]] 1369[[package]]
1370name = "rustc-demangle" 1370name = "rustc-demangle"
1371version = "0.1.18" 1371version = "0.1.19"
1372source = "registry+https://github.com/rust-lang/crates.io-index" 1372source = "registry+https://github.com/rust-lang/crates.io-index"
1373checksum = "6e3bad0ee36814ca07d7968269dd4b7ec89ec2da10c4bb613928d3077083c232" 1373checksum = "410f7acf3cb3a44527c5d9546bad4bf4e6c460915d5f9f2fc524498bfe8f70ce"
1374 1374
1375[[package]] 1375[[package]]
1376name = "rustc-hash" 1376name = "rustc-hash"
@@ -1455,18 +1455,18 @@ dependencies = [
1455 1455
1456[[package]] 1456[[package]]
1457name = "serde" 1457name = "serde"
1458version = "1.0.125" 1458version = "1.0.126"
1459source = "registry+https://github.com/rust-lang/crates.io-index" 1459source = "registry+https://github.com/rust-lang/crates.io-index"
1460checksum = "558dc50e1a5a5fa7112ca2ce4effcb321b0300c0d4ccf0776a9f60cd89031171" 1460checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03"
1461dependencies = [ 1461dependencies = [
1462 "serde_derive", 1462 "serde_derive",
1463] 1463]
1464 1464
1465[[package]] 1465[[package]]
1466name = "serde_derive" 1466name = "serde_derive"
1467version = "1.0.125" 1467version = "1.0.126"
1468source = "registry+https://github.com/rust-lang/crates.io-index" 1468source = "registry+https://github.com/rust-lang/crates.io-index"
1469checksum = "b093b7a2bb58203b5da3056c05b4ec1fed827dcfdb37347a8841695263b3d06d" 1469checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43"
1470dependencies = [ 1470dependencies = [
1471 "proc-macro2", 1471 "proc-macro2",
1472 "quote", 1472 "quote",
@@ -1496,9 +1496,9 @@ dependencies = [
1496 1496
1497[[package]] 1497[[package]]
1498name = "serde_repr" 1498name = "serde_repr"
1499version = "0.1.6" 1499version = "0.1.7"
1500source = "registry+https://github.com/rust-lang/crates.io-index" 1500source = "registry+https://github.com/rust-lang/crates.io-index"
1501checksum = "2dc6b7951b17b051f3210b063f12cc17320e2fe30ae05b0fe2a3abb068551c76" 1501checksum = "98d0516900518c29efa217c298fa1f4e6c6ffc85ae29fd7f4ee48f176e1a9ed5"
1502dependencies = [ 1502dependencies = [
1503 "proc-macro2", 1503 "proc-macro2",
1504 "quote", 1504 "quote",
@@ -1548,9 +1548,9 @@ dependencies = [
1548 1548
1549[[package]] 1549[[package]]
1550name = "syn" 1550name = "syn"
1551version = "1.0.71" 1551version = "1.0.72"
1552source = "registry+https://github.com/rust-lang/crates.io-index" 1552source = "registry+https://github.com/rust-lang/crates.io-index"
1553checksum = "ad184cc9470f9117b2ac6817bfe297307418819ba40552f9b3846f05c33d5373" 1553checksum = "a1e8cdbefb79a9a5a65e0db8b47b723ee907b7c7f8496c76a1770b5c310bab82"
1554dependencies = [ 1554dependencies = [
1555 "proc-macro2", 1555 "proc-macro2",
1556 "quote", 1556 "quote",
@@ -1848,9 +1848,9 @@ checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3"
1848 1848
1849[[package]] 1849[[package]]
1850name = "url" 1850name = "url"
1851version = "2.2.1" 1851version = "2.2.2"
1852source = "registry+https://github.com/rust-lang/crates.io-index" 1852source = "registry+https://github.com/rust-lang/crates.io-index"
1853checksum = "9ccd964113622c8e9322cfac19eb1004a07e636c545f325da085d5cdde6f1f8b" 1853checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c"
1854dependencies = [ 1854dependencies = [
1855 "form_urlencoded", 1855 "form_urlencoded",
1856 "idna", 1856 "idna",
@@ -1957,18 +1957,18 @@ dependencies = [
1957 1957
1958[[package]] 1958[[package]]
1959name = "xshell" 1959name = "xshell"
1960version = "0.1.10" 1960version = "0.1.13"
1961source = "registry+https://github.com/rust-lang/crates.io-index" 1961source = "registry+https://github.com/rust-lang/crates.io-index"
1962checksum = "aa25217c682f9f991d7889238a99e65eb8431c266d36e0f4e850a73773415473" 1962checksum = "eb15bb1b41eb14efe628006294c294e10c366e03a0283b9c2063fc27d97934c6"
1963dependencies = [ 1963dependencies = [
1964 "xshell-macros", 1964 "xshell-macros",
1965] 1965]
1966 1966
1967[[package]] 1967[[package]]
1968name = "xshell-macros" 1968name = "xshell-macros"
1969version = "0.1.10" 1969version = "0.1.13"
1970source = "registry+https://github.com/rust-lang/crates.io-index" 1970source = "registry+https://github.com/rust-lang/crates.io-index"
1971checksum = "4404d53d2113af4fa31c58326eb7b37d6d7bf11ba87520787cddeaff45385c72" 1971checksum = "cf7ed94a2c75b9bcc57031229be2b57ee47ba71122f71aabef8610ec66a97e52"
1972 1972
1973[[package]] 1973[[package]]
1974name = "xtask" 1974name = "xtask"
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 0ef77ef5d..64ccd11ee 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -53,11 +53,15 @@ impl SourceRoot {
53} 53}
54 54
55/// `CrateGraph` is a bit of information which turns a set of text files into a 55/// `CrateGraph` is a bit of information which turns a set of text files into a
56/// number of Rust crates. Each crate is defined by the `FileId` of its root module, 56/// number of Rust crates.
57/// the set of cfg flags (not yet implemented) and the set of dependencies. Note 57///
58/// that, due to cfg's, there might be several crates for a single `FileId`! As 58/// Each crate is defined by the `FileId` of its root module, the set of enabled
59/// in the rust-lang proper, a crate does not have a name. Instead, names are 59/// `cfg` flags and the set of dependencies.
60/// specified on dependency edges. That is, a crate might be known under 60///
61/// Note that, due to cfg's, there might be several crates for a single `FileId`!
62///
63/// For the purposes of analysis, a crate does not have a name. Instead, names
64/// are specified on dependency edges. That is, a crate might be known under
61/// different names in different dependent crates. 65/// different names in different dependent crates.
62/// 66///
63/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust 67/// Note that `CrateGraph` is build-system agnostic: it's a concept of the Rust
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 508ac37c2..c5cf803fd 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -92,7 +92,7 @@ impl HirDisplay for Function {
92 &data.ret_type 92 &data.ret_type
93 } else { 93 } else {
94 match &*data.ret_type { 94 match &*data.ret_type {
95 TypeRef::ImplTrait(bounds) => match &bounds[0] { 95 TypeRef::ImplTrait(bounds) => match bounds[0].as_ref() {
96 TypeBound::Path(path) => { 96 TypeBound::Path(path) => {
97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings 97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
98 [0] 98 [0]
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index ec5f0c53d..cdf65a044 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -513,9 +513,8 @@ impl Field {
513 } 513 }
514 514
515 /// Returns the type as in the signature of the struct (i.e., with 515 /// Returns the type as in the signature of the struct (i.e., with
516 /// placeholder types for type parameters). This is good for showing 516 /// placeholder types for type parameters). Only use this in the context of
517 /// signature help, but not so good to actually get the type of the field 517 /// the field definition.
518 /// when you actually have a variable of the struct.
519 pub fn ty(&self, db: &dyn HirDatabase) -> Type { 518 pub fn ty(&self, db: &dyn HirDatabase) -> Type {
520 let var_id = self.parent.into(); 519 let var_id = self.parent.into();
521 let generic_def_id: GenericDefId = match self.parent { 520 let generic_def_id: GenericDefId = match self.parent {
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 1b5064b5a..8d3c43d08 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -11,7 +11,7 @@ use hir_def::{
11 AsMacroCall, FunctionId, TraitId, VariantId, 11 AsMacroCall, FunctionId, TraitId, VariantId,
12}; 12};
13use hir_expand::{name::AsName, ExpansionInfo}; 13use hir_expand::{name::AsName, ExpansionInfo};
14use hir_ty::associated_type_shorthand_candidates; 14use hir_ty::{associated_type_shorthand_candidates, Interner};
15use itertools::Itertools; 15use itertools::Itertools;
16use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
17use syntax::{ 17use syntax::{
@@ -120,10 +120,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
120 pub fn speculative_expand( 120 pub fn speculative_expand(
121 &self, 121 &self,
122 actual_macro_call: &ast::MacroCall, 122 actual_macro_call: &ast::MacroCall,
123 hypothetical_args: &ast::TokenTree, 123 speculative_args: &ast::TokenTree,
124 token_to_map: SyntaxToken, 124 token_to_map: SyntaxToken,
125 ) -> Option<(SyntaxNode, SyntaxToken)> { 125 ) -> Option<(SyntaxNode, SyntaxToken)> {
126 self.imp.speculative_expand(actual_macro_call, hypothetical_args, token_to_map) 126 self.imp.speculative_expand(actual_macro_call, speculative_args, token_to_map)
127 } 127 }
128 128
129 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken { 129 pub fn descend_into_macros(&self, token: SyntaxToken) -> SyntaxToken {
@@ -227,7 +227,7 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
227 pub fn resolve_record_field( 227 pub fn resolve_record_field(
228 &self, 228 &self,
229 field: &ast::RecordExprField, 229 field: &ast::RecordExprField,
230 ) -> Option<(Field, Option<Local>)> { 230 ) -> Option<(Field, Option<Local>, Type)> {
231 self.imp.resolve_record_field(field) 231 self.imp.resolve_record_field(field)
232 } 232 }
233 233
@@ -335,7 +335,7 @@ impl<'db> SemanticsImpl<'db> {
335 fn speculative_expand( 335 fn speculative_expand(
336 &self, 336 &self,
337 actual_macro_call: &ast::MacroCall, 337 actual_macro_call: &ast::MacroCall,
338 hypothetical_args: &ast::TokenTree, 338 speculative_args: &ast::TokenTree,
339 token_to_map: SyntaxToken, 339 token_to_map: SyntaxToken,
340 ) -> Option<(SyntaxNode, SyntaxToken)> { 340 ) -> Option<(SyntaxNode, SyntaxToken)> {
341 let sa = self.analyze(actual_macro_call.syntax()); 341 let sa = self.analyze(actual_macro_call.syntax());
@@ -344,10 +344,10 @@ impl<'db> SemanticsImpl<'db> {
344 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| { 344 let macro_call_id = macro_call.as_call_id(self.db.upcast(), krate, |path| {
345 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path) 345 sa.resolver.resolve_path_as_macro(self.db.upcast(), &path)
346 })?; 346 })?;
347 hir_expand::db::expand_hypothetical( 347 hir_expand::db::expand_speculative(
348 self.db.upcast(), 348 self.db.upcast(),
349 macro_call_id, 349 macro_call_id,
350 hypothetical_args, 350 speculative_args,
351 token_to_map, 351 token_to_map,
352 ) 352 )
353 } 353 }
@@ -501,14 +501,12 @@ impl<'db> SemanticsImpl<'db> {
501 } 501 }
502 502
503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> { 503 fn resolve_method_call(&self, call: &ast::MethodCallExpr) -> Option<FunctionId> {
504 self.analyze(call.syntax()).resolve_method_call(self.db, call) 504 self.analyze(call.syntax()).resolve_method_call(self.db, call).map(|(id, _)| id)
505 } 505 }
506 506
507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 507 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
508 // FIXME: this erases Substs, we should instead record the correct 508 let (func, subst) = self.analyze(call.syntax()).resolve_method_call(self.db, call)?;
509 // substitution during inference and use that 509 let ty = self.db.value_ty(func.into()).substitute(&Interner, &subst);
510 let func = self.resolve_method_call(call)?;
511 let ty = hir_ty::TyBuilder::value_ty(self.db, func.into()).fill_with_unknown().build();
512 let resolver = self.analyze(call.syntax()).resolver; 510 let resolver = self.analyze(call.syntax()).resolver;
513 let ty = Type::new_with_resolver(self.db, &resolver, ty)?; 511 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
514 let mut res = ty.as_callable(self.db)?; 512 let mut res = ty.as_callable(self.db)?;
@@ -520,7 +518,10 @@ impl<'db> SemanticsImpl<'db> {
520 self.analyze(field.syntax()).resolve_field(self.db, field) 518 self.analyze(field.syntax()).resolve_field(self.db, field)
521 } 519 }
522 520
523 fn resolve_record_field(&self, field: &ast::RecordExprField) -> Option<(Field, Option<Local>)> { 521 fn resolve_record_field(
522 &self,
523 field: &ast::RecordExprField,
524 ) -> Option<(Field, Option<Local>, Type)> {
524 self.analyze(field.syntax()).resolve_record_field(self.db, field) 525 self.analyze(field.syntax()).resolve_record_field(self.db, field)
525 } 526 }
526 527
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index b5c65808e..3f940124c 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -143,7 +143,7 @@ impl SourceAnalyzer {
143 &self, 143 &self,
144 db: &dyn HirDatabase, 144 db: &dyn HirDatabase,
145 call: &ast::MethodCallExpr, 145 call: &ast::MethodCallExpr,
146 ) -> Option<FunctionId> { 146 ) -> Option<(FunctionId, Substitution)> {
147 let expr_id = self.expr_id(db, &call.clone().into())?; 147 let expr_id = self.expr_id(db, &call.clone().into())?;
148 self.infer.as_ref()?.method_resolution(expr_id) 148 self.infer.as_ref()?.method_resolution(expr_id)
149 } 149 }
@@ -161,7 +161,7 @@ impl SourceAnalyzer {
161 &self, 161 &self,
162 db: &dyn HirDatabase, 162 db: &dyn HirDatabase,
163 field: &ast::RecordExprField, 163 field: &ast::RecordExprField,
164 ) -> Option<(Field, Option<Local>)> { 164 ) -> Option<(Field, Option<Local>, Type)> {
165 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?; 165 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
166 let expr = ast::Expr::from(record_expr); 166 let expr = ast::Expr::from(record_expr);
167 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?; 167 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
@@ -178,10 +178,13 @@ impl SourceAnalyzer {
178 _ => None, 178 _ => None,
179 } 179 }
180 }; 180 };
181 let (_, subst) = self.infer.as_ref()?.type_of_expr.get(expr_id)?.as_adt()?;
181 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?; 182 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
182 let variant_data = variant.variant_data(db.upcast()); 183 let variant_data = variant.variant_data(db.upcast());
183 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? }; 184 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
184 Some((field.into(), local)) 185 let field_ty =
186 db.field_types(variant).get(field.local_id)?.clone().substitute(&Interner, subst);
187 Some((field.into(), local, Type::new_with_resolver(db, &self.resolver, field_ty)?))
185 } 188 }
186 189
187 pub(crate) fn resolve_record_pat_field( 190 pub(crate) fn resolve_record_pat_field(
@@ -286,7 +289,7 @@ impl SourceAnalyzer {
286 let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene); 289 let ctx = body::LowerCtx::with_hygiene(db.upcast(), &hygiene);
287 let hir_path = Path::from_src(path.clone(), &ctx)?; 290 let hir_path = Path::from_src(path.clone(), &ctx)?;
288 291
289 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we 292 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we are
290 // trying to resolve foo::bar. 293 // trying to resolve foo::bar.
291 if let Some(outer_path) = parent().and_then(ast::Path::cast) { 294 if let Some(outer_path) = parent().and_then(ast::Path::cast) {
292 if let Some(qualifier) = outer_path.qualifier() { 295 if let Some(qualifier) = outer_path.qualifier() {
@@ -295,6 +298,15 @@ impl SourceAnalyzer {
295 } 298 }
296 } 299 }
297 } 300 }
301 // Case where path is a qualifier of a use tree, e.g. foo::bar::{Baz, Qux} where we are
302 // trying to resolve foo::bar.
303 if let Some(use_tree) = parent().and_then(ast::UseTree::cast) {
304 if let Some(qualifier) = use_tree.path() {
305 if path == &qualifier && use_tree.coloncolon_token().is_some() {
306 return resolve_hir_path_qualifier(db, &self.resolver, &hir_path);
307 }
308 }
309 }
298 310
299 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns) 311 resolve_hir_path_(db, &self.resolver, &hir_path, prefer_value_ns)
300 } 312 }
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 89a1ea770..385ba8c80 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -105,7 +105,7 @@ impl RawAttrs {
105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id), 105 Either::Left(attr) => Attr::from_src(db, attr, hygiene, id),
106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 106 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
107 id, 107 id,
108 input: Some(AttrInput::Literal(SmolStr::new(doc))), 108 input: Some(Interned::new(AttrInput::Literal(SmolStr::new(doc)))),
109 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 109 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
110 }), 110 }),
111 }) 111 })
@@ -151,7 +151,7 @@ impl RawAttrs {
151 return smallvec![attr.clone()]; 151 return smallvec![attr.clone()];
152 } 152 }
153 153
154 let subtree = match &attr.input { 154 let subtree = match attr.input.as_deref() {
155 Some(AttrInput::TokenTree(it)) => it, 155 Some(AttrInput::TokenTree(it)) => it,
156 _ => return smallvec![attr.clone()], 156 _ => return smallvec![attr.clone()],
157 }; 157 };
@@ -251,7 +251,7 @@ impl Attrs {
251 } 251 }
252 252
253 pub fn docs(&self) -> Option<Documentation> { 253 pub fn docs(&self) -> Option<Documentation> {
254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 254 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
255 AttrInput::Literal(s) => Some(s), 255 AttrInput::Literal(s) => Some(s),
256 AttrInput::TokenTree(_) => None, 256 AttrInput::TokenTree(_) => None,
257 }); 257 });
@@ -454,7 +454,7 @@ impl AttrsWithOwner {
454 db: &dyn DefDatabase, 454 db: &dyn DefDatabase,
455 ) -> Option<(Documentation, DocsRangeMap)> { 455 ) -> Option<(Documentation, DocsRangeMap)> {
456 // FIXME: code duplication in `docs` above 456 // FIXME: code duplication in `docs` above
457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? { 457 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_deref()? {
458 AttrInput::Literal(s) => Some((s, attr.id)), 458 AttrInput::Literal(s) => Some((s, attr.id)),
459 AttrInput::TokenTree(_) => None, 459 AttrInput::TokenTree(_) => None,
460 }); 460 });
@@ -637,10 +637,10 @@ pub(crate) struct AttrId {
637pub struct Attr { 637pub struct Attr {
638 pub(crate) id: AttrId, 638 pub(crate) id: AttrId,
639 pub(crate) path: Interned<ModPath>, 639 pub(crate) path: Interned<ModPath>,
640 pub(crate) input: Option<AttrInput>, 640 pub(crate) input: Option<Interned<AttrInput>>,
641} 641}
642 642
643#[derive(Debug, Clone, PartialEq, Eq)] 643#[derive(Debug, Clone, PartialEq, Eq, Hash)]
644pub enum AttrInput { 644pub enum AttrInput {
645 /// `#[attr = "string"]` 645 /// `#[attr = "string"]`
646 Literal(SmolStr), 646 Literal(SmolStr),
@@ -670,9 +670,9 @@ impl Attr {
670 ast::LiteralKind::String(string) => string.value()?.into(), 670 ast::LiteralKind::String(string) => string.value()?.into(),
671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(), 671 _ => lit.syntax().first_token()?.text().trim_matches('"').into(),
672 }; 672 };
673 Some(AttrInput::Literal(value)) 673 Some(Interned::new(AttrInput::Literal(value)))
674 } else if let Some(tt) = ast.token_tree() { 674 } else if let Some(tt) = ast.token_tree() {
675 Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0)) 675 Some(Interned::new(AttrInput::TokenTree(ast_to_token_tree(&tt).0)))
676 } else { 676 } else {
677 None 677 None
678 }; 678 };
@@ -688,7 +688,7 @@ impl Attr {
688 return None; 688 return None;
689 } 689 }
690 690
691 match &self.input { 691 match self.input.as_deref() {
692 Some(AttrInput::TokenTree(args)) => { 692 Some(AttrInput::TokenTree(args)) => {
693 let mut counter = 0; 693 let mut counter = 0;
694 let paths = args 694 let paths = args
@@ -720,7 +720,7 @@ impl Attr {
720 } 720 }
721 721
722 pub fn string_value(&self) -> Option<&SmolStr> { 722 pub fn string_value(&self) -> Option<&SmolStr> {
723 match self.input.as_ref()? { 723 match self.input.as_deref()? {
724 AttrInput::Literal(it) => Some(it), 724 AttrInput::Literal(it) => Some(it),
725 _ => None, 725 _ => None,
726 } 726 }
@@ -735,14 +735,14 @@ pub struct AttrQuery<'a> {
735 735
736impl<'a> AttrQuery<'a> { 736impl<'a> AttrQuery<'a> {
737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> { 737 pub fn tt_values(self) -> impl Iterator<Item = &'a Subtree> {
738 self.attrs().filter_map(|attr| match attr.input.as_ref()? { 738 self.attrs().filter_map(|attr| match attr.input.as_deref()? {
739 AttrInput::TokenTree(it) => Some(it), 739 AttrInput::TokenTree(it) => Some(it),
740 _ => None, 740 _ => None,
741 }) 741 })
742 } 742 }
743 743
744 pub fn string_value(self) -> Option<&'a SmolStr> { 744 pub fn string_value(self) -> Option<&'a SmolStr> {
745 self.attrs().find_map(|attr| match attr.input.as_ref()? { 745 self.attrs().find_map(|attr| match attr.input.as_deref()? {
746 AttrInput::Literal(it) => Some(it), 746 AttrInput::Literal(it) => Some(it),
747 _ => None, 747 _ => None,
748 }) 748 })
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 135a6698e..8bcac60ef 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -112,7 +112,7 @@ pub struct TypeAliasData {
112 pub visibility: RawVisibility, 112 pub visibility: RawVisibility,
113 pub is_extern: bool, 113 pub is_extern: bool,
114 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). 114 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
115 pub bounds: Vec<TypeBound>, 115 pub bounds: Vec<Interned<TypeBound>>,
116} 116}
117 117
118impl TypeAliasData { 118impl TypeAliasData {
@@ -141,7 +141,7 @@ pub struct TraitData {
141 pub is_auto: bool, 141 pub is_auto: bool,
142 pub is_unsafe: bool, 142 pub is_unsafe: bool,
143 pub visibility: RawVisibility, 143 pub visibility: RawVisibility,
144 pub bounds: Box<[TypeBound]>, 144 pub bounds: Box<[Interned<TypeBound>]>,
145} 145}
146 146
147impl TraitData { 147impl TraitData {
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index de5acced8..44d22b918 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -68,9 +68,19 @@ pub struct GenericParams {
68/// associated type bindings like `Iterator<Item = u32>`. 68/// associated type bindings like `Iterator<Item = u32>`.
69#[derive(Clone, PartialEq, Eq, Debug, Hash)] 69#[derive(Clone, PartialEq, Eq, Debug, Hash)]
70pub enum WherePredicate { 70pub enum WherePredicate {
71 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, 71 TypeBound {
72 Lifetime { target: LifetimeRef, bound: LifetimeRef }, 72 target: WherePredicateTypeTarget,
73 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, 73 bound: Interned<TypeBound>,
74 },
75 Lifetime {
76 target: LifetimeRef,
77 bound: LifetimeRef,
78 },
79 ForLifetime {
80 lifetimes: Box<[Name]>,
81 target: WherePredicateTypeTarget,
82 bound: Interned<TypeBound>,
83 },
74} 84}
75 85
76#[derive(Clone, PartialEq, Eq, Debug, Hash)] 86#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -339,11 +349,11 @@ impl GenericParams {
339 Some(hrtb_lifetimes) => WherePredicate::ForLifetime { 349 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
340 lifetimes: hrtb_lifetimes.clone(), 350 lifetimes: hrtb_lifetimes.clone(),
341 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 351 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
342 bound, 352 bound: Interned::new(bound),
343 }, 353 },
344 None => WherePredicate::TypeBound { 354 None => WherePredicate::TypeBound {
345 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)), 355 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
346 bound, 356 bound: Interned::new(bound),
347 }, 357 },
348 }, 358 },
349 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => { 359 (Either::Right(lifetime), TypeBound::Lifetime(bound)) => {
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs
index 5cc7f2df6..79ba970e7 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -216,7 +216,10 @@ pub use crate::_impl_internable as impl_internable;
216impl_internable!( 216impl_internable!(
217 crate::type_ref::TypeRef, 217 crate::type_ref::TypeRef,
218 crate::type_ref::TraitRef, 218 crate::type_ref::TraitRef,
219 crate::type_ref::TypeBound,
219 crate::path::ModPath, 220 crate::path::ModPath,
221 crate::path::GenericArgs,
222 crate::attr::AttrInput,
220 GenericParams, 223 GenericParams,
221 str, 224 str,
222); 225);
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 528270d49..11767d100 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -1,4 +1,34 @@
1//! A simplified AST that only contains items. 1//! A simplified AST that only contains items.
2//!
3//! This is the primary IR used throughout `hir_def`. It is the input to the name resolution
4//! algorithm, as well as to the queries defined in `adt.rs`, `data.rs`, and most things in
5//! `attr.rs`.
6//!
7//! `ItemTree`s are built per `HirFileId`, from the syntax tree of the parsed file. This means that
8//! they are crate-independent: they don't know which `#[cfg]`s are active or which module they
9//! belong to, since those concepts don't exist at this level (a single `ItemTree` might be part of
10//! multiple crates, or might be included into the same crate twice via `#[path]`).
11//!
12//! One important purpose of this layer is to provide an "invalidation barrier" for incremental
13//! computations: when typing inside an item body, the `ItemTree` of the modified file is typically
14//! unaffected, so we don't have to recompute name resolution results or item data (see `data.rs`).
15//!
16//! The `ItemTree` for the currently open file can be displayed by using the VS Code command
17//! "Rust Analyzer: Debug ItemTree".
18//!
19//! Compared to rustc's architecture, `ItemTree` has properties from both rustc's AST and HIR: many
20//! syntax-level Rust features are already desugared to simpler forms in the `ItemTree`, but name
21//! resolution has not yet been performed. `ItemTree`s are per-file, while rustc's AST and HIR are
22//! per-crate, because we are interested in incrementally computing it.
23//!
24//! The representation of items in the `ItemTree` should generally mirror the surface syntax: it is
25//! usually a bad idea to desugar a syntax-level construct to something that is structurally
26//! different here. Name resolution needs to be able to process attributes and expand macros
27//! (including attribute macros), and having a 1-to-1 mapping between syntax and the `ItemTree`
28//! avoids introducing subtle bugs.
29//!
30//! In general, any item in the `ItemTree` stores its `AstId`, which allows mapping it back to its
31//! surface syntax.
2 32
3mod lower; 33mod lower;
4mod pretty; 34mod pretty;
@@ -500,8 +530,8 @@ pub struct Import {
500 pub alias: Option<ImportAlias>, 530 pub alias: Option<ImportAlias>,
501 pub visibility: RawVisibilityId, 531 pub visibility: RawVisibilityId,
502 pub is_glob: bool, 532 pub is_glob: bool,
503 /// AST ID of the `use` or `extern crate` item this import was derived from. Note that many 533 /// AST ID of the `use` item this import was derived from. Note that many `Import`s can map to
504 /// `Import`s can map to the same `use` item. 534 /// the same `use` item.
505 pub ast_id: FileAstId<ast::Use>, 535 pub ast_id: FileAstId<ast::Use>,
506 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`. 536 /// Index of this `Import` when the containing `Use` is visited via `ModPath::expand_use_item`.
507 /// 537 ///
@@ -614,7 +644,7 @@ pub struct Trait {
614 pub generic_params: Interned<GenericParams>, 644 pub generic_params: Interned<GenericParams>,
615 pub is_auto: bool, 645 pub is_auto: bool,
616 pub is_unsafe: bool, 646 pub is_unsafe: bool,
617 pub bounds: Box<[TypeBound]>, 647 pub bounds: Box<[Interned<TypeBound>]>,
618 pub items: Box<[AssocItem]>, 648 pub items: Box<[AssocItem]>,
619 pub ast_id: FileAstId<ast::Trait>, 649 pub ast_id: FileAstId<ast::Trait>,
620} 650}
@@ -634,7 +664,7 @@ pub struct TypeAlias {
634 pub name: Name, 664 pub name: Name,
635 pub visibility: RawVisibilityId, 665 pub visibility: RawVisibilityId,
636 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 666 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
637 pub bounds: Box<[TypeBound]>, 667 pub bounds: Box<[Interned<TypeBound>]>,
638 pub generic_params: Interned<GenericParams>, 668 pub generic_params: Interned<GenericParams>,
639 pub type_ref: Option<Interned<TypeRef>>, 669 pub type_ref: Option<Interned<TypeRef>>,
640 pub is_extern: bool, 670 pub is_extern: bool,
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 91cf75371..b4389371f 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -384,7 +384,7 @@ impl<'a> Ctx<'a> {
384 384
385 let ret_type = if func.async_token().is_some() { 385 let ret_type = if func.async_token().is_some() {
386 let future_impl = desugar_future_path(ret_type); 386 let future_impl = desugar_future_path(ret_type);
387 let ty_bound = TypeBound::Path(future_impl); 387 let ty_bound = Interned::new(TypeBound::Path(future_impl));
388 TypeRef::ImplTrait(vec![ty_bound]) 388 TypeRef::ImplTrait(vec![ty_bound])
389 } else { 389 } else {
390 ret_type 390 ret_type
@@ -738,11 +738,12 @@ impl<'a> Ctx<'a> {
738 Interned::new(generics) 738 Interned::new(generics)
739 } 739 }
740 740
741 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { 741 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<Interned<TypeBound>> {
742 match node.type_bound_list() { 742 match node.type_bound_list() {
743 Some(bound_list) => { 743 Some(bound_list) => bound_list
744 bound_list.bounds().map(|it| TypeBound::from_ast(&self.body_ctx, it)).collect() 744 .bounds()
745 } 745 .map(|it| Interned::new(TypeBound::from_ast(&self.body_ctx, it)))
746 .collect(),
746 None => Vec::new(), 747 None => Vec::new(),
747 } 748 }
748 } 749 }
@@ -810,7 +811,7 @@ fn desugar_future_path(orig: TypeRef) -> Path {
810 let binding = 811 let binding =
811 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() }; 812 AssociatedTypeBinding { name: name![Output], type_ref: Some(orig), bounds: Vec::new() };
812 last.bindings.push(binding); 813 last.bindings.push(binding);
813 generic_args.push(Some(Arc::new(last))); 814 generic_args.push(Some(Interned::new(last)));
814 815
815 Path::from_known_path(path, generic_args) 816 Path::from_known_path(path, generic_args)
816} 817}
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 4bc87a0e2..9394a5de6 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -513,13 +513,13 @@ impl<'a> Printer<'a> {
513 } 513 }
514 } 514 }
515 515
516 fn print_type_bounds(&mut self, bounds: &[TypeBound]) { 516 fn print_type_bounds(&mut self, bounds: &[Interned<TypeBound>]) {
517 for (i, bound) in bounds.iter().enumerate() { 517 for (i, bound) in bounds.iter().enumerate() {
518 if i != 0 { 518 if i != 0 {
519 w!(self, " + "); 519 w!(self, " + ");
520 } 520 }
521 521
522 match bound { 522 match bound.as_ref() {
523 TypeBound::Path(path) => self.print_path(path), 523 TypeBound::Path(path) => self.print_path(path),
524 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name), 524 TypeBound::Lifetime(lt) => w!(self, "{}", lt.name),
525 TypeBound::Error => w!(self, "{{unknown}}"), 525 TypeBound::Error => w!(self, "{{unknown}}"),
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index a82ea5957..70001cac8 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -485,6 +485,14 @@ impl VariantId {
485 VariantId::UnionId(it) => it.lookup(db).id.file_id(), 485 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
486 } 486 }
487 } 487 }
488
489 pub fn adt_id(self) -> AdtId {
490 match self {
491 VariantId::EnumVariantId(it) => it.parent.into(),
492 VariantId::StructId(it) => it.into(),
493 VariantId::UnionId(it) => it.into(),
494 }
495 }
488} 496}
489 497
490trait Intern { 498trait Intern {
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 014ea4de4..2ae740d0e 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -285,7 +285,7 @@ impl DefCollector<'_> {
285 let registered_name = if *attr_name == hir_expand::name![register_attr] 285 let registered_name = if *attr_name == hir_expand::name![register_attr]
286 || *attr_name == hir_expand::name![register_tool] 286 || *attr_name == hir_expand::name![register_tool]
287 { 287 {
288 match &attr.input { 288 match attr.input.as_deref() {
289 Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees { 289 Some(AttrInput::TokenTree(subtree)) => match &*subtree.token_trees {
290 [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(), 290 [tt::TokenTree::Leaf(tt::Leaf::Ident(name))] => name.as_name(),
291 _ => continue, 291 _ => continue,
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 9b8873fd2..45ab9d0ff 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -4,7 +4,6 @@ mod lower;
4use std::{ 4use std::{
5 fmt::{self, Display}, 5 fmt::{self, Display},
6 iter, 6 iter,
7 sync::Arc,
8}; 7};
9 8
10use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef}; 9use crate::{body::LowerCtx, db::DefDatabase, intern::Interned, type_ref::LifetimeRef};
@@ -136,7 +135,7 @@ pub struct Path {
136 type_anchor: Option<Interned<TypeRef>>, 135 type_anchor: Option<Interned<TypeRef>>,
137 mod_path: Interned<ModPath>, 136 mod_path: Interned<ModPath>,
138 /// Invariant: the same len as `self.mod_path.segments` 137 /// Invariant: the same len as `self.mod_path.segments`
139 generic_args: Vec<Option<Arc<GenericArgs>>>, 138 generic_args: Vec<Option<Interned<GenericArgs>>>,
140} 139}
141 140
142/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 141/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
@@ -165,7 +164,7 @@ pub struct AssociatedTypeBinding {
165 /// Bounds for the associated type, like in `Iterator<Item: 164 /// Bounds for the associated type, like in `Iterator<Item:
166 /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds` 165 /// SomeOtherTrait>`. (This is the unstable `associated_type_bounds`
167 /// feature.) 166 /// feature.)
168 pub bounds: Vec<TypeBound>, 167 pub bounds: Vec<Interned<TypeBound>>,
169} 168}
170 169
171/// A single generic argument. 170/// A single generic argument.
@@ -185,7 +184,7 @@ impl Path {
185 /// Converts a known mod path to `Path`. 184 /// Converts a known mod path to `Path`.
186 pub(crate) fn from_known_path( 185 pub(crate) fn from_known_path(
187 path: ModPath, 186 path: ModPath,
188 generic_args: Vec<Option<Arc<GenericArgs>>>, 187 generic_args: Vec<Option<Interned<GenericArgs>>>,
189 ) -> Path { 188 ) -> Path {
190 Path { type_anchor: None, mod_path: Interned::new(path), generic_args } 189 Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
191 } 190 }
@@ -239,7 +238,7 @@ pub struct PathSegment<'a> {
239 238
240pub struct PathSegments<'a> { 239pub struct PathSegments<'a> {
241 segments: &'a [Name], 240 segments: &'a [Name],
242 generic_args: &'a [Option<Arc<GenericArgs>>], 241 generic_args: &'a [Option<Interned<GenericArgs>>],
243} 242}
244 243
245impl<'a> PathSegments<'a> { 244impl<'a> PathSegments<'a> {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index a873325b2..5d5dd9c8f 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -3,7 +3,6 @@
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned; 5use crate::intern::Interned;
6use std::sync::Arc;
7 6
8use either::Either; 7use either::Either;
9use hir_expand::name::{name, AsName}; 8use hir_expand::name::{name, AsName};
@@ -48,7 +47,7 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
48 segment.ret_type(), 47 segment.ret_type(),
49 ) 48 )
50 }) 49 })
51 .map(Arc::new); 50 .map(Interned::new);
52 segments.push(name); 51 segments.push(name);
53 generic_args.push(args) 52 generic_args.push(args)
54 } 53 }
@@ -87,13 +86,13 @@ pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
87 // Insert the type reference (T in the above example) as Self parameter for the trait 86 // Insert the type reference (T in the above example) as Self parameter for the trait
88 let last_segment = 87 let last_segment =
89 generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?; 88 generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
90 if last_segment.is_none() { 89 let mut args_inner = match last_segment {
91 *last_segment = Some(Arc::new(GenericArgs::empty())); 90 Some(it) => it.as_ref().clone(),
91 None => GenericArgs::empty(),
92 }; 92 };
93 let args = last_segment.as_mut().unwrap();
94 let mut args_inner = Arc::make_mut(args);
95 args_inner.has_self_type = true; 93 args_inner.has_self_type = true;
96 args_inner.args.insert(0, GenericArg::Type(self_type)); 94 args_inner.args.insert(0, GenericArg::Type(self_type));
95 *last_segment = Some(Interned::new(args_inner));
97 } 96 }
98 } 97 }
99 } 98 }
@@ -171,7 +170,9 @@ pub(super) fn lower_generic_args(
171 let name = name_ref.as_name(); 170 let name = name_ref.as_name();
172 let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it)); 171 let type_ref = assoc_type_arg.ty().map(|it| TypeRef::from_ast(lower_ctx, it));
173 let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { 172 let bounds = if let Some(l) = assoc_type_arg.type_bound_list() {
174 l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() 173 l.bounds()
174 .map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it)))
175 .collect()
175 } else { 176 } else {
176 Vec::new() 177 Vec::new()
177 }; 178 };
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 9e44547cb..cbde6b940 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -5,7 +5,7 @@ use hir_expand::{name::Name, AstId, InFile};
5use std::convert::TryInto; 5use std::convert::TryInto;
6use syntax::ast; 6use syntax::ast;
7 7
8use crate::{body::LowerCtx, path::Path}; 8use crate::{body::LowerCtx, intern::Interned, path::Path};
9 9
10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] 10#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
11pub enum Mutability { 11pub enum Mutability {
@@ -72,6 +72,10 @@ impl TraitRef {
72} 72}
73 73
74/// Compare ty::Ty 74/// Compare ty::Ty
75///
76/// Note: Most users of `TypeRef` that end up in the salsa database intern it using
77/// `Interned<TypeRef>` to save space. But notably, nested `TypeRef`s are not interned, since that
78/// does not seem to save any noticeable amount of memory.
75#[derive(Clone, PartialEq, Eq, Hash, Debug)] 79#[derive(Clone, PartialEq, Eq, Hash, Debug)]
76pub enum TypeRef { 80pub enum TypeRef {
77 Never, 81 Never,
@@ -87,8 +91,8 @@ pub enum TypeRef {
87 /// A fn pointer. Last element of the vector is the return type. 91 /// A fn pointer. Last element of the vector is the return type.
88 Fn(Vec<TypeRef>, bool /*varargs*/), 92 Fn(Vec<TypeRef>, bool /*varargs*/),
89 // For 93 // For
90 ImplTrait(Vec<TypeBound>), 94 ImplTrait(Vec<Interned<TypeBound>>),
91 DynTrait(Vec<TypeBound>), 95 DynTrait(Vec<Interned<TypeBound>>),
92 Macro(AstId<ast::MacroCall>), 96 Macro(AstId<ast::MacroCall>),
93 Error, 97 Error,
94} 98}
@@ -228,7 +232,7 @@ impl TypeRef {
228 | TypeRef::Slice(type_ref) => go(&type_ref, f), 232 | TypeRef::Slice(type_ref) => go(&type_ref, f),
229 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
230 for bound in bounds { 234 for bound in bounds {
231 match bound { 235 match bound.as_ref() {
232 TypeBound::Path(path) => go_path(path, f), 236 TypeBound::Path(path) => go_path(path, f),
233 TypeBound::Lifetime(_) | TypeBound::Error => (), 237 TypeBound::Lifetime(_) | TypeBound::Error => (),
234 } 238 }
@@ -258,7 +262,7 @@ impl TypeRef {
258 go(type_ref, f); 262 go(type_ref, f);
259 } 263 }
260 for bound in &binding.bounds { 264 for bound in &binding.bounds {
261 match bound { 265 match bound.as_ref() {
262 TypeBound::Path(path) => go_path(path, f), 266 TypeBound::Path(path) => go_path(path, f),
263 TypeBound::Lifetime(_) | TypeBound::Error => (), 267 TypeBound::Lifetime(_) | TypeBound::Error => (),
264 } 268 }
@@ -273,9 +277,9 @@ impl TypeRef {
273pub(crate) fn type_bounds_from_ast( 277pub(crate) fn type_bounds_from_ast(
274 lower_ctx: &LowerCtx, 278 lower_ctx: &LowerCtx,
275 type_bounds_opt: Option<ast::TypeBoundList>, 279 type_bounds_opt: Option<ast::TypeBoundList>,
276) -> Vec<TypeBound> { 280) -> Vec<Interned<TypeBound>> {
277 if let Some(type_bounds) = type_bounds_opt { 281 if let Some(type_bounds) = type_bounds_opt {
278 type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() 282 type_bounds.bounds().map(|it| Interned::new(TypeBound::from_ast(lower_ctx, it))).collect()
279 } else { 283 } else {
280 vec![] 284 vec![]
281 } 285 }
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 5c769c1bf..625c26f0a 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -131,15 +131,15 @@ pub trait AstDatabase: SourceDatabase {
131/// used for completion, where we want to see what 'would happen' if we insert a 131/// used for completion, where we want to see what 'would happen' if we insert a
132/// token. The `token_to_map` mapped down into the expansion, with the mapped 132/// token. The `token_to_map` mapped down into the expansion, with the mapped
133/// token returned. 133/// token returned.
134pub fn expand_hypothetical( 134pub fn expand_speculative(
135 db: &dyn AstDatabase, 135 db: &dyn AstDatabase,
136 actual_macro_call: MacroCallId, 136 actual_macro_call: MacroCallId,
137 hypothetical_args: &ast::TokenTree, 137 speculative_args: &ast::TokenTree,
138 token_to_map: SyntaxToken, 138 token_to_map: SyntaxToken,
139) -> Option<(SyntaxNode, SyntaxToken)> { 139) -> Option<(SyntaxNode, SyntaxToken)> {
140 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()); 140 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(speculative_args.syntax());
141 let range = 141 let range =
142 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; 142 token_to_map.text_range().checked_sub(speculative_args.syntax().text_range().start())?;
143 let token_id = tmap_1.token_by_range(range)?; 143 let token_id = tmap_1.token_by_range(range)?;
144 144
145 let macro_def = { 145 let macro_def = {
@@ -147,15 +147,15 @@ pub fn expand_hypothetical(
147 db.macro_def(loc.def)? 147 db.macro_def(loc.def)?
148 }; 148 };
149 149
150 let hypothetical_expansion = macro_def.expand(db, actual_macro_call, &tt); 150 let speculative_expansion = macro_def.expand(db, actual_macro_call, &tt);
151 151
152 let fragment_kind = macro_fragment_kind(db, actual_macro_call); 152 let fragment_kind = macro_fragment_kind(db, actual_macro_call);
153 153
154 let (node, tmap_2) = 154 let (node, tmap_2) =
155 mbe::token_tree_to_syntax_node(&hypothetical_expansion.value, fragment_kind).ok()?; 155 mbe::token_tree_to_syntax_node(&speculative_expansion.value, fragment_kind).ok()?;
156 156
157 let token_id = macro_def.map_id_down(token_id); 157 let token_id = macro_def.map_id_down(token_id);
158 let range = tmap_2.range_by_token(token_id)?.by_kind(token_to_map.kind())?; 158 let range = tmap_2.range_by_token(token_id, token_to_map.kind())?;
159 let token = node.syntax_node().covering_element(range).into_token()?; 159 let token = node.syntax_node().covering_element(range).into_token()?;
160 Some((node.syntax_node(), token)) 160 Some((node.syntax_node(), token))
161} 161}
@@ -325,7 +325,7 @@ fn macro_expand_with_arg(
325 if let Some(eager) = &loc.eager { 325 if let Some(eager) = &loc.eager {
326 if arg.is_some() { 326 if arg.is_some() {
327 return ExpandResult::str_err( 327 return ExpandResult::str_err(
328 "hypothetical macro expansion not implemented for eager macro".to_owned(), 328 "speculative macro expansion not implemented for eager macro".to_owned(),
329 ); 329 );
330 } else { 330 } else {
331 return ExpandResult { 331 return ExpandResult {
diff --git a/crates/hir_expand/src/hygiene.rs b/crates/hir_expand/src/hygiene.rs
index 38e09fdd4..d98913907 100644
--- a/crates/hir_expand/src/hygiene.rs
+++ b/crates/hir_expand/src/hygiene.rs
@@ -154,7 +154,7 @@ impl HygieneInfo {
154 }, 154 },
155 }; 155 };
156 156
157 let range = token_map.range_by_token(token_id)?.by_kind(SyntaxKind::IDENT)?; 157 let range = token_map.range_by_token(token_id, SyntaxKind::IDENT)?;
158 Some((tt.with_value(range + tt.value), origin)) 158 Some((tt.with_value(range + tt.value), origin))
159 } 159 }
160} 160}
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 92c679dd2..6be4516a3 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -329,7 +329,7 @@ impl ExpansionInfo {
329 let token_id = self.macro_arg.1.token_by_range(range)?; 329 let token_id = self.macro_arg.1.token_by_range(range)?;
330 let token_id = self.macro_def.map_id_down(token_id); 330 let token_id = self.macro_def.map_id_down(token_id);
331 331
332 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 332 let range = self.exp_map.range_by_token(token_id, token.value.kind())?;
333 333
334 let token = self.expanded.value.covering_element(range).into_token()?; 334 let token = self.expanded.value.covering_element(range).into_token()?;
335 335
@@ -354,7 +354,7 @@ impl ExpansionInfo {
354 }, 354 },
355 }; 355 };
356 356
357 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?; 357 let range = token_map.range_by_token(token_id, token.value.kind())?;
358 let token = 358 let token =
359 tt.value.covering_element(range + tt.value.text_range().start()).into_token()?; 359 tt.value.covering_element(range + tt.value.text_range().start()).into_token()?;
360 Some((tt.with_value(token), origin)) 360 Some((tt.with_value(token), origin))
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 66b3418f2..a9994082a 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
18log = "0.4.8" 18log = "0.4.8"
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20scoped-tls = "1" 20scoped-tls = "1"
21chalk-solve = { version = "0.64", default-features = false } 21chalk-solve = { version = "0.67", default-features = false }
22chalk-ir = "0.64" 22chalk-ir = "0.67"
23chalk-recursive = "0.64" 23chalk-recursive = "0.67"
24la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
25 25
26stdx = { path = "../stdx", version = "0.0.0" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 53c4ee9da..d1f113e7f 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -181,7 +181,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
181 for (id, expr) in body.exprs.iter() { 181 for (id, expr) in body.exprs.iter() {
182 if let Expr::MethodCall { receiver, .. } = expr { 182 if let Expr::MethodCall { receiver, .. } = expr {
183 let function_id = match self.infer.method_resolution(id) { 183 let function_id = match self.infer.method_resolution(id) {
184 Some(id) => id, 184 Some((id, _)) => id,
185 None => continue, 185 None => continue,
186 }; 186 };
187 187
@@ -239,15 +239,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
239 return; 239 return;
240 } 240 }
241 241
242 // FIXME: note that we erase information about substs here. This 242 let (callee, subst) = match self.infer.method_resolution(call_id) {
243 // is not right, but, luckily, doesn't matter as we care only 243 Some(it) => it,
244 // about the number of params
245 let callee = match self.infer.method_resolution(call_id) {
246 Some(callee) => callee,
247 None => return, 244 None => return,
248 }; 245 };
249 let sig = 246 let sig = db.callable_item_signature(callee.into()).substitute(&Interner, &subst);
250 db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0;
251 247
252 (sig, args) 248 (sig, args)
253 } 249 }
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index ed97dc0e3..5d13bddea 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -105,7 +105,7 @@ fn walk_unsafe(
105 Expr::MethodCall { .. } => { 105 Expr::MethodCall { .. } => {
106 if infer 106 if infer
107 .method_resolution(current) 107 .method_resolution(current)
108 .map(|func| db.function_data(func).is_unsafe()) 108 .map(|(func, _)| db.function_data(func).is_unsafe())
109 .unwrap_or(false) 109 .unwrap_or(false)
110 { 110 {
111 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 111 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 7bbd1a1f7..637bbc634 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -13,6 +13,7 @@ use hir_def::{
13 db::DefDatabase, 13 db::DefDatabase,
14 find_path, 14 find_path,
15 generics::TypeParamProvenance, 15 generics::TypeParamProvenance,
16 intern::{Internable, Interned},
16 item_scope::ItemInNs, 17 item_scope::ItemInNs,
17 path::{Path, PathKind}, 18 path::{Path, PathKind},
18 type_ref::{TypeBound, TypeRef}, 19 type_ref::{TypeBound, TypeRef},
@@ -256,6 +257,12 @@ impl<T: HirDisplay> HirDisplay for &'_ T {
256 } 257 }
257} 258}
258 259
260impl<T: HirDisplay + Internable> HirDisplay for Interned<T> {
261 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
262 HirDisplay::hir_fmt(self.as_ref(), f)
263 }
264}
265
259impl HirDisplay for ProjectionTy { 266impl HirDisplay for ProjectionTy {
260 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 267 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
261 if f.should_truncate() { 268 if f.should_truncate() {
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index f1cebbdb9..db3c937ff 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -37,8 +37,8 @@ use syntax::SmolStr;
37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty}; 37use super::{DomainGoal, InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty};
38use crate::{ 38use crate::{
39 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic, 39 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
40 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, TyBuilder, 40 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Goal, Interner, Substitution,
41 TyExt, TyKind, 41 TyBuilder, TyExt, TyKind,
42}; 42};
43 43
44// This lint has a false positive here. See the link below for details. 44// This lint has a false positive here. See the link below for details.
@@ -132,7 +132,7 @@ impl Default for InternedStandardTypes {
132#[derive(Clone, PartialEq, Eq, Debug, Default)] 132#[derive(Clone, PartialEq, Eq, Debug, Default)]
133pub struct InferenceResult { 133pub struct InferenceResult {
134 /// For each method call expr, records the function it resolves to. 134 /// For each method call expr, records the function it resolves to.
135 method_resolutions: FxHashMap<ExprId, FunctionId>, 135 method_resolutions: FxHashMap<ExprId, (FunctionId, Substitution)>,
136 /// For each field access expr, records the field it resolves to. 136 /// For each field access expr, records the field it resolves to.
137 field_resolutions: FxHashMap<ExprId, FieldId>, 137 field_resolutions: FxHashMap<ExprId, FieldId>,
138 /// For each struct literal or pattern, records the variant it resolves to. 138 /// For each struct literal or pattern, records the variant it resolves to.
@@ -152,8 +152,8 @@ pub struct InferenceResult {
152} 152}
153 153
154impl InferenceResult { 154impl InferenceResult {
155 pub fn method_resolution(&self, expr: ExprId) -> Option<FunctionId> { 155 pub fn method_resolution(&self, expr: ExprId) -> Option<(FunctionId, Substitution)> {
156 self.method_resolutions.get(&expr).copied() 156 self.method_resolutions.get(&expr).cloned()
157 } 157 }
158 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { 158 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
159 self.field_resolutions.get(&expr).copied() 159 self.field_resolutions.get(&expr).copied()
@@ -284,14 +284,17 @@ impl<'a> InferenceContext<'a> {
284 self.table.propagate_diverging_flag(); 284 self.table.propagate_diverging_flag();
285 let mut result = std::mem::take(&mut self.result); 285 let mut result = std::mem::take(&mut self.result);
286 for ty in result.type_of_expr.values_mut() { 286 for ty in result.type_of_expr.values_mut() {
287 *ty = self.table.resolve_ty_completely(ty.clone()); 287 *ty = self.table.resolve_completely(ty.clone());
288 } 288 }
289 for ty in result.type_of_pat.values_mut() { 289 for ty in result.type_of_pat.values_mut() {
290 *ty = self.table.resolve_ty_completely(ty.clone()); 290 *ty = self.table.resolve_completely(ty.clone());
291 } 291 }
292 for mismatch in result.type_mismatches.values_mut() { 292 for mismatch in result.type_mismatches.values_mut() {
293 mismatch.expected = self.table.resolve_ty_completely(mismatch.expected.clone()); 293 mismatch.expected = self.table.resolve_completely(mismatch.expected.clone());
294 mismatch.actual = self.table.resolve_ty_completely(mismatch.actual.clone()); 294 mismatch.actual = self.table.resolve_completely(mismatch.actual.clone());
295 }
296 for (_, subst) in result.method_resolutions.values_mut() {
297 *subst = self.table.resolve_completely(subst.clone());
295 } 298 }
296 result 299 result
297 } 300 }
@@ -300,8 +303,8 @@ impl<'a> InferenceContext<'a> {
300 self.result.type_of_expr.insert(expr, ty); 303 self.result.type_of_expr.insert(expr, ty);
301 } 304 }
302 305
303 fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId) { 306 fn write_method_resolution(&mut self, expr: ExprId, func: FunctionId, subst: Substitution) {
304 self.result.method_resolutions.insert(expr, func); 307 self.result.method_resolutions.insert(expr, (func, subst));
305 } 308 }
306 309
307 fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) { 310 fn write_field_resolution(&mut self, expr: ExprId, field: FieldId) {
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index 08c05c67c..eab8fac91 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -891,17 +891,21 @@ impl<'a> InferenceContext<'a> {
891 method_name, 891 method_name,
892 ) 892 )
893 }); 893 });
894 let (derefed_receiver_ty, method_ty, def_generics) = match resolved { 894 let (derefed_receiver_ty, method_ty, substs) = match resolved {
895 Some((ty, func)) => { 895 Some((ty, func)) => {
896 let ty = canonicalized_receiver.decanonicalize_ty(ty); 896 let ty = canonicalized_receiver.decanonicalize_ty(ty);
897 self.write_method_resolution(tgt_expr, func); 897 let generics = generics(self.db.upcast(), func.into());
898 (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into()))) 898 let substs = self.substs_for_method_call(generics, generic_args, &ty);
899 self.write_method_resolution(tgt_expr, func, substs.clone());
900 (ty, self.db.value_ty(func.into()), substs)
899 } 901 }
900 None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None), 902 None => (
903 receiver_ty,
904 Binders::empty(&Interner, self.err_ty()),
905 Substitution::empty(&Interner),
906 ),
901 }; 907 };
902 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
903 let method_ty = method_ty.substitute(&Interner, &substs); 908 let method_ty = method_ty.substitute(&Interner, &substs);
904 let method_ty = self.insert_type_vars(method_ty);
905 self.register_obligations_for_call(&method_ty); 909 self.register_obligations_for_call(&method_ty);
906 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 910 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
907 Some(sig) => { 911 Some(sig) => {
@@ -950,23 +954,21 @@ impl<'a> InferenceContext<'a> {
950 954
951 fn substs_for_method_call( 955 fn substs_for_method_call(
952 &mut self, 956 &mut self,
953 def_generics: Option<Generics>, 957 def_generics: Generics,
954 generic_args: Option<&GenericArgs>, 958 generic_args: Option<&GenericArgs>,
955 receiver_ty: &Ty, 959 receiver_ty: &Ty,
956 ) -> Substitution { 960 ) -> Substitution {
957 let (parent_params, self_params, type_params, impl_trait_params) = 961 let (parent_params, self_params, type_params, impl_trait_params) =
958 def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split()); 962 def_generics.provenance_split();
959 assert_eq!(self_params, 0); // method shouldn't have another Self param 963 assert_eq!(self_params, 0); // method shouldn't have another Self param
960 let total_len = parent_params + type_params + impl_trait_params; 964 let total_len = parent_params + type_params + impl_trait_params;
961 let mut substs = Vec::with_capacity(total_len); 965 let mut substs = Vec::with_capacity(total_len);
962 // Parent arguments are unknown, except for the receiver type 966 // Parent arguments are unknown, except for the receiver type
963 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 967 for (_id, param) in def_generics.iter_parent() {
964 for (_id, param) in parent_generics { 968 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
965 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf { 969 substs.push(receiver_ty.clone());
966 substs.push(receiver_ty.clone()); 970 } else {
967 } else { 971 substs.push(self.table.new_type_var());
968 substs.push(self.err_ty());
969 }
970 } 972 }
971 } 973 }
972 // handle provided type arguments 974 // handle provided type arguments
@@ -989,7 +991,7 @@ impl<'a> InferenceContext<'a> {
989 }; 991 };
990 let supplied_params = substs.len(); 992 let supplied_params = substs.len();
991 for _ in supplied_params..total_len { 993 for _ in supplied_params..total_len {
992 substs.push(self.err_ty()); 994 substs.push(self.table.new_type_var());
993 } 995 }
994 assert_eq!(substs.len(), total_len); 996 assert_eq!(substs.len(), total_len);
995 Substitution::from_iter(&Interner, substs) 997 Substitution::from_iter(&Interner, substs)
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index f8233cac3..ea5684229 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -295,8 +295,11 @@ impl<'a> InferenceTable<'a> {
295 .expect("fold failed unexpectedly") 295 .expect("fold failed unexpectedly")
296 } 296 }
297 297
298 pub(crate) fn resolve_ty_completely(&mut self, ty: Ty) -> Ty { 298 pub(crate) fn resolve_completely<T>(&mut self, t: T) -> T::Result
299 self.resolve_with_fallback(ty, |_, _, d, _| d) 299 where
300 T: HasInterner<Interner = Interner> + Fold<Interner>,
301 {
302 self.resolve_with_fallback(t, |_, _, d, _| d)
300 } 303 }
301 304
302 /// Unify two types and register new trait goals that arise from that. 305 /// Unify two types and register new trait goals that arise from that.
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 8a375b973..c83933c73 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -10,6 +10,7 @@ use std::{iter, sync::Arc};
10 10
11use base_db::CrateId; 11use base_db::CrateId;
12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; 12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
13use hir_def::intern::Interned;
13use hir_def::{ 14use hir_def::{
14 adt::StructKind, 15 adt::StructKind,
15 body::{Expander, LowerCtx}, 16 body::{Expander, LowerCtx},
@@ -843,7 +844,7 @@ impl<'a> TyLoweringContext<'a> {
843 }) 844 })
844 } 845 }
845 846
846 fn lower_impl_trait(&self, bounds: &[TypeBound]) -> ReturnTypeImplTrait { 847 fn lower_impl_trait(&self, bounds: &[Interned<TypeBound>]) -> ReturnTypeImplTrait {
847 cov_mark::hit!(lower_rpit); 848 cov_mark::hit!(lower_rpit);
848 let self_ty = 849 let self_ty =
849 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner); 850 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(&Interner);
@@ -1025,7 +1026,7 @@ pub(crate) fn trait_environment_query(
1025 }; 1026 };
1026 if let Some(AssocContainerId::TraitId(trait_id)) = container { 1027 if let Some(AssocContainerId::TraitId(trait_id)) = container {
1027 // add `Self: Trait<T1, T2, ...>` to the environment in trait 1028 // add `Self: Trait<T1, T2, ...>` to the environment in trait
1028 // function default implementations (and hypothetical code 1029 // function default implementations (and speculative code
1029 // inside consts or type aliases) 1030 // inside consts or type aliases)
1030 cov_mark::hit!(trait_self_implements_self); 1031 cov_mark::hit!(trait_self_implements_self);
1031 let substs = TyBuilder::type_params_subst(db, trait_id); 1032 let substs = TyBuilder::type_params_subst(db, trait_id);
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 320694a17..ec3828ab2 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -286,7 +286,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
286 .and_then( 286 .and_then(
287 |url| if let Some(fragment) = fragment { url.join(&fragment).ok() } else { Some(url) }, 287 |url| if let Some(fragment) = fragment { url.join(&fragment).ok() } else { Some(url) },
288 ) 288 )
289 .map(|url| url.into_string()) 289 .map(|url| url.into())
290} 290}
291 291
292fn rewrite_intra_doc_link( 292fn rewrite_intra_doc_link(
@@ -325,7 +325,7 @@ fn rewrite_intra_doc_link(
325 }; 325 };
326 } 326 }
327 327
328 Some((new_url.into_string(), strip_prefixes_suffixes(title).to_string())) 328 Some((new_url.into(), strip_prefixes_suffixes(title).to_string()))
329} 329}
330 330
331/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`). 331/// Try to resolve path to local documentation via path-based links (i.e. `../gateway/struct.Shard.html`).
@@ -345,7 +345,7 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S
345 get_symbol_filename(db, &def).as_deref().map(|f| url.join(f).ok()).flatten() 345 get_symbol_filename(db, &def).as_deref().map(|f| url.join(f).ok()).flatten()
346 }) 346 })
347 .and_then(|url| url.join(target).ok()) 347 .and_then(|url| url.join(target).ok())
348 .map(|url| url.into_string()) 348 .map(|url| url.into())
349} 349}
350 350
351/// Rewrites a markdown document, applying 'callback' to each link. 351/// Rewrites a markdown document, applying 'callback' to each link.
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 9de653739..04598cd06 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -3957,4 +3957,24 @@ mod string {
3957 "#]], 3957 "#]],
3958 ) 3958 )
3959 } 3959 }
3960
3961 #[test]
3962 fn function_doesnt_shadow_crate_in_use_tree() {
3963 check(
3964 r#"
3965//- /main.rs crate:main deps:foo
3966use foo$0::{foo};
3967
3968//- /foo.rs crate:foo
3969pub fn foo() {}
3970"#,
3971 expect![[r#"
3972 *foo*
3973
3974 ```rust
3975 extern crate foo
3976 ```
3977 "#]],
3978 )
3979 }
3960} 3980}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 0ada3f92b..85f887737 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -225,8 +225,10 @@ fn hint_iterator(
225 } 225 }
226 let iter_trait = famous_defs.core_iter_Iterator()?; 226 let iter_trait = famous_defs.core_iter_Iterator()?;
227 let iter_mod = famous_defs.core_iter()?; 227 let iter_mod = famous_defs.core_iter()?;
228 // assert this struct comes from `core::iter` 228
229 // Assert that this struct comes from `core::iter`.
229 iter_mod.visibility_of(db, &strukt.into()).filter(|&vis| vis == hir::Visibility::Public)?; 230 iter_mod.visibility_of(db, &strukt.into()).filter(|&vis| vis == hir::Visibility::Public)?;
231
230 if ty.impls_trait(db, iter_trait, &[]) { 232 if ty.impls_trait(db, iter_trait, &[]) {
231 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item { 233 let assoc_type_item = iter_trait.items(db).into_iter().find_map(|item| match item {
232 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), 234 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 97435f021..3d2cd739a 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -31,8 +31,8 @@ use crate::{
31// 31//
32// fn handle(action: Action) { 32// fn handle(action: Action) {
33// match action { 33// match action {
34// $0Action::Move { distance } => {} 34// $0Action::Move { distance } => todo!(),
35// Action::Stop => {} 35// Action::Stop => todo!(),
36// } 36// }
37// } 37// }
38// ``` 38// ```
@@ -129,7 +129,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
129 |builder| { 129 |builder| {
130 let new_match_arm_list = match_arm_list.clone_for_update(); 130 let new_match_arm_list = match_arm_list.clone_for_update();
131 let missing_arms = missing_pats 131 let missing_arms = missing_pats
132 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 132 .map(|pat| make::match_arm(iter::once(pat), make::ext::expr_todo()))
133 .map(|it| it.clone_for_update()); 133 .map(|it| it.clone_for_update());
134 134
135 let catch_all_arm = new_match_arm_list 135 let catch_all_arm = new_match_arm_list
@@ -350,8 +350,8 @@ fn foo(a: bool) {
350 r#" 350 r#"
351fn foo(a: bool) { 351fn foo(a: bool) {
352 match a { 352 match a {
353 $0true => {} 353 $0true => todo!(),
354 false => {} 354 false => todo!(),
355 } 355 }
356} 356}
357"#, 357"#,
@@ -373,7 +373,7 @@ fn foo(a: bool) {
373fn foo(a: bool) { 373fn foo(a: bool) {
374 match a { 374 match a {
375 true => {} 375 true => {}
376 $0false => {} 376 $0false => todo!(),
377 } 377 }
378} 378}
379"#, 379"#,
@@ -410,10 +410,10 @@ fn foo(a: bool) {
410 r#" 410 r#"
411fn foo(a: bool) { 411fn foo(a: bool) {
412 match (a, a) { 412 match (a, a) {
413 $0(true, true) => {} 413 $0(true, true) => todo!(),
414 (true, false) => {} 414 (true, false) => todo!(),
415 (false, true) => {} 415 (false, true) => todo!(),
416 (false, false) => {} 416 (false, false) => todo!(),
417 } 417 }
418} 418}
419"#, 419"#,
@@ -435,9 +435,9 @@ fn foo(a: bool) {
435fn foo(a: bool) { 435fn foo(a: bool) {
436 match (a, a) { 436 match (a, a) {
437 (false, true) => {} 437 (false, true) => {}
438 $0(true, true) => {} 438 $0(true, true) => todo!(),
439 (true, false) => {} 439 (true, false) => todo!(),
440 (false, false) => {} 440 (false, false) => todo!(),
441 } 441 }
442} 442}
443"#, 443"#,
@@ -471,7 +471,7 @@ fn main() {
471 match A::As { 471 match A::As {
472 A::Bs { x, y: Some(_) } => {} 472 A::Bs { x, y: Some(_) } => {}
473 A::Cs(_, Some(_)) => {} 473 A::Cs(_, Some(_)) => {}
474 $0A::As => {} 474 $0A::As => todo!(),
475 } 475 }
476} 476}
477"#, 477"#,
@@ -499,7 +499,7 @@ use Option::*;
499fn main() { 499fn main() {
500 match None { 500 match None {
501 None => {} 501 None => {}
502 Some(${0:_}) => {} 502 Some(${0:_}) => todo!(),
503 } 503 }
504} 504}
505 "#, 505 "#,
@@ -523,7 +523,7 @@ enum A { As, Bs, Cs(Option<i32>) }
523fn main() { 523fn main() {
524 match A::As { 524 match A::As {
525 A::Cs(_) | A::Bs => {} 525 A::Cs(_) | A::Bs => {}
526 $0A::As => {} 526 $0A::As => todo!(),
527 } 527 }
528} 528}
529"#, 529"#,
@@ -553,8 +553,8 @@ fn main() {
553 A::Bs if 0 < 1 => {} 553 A::Bs if 0 < 1 => {}
554 A::Ds(_value) => { let x = 1; } 554 A::Ds(_value) => { let x = 1; }
555 A::Es(B::Xs) => (), 555 A::Es(B::Xs) => (),
556 $0A::As => {} 556 $0A::As => todo!(),
557 A::Cs => {} 557 A::Cs => todo!(),
558 } 558 }
559} 559}
560"#, 560"#,
@@ -580,7 +580,7 @@ fn main() {
580 match A::As { 580 match A::As {
581 A::As(_) => {} 581 A::As(_) => {}
582 a @ A::Bs(_) => {} 582 a @ A::Bs(_) => {}
583 A::Cs(${0:_}) => {} 583 A::Cs(${0:_}) => todo!(),
584 } 584 }
585} 585}
586"#, 586"#,
@@ -605,11 +605,11 @@ enum A { As, Bs, Cs(String), Ds(String, String), Es { x: usize, y: usize } }
605fn main() { 605fn main() {
606 let a = A::As; 606 let a = A::As;
607 match a { 607 match a {
608 $0A::As => {} 608 $0A::As => todo!(),
609 A::Bs => {} 609 A::Bs => todo!(),
610 A::Cs(_) => {} 610 A::Cs(_) => todo!(),
611 A::Ds(_, _) => {} 611 A::Ds(_, _) => todo!(),
612 A::Es { x, y } => {} 612 A::Es { x, y } => todo!(),
613 } 613 }
614} 614}
615"#, 615"#,
@@ -638,10 +638,10 @@ fn main() {
638 let a = A::One; 638 let a = A::One;
639 let b = B::One; 639 let b = B::One;
640 match (a, b) { 640 match (a, b) {
641 $0(A::One, B::One) => {} 641 $0(A::One, B::One) => todo!(),
642 (A::One, B::Two) => {} 642 (A::One, B::Two) => todo!(),
643 (A::Two, B::One) => {} 643 (A::Two, B::One) => todo!(),
644 (A::Two, B::Two) => {} 644 (A::Two, B::Two) => todo!(),
645 } 645 }
646} 646}
647"#, 647"#,
@@ -670,10 +670,10 @@ fn main() {
670 let a = A::One; 670 let a = A::One;
671 let b = B::One; 671 let b = B::One;
672 match (&a, &b) { 672 match (&a, &b) {
673 $0(A::One, B::One) => {} 673 $0(A::One, B::One) => todo!(),
674 (A::One, B::Two) => {} 674 (A::One, B::Two) => todo!(),
675 (A::Two, B::One) => {} 675 (A::Two, B::One) => todo!(),
676 (A::Two, B::Two) => {} 676 (A::Two, B::Two) => todo!(),
677 } 677 }
678} 678}
679"#, 679"#,
@@ -705,9 +705,9 @@ fn main() {
705 let b = B::One; 705 let b = B::One;
706 match (a, b) { 706 match (a, b) {
707 (A::Two, B::One) => {} 707 (A::Two, B::One) => {}
708 $0(A::One, B::One) => {} 708 $0(A::One, B::One) => todo!(),
709 (A::One, B::Two) => {} 709 (A::One, B::Two) => todo!(),
710 (A::Two, B::Two) => {} 710 (A::Two, B::Two) => todo!(),
711 } 711 }
712} 712}
713"#, 713"#,
@@ -736,7 +736,7 @@ fn main() {
736 match (a, b) { 736 match (a, b) {
737 (Some(_), _) => {} 737 (Some(_), _) => {}
738 (None, Some(_)) => {} 738 (None, Some(_)) => {}
739 $0(None, None) => {} 739 $0(None, None) => todo!(),
740 } 740 }
741} 741}
742"#, 742"#,
@@ -801,8 +801,8 @@ enum A { One, Two }
801fn main() { 801fn main() {
802 let a = A::One; 802 let a = A::One;
803 match (a, ) { 803 match (a, ) {
804 $0(A::One,) => {} 804 $0(A::One,) => todo!(),
805 (A::Two,) => {} 805 (A::Two,) => todo!(),
806 } 806 }
807} 807}
808"#, 808"#,
@@ -826,7 +826,7 @@ enum A { As }
826 826
827fn foo(a: &A) { 827fn foo(a: &A) {
828 match a { 828 match a {
829 $0A::As => {} 829 $0A::As => todo!(),
830 } 830 }
831} 831}
832"#, 832"#,
@@ -851,7 +851,7 @@ enum A {
851 851
852fn foo(a: &mut A) { 852fn foo(a: &mut A) {
853 match a { 853 match a {
854 $0A::Es { x, y } => {} 854 $0A::Es { x, y } => todo!(),
855 } 855 }
856} 856}
857"#, 857"#,
@@ -891,8 +891,8 @@ enum E { X, Y }
891 891
892fn main() { 892fn main() {
893 match E::X { 893 match E::X {
894 $0E::X => {} 894 $0E::X => todo!(),
895 E::Y => {} 895 E::Y => todo!(),
896 } 896 }
897} 897}
898"#, 898"#,
@@ -919,8 +919,8 @@ use foo::E::X;
919 919
920fn main() { 920fn main() {
921 match X { 921 match X {
922 $0X => {} 922 $0X => todo!(),
923 foo::E::Y => {} 923 foo::E::Y => todo!(),
924 } 924 }
925} 925}
926"#, 926"#,
@@ -947,7 +947,7 @@ fn foo(a: A) {
947 match a { 947 match a {
948 // foo bar baz 948 // foo bar baz
949 A::One => {} 949 A::One => {}
950 $0A::Two => {} 950 $0A::Two => todo!(),
951 // This is where the rest should be 951 // This is where the rest should be
952 } 952 }
953} 953}
@@ -971,8 +971,8 @@ fn foo(a: A) {
971enum A { One, Two } 971enum A { One, Two }
972fn foo(a: A) { 972fn foo(a: A) {
973 match a { 973 match a {
974 $0A::One => {} 974 $0A::One => todo!(),
975 A::Two => {} 975 A::Two => todo!(),
976 // foo bar baz 976 // foo bar baz
977 } 977 }
978} 978}
@@ -996,8 +996,8 @@ fn foo(a: A) {
996enum A { One, Two, } 996enum A { One, Two, }
997fn foo(a: A) { 997fn foo(a: A) {
998 match a { 998 match a {
999 $0A::One => {} 999 $0A::One => todo!(),
1000 A::Two => {} 1000 A::Two => todo!(),
1001 } 1001 }
1002} 1002}
1003"#, 1003"#,
@@ -1021,8 +1021,8 @@ fn foo(opt: Option<i32>) {
1021 r#" 1021 r#"
1022fn foo(opt: Option<i32>) { 1022fn foo(opt: Option<i32>) {
1023 match opt { 1023 match opt {
1024 Some(${0:_}) => {} 1024 Some(${0:_}) => todo!(),
1025 None => {} 1025 None => todo!(),
1026 } 1026 }
1027} 1027}
1028"#, 1028"#,
@@ -1054,9 +1054,9 @@ enum Test {
1054 1054
1055fn foo(t: Test) { 1055fn foo(t: Test) {
1056 m!(match t { 1056 m!(match t {
1057 $0Test::A => {} 1057 $0Test::A => todo!(),
1058 Test::B => {} 1058 Test::B => todo!(),
1059 Test::C => {} 1059 Test::C => todo!(),
1060}); 1060});
1061}"#, 1061}"#,
1062 ); 1062 );
@@ -1076,4 +1076,44 @@ fn foo(tuple: (A, A)) {
1076"#, 1076"#,
1077 ); 1077 );
1078 } 1078 }
1079
1080 #[test]
1081 fn adds_comma_before_new_arms() {
1082 check_assist(
1083 fill_match_arms,
1084 r#"
1085fn foo(t: bool) {
1086 match $0t {
1087 true => 1 + 2
1088 }
1089}"#,
1090 r#"
1091fn foo(t: bool) {
1092 match t {
1093 true => 1 + 2,
1094 $0false => todo!(),
1095 }
1096}"#,
1097 );
1098 }
1099
1100 #[test]
1101 fn does_not_add_extra_comma() {
1102 check_assist(
1103 fill_match_arms,
1104 r#"
1105fn foo(t: bool) {
1106 match $0t {
1107 true => 1 + 2,
1108 }
1109}"#,
1110 r#"
1111fn foo(t: bool) {
1112 match t {
1113 true => 1 + 2,
1114 $0false => todo!(),
1115 }
1116}"#,
1117 );
1118 }
1079} 1119}
diff --git a/crates/ide_assists/src/handlers/fix_visibility.rs b/crates/ide_assists/src/handlers/fix_visibility.rs
index 6c7824e55..89f7b2c2c 100644
--- a/crates/ide_assists/src/handlers/fix_visibility.rs
+++ b/crates/ide_assists/src/handlers/fix_visibility.rs
@@ -85,7 +85,7 @@ fn add_vis_to_referenced_module_def(acc: &mut Assists, ctx: &AssistContext) -> O
85 85
86fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 86fn add_vis_to_referenced_record_field(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
87 let record_field: ast::RecordExprField = ctx.find_node_at_offset()?; 87 let record_field: ast::RecordExprField = ctx.find_node_at_offset()?;
88 let (record_field_def, _) = ctx.sema.resolve_record_field(&record_field)?; 88 let (record_field_def, _, _) = ctx.sema.resolve_record_field(&record_field)?;
89 89
90 let current_module = ctx.sema.scope(record_field.syntax()).module()?; 90 let current_module = ctx.sema.scope(record_field.syntax()).module()?;
91 let visibility = record_field_def.visibility(ctx.db()); 91 let visibility = record_field_def.visibility(ctx.db());
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index df7d1bb95..09971226e 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -23,12 +23,46 @@ use crate::{
23// 23//
24// impl Person { 24// impl Person {
25// /// Get a reference to the person's name. 25// /// Get a reference to the person's name.
26// fn name(&self) -> &String { 26// fn $0name(&self) -> &str {
27// &self.name 27// self.name.as_str()
28// } 28// }
29// } 29// }
30// ``` 30// ```
31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 generate_getter_impl(acc, ctx, false)
33}
34
35// Assist: generate_getter_mut
36//
37// Generate a mut getter method.
38//
39// ```
40// struct Person {
41// nam$0e: String,
42// }
43// ```
44// ->
45// ```
46// struct Person {
47// name: String,
48// }
49//
50// impl Person {
51// /// Get a mutable reference to the person's name.
52// fn $0name_mut(&mut self) -> &mut String {
53// &mut self.name
54// }
55// }
56// ```
57pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
58 generate_getter_impl(acc, ctx, true)
59}
60
61pub(crate) fn generate_getter_impl(
62 acc: &mut Assists,
63 ctx: &AssistContext,
64 mutable: bool,
65) -> Option<()> {
32 let strukt = ctx.find_node_at_offset::<ast::Struct>()?; 66 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
33 let field = ctx.find_node_at_offset::<ast::RecordField>()?; 67 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
34 68
@@ -37,39 +71,52 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
37 let field_ty = field.ty()?; 71 let field_ty = field.ty()?;
38 72
39 // Return early if we've found an existing fn 73 // Return early if we've found an existing fn
40 let fn_name = to_lower_snake_case(&field_name.to_string()); 74 let mut fn_name = to_lower_snake_case(&field_name.to_string());
75 if mutable {
76 format_to!(fn_name, "_mut");
77 }
41 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?; 78 let impl_def = find_struct_impl(&ctx, &ast::Adt::Struct(strukt.clone()), fn_name.as_str())?;
42 79
80 let (id, label) = if mutable {
81 ("generate_getter_mut", "Generate a mut getter method")
82 } else {
83 ("generate_getter", "Generate a getter method")
84 };
43 let target = field.syntax().text_range(); 85 let target = field.syntax().text_range();
44 acc.add_group( 86 acc.add_group(
45 &GroupLabel("Generate getter/setter".to_owned()), 87 &GroupLabel("Generate getter/setter".to_owned()),
46 AssistId("generate_getter", AssistKind::Generate), 88 AssistId(id, AssistKind::Generate),
47 "Generate a getter method", 89 label,
48 target, 90 target,
49 |builder| { 91 |builder| {
50 let mut buf = String::with_capacity(512); 92 let mut buf = String::with_capacity(512);
51 93
52 let fn_name_spaced = fn_name.replace('_', " ");
53 let strukt_name_spaced =
54 to_lower_snake_case(&strukt_name.to_string()).replace('_', " ");
55
56 if impl_def.is_some() { 94 if impl_def.is_some() {
57 buf.push('\n'); 95 buf.push('\n');
58 } 96 }
59 97
60 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v)); 98 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
99 let (ty, body) = if mutable {
100 (format!("&mut {}", field_ty), format!("&mut self.{}", field_name))
101 } else {
102 useless_type_special_case(&field_name.to_string(), &field_ty)
103 .unwrap_or_else(|| (format!("&{}", field_ty), format!("&self.{}", field_name)))
104 };
105
61 format_to!( 106 format_to!(
62 buf, 107 buf,
63 " /// Get a reference to the {}'s {}. 108 " /// Get a {}reference to the {}'s {}.
64 {}fn {}(&self) -> &{} {{ 109 {}fn {}(&{}self) -> {} {{
65 &self.{} 110 {}
66 }}", 111 }}",
67 strukt_name_spaced, 112 mutable.then(|| "mutable ").unwrap_or_default(),
68 fn_name_spaced, 113 to_lower_snake_case(&strukt_name.to_string()).replace('_', " "),
114 fn_name.trim_end_matches("_mut").replace('_', " "),
69 vis, 115 vis,
70 fn_name, 116 fn_name,
71 field_ty, 117 mutable.then(|| "mut ").unwrap_or_default(),
72 fn_name, 118 ty,
119 body,
73 ); 120 );
74 121
75 let start_offset = impl_def 122 let start_offset = impl_def
@@ -79,56 +126,120 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
79 strukt.syntax().text_range().end() 126 strukt.syntax().text_range().end()
80 }); 127 });
81 128
82 builder.insert(start_offset, buf); 129 match ctx.config.snippet_cap {
130 Some(cap) => {
131 builder.insert_snippet(cap, start_offset, buf.replacen("fn ", "fn $0", 1))
132 }
133 None => builder.insert(start_offset, buf),
134 }
83 }, 135 },
84 ) 136 )
85} 137}
86 138
139fn useless_type_special_case(field_name: &str, field_ty: &ast::Type) -> Option<(String, String)> {
140 if field_ty.to_string() == "String" {
141 cov_mark::hit!(useless_type_special_case);
142 return Some(("&str".to_string(), format!("self.{}.as_str()", field_name)));
143 }
144 if let Some(arg) = ty_ctor(field_ty, "Vec") {
145 return Some((format!("&[{}]", arg), format!("self.{}.as_slice()", field_name)));
146 }
147 if let Some(arg) = ty_ctor(field_ty, "Box") {
148 return Some((format!("&{}", arg), format!("self.{}.as_ref()", field_name)));
149 }
150 if let Some(arg) = ty_ctor(field_ty, "Option") {
151 return Some((format!("Option<&{}>", arg), format!("self.{}.as_ref()", field_name)));
152 }
153 None
154}
155
156// FIXME: This should rely on semantic info.
157fn ty_ctor(ty: &ast::Type, ctor: &str) -> Option<String> {
158 let res = ty.to_string().strip_prefix(ctor)?.strip_prefix('<')?.strip_suffix('>')?.to_string();
159 Some(res)
160}
161
87#[cfg(test)] 162#[cfg(test)]
88mod tests { 163mod tests {
89 use crate::tests::{check_assist, check_assist_not_applicable}; 164 use crate::tests::{check_assist, check_assist_not_applicable};
90 165
91 use super::*; 166 use super::*;
92 167
93 fn check_not_applicable(ra_fixture: &str) {
94 check_assist_not_applicable(generate_getter, ra_fixture)
95 }
96
97 #[test] 168 #[test]
98 fn test_generate_getter_from_field() { 169 fn test_generate_getter_from_field() {
99 check_assist( 170 check_assist(
100 generate_getter, 171 generate_getter,
101 r#" 172 r#"
102struct Context<T: Clone> { 173struct Context {
103 dat$0a: T, 174 dat$0a: Data,
104}"#, 175}
176"#,
105 r#" 177 r#"
106struct Context<T: Clone> { 178struct Context {
107 data: T, 179 data: Data,
108} 180}
109 181
110impl<T: Clone> Context<T> { 182impl Context {
111 /// Get a reference to the context's data. 183 /// Get a reference to the context's data.
112 fn data(&self) -> &T { 184 fn $0data(&self) -> &Data {
113 &self.data 185 &self.data
114 } 186 }
115}"#, 187}
188"#,
189 );
190
191 check_assist(
192 generate_getter_mut,
193 r#"
194struct Context {
195 dat$0a: Data,
196}
197"#,
198 r#"
199struct Context {
200 data: Data,
201}
202
203impl Context {
204 /// Get a mutable reference to the context's data.
205 fn $0data_mut(&mut self) -> &mut Data {
206 &mut self.data
207 }
208}
209"#,
116 ); 210 );
117 } 211 }
118 212
119 #[test] 213 #[test]
120 fn test_generate_getter_already_implemented() { 214 fn test_generate_getter_already_implemented() {
121 check_not_applicable( 215 check_assist_not_applicable(
216 generate_getter,
122 r#" 217 r#"
123struct Context<T: Clone> { 218struct Context {
124 dat$0a: T, 219 dat$0a: Data,
125} 220}
126 221
127impl<T: Clone> Context<T> { 222impl Context {
128 fn data(&self) -> &T { 223 fn data(&self) -> &Data {
129 &self.data 224 &self.data
130 } 225 }
131}"#, 226}
227"#,
228 );
229
230 check_assist_not_applicable(
231 generate_getter_mut,
232 r#"
233struct Context {
234 dat$0a: Data,
235}
236
237impl Context {
238 fn data_mut(&mut self) -> &mut Data {
239 &mut self.data
240 }
241}
242"#,
132 ); 243 );
133 } 244 }
134 245
@@ -137,20 +248,22 @@ impl<T: Clone> Context<T> {
137 check_assist( 248 check_assist(
138 generate_getter, 249 generate_getter,
139 r#" 250 r#"
140pub(crate) struct Context<T: Clone> { 251pub(crate) struct Context {
141 dat$0a: T, 252 dat$0a: Data,
142}"#, 253}
254"#,
143 r#" 255 r#"
144pub(crate) struct Context<T: Clone> { 256pub(crate) struct Context {
145 data: T, 257 data: Data,
146} 258}
147 259
148impl<T: Clone> Context<T> { 260impl Context {
149 /// Get a reference to the context's data. 261 /// Get a reference to the context's data.
150 pub(crate) fn data(&self) -> &T { 262 pub(crate) fn $0data(&self) -> &Data {
151 &self.data 263 &self.data
152 } 264 }
153}"#, 265}
266"#,
154 ); 267 );
155 } 268 }
156 269
@@ -159,34 +272,105 @@ impl<T: Clone> Context<T> {
159 check_assist( 272 check_assist(
160 generate_getter, 273 generate_getter,
161 r#" 274 r#"
162struct Context<T: Clone> { 275struct Context {
163 data: T, 276 data: Data,
164 cou$0nt: usize, 277 cou$0nt: usize,
165} 278}
166 279
167impl<T: Clone> Context<T> { 280impl Context {
168 /// Get a reference to the context's data. 281 /// Get a reference to the context's data.
169 fn data(&self) -> &T { 282 fn data(&self) -> &Data {
170 &self.data 283 &self.data
171 } 284 }
172}"#, 285}
286"#,
173 r#" 287 r#"
174struct Context<T: Clone> { 288struct Context {
175 data: T, 289 data: Data,
176 count: usize, 290 count: usize,
177} 291}
178 292
179impl<T: Clone> Context<T> { 293impl Context {
180 /// Get a reference to the context's data. 294 /// Get a reference to the context's data.
181 fn data(&self) -> &T { 295 fn data(&self) -> &Data {
182 &self.data 296 &self.data
183 } 297 }
184 298
185 /// Get a reference to the context's count. 299 /// Get a reference to the context's count.
186 fn count(&self) -> &usize { 300 fn $0count(&self) -> &usize {
187 &self.count 301 &self.count
188 } 302 }
189}"#, 303}
304"#,
305 );
306 }
307
308 #[test]
309 fn test_special_cases() {
310 cov_mark::check!(useless_type_special_case);
311 check_assist(
312 generate_getter,
313 r#"
314struct S { foo: $0String }
315"#,
316 r#"
317struct S { foo: String }
318
319impl S {
320 /// Get a reference to the s's foo.
321 fn $0foo(&self) -> &str {
322 self.foo.as_str()
323 }
324}
325"#,
326 );
327 check_assist(
328 generate_getter,
329 r#"
330struct S { foo: $0Box<Sweets> }
331"#,
332 r#"
333struct S { foo: Box<Sweets> }
334
335impl S {
336 /// Get a reference to the s's foo.
337 fn $0foo(&self) -> &Sweets {
338 self.foo.as_ref()
339 }
340}
341"#,
342 );
343 check_assist(
344 generate_getter,
345 r#"
346struct S { foo: $0Vec<()> }
347"#,
348 r#"
349struct S { foo: Vec<()> }
350
351impl S {
352 /// Get a reference to the s's foo.
353 fn $0foo(&self) -> &[()] {
354 self.foo.as_slice()
355 }
356}
357"#,
358 );
359 check_assist(
360 generate_getter,
361 r#"
362struct S { foo: $0Option<Failure> }
363"#,
364 r#"
365struct S { foo: Option<Failure> }
366
367impl S {
368 /// Get a reference to the s's foo.
369 fn $0foo(&self) -> Option<&Failure> {
370 self.foo.as_ref()
371 }
372}
373"#,
190 ); 374 );
191 } 375 }
192} 376}
diff --git a/crates/ide_assists/src/handlers/generate_getter_mut.rs b/crates/ide_assists/src/handlers/generate_getter_mut.rs
deleted file mode 100644
index 821c2eed5..000000000
--- a/crates/ide_assists/src/handlers/generate_getter_mut.rs
+++ /dev/null
@@ -1,195 +0,0 @@
1use stdx::{format_to, to_lower_snake_case};
2use syntax::ast::{self, AstNode, NameOwner, VisibilityOwner};
3
4use crate::{
5 utils::{find_impl_block_end, find_struct_impl, generate_impl_text},
6 AssistContext, AssistId, AssistKind, Assists, GroupLabel,
7};
8
9// Assist: generate_getter_mut
10//
11// Generate a mut getter method.
12//
13// ```
14// struct Person {
15// nam$0e: String,
16// }
17// ```
18// ->
19// ```
20// struct Person {
21// name: String,
22// }
23//
24// impl Person {
25// /// Get a mutable reference to the person's name.
26// fn name_mut(&mut self) -> &mut String {
27// &mut self.name
28// }
29// }
30// ```
31pub(crate) fn generate_getter_mut(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
32 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
33 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
34
35 let strukt_name = strukt.name()?;
36 let field_name = field.name()?;
37 let field_ty = field.ty()?;
38
39 // Return early if we've found an existing fn
40 let fn_name = to_lower_snake_case(&field_name.to_string());
41 let impl_def = find_struct_impl(
42 &ctx,
43 &ast::Adt::Struct(strukt.clone()),
44 format!("{}_mut", fn_name).as_str(),
45 )?;
46
47 let target = field.syntax().text_range();
48 acc.add_group(
49 &GroupLabel("Generate getter/setter".to_owned()),
50 AssistId("generate_getter_mut", AssistKind::Generate),
51 "Generate a mut getter method",
52 target,
53 |builder| {
54 let mut buf = String::with_capacity(512);
55 let fn_name_spaced = fn_name.replace('_', " ");
56 let strukt_name_spaced =
57 to_lower_snake_case(&strukt_name.to_string()).replace('_', " ");
58
59 if impl_def.is_some() {
60 buf.push('\n');
61 }
62
63 let vis = strukt.visibility().map_or(String::new(), |v| format!("{} ", v));
64 format_to!(
65 buf,
66 " /// Get a mutable reference to the {}'s {}.
67 {}fn {}_mut(&mut self) -> &mut {} {{
68 &mut self.{}
69 }}",
70 strukt_name_spaced,
71 fn_name_spaced,
72 vis,
73 fn_name,
74 field_ty,
75 fn_name,
76 );
77
78 let start_offset = impl_def
79 .and_then(|impl_def| find_impl_block_end(impl_def, &mut buf))
80 .unwrap_or_else(|| {
81 buf = generate_impl_text(&ast::Adt::Struct(strukt.clone()), &buf);
82 strukt.syntax().text_range().end()
83 });
84
85 builder.insert(start_offset, buf);
86 },
87 )
88}
89
90#[cfg(test)]
91mod tests {
92 use crate::tests::{check_assist, check_assist_not_applicable};
93
94 use super::*;
95
96 fn check_not_applicable(ra_fixture: &str) {
97 check_assist_not_applicable(generate_getter_mut, ra_fixture)
98 }
99
100 #[test]
101 fn test_generate_getter_mut_from_field() {
102 check_assist(
103 generate_getter_mut,
104 r#"
105struct Context<T: Clone> {
106 dat$0a: T,
107}"#,
108 r#"
109struct Context<T: Clone> {
110 data: T,
111}
112
113impl<T: Clone> Context<T> {
114 /// Get a mutable reference to the context's data.
115 fn data_mut(&mut self) -> &mut T {
116 &mut self.data
117 }
118}"#,
119 );
120 }
121
122 #[test]
123 fn test_generate_getter_mut_already_implemented() {
124 check_not_applicable(
125 r#"
126struct Context<T: Clone> {
127 dat$0a: T,
128}
129
130impl<T: Clone> Context<T> {
131 fn data_mut(&mut self) -> &mut T {
132 &mut self.data
133 }
134}"#,
135 );
136 }
137
138 #[test]
139 fn test_generate_getter_mut_from_field_with_visibility_marker() {
140 check_assist(
141 generate_getter_mut,
142 r#"
143pub(crate) struct Context<T: Clone> {
144 dat$0a: T,
145}"#,
146 r#"
147pub(crate) struct Context<T: Clone> {
148 data: T,
149}
150
151impl<T: Clone> Context<T> {
152 /// Get a mutable reference to the context's data.
153 pub(crate) fn data_mut(&mut self) -> &mut T {
154 &mut self.data
155 }
156}"#,
157 );
158 }
159
160 #[test]
161 fn test_multiple_generate_getter_mut() {
162 check_assist(
163 generate_getter_mut,
164 r#"
165struct Context<T: Clone> {
166 data: T,
167 cou$0nt: usize,
168}
169
170impl<T: Clone> Context<T> {
171 /// Get a mutable reference to the context's data.
172 fn data_mut(&mut self) -> &mut T {
173 &mut self.data
174 }
175}"#,
176 r#"
177struct Context<T: Clone> {
178 data: T,
179 count: usize,
180}
181
182impl<T: Clone> Context<T> {
183 /// Get a mutable reference to the context's data.
184 fn data_mut(&mut self) -> &mut T {
185 &mut self.data
186 }
187
188 /// Get a mutable reference to the context's count.
189 fn count_mut(&mut self) -> &mut usize {
190 &mut self.count
191 }
192}"#,
193 );
194 }
195}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 05644b6ff..16af72927 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -20,8 +20,7 @@ pub mod path_transform;
20use std::str::FromStr; 20use std::str::FromStr;
21 21
22use hir::Semantics; 22use hir::Semantics;
23use ide_db::base_db::FileRange; 23use ide_db::{base_db::FileRange, label::Label, source_change::SourceChange, RootDatabase};
24use ide_db::{label::Label, source_change::SourceChange, RootDatabase};
25use syntax::TextRange; 24use syntax::TextRange;
26 25
27pub(crate) use crate::assist_context::{AssistContext, Assists}; 26pub(crate) use crate::assist_context::{AssistContext, Assists};
@@ -207,7 +206,6 @@ mod handlers {
207 mod generate_enum_projection_method; 206 mod generate_enum_projection_method;
208 mod generate_from_impl_for_enum; 207 mod generate_from_impl_for_enum;
209 mod generate_function; 208 mod generate_function;
210 mod generate_getter_mut;
211 mod generate_getter; 209 mod generate_getter;
212 mod generate_impl; 210 mod generate_impl;
213 mod generate_new; 211 mod generate_new;
@@ -277,8 +275,8 @@ mod handlers {
277 generate_enum_projection_method::generate_enum_try_into_method, 275 generate_enum_projection_method::generate_enum_try_into_method,
278 generate_from_impl_for_enum::generate_from_impl_for_enum, 276 generate_from_impl_for_enum::generate_from_impl_for_enum,
279 generate_function::generate_function, 277 generate_function::generate_function,
280 generate_getter_mut::generate_getter_mut,
281 generate_getter::generate_getter, 278 generate_getter::generate_getter,
279 generate_getter::generate_getter_mut,
282 generate_impl::generate_impl, 280 generate_impl::generate_impl,
283 generate_new::generate_new, 281 generate_new::generate_new,
284 generate_setter::generate_setter, 282 generate_setter::generate_setter,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index 6a9231e07..2b7c2d581 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -215,8 +215,8 @@ fn assist_order_field_struct() {
215 215
216 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); 216 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
217 assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`"); 217 assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`");
218 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
219 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); 218 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
219 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
220 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); 220 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
221 assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`"); 221 assert_eq!(assists.next().expect("expected assist").label, "Add `#[derive]`");
222} 222}
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 4406406a2..de5d9e55a 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -455,8 +455,8 @@ enum Action { Move { distance: u32 }, Stop }
455 455
456fn handle(action: Action) { 456fn handle(action: Action) {
457 match action { 457 match action {
458 $0Action::Move { distance } => {} 458 $0Action::Move { distance } => todo!(),
459 Action::Stop => {} 459 Action::Stop => todo!(),
460 } 460 }
461} 461}
462"#####, 462"#####,
@@ -786,8 +786,8 @@ struct Person {
786 786
787impl Person { 787impl Person {
788 /// Get a reference to the person's name. 788 /// Get a reference to the person's name.
789 fn name(&self) -> &String { 789 fn $0name(&self) -> &str {
790 &self.name 790 self.name.as_str()
791 } 791 }
792} 792}
793"#####, 793"#####,
@@ -810,7 +810,7 @@ struct Person {
810 810
811impl Person { 811impl Person {
812 /// Get a mutable reference to the person's name. 812 /// Get a mutable reference to the person's name.
813 fn name_mut(&mut self) -> &mut String { 813 fn $0name_mut(&mut self) -> &mut String {
814 &mut self.name 814 &mut self.name
815 } 815 }
816} 816}
diff --git a/crates/ide_completion/src/context.rs b/crates/ide_completion/src/context.rs
index 787eb2fd3..2f3fb1710 100644
--- a/crates/ide_completion/src/context.rs
+++ b/crates/ide_completion/src/context.rs
@@ -196,46 +196,46 @@ impl<'a> CompletionContext<'a> {
196 }; 196 };
197 197
198 let mut original_file = original_file.syntax().clone(); 198 let mut original_file = original_file.syntax().clone();
199 let mut hypothetical_file = file_with_fake_ident.syntax().clone(); 199 let mut speculative_file = file_with_fake_ident.syntax().clone();
200 let mut offset = position.offset; 200 let mut offset = position.offset;
201 let mut fake_ident_token = fake_ident_token; 201 let mut fake_ident_token = fake_ident_token;
202 202
203 // Are we inside a macro call? 203 // Are we inside a macro call?
204 while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = ( 204 while let (Some(actual_macro_call), Some(macro_call_with_fake_ident)) = (
205 find_node_at_offset::<ast::MacroCall>(&original_file, offset), 205 find_node_at_offset::<ast::MacroCall>(&original_file, offset),
206 find_node_at_offset::<ast::MacroCall>(&hypothetical_file, offset), 206 find_node_at_offset::<ast::MacroCall>(&speculative_file, offset),
207 ) { 207 ) {
208 if actual_macro_call.path().as_ref().map(|s| s.syntax().text()) 208 if actual_macro_call.path().as_ref().map(|s| s.syntax().text())
209 != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text()) 209 != macro_call_with_fake_ident.path().as_ref().map(|s| s.syntax().text())
210 { 210 {
211 break; 211 break;
212 } 212 }
213 let hypothetical_args = match macro_call_with_fake_ident.token_tree() { 213 let speculative_args = match macro_call_with_fake_ident.token_tree() {
214 Some(tt) => tt, 214 Some(tt) => tt,
215 None => break, 215 None => break,
216 }; 216 };
217 if let (Some(actual_expansion), Some(hypothetical_expansion)) = ( 217 if let (Some(actual_expansion), Some(speculative_expansion)) = (
218 ctx.sema.expand(&actual_macro_call), 218 ctx.sema.expand(&actual_macro_call),
219 ctx.sema.speculative_expand( 219 ctx.sema.speculative_expand(
220 &actual_macro_call, 220 &actual_macro_call,
221 &hypothetical_args, 221 &speculative_args,
222 fake_ident_token, 222 fake_ident_token,
223 ), 223 ),
224 ) { 224 ) {
225 let new_offset = hypothetical_expansion.1.text_range().start(); 225 let new_offset = speculative_expansion.1.text_range().start();
226 if new_offset > actual_expansion.text_range().end() { 226 if new_offset > actual_expansion.text_range().end() {
227 break; 227 break;
228 } 228 }
229 original_file = actual_expansion; 229 original_file = actual_expansion;
230 hypothetical_file = hypothetical_expansion.0; 230 speculative_file = speculative_expansion.0;
231 fake_ident_token = hypothetical_expansion.1; 231 fake_ident_token = speculative_expansion.1;
232 offset = new_offset; 232 offset = new_offset;
233 } else { 233 } else {
234 break; 234 break;
235 } 235 }
236 } 236 }
237 ctx.fill_keyword_patterns(&hypothetical_file, offset); 237 ctx.fill_keyword_patterns(&speculative_file, offset);
238 ctx.fill(&original_file, hypothetical_file, offset); 238 ctx.fill(&original_file, speculative_file, offset);
239 Some(ctx) 239 Some(ctx)
240 } 240 }
241 241
@@ -337,25 +337,24 @@ impl<'a> CompletionContext<'a> {
337 }, 337 },
338 ast::RecordExprFieldList(_it) => { 338 ast::RecordExprFieldList(_it) => {
339 cov_mark::hit!(expected_type_struct_field_without_leading_char); 339 cov_mark::hit!(expected_type_struct_field_without_leading_char);
340 self.token.prev_sibling_or_token() 340 // wouldn't try {} be nice...
341 .and_then(|se| se.into_node()) 341 (|| {
342 .and_then(|node| ast::RecordExprField::cast(node)) 342 let expr_field = self.token.prev_sibling_or_token()?
343 .and_then(|rf| self.sema.resolve_record_field(&rf).zip(Some(rf))) 343 .into_node()
344 .map(|(f, rf)|( 344 .and_then(|node| ast::RecordExprField::cast(node))?;
345 Some(f.0.ty(self.db)), 345 let (_, _, ty) = self.sema.resolve_record_field(&expr_field)?;
346 rf.field_name().map(NameOrNameRef::NameRef), 346 Some((
347 Some(ty),
348 expr_field.field_name().map(NameOrNameRef::NameRef),
347 )) 349 ))
348 .unwrap_or((None, None)) 350 })().unwrap_or((None, None))
349 }, 351 },
350 ast::RecordExprField(it) => { 352 ast::RecordExprField(it) => {
351 cov_mark::hit!(expected_type_struct_field_with_leading_char); 353 cov_mark::hit!(expected_type_struct_field_with_leading_char);
352 self.sema 354 (
353 .resolve_record_field(&it) 355 it.expr().as_ref().and_then(|e| self.sema.type_of_expr(e)),
354 .map(|f|( 356 it.field_name().map(NameOrNameRef::NameRef),
355 Some(f.0.ty(self.db)), 357 )
356 it.field_name().map(NameOrNameRef::NameRef),
357 ))
358 .unwrap_or((None, None))
359 }, 358 },
360 ast::MatchExpr(it) => { 359 ast::MatchExpr(it) => {
361 cov_mark::hit!(expected_type_match_arm_without_leading_char); 360 cov_mark::hit!(expected_type_match_arm_without_leading_char);
@@ -382,6 +381,12 @@ impl<'a> CompletionContext<'a> {
382 let def = self.sema.to_def(&it); 381 let def = self.sema.to_def(&it);
383 (def.map(|def| def.ret_type(self.db)), None) 382 (def.map(|def| def.ret_type(self.db)), None)
384 }, 383 },
384 ast::ClosureExpr(it) => {
385 let ty = self.sema.type_of_expr(&it.into());
386 ty.and_then(|ty| ty.as_callable(self.db))
387 .map(|c| (Some(c.return_type()), None))
388 .unwrap_or((None, None))
389 },
385 ast::Stmt(_it) => (None, None), 390 ast::Stmt(_it) => (None, None),
386 _ => { 391 _ => {
387 match node.parent() { 392 match node.parent() {
@@ -785,6 +790,19 @@ fn foo() {
785 } 790 }
786 791
787 #[test] 792 #[test]
793 fn expected_type_generic_struct_field() {
794 check_expected_type_and_name(
795 r#"
796struct Foo<T> { a: T }
797fn foo() -> Foo<u32> {
798 Foo { a: $0 }
799}
800"#,
801 expect![[r#"ty: u32, name: a"#]],
802 )
803 }
804
805 #[test]
788 fn expected_type_struct_field_with_leading_char() { 806 fn expected_type_struct_field_with_leading_char() {
789 cov_mark::check!(expected_type_struct_field_with_leading_char); 807 cov_mark::check!(expected_type_struct_field_with_leading_char);
790 check_expected_type_and_name( 808 check_expected_type_and_name(
@@ -895,4 +913,52 @@ fn foo() -> u32 {
895 expect![[r#"ty: u32, name: ?"#]], 913 expect![[r#"ty: u32, name: ?"#]],
896 ) 914 )
897 } 915 }
916
917 #[test]
918 fn expected_type_closure_param_return() {
919 // FIXME: make this work with `|| $0`
920 check_expected_type_and_name(
921 r#"
922fn foo() {
923 bar(|| a$0);
924}
925
926fn bar(f: impl FnOnce() -> u32) {}
927#[lang = "fn_once"]
928trait FnOnce { type Output; }
929"#,
930 expect![[r#"ty: u32, name: ?"#]],
931 );
932 }
933
934 #[test]
935 fn expected_type_generic_function() {
936 check_expected_type_and_name(
937 r#"
938fn foo() {
939 bar::<u32>($0);
940}
941
942fn bar<T>(t: T) {}
943"#,
944 expect![[r#"ty: u32, name: t"#]],
945 );
946 }
947
948 #[test]
949 fn expected_type_generic_method() {
950 check_expected_type_and_name(
951 r#"
952fn foo() {
953 S(1u32).bar($0);
954}
955
956struct S<T>(T);
957impl<T> S<T> {
958 fn bar(self, t: T) {}
959}
960"#,
961 expect![[r#"ty: u32, name: t"#]],
962 );
963 }
898} 964}
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 645349215..1152a9850 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -107,7 +107,7 @@ pub use crate::{
107/// identifier prefix/fuzzy match should be done higher in the stack, together 107/// identifier prefix/fuzzy match should be done higher in the stack, together
108/// with ordering of completions (currently this is done by the client). 108/// with ordering of completions (currently this is done by the client).
109/// 109///
110/// # Hypothetical Completion Problem 110/// # Speculative Completion Problem
111/// 111///
112/// There's a curious unsolved problem in the current implementation. Often, you 112/// There's a curious unsolved problem in the current implementation. Often, you
113/// want to compute completions on a *slightly different* text document. 113/// want to compute completions on a *slightly different* text document.
@@ -121,7 +121,7 @@ pub use crate::{
121/// doesn't allow such "phantom" inputs. 121/// doesn't allow such "phantom" inputs.
122/// 122///
123/// Another case where this would be instrumental is macro expansion. We want to 123/// Another case where this would be instrumental is macro expansion. We want to
124/// insert a fake ident and re-expand code. There's `expand_hypothetical` as a 124/// insert a fake ident and re-expand code. There's `expand_speculative` as a
125/// work-around for this. 125/// work-around for this.
126/// 126///
127/// A different use-case is completion of injection (examples and links in doc 127/// A different use-case is completion of injection (examples and links in doc
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 6b04ee164..d7f96b864 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -667,6 +667,13 @@ fn foo() { A { the$0 } }
667 ), 667 ),
668 detail: "u32", 668 detail: "u32",
669 deprecated: true, 669 deprecated: true,
670 relevance: CompletionRelevance {
671 exact_name_match: false,
672 type_match: Some(
673 CouldUnify,
674 ),
675 is_local: false,
676 },
670 }, 677 },
671 ] 678 ]
672 "#]], 679 "#]],
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
index be1cc12de..1aeda08e5 100644
--- a/crates/ide_db/src/call_info/tests.rs
+++ b/crates/ide_db/src/call_info/tests.rs
@@ -189,6 +189,24 @@ fn main() { S.foo($0); }
189} 189}
190 190
191#[test] 191#[test]
192fn test_fn_signature_for_generic_method() {
193 check(
194 r#"
195struct S<T>(T);
196impl<T> S<T> {
197 fn foo(&self, x: T) {}
198}
199
200fn main() { S(1u32).foo($0); }
201"#,
202 expect![[r#"
203 fn foo(&self, x: u32)
204 (<x: u32>)
205 "#]],
206 );
207}
208
209#[test]
192fn test_fn_signature_for_method_with_arg_as_assoc_fn() { 210fn test_fn_signature_for_method_with_arg_as_assoc_fn() {
193 check( 211 check(
194 r#" 212 r#"
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index de0dc2a40..1dcccbb8b 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -311,7 +311,7 @@ impl NameRefClass {
311 } 311 }
312 312
313 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) { 313 if let Some(record_field) = ast::RecordExprField::for_field_name(name_ref) {
314 if let Some((field, local)) = sema.resolve_record_field(&record_field) { 314 if let Some((field, local, _)) = sema.resolve_record_field(&record_field) {
315 let field = Definition::Field(field); 315 let field = Definition::Field(field);
316 let res = match local { 316 let res = match local {
317 None => NameRefClass::Definition(field), 317 None => NameRefClass::Definition(field),
diff --git a/crates/ide_db/src/ty_filter.rs b/crates/ide_db/src/ty_filter.rs
index 00678bf3e..766d8c628 100644
--- a/crates/ide_db/src/ty_filter.rs
+++ b/crates/ide_db/src/ty_filter.rs
@@ -4,7 +4,7 @@
4 4
5use std::iter; 5use std::iter;
6 6
7use hir::{Adt, Semantics, Type}; 7use hir::Semantics;
8use syntax::ast::{self, make}; 8use syntax::ast::{self, make};
9 9
10use crate::RootDatabase; 10use crate::RootDatabase;
@@ -20,9 +20,9 @@ impl TryEnum {
20 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; 20 const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result];
21 21
22 /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`. 22 /// Returns `Some(..)` if the provided type is an enum that implements `std::ops::Try`.
23 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { 23 pub fn from_ty(sema: &Semantics<RootDatabase>, ty: &hir::Type) -> Option<TryEnum> {
24 let enum_ = match ty.as_adt() { 24 let enum_ = match ty.as_adt() {
25 Some(Adt::Enum(it)) => it, 25 Some(hir::Adt::Enum(it)) => it,
26 _ => return None, 26 _ => return None,
27 }; 27 };
28 TryEnum::ALL.iter().find_map(|&var| { 28 TryEnum::ALL.iter().find_map(|&var| {
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index 3af5bc18b..b95374b76 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -14,6 +14,7 @@ mod tests;
14 14
15#[cfg(test)] 15#[cfg(test)]
16mod benchmark; 16mod benchmark;
17mod token_map;
17 18
18use std::fmt; 19use std::fmt;
19 20
@@ -63,9 +64,12 @@ impl fmt::Display for ExpandError {
63 } 64 }
64} 65}
65 66
66pub use crate::syntax_bridge::{ 67pub use crate::{
67 ast_to_token_tree, parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree, 68 syntax_bridge::{
68 token_tree_to_syntax_node, TokenMap, 69 ast_to_token_tree, parse_exprs_with_sep, parse_to_token_tree, syntax_node_to_token_tree,
70 token_tree_to_syntax_node,
71 },
72 token_map::TokenMap,
69}; 73};
70 74
71/// This struct contains AST for a single `macro_rules` definition. What might 75/// This struct contains AST for a single `macro_rules` definition. What might
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index b13168bd3..b11172caf 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -10,36 +10,8 @@ use syntax::{
10}; 10};
11use tt::buffer::{Cursor, TokenBuffer}; 11use tt::buffer::{Cursor, TokenBuffer};
12 12
13use crate::ExpandError;
14use crate::{subtree_source::SubtreeTokenSource, tt_iter::TtIter}; 13use crate::{subtree_source::SubtreeTokenSource, tt_iter::TtIter};
15 14use crate::{ExpandError, TokenMap};
16#[derive(Debug, PartialEq, Eq, Clone, Copy)]
17pub enum TokenTextRange {
18 Token(TextRange),
19 Delimiter(TextRange),
20}
21
22impl TokenTextRange {
23 pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> {