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.rs38
-rw-r--r--crates/hir/src/semantics.rs27
-rw-r--r--crates/hir/src/source_analyzer.rs9
-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.rs14
-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.rs36
-rw-r--r--crates/hir_ty/src/infer/unify.rs7
-rw-r--r--crates/hir_ty/src/lower.rs5
-rw-r--r--crates/hir_ty/src/tests/coercion.rs101
-rw-r--r--crates/ide/src/doc_links.rs6
-rw-r--r--crates/ide/src/goto_type_definition.rs32
-rw-r--r--crates/ide/src/inlay_hints.rs2
-rw-r--r--crates/ide/src/runnables.rs2
-rw-r--r--crates/ide/src/syntax_highlighting.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs84
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs4
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html18
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs38
-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.rs3
-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/semantic_tokens.rs1
-rw-r--r--crates/rust-analyzer/src/to_proto.rs3
-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
91 files changed, 1385 insertions, 779 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 a7c42ca1e..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 {
@@ -552,10 +551,6 @@ impl Struct {
552 Module { id: self.id.lookup(db.upcast()).container } 551 Module { id: self.id.lookup(db.upcast()).container }
553 } 552 }
554 553
555 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
556 Some(self.module(db).krate())
557 }
558
559 pub fn name(self, db: &dyn HirDatabase) -> Name { 554 pub fn name(self, db: &dyn HirDatabase) -> Name {
560 db.struct_data(self.id).name.clone() 555 db.struct_data(self.id).name.clone()
561 } 556 }
@@ -640,10 +635,6 @@ impl Enum {
640 Module { id: self.id.lookup(db.upcast()).container } 635 Module { id: self.id.lookup(db.upcast()).container }
641 } 636 }
642 637
643 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
644 Some(self.module(db).krate())
645 }
646
647 pub fn name(self, db: &dyn HirDatabase) -> Name { 638 pub fn name(self, db: &dyn HirDatabase) -> Name {
648 db.enum_data(self.id).name.clone() 639 db.enum_data(self.id).name.clone()
649 } 640 }
@@ -673,6 +664,7 @@ impl Variant {
673 pub fn module(self, db: &dyn HirDatabase) -> Module { 664 pub fn module(self, db: &dyn HirDatabase) -> Module {
674 self.parent.module(db) 665 self.parent.module(db)
675 } 666 }
667
676 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum { 668 pub fn parent_enum(self, _db: &dyn HirDatabase) -> Enum {
677 self.parent 669 self.parent
678 } 670 }
@@ -729,10 +721,6 @@ impl Adt {
729 } 721 }
730 } 722 }
731 723
732 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
733 self.module(db).krate()
734 }
735
736 pub fn name(self, db: &dyn HirDatabase) -> Name { 724 pub fn name(self, db: &dyn HirDatabase) -> Name {
737 match self { 725 match self {
738 Adt::Struct(s) => s.name(db), 726 Adt::Struct(s) => s.name(db),
@@ -821,10 +809,6 @@ impl Function {
821 self.id.lookup(db.upcast()).module(db.upcast()).into() 809 self.id.lookup(db.upcast()).module(db.upcast()).into()
822 } 810 }
823 811
824 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
825 Some(self.module(db).krate())
826 }
827
828 pub fn name(self, db: &dyn HirDatabase) -> Name { 812 pub fn name(self, db: &dyn HirDatabase) -> Name {
829 db.function_data(self.id).name.clone() 813 db.function_data(self.id).name.clone()
830 } 814 }
@@ -1014,10 +998,6 @@ impl Const {
1014 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 998 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1015 } 999 }
1016 1000
1017 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
1018 Some(self.module(db).krate())
1019 }
1020
1021 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 1001 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1022 db.const_data(self.id).name.clone() 1002 db.const_data(self.id).name.clone()
1023 } 1003 }
@@ -1045,10 +1025,6 @@ impl Static {
1045 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1025 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1046 } 1026 }
1047 1027
1048 pub fn krate(self, db: &dyn HirDatabase) -> Option<Crate> {
1049 Some(self.module(db).krate())
1050 }
1051
1052 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> { 1028 pub fn name(self, db: &dyn HirDatabase) -> Option<Name> {
1053 db.static_data(self.id).name.clone() 1029 db.static_data(self.id).name.clone()
1054 } 1030 }
@@ -1112,10 +1088,6 @@ impl TypeAlias {
1112 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) } 1088 Module { id: self.id.lookup(db.upcast()).module(db.upcast()) }
1113 } 1089 }
1114 1090
1115 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1116 self.module(db).krate()
1117 }
1118
1119 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1091 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1120 db.type_alias_data(self.id).type_ref.as_deref().cloned() 1092 db.type_alias_data(self.id).type_ref.as_deref().cloned()
1121 } 1093 }
@@ -1667,10 +1639,6 @@ impl Impl {
1667 self.id.lookup(db.upcast()).container.into() 1639 self.id.lookup(db.upcast()).container.into()
1668 } 1640 }
1669 1641
1670 pub fn krate(self, db: &dyn HirDatabase) -> Crate {
1671 Crate { id: self.module(db).id.krate() }
1672 }
1673
1674 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { 1642 pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> {
1675 let src = self.source(db)?; 1643 let src = self.source(db)?;
1676 let item = src.file_id.is_builtin_derive(db.upcast())?; 1644 let item = src.file_id.is_builtin_derive(db.upcast())?;
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 20753314d..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(
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 cdcab7110..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 {
@@ -91,8 +91,8 @@ pub enum TypeRef {
91 /// 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.
92 Fn(Vec<TypeRef>, bool /*varargs*/), 92 Fn(Vec<TypeRef>, bool /*varargs*/),
93 // For 93 // For
94 ImplTrait(Vec<TypeBound>), 94 ImplTrait(Vec<Interned<TypeBound>>),
95 DynTrait(Vec<TypeBound>), 95 DynTrait(Vec<Interned<TypeBound>>),
96 Macro(AstId<ast::MacroCall>), 96 Macro(AstId<ast::MacroCall>),
97 Error, 97 Error,
98} 98}
@@ -232,7 +232,7 @@ impl TypeRef {
232 | TypeRef::Slice(type_ref) => go(&type_ref, f), 232 | TypeRef::Slice(type_ref) => go(&type_ref, f),
233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 233 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
234 for bound in bounds { 234 for bound in bounds {
235 match bound { 235 match bound.as_ref() {
236 TypeBound::Path(path) => go_path(path, f), 236 TypeBound::Path(path) => go_path(path, f),
237 TypeBound::Lifetime(_) | TypeBound::Error => (), 237 TypeBound::Lifetime(_) | TypeBound::Error => (),
238 } 238 }
@@ -262,7 +262,7 @@ impl TypeRef {
262 go(type_ref, f); 262 go(type_ref, f);
263 } 263 }
264 for bound in &binding.bounds { 264 for bound in &binding.bounds {
265 match bound { 265 match bound.as_ref() {
266 TypeBound::Path(path) => go_path(path, f), 266 TypeBound::Path(path) => go_path(path, f),
267 TypeBound::Lifetime(_) | TypeBound::Error => (), 267 TypeBound::Lifetime(_) | TypeBound::Error => (),
268 } 268 }
@@ -277,9 +277,9 @@ impl TypeRef {
277pub(crate) fn type_bounds_from_ast( 277pub(crate) fn type_bounds_from_ast(
278 lower_ctx: &LowerCtx, 278 lower_ctx: &LowerCtx,
279 type_bounds_opt: Option<ast::TypeBoundList>, 279 type_bounds_opt: Option<ast::TypeBoundList>,
280) -> Vec<TypeBound> { 280) -> Vec<Interned<TypeBound>> {
281 if let Some(type_bounds) = type_bounds_opt { 281 if let Some(type_bounds) = type_bounds_opt {
282 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()
283 } else { 283 } else {
284 vec![] 284 vec![]
285 } 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..79a732106 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -805,7 +805,7 @@ impl<'a> InferenceContext<'a> {
805 None => self.table.new_float_var(), 805 None => self.table.new_float_var(),
806 }, 806 },
807 }, 807 },
808 Expr::MacroStmts { tail } => self.infer_expr(*tail, expected), 808 Expr::MacroStmts { tail } => self.infer_expr_inner(*tail, expected),
809 }; 809 };
810 // use a new type variable if we got unknown here 810 // use a new type variable if we got unknown here
811 let ty = self.insert_type_vars_shallow(ty); 811 let ty = self.insert_type_vars_shallow(ty);
@@ -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/hir_ty/src/tests/coercion.rs b/crates/hir_ty/src/tests/coercion.rs
index bb568ea37..6dac7e103 100644
--- a/crates/hir_ty/src/tests/coercion.rs
+++ b/crates/hir_ty/src/tests/coercion.rs
@@ -832,11 +832,9 @@ fn coerce_unsize_super_trait_cycle() {
832 ); 832 );
833} 833}
834 834
835#[ignore]
836#[test] 835#[test]
837fn coerce_unsize_generic() { 836fn coerce_unsize_generic() {
838 // FIXME: Implement this 837 // FIXME: fix the type mismatches here
839 // https://doc.rust-lang.org/reference/type-coercions.html#unsized-coercions
840 check_infer_with_mismatches( 838 check_infer_with_mismatches(
841 r#" 839 r#"
842 #[lang = "unsize"] 840 #[lang = "unsize"]
@@ -854,8 +852,58 @@ fn coerce_unsize_generic() {
854 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] }); 852 let _: &Bar<[usize]> = &Bar(Foo { t: [1, 2, 3] });
855 } 853 }
856 "#, 854 "#,
857 expect![[r" 855 expect![[r#"
858 "]], 856 209..317 '{ ... }); }': ()
857 219..220 '_': &Foo<[usize]>
858 238..259 '&Foo {..., 3] }': &Foo<[usize]>
859 239..259 'Foo { ..., 3] }': Foo<[usize]>
860 248..257 '[1, 2, 3]': [usize; 3]
861 249..250 '1': usize
862 252..253 '2': usize
863 255..256 '3': usize
864 269..270 '_': &Bar<[usize]>
865 288..314 '&Bar(F... 3] })': &Bar<[i32; 3]>
866 289..292 'Bar': Bar<[i32; 3]>(Foo<[i32; 3]>) -> Bar<[i32; 3]>
867 289..314 'Bar(Fo... 3] })': Bar<[i32; 3]>
868 293..313 'Foo { ..., 3] }': Foo<[i32; 3]>
869 302..311 '[1, 2, 3]': [i32; 3]
870 303..304 '1': i32
871 306..307 '2': i32
872 309..310 '3': i32
873 248..257: expected [usize], got [usize; 3]
874 288..314: expected &Bar<[usize]>, got &Bar<[i32; 3]>
875 "#]],
876 );
877}
878
879#[test]
880fn coerce_unsize_apit() {
881 // FIXME: #8984
882 check_infer_with_mismatches(
883 r#"
884#[lang = "sized"]
885pub trait Sized {}
886#[lang = "unsize"]
887pub trait Unsize<T> {}
888#[lang = "coerce_unsized"]
889pub trait CoerceUnsized<T> {}
890
891impl<T: Unsize<U>, U> CoerceUnsized<&U> for &T {}
892
893trait Foo {}
894
895fn test(f: impl Foo) {
896 let _: &dyn Foo = &f;
897}
898 "#,
899 expect![[r#"
900 210..211 'f': impl Foo
901 223..252 '{ ... &f; }': ()
902 233..234 '_': &dyn Foo
903 247..249 '&f': &impl Foo
904 248..249 'f': impl Foo
905 247..249: expected &dyn Foo, got &impl Foo
906 "#]],
859 ); 907 );
860} 908}
861 909
@@ -912,3 +960,46 @@ fn test() -> i32 {
912 "#, 960 "#,
913 ) 961 )
914} 962}
963
964#[test]
965fn panic_macro() {
966 check_infer_with_mismatches(
967 r#"
968mod panic {
969 #[macro_export]
970 pub macro panic_2015 {
971 () => (
972 $crate::panicking::panic()
973 ),
974 }
975}
976
977mod panicking {
978 pub fn panic() -> ! { loop {} }
979}
980
981#[rustc_builtin_macro = "core_panic"]
982macro_rules! panic {
983 // Expands to either `$crate::panic::panic_2015` or `$crate::panic::panic_2021`
984 // depending on the edition of the caller.
985 ($($arg:tt)*) => {
986 /* compiler built-in */
987 };
988}
989
990fn main() {
991 panic!()
992}
993 "#,
994 expect![[r#"
995 174..185 '{ loop {} }': !
996 176..183 'loop {}': !
997 181..183 '{}': ()
998 !0..24 '$crate...:panic': fn panic() -> !
999 !0..26 '$crate...anic()': !
1000 !0..26 '$crate...anic()': !
1001 !0..28 '$crate...015!()': !
1002 454..470 '{ ...c!() }': ()
1003 "#]],
1004 );
1005}
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/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index f3284bb96..004d9cb68 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -1,3 +1,4 @@
1use ide_db::base_db::Upcast;
1use ide_db::RootDatabase; 2use ide_db::RootDatabase;
2use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T}; 3use syntax::{ast, match_ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset, T};
3 4
@@ -31,6 +32,7 @@ pub(crate) fn goto_type_definition(
31 ast::Pat(it) => sema.type_of_pat(&it)?, 32 ast::Pat(it) => sema.type_of_pat(&it)?,
32 ast::SelfParam(it) => sema.type_of_self(&it)?, 33 ast::SelfParam(it) => sema.type_of_self(&it)?,
33 ast::Type(it) => sema.resolve_type(&it)?, 34 ast::Type(it) => sema.resolve_type(&it)?,
35 ast::RecordField(it) => sema.to_def(&it).map(|d| d.ty(db.upcast()))?,
34 _ => return None, 36 _ => return None,
35 } 37 }
36 }; 38 };
@@ -161,4 +163,34 @@ impl Foo$0 {}
161"#, 163"#,
162 ) 164 )
163 } 165 }
166
167 #[test]
168 fn goto_def_for_struct_field() {
169 check(
170 r#"
171struct Bar;
172 //^^^
173
174struct Foo {
175 bar$0: Bar,
176}
177"#,
178 );
179 }
180
181 #[test]
182 fn goto_def_for_enum_struct_field() {
183 check(
184 r#"
185struct Bar;
186 //^^^
187
188enum Foo {
189 Bar {
190 bar$0: Bar
191 },
192}
193"#,
194 );
195 }
164} 196}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 8f490e922..85f887737 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -219,7 +219,7 @@ fn hint_iterator(
219) -> Option<SmolStr> { 219) -> Option<SmolStr> {
220 let db = sema.db; 220 let db = sema.db;
221 let strukt = ty.strip_references().as_adt()?; 221 let strukt = ty.strip_references().as_adt()?;
222 let krate = strukt.krate(db); 222 let krate = strukt.module(db).krate();
223 if krate != famous_defs.core()? { 223 if krate != famous_defs.core()? {
224 return None; 224 return None;
225 } 225 }
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index f76715d84..ce1c76f37 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -227,7 +227,7 @@ pub(crate) fn runnable_fn(sema: &Semantics<RootDatabase>, def: hir::Function) ->
227 let func = def.source(sema.db)?; 227 let func = def.source(sema.db)?;
228 let name_string = def.name(sema.db).to_string(); 228 let name_string = def.name(sema.db).to_string();
229 229
230 let root = def.krate(sema.db)?.root_module(sema.db); 230 let root = def.module(sema.db).krate().root_module(sema.db);
231 231
232 let kind = if name_string == "main" && def.module(sema.db) == root { 232 let kind = if name_string == "main" && def.module(sema.db) == root {
233 RunnableKind::Bin 233 RunnableKind::Bin
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 9df8d21af..cf1a8bad7 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -80,6 +80,7 @@ pub(crate) fn highlight(
80 &mut hl, 80 &mut hl,
81 &sema, 81 &sema,
82 InFile::new(file_id.into(), &root), 82 InFile::new(file_id.into(), &root),
83 sema.scope(&root).krate(),
83 range_to_highlight, 84 range_to_highlight,
84 syntactic_name_ref_highlighting, 85 syntactic_name_ref_highlighting,
85 ); 86 );
@@ -90,6 +91,7 @@ fn traverse(
90 hl: &mut Highlights, 91 hl: &mut Highlights,
91 sema: &Semantics<RootDatabase>, 92 sema: &Semantics<RootDatabase>,
92 root: InFile<&SyntaxNode>, 93 root: InFile<&SyntaxNode>,
94 krate: Option<hir::Crate>,
93 range_to_highlight: TextRange, 95 range_to_highlight: TextRange,
94 syntactic_name_ref_highlighting: bool, 96 syntactic_name_ref_highlighting: bool,
95) { 97) {
@@ -209,6 +211,7 @@ fn traverse(
209 211
210 if let Some((mut highlight, binding_hash)) = highlight::element( 212 if let Some((mut highlight, binding_hash)) = highlight::element(
211 &sema, 213 &sema,
214 krate,
212 &mut bindings_shadow_count, 215 &mut bindings_shadow_count,
213 syntactic_name_ref_highlighting, 216 syntactic_name_ref_highlighting,
214 element_to_highlight.clone(), 217 element_to_highlight.clone(),
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 058e37ff0..b4a3d39c9 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -19,6 +19,7 @@ use crate::{
19 19
20pub(super) fn element( 20pub(super) fn element(
21 sema: &Semantics<RootDatabase>, 21 sema: &Semantics<RootDatabase>,
22 krate: Option<hir::Crate>,
22 bindings_shadow_count: &mut FxHashMap<hir::Name, u32>, 23 bindings_shadow_count: &mut FxHashMap<hir::Name, u32>,
23 syntactic_name_ref_highlighting: bool, 24 syntactic_name_ref_highlighting: bool,
24 element: SyntaxElement, 25 element: SyntaxElement,
@@ -46,8 +47,10 @@ pub(super) fn element(
46 47
47 match name_kind { 48 match name_kind {
48 Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(), 49 Some(NameClass::ExternCrate(_)) => SymbolKind::Module.into(),
49 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, 50 Some(NameClass::Definition(def)) => {
50 Some(NameClass::ConstReference(def)) => highlight_def(db, def), 51 highlight_def(db, krate, def) | HlMod::Definition
52 }
53 Some(NameClass::ConstReference(def)) => highlight_def(db, krate, def),
51 Some(NameClass::PatFieldShorthand { field_ref, .. }) => { 54 Some(NameClass::PatFieldShorthand { field_ref, .. }) => {
52 let mut h = HlTag::Symbol(SymbolKind::Field).into(); 55 let mut h = HlTag::Symbol(SymbolKind::Field).into();
53 if let Definition::Field(field) = field_ref { 56 if let Definition::Field(field) = field_ref {
@@ -82,7 +85,7 @@ pub(super) fn element(
82 } 85 }
83 }; 86 };
84 87
85 let mut h = highlight_def(db, def); 88 let mut h = highlight_def(db, krate, def);
86 89
87 if let Definition::Local(local) = &def { 90 if let Definition::Local(local) = &def {
88 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) { 91 if is_consumed_lvalue(name_ref.syntax().clone().into(), local, db) {
@@ -136,9 +139,11 @@ pub(super) fn element(
136 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); 139 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
137 140
138 match NameClass::classify_lifetime(sema, &lifetime) { 141 match NameClass::classify_lifetime(sema, &lifetime) {
139 Some(NameClass::Definition(def)) => highlight_def(db, def) | HlMod::Definition, 142 Some(NameClass::Definition(def)) => {
143 highlight_def(db, krate, def) | HlMod::Definition
144 }
140 None => match NameRefClass::classify_lifetime(sema, &lifetime) { 145 None => match NameRefClass::classify_lifetime(sema, &lifetime) {
141 Some(NameRefClass::Definition(def)) => highlight_def(db, def), 146 Some(NameRefClass::Definition(def)) => highlight_def(db, krate, def),
142 _ => SymbolKind::LifetimeParam.into(), 147 _ => SymbolKind::LifetimeParam.into(),
143 }, 148 },
144 _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition, 149 _ => Highlight::from(SymbolKind::LifetimeParam) | HlMod::Definition,
@@ -277,12 +282,12 @@ pub(super) fn element(
277 hash((name, shadow_count)) 282 hash((name, shadow_count))
278 } 283 }
279} 284}
280fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight { 285fn highlight_def(db: &RootDatabase, krate: Option<hir::Crate>, def: Definition) -> Highlight {
281 match def { 286 let mut h = match def {
282 Definition::Macro(_) => HlTag::Symbol(SymbolKind::Macro), 287 Definition::Macro(_) => Highlight::new(HlTag::Symbol(SymbolKind::Macro)),
283 Definition::Field(_) => HlTag::Symbol(SymbolKind::Field), 288 Definition::Field(_) => Highlight::new(HlTag::Symbol(SymbolKind::Field)),
284 Definition::ModuleDef(def) => match def { 289 Definition::ModuleDef(def) => match def {
285 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), 290 hir::ModuleDef::Module(_) => Highlight::new(HlTag::Symbol(SymbolKind::Module)),
286 hir::ModuleDef::Function(func) => { 291 hir::ModuleDef::Function(func) => {
287 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); 292 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
288 if let Some(item) = func.as_assoc_item(db) { 293 if let Some(item) = func.as_assoc_item(db) {
@@ -314,14 +319,22 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
314 if func.is_async(db) { 319 if func.is_async(db) {
315 h |= HlMod::Async; 320 h |= HlMod::Async;
316 } 321 }
317 return h; 322
323 h
318 } 324 }
319 hir::ModuleDef::Adt(hir::Adt::Struct(_)) => HlTag::Symbol(SymbolKind::Struct), 325 hir::ModuleDef::Adt(adt) => {
320 hir::ModuleDef::Adt(hir::Adt::Enum(_)) => HlTag::Symbol(SymbolKind::Enum), 326 let h = match adt {
321 hir::ModuleDef::Adt(hir::Adt::Union(_)) => HlTag::Symbol(SymbolKind::Union), 327 hir::Adt::Struct(_) => HlTag::Symbol(SymbolKind::Struct),
322 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), 328 hir::Adt::Enum(_) => HlTag::Symbol(SymbolKind::Enum),
329 hir::Adt::Union(_) => HlTag::Symbol(SymbolKind::Union),
330 };
331
332 Highlight::new(h)
333 }
334 hir::ModuleDef::Variant(_) => Highlight::new(HlTag::Symbol(SymbolKind::Variant)),
323 hir::ModuleDef::Const(konst) => { 335 hir::ModuleDef::Const(konst) => {
324 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); 336 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
337
325 if let Some(item) = konst.as_assoc_item(db) { 338 if let Some(item) = konst.as_assoc_item(db) {
326 h |= HlMod::Associated; 339 h |= HlMod::Associated;
327 match item.container(db) { 340 match item.container(db) {
@@ -336,7 +349,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
336 } 349 }
337 } 350 }
338 351
339 return h; 352 h
340 } 353 }
341 hir::ModuleDef::Trait(trait_) => { 354 hir::ModuleDef::Trait(trait_) => {
342 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait)); 355 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Trait));
@@ -344,10 +357,12 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
344 if trait_.is_unsafe(db) { 357 if trait_.is_unsafe(db) {
345 h |= HlMod::Unsafe; 358 h |= HlMod::Unsafe;
346 } 359 }
347 return h; 360
361 h
348 } 362 }
349 hir::ModuleDef::TypeAlias(type_) => { 363 hir::ModuleDef::TypeAlias(type_) => {
350 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 364 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
365
351 if let Some(item) = type_.as_assoc_item(db) { 366 if let Some(item) = type_.as_assoc_item(db) {
352 h |= HlMod::Associated; 367 h |= HlMod::Associated;
353 match item.container(db) { 368 match item.container(db) {
@@ -361,23 +376,30 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
361 } 376 }
362 } 377 }
363 } 378 }
364 return h; 379
380 h
365 } 381 }
366 hir::ModuleDef::BuiltinType(_) => HlTag::BuiltinType, 382 hir::ModuleDef::BuiltinType(_) => Highlight::new(HlTag::BuiltinType),
367 hir::ModuleDef::Static(s) => { 383 hir::ModuleDef::Static(s) => {
368 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static)); 384 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Static));
385
369 if s.is_mut(db) { 386 if s.is_mut(db) {
370 h |= HlMod::Mutable; 387 h |= HlMod::Mutable;
371 h |= HlMod::Unsafe; 388 h |= HlMod::Unsafe;
372 } 389 }
373 return h; 390
391 h
374 } 392 }
375 }, 393 },
376 Definition::SelfType(_) => HlTag::Symbol(SymbolKind::Impl), 394 Definition::SelfType(_) => Highlight::new(HlTag::Symbol(SymbolKind::Impl)),
377 Definition::GenericParam(it) => match it { 395 Definition::GenericParam(it) => match it {
378 hir::GenericParam::TypeParam(_) => HlTag::Symbol(SymbolKind::TypeParam), 396 hir::GenericParam::TypeParam(_) => Highlight::new(HlTag::Symbol(SymbolKind::TypeParam)),
379 hir::GenericParam::ConstParam(_) => HlTag::Symbol(SymbolKind::ConstParam), 397 hir::GenericParam::ConstParam(_) => {
380 hir::GenericParam::LifetimeParam(_) => HlTag::Symbol(SymbolKind::LifetimeParam), 398 Highlight::new(HlTag::Symbol(SymbolKind::ConstParam))
399 }
400 hir::GenericParam::LifetimeParam(_) => {
401 Highlight::new(HlTag::Symbol(SymbolKind::LifetimeParam))
402 }
381 }, 403 },
382 Definition::Local(local) => { 404 Definition::Local(local) => {
383 let tag = if local.is_self(db) { 405 let tag = if local.is_self(db) {
@@ -395,11 +417,19 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
395 if ty.as_callable(db).is_some() || ty.impls_fnonce(db) { 417 if ty.as_callable(db).is_some() || ty.impls_fnonce(db) {
396 h |= HlMod::Callable; 418 h |= HlMod::Callable;
397 } 419 }
398 return h; 420 h
399 } 421 }
400 Definition::Label(_) => HlTag::Symbol(SymbolKind::Label), 422 Definition::Label(_) => Highlight::new(HlTag::Symbol(SymbolKind::Label)),
423 };
424
425 let is_from_other_crate = def.module(db).map(hir::Module::krate) != krate;
426 let is_builtin_type = matches!(def, Definition::ModuleDef(hir::ModuleDef::BuiltinType(_)));
427
428 if is_from_other_crate && !is_builtin_type {
429 h |= HlMod::Library;
401 } 430 }
402 .into() 431
432 h
403} 433}
404 434
405fn highlight_func_by_name_ref( 435fn highlight_func_by_name_ref(
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 27473a2f9..e94f17cd9 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -67,6 +67,8 @@ pub enum HlMod {
67 Trait, 67 Trait,
68 /// Used with keywords like `async` and `await`. 68 /// Used with keywords like `async` and `await`.
69 Async, 69 Async,
70 /// Used for items from other crates.
71 Library,
70 // Keep this last! 72 // Keep this last!
71 /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations. 73 /// Used for unsafe functions, unsafe traits, mutable statics, union accesses and unsafe operations.
72 Unsafe, 74 Unsafe,
@@ -189,6 +191,7 @@ impl HlMod {
189 HlMod::Static, 191 HlMod::Static,
190 HlMod::Trait, 192 HlMod::Trait,
191 HlMod::Async, 193 HlMod::Async,
194 HlMod::Library,
192 HlMod::Unsafe, 195 HlMod::Unsafe,
193 ]; 196 ];
194 197
@@ -207,6 +210,7 @@ impl HlMod {
207 HlMod::Static => "static", 210 HlMod::Static => "static",
208 HlMod::Trait => "trait", 211 HlMod::Trait => "trait",
209 HlMod::Async => "async", 212 HlMod::Async => "async",
213 HlMod::Library => "library",
210 HlMod::Unsafe => "unsafe", 214 HlMod::Unsafe => "unsafe",
211 } 215 }
212 } 216 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 878431b56..055d21109 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -248,4 +248,20 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
248<span class="brace">}</span> 248<span class="brace">}</span>
249 249
250<span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span> 250<span class="keyword unsafe">unsafe</span> <span class="keyword">trait</span> <span class="trait declaration unsafe">Dangerous</span> <span class="brace">{</span><span class="brace">}</span>
251<span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span></code></pre> \ No newline at end of file 251<span class="keyword">impl</span> <span class="trait unsafe">Dangerous</span> <span class="keyword">for</span> <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
252
253<span class="keyword">fn</span> <span class="function declaration">use_foo_items</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
254 <span class="keyword">let</span> <span class="variable declaration">bob</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="struct library">Person</span> <span class="brace">{</span>
255 <span class="field library">name</span><span class="colon">:</span> <span class="string_literal">"Bob"</span><span class="comma">,</span>
256 <span class="field library">age</span><span class="colon">:</span> <span class="module library">foo</span><span class="operator">::</span><span class="module library">consts</span><span class="operator">::</span><span class="constant library">NUMBER</span><span class="comma">,</span>
257 <span class="brace">}</span><span class="semicolon">;</span>
258
259 <span class="keyword">let</span> <span class="variable declaration">control_flow</span> <span class="operator">=</span> <span class="module library">foo</span><span class="operator">::</span><span class="function library">identity</span><span class="parenthesis">(</span><span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Continue</span><span class="parenthesis">)</span><span class="semicolon">;</span>
260
261 <span class="keyword control">if</span> <span class="keyword">let</span> <span class="module library">foo</span><span class="operator">::</span><span class="enum library">ControlFlow</span><span class="operator">::</span><span class="enum_variant library">Die</span> <span class="operator">=</span> <span class="variable">control_flow</span> <span class="brace">{</span>
262 foo::<span class="macro">die!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
263 <span class="brace">}</span>
264<span class="brace">}</span>
265
266
267</code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 9ce26e930..be4447ebb 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -10,6 +10,7 @@ use crate::{fixture, FileRange, HlTag, TextRange};
10fn test_highlighting() { 10fn test_highlighting() {
11 check_highlighting( 11 check_highlighting(
12 r#" 12 r#"
13//- /main.rs crate:main deps:foo
13use inner::{self as inner_mod}; 14use inner::{self as inner_mod};
14mod inner {} 15mod inner {}
15 16
@@ -222,6 +223,43 @@ async fn async_main() {
222 223
223unsafe trait Dangerous {} 224unsafe trait Dangerous {}
224impl Dangerous for () {} 225impl Dangerous for () {}
226
227fn use_foo_items() {
228 let bob = foo::Person {
229 name: "Bob",
230 age: foo::consts::NUMBER,
231 };
232
233 let control_flow = foo::identity(foo::ControlFlow::Continue);
234
235 if let foo::ControlFlow::Die = control_flow {
236 foo::die!();
237 }
238}
239
240
241//- /foo.rs crate:foo
242pub struct Person {
243 pub name: &'static str,
244 pub age: u8,
245}
246
247pub enum ControlFlow {
248 Continue,
249 Die,
250}
251
252pub fn identity<T>(x: T) -> T { x }
253
254pub mod consts {
255 pub const NUMBER: i64 = 92;
256}
257
258macro_rules! die {
259 () => {
260 panic!();
261 };
262}
225"# 263"#
226 .trim(), 264 .trim(),
227 expect_file!["./test_data/highlighting.html"], 265 expect_file!["./test_data/highlighting.html"],
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//