aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Cargo.lock173
-rw-r--r--crates/ra_assists/src/ast_editor.rs30
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/move_bounds.rs135
-rw-r--r--crates/ra_batch/Cargo.toml2
-rw-r--r--crates/ra_batch/src/lib.rs3
-rw-r--r--crates/ra_cli/src/analysis_bench.rs5
-rw-r--r--crates/ra_cli/src/analysis_stats.rs9
-rw-r--r--crates/ra_db/src/input.rs16
-rw-r--r--crates/ra_db/src/lib.rs5
-rw-r--r--crates/ra_hir/src/code_model/src.rs31
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/expr.rs60
-rw-r--r--crates/ra_hir/src/expr/lower.rs238
-rw-r--r--crates/ra_hir/src/expr/validation.rs47
-rw-r--r--crates/ra_hir/src/lib.rs4
-rw-r--r--crates/ra_hir/src/marks.rs2
-rw-r--r--crates/ra_hir/src/mock.rs2
-rw-r--r--crates/ra_hir/src/nameres.rs100
-rw-r--r--crates/ra_hir/src/nameres/collector.rs249
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs186
-rw-r--r--crates/ra_hir/src/nameres/raw.rs13
-rw-r--r--crates/ra_hir/src/nameres/tests.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs121
-rw-r--r--crates/ra_hir/src/nameres/tests/mod_resolution.rs (renamed from crates/ra_hir/src/nameres/tests/mods.rs)0
-rw-r--r--crates/ra_hir/src/path.rs21
-rw-r--r--crates/ra_hir/src/source_binder.rs29
-rw-r--r--crates/ra_hir/src/ty.rs348
-rw-r--r--crates/ra_hir/src/ty/autoderef.rs2
-rw-r--r--crates/ra_hir/src/ty/infer.rs2
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs2
-rw-r--r--crates/ra_hir/src/ty/lower.rs86
-rw-r--r--crates/ra_hir/src/ty/tests.rs124
-rw-r--r--crates/ra_hir/src/ty/traits.rs17
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs8
-rw-r--r--crates/ra_ide_api/src/change.rs4
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs2
-rw-r--r--crates/ra_ide_api/src/lib.rs4
-rw-r--r--crates/ra_ide_api/src/references.rs154
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs2
-rw-r--r--crates/ra_ide_api/src/syntax_tree.rs714
-rw-r--r--crates/ra_lsp_server/Cargo.toml4
-rw-r--r--crates/ra_lsp_server/src/caps.rs1
-rw-r--r--crates/ra_lsp_server/src/config.rs3
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs174
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs14
-rw-r--r--crates/ra_lsp_server/src/req.rs9
-rw-r--r--crates/ra_lsp_server/src/world.rs5
-rw-r--r--crates/ra_parser/src/grammar/items.rs2
-rw-r--r--crates/ra_parser/src/grammar/items/use_item.rs5
-rw-r--r--crates/ra_project_model/src/lib.rs2
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs1
-rw-r--r--crates/ra_syntax/src/grammar.ron1
-rw-r--r--crates/ra_syntax/src/ptr.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0035_use_recover.txt54
-rw-r--r--crates/ra_vfs_glob/Cargo.toml2
-rw-r--r--docs/user/README.md2
-rw-r--r--docs/user/features.md10
-rw-r--r--editors/code/package.json5
-rw-r--r--editors/code/src/config.ts4
-rw-r--r--editors/code/src/server.ts1
-rw-r--r--rustfmt.toml1
65 files changed, 2066 insertions, 1206 deletions
diff --git a/Cargo.lock b/Cargo.lock
index d1fa5ebee..f93f11a82 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -32,7 +32,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
32 32
33[[package]] 33[[package]]
34name = "backtrace" 34name = "backtrace"
35version = "0.3.35" 35version = "0.3.37"
36source = "registry+https://github.com/rust-lang/crates.io-index" 36source = "registry+https://github.com/rust-lang/crates.io-index"
37dependencies = [ 37dependencies = [
38 "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", 38 "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -46,7 +46,7 @@ name = "backtrace-sys"
46version = "0.1.31" 46version = "0.1.31"
47source = "registry+https://github.com/rust-lang/crates.io-index" 47source = "registry+https://github.com/rust-lang/crates.io-index"
48dependencies = [ 48dependencies = [
49 "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", 49 "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
50 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 50 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
51] 51]
52 52
@@ -78,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
78 78
79[[package]] 79[[package]]
80name = "bstr" 80name = "bstr"
81version = "0.2.7" 81version = "0.2.8"
82source = "registry+https://github.com/rust-lang/crates.io-index" 82source = "registry+https://github.com/rust-lang/crates.io-index"
83dependencies = [ 83dependencies = [
84 "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 84 "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -111,7 +111,7 @@ dependencies = [
111 111
112[[package]] 112[[package]]
113name = "cc" 113name = "cc"
114version = "1.0.41" 114version = "1.0.42"
115source = "registry+https://github.com/rust-lang/crates.io-index" 115source = "registry+https://github.com/rust-lang/crates.io-index"
116 116
117[[package]] 117[[package]]
@@ -122,7 +122,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
122[[package]] 122[[package]]
123name = "chalk-engine" 123name = "chalk-engine"
124version = "0.9.0" 124version = "0.9.0"
125source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 125source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
126dependencies = [ 126dependencies = [
127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 128 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -132,7 +132,7 @@ dependencies = [
132[[package]] 132[[package]]
133name = "chalk-ir" 133name = "chalk-ir"
134version = "0.1.0" 134version = "0.1.0"
135source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 135source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
136dependencies = [ 136dependencies = [
137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 138 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
@@ -142,7 +142,7 @@ dependencies = [
142[[package]] 142[[package]]
143name = "chalk-macros" 143name = "chalk-macros"
144version = "0.1.1" 144version = "0.1.1"
145source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 145source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
146dependencies = [ 146dependencies = [
147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
148] 148]
@@ -150,7 +150,7 @@ dependencies = [
150[[package]] 150[[package]]
151name = "chalk-rust-ir" 151name = "chalk-rust-ir"
152version = "0.1.0" 152version = "0.1.0"
153source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 153source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
154dependencies = [ 154dependencies = [
155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 156 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -160,7 +160,7 @@ dependencies = [
160[[package]] 160[[package]]
161name = "chalk-solve" 161name = "chalk-solve"
162version = "0.1.0" 162version = "0.1.0"
163source = "git+https://github.com/rust-lang/chalk.git#c9314e425e49969c33cabcb8fac7da6eac3c5073" 163source = "git+https://github.com/rust-lang/chalk.git#5c6cea8bc02c8bc282223aa12528648b5cd0b6e4"
164dependencies = [ 164dependencies = [
165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)",
166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 166 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -176,7 +176,7 @@ dependencies = [
176 176
177[[package]] 177[[package]]
178name = "chrono" 178name = "chrono"
179version = "0.4.7" 179version = "0.4.9"
180source = "registry+https://github.com/rust-lang/crates.io-index" 180source = "registry+https://github.com/rust-lang/crates.io-index"
181dependencies = [ 181dependencies = [
182 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 182 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -223,7 +223,7 @@ dependencies = [
223 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 223 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
224 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 224 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
225 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 225 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
226 "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 226 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
227 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 227 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
228 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 228 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
229 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 229 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -252,15 +252,6 @@ dependencies = [
252 252
253[[package]] 253[[package]]
254name = "crossbeam-deque" 254name = "crossbeam-deque"
255version = "0.6.3"
256source = "registry+https://github.com/rust-lang/crates.io-index"
257dependencies = [
258 "crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
259 "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
260]
261
262[[package]]
263name = "crossbeam-deque"
264version = "0.7.1" 255version = "0.7.1"
265source = "registry+https://github.com/rust-lang/crates.io-index" 256source = "registry+https://github.com/rust-lang/crates.io-index"
266dependencies = [ 257dependencies = [
@@ -303,7 +294,7 @@ name = "derive-new"
303version = "0.5.8" 294version = "0.5.8"
304source = "registry+https://github.com/rust-lang/crates.io-index" 295source = "registry+https://github.com/rust-lang/crates.io-index"
305dependencies = [ 296dependencies = [
306 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 297 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
307 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 298 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
308 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 299 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
309] 300]
@@ -346,7 +337,7 @@ name = "failure"
346version = "0.1.5" 337version = "0.1.5"
347source = "registry+https://github.com/rust-lang/crates.io-index" 338source = "registry+https://github.com/rust-lang/crates.io-index"
348dependencies = [ 339dependencies = [
349 "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 340 "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
350 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 341 "failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
351] 342]
352 343
@@ -363,12 +354,13 @@ dependencies = [
363 354
364[[package]] 355[[package]]
365name = "filetime" 356name = "filetime"
366version = "0.2.5" 357version = "0.2.7"
367source = "registry+https://github.com/rust-lang/crates.io-index" 358source = "registry+https://github.com/rust-lang/crates.io-index"
368dependencies = [ 359dependencies = [
369 "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 360 "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
370 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 361 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
371 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 362 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
363 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
372] 364]
373 365
374[[package]] 366[[package]]
@@ -381,10 +373,10 @@ name = "flexi_logger"
381version = "0.14.3" 373version = "0.14.3"
382source = "registry+https://github.com/rust-lang/crates.io-index" 374source = "registry+https://github.com/rust-lang/crates.io-index"
383dependencies = [ 375dependencies = [
384 "chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)", 376 "chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)",
385 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 377 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
386 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 378 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
387 "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 379 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
388 "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 380 "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
389] 381]
390 382
@@ -468,10 +460,10 @@ version = "0.4.4"
468source = "registry+https://github.com/rust-lang/crates.io-index" 460source = "registry+https://github.com/rust-lang/crates.io-index"
469dependencies = [ 461dependencies = [
470 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 462 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
471 "bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 463 "bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
472 "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 464 "fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
473 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 465 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
474 "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 466 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
475] 467]
476 468
477[[package]] 469[[package]]
@@ -506,7 +498,7 @@ dependencies = [
506 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 498 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
507 "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 499 "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
508 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 500 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
509 "regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 501 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
510] 502]
511 503
512[[package]] 504[[package]]
@@ -578,7 +570,7 @@ name = "jemalloc-sys"
578version = "0.3.2" 570version = "0.3.2"
579source = "registry+https://github.com/rust-lang/crates.io-index" 571source = "registry+https://github.com/rust-lang/crates.io-index"
580dependencies = [ 572dependencies = [
581 "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", 573 "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
582 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 574 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
583 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 575 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
584] 576]
@@ -665,7 +657,7 @@ dependencies = [
665 657
666[[package]] 658[[package]]
667name = "lsp-types" 659name = "lsp-types"
668version = "0.60.0" 660version = "0.61.0"
669source = "registry+https://github.com/rust-lang/crates.io-index" 661source = "registry+https://github.com/rust-lang/crates.io-index"
670dependencies = [ 662dependencies = [
671 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 663 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -749,11 +741,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
749 741
750[[package]] 742[[package]]
751name = "notify" 743name = "notify"
752version = "4.0.12" 744version = "4.0.13"
753source = "registry+https://github.com/rust-lang/crates.io-index" 745source = "registry+https://github.com/rust-lang/crates.io-index"
754dependencies = [ 746dependencies = [
755 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 747 "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
756 "filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", 748 "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
757 "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 749 "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
758 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 750 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
759 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", 751 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -800,7 +792,7 @@ dependencies = [
800 792
801[[package]] 793[[package]]
802name = "once_cell" 794name = "once_cell"
803version = "1.0.1" 795version = "1.0.2"
804source = "registry+https://github.com/rust-lang/crates.io-index" 796source = "registry+https://github.com/rust-lang/crates.io-index"
805 797
806[[package]] 798[[package]]
@@ -847,7 +839,7 @@ version = "0.1.6"
847source = "registry+https://github.com/rust-lang/crates.io-index" 839source = "registry+https://github.com/rust-lang/crates.io-index"
848dependencies = [ 840dependencies = [
849 "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", 841 "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)",
850 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 842 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
851 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 843 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
852 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 844 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
853] 845]
@@ -876,7 +868,7 @@ name = "proc-macro-hack"
876version = "0.5.9" 868version = "0.5.9"
877source = "registry+https://github.com/rust-lang/crates.io-index" 869source = "registry+https://github.com/rust-lang/crates.io-index"
878dependencies = [ 870dependencies = [
879 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 871 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
880 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 872 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
881 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 873 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
882] 874]
@@ -891,7 +883,7 @@ dependencies = [
891 883
892[[package]] 884[[package]]
893name = "proc-macro2" 885name = "proc-macro2"
894version = "1.0.1" 886version = "1.0.2"
895source = "registry+https://github.com/rust-lang/crates.io-index" 887source = "registry+https://github.com/rust-lang/crates.io-index"
896dependencies = [ 888dependencies = [
897 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 889 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -911,7 +903,7 @@ dependencies = [
911 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", 903 "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)",
912 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 904 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
913 "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 905 "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
914 "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 906 "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
915] 907]
916 908
917[[package]] 909[[package]]
@@ -932,7 +924,7 @@ name = "quote"
932version = "1.0.2" 924version = "1.0.2"
933source = "registry+https://github.com/rust-lang/crates.io-index" 925source = "registry+https://github.com/rust-lang/crates.io-index"
934dependencies = [ 926dependencies = [
935 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 927 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
936] 928]
937 929
938[[package]] 930[[package]]
@@ -947,7 +939,7 @@ dependencies = [
947 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 939 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
948 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 940 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
949 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 941 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
950 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 942 "once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
951 "ra_db 0.1.0", 943 "ra_db 0.1.0",
952 "ra_fmt 0.1.0", 944 "ra_fmt 0.1.0",
953 "ra_hir 0.1.0", 945 "ra_hir 0.1.0",
@@ -966,7 +958,7 @@ dependencies = [
966 "ra_hir 0.1.0", 958 "ra_hir 0.1.0",
967 "ra_ide_api 0.1.0", 959 "ra_ide_api 0.1.0",
968 "ra_project_model 0.1.0", 960 "ra_project_model 0.1.0",
969 "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 961 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
970 "ra_vfs_glob 0.1.0", 962 "ra_vfs_glob 0.1.0",
971 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 963 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
972] 964]
@@ -1017,7 +1009,7 @@ dependencies = [
1017 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1009 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
1018 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1010 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
1019 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1011 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1020 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1012 "once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1021 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1022 "ra_arena 0.1.0", 1014 "ra_arena 0.1.0",
1023 "ra_db 0.1.0", 1015 "ra_db 0.1.0",
@@ -1049,12 +1041,12 @@ dependencies = [
1049 "ra_syntax 0.1.0", 1041 "ra_syntax 0.1.0",
1050 "ra_text_edit 0.1.0", 1042 "ra_text_edit 0.1.0",
1051 "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 1043 "rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
1052 "rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1044 "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1053 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1045 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1054 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1046 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1055 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1047 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1056 "test_utils 0.1.0", 1048 "test_utils 0.1.0",
1057 "unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1049 "unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1058] 1050]
1059 1051
1060[[package]] 1052[[package]]
@@ -1066,14 +1058,14 @@ dependencies = [
1066 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1058 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1067 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1059 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1068 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1060 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1069 "lsp-types 0.60.0 (registry+https://github.com/rust-lang/crates.io-index)", 1061 "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
1070 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1062 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1071 "ra_ide_api 0.1.0", 1063 "ra_ide_api 0.1.0",
1072 "ra_prof 0.1.0", 1064 "ra_prof 0.1.0",
1073 "ra_project_model 0.1.0", 1065 "ra_project_model 0.1.0",
1074 "ra_syntax 0.1.0", 1066 "ra_syntax 0.1.0",
1075 "ra_text_edit 0.1.0", 1067 "ra_text_edit 0.1.0",
1076 "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1068 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1077 "ra_vfs_glob 0.1.0", 1069 "ra_vfs_glob 0.1.0",
1078 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1070 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1079 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1071 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1108,11 +1100,11 @@ dependencies = [
1108name = "ra_prof" 1100name = "ra_prof"
1109version = "0.1.0" 1101version = "0.1.0"
1110dependencies = [ 1102dependencies = [
1111 "backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)", 1103 "backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)",
1112 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1104 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1113 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1105 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
1114 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 1106 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
1115 "once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1107 "once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1116] 1108]
1117 1109
1118[[package]] 1110[[package]]
@@ -1129,22 +1121,14 @@ dependencies = [
1129] 1121]
1130 1122
1131[[package]] 1123[[package]]
1132name = "ra_rustc_lexer"
1133version = "0.1.0-pre.3"
1134source = "registry+https://github.com/rust-lang/crates.io-index"
1135dependencies = [
1136 "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1137]
1138
1139[[package]]
1140name = "ra_syntax" 1124name = "ra_syntax"
1141version = "0.1.0" 1125version = "0.1.0"
1142dependencies = [ 1126dependencies = [
1143 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1127 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1144 "ra_parser 0.1.0", 1128 "ra_parser 0.1.0",
1145 "ra_rustc_lexer 0.1.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)",
1146 "ra_text_edit 0.1.0", 1129 "ra_text_edit 0.1.0",
1147 "rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 1130 "rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
1131 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1148 "smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1132 "smol_str 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
1149 "test_utils 0.1.0", 1133 "test_utils 0.1.0",
1150 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 1134 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1165,7 +1149,7 @@ version = "0.1.0"
1165dependencies = [ 1149dependencies = [
1166 "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)", 1150 "clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)",
1167 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1151 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1168 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1152 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1169 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1153 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1170 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1154 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1171 "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", 1155 "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1181,13 +1165,13 @@ dependencies = [
1181 1165
1182[[package]] 1166[[package]]
1183name = "ra_vfs" 1167name = "ra_vfs"
1184version = "0.3.0" 1168version = "0.4.0"
1185source = "registry+https://github.com/rust-lang/crates.io-index" 1169source = "registry+https://github.com/rust-lang/crates.io-index"
1186dependencies = [ 1170dependencies = [
1187 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 1171 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
1188 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1172 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1189 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1173 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1190 "notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)", 1174 "notify 4.0.13 (registry+https://github.com/rust-lang/crates.io-index)",
1191 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1175 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1192 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1176 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1193 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1177 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1199,7 +1183,7 @@ name = "ra_vfs_glob"
1199version = "0.1.0" 1183version = "0.1.0"
1200dependencies = [ 1184dependencies = [
1201 "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1185 "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1202 "ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1186 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1203] 1187]
1204 1188
1205[[package]] 1189[[package]]
@@ -1347,20 +1331,20 @@ dependencies = [
1347 1331
1348[[package]] 1332[[package]]
1349name = "rayon" 1333name = "rayon"
1350version = "1.1.0" 1334version = "1.2.0"
1351source = "registry+https://github.com/rust-lang/crates.io-index" 1335source = "registry+https://github.com/rust-lang/crates.io-index"
1352dependencies = [ 1336dependencies = [
1353 "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", 1337 "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1354 "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1338 "either 1.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1355 "rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)", 1339 "rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
1356] 1340]
1357 1341
1358[[package]] 1342[[package]]
1359name = "rayon-core" 1343name = "rayon-core"
1360version = "1.5.0" 1344version = "1.6.0"
1361source = "registry+https://github.com/rust-lang/crates.io-index" 1345source = "registry+https://github.com/rust-lang/crates.io-index"
1362dependencies = [ 1346dependencies = [
1363 "crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", 1347 "crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1364 "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 1348 "crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
1365 "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 1349 "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
1366 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1350 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1382,18 +1366,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1382 1366
1383[[package]] 1367[[package]]
1384name = "regex" 1368name = "regex"
1385version = "1.2.1" 1369version = "1.3.1"
1386source = "registry+https://github.com/rust-lang/crates.io-index" 1370source = "registry+https://github.com/rust-lang/crates.io-index"
1387dependencies = [ 1371dependencies = [
1388 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)", 1372 "aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)",
1389 "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1373 "memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1390 "regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)", 1374 "regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)",
1391 "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 1375 "thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
1392] 1376]
1393 1377
1394[[package]] 1378[[package]]
1395name = "regex-syntax" 1379name = "regex-syntax"
1396version = "0.6.11" 1380version = "0.6.12"
1397source = "registry+https://github.com/rust-lang/crates.io-index" 1381source = "registry+https://github.com/rust-lang/crates.io-index"
1398 1382
1399[[package]] 1383[[package]]
@@ -1443,6 +1427,14 @@ dependencies = [
1443] 1427]
1444 1428
1445[[package]] 1429[[package]]
1430name = "rustc_lexer"
1431version = "0.1.0"
1432source = "registry+https://github.com/rust-lang/crates.io-index"
1433dependencies = [
1434 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1435]
1436
1437[[package]]
1446name = "rustc_version" 1438name = "rustc_version"
1447version = "0.2.3" 1439version = "0.2.3"
1448source = "registry+https://github.com/rust-lang/crates.io-index" 1440source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1477,7 +1469,7 @@ version = "0.13.1"
1477source = "registry+https://github.com/rust-lang/crates.io-index" 1469source = "registry+https://github.com/rust-lang/crates.io-index"
1478dependencies = [ 1470dependencies = [
1479 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1471 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1480 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1472 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1481 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1473 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1482 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1474 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1483] 1475]
@@ -1522,7 +1514,7 @@ name = "serde_derive"
1522version = "1.0.99" 1514version = "1.0.99"
1523source = "registry+https://github.com/rust-lang/crates.io-index" 1515source = "registry+https://github.com/rust-lang/crates.io-index"
1524dependencies = [ 1516dependencies = [
1525 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1517 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1526 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1518 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1527 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1519 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1528] 1520]
@@ -1542,7 +1534,7 @@ name = "serde_repr"
1542version = "0.1.5" 1534version = "0.1.5"
1543source = "registry+https://github.com/rust-lang/crates.io-index" 1535source = "registry+https://github.com/rust-lang/crates.io-index"
1544dependencies = [ 1536dependencies = [
1545 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1537 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1546 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1538 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1547 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1539 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1548] 1540]
@@ -1581,7 +1573,7 @@ name = "stacker"
1581version = "0.1.5" 1573version = "0.1.5"
1582source = "registry+https://github.com/rust-lang/crates.io-index" 1574source = "registry+https://github.com/rust-lang/crates.io-index"
1583dependencies = [ 1575dependencies = [
1584 "cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)", 1576 "cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)",
1585 "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1577 "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1586 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1578 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)",
1587 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1579 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1607,7 +1599,7 @@ name = "syn"
1607version = "1.0.5" 1599version = "1.0.5"
1608source = "registry+https://github.com/rust-lang/crates.io-index" 1600source = "registry+https://github.com/rust-lang/crates.io-index"
1609dependencies = [ 1601dependencies = [
1610 "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1602 "proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1611 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1603 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1612 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1604 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1613] 1605]
@@ -1694,7 +1686,7 @@ dependencies = [
1694 1686
1695[[package]] 1687[[package]]
1696name = "unicase" 1688name = "unicase"
1697version = "2.4.0" 1689version = "2.5.1"
1698source = "registry+https://github.com/rust-lang/crates.io-index" 1690source = "registry+https://github.com/rust-lang/crates.io-index"
1699dependencies = [ 1691dependencies = [
1700 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 1692 "version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1847,31 +1839,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1847"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" 1839"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba"
1848"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1840"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
1849"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" 1841"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875"
1850"checksum backtrace 0.3.35 (registry+https://github.com/rust-lang/crates.io-index)" = "1371048253fa3bac6704bfd6bbfc922ee9bdcee8881330d40f308b81cc5adc55" 1842"checksum backtrace 0.3.37 (registry+https://github.com/rust-lang/crates.io-index)" = "5180c5a20655b14a819b652fd2378fa5f1697b6c9ddad3e695c2f9cedf6df4e2"
1851"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" 1843"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b"
1852"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1844"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1853"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" 1845"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1854"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" 1846"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1855"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd" 1847"checksum bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d155346769a6855b86399e9bc3814ab343cd3d62c7e985113d46a0ec3c281fd"
1856"checksum bstr 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "94cdf78eb7e94c566c1f5dbe2abf8fc70a548fc902942a48c4b3a98b48ca9ade" 1848"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
1857"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1849"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
1858"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" 1850"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101"
1859"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" 1851"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426"
1860"checksum cc 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "8dae9c4b8fedcae85592ba623c4fd08cfdab3e3b72d6df780c6ead964a69bfff" 1852"checksum cc 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "a61c7bce55cd2fae6ec8cb935ebd76256c2959a1f95790f6118a441c2cd5b406"
1861"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33" 1853"checksum cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "b486ce3ccf7ffd79fdeb678eac06a9e6c09fc88d33836340becb8fffe87c5e33"
1862"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1854"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1863"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1855"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1864"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1856"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1865"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1857"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1866"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1858"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1867"checksum chrono 0.4.7 (registry+https://github.com/rust-lang/crates.io-index)" = "77d81f58b7301084de3b958691458a53c3f7e0b1d702f77e550b6a88e3a88abe" 1859"checksum chrono 0.4.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e8493056968583b0193c1bb04d6f7684586f3726992d6c573261941a895dbd68"
1868"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9" 1860"checksum clap 2.33.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5067f5bb2d80ef5d68b4c87db81601f0b75bca627bc2ef76b141d7b846a3c6d9"
1869"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1861"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1870"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1862"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1871"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242" 1863"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
1872"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" 1864"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
1873"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" 1865"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
1874"checksum crossbeam-deque 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "05e44b8cf3e1a625844d1750e1f7820da46044ff6d28f4d43e455ba3e5bb2c13"
1875"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 1866"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
1876"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9" 1867"checksum crossbeam-epoch 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "fedcd6772e37f3da2a9af9bf12ebe046c0dfe657992377b4df982a2b54cd37a9"
1877"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" 1868"checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b"
@@ -1885,7 +1876,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1885"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 1876"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
1886"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2" 1877"checksum failure 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "795bd83d3abeb9220f257e597aa0080a508b27533824adf336529648f6abf7e2"
1887"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1" 1878"checksum failure_derive 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "ea1063915fd7ef4309e222a5a07cf9c319fb9c7836b1f89b85458672dbb127e1"
1888"checksum filetime 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "2f8c63033fcba1f51ef744505b3cad42510432b904c062afa67ad7ece008429d" 1879"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469"
1889"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" 1880"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
1890"checksum flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66473c1b6a0d2a72f6ed983d33021a4c744a1d179e6f4265867b7d0a9dd679c5" 1881"checksum flexi_logger 0.14.3 (registry+https://github.com/rust-lang/crates.io-index)" = "66473c1b6a0d2a72f6ed983d33021a4c744a1d179e6f4265867b7d0a9dd679c5"
1891"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1882"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
@@ -1924,7 +1915,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1924"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" 1915"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
1925"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1916"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
1926"checksum lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "148cfb1c0b3295c23d9fb4a20fd1b242f5e6f46c525fdcc7f5c0a65710362012" 1917"checksum lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "148cfb1c0b3295c23d9fb4a20fd1b242f5e6f46c525fdcc7f5c0a65710362012"
1927"checksum lsp-types 0.60.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fe3edefcd66dde1f7f1df706f46520a3c93adc5ca4bc5747da6621195e894efd" 1918"checksum lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa3268fbe8beb2795c2fb327bf44f4f3d24f5fe9ebc18d7e2980afd444d72bcf"
1928"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1919"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1929"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 1920"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
1930"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f" 1921"checksum memoffset 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ce6075db033bbbb7ee5a0bbd3a3186bbae616f57fb001c485c7ff77955f8177f"
@@ -1933,12 +1924,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1933"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1924"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
1934"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1925"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
1935"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 1926"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
1936"checksum notify 4.0.12 (registry+https://github.com/rust-lang/crates.io-index)" = "3572d71f13ea8ed41867accd971fd564aa75934cf7a1fae03ddb8c74a8a49943" 1927"checksum notify 4.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1191efa2b8fe041decb55c238a125b7a1aeb6fad7a525133a02be5ec949ff3cb"
1937"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 1928"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
1938"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 1929"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
1939"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 1930"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
1940"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" 1931"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee"
1941"checksum once_cell 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c9192c5a4c3b5488dae8d3886ef9df6b5eb246d36323dc7a5078595a154e7771" 1932"checksum once_cell 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bd38c1bb51148ca239ec38ef1bb4f7570d432861f03e91774d53b01c2ba2132f"
1942"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" 1933"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
1943"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1934"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
1944"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b" 1935"checksum parking_lot_core 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b876b1b9e7ac6e1a74a6da34d25c42e17e8862aa409cbbbdcfc8d86c6f3bc62b"
@@ -1949,13 +1940,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1949"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 1940"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b"
1950"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" 1941"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8"
1951"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" 1942"checksum proc-macro2 0.4.30 (registry+https://github.com/rust-lang/crates.io-index)" = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759"
1952"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" 1943"checksum proc-macro2 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "175a40b9cf564ce9bf050654633dbf339978706b8ead1a907bb970b63185dd95"
1953"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" 1944"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
1954"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1945"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1955"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" 1946"checksum quote 0.6.13 (registry+https://github.com/rust-lang/crates.io-index)" = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1"
1956"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1947"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1957"checksum ra_rustc_lexer 0.1.0-pre.3 (registry+https://github.com/rust-lang/crates.io-index)" = "04371af481820ff8d35c7d12b503eb09cf9e1bd246269bf4a33e3d8c54fa3a4a" 1948"checksum ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf6a0926414eb0c00866eb9274894182302f879cd06b5459c1d8ee7f1234aed"
1958"checksum ra_vfs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ccc8b709e0b7ceec822513451b610df1b9370b01953a8bc545a041a6b3bfef01"
1959"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1949"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
1960"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c" 1950"checksum rand 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d47eab0e83d9693d40f825f86948aa16eff6750ead4bdffc4ab95b8b3a7f052c"
1961"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1951"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
@@ -1971,18 +1961,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1971"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" 1961"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44"
1972"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6" 1962"checksum rand_pcg 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3e196346cbbc5c70c77e7b4926147ee8e383a38ee4d15d58a08098b169e492b6"
1973"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" 1963"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c"
1974"checksum rayon 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a4b0186e22767d5b9738a05eab7c6ac90b15db17e5b5f9bd87976dd7d89a10a4" 1964"checksum rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "83a27732a533a1be0a0035a111fe76db89ad312f6f0347004c220c57f209a123"
1975"checksum rayon-core 1.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ebbe0df8435ac0c397d467b6cad6d25543d06e8a019ef3f6af3c384597515bd2" 1965"checksum rayon-core 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "98dcf634205083b17d0861252431eb2acbfb698ab7478a2d20de07954f47ec7b"
1976"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" 1966"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2"
1977"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1967"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
1978"checksum regex 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88c3d9193984285d544df4a30c23a4e62ead42edf70a4452ceb76dac1ce05c26" 1968"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
1979"checksum regex-syntax 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b143cceb2ca5e56d5671988ef8b15615733e7ee16cd348e064333b251b89343f" 1969"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
1980"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 1970"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c"
1981"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 1971"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
1982"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" 1972"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
1983"checksum rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dc2b79612dedc9004083a61448eb669d336d56690aab29fbd7249e8c8ab41d8c" 1973"checksum rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dc2b79612dedc9004083a61448eb669d336d56690aab29fbd7249e8c8ab41d8c"
1984"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 1974"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
1985"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1975"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
1976"checksum rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5"
1986"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1977"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1987"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" 1978"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997"
1988"checksum salsa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3265a2a9bbd384bd2a9f9511c2c18fb41f62c412516052e8934517dc8ff64f1" 1979"checksum salsa 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e3265a2a9bbd384bd2a9f9511c2c18fb41f62c412516052e8934517dc8ff64f1"
@@ -2011,7 +2002,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
2011"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 2002"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
2012"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" 2003"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
2013"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" 2004"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
2014"checksum unicase 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a84e5511b2a947f3ae965dcb29b13b7b1691b6e7332cf5dbc1744138d5acb7f6" 2005"checksum unicase 2.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2e2e6bd1e59e56598518beb94fd6db628ded570326f0a98c679a304bd9f00150"
2015"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 2006"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
2016"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426" 2007"checksum unicode-normalization 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "141339a08b982d942be2ca06ff8b076563cbe223d1befd5450716790d44e2426"
2017"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9" 2008"checksum unicode-segmentation 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1967f4cdfc355b37fd76d2a954fb2ed3871034eb4f26d60537d88795cfc332a9"
diff --git a/crates/ra_assists/src/ast_editor.rs b/crates/ra_assists/src/ast_editor.rs
index 048478662..a710edce8 100644
--- a/crates/ra_assists/src/ast_editor.rs
+++ b/crates/ra_assists/src/ast_editor.rs
@@ -297,6 +297,11 @@ impl AstBuilder<ast::Path> {
297 ast_node_from_file_text(text) 297 ast_node_from_file_text(text)
298 } 298 }
299 299
300 pub fn from_name(name: ast::Name) -> ast::Path {
301 let name = name.syntax().to_string();
302 Self::from_text(name.as_str())
303 }
304
300 pub fn from_pieces(enum_name: ast::Name, var_name: ast::Name) -> ast::Path { 305 pub fn from_pieces(enum_name: ast::Name, var_name: ast::Name) -> ast::Path {
301 Self::from_text(&format!("{}::{}", enum_name.syntax(), var_name.syntax())) 306 Self::from_text(&format!("{}::{}", enum_name.syntax(), var_name.syntax()))
302 } 307 }
@@ -380,6 +385,31 @@ impl AstBuilder<ast::MatchArmList> {
380 } 385 }
381} 386}
382 387
388impl AstBuilder<ast::WherePred> {
389 fn from_text(text: &str) -> ast::WherePred {
390 ast_node_from_file_text(&format!("fn f() where {} {{ }}", text))
391 }
392
393 pub fn from_pieces(
394 path: ast::Path,
395 bounds: impl Iterator<Item = ast::TypeBound>,
396 ) -> ast::WherePred {
397 let bounds = bounds.map(|b| b.syntax().to_string()).collect::<Vec<_>>().join(" + ");
398 Self::from_text(&format!("{}: {}", path.syntax(), bounds))
399 }
400}
401
402impl AstBuilder<ast::WhereClause> {
403 fn from_text(text: &str) -> ast::WhereClause {
404 ast_node_from_file_text(&format!("fn f() where {} {{ }}", text))
405 }
406
407 pub fn from_predicates(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereClause {
408 let preds = preds.map(|p| p.syntax().to_string()).collect::<Vec<_>>().join(", ");
409 Self::from_text(preds.as_str())
410 }
411}
412
383fn ast_node_from_file_text<N: AstNode>(text: &str) -> N { 413fn ast_node_from_file_text<N: AstNode>(text: &str) -> N {
384 let parse = SourceFile::parse(text); 414 let parse = SourceFile::parse(text);
385 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 415 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index 03eec73ad..10ccc345c 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -102,6 +102,7 @@ mod remove_dbg;
102pub mod auto_import; 102pub mod auto_import;
103mod add_missing_impl_members; 103mod add_missing_impl_members;
104mod move_guard; 104mod move_guard;
105mod move_bounds;
105 106
106fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { 107fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
107 &[ 108 &[
@@ -123,6 +124,7 @@ fn all_assists<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assis
123 inline_local_variable::inline_local_varialbe, 124 inline_local_variable::inline_local_varialbe,
124 move_guard::move_guard_to_arm_body, 125 move_guard::move_guard_to_arm_body,
125 move_guard::move_arm_cond_to_match_guard, 126 move_guard::move_arm_cond_to_match_guard,
127 move_bounds::move_bounds_to_where_clause,
126 ] 128 ]
127} 129}
128 130
diff --git a/crates/ra_assists/src/move_bounds.rs b/crates/ra_assists/src/move_bounds.rs
new file mode 100644
index 000000000..526de1d98
--- /dev/null
+++ b/crates/ra_assists/src/move_bounds.rs
@@ -0,0 +1,135 @@
1use hir::db::HirDatabase;
2use ra_syntax::{
3 ast::{self, AstNode, NameOwner, TypeBoundsOwner},
4 SyntaxElement,
5 SyntaxKind::*,
6 TextRange,
7};
8
9use crate::{ast_editor::AstBuilder, Assist, AssistCtx, AssistId};
10
11pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
12 let type_param_list = ctx.node_at_offset::<ast::TypeParamList>()?;
13
14 let mut type_params = type_param_list.type_params();
15 if type_params.all(|p| p.type_bound_list().is_none()) {
16 return None;
17 }
18
19 let parent = type_param_list.syntax().parent()?;
20 if parent.children_with_tokens().find(|it| it.kind() == WHERE_CLAUSE).is_some() {
21 return None;
22 }
23
24 let anchor: SyntaxElement = match parent.kind() {
25 FN_DEF => ast::FnDef::cast(parent)?.body()?.syntax().clone().into(),
26 TRAIT_DEF => ast::TraitDef::cast(parent)?.item_list()?.syntax().clone().into(),
27 IMPL_BLOCK => ast::ImplBlock::cast(parent)?.item_list()?.syntax().clone().into(),
28 ENUM_DEF => ast::EnumDef::cast(parent)?.variant_list()?.syntax().clone().into(),
29 STRUCT_DEF => parent
30 .children_with_tokens()
31 .find(|it| it.kind() == RECORD_FIELD_DEF_LIST || it.kind() == SEMI)?,
32 _ => return None,
33 };
34
35 ctx.add_action(
36 AssistId("move_bounds_to_where_clause"),
37 "move_bounds_to_where_clause",
38 |edit| {
39 let type_params = type_param_list.type_params().collect::<Vec<_>>();
40
41 for param in &type_params {
42 if let Some(bounds) = param.type_bound_list() {
43 let colon = param
44 .syntax()
45 .children_with_tokens()
46 .find(|it| it.kind() == COLON)
47 .unwrap();
48 let start = colon.text_range().start();
49 let end = bounds.syntax().text_range().end();
50 edit.delete(TextRange::from_to(start, end));
51 }
52 }
53
54 let predicates = type_params.iter().filter_map(build_predicate);
55 let where_clause = AstBuilder::<ast::WhereClause>::from_predicates(predicates);
56
57 let to_insert = match anchor.prev_sibling_or_token() {
58 Some(ref elem) if elem.kind() == WHITESPACE => {
59 format!("{} ", where_clause.syntax())
60 }
61 _ => format!(" {}", where_clause.syntax()),
62 };
63 edit.insert(anchor.text_range().start(), to_insert);
64 edit.target(type_param_list.syntax().text_range());
65 },
66 );
67
68 ctx.build()
69}
70
71fn build_predicate(param: &ast::TypeParam) -> Option<ast::WherePred> {
72 let path = AstBuilder::<ast::Path>::from_name(param.name()?);
73 let predicate =
74 AstBuilder::<ast::WherePred>::from_pieces(path, param.type_bound_list()?.bounds());
75 Some(predicate)
76}
77
78#[cfg(test)]
79mod tests {
80 use super::*;
81
82 use crate::helpers::check_assist;
83
84 #[test]
85 fn move_bounds_to_where_clause_fn() {
86 check_assist(
87 move_bounds_to_where_clause,
88 r#"
89 fn foo<T: u32, <|>F: FnOnce(T) -> T>() {}
90 "#,
91 r#"
92 fn foo<T, <|>F>() where T: u32, F: FnOnce(T) -> T {}
93 "#,
94 );
95 }
96
97 #[test]
98 fn move_bounds_to_where_clause_impl() {
99 check_assist(
100 move_bounds_to_where_clause,
101 r#"
102 impl<U: u32, <|>T> A<U, T> {}
103 "#,
104 r#"
105 impl<U, <|>T> A<U, T> where U: u32 {}
106 "#,
107 );
108 }
109
110 #[test]
111 fn move_bounds_to_where_clause_struct() {
112 check_assist(
113 move_bounds_to_where_clause,
114 r#"
115 struct A<<|>T: Iterator<Item = u32>> {}
116 "#,
117 r#"
118 struct A<<|>T> where T: Iterator<Item = u32> {}
119 "#,
120 );
121 }
122
123 #[test]
124 fn move_bounds_to_where_clause_tuple_struct() {
125 check_assist(
126 move_bounds_to_where_clause,
127 r#"
128 struct Pair<<|>T: u32>(T, T);
129 "#,
130 r#"
131 struct Pair<<|>T>(T, T) where T: u32;
132 "#,
133 );
134 }
135}
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml
index 5fc2703ee..62850746f 100644
--- a/crates/ra_batch/Cargo.toml
+++ b/crates/ra_batch/Cargo.toml
@@ -9,7 +9,7 @@ log = "0.4.5"
9rustc-hash = "1.0" 9rustc-hash = "1.0"
10crossbeam-channel = "0.3.5" 10crossbeam-channel = "0.3.5"
11 11
12ra_vfs = "0.3.0" 12ra_vfs = "0.4.0"
13ra_vfs_glob = { path = "../ra_vfs_glob" } 13ra_vfs_glob = { path = "../ra_vfs_glob" }
14ra_db = { path = "../ra_db" } 14ra_db = { path = "../ra_db" }
15ra_ide_api = { path = "../ra_ide_api" } 15ra_ide_api = { path = "../ra_ide_api" }
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index 4e5bad044..07a7e0c86 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -6,7 +6,7 @@ use crossbeam_channel::{unbounded, Receiver};
6use ra_db::{CrateGraph, FileId, SourceRootId}; 6use ra_db::{CrateGraph, FileId, SourceRootId};
7use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags}; 7use ra_ide_api::{AnalysisChange, AnalysisHost, FeatureFlags};
8use ra_project_model::{PackageRoot, ProjectWorkspace}; 8use ra_project_model::{PackageRoot, ProjectWorkspace};
9use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask}; 9use ra_vfs::{RootEntry, Vfs, VfsChange, VfsTask, Watch};
10use ra_vfs_glob::RustPackageFilterBuilder; 10use ra_vfs_glob::RustPackageFilterBuilder;
11 11
12type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>; 12type Result<T> = std::result::Result<T, Box<dyn Error + Send + Sync>>;
@@ -37,6 +37,7 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
37 }) 37 })
38 .collect(), 38 .collect(),
39 sender, 39 sender,
40 Watch(false),
40 ); 41 );
41 let crate_graph = ws.to_crate_graph(&mut |path: &Path| { 42 let crate_graph = ws.to_crate_graph(&mut |path: &Path| {
42 let vfs_file = vfs.load(path); 43 let vfs_file = vfs.load(path);
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 9e76bcebf..01b96ec58 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -34,10 +34,11 @@ pub(crate) fn run(verbose: bool, path: &Path, op: Op) -> Result<()> {
34 .iter() 34 .iter()
35 .find_map(|(source_root_id, project_root)| { 35 .find_map(|(source_root_id, project_root)| {
36 if project_root.is_member() { 36 if project_root.is_member() {
37 for (rel_path, file_id) in &db.source_root(*source_root_id).files { 37 for file_id in db.source_root(*source_root_id).walk() {
38 let rel_path = db.file_relative_path(file_id);
38 let abs_path = rel_path.to_path(project_root.path()); 39 let abs_path = rel_path.to_path(project_root.path());
39 if abs_path == path { 40 if abs_path == path {
40 return Some(*file_id); 41 return Some(file_id);
41 } 42 }
42 } 43 }
43 } 44 }
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index d355fa2e8..1fad5b233 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -1,7 +1,7 @@
1use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 1use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
2 2
3use ra_db::SourceDatabase; 3use ra_db::SourceDatabase;
4use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty}; 4use ra_hir::{Crate, HasBodySource, HasSource, HirDisplay, ImplItem, ModuleDef, Ty, TypeWalk};
5use ra_syntax::AstNode; 5use ra_syntax::AstNode;
6 6
7use crate::Result; 7use crate::Result;
@@ -110,9 +110,12 @@ pub fn run(verbose: bool, memory_usage: bool, path: &Path, only: Option<&str>) -
110 let original_file = src.file_id.original_file(db); 110 let original_file = src.file_id.original_file(db);
111 let path = db.file_relative_path(original_file); 111 let path = db.file_relative_path(original_file);
112 let line_index = host.analysis().file_line_index(original_file).unwrap(); 112 let line_index = host.analysis().file_line_index(original_file).unwrap();
113 let text_range = src
114 .ast
115 .either(|it| it.syntax().text_range(), |it| it.syntax().text_range());
113 let (start, end) = ( 116 let (start, end) = (
114 line_index.line_col(src.ast.syntax().text_range().start()), 117 line_index.line_col(text_range.start()),
115 line_index.line_col(src.ast.syntax().text_range().end()), 118 line_index.line_col(text_range.end()),
116 ); 119 );
117 bar.println(format!( 120 bar.println(format!(
118 "{} {}:{}-{}:{}: Expected {}, got {}", 121 "{} {}:{}-{}:{}: Expected {}, got {}",
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index ad8e10c52..d1ee3c036 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -5,7 +5,7 @@
5/// Note that neither this module, nor any other part of the analyzer's core do 5/// Note that neither this module, nor any other part of the analyzer's core do
6/// actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how 6/// actual IO. See `vfs` and `project_model` in the `ra_lsp_server` crate for how
7/// actual IO is done and lowered to input. 7/// actual IO is done and lowered to input.
8use relative_path::RelativePathBuf; 8use relative_path::{RelativePath, RelativePathBuf};
9use rustc_hash::FxHashMap; 9use rustc_hash::FxHashMap;
10 10
11use ra_syntax::SmolStr; 11use ra_syntax::SmolStr;
@@ -36,7 +36,7 @@ pub struct SourceRoot {
36 /// Libraries are considered mostly immutable, this assumption is used to 36 /// Libraries are considered mostly immutable, this assumption is used to
37 /// optimize salsa's query structure 37 /// optimize salsa's query structure
38 pub is_library: bool, 38 pub is_library: bool,
39 pub files: FxHashMap<RelativePathBuf, FileId>, 39 files: FxHashMap<RelativePathBuf, FileId>,
40} 40}
41 41
42impl SourceRoot { 42impl SourceRoot {
@@ -46,6 +46,18 @@ impl SourceRoot {
46 pub fn new_library() -> SourceRoot { 46 pub fn new_library() -> SourceRoot {
47 SourceRoot { is_library: true, ..SourceRoot::new() } 47 SourceRoot { is_library: true, ..SourceRoot::new() }
48 } 48 }
49 pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
50 self.files.get(path).copied()
51 }
52 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
53 self.files.insert(path, file_id);
54 }
55 pub fn remove_file(&mut self, path: &RelativePath) {
56 self.files.remove(path);
57 }
58 pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
59 self.files.values().copied()
60 }
49} 61}
50 62
51/// `CrateGraph` is a bit of information which turns a set of text files into a 63/// `CrateGraph` is a bit of information which turns a set of text files into a
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs
index b82d1bda0..c54791b7a 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -12,7 +12,7 @@ pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
13 input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId}, 13 input::{CrateGraph, CrateId, Dependency, Edition, FileId, SourceRoot, SourceRootId},
14}; 14};
15pub use ::salsa; 15pub use salsa;
16 16
17pub trait CheckCanceled { 17pub trait CheckCanceled {
18 /// Aborts current query if there are pending changes. 18 /// Aborts current query if there are pending changes.
@@ -93,8 +93,7 @@ pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
93fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> { 93fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> {
94 let root = db.source_root(id); 94 let root = db.source_root(id);
95 let graph = db.crate_graph(); 95 let graph = db.crate_graph();
96 let res = 96 let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
97 root.files.values().filter_map(|&it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
98 Arc::new(res) 97 Arc::new(res)
99} 98}
100 99
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
index 7c9454c0b..b9ffb0c7a 100644
--- a/crates/ra_hir/src/code_model/src.rs
+++ b/crates/ra_hir/src/code_model/src.rs
@@ -1,11 +1,15 @@
1use ra_syntax::ast::{self, AstNode}; 1use ra_syntax::{
2 ast::{self, AstNode},
3 SyntaxNode,
4};
2 5
3use crate::{ 6use crate::{
4 ids::AstItemDef, AstDatabase, Const, DefDatabase, Enum, EnumVariant, FieldSource, Function, 7 ids::AstItemDef, AstDatabase, Const, DefDatabase, Either, Enum, EnumVariant, FieldSource,
5 HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct, StructField, 8 Function, HasBody, HirDatabase, HirFileId, MacroDef, Module, ModuleSource, Static, Struct,
6 Trait, TypeAlias, Union, 9 StructField, Trait, TypeAlias, Union,
7}; 10};
8 11
12#[derive(Debug, PartialEq, Eq, Clone, Copy)]
9pub struct Source<T> { 13pub struct Source<T> {
10 pub file_id: HirFileId, 14 pub file_id: HirFileId,
11 pub ast: T, 15 pub ast: T,
@@ -16,6 +20,15 @@ pub trait HasSource {
16 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>; 20 fn source(self, db: &(impl DefDatabase + AstDatabase)) -> Source<Self::Ast>;
17} 21}
18 22
23impl<T> Source<T> {
24 pub(crate) fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
25 Source { file_id: self.file_id, ast: f(self.ast) }
26 }
27 pub(crate) fn file_syntax(&self, db: &impl AstDatabase) -> SyntaxNode {
28 db.parse_or_expand(self.file_id).expect("source created from invalid file")
29 }
30}
31
19/// NB: Module is !HasSource, because it has two source nodes at the same time: 32/// NB: Module is !HasSource, because it has two source nodes at the same time:
20/// definition and declaration. 33/// definition and declaration.
21impl Module { 34impl Module {
@@ -117,12 +130,12 @@ where
117 self, 130 self,
118 db: &impl HirDatabase, 131 db: &impl HirDatabase,
119 expr_id: crate::expr::ExprId, 132 expr_id: crate::expr::ExprId,
120 ) -> Option<Source<ast::Expr>> { 133 ) -> Option<Source<Either<ast::Expr, ast::RecordField>>> {
121 let source_map = self.body_source_map(db); 134 let source_map = self.body_source_map(db);
122 let expr_syntax = source_map.expr_syntax(expr_id)?.a()?; 135 let source_ptr = source_map.expr_syntax(expr_id)?;
123 let source = self.source(db); 136 let root = source_ptr.file_syntax(db);
124 let ast = expr_syntax.to_node(&source.ast.syntax()); 137 let source = source_ptr.map(|ast| ast.map(|it| it.to_node(&root), |it| it.to_node(&root)));
125 Some(Source { file_id: source.file_id, ast }) 138 Some(source)
126 } 139 }
127} 140}
128 141
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index f669ab969..7b7974f5b 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -169,13 +169,13 @@ pub trait HirDatabase: DefDatabase + AstDatabase {
169 #[salsa::invoke(crate::ty::generic_defaults_query)] 169 #[salsa::invoke(crate::ty::generic_defaults_query)]
170 fn generic_defaults(&self, def: GenericDef) -> Substs; 170 fn generic_defaults(&self, def: GenericDef) -> Substs;
171 171
172 #[salsa::invoke(crate::expr::lower::body_with_source_map_query)] 172 #[salsa::invoke(crate::expr::body_with_source_map_query)]
173 fn body_with_source_map( 173 fn body_with_source_map(
174 &self, 174 &self,
175 def: DefWithBody, 175 def: DefWithBody,
176 ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>); 176 ) -> (Arc<crate::expr::Body>, Arc<crate::expr::BodySourceMap>);
177 177
178 #[salsa::invoke(crate::expr::lower::body_hir_query)] 178 #[salsa::invoke(crate::expr::body_hir_query)]
179 fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>; 179 fn body_hir(&self, def: DefWithBody) -> Arc<crate::expr::Body>;
180 180
181 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)] 181 #[salsa::invoke(crate::ty::method_resolution::CrateImplBlocks::impls_in_crate_query)]
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index bfd250f38..fc21e269f 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -12,7 +12,7 @@ use crate::{
12 path::GenericArgs, 12 path::GenericArgs,
13 ty::primitive::{UncertainFloatTy, UncertainIntTy}, 13 ty::primitive::{UncertainFloatTy, UncertainIntTy},
14 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
15 DefWithBody, Either, HirDatabase, Name, Path, Resolver, 15 DefWithBody, Either, HasSource, HirDatabase, Name, Path, Resolver, Source,
16}; 16};
17 17
18pub use self::scope::ExprScopes; 18pub use self::scope::ExprScopes;
@@ -43,23 +43,32 @@ pub struct Body {
43 body_expr: ExprId, 43 body_expr: ExprId,
44} 44}
45 45
46type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
47type ExprSource = Source<ExprPtr>;
48
49type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
50type PatSource = Source<PatPtr>;
51
46/// An item body together with the mapping from syntax nodes to HIR expression 52/// An item body together with the mapping from syntax nodes to HIR expression
47/// IDs. This is needed to go from e.g. a position in a file to the HIR 53/// IDs. This is needed to go from e.g. a position in a file to the HIR
48/// expression containing it; but for type inference etc., we want to operate on 54/// expression containing it; but for type inference etc., we want to operate on
49/// a structure that is agnostic to the actual positions of expressions in the 55/// a structure that is agnostic to the actual positions of expressions in the
50/// file, so that we don't recompute types whenever some whitespace is typed. 56/// file, so that we don't recompute types whenever some whitespace is typed.
57///
58/// One complication here is that, due to macro expansion, a single `Body` might
59/// be spread across several files. So, for each ExprId and PatId, we record
60/// both the HirFileId and the position inside the file. However, we only store
61/// AST -> ExprId mapping for non-macro files, as it is not clear how to handle
62/// this properly for macros.
51#[derive(Default, Debug, Eq, PartialEq)] 63#[derive(Default, Debug, Eq, PartialEq)]
52pub struct BodySourceMap { 64pub struct BodySourceMap {
53 expr_map: FxHashMap<ExprPtr, ExprId>, 65 expr_map: FxHashMap<ExprPtr, ExprId>,
54 expr_map_back: ArenaMap<ExprId, ExprPtr>, 66 expr_map_back: ArenaMap<ExprId, ExprSource>,
55 pat_map: FxHashMap<PatPtr, PatId>, 67 pat_map: FxHashMap<PatPtr, PatId>,
56 pat_map_back: ArenaMap<PatId, PatPtr>, 68 pat_map_back: ArenaMap<PatId, PatSource>,
57 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>, 69 field_map: FxHashMap<(ExprId, usize), AstPtr<ast::RecordField>>,
58} 70}
59 71
60type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
61type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
62
63impl Body { 72impl Body {
64 pub fn params(&self) -> &[PatId] { 73 pub fn params(&self) -> &[PatId] {
65 &self.params 74 &self.params
@@ -123,16 +132,16 @@ impl Index<PatId> for Body {
123} 132}
124 133
125impl BodySourceMap { 134impl BodySourceMap {
126 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprPtr> { 135 pub(crate) fn expr_syntax(&self, expr: ExprId) -> Option<ExprSource> {
127 self.expr_map_back.get(expr).cloned() 136 self.expr_map_back.get(expr).copied()
128 } 137 }
129 138
130 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> { 139 pub(crate) fn node_expr(&self, node: &ast::Expr) -> Option<ExprId> {
131 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned() 140 self.expr_map.get(&Either::A(AstPtr::new(node))).cloned()
132 } 141 }
133 142
134 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatPtr> { 143 pub(crate) fn pat_syntax(&self, pat: PatId) -> Option<PatSource> {
135 self.pat_map_back.get(pat).cloned() 144 self.pat_map_back.get(pat).copied()
136 } 145 }
137 146
138 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> { 147 pub(crate) fn node_pat(&self, node: &ast::Pat) -> Option<PatId> {
@@ -524,3 +533,34 @@ impl Pat {
524 } 533 }
525 } 534 }
526} 535}
536
537// Queries
538pub(crate) fn body_with_source_map_query(
539 db: &impl HirDatabase,
540 def: DefWithBody,
541) -> (Arc<Body>, Arc<BodySourceMap>) {
542 let mut params = None;
543
544 let (file_id, body) = match def {
545 DefWithBody::Function(f) => {
546 let src = f.source(db);
547 params = src.ast.param_list();
548 (src.file_id, src.ast.body().map(ast::Expr::from))
549 }
550 DefWithBody::Const(c) => {
551 let src = c.source(db);
552 (src.file_id, src.ast.body())
553 }
554 DefWithBody::Static(s) => {
555 let src = s.source(db);
556 (src.file_id, src.ast.body())
557 }
558 };
559
560 let (body, source_map) = lower::lower(db, def.resolver(db), file_id, def, params, body);
561 (Arc::new(body), Arc::new(source_map))
562}
563
564pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
565 db.body_with_source_map(def).0
566}
diff --git a/crates/ra_hir/src/expr/lower.rs b/crates/ra_hir/src/expr/lower.rs
index f6a75a379..6afd80989 100644
--- a/crates/ra_hir/src/expr/lower.rs
+++ b/crates/ra_hir/src/expr/lower.rs
@@ -1,5 +1,3 @@
1use std::sync::Arc;
2
3use ra_arena::Arena; 1use ra_arena::Arena;
4use ra_syntax::{ 2use ra_syntax::{
5 ast::{ 3 ast::{
@@ -15,8 +13,8 @@ use crate::{
15 path::GenericArgs, 13 path::GenericArgs,
16 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, 14 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
17 type_ref::TypeRef, 15 type_ref::TypeRef,
18 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, 16 DefWithBody, Either, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Mutability, Path,
19 Mutability, Path, Resolver, 17 Resolver, Source,
20}; 18};
21 19
22use super::{ 20use super::{
@@ -24,14 +22,33 @@ use super::{
24 LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement, 22 LogicOp, MatchArm, Ordering, Pat, PatId, PatPtr, RecordFieldPat, RecordLitField, Statement,
25}; 23};
26 24
27pub(crate) struct ExprCollector<DB> { 25pub(super) fn lower(
28 db: DB, 26 db: &impl HirDatabase,
27 resolver: Resolver,
28 file_id: HirFileId,
29 owner: DefWithBody, 29 owner: DefWithBody,
30 exprs: Arena<ExprId, Expr>, 30 params: Option<ast::ParamList>,
31 pats: Arena<PatId, Pat>, 31 body: Option<ast::Expr>,
32 source_map: BodySourceMap, 32) -> (Body, BodySourceMap) {
33 params: Vec<PatId>, 33 ExprCollector {
34 body_expr: Option<ExprId>, 34 resolver,
35 db,
36 original_file_id: file_id,
37 current_file_id: file_id,
38 source_map: BodySourceMap::default(),
39 body: Body {
40 owner,
41 exprs: Arena::default(),
42 pats: Arena::default(),
43 params: Vec::new(),
44 body_expr: ExprId((!0).into()),
45 },
46 }
47 .collect(params, body)
48}
49
50struct ExprCollector<DB> {
51 db: DB,
35 resolver: Resolver, 52 resolver: Resolver,
36 // Expr collector expands macros along the way. original points to the file 53 // Expr collector expands macros along the way. original points to the file
37 // we started with, current points to the current macro expansion. source 54 // we started with, current points to the current macro expansion. source
@@ -39,50 +56,95 @@ pub(crate) struct ExprCollector<DB> {
39 // current == original (see #1196) 56 // current == original (see #1196)
40 original_file_id: HirFileId, 57 original_file_id: HirFileId,
41 current_file_id: HirFileId, 58 current_file_id: HirFileId,
59
60 body: Body,
61 source_map: BodySourceMap,
42} 62}
43 63
44impl<'a, DB> ExprCollector<&'a DB> 64impl<'a, DB> ExprCollector<&'a DB>
45where 65where
46 DB: HirDatabase, 66 DB: HirDatabase,
47{ 67{
48 fn new(owner: DefWithBody, file_id: HirFileId, resolver: Resolver, db: &'a DB) -> Self { 68 fn collect(
49 ExprCollector { 69 mut self,
50 owner, 70 param_list: Option<ast::ParamList>,
51 resolver, 71 body: Option<ast::Expr>,
52 db, 72 ) -> (Body, BodySourceMap) {
53 exprs: Arena::default(), 73 if let Some(param_list) = param_list {
54 pats: Arena::default(), 74 if let Some(self_param) = param_list.self_param() {
55 source_map: BodySourceMap::default(), 75 let ptr = AstPtr::new(&self_param);
56 params: Vec::new(), 76 let param_pat = self.alloc_pat(
57 body_expr: None, 77 Pat::Bind {
58 original_file_id: file_id, 78 name: SELF_PARAM,
59 current_file_id: file_id, 79 mode: BindingAnnotation::Unannotated,
60 } 80 subpat: None,
81 },
82 Either::B(ptr),
83 );
84 self.body.params.push(param_pat);
85 }
86
87 for param in param_list.params() {
88 let pat = match param.pat() {
89 None => continue,
90 Some(pat) => pat,
91 };
92 let param_pat = self.collect_pat(pat);
93 self.body.params.push(param_pat);
94 }
95 };
96
97 self.body.body_expr = self.collect_expr_opt(body);
98 (self.body, self.source_map)
61 } 99 }
100
62 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
63 let ptr = Either::A(ptr); 102 let ptr = Either::A(ptr);
64 let id = self.exprs.alloc(expr); 103 let id = self.body.exprs.alloc(expr);
65 if self.current_file_id == self.original_file_id { 104 if self.current_file_id == self.original_file_id {
66 self.source_map.expr_map.insert(ptr, id); 105 self.source_map.expr_map.insert(ptr, id);
67 self.source_map.expr_map_back.insert(id, ptr);
68 } 106 }
107 self.source_map
108 .expr_map_back
109 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
110 id
111 }
112 // desugared exprs don't have ptr, that's wrong and should be fixed
113 // somehow.
114 fn alloc_expr_desugared(&mut self, expr: Expr) -> ExprId {
115 self.body.exprs.alloc(expr)
116 }
117 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
118 let ptr = Either::B(ptr);
119 let id = self.body.exprs.alloc(expr);
120 if self.current_file_id == self.original_file_id {
121 self.source_map.expr_map.insert(ptr, id);
122 }
123 self.source_map
124 .expr_map_back
125 .insert(id, Source { file_id: self.current_file_id, ast: ptr });
69 id 126 id
70 } 127 }
71
72 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId { 128 fn alloc_pat(&mut self, pat: Pat, ptr: PatPtr) -> PatId {
73 let id = self.pats.alloc(pat); 129 let id = self.body.pats.alloc(pat);
74
75 if self.current_file_id == self.original_file_id { 130 if self.current_file_id == self.original_file_id {
76 self.source_map.pat_map.insert(ptr, id); 131 self.source_map.pat_map.insert(ptr, id);
77 self.source_map.pat_map_back.insert(id, ptr);
78 } 132 }
79 133 self.source_map.pat_map_back.insert(id, Source { file_id: self.current_file_id, ast: ptr });
80 id 134 id
81 } 135 }
82 136
83 fn empty_block(&mut self) -> ExprId { 137 fn empty_block(&mut self) -> ExprId {
84 let block = Expr::Block { statements: Vec::new(), tail: None }; 138 let block = Expr::Block { statements: Vec::new(), tail: None };
85 self.exprs.alloc(block) 139 self.body.exprs.alloc(block)
140 }
141
142 fn missing_expr(&mut self) -> ExprId {
143 self.body.exprs.alloc(Expr::Missing)
144 }
145
146 fn missing_pat(&mut self) -> PatId {
147 self.body.pats.alloc(Pat::Missing)
86 } 148 }
87 149
88 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId { 150 fn collect_expr(&mut self, expr: ast::Expr) -> ExprId {
@@ -100,14 +162,14 @@ where
100 }); 162 });
101 163
102 let condition = match e.condition() { 164 let condition = match e.condition() {
103 None => self.exprs.alloc(Expr::Missing), 165 None => self.missing_expr(),
104 Some(condition) => match condition.pat() { 166 Some(condition) => match condition.pat() {
105 None => self.collect_expr_opt(condition.expr()), 167 None => self.collect_expr_opt(condition.expr()),
106 // if let -- desugar to match 168 // if let -- desugar to match
107 Some(pat) => { 169 Some(pat) => {
108 let pat = self.collect_pat(pat); 170 let pat = self.collect_pat(pat);
109 let match_expr = self.collect_expr_opt(condition.expr()); 171 let match_expr = self.collect_expr_opt(condition.expr());
110 let placeholder_pat = self.pats.alloc(Pat::Missing); 172 let placeholder_pat = self.missing_pat();
111 let arms = vec![ 173 let arms = vec![
112 MatchArm { pats: vec![pat], expr: then_branch, guard: None }, 174 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
113 MatchArm { 175 MatchArm {
@@ -137,7 +199,7 @@ where
137 let body = self.collect_block_opt(e.loop_body()); 199 let body = self.collect_block_opt(e.loop_body());
138 200
139 let condition = match e.condition() { 201 let condition = match e.condition() {
140 None => self.exprs.alloc(Expr::Missing), 202 None => self.missing_expr(),
141 Some(condition) => match condition.pat() { 203 Some(condition) => match condition.pat() {
142 None => self.collect_expr_opt(condition.expr()), 204 None => self.collect_expr_opt(condition.expr()),
143 // if let -- desugar to match 205 // if let -- desugar to match
@@ -145,14 +207,14 @@ where
145 tested_by!(infer_while_let); 207 tested_by!(infer_while_let);
146 let pat = self.collect_pat(pat); 208 let pat = self.collect_pat(pat);
147 let match_expr = self.collect_expr_opt(condition.expr()); 209 let match_expr = self.collect_expr_opt(condition.expr());
148 let placeholder_pat = self.pats.alloc(Pat::Missing); 210 let placeholder_pat = self.missing_pat();
149 let break_ = self.exprs.alloc(Expr::Break { expr: None }); 211 let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
150 let arms = vec![ 212 let arms = vec![
151 MatchArm { pats: vec![pat], expr: body, guard: None }, 213 MatchArm { pats: vec![pat], expr: body, guard: None },
152 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, 214 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
153 ]; 215 ];
154 let match_expr = 216 let match_expr =
155 self.exprs.alloc(Expr::Match { expr: match_expr, arms }); 217 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
156 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); 218 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
157 } 219 }
158 }, 220 },
@@ -247,13 +309,12 @@ where
247 self.collect_expr(e) 309 self.collect_expr(e)
248 } else if let Some(nr) = field.name_ref() { 310 } else if let Some(nr) = field.name_ref() {
249 // field shorthand 311 // field shorthand
250 let id = self.exprs.alloc(Expr::Path(Path::from_name_ref(&nr))); 312 self.alloc_expr_field_shorthand(
251 let ptr = Either::B(AstPtr::new(&field)); 313 Expr::Path(Path::from_name_ref(&nr)),
252 self.source_map.expr_map.insert(ptr, id); 314 AstPtr::new(&field),
253 self.source_map.expr_map_back.insert(id, ptr); 315 )
254 id
255 } else { 316 } else {
256 self.exprs.alloc(Expr::Missing) 317 self.missing_expr()
257 }, 318 },
258 }) 319 })
259 .collect(); 320 .collect();
@@ -420,7 +481,7 @@ where
420 if let Some(expr) = expr { 481 if let Some(expr) = expr {
421 self.collect_expr(expr) 482 self.collect_expr(expr)
422 } else { 483 } else {
423 self.exprs.alloc(Expr::Missing) 484 self.missing_expr()
424 } 485 }
425 } 486 }
426 487
@@ -450,7 +511,7 @@ where
450 if let Some(block) = expr { 511 if let Some(block) = expr {
451 self.collect_block(block) 512 self.collect_block(block)
452 } else { 513 } else {
453 self.exprs.alloc(Expr::Missing) 514 self.missing_expr()
454 } 515 }
455 } 516 }
456 517
@@ -519,60 +580,9 @@ where
519 if let Some(pat) = pat { 580 if let Some(pat) = pat {
520 self.collect_pat(pat) 581 self.collect_pat(pat)
521 } else { 582 } else {
522 self.pats.alloc(Pat::Missing) 583 self.missing_pat()
523 } 584 }
524 } 585 }
525
526 fn collect_const_body(&mut self, node: ast::ConstDef) {
527 let body = self.collect_expr_opt(node.body());
528 self.body_expr = Some(body);
529 }
530
531 fn collect_static_body(&mut self, node: ast::StaticDef) {
532 let body = self.collect_expr_opt(node.body());
533 self.body_expr = Some(body);
534 }
535
536 fn collect_fn_body(&mut self, node: ast::FnDef) {
537 if let Some(param_list) = node.param_list() {
538 if let Some(self_param) = param_list.self_param() {
539 let ptr = AstPtr::new(&self_param);
540 let param_pat = self.alloc_pat(
541 Pat::Bind {
542 name: SELF_PARAM,
543 mode: BindingAnnotation::Unannotated,
544 subpat: None,
545 },
546 Either::B(ptr),
547 );
548 self.params.push(param_pat);
549 }
550
551 for param in param_list.params() {
552 let pat = if let Some(pat) = param.pat() {
553 pat
554 } else {
555 continue;
556 };
557 let param_pat = self.collect_pat(pat);
558 self.params.push(param_pat);
559 }
560 };
561
562 let body = self.collect_block_opt(node.body());
563 self.body_expr = Some(body);
564 }
565
566 fn finish(self) -> (Body, BodySourceMap) {
567 let body = Body {
568 owner: self.owner,
569 exprs: self.exprs,
570 pats: self.pats,
571 params: self.params,
572 body_expr: self.body_expr.expect("A body should have been collected"),
573 };
574 (body, self.source_map)
575 }
576} 586}
577 587
578impl From<ast::BinOp> for BinaryOp { 588impl From<ast::BinOp> for BinaryOp {
@@ -618,35 +628,3 @@ impl From<ast::BinOp> for BinaryOp {
618 } 628 }
619 } 629 }
620} 630}
621
622pub(crate) fn body_with_source_map_query(
623 db: &impl HirDatabase,
624 def: DefWithBody,
625) -> (Arc<Body>, Arc<BodySourceMap>) {
626 let mut collector;
627
628 match def {
629 DefWithBody::Const(ref c) => {
630 let src = c.source(db);
631 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
632 collector.collect_const_body(src.ast)
633 }
634 DefWithBody::Function(ref f) => {
635 let src = f.source(db);
636 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
637 collector.collect_fn_body(src.ast)
638 }
639 DefWithBody::Static(ref s) => {
640 let src = s.source(db);
641 collector = ExprCollector::new(def, src.file_id, def.resolver(db), db);
642 collector.collect_static_body(src.ast)
643 }
644 }
645
646 let (body, source_map) = collector.finish();
647 (Arc::new(body), Arc::new(source_map))
648}
649
650pub(crate) fn body_hir_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<Body> {
651 db.body_with_source_map(def).0
652}
diff --git a/crates/ra_hir/src/expr/validation.rs b/crates/ra_hir/src/expr/validation.rs
index 6fdaf1fce..1202913e2 100644
--- a/crates/ra_hir/src/expr/validation.rs
+++ b/crates/ra_hir/src/expr/validation.rs
@@ -1,9 +1,8 @@
1use std::sync::Arc; 1use std::sync::Arc;
2 2
3use ra_syntax::ast::{self, AstNode}; 3use ra_syntax::ast;
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
5 5
6use super::{Expr, ExprId, RecordLitField};
7use crate::{ 6use crate::{
8 adt::AdtDef, 7 adt::AdtDef,
9 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr}, 8 diagnostics::{DiagnosticSink, MissingFields, MissingOkInTailExpr},
@@ -11,9 +10,11 @@ use crate::{
11 name, 10 name,
12 path::{PathKind, PathSegment}, 11 path::{PathKind, PathSegment},
13 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor}, 12 ty::{ApplicationTy, InferenceResult, Ty, TypeCtor},
14 Function, HasSource, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution, 13 Function, HirDatabase, ModuleDef, Name, Path, PerNs, Resolution,
15}; 14};
16 15
16use super::{Expr, ExprId, RecordLitField};
17
17pub(crate) struct ExprValidator<'a, 'b: 'a> { 18pub(crate) struct ExprValidator<'a, 'b: 'a> {
18 func: Function, 19 func: Function,
19 infer: Arc<InferenceResult>, 20 infer: Arc<InferenceResult>,
@@ -78,25 +79,20 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
78 return; 79 return;
79 } 80 }
80 let source_map = self.func.body_source_map(db); 81 let source_map = self.func.body_source_map(db);
81 let file_id = self.func.source(db).file_id; 82
82 let parse = db.parse(file_id.original_file(db)); 83 if let Some(source_ptr) = source_map.expr_syntax(id) {
83 let source_file = parse.tree(); 84 if let Some(expr) = source_ptr.ast.a() {
84 if let Some(field_list_node) = source_map 85 let root = source_ptr.file_syntax(db);
85 .expr_syntax(id) 86 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
86 .and_then(|ptr| ptr.a()) 87 if let Some(field_list) = record_lit.record_field_list() {
87 .map(|ptr| ptr.to_node(source_file.syntax())) 88 self.sink.push(MissingFields {
88 .and_then(|expr| match expr { 89 file: source_ptr.file_id,
89 ast::Expr::RecordLit(it) => Some(it), 90 field_list: AstPtr::new(&field_list),
90 _ => None, 91 missed_fields,
91 }) 92 })
92 .and_then(|lit| lit.record_field_list()) 93 }
93 { 94 }
94 let field_list_ptr = AstPtr::new(&field_list_node); 95 }
95 self.sink.push(MissingFields {
96 file: file_id,
97 field_list: field_list_ptr,
98 missed_fields,
99 })
100 } 96 }
101 } 97 }
102 98
@@ -136,10 +132,11 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
136 132
137 if params.len() == 2 && &params[0] == &mismatch.actual { 133 if params.len() == 2 && &params[0] == &mismatch.actual {
138 let source_map = self.func.body_source_map(db); 134 let source_map = self.func.body_source_map(db);
139 let file_id = self.func.source(db).file_id;
140 135
141 if let Some(expr) = source_map.expr_syntax(id).and_then(|n| n.a()) { 136 if let Some(source_ptr) = source_map.expr_syntax(id) {
142 self.sink.push(MissingOkInTailExpr { file: file_id, expr }); 137 if let Some(expr) = source_ptr.ast.a() {
138 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
139 }
143 } 140 }
144 } 141 }
145 } 142 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 752653ad7..c3e589921 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -69,7 +69,9 @@ pub use self::{
69 resolve::Resolution, 69 resolve::Resolution,
70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 70 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
71 source_id::{AstIdMap, ErasedFileAstId}, 71 source_id::{AstIdMap, ErasedFileAstId},
72 ty::{display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor}, 72 ty::{
73 display::HirDisplay, ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
74 },
73 type_ref::Mutability, 75 type_ref::Mutability,
74}; 76};
75 77
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 5b15eee90..fe119b97c 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -11,4 +11,6 @@ test_utils::marks!(
11 match_ergonomics_ref 11 match_ergonomics_ref
12 trait_resolution_on_fn_type 12 trait_resolution_on_fn_type
13 infer_while_let 13 infer_while_let
14 macro_rules_from_other_crates_are_visible_with_macro_use
15 prelude_is_macro_use
14); 16);
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index 77a44a275..972f0ece5 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -157,7 +157,7 @@ impl MockDatabase {
157 self.set_file_text(file_id, text); 157 self.set_file_text(file_id, text);
158 self.set_file_relative_path(file_id, rel_path.clone()); 158 self.set_file_relative_path(file_id, rel_path.clone());
159 self.set_file_source_root(file_id, source_root_id); 159 self.set_file_source_root(file_id, source_root_id);
160 source_root.files.insert(rel_path, file_id); 160 source_root.insert_file(rel_path, file_id);
161 161
162 if is_crate_root { 162 if is_crate_root {
163 let mut crate_graph = CrateGraph::default(); 163 let mut crate_graph = CrateGraph::default();
diff --git a/crates/ra_hir/src/nameres.rs b/crates/ra_hir/src/nameres.rs
index bbdc606cd..fe90879b6 100644
--- a/crates/ra_hir/src/nameres.rs
+++ b/crates/ra_hir/src/nameres.rs
@@ -1,55 +1,56 @@
1/// This module implements import-resolution/macro expansion algorithm. 1//! This module implements import-resolution/macro expansion algorithm.
2/// 2//!
3/// The result of this module is `CrateDefMap`: a data structure which contains: 3//! The result of this module is `CrateDefMap`: a data structure which contains:
4/// 4//!
5/// * a tree of modules for the crate 5//! * a tree of modules for the crate
6/// * for each module, a set of items visible in the module (directly declared 6//! * for each module, a set of items visible in the module (directly declared
7/// or imported) 7//! or imported)
8/// 8//!
9/// Note that `CrateDefMap` contains fully macro expanded code. 9//! Note that `CrateDefMap` contains fully macro expanded code.
10/// 10//!
11/// Computing `CrateDefMap` can be partitioned into several logically 11//! Computing `CrateDefMap` can be partitioned into several logically
12/// independent "phases". The phases are mutually recursive though, there's no 12//! independent "phases". The phases are mutually recursive though, there's no
13/// strict ordering. 13//! strict ordering.
14/// 14//!
15/// ## Collecting RawItems 15//! ## Collecting RawItems
16/// 16//!
17/// This happens in the `raw` module, which parses a single source file into a 17//! This happens in the `raw` module, which parses a single source file into a
18/// set of top-level items. Nested imports are desugared to flat imports in 18//! set of top-level items. Nested imports are desugared to flat imports in
19/// this phase. Macro calls are represented as a triple of (Path, Option<Name>, 19//! this phase. Macro calls are represented as a triple of (Path, Option<Name>,
20/// TokenTree). 20//! TokenTree).
21/// 21//!
22/// ## Collecting Modules 22//! ## Collecting Modules
23/// 23//!
24/// This happens in the `collector` module. In this phase, we recursively walk 24//! This happens in the `collector` module. In this phase, we recursively walk
25/// tree of modules, collect raw items from submodules, populate module scopes 25//! tree of modules, collect raw items from submodules, populate module scopes
26/// with defined items (so, we assign item ids in this phase) and record the set 26//! with defined items (so, we assign item ids in this phase) and record the set
27/// of unresolved imports and macros. 27//! of unresolved imports and macros.
28/// 28//!
29/// While we walk tree of modules, we also record macro_rules definitions and 29//! While we walk tree of modules, we also record macro_rules definitions and
30/// expand calls to macro_rules defined macros. 30//! expand calls to macro_rules defined macros.
31/// 31//!
32/// ## Resolving Imports 32//! ## Resolving Imports
33/// 33//!
34/// We maintain a list of currently unresolved imports. On every iteration, we 34//! We maintain a list of currently unresolved imports. On every iteration, we
35/// try to resolve some imports from this list. If the import is resolved, we 35//! try to resolve some imports from this list. If the import is resolved, we
36/// record it, by adding an item to current module scope and, if necessary, by 36//! record it, by adding an item to current module scope and, if necessary, by
37/// recursively populating glob imports. 37//! recursively populating glob imports.
38/// 38//!
39/// ## Resolving Macros 39//! ## Resolving Macros
40/// 40//!
41/// macro_rules from the same crate use a global mutable namespace. We expand 41//! macro_rules from the same crate use a global mutable namespace. We expand
42/// them immediately, when we collect modules. 42//! them immediately, when we collect modules.
43/// 43//!
44/// Macros from other crates (including proc-macros) can be used with 44//! Macros from other crates (including proc-macros) can be used with
45/// `foo::bar!` syntax. We handle them similarly to imports. There's a list of 45//! `foo::bar!` syntax. We handle them similarly to imports. There's a list of
46/// unexpanded macros. On every iteration, we try to resolve each macro call 46//! unexpanded macros. On every iteration, we try to resolve each macro call
47/// path and, upon success, we run macro expansion and "collect module" phase 47//! path and, upon success, we run macro expansion and "collect module" phase
48/// on the result 48//! on the result
49 49
50mod per_ns; 50mod per_ns;
51mod raw; 51mod raw;
52mod collector; 52mod collector;
53mod mod_resolution;
53#[cfg(test)] 54#[cfg(test)]
54mod tests; 55mod tests;
55 56
@@ -101,6 +102,8 @@ pub struct CrateDefMap {
101 /// However, do we want to put it as a global variable? 102 /// However, do we want to put it as a global variable?
102 poison_macros: FxHashSet<MacroDefId>, 103 poison_macros: FxHashSet<MacroDefId>,
103 104
105 exported_macros: FxHashMap<Name, MacroDefId>,
106
104 diagnostics: Vec<DefDiagnostic>, 107 diagnostics: Vec<DefDiagnostic>,
105} 108}
106 109
@@ -245,6 +248,7 @@ impl CrateDefMap {
245 root, 248 root,
246 modules, 249 modules,
247 poison_macros: FxHashSet::default(), 250 poison_macros: FxHashSet::default(),
251 exported_macros: FxHashMap::default(),
248 diagnostics: Vec::new(), 252 diagnostics: Vec::new(),
249 } 253 }
250 }; 254 };
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index 7da2dcdff..5af26f953 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -1,9 +1,5 @@
1use std::borrow::Cow; 1use ra_db::FileId;
2use std::sync::Arc; 2use ra_syntax::ast;
3
4use ra_db::{FileId, SourceRoot};
5use ra_syntax::{ast, SmolStr};
6use relative_path::RelativePathBuf;
7use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
8use test_utils::tested_by; 4use test_utils::tested_by;
9 5
@@ -12,8 +8,10 @@ use crate::{
12 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 8 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
13 name::MACRO_RULES, 9 name::MACRO_RULES,
14 nameres::{ 10 nameres::{
15 diagnostics::DefDiagnostic, raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, 11 diagnostics::DefDiagnostic,
16 ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode, 12 mod_resolution::{resolve_submodule, ParentModule},
13 raw, CrateDefMap, CrateModuleId, ItemOrMacro, ModuleData, ModuleDef, PerNs,
14 ReachedFixedPoint, Resolution, ResolveMode,
17 }, 15 },
18 AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static, 16 AstId, Const, DefDatabase, Enum, Function, HirFileId, MacroDef, Module, Name, Path, Static,
19 Struct, Trait, TypeAlias, Union, 17 Struct, Trait, TypeAlias, Union,
@@ -157,11 +155,45 @@ where
157 // crate root, even if the parent modules is **not** visible. 155 // crate root, even if the parent modules is **not** visible.
158 if export { 156 if export {
159 self.update(self.def_map.root, None, &[(name.clone(), def.clone())]); 157 self.update(self.def_map.root, None, &[(name.clone(), def.clone())]);
158
159 // Exported macros are collected in crate level ready for
160 // glob import with `#[macro_use]`.
161 self.def_map.exported_macros.insert(name.clone(), macro_id);
160 } 162 }
161 self.update(module_id, None, &[(name.clone(), def)]); 163 self.update(module_id, None, &[(name.clone(), def)]);
162 self.global_macro_scope.insert(name, macro_id); 164 self.global_macro_scope.insert(name, macro_id);
163 } 165 }
164 166
167 /// Import macros from `#[macro_use] extern crate`.
168 ///
169 /// They are non-scoped, and will only be inserted into mutable `global_macro_scope`.
170 fn import_macros_from_extern_crate(&mut self, import: &raw::ImportData) {
171 log::debug!(
172 "importing macros from extern crate: {:?} ({:?})",
173 import,
174 self.def_map.edition,
175 );
176
177 let res = self.def_map.resolve_name_in_extern_prelude(
178 &import
179 .path
180 .as_ident()
181 .expect("extern crate should have been desugared to one-element path"),
182 );
183
184 if let Some(ModuleDef::Module(m)) = res.take_types() {
185 tested_by!(macro_rules_from_other_crates_are_visible_with_macro_use);
186 self.import_all_macros_exported(m);
187 }
188 }
189
190 fn import_all_macros_exported(&mut self, module: Module) {
191 let item_map = self.db.crate_def_map(module.krate);
192 for (name, &macro_id) in &item_map.exported_macros {
193 self.global_macro_scope.insert(name.clone(), macro_id);
194 }
195 }
196
165 fn resolve_imports(&mut self) -> ReachedFixedPoint { 197 fn resolve_imports(&mut self) -> ReachedFixedPoint {
166 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 198 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
167 let mut resolved = Vec::new(); 199 let mut resolved = Vec::new();
@@ -491,13 +523,31 @@ where
491 DB: DefDatabase, 523 DB: DefDatabase,
492{ 524{
493 fn collect(&mut self, items: &[raw::RawItem]) { 525 fn collect(&mut self, items: &[raw::RawItem]) {
526 // Prelude module is always considered to be `#[macro_use]`.
527 if let Some(prelude_module) = self.def_collector.def_map.prelude {
528 tested_by!(prelude_is_macro_use);
529 self.def_collector.import_all_macros_exported(prelude_module);
530 }
531
532 // This should be processed eagerly instead of deferred to resolving.
533 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
534 // any other items.
535 for item in items {
536 if let raw::RawItem::Import(import_id) = *item {
537 let import = self.raw_items[import_id].clone();
538 if import.is_extern_crate && import.is_macro_use {
539 self.def_collector.import_macros_from_extern_crate(&import);
540 }
541 }
542 }
543
494 for item in items { 544 for item in items {
495 match *item { 545 match *item {
496 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]), 546 raw::RawItem::Module(m) => self.collect_module(&self.raw_items[m]),
497 raw::RawItem::Import(import) => self.def_collector.unresolved_imports.push(( 547 raw::RawItem::Import(import_id) => self.def_collector.unresolved_imports.push((
498 self.module_id, 548 self.module_id,
499 import, 549 import_id,
500 self.raw_items[import].clone(), 550 self.raw_items[import_id].clone(),
501 )), 551 )),
502 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]), 552 raw::RawItem::Def(def) => self.define_def(&self.raw_items[def]),
503 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 553 raw::RawItem::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
@@ -531,7 +581,7 @@ where
531 name, 581 name,
532 is_root, 582 is_root,
533 attr_path.as_ref(), 583 attr_path.as_ref(),
534 self.parent_module.as_ref(), 584 self.parent_module,
535 ) { 585 ) {
536 Ok(file_id) => { 586 Ok(file_id) => {
537 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); 587 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
@@ -642,180 +692,6 @@ fn is_macro_rules(path: &Path) -> bool {
642 path.as_ident() == Some(&MACRO_RULES) 692 path.as_ident() == Some(&MACRO_RULES)
643} 693}
644 694
645fn resolve_submodule(
646 db: &impl DefDatabase,
647 file_id: HirFileId,
648 name: &Name,
649 is_root: bool,
650 attr_path: Option<&SmolStr>,
651 parent_module: Option<&ParentModule>,
652) -> Result<FileId, RelativePathBuf> {
653 let file_id = file_id.original_file(db);
654 let source_root_id = db.file_source_root(file_id);
655 let path = db.file_relative_path(file_id);
656 let root = RelativePathBuf::default();
657 let dir_path = path.parent().unwrap_or(&root);
658 let mod_name = path.file_stem().unwrap_or("unknown");
659
660 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
661 (Some(file_path), Some(parent_module)) => {
662 let file_path = normalize_attribute_path(file_path);
663 match parent_module.attribute_path() {
664 Some(parent_module_attr_path) => {
665 let path = dir_path
666 .join(format!(
667 "{}/{}",
668 normalize_attribute_path(parent_module_attr_path),
669 file_path
670 ))
671 .normalize();
672 ResolutionMode::InlineModuleWithAttributePath(
673 InsideInlineModuleMode::WithAttributePath(path),
674 )
675 }
676 None => {
677 let path =
678 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
679 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
680 path,
681 ))
682 }
683 }
684 }
685 (None, Some(parent_module)) => match parent_module.attribute_path() {
686 Some(parent_module_attr_path) => {
687 let path = dir_path.join(format!(
688 "{}/{}.rs",
689 normalize_attribute_path(parent_module_attr_path),
690 name
691 ));
692 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path))
693 }
694 None => {
695 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name));
696 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path))
697 }
698 },
699 (Some(file_path), None) => {
700 let file_path = normalize_attribute_path(file_path);
701 let path = dir_path.join(file_path.as_ref()).normalize();
702 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
703 }
704 _ => {
705 let is_dir_owner = is_root || mod_name == "mod";
706 if is_dir_owner {
707 let file_mod = dir_path.join(format!("{}.rs", name));
708 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
709 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
710 file: file_mod,
711 directory: dir_mod,
712 })
713 } else {
714 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
715 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
716 }
717 }
718 };
719
720 resolve_mode.resolve(db.source_root(source_root_id))
721}
722
723fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
724 let current_dir = "./";
725 let windows_path_separator = r#"\"#;
726 let current_dir_normalize = if file_path.starts_with(current_dir) {
727 &file_path[current_dir.len()..]
728 } else {
729 file_path.as_str()
730 };
731 if current_dir_normalize.contains(windows_path_separator) {
732 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
733 } else {
734 Cow::Borrowed(current_dir_normalize)
735 }
736}
737
738enum OutOfLineMode {
739 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
740 FileInDirectory(RelativePathBuf),
741 WithAttributePath(RelativePathBuf),
742}
743
744impl OutOfLineMode {
745 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
746 match self {
747 OutOfLineMode::RootOrModRs { file, directory } => match source_root.files.get(file) {
748 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
749 file_id => resolve_find_result(file_id, file),
750 },
751 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
752 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
753 }
754 }
755}
756
757enum InsideInlineModuleMode {
758 File(RelativePathBuf),
759 WithAttributePath(RelativePathBuf),
760}
761
762impl InsideInlineModuleMode {
763 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
764 match self {
765 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
766 InsideInlineModuleMode::WithAttributePath(path) => {
767 resolve_simple_path(source_root, path)
768 }
769 }
770 }
771}
772
773enum ResolutionMode {
774 OutOfLine(OutOfLineMode),
775 InsideInlineModule(InsideInlineModuleMode),
776 InlineModuleWithAttributePath(InsideInlineModuleMode),
777}
778
779impl ResolutionMode {
780 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
781 use self::ResolutionMode::*;
782
783 match self {
784 OutOfLine(mode) => mode.resolve(source_root),
785 InsideInlineModule(mode) => mode.resolve(source_root),
786 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
787 }
788 }
789}
790
791fn resolve_simple_path(
792 source_root: Arc<SourceRoot>,
793 path: &RelativePathBuf,
794) -> Result<FileId, RelativePathBuf> {
795 resolve_find_result(source_root.files.get(path), path)
796}
797
798fn resolve_find_result(
799 file_id: Option<&FileId>,
800 path: &RelativePathBuf,
801) -> Result<FileId, RelativePathBuf> {
802 match file_id {
803 Some(file_id) => Ok(file_id.clone()),
804 None => Err(path.clone()),
805 }
806}
807
808struct ParentModule<'a> {
809 name: &'a Name,
810 attr_path: Option<&'a SmolStr>,
811}
812
813impl<'a> ParentModule<'a> {
814 pub fn attribute_path(&self) -> Option<&SmolStr> {
815 self.attr_path.filter(|p| !p.is_empty())
816 }
817}
818
819#[cfg(test)] 695#[cfg(test)]
820mod tests { 696mod tests {
821 use ra_db::SourceDatabase; 697 use ra_db::SourceDatabase;
@@ -860,6 +736,7 @@ mod tests {
860 root, 736 root,
861 modules, 737 modules,
862 poison_macros: FxHashSet::default(), 738 poison_macros: FxHashSet::default(),
739 exported_macros: FxHashMap::default(),
863 diagnostics: Vec::new(), 740 diagnostics: Vec::new(),
864 } 741 }
865 }; 742 };
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs
new file mode 100644
index 000000000..918c9591f
--- /dev/null
+++ b/crates/ra_hir/src/nameres/mod_resolution.rs
@@ -0,0 +1,186 @@
1//! This module resolves `mod foo;` declaration to file.
2
3use std::{borrow::Cow, sync::Arc};
4
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::SmolStr;
7use relative_path::RelativePathBuf;
8
9use crate::{DefDatabase, HirFileId, Name};
10
11#[derive(Clone, Copy)]
12pub(super) struct ParentModule<'a> {
13 pub(super) name: &'a Name,
14 pub(super) attr_path: Option<&'a SmolStr>,
15}
16
17impl<'a> ParentModule<'a> {
18 fn attribute_path(&self) -> Option<&SmolStr> {
19 self.attr_path.filter(|p| !p.is_empty())
20 }
21}
22
23pub(super) fn resolve_submodule(
24 db: &impl DefDatabase,
25 file_id: HirFileId,
26 name: &Name,
27 is_root: bool,
28 attr_path: Option<&SmolStr>,
29 parent_module: Option<ParentModule<'_>>,
30) -> Result<FileId, RelativePathBuf> {
31 let file_id = file_id.original_file(db);
32 let source_root_id = db.file_source_root(file_id);
33 let path = db.file_relative_path(file_id);
34 let root = RelativePathBuf::default();
35 let dir_path = path.parent().unwrap_or(&root);
36 let mod_name = path.file_stem().unwrap_or("unknown");
37
38 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
39 (Some(file_path), Some(parent_module)) => {
40 let file_path = normalize_attribute_path(file_path);
41 match parent_module.attribute_path() {
42 Some(parent_module_attr_path) => {
43 let path = dir_path
44 .join(format!(
45 "{}/{}",
46 normalize_attribute_path(parent_module_attr_path),
47 file_path
48 ))
49 .normalize();
50 ResolutionMode::InlineModuleWithAttributePath(
51 InsideInlineModuleMode::WithAttributePath(path),
52 )
53 }
54 None => {
55 let path =
56 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
57 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
58 path,
59 ))
60 }
61 }
62 }
63 (None, Some(parent_module)) => match parent_module.attribute_path() {
64 Some(parent_module_attr_path) => {
65 let path = dir_path.join(format!(
66 "{}/{}.rs",
67 normalize_attribute_path(parent_module_attr_path),
68 name
69 ));
70 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path))
71 }
72 None => {
73 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name));
74 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path))
75 }
76 },
77 (Some(file_path), None) => {
78 let file_path = normalize_attribute_path(file_path);
79 let path = dir_path.join(file_path.as_ref()).normalize();
80 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
81 }
82 (None, None) => {
83 let is_dir_owner = is_root || mod_name == "mod";
84 if is_dir_owner {
85 let file_mod = dir_path.join(format!("{}.rs", name));
86 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
87 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
88 file: file_mod,
89 directory: dir_mod,
90 })
91 } else {
92 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
93 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
94 }
95 }
96 };
97
98 resolve_mode.resolve(db.source_root(source_root_id))
99}
100
101fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> {
102 let current_dir = "./";
103 let windows_path_separator = r#"\"#;
104 let current_dir_normalize = if file_path.starts_with(current_dir) {
105 &file_path[current_dir.len()..]
106 } else {
107 file_path.as_str()
108 };
109 if current_dir_normalize.contains(windows_path_separator) {
110 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
111 } else {
112 Cow::Borrowed(current_dir_normalize)
113 }
114}
115
116enum OutOfLineMode {
117 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
118 FileInDirectory(RelativePathBuf),
119 WithAttributePath(RelativePathBuf),
120}
121
122impl OutOfLineMode {
123 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
124 match self {
125 OutOfLineMode::RootOrModRs { file, directory } => {
126 match source_root.file_by_relative_path(file) {
127 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
128 file_id => resolve_find_result(file_id, file),
129 }
130 }
131 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
132 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
133 }
134 }
135}
136
137enum InsideInlineModuleMode {
138 File(RelativePathBuf),
139 WithAttributePath(RelativePathBuf),
140}
141
142impl InsideInlineModuleMode {
143 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
144 match self {
145 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
146 InsideInlineModuleMode::WithAttributePath(path) => {
147 resolve_simple_path(source_root, path)
148 }
149 }
150 }
151}
152
153enum ResolutionMode {
154 OutOfLine(OutOfLineMode),
155 InsideInlineModule(InsideInlineModuleMode),
156 InlineModuleWithAttributePath(InsideInlineModuleMode),
157}
158
159impl ResolutionMode {
160 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
161 use self::ResolutionMode::*;
162
163 match self {
164 OutOfLine(mode) => mode.resolve(source_root),
165 InsideInlineModule(mode) => mode.resolve(source_root),
166 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
167 }
168 }
169}
170
171fn resolve_simple_path(
172 source_root: Arc<SourceRoot>,
173 path: &RelativePathBuf,
174) -> Result<FileId, RelativePathBuf> {
175 resolve_find_result(source_root.file_by_relative_path(path), path)
176}
177
178fn resolve_find_result(
179 file_id: Option<FileId>,
180 path: &RelativePathBuf,
181) -> Result<FileId, RelativePathBuf> {
182 match file_id {
183 Some(file_id) => Ok(file_id.clone()),
184 None => Err(path.clone()),
185 }
186}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 2f973359f..129b047eb 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -154,6 +154,7 @@ pub struct ImportData {
154 pub(super) is_glob: bool, 154 pub(super) is_glob: bool,
155 pub(super) is_prelude: bool, 155 pub(super) is_prelude: bool,
156 pub(super) is_extern_crate: bool, 156 pub(super) is_extern_crate: bool,
157 pub(super) is_macro_use: bool,
157} 158}
158 159
159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 160#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -293,8 +294,14 @@ impl RawItemsCollector {
293 let is_prelude = use_item.has_atom_attr("prelude_import"); 294 let is_prelude = use_item.has_atom_attr("prelude_import");
294 295
295 Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| { 296 Path::expand_use_item(&use_item, |path, use_tree, is_glob, alias| {
296 let import_data = 297 let import_data = ImportData {
297 ImportData { path, alias, is_glob, is_prelude, is_extern_crate: false }; 298 path,
299 alias,
300 is_glob,
301 is_prelude,
302 is_extern_crate: false,
303 is_macro_use: false,
304 };
298 self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree))); 305 self.push_import(current_module, import_data, Either::A(AstPtr::new(use_tree)));
299 }) 306 })
300 } 307 }
@@ -307,12 +314,14 @@ impl RawItemsCollector {
307 if let Some(name_ref) = extern_crate.name_ref() { 314 if let Some(name_ref) = extern_crate.name_ref() {
308 let path = Path::from_name_ref(&name_ref); 315 let path = Path::from_name_ref(&name_ref);
309 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 316 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
317 let is_macro_use = extern_crate.has_atom_attr("macro_use");
310 let import_data = ImportData { 318 let import_data = ImportData {
311 path, 319 path,
312 alias, 320 alias,
313 is_glob: false, 321 is_glob: false,
314 is_prelude: false, 322 is_prelude: false,
315 is_extern_crate: true, 323 is_extern_crate: true,
324 is_macro_use,
316 }; 325 };
317 self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate))); 326 self.push_import(current_module, import_data, Either::B(AstPtr::new(&extern_crate)));
318 } 327 }
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index c1dbad283..4ff897ca5 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -2,7 +2,7 @@ mod macros;
2mod globs; 2mod globs;
3mod incremental; 3mod incremental;
4mod primitives; 4mod primitives;
5mod mods; 5mod mod_resolution;
6 6
7use std::sync::Arc; 7use std::sync::Arc;
8 8
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index 631df2cef..aece1515b 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -99,14 +99,14 @@ fn macro_rules_from_other_crates_are_visible() {
99fn unexpanded_macro_should_expand_by_fixedpoint_loop() { 99fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
100 let map = def_map_with_crate_graph( 100 let map = def_map_with_crate_graph(
101 " 101 "
102 //- /main.rs 102 //- /main.rs
103 macro_rules! baz { 103 macro_rules! baz {
104 () => { 104 () => {
105 use foo::bar; 105 use foo::bar;
106 } 106 }
107 } 107 }
108 108
109 foo!(); 109 foo!();
110 bar!(); 110 bar!();
111 baz!(); 111 baz!();
112 112
@@ -114,7 +114,7 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
114 #[macro_export] 114 #[macro_export]
115 macro_rules! foo { 115 macro_rules! foo {
116 () => { 116 () => {
117 struct Foo { field: u32 } 117 struct Foo { field: u32 }
118 } 118 }
119 } 119 }
120 #[macro_export] 120 #[macro_export]
@@ -137,3 +137,114 @@ fn unexpanded_macro_should_expand_by_fixedpoint_loop() {
137 ⋮foo: m 137 ⋮foo: m
138 "###); 138 "###);
139} 139}
140
141#[test]
142fn macro_rules_from_other_crates_are_visible_with_macro_use() {
143 covers!(macro_rules_from_other_crates_are_visible_with_macro_use);
144 let map = def_map_with_crate_graph(
145 "
146 //- /main.rs
147 structs!(Foo);
148 structs_priv!(Bar);
149 structs_not_exported!(MacroNotResolved1);
150 crate::structs!(MacroNotResolved2);
151
152 mod bar;
153
154 #[macro_use]
155 extern crate foo;
156
157 //- /bar.rs
158 structs!(Baz);
159 crate::structs!(MacroNotResolved3);
160
161 //- /lib.rs
162 #[macro_export]
163 macro_rules! structs {
164 ($i:ident) => { struct $i; }
165 }
166
167 macro_rules! structs_not_exported {
168 ($i:ident) => { struct $i; }
169 }
170
171 mod priv_mod {
172 #[macro_export]
173 macro_rules! structs_priv {
174 ($i:ident) => { struct $i; }
175 }
176 }
177 ",
178 crate_graph! {
179 "main": ("/main.rs", ["foo"]),
180 "foo": ("/lib.rs", []),
181 },
182 );
183 assert_snapshot!(map, @r###"
184 ⋮crate
185 ⋮Bar: t v
186 ⋮Foo: t v
187 ⋮bar: t
188 ⋮foo: t
189
190 ⋮crate::bar
191 ⋮Baz: t v
192 "###);
193}
194
195#[test]
196fn prelude_is_macro_use() {
197 covers!(prelude_is_macro_use);
198 let map = def_map_with_crate_graph(
199 "
200 //- /main.rs
201 structs!(Foo);
202 structs_priv!(Bar);
203 structs_outside!(Out);
204 crate::structs!(MacroNotResolved2);
205
206 mod bar;
207
208 //- /bar.rs
209 structs!(Baz);
210 crate::structs!(MacroNotResolved3);
211
212 //- /lib.rs
213 #[prelude_import]
214 use self::prelude::*;
215
216 mod prelude {
217 #[macro_export]
218 macro_rules! structs {
219 ($i:ident) => { struct $i; }
220 }
221
222 mod priv_mod {
223 #[macro_export]
224 macro_rules! structs_priv {
225 ($i:ident) => { struct $i; }
226 }
227 }
228 }
229
230 #[macro_export]
231 macro_rules! structs_outside {
232 ($i:ident) => { struct $i; }
233 }
234 ",
235 crate_graph! {
236 "main": ("/main.rs", ["foo"]),
237 "foo": ("/lib.rs", []),
238 },
239 );
240 assert_snapshot!(map, @r###"
241 ⋮crate
242 ⋮Bar: t v
243 ⋮Foo: t v
244 ⋮Out: t v
245 ⋮bar: t
246
247 ⋮crate::bar
248 ⋮Baz: t v
249 "###);
250}
diff --git a/crates/ra_hir/src/nameres/tests/mods.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
index 4f8398460..4f8398460 100644
--- a/crates/ra_hir/src/nameres/tests/mods.rs
+++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 5ee71e421..24316fc91 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -31,7 +31,8 @@ pub struct GenericArgs {
31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type 31 /// Self type. Otherwise, when we have a path `Trait<X, Y>`, the Self type
32 /// is left out. 32 /// is left out.
33 pub has_self_type: bool, 33 pub has_self_type: bool,
34 // someday also bindings 34 /// Associated type bindings like in `Iterator<Item = T>`.
35 pub bindings: Vec<(Name, TypeRef)>,
35} 36}
36 37
37/// A single generic argument. 38/// A single generic argument.
@@ -170,16 +171,24 @@ impl GenericArgs {
170 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 171 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
171 args.push(GenericArg::Type(type_ref)); 172 args.push(GenericArg::Type(type_ref));
172 } 173 }
173 // lifetimes and assoc type args ignored for now 174 // lifetimes ignored for now
174 if !args.is_empty() { 175 let mut bindings = Vec::new();
175 Some(GenericArgs { args, has_self_type: false }) 176 for assoc_type_arg in node.assoc_type_args() {
176 } else { 177 if let Some(name_ref) = assoc_type_arg.name_ref() {
178 let name = name_ref.as_name();
179 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
180 bindings.push((name, type_ref));
181 }
182 }
183 if args.is_empty() && bindings.is_empty() {
177 None 184 None
185 } else {
186 Some(GenericArgs { args, has_self_type: false, bindings })
178 } 187 }
179 } 188 }
180 189
181 pub(crate) fn empty() -> GenericArgs { 190 pub(crate) fn empty() -> GenericArgs {
182 GenericArgs { args: Vec::new(), has_self_type: false } 191 GenericArgs { args: Vec::new(), has_self_type: false, bindings: Vec::new() }
183 } 192 }
184} 193}
185 194
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index e5f4d11a6..fdbe5e8b0 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -228,7 +228,7 @@ impl SourceAnalyzer {
228 let scopes = db.expr_scopes(def); 228 let scopes = db.expr_scopes(def);
229 let scope = match offset { 229 let scope = match offset {
230 None => scope_for(&scopes, &source_map, &node), 230 None => scope_for(&scopes, &source_map, &node),
231 Some(offset) => scope_for_offset(&scopes, &source_map, offset), 231 Some(offset) => scope_for_offset(&scopes, &source_map, file_id.into(), offset),
232 }; 232 };
233 let resolver = expr::resolver_for_scope(def.body(db), db, scope); 233 let resolver = expr::resolver_for_scope(def.body(db), db, scope);
234 SourceAnalyzer { 234 SourceAnalyzer {
@@ -330,6 +330,7 @@ impl SourceAnalyzer {
330 .body_source_map 330 .body_source_map
331 .as_ref()? 331 .as_ref()?
332 .pat_syntax(it)? 332 .pat_syntax(it)?
333 .ast // FIXME: ignoring file_id here is definitelly wrong
333 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap()); 334 .map_a(|ptr| ptr.cast::<ast::BindPat>().unwrap());
334 PathResolution::LocalBinding(pat_ptr) 335 PathResolution::LocalBinding(pat_ptr)
335 } 336 }
@@ -354,7 +355,7 @@ impl SourceAnalyzer {
354 ret.and_then(|entry| { 355 ret.and_then(|entry| {
355 Some(ScopeEntryWithSyntax { 356 Some(ScopeEntryWithSyntax {
356 name: entry.name().clone(), 357 name: entry.name().clone(),
357 ptr: source_map.pat_syntax(entry.pat())?, 358 ptr: source_map.pat_syntax(entry.pat())?.ast,
358 }) 359 })
359 }) 360 })
360 } 361 }
@@ -470,20 +471,27 @@ fn scope_for(
470fn scope_for_offset( 471fn scope_for_offset(
471 scopes: &ExprScopes, 472 scopes: &ExprScopes,
472 source_map: &BodySourceMap, 473 source_map: &BodySourceMap,
474 file_id: HirFileId,
473 offset: TextUnit, 475 offset: TextUnit,
474) -> Option<ScopeId> { 476) -> Option<ScopeId> {
475 scopes 477 scopes
476 .scope_by_expr() 478 .scope_by_expr()
477 .iter() 479 .iter()
478 .filter_map(|(id, scope)| { 480 .filter_map(|(id, scope)| {
479 let ast_ptr = source_map.expr_syntax(*id)?.a()?; 481 let source = source_map.expr_syntax(*id)?;
480 Some((ast_ptr.syntax_node_ptr(), scope)) 482 // FIXME: correctly handle macro expansion
483 if source.file_id != file_id {
484 return None;
485 }
486 let syntax_node_ptr =
487 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
488 Some((syntax_node_ptr, scope))
481 }) 489 })
482 // find containing scope 490 // find containing scope
483 .min_by_key(|(ptr, _scope)| { 491 .min_by_key(|(ptr, _scope)| {
484 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len()) 492 (!(ptr.range().start() <= offset && offset <= ptr.range().end()), ptr.range().len())
485 }) 493 })
486 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, offset).unwrap_or(*scope)) 494 .map(|(ptr, scope)| adjust(scopes, source_map, ptr, file_id, offset).unwrap_or(*scope))
487} 495}
488 496
489// XXX: during completion, cursor might be outside of any particular 497// XXX: during completion, cursor might be outside of any particular
@@ -492,6 +500,7 @@ fn adjust(
492 scopes: &ExprScopes, 500 scopes: &ExprScopes,
493 source_map: &BodySourceMap, 501 source_map: &BodySourceMap,
494 ptr: SyntaxNodePtr, 502 ptr: SyntaxNodePtr,
503 file_id: HirFileId,
495 offset: TextUnit, 504 offset: TextUnit,
496) -> Option<ScopeId> { 505) -> Option<ScopeId> {
497 let r = ptr.range(); 506 let r = ptr.range();
@@ -499,8 +508,14 @@ fn adjust(
499 .scope_by_expr() 508 .scope_by_expr()
500 .iter() 509 .iter()
501 .filter_map(|(id, scope)| { 510 .filter_map(|(id, scope)| {
502 let ast_ptr = source_map.expr_syntax(*id)?.a()?; 511 let source = source_map.expr_syntax(*id)?;
503 Some((ast_ptr.syntax_node_ptr(), scope)) 512 // FIXME: correctly handle macro expansion
513 if source.file_id != file_id {
514 return None;
515 }
516 let syntax_node_ptr =
517 source.ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr());
518 Some((syntax_node_ptr, scope))
504 }) 519 })
505 .map(|(ptr, scope)| (ptr.range(), scope)) 520 .map(|(ptr, scope)| (ptr.range(), scope))
506 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r); 521 .filter(|(range, _)| range.start() <= offset && range.is_subrange(&r) && *range != r);
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index b54c80318..a3df08827 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -120,12 +120,44 @@ pub struct ProjectionTy {
120 pub parameters: Substs, 120 pub parameters: Substs,
121} 121}
122 122
123impl ProjectionTy {
124 pub fn trait_ref(&self, db: &impl HirDatabase) -> TraitRef {
125 TraitRef {
126 trait_: self
127 .associated_ty
128 .parent_trait(db)
129 .expect("projection ty without parent trait"),
130 substs: self.parameters.clone(),
131 }
132 }
133}
134
135impl TypeWalk for ProjectionTy {
136 fn walk(&self, f: &mut impl FnMut(&Ty)) {
137 self.parameters.walk(f);
138 }
139
140 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
141 self.parameters.walk_mut(f);
142 }
143}
144
123#[derive(Clone, PartialEq, Eq, Debug, Hash)] 145#[derive(Clone, PartialEq, Eq, Debug, Hash)]
124pub struct UnselectedProjectionTy { 146pub struct UnselectedProjectionTy {
125 pub type_name: Name, 147 pub type_name: Name,
126 pub parameters: Substs, 148 pub parameters: Substs,
127} 149}
128 150
151impl TypeWalk for UnselectedProjectionTy {
152 fn walk(&self, f: &mut impl FnMut(&Ty)) {
153 self.parameters.walk(f);
154 }
155
156 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
157 self.parameters.walk_mut(f);
158 }
159}
160
129/// A type. 161/// A type.
130/// 162///
131/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents 163/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@@ -282,20 +314,14 @@ impl TraitRef {
282 pub fn self_ty(&self) -> &Ty { 314 pub fn self_ty(&self) -> &Ty {
283 &self.substs[0] 315 &self.substs[0]
284 } 316 }
317}
285 318
286 pub fn subst(mut self, substs: &Substs) -> TraitRef { 319impl TypeWalk for TraitRef {
287 self.substs.walk_mut(&mut |ty_mut| { 320 fn walk(&self, f: &mut impl FnMut(&Ty)) {
288 let ty = mem::replace(ty_mut, Ty::Unknown);
289 *ty_mut = ty.subst(substs);
290 });
291 self
292 }
293
294 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
295 self.substs.walk(f); 321 self.substs.walk(f);
296 } 322 }
297 323
298 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 324 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
299 self.substs.walk_mut(f); 325 self.substs.walk_mut(f);
300 } 326 }
301} 327}
@@ -306,6 +332,8 @@ impl TraitRef {
306pub enum GenericPredicate { 332pub enum GenericPredicate {
307 /// The given trait needs to be implemented for its type parameters. 333 /// The given trait needs to be implemented for its type parameters.
308 Implemented(TraitRef), 334 Implemented(TraitRef),
335 /// An associated type bindings like in `Iterator<Item = T>`.
336 Projection(ProjectionPredicate),
309 /// We couldn't resolve the trait reference. (If some type parameters can't 337 /// We couldn't resolve the trait reference. (If some type parameters can't
310 /// be resolved, they will just be Unknown). 338 /// be resolved, they will just be Unknown).
311 Error, 339 Error,
@@ -319,25 +347,35 @@ impl GenericPredicate {
319 } 347 }
320 } 348 }
321 349
322 pub fn subst(self, substs: &Substs) -> GenericPredicate { 350 pub fn is_implemented(&self) -> bool {
323 match self { 351 match self {
324 GenericPredicate::Implemented(trait_ref) => { 352 GenericPredicate::Implemented(_) => true,
325 GenericPredicate::Implemented(trait_ref.subst(substs)) 353 _ => false,
326 }
327 GenericPredicate::Error => self,
328 } 354 }
329 } 355 }
330 356
331 pub fn walk(&self, f: &mut impl FnMut(&Ty)) { 357 pub fn trait_ref(&self, db: &impl HirDatabase) -> Option<TraitRef> {
358 match self {
359 GenericPredicate::Implemented(tr) => Some(tr.clone()),
360 GenericPredicate::Projection(proj) => Some(proj.projection_ty.trait_ref(db)),
361 GenericPredicate::Error => None,
362 }
363 }
364}
365
366impl TypeWalk for GenericPredicate {
367 fn walk(&self, f: &mut impl FnMut(&Ty)) {
332 match self { 368 match self {
333 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f), 369 GenericPredicate::Implemented(trait_ref) => trait_ref.walk(f),
370 GenericPredicate::Projection(projection_pred) => projection_pred.walk(f),
334 GenericPredicate::Error => {} 371 GenericPredicate::Error => {}
335 } 372 }
336 } 373 }
337 374
338 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 375 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
339 match self { 376 match self {
340 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f), 377 GenericPredicate::Implemented(trait_ref) => trait_ref.walk_mut(f),
378 GenericPredicate::Projection(projection_pred) => projection_pred.walk_mut(f),
341 GenericPredicate::Error => {} 379 GenericPredicate::Error => {}
342 } 380 }
343 } 381 }
@@ -378,16 +416,16 @@ impl FnSig {
378 pub fn ret(&self) -> &Ty { 416 pub fn ret(&self) -> &Ty {
379 &self.params_and_return[self.params_and_return.len() - 1] 417 &self.params_and_return[self.params_and_return.len() - 1]
380 } 418 }
419}
381 420
382 /// Applies the given substitutions to all types in this signature and 421impl TypeWalk for FnSig {
383 /// returns the result. 422 fn walk(&self, f: &mut impl FnMut(&Ty)) {
384 pub fn subst(&self, substs: &Substs) -> FnSig { 423 for t in self.params_and_return.iter() {
385 let result: Vec<_> = 424 t.walk(f);
386 self.params_and_return.iter().map(|ty| ty.clone().subst(substs)).collect(); 425 }
387 FnSig { params_and_return: result.into() }
388 } 426 }
389 427
390 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 428 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
391 // Without an Arc::make_mut_slice, we can't avoid the clone here: 429 // Without an Arc::make_mut_slice, we can't avoid the clone here:
392 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect(); 430 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
393 for t in &mut v { 431 for t in &mut v {
@@ -411,64 +449,6 @@ impl Ty {
411 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty()) 449 Ty::apply(TypeCtor::Tuple { cardinality: 0 }, Substs::empty())
412 } 450 }
413 451
414 pub fn walk(&self, f: &mut impl FnMut(&Ty)) {
415 match self {
416 Ty::Apply(a_ty) => {
417 for t in a_ty.parameters.iter() {
418 t.walk(f);
419 }
420 }
421 Ty::Projection(p_ty) => {
422 for t in p_ty.parameters.iter() {
423 t.walk(f);
424 }
425 }
426 Ty::UnselectedProjection(p_ty) => {
427 for t in p_ty.parameters.iter() {
428 t.walk(f);
429 }
430 }
431 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
432 for p in predicates.iter() {
433 p.walk(f);
434 }
435 }
436 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
437 }
438 f(self);
439 }
440
441 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
442 match self {
443 Ty::Apply(a_ty) => {
444 a_ty.parameters.walk_mut(f);
445 }
446 Ty::Projection(p_ty) => {
447 p_ty.parameters.walk_mut(f);
448 }
449 Ty::UnselectedProjection(p_ty) => {
450 p_ty.parameters.walk_mut(f);
451 }
452 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
453 let mut v: Vec<_> = predicates.iter().cloned().collect();
454 for p in &mut v {
455 p.walk_mut(f);
456 }
457 *predicates = v.into();
458 }
459 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
460 }
461 f(self);
462 }
463
464 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Ty {
465 self.walk_mut(&mut |ty_mut| {
466 let ty = mem::replace(ty_mut, Ty::Unknown);
467 *ty_mut = f(ty);
468 });
469 self
470 }
471
472 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> { 452 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
473 match self { 453 match self {
474 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { 454 Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => {
@@ -544,10 +524,53 @@ impl Ty {
544 } 524 }
545 } 525 }
546 526
527 /// Returns the type parameters of this type if it has some (i.e. is an ADT
528 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
529 pub fn substs(&self) -> Option<Substs> {
530 match self {
531 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
532 _ => None,
533 }
534 }
535
536 /// If this is an `impl Trait` or `dyn Trait`, returns that trait.
537 pub fn inherent_trait(&self) -> Option<Trait> {
538 match self {
539 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
540 predicates.iter().find_map(|pred| match pred {
541 GenericPredicate::Implemented(tr) => Some(tr.trait_),
542 _ => None,
543 })
544 }
545 _ => None,
546 }
547 }
548}
549
550/// This allows walking structures that contain types to do something with those
551/// types, similar to Chalk's `Fold` trait.
552pub trait TypeWalk {
553 fn walk(&self, f: &mut impl FnMut(&Ty));
554 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty));
555
556 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
557 where
558 Self: Sized,
559 {
560 self.walk_mut(&mut |ty_mut| {
561 let ty = mem::replace(ty_mut, Ty::Unknown);
562 *ty_mut = f(ty);
563 });
564 self
565 }
566
547 /// Replaces type parameters in this type using the given `Substs`. (So e.g. 567 /// Replaces type parameters in this type using the given `Substs`. (So e.g.
548 /// if `self` is `&[T]`, where type parameter T has index 0, and the 568 /// if `self` is `&[T]`, where type parameter T has index 0, and the
549 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.) 569 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
550 pub fn subst(self, substs: &Substs) -> Ty { 570 fn subst(self, substs: &Substs) -> Self
571 where
572 Self: Sized,
573 {
551 self.fold(&mut |ty| match ty { 574 self.fold(&mut |ty| match ty {
552 Ty::Param { idx, name } => { 575 Ty::Param { idx, name } => {
553 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name }) 576 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
@@ -557,24 +580,21 @@ impl Ty {
557 } 580 }
558 581
559 /// Substitutes `Ty::Bound` vars (as opposed to type parameters). 582 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
560 pub fn subst_bound_vars(self, substs: &Substs) -> Ty { 583 fn subst_bound_vars(self, substs: &Substs) -> Self
584 where
585 Self: Sized,
586 {
561 self.fold(&mut |ty| match ty { 587 self.fold(&mut |ty| match ty {
562 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)), 588 Ty::Bound(idx) => substs.get(idx as usize).cloned().unwrap_or_else(|| Ty::Bound(idx)),
563 ty => ty, 589 ty => ty,
564 }) 590 })
565 } 591 }
566 592
567 /// Returns the type parameters of this type if it has some (i.e. is an ADT
568 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
569 pub fn substs(&self) -> Option<Substs> {
570 match self {
571 Ty::Apply(ApplicationTy { parameters, .. }) => Some(parameters.clone()),
572 _ => None,
573 }
574 }
575
576 /// Shifts up `Ty::Bound` vars by `n`. 593 /// Shifts up `Ty::Bound` vars by `n`.
577 pub fn shift_bound_vars(self, n: i32) -> Ty { 594 fn shift_bound_vars(self, n: i32) -> Self
595 where
596 Self: Sized,
597 {
578 self.fold(&mut |ty| match ty { 598 self.fold(&mut |ty| match ty {
579 Ty::Bound(idx) => { 599 Ty::Bound(idx) => {
580 assert!(idx as i32 >= -n); 600 assert!(idx as i32 >= -n);
@@ -583,18 +603,57 @@ impl Ty {
583 ty => ty, 603 ty => ty,
584 }) 604 })
585 } 605 }
606}
586 607
587 /// If this is an `impl Trait` or `dyn Trait`, returns that trait. 608impl TypeWalk for Ty {
588 pub fn inherent_trait(&self) -> Option<Trait> { 609 fn walk(&self, f: &mut impl FnMut(&Ty)) {
610 match self {
611 Ty::Apply(a_ty) => {
612 for t in a_ty.parameters.iter() {
613 t.walk(f);
614 }
615 }
616 Ty::Projection(p_ty) => {
617 for t in p_ty.parameters.iter() {
618 t.walk(f);
619 }
620 }
621 Ty::UnselectedProjection(p_ty) => {
622 for t in p_ty.parameters.iter() {
623 t.walk(f);
624 }
625 }
626 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
627 for p in predicates.iter() {
628 p.walk(f);
629 }
630 }
631 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
632 }
633 f(self);
634 }
635
636 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
589 match self { 637 match self {
638 Ty::Apply(a_ty) => {
639 a_ty.parameters.walk_mut(f);
640 }
641 Ty::Projection(p_ty) => {
642 p_ty.parameters.walk_mut(f);
643 }
644 Ty::UnselectedProjection(p_ty) => {
645 p_ty.parameters.walk_mut(f);
646 }
590 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 647 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
591 predicates.iter().find_map(|pred| match pred { 648 let mut v: Vec<_> = predicates.iter().cloned().collect();
592 GenericPredicate::Implemented(tr) => Some(tr.trait_), 649 for p in &mut v {
593 _ => None, 650 p.walk_mut(f);
594 }) 651 }
652 *predicates = v.into();
595 } 653 }
596 _ => None, 654 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
597 } 655 }
656 f(self);
598 } 657 }
599} 658}
600 659
@@ -742,20 +801,66 @@ impl HirDisplay for Ty {
742 Ty::Opaque(_) => write!(f, "impl ")?, 801 Ty::Opaque(_) => write!(f, "impl ")?,
743 _ => unreachable!(), 802 _ => unreachable!(),
744 }; 803 };
745 // looping by hand here just to format the bounds in a slightly nicer way 804 // Note: This code is written to produce nice results (i.e.
805 // corresponding to surface Rust) for types that can occur in
806 // actual Rust. It will have weird results if the predicates
807 // aren't as expected (i.e. self types = $0, projection
808 // predicates for a certain trait come after the Implemented
809 // predicate for that trait).
746 let mut first = true; 810 let mut first = true;
811 let mut angle_open = false;
747 for p in predicates.iter() { 812 for p in predicates.iter() {
748 if !first {
749 write!(f, " + ")?;
750 }
751 first = false;
752 match p { 813 match p {
753 // don't show the $0 self type
754 GenericPredicate::Implemented(trait_ref) => { 814 GenericPredicate::Implemented(trait_ref) => {
755 trait_ref.hir_fmt_ext(f, false)? 815 if angle_open {
816 write!(f, ">")?;
817 }
818 if !first {
819 write!(f, " + ")?;
820 }
821 // We assume that the self type is $0 (i.e. the
822 // existential) here, which is the only thing that's
823 // possible in actual Rust, and hence don't print it
824 write!(
825 f,
826 "{}",
827 trait_ref.trait_.name(f.db).unwrap_or_else(Name::missing)
828 )?;
829 if trait_ref.substs.len() > 1 {
830 write!(f, "<")?;
831 f.write_joined(&trait_ref.substs[1..], ", ")?;
832 // there might be assoc type bindings, so we leave the angle brackets open
833 angle_open = true;
834 }
835 }
836 GenericPredicate::Projection(projection_pred) => {
837 // in types in actual Rust, these will always come
838 // after the corresponding Implemented predicate
839 if angle_open {
840 write!(f, ", ")?;
841 } else {
842 write!(f, "<")?;
843 angle_open = true;
844 }
845 let name = projection_pred.projection_ty.associated_ty.name(f.db);
846 write!(f, "{} = ", name)?;
847 projection_pred.ty.hir_fmt(f)?;
848 }
849 GenericPredicate::Error => {
850 if angle_open {
851 // impl Trait<X, {error}>
852 write!(f, ", ")?;
853 } else if !first {
854 // impl Trait + {error}
855 write!(f, " + ")?;
856 }
857 p.hir_fmt(f)?;
756 } 858 }
757 GenericPredicate::Error => p.hir_fmt(f)?,
758 } 859 }
860 first = false;
861 }
862 if angle_open {
863 write!(f, ">")?;
759 } 864 }
760 } 865 }
761 Ty::Unknown => write!(f, "{{unknown}}")?, 866 Ty::Unknown => write!(f, "{{unknown}}")?,
@@ -766,13 +871,12 @@ impl HirDisplay for Ty {
766} 871}
767 872
768impl TraitRef { 873impl TraitRef {
769 fn hir_fmt_ext( 874 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
770 &self, 875 self.substs[0].hir_fmt(f)?;
771 f: &mut HirFormatter<impl HirDatabase>, 876 if use_as {
772 with_self_ty: bool, 877 write!(f, " as ")?;
773 ) -> fmt::Result { 878 } else {
774 if with_self_ty { 879 write!(f, ": ")?;
775 write!(f, "{}: ", self.substs[0].display(f.db),)?;
776 } 880 }
777 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?; 881 write!(f, "{}", self.trait_.name(f.db).unwrap_or_else(Name::missing))?;
778 if self.substs.len() > 1 { 882 if self.substs.len() > 1 {
@@ -786,7 +890,7 @@ impl TraitRef {
786 890
787impl HirDisplay for TraitRef { 891impl HirDisplay for TraitRef {
788 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 892 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
789 self.hir_fmt_ext(f, true) 893 self.hir_fmt_ext(f, false)
790 } 894 }
791} 895}
792 896
@@ -800,6 +904,16 @@ impl HirDisplay for GenericPredicate {
800 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result { 904 fn hir_fmt(&self, f: &mut HirFormatter<impl HirDatabase>) -> fmt::Result {
801 match self { 905 match self {
802 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 906 GenericPredicate::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
907 GenericPredicate::Projection(projection_pred) => {
908 write!(f, "<")?;
909 projection_pred.projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?;
910 write!(
911 f,
912 ">::{} = {}",
913 projection_pred.projection_ty.associated_ty.name(f.db),
914 projection_pred.ty.display(f.db)
915 )?;
916 }
803 GenericPredicate::Error => write!(f, "{{error}}")?, 917 GenericPredicate::Error => write!(f, "{{error}}")?,
804 } 918 }
805 Ok(()) 919 Ok(())
diff --git a/crates/ra_hir/src/ty/autoderef.rs b/crates/ra_hir/src/ty/autoderef.rs
index 2535d4ae7..08f52a53b 100644
--- a/crates/ra_hir/src/ty/autoderef.rs
+++ b/crates/ra_hir/src/ty/autoderef.rs
@@ -7,7 +7,7 @@ use std::iter::successors;
7 7
8use log::{info, warn}; 8use log::{info, warn};
9 9
10use super::{traits::Solution, Canonical, Ty}; 10use super::{traits::Solution, Canonical, Ty, TypeWalk};
11use crate::{HasGenericParams, HirDatabase, Name, Resolver}; 11use crate::{HasGenericParams, HirDatabase, Name, Resolver};
12 12
13const AUTODEREF_RECURSION_LIMIT: usize = 10; 13const AUTODEREF_RECURSION_LIMIT: usize = 10;
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index b89a40b4b..ec3b7ffef 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -30,7 +30,7 @@ use super::{
30 autoderef, lower, method_resolution, op, primitive, 30 autoderef, lower, method_resolution, op, primitive,
31 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 31 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, 32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef,
33 Ty, TypableDef, TypeCtor, 33 Ty, TypableDef, TypeCtor, TypeWalk,
34}; 34};
35use crate::{ 35use crate::{
36 adt::VariantDef, 36 adt::VariantDef,
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index e7e8825d1..9a0d2d8f9 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -3,7 +3,7 @@
3use super::{InferenceContext, Obligation}; 3use super::{InferenceContext, Obligation};
4use crate::db::HirDatabase; 4use crate::db::HirDatabase;
5use crate::ty::{ 5use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, TraitRef, Ty, TypeWalk,
7}; 7};
8 8
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 9impl<'a, D: HirDatabase> InferenceContext<'a, D> {
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 47d161277..f6f0137cf 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -8,7 +8,10 @@
8use std::iter; 8use std::iter;
9use std::sync::Arc; 9use std::sync::Arc;
10 10
11use super::{FnSig, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor}; 11use super::{
12 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
13 TypeWalk,
14};
12use crate::{ 15use crate::{
13 adt::VariantDef, 16 adt::VariantDef,
14 generics::HasGenericParams, 17 generics::HasGenericParams,
@@ -62,7 +65,9 @@ impl Ty {
62 let self_ty = Ty::Bound(0); 65 let self_ty = Ty::Bound(0);
63 let predicates = bounds 66 let predicates = bounds
64 .iter() 67 .iter()
65 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 68 .flat_map(|b| {
69 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
70 })
66 .collect::<Vec<_>>(); 71 .collect::<Vec<_>>();
67 Ty::Dyn(predicates.into()) 72 Ty::Dyn(predicates.into())
68 } 73 }
@@ -70,7 +75,9 @@ impl Ty {
70 let self_ty = Ty::Bound(0); 75 let self_ty = Ty::Bound(0);
71 let predicates = bounds 76 let predicates = bounds
72 .iter() 77 .iter()
73 .map(|b| GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())) 78 .flat_map(|b| {
79 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
80 })
74 .collect::<Vec<_>>(); 81 .collect::<Vec<_>>();
75 Ty::Opaque(predicates.into()) 82 Ty::Opaque(predicates.into())
76 } 83 }
@@ -326,15 +333,6 @@ impl TraitRef {
326 TraitRef { trait_, substs } 333 TraitRef { trait_, substs }
327 } 334 }
328 335
329 pub(crate) fn from_where_predicate(
330 db: &impl HirDatabase,
331 resolver: &Resolver,
332 pred: &WherePredicate,
333 ) -> Option<TraitRef> {
334 let self_ty = Ty::from_hir(db, resolver, &pred.type_ref);
335 TraitRef::from_type_bound(db, resolver, &pred.bound, self_ty)
336 }
337
338 pub(crate) fn from_type_bound( 336 pub(crate) fn from_type_bound(
339 db: &impl HirDatabase, 337 db: &impl HirDatabase,
340 resolver: &Resolver, 338 resolver: &Resolver,
@@ -349,26 +347,58 @@ impl TraitRef {
349} 347}
350 348
351impl GenericPredicate { 349impl GenericPredicate {
352 pub(crate) fn from_where_predicate( 350 pub(crate) fn from_where_predicate<'a>(
353 db: &impl HirDatabase, 351 db: &'a impl HirDatabase,
354 resolver: &Resolver, 352 resolver: &'a Resolver,
355 where_predicate: &WherePredicate, 353 where_predicate: &'a WherePredicate,
356 ) -> GenericPredicate { 354 ) -> impl Iterator<Item = GenericPredicate> + 'a {
357 TraitRef::from_where_predicate(db, &resolver, where_predicate) 355 let self_ty = Ty::from_hir(db, resolver, &where_predicate.type_ref);
358 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 356 GenericPredicate::from_type_bound(db, resolver, &where_predicate.bound, self_ty)
359 } 357 }
360 358
361 pub(crate) fn from_type_bound( 359 pub(crate) fn from_type_bound<'a>(
362 db: &impl HirDatabase, 360 db: &'a impl HirDatabase,
363 resolver: &Resolver, 361 resolver: &'a Resolver,
364 bound: &TypeBound, 362 bound: &'a TypeBound,
365 self_ty: Ty, 363 self_ty: Ty,
366 ) -> GenericPredicate { 364 ) -> impl Iterator<Item = GenericPredicate> + 'a {
367 TraitRef::from_type_bound(db, &resolver, bound, self_ty) 365 let trait_ref = TraitRef::from_type_bound(db, &resolver, bound, self_ty);
368 .map_or(GenericPredicate::Error, GenericPredicate::Implemented) 366 iter::once(trait_ref.clone().map_or(GenericPredicate::Error, GenericPredicate::Implemented))
367 .chain(
368 trait_ref.into_iter().flat_map(move |tr| {
369 assoc_type_bindings_from_type_bound(db, resolver, bound, tr)
370 }),
371 )
369 } 372 }
370} 373}
371 374
375fn assoc_type_bindings_from_type_bound<'a>(
376 db: &'a impl HirDatabase,
377 resolver: &'a Resolver,
378 bound: &'a TypeBound,
379 trait_ref: TraitRef,
380) -> impl Iterator<Item = GenericPredicate> + 'a {
381 let last_segment = match bound {
382 TypeBound::Path(path) => path.segments.last(),
383 TypeBound::Error => None,
384 };
385 last_segment
386 .into_iter()
387 .flat_map(|segment| segment.args_and_bindings.iter())
388 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
389 .map(move |(name, type_ref)| {
390 let associated_ty = match trait_ref.trait_.associated_type_by_name(db, name.clone()) {
391 None => return GenericPredicate::Error,
392 Some(t) => t,
393 };
394 let projection_ty =
395 ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() };
396 let ty = Ty::from_hir(db, resolver, type_ref);
397 let projection_predicate = ProjectionPredicate { projection_ty, ty };
398 GenericPredicate::Projection(projection_predicate)
399 })
400}
401
372/// Build the declared type of an item. This depends on the namespace; e.g. for 402/// Build the declared type of an item. This depends on the namespace; e.g. for
373/// `struct Foo(usize)`, we have two types: The type of the struct itself, and 403/// `struct Foo(usize)`, we have two types: The type of the struct itself, and
374/// the constructor function `(usize) -> Foo` which lives in the values 404/// the constructor function `(usize) -> Foo` which lives in the values
@@ -425,7 +455,7 @@ pub(crate) fn trait_env(
425) -> Arc<super::TraitEnvironment> { 455) -> Arc<super::TraitEnvironment> {
426 let predicates = resolver 456 let predicates = resolver
427 .where_predicates_in_scope() 457 .where_predicates_in_scope()
428 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 458 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
429 .collect::<Vec<_>>(); 459 .collect::<Vec<_>>();
430 460
431 Arc::new(super::TraitEnvironment { predicates }) 461 Arc::new(super::TraitEnvironment { predicates })
@@ -439,7 +469,7 @@ pub(crate) fn generic_predicates_query(
439 let resolver = def.resolver(db); 469 let resolver = def.resolver(db);
440 let predicates = resolver 470 let predicates = resolver
441 .where_predicates_in_scope() 471 .where_predicates_in_scope()
442 .map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 472 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
443 .collect::<Vec<_>>(); 473 .collect::<Vec<_>>();
444 predicates.into() 474 predicates.into()
445} 475}
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index d344ab12e..d92d4659b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -2793,6 +2793,10 @@ fn main() {
2793} 2793}
2794"#), 2794"#),
2795 @r###" 2795 @r###"
2796 ![0; 17) '{Foo(v...,2,])}': Foo
2797 ![1; 4) 'Foo': Foo({unknown}) -> Foo
2798 ![1; 16) 'Foo(vec![1,2,])': Foo
2799 ![5; 15) 'vec![1,2,]': {unknown}
2796 [156; 182) '{ ...,2); }': () 2800 [156; 182) '{ ...,2); }': ()
2797 [166; 167) 'x': Foo 2801 [166; 167) 'x': Foo
2798 "### 2802 "###
@@ -3548,6 +3552,97 @@ fn test() {
3548 ); 3552 );
3549} 3553}
3550 3554
3555#[test]
3556fn assoc_type_bindings() {
3557 assert_snapshot!(
3558 infer(r#"
3559trait Trait {
3560 type Type;
3561}
3562
3563fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
3564fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
3565fn set<T: Trait<Type = u64>>(t: T) -> T {t}
3566
3567struct S<T>;
3568impl<T> Trait for S<T> { type Type = T; }
3569
3570fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
3571 get(x);
3572 get2(x);
3573 get(y);
3574 get2(y);
3575 get(set(S));
3576 get2(set(S));
3577 get2(S::<str>);
3578}
3579"#),
3580 @r###"
3581 [50; 51) 't': T
3582 [78; 80) '{}': ()
3583 [112; 113) 't': T
3584 [123; 125) '{}': ()
3585 [155; 156) 't': T
3586 [166; 169) '{t}': T
3587 [167; 168) 't': T
3588 [257; 258) 'x': T
3589 [263; 264) 'y': impl Trait<Type = i64>
3590 [290; 398) '{ ...r>); }': ()
3591 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
3592 [296; 302) 'get(x)': {unknown}
3593 [300; 301) 'x': T
3594 [308; 312) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
3595 [308; 315) 'get2(x)': {unknown}
3596 [313; 314) 'x': T
3597 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
3598 [321; 327) 'get(y)': {unknown}
3599 [325; 326) 'y': impl Trait<Type = i64>
3600 [333; 337) 'get2': fn get2<{unknown}, S<{unknown}>>(T) -> U
3601 [333; 340) 'get2(y)': {unknown}
3602 [338; 339) 'y': impl Trait<Type = i64>
3603 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
3604 [346; 357) 'get(set(S))': u64
3605 [350; 353) 'set': fn set<S<u64>>(T) -> T
3606 [350; 356) 'set(S)': S<u64>
3607 [354; 355) 'S': S<u64>
3608 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
3609 [363; 375) 'get2(set(S))': u64
3610 [368; 371) 'set': fn set<S<u64>>(T) -> T
3611 [368; 374) 'set(S)': S<u64>
3612 [372; 373) 'S': S<u64>
3613 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
3614 [381; 395) 'get2(S::<str>)': str
3615 [386; 394) 'S::<str>': S<str>
3616 "###
3617 );
3618}
3619
3620#[test]
3621fn projection_eq_within_chalk() {
3622 // std::env::set_var("CHALK_DEBUG", "1");
3623 assert_snapshot!(
3624 infer(r#"
3625trait Trait1 {
3626 type Type;
3627}
3628trait Trait2<T> {
3629 fn foo(self) -> T;
3630}
3631impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
3632
3633fn test<T: Trait1<Type = u32>>(x: T) {
3634 x.foo();
3635}
3636"#),
3637 @r###"
3638 [62; 66) 'self': Self
3639 [164; 165) 'x': T
3640 [170; 186) '{ ...o(); }': ()
3641 [176; 177) 'x': T
3642 [176; 183) 'x.foo()': {unknown}
3643 "###
3644 );
3645}
3551fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { 3646fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String {
3552 let file = db.parse(pos.file_id).ok().unwrap(); 3647 let file = db.parse(pos.file_id).ok().unwrap();
3553 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 3648 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
@@ -3566,7 +3661,6 @@ fn infer(content: &str) -> String {
3566 let source_file = db.parse(file_id).ok().unwrap(); 3661 let source_file = db.parse(file_id).ok().unwrap();
3567 3662
3568 let mut acc = String::new(); 3663 let mut acc = String::new();
3569 // acc.push_str("\n");
3570 3664
3571 let mut infer_def = |inference_result: Arc<InferenceResult>, 3665 let mut infer_def = |inference_result: Arc<InferenceResult>,
3572 body_source_map: Arc<BodySourceMap>| { 3666 body_source_map: Arc<BodySourceMap>| {
@@ -3574,7 +3668,9 @@ fn infer(content: &str) -> String {
3574 3668
3575 for (pat, ty) in inference_result.type_of_pat.iter() { 3669 for (pat, ty) in inference_result.type_of_pat.iter() {
3576 let syntax_ptr = match body_source_map.pat_syntax(pat) { 3670 let syntax_ptr = match body_source_map.pat_syntax(pat) {
3577 Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), 3671 Some(sp) => {
3672 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
3673 }
3578 None => continue, 3674 None => continue,
3579 }; 3675 };
3580 types.push((syntax_ptr, ty)); 3676 types.push((syntax_ptr, ty));
@@ -3582,22 +3678,34 @@ fn infer(content: &str) -> String {
3582 3678
3583 for (expr, ty) in inference_result.type_of_expr.iter() { 3679 for (expr, ty) in inference_result.type_of_expr.iter() {
3584 let syntax_ptr = match body_source_map.expr_syntax(expr) { 3680 let syntax_ptr = match body_source_map.expr_syntax(expr) {
3585 Some(sp) => sp.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()), 3681 Some(sp) => {
3682 sp.map(|ast| ast.either(|it| it.syntax_node_ptr(), |it| it.syntax_node_ptr()))
3683 }
3586 None => continue, 3684 None => continue,
3587 }; 3685 };
3588 types.push((syntax_ptr, ty)); 3686 types.push((syntax_ptr, ty));
3589 } 3687 }
3590 3688
3591 // sort ranges for consistency 3689 // sort ranges for consistency
3592 types.sort_by_key(|(ptr, _)| (ptr.range().start(), ptr.range().end())); 3690 types.sort_by_key(|(src_ptr, _)| (src_ptr.ast.range().start(), src_ptr.ast.range().end()));
3593 for (syntax_ptr, ty) in &types { 3691 for (src_ptr, ty) in &types {
3594 let node = syntax_ptr.to_node(source_file.syntax()); 3692 let node = src_ptr.ast.to_node(&src_ptr.file_syntax(&db));
3693
3595 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) { 3694 let (range, text) = if let Some(self_param) = ast::SelfParam::cast(node.clone()) {
3596 (self_param.self_kw_token().text_range(), "self".to_string()) 3695 (self_param.self_kw_token().text_range(), "self".to_string())
3597 } else { 3696 } else {
3598 (syntax_ptr.range(), node.text().to_string().replace("\n", " ")) 3697 (src_ptr.ast.range(), node.text().to_string().replace("\n", " "))
3599 }; 3698 };
3600 write!(acc, "{} '{}': {}\n", range, ellipsize(text, 15), ty.display(&db)).unwrap(); 3699 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
3700 write!(
3701 acc,
3702 "{}{} '{}': {}\n",
3703 macro_prefix,
3704 range,
3705 ellipsize(text, 15),
3706 ty.display(&db)
3707 )
3708 .unwrap();
3601 } 3709 }
3602 }; 3710 };
3603 3711
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index b634f0b79..6e0271a96 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -8,7 +8,7 @@ use ra_db::salsa;
8use ra_prof::profile; 8use ra_prof::profile;
9use rustc_hash::FxHashSet; 9use rustc_hash::FxHashSet;
10 10
11use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty}; 11use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
12use crate::{db::HirDatabase, Crate, ImplBlock, Trait}; 12use crate::{db::HirDatabase, Crate, ImplBlock, Trait};
13 13
14use self::chalk::{from_chalk, ToChalk}; 14use self::chalk::{from_chalk, ToChalk};
@@ -124,6 +124,9 @@ impl Obligation {
124 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> { 124 pub fn from_predicate(predicate: GenericPredicate) -> Option<Obligation> {
125 match predicate { 125 match predicate {
126 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)), 126 GenericPredicate::Implemented(trait_ref) => Some(Obligation::Trait(trait_ref)),
127 GenericPredicate::Projection(projection_pred) => {
128 Some(Obligation::Projection(projection_pred))
129 }
127 GenericPredicate::Error => None, 130 GenericPredicate::Error => None,
128 } 131 }
129 } 132 }
@@ -135,6 +138,18 @@ pub struct ProjectionPredicate {
135 pub ty: Ty, 138 pub ty: Ty,
136} 139}
137 140
141impl TypeWalk for ProjectionPredicate {
142 fn walk(&self, f: &mut impl FnMut(&Ty)) {
143 self.projection_ty.walk(f);
144 self.ty.walk(f);
145 }
146
147 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
148 self.projection_ty.walk_mut(f);
149 self.ty.walk_mut(f);
150 }
151}
152
138/// Solve a trait goal using Chalk. 153/// Solve a trait goal using Chalk.
139pub(crate) fn trait_solve_query( 154pub(crate) fn trait_solve_query(
140 db: &impl HirDatabase, 155 db: &impl HirDatabase,
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 2ebc06135..c201c5e50 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -19,6 +19,7 @@ use crate::{
19 ty::display::HirDisplay, 19 ty::display::HirDisplay,
20 ty::{ 20 ty::{
21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, 21 ApplicationTy, CallableDef, GenericPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor,
22 TypeWalk,
22 }, 23 },
23 Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias, 24 Crate, HasGenericParams, ImplBlock, ImplItem, Trait, TypeAlias,
24}; 25};
@@ -211,6 +212,13 @@ impl ToChalk for GenericPredicate {
211 GenericPredicate::Implemented(trait_ref) => { 212 GenericPredicate::Implemented(trait_ref) => {
212 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 213 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
213 } 214 }
215 GenericPredicate::Projection(projection_pred) => make_binders(
216 chalk_ir::WhereClause::ProjectionEq(chalk_ir::ProjectionEq {
217 projection: projection_pred.projection_ty.to_chalk(db),
218 ty: projection_pred.ty.to_chalk(db),
219 }),
220 0,
221 ),
214 GenericPredicate::Error => { 222 GenericPredicate::Error => {
215 let impossible_trait_ref = chalk_ir::TraitRef { 223 let impossible_trait_ref = chalk_ir::TraitRef {
216 trait_id: UNKNOWN_TRAIT, 224 trait_id: UNKNOWN_TRAIT,
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 0234c572d..89631935a 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -213,11 +213,11 @@ impl RootDatabase {
213 durability, 213 durability,
214 ); 214 );
215 self.set_file_source_root_with_durability(add_file.file_id, root_id, durability); 215 self.set_file_source_root_with_durability(add_file.file_id, root_id, durability);
216 source_root.files.insert(add_file.path, add_file.file_id); 216 source_root.insert_file(add_file.path, add_file.file_id);
217 } 217 }
218 for remove_file in root_change.removed { 218 for remove_file in root_change.removed {
219 self.set_file_text_with_durability(remove_file.file_id, Default::default(), durability); 219 self.set_file_text_with_durability(remove_file.file_id, Default::default(), durability);
220 source_root.files.remove(&remove_file.path); 220 source_root.remove_file(&remove_file.path);
221 } 221 }
222 self.set_source_root_with_durability(root_id, Arc::new(source_root), durability); 222 self.set_source_root_with_durability(root_id, Arc::new(source_root), durability);
223 } 223 }
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index f19eec9b7..db7e8348e 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,5 +1,5 @@
1//! This modules takes care of rendering various defenitions as completion items. 1//! This modules takes care of rendering various defenitions as completion items.
2use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty}; 2use hir::{Docs, HasSource, HirDisplay, PerNs, Resolution, Ty, TypeWalk};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::ast::NameOwner; 4use ra_syntax::ast::NameOwner;
5use test_utils::tested_by; 5use test_utils::tested_by;
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 514dcaf96..e90fbd428 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -466,7 +466,7 @@ impl Analysis {
466 &self, 466 &self,
467 position: FilePosition, 467 position: FilePosition,
468 ) -> Cancelable<Option<ReferenceSearchResult>> { 468 ) -> Cancelable<Option<ReferenceSearchResult>> {
469 self.with_db(|db| references::find_all_refs(db, position)) 469 self.with_db(|db| references::find_all_refs(db, position).map(|it| it.info))
470 } 470 }
471 471
472 /// Returns a short text describing element at position. 472 /// Returns a short text describing element at position.
@@ -536,7 +536,7 @@ impl Analysis {
536 &self, 536 &self,
537 position: FilePosition, 537 position: FilePosition,
538 new_name: &str, 538 new_name: &str,
539 ) -> Cancelable<Option<SourceChange>> { 539 ) -> Cancelable<Option<RangeInfo<SourceChange>>> {
540 self.with_db(|db| references::rename(db, position, new_name)) 540 self.with_db(|db| references::rename(db, position, new_name))
541 } 541 }
542 542
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index d8a00067f..5f1f0efc3 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -4,7 +4,7 @@ use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}
4use relative_path::{RelativePath, RelativePathBuf}; 4use relative_path::{RelativePath, RelativePathBuf};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, 7 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo,
8 SourceChange, SourceFileEdit, TextRange, 8 SourceChange, SourceFileEdit, TextRange,
9}; 9};
10 10
@@ -48,9 +48,9 @@ impl IntoIterator for ReferenceSearchResult {
48pub(crate) fn find_all_refs( 48pub(crate) fn find_all_refs(
49 db: &RootDatabase, 49 db: &RootDatabase,
50 position: FilePosition, 50 position: FilePosition,
51) -> Option<ReferenceSearchResult> { 51) -> Option<RangeInfo<ReferenceSearchResult>> {
52 let parse = db.parse(position.file_id); 52 let parse = db.parse(position.file_id);
53 let (binding, analyzer) = find_binding(db, &parse.tree(), position)?; 53 let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?;
54 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); 54 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding);
55 55
56 let references = analyzer 56 let references = analyzer
@@ -59,24 +59,26 @@ pub(crate) fn find_all_refs(
59 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) 59 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range })
60 .collect::<Vec<_>>(); 60 .collect::<Vec<_>>();
61 61
62 return Some(ReferenceSearchResult { declaration, references }); 62 return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }));
63 63
64 fn find_binding<'a>( 64 fn find_binding<'a>(
65 db: &RootDatabase, 65 db: &RootDatabase,
66 source_file: &SourceFile, 66 source_file: &SourceFile,
67 position: FilePosition, 67 position: FilePosition,
68 ) -> Option<(ast::BindPat, hir::SourceAnalyzer)> { 68 ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> {
69 let syntax = source_file.syntax(); 69 let syntax = source_file.syntax();
70 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) { 70 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
71 let range = binding.syntax().text_range();
71 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None); 72 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
72 return Some((binding, analyzer)); 73 return Some(RangeInfo::new(range, (binding, analyzer)));
73 }; 74 };
74 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?; 75 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
76 let range = name_ref.syntax().text_range();
75 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None); 77 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
76 let resolved = analyzer.resolve_local_name(&name_ref)?; 78 let resolved = analyzer.resolve_local_name(&name_ref)?;
77 if let Either::A(ptr) = resolved.ptr() { 79 if let Either::A(ptr) = resolved.ptr() {
78 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) { 80 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) {
79 return Some((binding, analyzer)); 81 return Some(RangeInfo::new(range, (binding, analyzer)));
80 } 82 }
81 } 83 }
82 None 84 None
@@ -87,12 +89,14 @@ pub(crate) fn rename(
87 db: &RootDatabase, 89 db: &RootDatabase,
88 position: FilePosition, 90 position: FilePosition,
89 new_name: &str, 91 new_name: &str,
90) -> Option<SourceChange> { 92) -> Option<RangeInfo<SourceChange>> {
91 let parse = db.parse(position.file_id); 93 let parse = db.parse(position.file_id);
92 if let Some((ast_name, ast_module)) = 94 if let Some((ast_name, ast_module)) =
93 find_name_and_module_at_offset(parse.tree().syntax(), position) 95 find_name_and_module_at_offset(parse.tree().syntax(), position)
94 { 96 {
97 let range = ast_name.syntax().text_range();
95 rename_mod(db, &ast_name, &ast_module, position, new_name) 98 rename_mod(db, &ast_name, &ast_module, position, new_name)
99 .map(|info| RangeInfo::new(range, info))
96 } else { 100 } else {
97 rename_reference(db, position, new_name) 101 rename_reference(db, position, new_name)
98 } 102 }
@@ -107,7 +111,7 @@ fn find_name_and_module_at_offset(
107 Some((ast_name, ast_module)) 111 Some((ast_name, ast_module))
108} 112}
109 113
110fn source_edit_from_fileid_range( 114fn source_edit_from_file_id_range(
111 file_id: FileId, 115 file_id: FileId,
112 range: TextRange, 116 range: TextRange,
113 new_name: &str, 117 new_name: &str,
@@ -179,19 +183,19 @@ fn rename_reference(
179 db: &RootDatabase, 183 db: &RootDatabase,
180 position: FilePosition, 184 position: FilePosition,
181 new_name: &str, 185 new_name: &str,
182) -> Option<SourceChange> { 186) -> Option<RangeInfo<SourceChange>> {
183 let refs = find_all_refs(db, position)?; 187 let RangeInfo { range, info: refs } = find_all_refs(db, position)?;
184 188
185 let edit = refs 189 let edit = refs
186 .into_iter() 190 .into_iter()
187 .map(|range| source_edit_from_fileid_range(range.file_id, range.range, new_name)) 191 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
188 .collect::<Vec<_>>(); 192 .collect::<Vec<_>>();
189 193
190 if edit.is_empty() { 194 if edit.is_empty() {
191 return None; 195 return None;
192 } 196 }
193 197
194 Some(SourceChange::source_file_edits("rename", edit)) 198 Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit)))
195} 199}
196 200
197#[cfg(test)] 201#[cfg(test)]
@@ -342,38 +346,43 @@ mod tests {
342 let new_name = "foo2"; 346 let new_name = "foo2";
343 let source_change = analysis.rename(position, new_name).unwrap(); 347 let source_change = analysis.rename(position, new_name).unwrap();
344 assert_debug_snapshot!(&source_change, 348 assert_debug_snapshot!(&source_change,
345@r#"Some( 349@r###"
346 SourceChange { 350 Some(
347 label: "rename", 351 RangeInfo {
348 source_file_edits: [ 352 range: [4; 7),
349 SourceFileEdit { 353 info: SourceChange {
350 file_id: FileId( 354 label: "rename",
351 2, 355 source_file_edits: [
352 ), 356 SourceFileEdit {
353 edit: TextEdit { 357 file_id: FileId(
354 atoms: [ 358 2,
355 AtomTextEdit { 359 ),
356 delete: [4; 7), 360 edit: TextEdit {
357 insert: "foo2", 361 atoms: [
362 AtomTextEdit {
363 delete: [4; 7),
364 insert: "foo2",
365 },
366 ],
367 },
368 },
369 ],
370 file_system_edits: [
371 MoveFile {
372 src: FileId(
373 3,
374 ),
375 dst_source_root: SourceRootId(
376 0,
377 ),
378 dst_path: "bar/foo2.rs",
358 }, 379 },
359 ], 380 ],
381 cursor_position: None,
360 }, 382 },
361 }, 383 },
362 ], 384 )
363 file_system_edits: [ 385 "###);
364 MoveFile {
365 src: FileId(
366 3,
367 ),
368 dst_source_root: SourceRootId(
369 0,
370 ),
371 dst_path: "bar/foo2.rs",
372 },
373 ],
374 cursor_position: None,
375 },
376)"#);
377 } 386 }
378 387
379 #[test] 388 #[test]
@@ -389,38 +398,43 @@ mod tests {
389 let new_name = "foo2"; 398 let new_name = "foo2";
390 let source_change = analysis.rename(position, new_name).unwrap(); 399 let source_change = analysis.rename(position, new_name).unwrap();
391 assert_debug_snapshot!(&source_change, 400 assert_debug_snapshot!(&source_change,
392 @r###"Some( 401 @r###"
393 SourceChange { 402 Some(
394 label: "rename", 403 RangeInfo {
395 source_file_edits: [ 404 range: [4; 7),
396 SourceFileEdit { 405 info: SourceChange {
397 file_id: FileId( 406 label: "rename",
398 1, 407 source_file_edits: [
399 ), 408 SourceFileEdit {
400 edit: TextEdit { 409 file_id: FileId(
401 atoms: [ 410 1,
402 AtomTextEdit { 411 ),
403 delete: [4; 7), 412 edit: TextEdit {
404 insert: "foo2", 413 atoms: [
414 AtomTextEdit {
415 delete: [4; 7),
416 insert: "foo2",
417 },
418 ],
419 },
420 },
421 ],
422 file_system_edits: [
423 MoveFile {
424 src: FileId(
425 2,
426 ),
427 dst_source_root: SourceRootId(
428 0,
429 ),
430 dst_path: "foo2/mod.rs",
405 }, 431 },
406 ], 432 ],
433 cursor_position: None,
407 }, 434 },
408 }, 435 },
409 ], 436 )
410 file_system_edits: [ 437 "###
411 MoveFile {
412 src: FileId(
413 2,
414 ),
415 dst_source_root: SourceRootId(
416 0,
417 ),
418 dst_path: "foo2/mod.rs",
419 },
420 ],
421 cursor_position: None,
422 },
423)"###
424 ); 438 );
425 } 439 }
426 440
@@ -430,7 +444,7 @@ mod tests {
430 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default(); 444 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
431 let mut file_id: Option<FileId> = None; 445 let mut file_id: Option<FileId> = None;
432 if let Some(change) = source_change { 446 if let Some(change) = source_change {
433 for edit in change.source_file_edits { 447 for edit in change.info.source_file_edits {
434 file_id = Some(edit.file_id); 448 file_id = Some(edit.file_id);
435 for atom in edit.edit.as_atoms() { 449 for atom in edit.edit.as_atoms() {
436 text_edit_builder.replace(atom.delete, atom.insert.clone()); 450 text_edit_builder.replace(atom.delete, atom.insert.clone());
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index d4afddab4..a5729c368 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -87,7 +87,7 @@ pub(crate) fn world_symbols(db: &RootDatabase, query: Query) -> Vec<FileSymbol>
87 let mut files = Vec::new(); 87 let mut files = Vec::new();
88 for &root in db.local_roots().iter() { 88 for &root in db.local_roots().iter() {
89 let sr = db.source_root(root); 89 let sr = db.source_root(root);
90 files.extend(sr.files.values().copied()) 90 files.extend(sr.walk())
91 } 91 }
92 92
93 let snap = Snap(db.snapshot()); 93 let snap = Snap(db.snapshot());
diff --git a/crates/ra_ide_api/src/syntax_tree.rs b/crates/ra_ide_api/src/syntax_tree.rs
index 914759709..e2bb120b4 100644
--- a/crates/ra_ide_api/src/syntax_tree.rs
+++ b/crates/ra_ide_api/src/syntax_tree.rs
@@ -1,357 +1,357 @@
1use crate::db::RootDatabase; 1use crate::db::RootDatabase;
2use ra_db::SourceDatabase; 2use ra_db::SourceDatabase;
3use ra_syntax::{ 3use ra_syntax::{
4 algo, AstNode, NodeOrToken, SourceFile, 4 algo, AstNode, NodeOrToken, SourceFile,
5 SyntaxKind::{RAW_STRING, STRING}, 5 SyntaxKind::{RAW_STRING, STRING},
6 SyntaxToken, TextRange, 6 SyntaxToken, TextRange,
7}; 7};
8 8
9pub use ra_db::FileId; 9pub use ra_db::FileId;
10 10
11pub(crate) fn syntax_tree( 11pub(crate) fn syntax_tree(
12 db: &RootDatabase, 12 db: &RootDatabase,
13 file_id: FileId, 13 file_id: FileId,
14 text_range: Option<TextRange>, 14 text_range: Option<TextRange>,
15) -> String { 15) -> String {
16 let parse = db.parse(file_id); 16 let parse = db.parse(file_id);
17 if let Some(text_range) = text_range { 17 if let Some(text_range) = text_range {
18 let node = match algo::find_covering_element(parse.tree().syntax(), text_range) { 18 let node = match algo::find_covering_element(parse.tree().syntax(), text_range) {
19 NodeOrToken::Node(node) => node, 19 NodeOrToken::Node(node) => node,
20 NodeOrToken::Token(token) => { 20 NodeOrToken::Token(token) => {
21 if let Some(tree) = syntax_tree_for_string(&token, text_range) { 21 if let Some(tree) = syntax_tree_for_string(&token, text_range) {
22 return tree; 22 return tree;
23 } 23 }
24 token.parent() 24 token.parent()
25 } 25 }
26 }; 26 };
27 27
28 format!("{:#?}", node) 28 format!("{:#?}", node)
29 } else { 29 } else {
30 format!("{:#?}", parse.tree().syntax()) 30 format!("{:#?}", parse.tree().syntax())
31 } 31 }
32} 32}
33 33
34/// Attempts parsing the selected contents of a string literal 34/// Attempts parsing the selected contents of a string literal
35/// as rust syntax and returns its syntax tree 35/// as rust syntax and returns its syntax tree
36fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> { 36fn syntax_tree_for_string(token: &SyntaxToken, text_range: TextRange) -> Option<String> {
37 // When the range is inside a string 37 // When the range is inside a string
38 // we'll attempt parsing it as rust syntax 38 // we'll attempt parsing it as rust syntax
39 // to provide the syntax tree of the contents of the string 39 // to provide the syntax tree of the contents of the string
40 match token.kind() { 40 match token.kind() {
41 STRING | RAW_STRING => syntax_tree_for_token(token, text_range), 41 STRING | RAW_STRING => syntax_tree_for_token(token, text_range),
42 _ => None, 42 _ => None,
43 } 43 }
44} 44}
45 45
46fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> { 46fn syntax_tree_for_token(node: &SyntaxToken, text_range: TextRange) -> Option<String> {
47 // Range of the full node 47 // Range of the full node
48 let node_range = node.text_range(); 48 let node_range = node.text_range();
49 let text = node.text().to_string(); 49 let text = node.text().to_string();
50 50
51 // We start at some point inside the node 51 // We start at some point inside the node
52 // Either we have selected the whole string 52 // Either we have selected the whole string
53 // or our selection is inside it 53 // or our selection is inside it
54 let start = text_range.start() - node_range.start(); 54 let start = text_range.start() - node_range.start();
55 55
56 // how many characters we have selected 56 // how many characters we have selected
57 let len = text_range.len().to_usize(); 57 let len = text_range.len().to_usize();
58 58
59 let node_len = node_range.len().to_usize(); 59 let node_len = node_range.len().to_usize();
60 60
61 let start = start.to_usize(); 61 let start = start.to_usize();
62 62
63 // We want to cap our length 63 // We want to cap our length
64 let len = len.min(node_len); 64 let len = len.min(node_len);
65 65
66 // Ensure our slice is inside the actual string 66 // Ensure our slice is inside the actual string
67 let end = if start + len < text.len() { start + len } else { text.len() - start }; 67 let end = if start + len < text.len() { start + len } else { text.len() - start };
68 68
69 let text = &text[start..end]; 69 let text = &text[start..end];
70 70
71 // Remove possible extra string quotes from the start 71 // Remove possible extra string quotes from the start
72 // and the end of the string 72 // and the end of the string
73 let text = text 73 let text = text
74 .trim_start_matches('r') 74 .trim_start_matches('r')
75 .trim_start_matches('#') 75 .trim_start_matches('#')
76 .trim_start_matches('"') 76 .trim_start_matches('"')
77 .trim_end_matches('#') 77 .trim_end_matches('#')
78 .trim_end_matches('"') 78 .trim_end_matches('"')
79 .trim() 79 .trim()
80 // Remove custom markers 80 // Remove custom markers
81 .replace("<|>", ""); 81 .replace("<|>", "");
82 82
83 let parsed = SourceFile::parse(&text); 83 let parsed = SourceFile::parse(&text);
84 84
85 // If the "file" parsed without errors, 85 // If the "file" parsed without errors,
86 // return its syntax 86 // return its syntax
87 if parsed.errors().is_empty() { 87 if parsed.errors().is_empty() {
88 return Some(format!("{:#?}", parsed.tree().syntax())); 88 return Some(format!("{:#?}", parsed.tree().syntax()));
89 } 89 }
90 90
91 None 91 None
92} 92}
93 93
94#[cfg(test)] 94#[cfg(test)]
95mod tests { 95mod tests {
96 use test_utils::assert_eq_text; 96 use test_utils::assert_eq_text;
97 97
98 use crate::mock_analysis::{single_file, single_file_with_range}; 98 use crate::mock_analysis::{single_file, single_file_with_range};
99 99
100 #[test] 100 #[test]
101 fn test_syntax_tree_without_range() { 101 fn test_syntax_tree_without_range() {
102 // Basic syntax 102 // Basic syntax
103 let (analysis, file_id) = single_file(r#"fn foo() {}"#); 103 let (analysis, file_id) = single_file(r#"fn foo() {}"#);
104 let syn = analysis.syntax_tree(file_id, None).unwrap(); 104 let syn = analysis.syntax_tree(file_id, None).unwrap();
105 105
106 assert_eq_text!( 106 assert_eq_text!(
107 syn.trim(), 107 syn.trim(),
108 r#" 108 r#"
109SOURCE_FILE@[0; 11) 109SOURCE_FILE@[0; 11)
110 FN_DEF@[0; 11) 110 FN_DEF@[0; 11)
111 FN_KW@[0; 2) "fn" 111 FN_KW@[0; 2) "fn"
112 WHITESPACE@[2; 3) " " 112 WHITESPACE@[2; 3) " "
113 NAME@[3; 6) 113 NAME@[3; 6)
114 IDENT@[3; 6) "foo" 114 IDENT@[3; 6) "foo"
115 PARAM_LIST@[6; 8) 115 PARAM_LIST@[6; 8)
116 L_PAREN@[6; 7) "(" 116 L_PAREN@[6; 7) "("
117 R_PAREN@[7; 8) ")" 117 R_PAREN@[7; 8) ")"
118 WHITESPACE@[8; 9) " " 118 WHITESPACE@[8; 9) " "
119 BLOCK_EXPR@[9; 11) 119 BLOCK_EXPR@[9; 11)
120 BLOCK@[9; 11) 120 BLOCK@[9; 11)
121 L_CURLY@[9; 10) "{" 121 L_CURLY@[9; 10) "{"
122 R_CURLY@[10; 11) "}" 122 R_CURLY@[10; 11) "}"
123"# 123"#
124 .trim() 124 .trim()
125 ); 125 );
126 126
127 let (analysis, file_id) = single_file( 127 let (analysis, file_id) = single_file(
128 r#" 128 r#"
129fn test() { 129fn test() {
130 assert!(" 130 assert!("
131 fn foo() { 131 fn foo() {
132 } 132 }
133 ", ""); 133 ", "");
134}"# 134}"#
135 .trim(), 135 .trim(),
136 ); 136 );
137 let syn = analysis.syntax_tree(file_id, None).unwrap(); 137 let syn = analysis.syntax_tree(file_id, None).unwrap();
138 138
139 assert_eq_text!( 139 assert_eq_text!(
140 syn.trim(), 140 syn.trim(),
141 r#" 141 r#"
142SOURCE_FILE@[0; 60) 142SOURCE_FILE@[0; 60)
143 FN_DEF@[0; 60) 143 FN_DEF@[0; 60)
144 FN_KW@[0; 2) "fn" 144 FN_KW@[0; 2) "fn"
145 WHITESPACE@[2; 3) " " 145 WHITESPACE@[2; 3) " "
146 NAME@[3; 7) 146 NAME@[3; 7)
147 IDENT@[3; 7) "test" 147 IDENT@[3; 7) "test"
148 PARAM_LIST@[7; 9) 148 PARAM_LIST@[7; 9)
149 L_PAREN@[7; 8) "(" 149 L_PAREN@[7; 8) "("
150 R_PAREN@[8; 9) ")" 150 R_PAREN@[8; 9) ")"
151 WHITESPACE@[9; 10) " " 151 WHITESPACE@[9; 10) " "
152 BLOCK_EXPR@[10; 60) 152 BLOCK_EXPR@[10; 60)
153 BLOCK@[10; 60) 153 BLOCK@[10; 60)
154 L_CURLY@[10; 11) "{" 154 L_CURLY@[10; 11) "{"
155 WHITESPACE@[11; 16) "\n " 155 WHITESPACE@[11; 16) "\n "
156 EXPR_STMT@[16; 58) 156 EXPR_STMT@[16; 58)
157 MACRO_CALL@[16; 57) 157 MACRO_CALL@[16; 57)
158 PATH@[16; 22) 158 PATH@[16; 22)
159 PATH_SEGMENT@[16; 22) 159 PATH_SEGMENT@[16; 22)
160 NAME_REF@[16; 22) 160 NAME_REF@[16; 22)
161 IDENT@[16; 22) "assert" 161 IDENT@[16; 22) "assert"
162 EXCL@[22; 23) "!" 162 EXCL@[22; 23) "!"
163 TOKEN_TREE@[23; 57) 163 TOKEN_TREE@[23; 57)
164 L_PAREN@[23; 24) "(" 164 L_PAREN@[23; 24) "("
165 STRING@[24; 52) "\"\n fn foo() {\n ..." 165 STRING@[24; 52) "\"\n fn foo() {\n ..."
166 COMMA@[52; 53) "," 166 COMMA@[52; 53) ","
167 WHITESPACE@[53; 54) " " 167 WHITESPACE@[53; 54) " "
168 STRING@[54; 56) "\"\"" 168 STRING@[54; 56) "\"\""
169 R_PAREN@[56; 57) ")" 169 R_PAREN@[56; 57) ")"
170 SEMI@[57; 58) ";" 170 SEMI@[57; 58) ";"
171 WHITESPACE@[58; 59) "\n" 171 WHITESPACE@[58; 59) "\n"
172 R_CURLY@[59; 60) "}" 172 R_CURLY@[59; 60) "}"
173"# 173"#
174 .trim() 174 .trim()
175 ); 175 );
176 } 176 }
177 177
178 #[test] 178 #[test]
179 fn test_syntax_tree_with_range() { 179 fn test_syntax_tree_with_range() {
180 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim()); 180 let (analysis, range) = single_file_with_range(r#"<|>fn foo() {}<|>"#.trim());
181 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 181 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
182 182
183 assert_eq_text!( 183 assert_eq_text!(
184 syn.trim(), 184 syn.trim(),
185 r#" 185 r#"
186FN_DEF@[0; 11) 186FN_DEF@[0; 11)
187 FN_KW@[0; 2) "fn" 187 FN_KW@[0; 2) "fn"
188 WHITESPACE@[2; 3) " " 188 WHITESPACE@[2; 3) " "
189 NAME@[3; 6) 189 NAME@[3; 6)
190 IDENT@[3; 6) "foo" 190 IDENT@[3; 6) "foo"
191 PARAM_LIST@[6; 8) 191 PARAM_LIST@[6; 8)
192 L_PAREN@[6; 7) "(" 192 L_PAREN@[6; 7) "("
193 R_PAREN@[7; 8) ")" 193 R_PAREN@[7; 8) ")"
194 WHITESPACE@[8; 9) " " 194 WHITESPACE@[8; 9) " "
195 BLOCK_EXPR@[9; 11) 195 BLOCK_EXPR@[9; 11)
196 BLOCK@[9; 11) 196 BLOCK@[9; 11)
197 L_CURLY@[9; 10) "{" 197 L_CURLY@[9; 10) "{"
198 R_CURLY@[10; 11) "}" 198 R_CURLY@[10; 11) "}"
199"# 199"#
200 .trim() 200 .trim()
201 ); 201 );
202 202
203 let (analysis, range) = single_file_with_range( 203 let (analysis, range) = single_file_with_range(
204 r#"fn test() { 204 r#"fn test() {
205 <|>assert!(" 205 <|>assert!("
206 fn foo() { 206 fn foo() {
207 } 207 }
208 ", "");<|> 208 ", "");<|>
209}"# 209}"#
210 .trim(), 210 .trim(),
211 ); 211 );
212 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 212 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
213 213
214 assert_eq_text!( 214 assert_eq_text!(
215 syn.trim(), 215 syn.trim(),
216 r#" 216 r#"
217EXPR_STMT@[16; 58) 217EXPR_STMT@[16; 58)
218 MACRO_CALL@[16; 57) 218 MACRO_CALL@[16; 57)
219 PATH@[16; 22) 219 PATH@[16; 22)
220 PATH_SEGMENT@[16; 22) 220 PATH_SEGMENT@[16; 22)
221 NAME_REF@[16; 22) 221 NAME_REF@[16; 22)
222 IDENT@[16; 22) "assert" 222 IDENT@[16; 22) "assert"
223 EXCL@[22; 23) "!" 223 EXCL@[22; 23) "!"
224 TOKEN_TREE@[23; 57) 224 TOKEN_TREE@[23; 57)
225 L_PAREN@[23; 24) "(" 225 L_PAREN@[23; 24) "("
226 STRING@[24; 52) "\"\n fn foo() {\n ..." 226 STRING@[24; 52) "\"\n fn foo() {\n ..."
227 COMMA@[52; 53) "," 227 COMMA@[52; 53) ","
228 WHITESPACE@[53; 54) " " 228 WHITESPACE@[53; 54) " "
229 STRING@[54; 56) "\"\"" 229 STRING@[54; 56) "\"\""
230 R_PAREN@[56; 57) ")" 230 R_PAREN@[56; 57) ")"
231 SEMI@[57; 58) ";" 231 SEMI@[57; 58) ";"
232"# 232"#
233 .trim() 233 .trim()
234 ); 234 );
235 } 235 }
236 236
237 #[test] 237 #[test]
238 fn test_syntax_tree_inside_string() { 238 fn test_syntax_tree_inside_string() {
239 let (analysis, range) = single_file_with_range( 239 let (analysis, range) = single_file_with_range(
240 r#"fn test() { 240 r#"fn test() {
241 assert!(" 241 assert!("
242<|>fn foo() { 242<|>fn foo() {
243}<|> 243}<|>
244fn bar() { 244fn bar() {
245} 245}
246 ", ""); 246 ", "");
247}"# 247}"#
248 .trim(), 248 .trim(),
249 ); 249 );
250 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 250 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
251 assert_eq_text!( 251 assert_eq_text!(
252 syn.trim(), 252 syn.trim(),
253 r#" 253 r#"
254SOURCE_FILE@[0; 12) 254SOURCE_FILE@[0; 12)
255 FN_DEF@[0; 12) 255 FN_DEF@[0; 12)
256 FN_KW@[0; 2) "fn" 256 FN_KW@[0; 2) "fn"
257 WHITESPACE@[2; 3) " " 257 WHITESPACE@[2; 3) " "
258 NAME@[3; 6) 258 NAME@[3; 6)
259 IDENT@[3; 6) "foo" 259 IDENT@[3; 6) "foo"
260 PARAM_LIST@[6; 8) 260 PARAM_LIST@[6; 8)
261 L_PAREN@[6; 7) "(" 261 L_PAREN@[6; 7) "("
262 R_PAREN@[7; 8) ")" 262 R_PAREN@[7; 8) ")"
263 WHITESPACE@[8; 9) " " 263 WHITESPACE@[8; 9) " "
264 BLOCK_EXPR@[9; 12) 264 BLOCK_EXPR@[9; 12)
265 BLOCK@[9; 12) 265 BLOCK@[9; 12)
266 L_CURLY@[9; 10) "{" 266 L_CURLY@[9; 10) "{"
267 WHITESPACE@[10; 11) "\n" 267 WHITESPACE@[10; 11) "\n"
268 R_CURLY@[11; 12) "}" 268 R_CURLY@[11; 12) "}"
269"# 269"#
270 .trim() 270 .trim()
271 ); 271 );
272 272
273 // With a raw string 273 // With a raw string
274 let (analysis, range) = single_file_with_range( 274 let (analysis, range) = single_file_with_range(
275 r###"fn test() { 275 r###"fn test() {
276 assert!(r#" 276 assert!(r#"
277<|>fn foo() { 277<|>fn foo() {
278}<|> 278}<|>
279fn bar() { 279fn bar() {
280} 280}
281 "#, ""); 281 "#, "");
282}"### 282}"###
283 .trim(), 283 .trim(),
284 ); 284 );
285 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 285 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
286 assert_eq_text!( 286 assert_eq_text!(
287 syn.trim(), 287 syn.trim(),
288 r#" 288 r#"
289SOURCE_FILE@[0; 12) 289SOURCE_FILE@[0; 12)
290 FN_DEF@[0; 12) 290 FN_DEF@[0; 12)
291 FN_KW@[0; 2) "fn" 291 FN_KW@[0; 2) "fn"
292 WHITESPACE@[2; 3) " " 292 WHITESPACE@[2; 3) " "
293 NAME@[3; 6) 293 NAME@[3; 6)
294 IDENT@[3; 6) "foo" 294 IDENT@[3; 6) "foo"
295 PARAM_LIST@[6; 8) 295 PARAM_LIST@[6; 8)
296 L_PAREN@[6; 7) "(" 296 L_PAREN@[6; 7) "("
297 R_PAREN@[7; 8) ")" 297 R_PAREN@[7; 8) ")"
298 WHITESPACE@[8; 9) " " 298 WHITESPACE@[8; 9) " "
299 BLOCK_EXPR@[9; 12) 299 BLOCK_EXPR@[9; 12)
300 BLOCK@[9; 12) 300 BLOCK@[9; 12)
301 L_CURLY@[9; 10) "{" 301 L_CURLY@[9; 10) "{"
302 WHITESPACE@[10; 11) "\n" 302 WHITESPACE@[10; 11) "\n"
303 R_CURLY@[11; 12) "}" 303 R_CURLY@[11; 12) "}"
304"# 304"#
305 .trim() 305 .trim()
306 ); 306 );
307 307
308 // With a raw string 308 // With a raw string
309 let (analysis, range) = single_file_with_range( 309 let (analysis, range) = single_file_with_range(
310 r###"fn test() { 310 r###"fn test() {
311 assert!(r<|>#" 311 assert!(r<|>#"
312fn foo() { 312fn foo() {
313} 313}
314fn bar() { 314fn bar() {
315}"<|>#, ""); 315}"<|>#, "");
316}"### 316}"###
317 .trim(), 317 .trim(),
318 ); 318 );
319 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap(); 319 let syn = analysis.syntax_tree(range.file_id, Some(range.range)).unwrap();
320 assert_eq_text!( 320 assert_eq_text!(
321 syn.trim(), 321 syn.trim(),
322 r#" 322 r#"
323SOURCE_FILE@[0; 25) 323SOURCE_FILE@[0; 25)
324 FN_DEF@[0; 12) 324 FN_DEF@[0; 12)
325 FN_KW@[0; 2) "fn" 325 FN_KW@[0; 2) "fn"
326 WHITESPACE@[2; 3) " " 326 WHITESPACE@[2; 3) " "
327 NAME@[3; 6) 327 NAME@[3; 6)
328 IDENT@[3; 6) "foo" 328 IDENT@[3; 6) "foo"
329 PARAM_LIST@[6; 8) 329 PARAM_LIST@[6; 8)
330 L_PAREN@[6; 7) "(" 330 L_PAREN@[6; 7) "("
331 R_PAREN@[7; 8) ")" 331 R_PAREN@[7; 8) ")"
332 WHITESPACE@[8; 9) " " 332 WHITESPACE@[8; 9) " "
333 BLOCK_EXPR@[9; 12) 333 BLOCK_EXPR@[9; 12)
334 BLOCK@[9; 12) 334 BLOCK@[9; 12)
335 L_CURLY@[9; 10) "{" 335 L_CURLY@[9; 10) "{"
336 WHITESPACE@[10; 11) "\n" 336 WHITESPACE@[10; 11) "\n"
337 R_CURLY@[11; 12) "}" 337 R_CURLY@[11; 12) "}"
338 WHITESPACE@[12; 13) "\n" 338 WHITESPACE@[12; 13) "\n"
339 FN_DEF@[13; 25) 339 FN_DEF@[13; 25)
340 FN_KW@[13; 15) "fn" 340 FN_KW@[13; 15) "fn"
341 WHITESPACE@[15; 16) " " 341 WHITESPACE@[15; 16) " "
342 NAME@[16; 19) 342 NAME@[16; 19)
343 IDENT@[16; 19) "bar" 343 IDENT@[16; 19) "bar"
344 PARAM_LIST@[19; 21) 344 PARAM_LIST@[19; 21)
345 L_PAREN@[19; 20) "(" 345 L_PAREN@[19; 20) "("
346 R_PAREN@[20; 21) ")" 346 R_PAREN@[20; 21) ")"
347 WHITESPACE@[21; 22) " " 347 WHITESPACE@[21; 22) " "
348 BLOCK_EXPR@[22; 25) 348 BLOCK_EXPR@[22; 25)
349 BLOCK@[22; 25) 349 BLOCK@[22; 25)
350 L_CURLY@[22; 23) "{" 350 L_CURLY@[22; 23) "{"
351 WHITESPACE@[23; 24) "\n" 351 WHITESPACE@[23; 24) "\n"
352 R_CURLY@[24; 25) "}" 352 R_CURLY@[24; 25) "}"
353"# 353"#
354 .trim() 354 .trim()
355 ); 355 );
356 } 356 }
357} 357}
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index eb4812633..46a0f958c 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -12,11 +12,11 @@ serde = { version = "1.0.83", features = ["derive"] }
12crossbeam-channel = "0.3.5" 12crossbeam-channel = "0.3.5"
13flexi_logger = "0.14.0" 13flexi_logger = "0.14.0"
14log = "0.4.3" 14log = "0.4.3"
15lsp-types = { version = "0.60.0", features = ["proposed"] } 15lsp-types = { version = "0.61.0", features = ["proposed"] }
16rustc-hash = "1.0" 16rustc-hash = "1.0"
17parking_lot = "0.9.0" 17parking_lot = "0.9.0"
18jod-thread = "0.1.0" 18jod-thread = "0.1.0"
19ra_vfs = "0.3.0" 19ra_vfs = "0.4.0"
20ra_syntax = { path = "../ra_syntax" } 20ra_syntax = { path = "../ra_syntax" }
21ra_text_edit = { path = "../ra_text_edit" } 21ra_text_edit = { path = "../ra_text_edit" }
22ra_ide_api = { path = "../ra_ide_api" } 22ra_ide_api = { path = "../ra_ide_api" }
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index bb9205aed..22fc97a97 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -43,6 +43,7 @@ pub fn server_capabilities() -> ServerCapabilities {
43 rename_provider: Some(RenameProviderCapability::Options(RenameOptions { 43 rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
44 prepare_provider: Some(true), 44 prepare_provider: Some(true),
45 })), 45 })),
46 document_link_provider: None,
46 color_provider: None, 47 color_provider: None,
47 execute_command_provider: None, 48 execute_command_provider: None,
48 workspace: None, 49 workspace: None,
diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs
index 5c5ae3e18..cf53e7c4c 100644
--- a/crates/ra_lsp_server/src/config.rs
+++ b/crates/ra_lsp_server/src/config.rs
@@ -15,6 +15,8 @@ pub struct ServerConfig {
15 pub publish_decorations: bool, 15 pub publish_decorations: bool,
16 16
17 pub exclude_globs: Vec<String>, 17 pub exclude_globs: Vec<String>,
18 #[serde(deserialize_with = "nullable_bool_false")]
19 pub use_client_watching: bool,
18 20
19 pub lru_capacity: Option<usize>, 21 pub lru_capacity: Option<usize>,
20 22
@@ -31,6 +33,7 @@ impl Default for ServerConfig {
31 ServerConfig { 33 ServerConfig {
32 publish_decorations: false, 34 publish_decorations: false,
33 exclude_globs: Vec::new(), 35 exclude_globs: Vec::new(),
36 use_client_watching: false,
34 lru_capacity: None, 37 lru_capacity: None,
35 with_sysroot: true, 38 with_sysroot: true,
36 feature_flags: FxHashMap::default(), 39 feature_flags: FxHashMap::default(),
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 80f0216e8..25fa51b8a 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -9,8 +9,9 @@ use lsp_server::{Connection, ErrorCode, Message, Notification, Request, RequestI
9use lsp_types::{ClientCapabilities, NumberOrString}; 9use lsp_types::{ClientCapabilities, NumberOrString};
10use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId}; 10use ra_ide_api::{Canceled, FeatureFlags, FileId, LibraryData, SourceRootId};
11use ra_prof::profile; 11use ra_prof::profile;
12use ra_vfs::VfsTask; 12use ra_vfs::{VfsTask, Watch};
13use relative_path::RelativePathBuf; 13use relative_path::RelativePathBuf;
14use rustc_hash::FxHashSet;
14use serde::{de::DeserializeOwned, Serialize}; 15use serde::{de::DeserializeOwned, Serialize};
15use threadpool::ThreadPool; 16use threadpool::ThreadPool;
16 17
@@ -55,72 +56,96 @@ pub fn main_loop(
55) -> Result<()> { 56) -> Result<()> {
56 log::info!("server_config: {:#?}", config); 57 log::info!("server_config: {:#?}", config);
57 58
58 // FIXME: support dynamic workspace loading. 59 let mut loop_state = LoopState::default();
59 let workspaces = { 60 let mut world_state = {
60 let mut loaded_workspaces = Vec::new(); 61 // FIXME: support dynamic workspace loading.
61 for ws_root in &ws_roots { 62 let workspaces = {
62 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( 63 let mut loaded_workspaces = Vec::new();
63 ws_root.as_path(), 64 for ws_root in &ws_roots {
64 config.with_sysroot, 65 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
65 ); 66 ws_root.as_path(),
66 match workspace { 67 config.with_sysroot,
67 Ok(workspace) => loaded_workspaces.push(workspace), 68 );
68 Err(e) => { 69 match workspace {
69 log::error!("loading workspace failed: {}", e); 70 Ok(workspace) => loaded_workspaces.push(workspace),
71 Err(e) => {
72 log::error!("loading workspace failed: {}", e);
73
74 show_message(
75 req::MessageType::Error,
76 format!("rust-analyzer failed to load workspace: {}", e),
77 &connection.sender,
78 );
79 }
80 }
81 }
82 loaded_workspaces
83 };
70 84
85 let globs = config
86 .exclude_globs
87 .iter()
88 .map(|glob| ra_vfs_glob::Glob::new(glob))
89 .collect::<std::result::Result<Vec<_>, _>>()?;
90
91 if config.use_client_watching {
92 let registration_options = req::DidChangeWatchedFilesRegistrationOptions {
93 watchers: workspaces
94 .iter()
95 .flat_map(|ws| ws.to_roots())
96 .filter(|root| root.is_member())
97 .map(|root| format!("{}/**/*.rs", root.path().display()))
98 .map(|glob_pattern| req::FileSystemWatcher { glob_pattern, kind: None })
99 .collect(),
100 };
101 let registration = req::Registration {
102 id: "file-watcher".to_string(),
103 method: "workspace/didChangeWatchedFiles".to_string(),
104 register_options: Some(serde_json::to_value(registration_options).unwrap()),
105 };
106 let params = req::RegistrationParams { registrations: vec![registration] };
107 let request =
108 request_new::<req::RegisterCapability>(loop_state.next_request_id(), params);
109 connection.sender.send(request.into()).unwrap();
110 }
111
112 let feature_flags = {
113 let mut ff = FeatureFlags::default();
114 for (flag, value) in config.feature_flags {
115 if let Err(_) = ff.set(flag.as_str(), value) {
116 log::error!("unknown feature flag: {:?}", flag);
71 show_message( 117 show_message(
72 req::MessageType::Error, 118 req::MessageType::Error,
73 format!("rust-analyzer failed to load workspace: {}", e), 119 format!("unknown feature flag: {:?}", flag),
74 &connection.sender, 120 &connection.sender,
75 ); 121 );
76 } 122 }
77 } 123 }
78 } 124 ff
79 loaded_workspaces 125 };
80 }; 126 log::info!("feature_flags: {:#?}", feature_flags);
81 127
82 let globs = config 128 WorldState::new(
83 .exclude_globs 129 ws_roots,
84 .iter() 130 workspaces,
85 .map(|glob| ra_vfs_glob::Glob::new(glob)) 131 config.lru_capacity,
86 .collect::<std::result::Result<Vec<_>, _>>()?; 132 &globs,
87 133 Watch(!config.use_client_watching),
88 let feature_flags = { 134 Options {
89 let mut ff = FeatureFlags::default(); 135 publish_decorations: config.publish_decorations,
90 for (flag, value) in config.feature_flags { 136 supports_location_link: client_caps
91 if let Err(_) = ff.set(flag.as_str(), value) { 137 .text_document
92 log::error!("unknown feature flag: {:?}", flag); 138 .and_then(|it| it.definition)
93 show_message( 139 .and_then(|it| it.link_support)
94 req::MessageType::Error, 140 .unwrap_or(false),
95 format!("unknown feature flag: {:?}", flag), 141 },
96 &connection.sender, 142 feature_flags,
97 ); 143 )
98 }
99 }
100 ff
101 }; 144 };
102 log::info!("feature_flags: {:#?}", feature_flags);
103
104 let mut world_state = WorldState::new(
105 ws_roots,
106 workspaces,
107 config.lru_capacity,
108 &globs,
109 Options {
110 publish_decorations: config.publish_decorations,
111 supports_location_link: client_caps
112 .text_document
113 .and_then(|it| it.definition)
114 .and_then(|it| it.link_support)
115 .unwrap_or(false),
116 },
117 feature_flags,
118 );
119 145
120 let pool = ThreadPool::new(THREADPOOL_SIZE); 146 let pool = ThreadPool::new(THREADPOOL_SIZE);
121 let (task_sender, task_receiver) = unbounded::<Task>(); 147 let (task_sender, task_receiver) = unbounded::<Task>();
122 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>(); 148 let (libdata_sender, libdata_receiver) = unbounded::<LibraryData>();
123 let mut loop_state = LoopState::default();
124 149
125 log::info!("server initialized, serving requests"); 150 log::info!("server initialized, serving requests");
126 { 151 {
@@ -227,6 +252,8 @@ impl fmt::Debug for Event {
227 252
228#[derive(Debug, Default)] 253#[derive(Debug, Default)]
229struct LoopState { 254struct LoopState {
255 next_request_id: u64,
256 pending_responses: FxHashSet<RequestId>,
230 pending_requests: PendingRequests, 257 pending_requests: PendingRequests,
231 subscriptions: Subscriptions, 258 subscriptions: Subscriptions,
232 // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same 259 // We try not to index more than MAX_IN_FLIGHT_LIBS libraries at the same
@@ -236,6 +263,16 @@ struct LoopState {
236 workspace_loaded: bool, 263 workspace_loaded: bool,
237} 264}
238 265
266impl LoopState {
267 fn next_request_id(&mut self) -> RequestId {
268 self.next_request_id += 1;
269 let res: RequestId = self.next_request_id.into();
270 let inserted = self.pending_responses.insert(res.clone());
271 assert!(inserted);
272 res
273 }
274}
275
239fn loop_turn( 276fn loop_turn(
240 pool: &ThreadPool, 277 pool: &ThreadPool,
241 task_sender: &Sender<Task>, 278 task_sender: &Sender<Task>,
@@ -290,7 +327,12 @@ fn loop_turn(
290 )?; 327 )?;
291 state_changed = true; 328 state_changed = true;
292 } 329 }
293 Message::Response(resp) => log::error!("unexpected response: {:?}", resp), 330 Message::Response(resp) => {
331 let removed = loop_state.pending_responses.remove(&resp.id);
332 if !removed {
333 log::error!("unexpected response: {:?}", resp)
334 }
335 }
294 }, 336 },
295 }; 337 };
296 338
@@ -479,6 +521,18 @@ fn on_notification(
479 } 521 }
480 Err(not) => not, 522 Err(not) => not,
481 }; 523 };
524 let not = match notification_cast::<req::DidChangeWatchedFiles>(not) {
525 Ok(params) => {
526 let mut vfs = state.vfs.write();
527 for change in params.changes {
528 let uri = change.uri;
529 let path = uri.to_file_path().map_err(|()| format!("invalid uri: {}", uri))?;
530 vfs.notify_changed(path)
531 }
532 return Ok(());
533 }
534 Err(not) => not,
535 };
482 log::error!("unhandled notification: {:?}", not); 536 log::error!("unhandled notification: {:?}", not);
483 Ok(()) 537 Ok(())
484} 538}
@@ -682,3 +736,11 @@ where
682{ 736{
683 Notification::new(N::METHOD.to_string(), params) 737 Notification::new(N::METHOD.to_string(), params)
684} 738}
739
740fn request_new<R>(id: RequestId, params: R::Params) -> Request
741where
742 R: lsp_types::request::Request,
743 R::Params: Serialize,
744{
745 Request::new(id, R::METHOD.to_string(), params)
746}
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index eb805a6d3..948d543ea 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -460,18 +460,16 @@ pub fn handle_prepare_rename(
460 460
461 // We support renaming references like handle_rename does. 461 // We support renaming references like handle_rename does.
462 // In the future we may want to reject the renaming of things like keywords here too. 462 // In the future we may want to reject the renaming of things like keywords here too.
463 let refs = match world.analysis().find_all_refs(position)? { 463 let optional_change = world.analysis().rename(position, "dummy")?;
464 let range = match optional_change {
464 None => return Ok(None), 465 None => return Ok(None),
465 Some(refs) => refs, 466 Some(it) => it.range,
466 }; 467 };
467 468
468 // Refs should always have a declaration
469 let r = refs.declaration();
470 let file_id = params.text_document.try_conv_with(&world)?; 469 let file_id = params.text_document.try_conv_with(&world)?;
471 let line_index = world.analysis().file_line_index(file_id)?; 470 let line_index = world.analysis().file_line_index(file_id)?;
472 let loc = to_location(r.file_id(), r.range(), &world, &line_index)?; 471 let range = range.conv_with(&line_index);
473 472 Ok(Some(PrepareRenameResponse::Range(range)))
474 Ok(Some(PrepareRenameResponse::Range(loc.range)))
475} 473}
476 474
477pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> { 475pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Option<WorkspaceEdit>> {
@@ -488,7 +486,7 @@ pub fn handle_rename(world: WorldSnapshot, params: RenameParams) -> Result<Optio
488 let optional_change = world.analysis().rename(position, &*params.new_name)?; 486 let optional_change = world.analysis().rename(position, &*params.new_name)?;
489 let change = match optional_change { 487 let change = match optional_change {
490 None => return Ok(None), 488 None => return Ok(None),
491 Some(it) => it, 489 Some(it) => it.info,
492 }; 490 };
493 491
494 let source_change_req = change.try_conv_with(&world)?; 492 let source_change_req = change.try_conv_with(&world)?;
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 1b23f0c3d..0540f166e 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -5,10 +5,11 @@ use serde::{Deserialize, Serialize};
5pub use lsp_types::{ 5pub use lsp_types::{
6 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens, 6 notification::*, request::*, ApplyWorkspaceEditParams, CodeActionParams, CodeLens,
7 CodeLensParams, CompletionParams, CompletionResponse, DidChangeConfigurationParams, 7 CodeLensParams, CompletionParams, CompletionResponse, DidChangeConfigurationParams,
8 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, Hover, 8 DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions,
9 InitializeResult, MessageType, PublishDiagnosticsParams, ReferenceParams, ShowMessageParams, 9 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
10 SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, 10 FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams,
11 WorkspaceSymbolParams, 11 ReferenceParams, Registration, RegistrationParams, ShowMessageParams, SignatureHelp,
12 TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams,
12}; 13};
13 14
14pub enum AnalyzerStatus {} 15pub enum AnalyzerStatus {}
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index e1c5c3343..086ecd587 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -12,7 +12,7 @@ use ra_ide_api::{
12 SourceRootId, 12 SourceRootId,
13}; 13};
14use ra_project_model::ProjectWorkspace; 14use ra_project_model::ProjectWorkspace;
15use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask}; 15use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
16use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 16use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
17use relative_path::RelativePathBuf; 17use relative_path::RelativePathBuf;
18 18
@@ -60,6 +60,7 @@ impl WorldState {
60 workspaces: Vec<ProjectWorkspace>, 60 workspaces: Vec<ProjectWorkspace>,
61 lru_capacity: Option<usize>, 61 lru_capacity: Option<usize>,
62 exclude_globs: &[Glob], 62 exclude_globs: &[Glob],
63 watch: Watch,
63 options: Options, 64 options: Options,
64 feature_flags: FeatureFlags, 65 feature_flags: FeatureFlags,
65 ) -> WorldState { 66 ) -> WorldState {
@@ -85,7 +86,7 @@ impl WorldState {
85 } 86 }
86 let (task_sender, task_receiver) = unbounded(); 87 let (task_sender, task_receiver) = unbounded();
87 let task_sender = Box::new(move |t| task_sender.send(t).unwrap()); 88 let task_sender = Box::new(move |t| task_sender.send(t).unwrap());
88 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender); 89 let (mut vfs, vfs_roots) = Vfs::new(roots, task_sender, watch);
89 let roots_to_scan = vfs_roots.len(); 90 let roots_to_scan = vfs_roots.len();
90 for r in vfs_roots { 91 for r in vfs_roots {
91 let vfs_root_path = vfs.root2path(r); 92 let vfs_root_path = vfs.root2path(r);
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 6d426206e..b4327b78f 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -31,7 +31,7 @@ pub(super) enum ItemFlavor {
31 31
32pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ 32pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
33 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, 33 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
34 CRATE_KW 34 CRATE_KW, USE_KW
35]; 35];
36 36
37pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { 37pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
diff --git a/crates/ra_parser/src/grammar/items/use_item.rs b/crates/ra_parser/src/grammar/items/use_item.rs
index c0c7d0ec6..83a65e226 100644
--- a/crates/ra_parser/src/grammar/items/use_item.rs
+++ b/crates/ra_parser/src/grammar/items/use_item.rs
@@ -101,7 +101,10 @@ fn use_tree(p: &mut Parser) {
101 } 101 }
102 _ => { 102 _ => {
103 m.abandon(p); 103 m.abandon(p);
104 p.err_and_bump("expected one of `*`, `::`, `{`, `self`, `super` or an indentifier"); 104 p.err_recover(
105 "expected one of `*`, `::`, `{`, `self`, `super` or an identifier",
106 ITEM_RECOVERY_SET,
107 );
105 return; 108 return;
106 } 109 }
107 } 110 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 676dc4941..9b2f534e7 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -153,7 +153,7 @@ impl ProjectWorkspace {
153 if let Some(file_id) = load(krate.root(&sysroot)) { 153 if let Some(file_id) = load(krate.root(&sysroot)) {
154 sysroot_crates.insert( 154 sysroot_crates.insert(
155 krate, 155 krate,
156 crate_graph.add_crate_root(file_id, Edition::Edition2015), 156 crate_graph.add_crate_root(file_id, Edition::Edition2018),
157 ); 157 );
158 } 158 }
159 } 159 }
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 0ead277b2..d3a8b516a 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -10,7 +10,7 @@ repository = "https://github.com/rust-analyzer/rust-analyzer"
10[dependencies] 10[dependencies]
11itertools = "0.8.0" 11itertools = "0.8.0"
12rowan = "0.6.1" 12rowan = "0.6.1"
13ra_rustc_lexer = { version = "0.1.0-pre.3", features = ["unicode-xid"] } 13rustc_lexer = "0.1.0"
14 14
15# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 15# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
16# to reduce number of compilations 16# to reduce number of compilations
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index e2a92ae60..bcf753f78 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -934,6 +934,7 @@ impl AstNode for ExternCrateItem {
934 &self.syntax 934 &self.syntax
935 } 935 }
936} 936}
937impl ast::AttrsOwner for ExternCrateItem {}
937impl ExternCrateItem { 938impl ExternCrateItem {
938 pub fn name_ref(&self) -> Option<NameRef> { 939 pub fn name_ref(&self) -> Option<NameRef> {
939 AstChildren::new(&self.syntax).next() 940 AstChildren::new(&self.syntax).next()
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index c14ee0e85..3e6c2d3f3 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -669,6 +669,7 @@ Grammar(
669 collections: [("use_trees", "UseTree")] 669 collections: [("use_trees", "UseTree")]
670 ), 670 ),
671 "ExternCrateItem": ( 671 "ExternCrateItem": (
672 traits: ["AttrsOwner"],
672 options: ["NameRef", "Alias"], 673 options: ["NameRef", "Alias"],
673 ), 674 ),
674 "ArgList": ( 675 "ArgList": (
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index 80e55d2aa..992034ef0 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -15,8 +15,9 @@ impl SyntaxNodePtr {
15 SyntaxNodePtr { range: node.text_range(), kind: node.kind() } 15 SyntaxNodePtr { range: node.text_range(), kind: node.kind() }
16 } 16 }
17 17
18 pub fn to_node(self, parent: &SyntaxNode) -> SyntaxNode { 18 pub fn to_node(self, root: &SyntaxNode) -> SyntaxNode {
19 successors(Some(parent.clone()), |node| { 19 assert!(root.parent().is_none());
20 successors(Some(root.clone()), |node| {
20 node.children().find(|it| self.range.is_subrange(&it.text_range())) 21 node.children().find(|it| self.range.is_subrange(&it.text_range()))
21 }) 22 })
22 .find(|it| it.text_range() == self.range && it.kind() == self.kind) 23 .find(|it| it.text_range() == self.range && it.kind() == self.kind)
diff --git a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
index 84867026f..bdb5fa6c5 100644
--- a/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
+++ b/crates/ra_syntax/test_data/parser/err/0002_duplicate_shebang.txt
@@ -28,7 +28,7 @@ SOURCE_FILE@[0; 42)
28 WHITESPACE@[41; 42) "\n" 28 WHITESPACE@[41; 42) "\n"
29error 23: expected `[` 29error 23: expected `[`
30error 23: expected an item 30error 23: expected an item
31error 27: expected one of `*`, `::`, `{`, `self`, `super` or an indentifier 31error 27: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
32error 28: expected SEMI 32error 28: expected SEMI
33error 31: expected EXCL 33error 31: expected EXCL
34error 31: expected `{`, `[`, `(` 34error 31: expected `{`, `[`, `(`
diff --git a/crates/ra_syntax/test_data/parser/err/0035_use_recover.rs b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rs
new file mode 100644
index 000000000..4a2668126
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0035_use_recover.rs
@@ -0,0 +1,5 @@
1use foo::bar;
2use
3use crate::baz;
4use
5fn f() {}
diff --git a/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt b/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt
new file mode 100644
index 000000000..636840828
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0035_use_recover.txt
@@ -0,0 +1,54 @@
1SOURCE_FILE@[0; 48)
2 USE_ITEM@[0; 13)
3 USE_KW@[0; 3) "use"
4 WHITESPACE@[3; 4) " "
5 USE_TREE@[4; 12)
6 PATH@[4; 12)
7 PATH@[4; 7)
8 PATH_SEGMENT@[4; 7)
9 NAME_REF@[4; 7)
10 IDENT@[4; 7) "foo"
11 COLONCOLON@[7; 9) "::"
12 PATH_SEGMENT@[9; 12)
13 NAME_REF@[9; 12)
14 IDENT@[9; 12) "bar"
15 SEMI@[12; 13) ";"
16 WHITESPACE@[13; 14) "\n"
17 USE_ITEM@[14; 17)
18 USE_KW@[14; 17) "use"
19 WHITESPACE@[17; 18) "\n"
20 USE_ITEM@[18; 33)
21 USE_KW@[18; 21) "use"
22 WHITESPACE@[21; 22) " "
23 USE_TREE@[22; 32)
24 PATH@[22; 32)
25 PATH@[22; 27)
26 PATH_SEGMENT@[22; 27)
27 CRATE_KW@[22; 27) "crate"
28 COLONCOLON@[27; 29) "::"
29 PATH_SEGMENT@[29; 32)
30 NAME_REF@[29; 32)
31 IDENT@[29; 32) "baz"
32 SEMI@[32; 33) ";"
33 WHITESPACE@[33; 34) "\n"
34 USE_ITEM@[34; 37)
35 USE_KW@[34; 37) "use"
36 WHITESPACE@[37; 38) "\n"
37 FN_DEF@[38; 47)
38 FN_KW@[38; 40) "fn"
39 WHITESPACE@[40; 41) " "
40 NAME@[41; 42)
41 IDENT@[41; 42) "f"
42 PARAM_LIST@[42; 44)
43 L_PAREN@[42; 43) "("
44 R_PAREN@[43; 44) ")"
45 WHITESPACE@[44; 45) " "
46 BLOCK_EXPR@[45; 47)
47 BLOCK@[45; 47)
48 L_CURLY@[45; 46) "{"
49 R_CURLY@[46; 47) "}"
50 WHITESPACE@[47; 48) "\n"
51error 17: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
52error 17: expected SEMI
53error 37: expected one of `*`, `::`, `{`, `self`, `super` or an identifier
54error 37: expected SEMI
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml
index 09ba3d3bf..d1073b2be 100644
--- a/crates/ra_vfs_glob/Cargo.toml
+++ b/crates/ra_vfs_glob/Cargo.toml
@@ -5,5 +5,5 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8ra_vfs = "0.3.0" 8ra_vfs = "0.4.0"
9globset = "0.4.4" 9globset = "0.4.4"
diff --git a/docs/user/README.md b/docs/user/README.md
index 00212a76f..c11e0fcb6 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -74,6 +74,8 @@ See https://github.com/microsoft/vscode/issues/72308[microsoft/vscode#72308] for
74* `rust-analyzer.excludeGlobs`: a list of glob-patterns for exclusion (see globset [docs](https://docs.rs/globset) for syntax). 74* `rust-analyzer.excludeGlobs`: a list of glob-patterns for exclusion (see globset [docs](https://docs.rs/globset) for syntax).
75 Note: glob patterns are applied to all Cargo packages and a rooted at a package root. 75 Note: glob patterns are applied to all Cargo packages and a rooted at a package root.
76 This is not very intuitive and a limitation of a current implementation. 76 This is not very intuitive and a limitation of a current implementation.
77* `rust-analyzer.useClientWatching`: use client provided file watching instead
78 of notify watching.
77* `rust-analyzer.cargo-watch.check-arguments`: cargo-watch check arguments. 79* `rust-analyzer.cargo-watch.check-arguments`: cargo-watch check arguments.
78 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` ) 80 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` )
79* `rust-analyzer.trace.server`: enables internal logging 81* `rust-analyzer.trace.server`: enables internal logging
diff --git a/docs/user/features.md b/docs/user/features.md
index b6e6008c4..1034a5117 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -435,6 +435,16 @@ fn f() {
435} 435}
436``` 436```
437 437
438- Move type bounds to where clause
439
440```rust
441// before:
442fn foo<T: u32, F: FnOnce(T) -> T>() {}
443
444// after:
445fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
446```
447
438### Magic Completions 448### Magic Completions
439 449
440In addition to usual reference completion, rust-analyzer provides some ✨magic✨ 450In addition to usual reference completion, rust-analyzer provides some ✨magic✨
diff --git a/editors/code/package.json b/editors/code/package.json
index e2bc72f32..7a48d6794 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -205,6 +205,11 @@
205 "default": [], 205 "default": [],
206 "description": "Paths to exclude from analysis" 206 "description": "Paths to exclude from analysis"
207 }, 207 },
208 "rust-analyzer.useClientWatching": {
209 "type": "boolean",
210 "default": false,
211 "description": "client provided file watching instead of notify watching."
212 },
208 "rust-analyzer.cargo-watch.arguments": { 213 "rust-analyzer.cargo-watch.arguments": {
209 "type": "string", 214 "type": "string",
210 "description": "`cargo-watch` arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo watch -x \"check --features=\"shumway,pdf\"\"` )", 215 "description": "`cargo-watch` arguments. (e.g: `--features=\"shumway,pdf\"` will run as `cargo watch -x \"check --features=\"shumway,pdf\"\"` )",
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 570ddca46..a4581485c 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -23,6 +23,7 @@ export class Config {
23 public lruCapacity: null | number = null; 23 public lruCapacity: null | number = null;
24 public displayInlayHints = true; 24 public displayInlayHints = true;
25 public excludeGlobs = []; 25 public excludeGlobs = [];
26 public useClientWatching = false;
26 public featureFlags = {}; 27 public featureFlags = {};
27 public cargoWatchOptions: CargoWatchOptions = { 28 public cargoWatchOptions: CargoWatchOptions = {
28 enableOnStartup: 'ask', 29 enableOnStartup: 'ask',
@@ -133,6 +134,9 @@ export class Config {
133 if (config.has('excludeGlobs')) { 134 if (config.has('excludeGlobs')) {
134 this.excludeGlobs = config.get('excludeGlobs') || []; 135 this.excludeGlobs = config.get('excludeGlobs') || [];
135 } 136 }
137 if (config.has('useClientWatching')) {
138 this.useClientWatching = config.get('useClientWatching') || false;
139 }
136 if (config.has('featureFlags')) { 140 if (config.has('featureFlags')) {
137 this.featureFlags = config.get('featureFlags') || {}; 141 this.featureFlags = config.get('featureFlags') || {};
138 } 142 }
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts
index 0d2a99c70..ff50fcd99 100644
--- a/editors/code/src/server.ts
+++ b/editors/code/src/server.ts
@@ -46,6 +46,7 @@ export class Server {
46 Server.config.showWorkspaceLoadedNotification, 46 Server.config.showWorkspaceLoadedNotification,
47 lruCapacity: Server.config.lruCapacity, 47 lruCapacity: Server.config.lruCapacity,
48 excludeGlobs: Server.config.excludeGlobs, 48 excludeGlobs: Server.config.excludeGlobs,
49 useClientWatching: Server.config.useClientWatching,
49 featureFlags: Server.config.featureFlags 50 featureFlags: Server.config.featureFlags
50 }, 51 },
51 traceOutputChannel 52 traceOutputChannel
diff --git a/rustfmt.toml b/rustfmt.toml
index 71007de81..f2e164618 100644
--- a/rustfmt.toml
+++ b/rustfmt.toml
@@ -1,2 +1,3 @@
1reorder_modules = false 1reorder_modules = false
2use_small_heuristics = "Max" 2use_small_heuristics = "Max"
3newline_style = "Unix"