aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.cargo/config25
-rw-r--r--.travis.yml6
-rw-r--r--Cargo.lock395
-rw-r--r--Cargo.toml5
-rw-r--r--README.md6
-rw-r--r--crates/ra_assists/Cargo.toml4
-rw-r--r--crates/ra_assists/src/assist_ctx.rs1
-rw-r--r--crates/ra_assists/src/assists/early_return.rs276
-rw-r--r--crates/ra_assists/src/assists/fill_match_arms.rs18
-rw-r--r--crates/ra_assists/src/assists/move_bounds.rs2
-rw-r--r--crates/ra_assists/src/assists/raw_string.rs110
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_batch/Cargo.toml2
-rw-r--r--crates/ra_batch/src/lib.rs18
-rw-r--r--crates/ra_cfg/src/lib.rs24
-rw-r--r--crates/ra_cli/Cargo.toml2
-rw-r--r--crates/ra_cli/src/analysis_bench.rs2
-rw-r--r--crates/ra_cli/src/analysis_stats.rs33
-rw-r--r--crates/ra_db/Cargo.toml2
-rw-r--r--crates/ra_db/src/input.rs6
-rw-r--r--crates/ra_db/src/lib.rs76
-rw-r--r--crates/ra_hir/Cargo.toml4
-rw-r--r--crates/ra_hir/src/adt.rs12
-rw-r--r--crates/ra_hir/src/attr.rs24
-rw-r--r--crates/ra_hir/src/code_model.rs44
-rw-r--r--crates/ra_hir/src/code_model/docs.rs20
-rw-r--r--crates/ra_hir/src/db.rs18
-rw-r--r--crates/ra_hir/src/debug.rs20
-rw-r--r--crates/ra_hir/src/from_source.rs10
-rw-r--r--crates/ra_hir/src/ids.rs45
-rw-r--r--crates/ra_hir/src/impl_block.rs35
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/mock.rs42
-rw-r--r--crates/ra_hir/src/nameres/collector.rs77
-rw-r--r--crates/ra_hir/src/nameres/mod_resolution.rs228
-rw-r--r--crates/ra_hir/src/nameres/raw.rs53
-rw-r--r--crates/ra_hir/src/nameres/tests.rs13
-rw-r--r--crates/ra_hir/src/nameres/tests/incremental.rs2
-rw-r--r--crates/ra_hir/src/nameres/tests/macros.rs29
-rw-r--r--crates/ra_hir/src/nameres/tests/mod_resolution.rs214
-rw-r--r--crates/ra_hir/src/resolve.rs32
-rw-r--r--crates/ra_hir/src/source_binder.rs2
-rw-r--r--crates/ra_hir/src/ty.rs24
-rw-r--r--crates/ra_hir/src/ty/infer.rs1164
-rw-r--r--crates/ra_hir/src/ty/infer/coerce.rs336
-rw-r--r--crates/ra_hir/src/ty/infer/expr.rs658
-rw-r--r--crates/ra_hir/src/ty/infer/pat.rs180
-rw-r--r--crates/ra_hir/src/ty/infer/unify.rs23
-rw-r--r--crates/ra_hir/src/ty/lower.rs39
-rw-r--r--crates/ra_hir/src/ty/tests.rs22
-rw-r--r--crates/ra_hir/src/ty/traits.rs2
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs61
-rw-r--r--crates/ra_hir/src/type_alias.rs18
-rw-r--r--crates/ra_hir/src/util.rs12
-rw-r--r--crates/ra_ide_api/Cargo.toml3
-rw-r--r--crates/ra_ide_api/src/change.rs2
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs185
-rw-r--r--crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs62
-rw-r--r--crates/ra_ide_api/src/completion/complete_path.rs166
-rw-r--r--crates/ra_ide_api/src/completion/complete_postfix.rs67
-rw-r--r--crates/ra_ide_api/src/completion/complete_scope.rs679
-rw-r--r--crates/ra_ide_api/src/completion/completion_context.rs19
-rw-r--r--crates/ra_ide_api/src/completion/completion_item.rs4
-rw-r--r--crates/ra_ide_api/src/completion/presentation.rs389
-rw-r--r--crates/ra_ide_api/src/db.rs25
-rw-r--r--crates/ra_ide_api/src/diagnostics.rs13
-rw-r--r--crates/ra_ide_api/src/display/navigation_target.rs6
-rw-r--r--crates/ra_ide_api/src/extend_selection.rs3
-rw-r--r--crates/ra_ide_api/src/goto_definition.rs12
-rw-r--r--crates/ra_ide_api/src/hover.rs11
-rw-r--r--crates/ra_ide_api/src/lib.rs14
-rw-r--r--crates/ra_ide_api/src/marks.rs1
-rw-r--r--crates/ra_ide_api/src/name_ref_kind.rs98
-rw-r--r--crates/ra_ide_api/src/references.rs524
-rw-r--r--crates/ra_ide_api/src/references/classify.rs179
-rw-r--r--crates/ra_ide_api/src/references/name_definition.rs113
-rw-r--r--crates/ra_ide_api/src/references/rename.rs469
-rw-r--r--crates/ra_ide_api/src/references/search_scope.rs92
-rw-r--r--crates/ra_ide_api/src/snapshots/highlighting.html2
-rw-r--r--crates/ra_ide_api/src/symbol_index.rs2
-rw-r--r--crates/ra_ide_api/src/syntax_highlighting.rs17
-rw-r--r--crates/ra_lsp_server/Cargo.toml6
-rw-r--r--crates/ra_lsp_server/src/conv.rs106
-rw-r--r--crates/ra_lsp_server/src/lib.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs24
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs22
-rw-r--r--crates/ra_lsp_server/src/world.rs9
-rw-r--r--crates/ra_mbe/Cargo.toml1
-rw-r--r--crates/ra_parser/src/grammar/expressions.rs11
-rw-r--r--crates/ra_project_model/Cargo.toml2
-rw-r--r--crates/ra_project_model/src/lib.rs44
-rw-r--r--crates/ra_syntax/Cargo.toml3
-rw-r--r--crates/ra_syntax/src/ast/edit.rs119
-rw-r--r--crates/ra_syntax/src/ast/make.rs14
-rw-r--r--crates/ra_syntax/src/grammar.ron2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt43
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs7
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt97
-rw-r--r--crates/ra_tt/Cargo.toml4
-rw-r--r--crates/ra_vfs_glob/Cargo.toml2
-rw-r--r--docs/dev/README.md12
-rw-r--r--docs/dev/architecture.md16
-rw-r--r--docs/user/README.md26
-rw-r--r--docs/user/features.md7
-rw-r--r--editors/code/package-lock.json46
-rw-r--r--editors/code/package.json16
-rw-r--r--editors/code/src/commands/cargo_watch.ts7
-rw-r--r--editors/code/src/config.ts11
-rw-r--r--website/src/index.html21
-rw-r--r--website/src/wasm-demo/index.html13
-rw-r--r--website/website-gen/Cargo.toml9
-rw-r--r--website/website-gen/src/main.rs64
-rw-r--r--xtask/Cargo.toml (renamed from crates/ra_tools/Cargo.toml)2
-rw-r--r--xtask/src/bin/pre-commit.rs (renamed from crates/ra_tools/src/bin/pre-commit.rs)2
-rw-r--r--xtask/src/boilerplate_gen.rs (renamed from crates/ra_tools/src/boilerplate_gen.rs)0
-rw-r--r--xtask/src/help.rs (renamed from crates/ra_tools/src/help.rs)10
-rw-r--r--xtask/src/lib.rs (renamed from crates/ra_tools/src/lib.rs)4
-rw-r--r--xtask/src/main.rs (renamed from crates/ra_tools/src/main.rs)52
-rw-r--r--xtask/tests/tidy-tests/cli.rs (renamed from crates/ra_tools/tests/cli.rs)6
-rw-r--r--xtask/tests/tidy-tests/docs.rs (renamed from crates/ra_tools/tests/docs.rs)2
-rw-r--r--xtask/tests/tidy-tests/main.rs (renamed from crates/ra_tools/tests/main.rs)0
122 files changed, 5209 insertions, 3276 deletions
diff --git a/.cargo/config b/.cargo/config
index 9f9b24a49..3812e1e2d 100644
--- a/.cargo/config
+++ b/.cargo/config
@@ -1,25 +1,4 @@
1[alias] 1[alias]
2# Automatically generates the ast and syntax kinds files 2xtask = "run --package xtask --bin xtask --"
3gen-syntax = "run --package ra_tools --bin ra_tools -- gen-syntax"
4 3
5# Extracts the tests from 4install-ra = "run --package xtask --bin xtask -- install" # for backwards compat
6gen-tests = "run --package ra_tools --bin ra_tools -- gen-tests"
7
8build-website = "run --package website-gen"
9
10# Installs the visual studio code extension
11install-ra = "run --package ra_tools --bin ra_tools -- install-ra"
12install-code = "run --package ra_tools --bin ra_tools -- install-ra" # just an alias
13
14# Formats the full repository or installs the git hook to do it automatically.
15format = "run --package ra_tools --bin ra_tools -- format"
16format-hook = "run --package ra_tools --bin ra_tools -- format-hook"
17
18# Run clippy
19lint = "run --package ra_tools --bin ra_tools -- lint"
20
21# Runs the fuzzing test suite (currently only parser)
22fuzz-tests = "run --package ra_tools --bin ra_tools -- fuzz-tests"
23
24# Parse a file. This should be piped the file contents
25parse = "run --package ra_cli -- parse"
diff --git a/.travis.yml b/.travis.yml
index d4cf71ab5..7d66f72d8 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -14,7 +14,7 @@ matrix:
14 script: 14 script:
15 - rustup component add rustfmt 15 - rustup component add rustfmt
16 - rustup component add rust-src 16 - rustup component add rust-src
17 - printf "\n\n[profile.dev]\ndebug = false\n" >> Cargo.toml 17 - sed -i "s/debug = 1/debug = false/g" Cargo.toml
18 - cargo test --no-run # let's measure compile time separately 18 - cargo test --no-run # let's measure compile time separately
19 - cargo test 19 - cargo test
20 env: 20 env:
@@ -28,7 +28,7 @@ matrix:
28 language: rust 28 language: rust
29 rust: stable 29 rust: stable
30 script: 30 script:
31 - cargo build-website 31 - cargo doc --all --no-deps
32 env: 32 env:
33 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0 33 - RUSTFLAGS="-D warnings", CARGO_INCREMENTAL=0
34 34
@@ -59,7 +59,7 @@ deploy:
59 skip-cleanup: true 59 skip-cleanup: true
60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable 60 github-token: $DOCS_TOKEN # Set in the settings page of your repository, as a secure variable
61 keep-history: false 61 keep-history: false
62 local-dir: target/website/ 62 local-dir: target/doc
63 on: 63 on:
64 branch: master 64 branch: master
65 condition: $DEPLOY_DOCS = 1 65 condition: $DEPLOY_DOCS = 1
diff --git a/Cargo.lock b/Cargo.lock
index a5a43cffc..634480e5f 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,44 +10,49 @@ dependencies = [
10 10
11[[package]] 11[[package]]
12name = "arrayvec" 12name = "arrayvec"
13version = "0.4.11" 13version = "0.4.12"
14source = "registry+https://github.com/rust-lang/crates.io-index" 14source = "registry+https://github.com/rust-lang/crates.io-index"
15dependencies = [ 15dependencies = [
16 "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 16 "nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)",
17] 17]
18 18
19[[package]] 19[[package]]
20name = "arrayvec"
21version = "0.5.1"
22source = "registry+https://github.com/rust-lang/crates.io-index"
23
24[[package]]
20name = "atty" 25name = "atty"
21version = "0.2.13" 26version = "0.2.13"
22source = "registry+https://github.com/rust-lang/crates.io-index" 27source = "registry+https://github.com/rust-lang/crates.io-index"
23dependencies = [ 28dependencies = [
24 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 29 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
25 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 30 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
26] 31]
27 32
28[[package]] 33[[package]]
29name = "autocfg" 34name = "autocfg"
30version = "0.1.6" 35version = "0.1.7"
31source = "registry+https://github.com/rust-lang/crates.io-index" 36source = "registry+https://github.com/rust-lang/crates.io-index"
32 37
33[[package]] 38[[package]]
34name = "backtrace" 39name = "backtrace"
35version = "0.3.38" 40version = "0.3.40"
36source = "registry+https://github.com/rust-lang/crates.io-index" 41source = "registry+https://github.com/rust-lang/crates.io-index"
37dependencies = [ 42dependencies = [
38 "backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)", 43 "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
39 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 44 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
40 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 45 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
41 "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 46 "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
42] 47]
43 48
44[[package]] 49[[package]]
45name = "backtrace-sys" 50name = "backtrace-sys"
46version = "0.1.31" 51version = "0.1.32"
47source = "registry+https://github.com/rust-lang/crates.io-index" 52source = "registry+https://github.com/rust-lang/crates.io-index"
48dependencies = [ 53dependencies = [
49 "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", 54 "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
50 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 55 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
51] 56]
52 57
53[[package]] 58[[package]]
@@ -73,7 +78,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
73 78
74[[package]] 79[[package]]
75name = "bitflags" 80name = "bitflags"
76version = "1.2.0" 81version = "1.2.1"
77source = "registry+https://github.com/rust-lang/crates.io-index" 82source = "registry+https://github.com/rust-lang/crates.io-index"
78 83
79[[package]] 84[[package]]
@@ -91,27 +96,26 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
91 96
92[[package]] 97[[package]]
93name = "c2-chacha" 98name = "c2-chacha"
94version = "0.2.2" 99version = "0.2.3"
95source = "registry+https://github.com/rust-lang/crates.io-index" 100source = "registry+https://github.com/rust-lang/crates.io-index"
96dependencies = [ 101dependencies = [
97 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 102 "ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
98 "ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
99] 103]
100 104
101[[package]] 105[[package]]
102name = "cargo_metadata" 106name = "cargo_metadata"
103version = "0.8.2" 107version = "0.9.0"
104source = "registry+https://github.com/rust-lang/crates.io-index" 108source = "registry+https://github.com/rust-lang/crates.io-index"
105dependencies = [ 109dependencies = [
106 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 110 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
107 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 111 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
108 "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 112 "serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
109 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 113 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
110] 114]
111 115
112[[package]] 116[[package]]
113name = "cc" 117name = "cc"
114version = "1.0.45" 118version = "1.0.46"
115source = "registry+https://github.com/rust-lang/crates.io-index" 119source = "registry+https://github.com/rust-lang/crates.io-index"
116 120
117[[package]] 121[[package]]
@@ -122,17 +126,17 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
122[[package]] 126[[package]]
123name = "chalk-engine" 127name = "chalk-engine"
124version = "0.9.0" 128version = "0.9.0"
125source = "git+https://github.com/rust-lang/chalk.git#df09cc603c0cff9ed95e5554055d483fdd756fbc" 129source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9"
126dependencies = [ 130dependencies = [
127 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 131 "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)", 132 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
129 "stacker 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 133 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
130] 134]
131 135
132[[package]] 136[[package]]
133name = "chalk-ir" 137name = "chalk-ir"
134version = "0.1.0" 138version = "0.1.0"
135source = "git+https://github.com/rust-lang/chalk.git#df09cc603c0cff9ed95e5554055d483fdd756fbc" 139source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9"
136dependencies = [ 140dependencies = [
137 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 141 "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)", 142 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
@@ -142,7 +146,7 @@ dependencies = [
142[[package]] 146[[package]]
143name = "chalk-macros" 147name = "chalk-macros"
144version = "0.1.1" 148version = "0.1.1"
145source = "git+https://github.com/rust-lang/chalk.git#df09cc603c0cff9ed95e5554055d483fdd756fbc" 149source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9"
146dependencies = [ 150dependencies = [
147 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 151 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
148] 152]
@@ -150,7 +154,7 @@ dependencies = [
150[[package]] 154[[package]]
151name = "chalk-rust-ir" 155name = "chalk-rust-ir"
152version = "0.1.0" 156version = "0.1.0"
153source = "git+https://github.com/rust-lang/chalk.git#df09cc603c0cff9ed95e5554055d483fdd756fbc" 157source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9"
154dependencies = [ 158dependencies = [
155 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 159 "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)", 160 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
@@ -160,14 +164,13 @@ dependencies = [
160[[package]] 164[[package]]
161name = "chalk-solve" 165name = "chalk-solve"
162version = "0.1.0" 166version = "0.1.0"
163source = "git+https://github.com/rust-lang/chalk.git#df09cc603c0cff9ed95e5554055d483fdd756fbc" 167source = "git+https://github.com/rust-lang/chalk.git#13303bb0067c6ed0572322080ae367ee38f9e7c9"
164dependencies = [ 168dependencies = [
165 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)", 169 "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)", 170 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
167 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)", 171 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git)",
168 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 172 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
169 "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", 173 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
170 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)",
171 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 174 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
172 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 175 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
173 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 176 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -178,7 +181,7 @@ name = "chrono"
178version = "0.4.9" 181version = "0.4.9"
179source = "registry+https://github.com/rust-lang/crates.io-index" 182source = "registry+https://github.com/rust-lang/crates.io-index"
180dependencies = [ 183dependencies = [
181 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 184 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
182 "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", 185 "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
183 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 186 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
184 "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)", 187 "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -191,7 +194,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
191dependencies = [ 194dependencies = [
192 "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 195 "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
193 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 196 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
194 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 197 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
195 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 198 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
196] 199]
197 200
@@ -200,7 +203,7 @@ name = "cloudabi"
200version = "0.0.3" 203version = "0.0.3"
201source = "registry+https://github.com/rust-lang/crates.io-index" 204source = "registry+https://github.com/rust-lang/crates.io-index"
202dependencies = [ 205dependencies = [
203 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 206 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
204] 207]
205 208
206[[package]] 209[[package]]
@@ -211,7 +214,22 @@ dependencies = [
211 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 214 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
212 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 215 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
213 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 216 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
214 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 217 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
218 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
219 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
220 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
221 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
222]
223
224[[package]]
225name = "console"
226version = "0.9.0"
227source = "registry+https://github.com/rust-lang/crates.io-index"
228dependencies = [
229 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
230 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
231 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
232 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
215 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 233 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
216 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 234 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
217 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 235 "unicode-width 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -253,7 +271,7 @@ name = "crossbeam-epoch"
253version = "0.7.2" 271version = "0.7.2"
254source = "registry+https://github.com/rust-lang/crates.io-index" 272source = "registry+https://github.com/rust-lang/crates.io-index"
255dependencies = [ 273dependencies = [
256 "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", 274 "arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)",
257 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 275 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
258 "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)", 276 "crossbeam-utils 0.6.6 (registry+https://github.com/rust-lang/crates.io-index)",
259 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 277 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -283,7 +301,7 @@ name = "derive-new"
283version = "0.5.8" 301version = "0.5.8"
284source = "registry+https://github.com/rust-lang/crates.io-index" 302source = "registry+https://github.com/rust-lang/crates.io-index"
285dependencies = [ 303dependencies = [
286 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 304 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
287 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 305 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
288 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 306 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
289] 307]
@@ -310,7 +328,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
310 328
311[[package]] 329[[package]]
312name = "ena" 330name = "ena"
313version = "0.13.0" 331version = "0.13.1"
314source = "registry+https://github.com/rust-lang/crates.io-index" 332source = "registry+https://github.com/rust-lang/crates.io-index"
315dependencies = [ 333dependencies = [
316 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 334 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -327,7 +345,7 @@ version = "0.2.7"
327source = "registry+https://github.com/rust-lang/crates.io-index" 345source = "registry+https://github.com/rust-lang/crates.io-index"
328dependencies = [ 346dependencies = [
329 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 347 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
330 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 348 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
331 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 349 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
332 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 350 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
333] 351]
@@ -369,7 +387,7 @@ name = "fsevent"
369version = "0.4.0" 387version = "0.4.0"
370source = "registry+https://github.com/rust-lang/crates.io-index" 388source = "registry+https://github.com/rust-lang/crates.io-index"
371dependencies = [ 389dependencies = [
372 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 390 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
373 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 391 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
374] 392]
375 393
@@ -378,7 +396,7 @@ name = "fsevent-sys"
378version = "2.0.1" 396version = "2.0.1"
379source = "registry+https://github.com/rust-lang/crates.io-index" 397source = "registry+https://github.com/rust-lang/crates.io-index"
380dependencies = [ 398dependencies = [
381 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 399 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
382] 400]
383 401
384[[package]] 402[[package]]
@@ -399,7 +417,7 @@ name = "fuchsia-zircon"
399version = "0.3.3" 417version = "0.3.3"
400source = "registry+https://github.com/rust-lang/crates.io-index" 418source = "registry+https://github.com/rust-lang/crates.io-index"
401dependencies = [ 419dependencies = [
402 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 420 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
403 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 421 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
404] 422]
405 423
@@ -414,7 +432,7 @@ version = "0.1.12"
414source = "registry+https://github.com/rust-lang/crates.io-index" 432source = "registry+https://github.com/rust-lang/crates.io-index"
415dependencies = [ 433dependencies = [
416 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 434 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
417 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 435 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
418 "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 436 "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
419] 437]
420 438
@@ -455,18 +473,20 @@ dependencies = [
455 473
456[[package]] 474[[package]]
457name = "indexmap" 475name = "indexmap"
458version = "1.2.0" 476version = "1.3.0"
459source = "registry+https://github.com/rust-lang/crates.io-index" 477source = "registry+https://github.com/rust-lang/crates.io-index"
478dependencies = [
479 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
480]
460 481
461[[package]] 482[[package]]
462name = "indicatif" 483name = "indicatif"
463version = "0.11.0" 484version = "0.12.0"
464source = "registry+https://github.com/rust-lang/crates.io-index" 485source = "registry+https://github.com/rust-lang/crates.io-index"
465dependencies = [ 486dependencies = [
466 "console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 487 "console 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
467 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 488 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
468 "number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 489 "number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
469 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
470 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 490 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
471] 491]
472 492
@@ -475,9 +495,9 @@ name = "inotify"
475version = "0.6.1" 495version = "0.6.1"
476source = "registry+https://github.com/rust-lang/crates.io-index" 496source = "registry+https://github.com/rust-lang/crates.io-index"
477dependencies = [ 497dependencies = [
478 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 498 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
479 "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 499 "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
480 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 500 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
481] 501]
482 502
483[[package]] 503[[package]]
@@ -485,7 +505,7 @@ name = "inotify-sys"
485version = "0.1.3" 505version = "0.1.3"
486source = "registry+https://github.com/rust-lang/crates.io-index" 506source = "registry+https://github.com/rust-lang/crates.io-index"
487dependencies = [ 507dependencies = [
488 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 508 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
489] 509]
490 510
491[[package]] 511[[package]]
@@ -497,18 +517,17 @@ dependencies = [
497 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 517 "difference 2.0.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)", 518 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
499 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 519 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
500 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 520 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
501 "serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)", 521 "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
502 "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)", 522 "uuid 0.7.4 (registry+https://github.com/rust-lang/crates.io-index)",
503] 523]
504 524
505[[package]] 525[[package]]
506name = "iovec" 526name = "iovec"
507version = "0.1.2" 527version = "0.1.4"
508source = "registry+https://github.com/rust-lang/crates.io-index" 528source = "registry+https://github.com/rust-lang/crates.io-index"
509dependencies = [ 529dependencies = [
510 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 530 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
511 "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
512] 531]
513 532
514[[package]] 533[[package]]
@@ -530,7 +549,7 @@ version = "0.3.3"
530source = "registry+https://github.com/rust-lang/crates.io-index" 549source = "registry+https://github.com/rust-lang/crates.io-index"
531dependencies = [ 550dependencies = [
532 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 551 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
533 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 552 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
534 "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 553 "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
535] 554]
536 555
@@ -539,9 +558,9 @@ name = "jemalloc-sys"
539version = "0.3.2" 558version = "0.3.2"
540source = "registry+https://github.com/rust-lang/crates.io-index" 559source = "registry+https://github.com/rust-lang/crates.io-index"
541dependencies = [ 560dependencies = [
542 "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", 561 "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
543 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 562 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
544 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 563 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
545] 564]
546 565
547[[package]] 566[[package]]
@@ -550,7 +569,7 @@ version = "0.3.2"
550source = "registry+https://github.com/rust-lang/crates.io-index" 569source = "registry+https://github.com/rust-lang/crates.io-index"
551dependencies = [ 570dependencies = [
552 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 571 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
553 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 572 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
554] 573]
555 574
556[[package]] 575[[package]]
@@ -589,7 +608,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
589 608
590[[package]] 609[[package]]
591name = "libc" 610name = "libc"
592version = "0.2.62" 611version = "0.2.65"
593source = "registry+https://github.com/rust-lang/crates.io-index" 612source = "registry+https://github.com/rust-lang/crates.io-index"
594 613
595[[package]] 614[[package]]
@@ -621,7 +640,7 @@ dependencies = [
621 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 640 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
622 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 641 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
623 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 642 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
624 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 643 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
625] 644]
626 645
627[[package]] 646[[package]]
@@ -629,9 +648,9 @@ name = "lsp-types"
629version = "0.61.0" 648version = "0.61.0"
630source = "registry+https://github.com/rust-lang/crates.io-index" 649source = "registry+https://github.com/rust-lang/crates.io-index"
631dependencies = [ 650dependencies = [
632 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 651 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
633 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 652 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
634 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 653 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
635 "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 654 "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
636 "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 655 "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
637] 656]
@@ -661,9 +680,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
661dependencies = [ 680dependencies = [
662 "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 681 "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
663 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 682 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
664 "iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", 683 "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
665 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 684 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
666 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 685 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
667 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 686 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
668 "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 687 "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
669 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 688 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -699,27 +718,27 @@ version = "0.2.33"
699source = "registry+https://github.com/rust-lang/crates.io-index" 718source = "registry+https://github.com/rust-lang/crates.io-index"
700dependencies = [ 719dependencies = [
701 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 720 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
702 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 721 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
703 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 722 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
704] 723]
705 724
706[[package]] 725[[package]]
707name = "nodrop" 726name = "nodrop"
708version = "0.1.13" 727version = "0.1.14"
709source = "registry+https://github.com/rust-lang/crates.io-index" 728source = "registry+https://github.com/rust-lang/crates.io-index"
710 729
711[[package]] 730[[package]]
712name = "notify" 731name = "notify"
713version = "4.0.13" 732version = "4.0.14"
714source = "registry+https://github.com/rust-lang/crates.io-index" 733source = "registry+https://github.com/rust-lang/crates.io-index"
715dependencies = [ 734dependencies = [
716 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 735 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
717 "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)", 736 "filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)",
718 "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 737 "fsevent 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
719 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 738 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
720 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", 739 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
721 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 740 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
722 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 741 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
723 "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)", 742 "mio 0.6.19 (registry+https://github.com/rust-lang/crates.io-index)",
724 "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 743 "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
725 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 744 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -731,7 +750,7 @@ name = "num-integer"
731version = "0.1.41" 750version = "0.1.41"
732source = "registry+https://github.com/rust-lang/crates.io-index" 751source = "registry+https://github.com/rust-lang/crates.io-index"
733dependencies = [ 752dependencies = [
734 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 753 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
735 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 754 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
736] 755]
737 756
@@ -740,7 +759,7 @@ name = "num-traits"
740version = "0.2.8" 759version = "0.2.8"
741source = "registry+https://github.com/rust-lang/crates.io-index" 760source = "registry+https://github.com/rust-lang/crates.io-index"
742dependencies = [ 761dependencies = [
743 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 762 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
744] 763]
745 764
746[[package]] 765[[package]]
@@ -748,16 +767,13 @@ name = "num_cpus"
748version = "1.10.1" 767version = "1.10.1"
749source = "registry+https://github.com/rust-lang/crates.io-index" 768source = "registry+https://github.com/rust-lang/crates.io-index"
750dependencies = [ 769dependencies = [
751 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 770 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
752] 771]
753 772
754[[package]] 773[[package]]
755name = "number_prefix" 774name = "number_prefix"
756version = "0.2.8" 775version = "0.3.0"
757source = "registry+https://github.com/rust-lang/crates.io-index" 776source = "registry+https://github.com/rust-lang/crates.io-index"
758dependencies = [
759 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
760]
761 777
762[[package]] 778[[package]]
763name = "once_cell" 779name = "once_cell"
@@ -786,7 +802,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
786dependencies = [ 802dependencies = [
787 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 803 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
788 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 804 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
789 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 805 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
790 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 806 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
791 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", 807 "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
792 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 808 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -799,7 +815,7 @@ version = "0.1.6"
799source = "registry+https://github.com/rust-lang/crates.io-index" 815source = "registry+https://github.com/rust-lang/crates.io-index"
800dependencies = [ 816dependencies = [
801 "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 817 "paste-impl 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
802 "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", 818 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
803] 819]
804 820
805[[package]] 821[[package]]
@@ -807,8 +823,8 @@ name = "paste-impl"
807version = "0.1.6" 823version = "0.1.6"
808source = "registry+https://github.com/rust-lang/crates.io-index" 824source = "registry+https://github.com/rust-lang/crates.io-index"
809dependencies = [ 825dependencies = [
810 "proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)", 826 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
811 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 827 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
812 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 828 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
813 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 829 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
814] 830]
@@ -834,22 +850,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
834 850
835[[package]] 851[[package]]
836name = "ppv-lite86" 852name = "ppv-lite86"
837version = "0.2.5" 853version = "0.2.6"
838source = "registry+https://github.com/rust-lang/crates.io-index" 854source = "registry+https://github.com/rust-lang/crates.io-index"
839 855
840[[package]] 856[[package]]
841name = "proc-macro-hack" 857name = "proc-macro-hack"
842version = "0.5.9" 858version = "0.5.11"
843source = "registry+https://github.com/rust-lang/crates.io-index" 859source = "registry+https://github.com/rust-lang/crates.io-index"
844dependencies = [ 860dependencies = [
845 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 861 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
846 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 862 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
847 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 863 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
848] 864]
849 865
850[[package]] 866[[package]]
851name = "proc-macro2" 867name = "proc-macro2"
852version = "1.0.5" 868version = "1.0.6"
853source = "registry+https://github.com/rust-lang/crates.io-index" 869source = "registry+https://github.com/rust-lang/crates.io-index"
854dependencies = [ 870dependencies = [
855 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 871 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -861,7 +877,7 @@ version = "0.9.4"
861source = "registry+https://github.com/rust-lang/crates.io-index" 877source = "registry+https://github.com/rust-lang/crates.io-index"
862dependencies = [ 878dependencies = [
863 "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 879 "bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
864 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 880 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
865 "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 881 "byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
866 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 882 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
867 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", 883 "num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -873,6 +889,14 @@ dependencies = [
873] 889]
874 890
875[[package]] 891[[package]]
892name = "psm"
893version = "0.1.5"
894source = "registry+https://github.com/rust-lang/crates.io-index"
895dependencies = [
896 "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
897]
898
899[[package]]
876name = "quick-error" 900name = "quick-error"
877version = "1.2.2" 901version = "1.2.2"
878source = "registry+https://github.com/rust-lang/crates.io-index" 902source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -882,7 +906,7 @@ name = "quote"
882version = "1.0.2" 906version = "1.0.2"
883source = "registry+https://github.com/rust-lang/crates.io-index" 907source = "registry+https://github.com/rust-lang/crates.io-index"
884dependencies = [ 908dependencies = [
885 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 909 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
886] 910]
887 911
888[[package]] 912[[package]]
@@ -893,17 +917,15 @@ version = "0.1.0"
893name = "ra_assists" 917name = "ra_assists"
894version = "0.1.0" 918version = "0.1.0"
895dependencies = [ 919dependencies = [
896 "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)",
897 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 920 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
898 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 921 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
899 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 922 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
900 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
901 "ra_db 0.1.0", 923 "ra_db 0.1.0",
902 "ra_fmt 0.1.0", 924 "ra_fmt 0.1.0",
903 "ra_hir 0.1.0", 925 "ra_hir 0.1.0",
904 "ra_syntax 0.1.0", 926 "ra_syntax 0.1.0",
905 "ra_text_edit 0.1.0", 927 "ra_text_edit 0.1.0",
906 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 928 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
907 "test_utils 0.1.0", 929 "test_utils 0.1.0",
908] 930]
909 931
@@ -917,7 +939,7 @@ dependencies = [
917 "ra_hir 0.1.0", 939 "ra_hir 0.1.0",
918 "ra_ide_api 0.1.0", 940 "ra_ide_api 0.1.0",
919 "ra_project_model 0.1.0", 941 "ra_project_model 0.1.0",
920 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 942 "ra_vfs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
921 "ra_vfs_glob 0.1.0", 943 "ra_vfs_glob 0.1.0",
922 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 944 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
923] 945]
@@ -937,7 +959,7 @@ name = "ra_cli"
937version = "0.1.0" 959version = "0.1.0"
938dependencies = [ 960dependencies = [
939 "flexi_logger 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)", 961 "flexi_logger 0.14.4 (registry+https://github.com/rust-lang/crates.io-index)",
940 "indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 962 "indicatif 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
941 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 963 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
942 "ra_batch 0.1.0", 964 "ra_batch 0.1.0",
943 "ra_db 0.1.0", 965 "ra_db 0.1.0",
@@ -954,9 +976,9 @@ dependencies = [
954 "ra_cfg 0.1.0", 976 "ra_cfg 0.1.0",
955 "ra_prof 0.1.0", 977 "ra_prof 0.1.0",
956 "ra_syntax 0.1.0", 978 "ra_syntax 0.1.0",
957 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 979 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
958 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 980 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
959 "salsa 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 981 "salsa 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
960] 982]
961 983
962[[package]] 984[[package]]
@@ -971,11 +993,11 @@ dependencies = [
971name = "ra_hir" 993name = "ra_hir"
972version = "0.1.0" 994version = "0.1.0"
973dependencies = [ 995dependencies = [
974 "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", 996 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
975 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 997 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
976 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 998 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
977 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)", 999 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git)",
978 "ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)", 1000 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
979 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", 1001 "insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
980 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1002 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
981 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1003 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -988,7 +1010,7 @@ dependencies = [
988 "ra_prof 0.1.0", 1010 "ra_prof 0.1.0",
989 "ra_syntax 0.1.0", 1011 "ra_syntax 0.1.0",
990 "ra_tt 0.1.0", 1012 "ra_tt 0.1.0",
991 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1013 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
992 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1014 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
993 "test_utils 0.1.0", 1015 "test_utils 0.1.0",
994] 1016]
@@ -1003,6 +1025,7 @@ dependencies = [
1003 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1025 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1004 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 1026 "join_to_string 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
1005 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1027 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1028 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1006 "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)", 1029 "proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)",
1007 "ra_assists 0.1.0", 1030 "ra_assists 0.1.0",
1008 "ra_cfg 0.1.0", 1031 "ra_cfg 0.1.0",
@@ -1014,7 +1037,7 @@ dependencies = [
1014 "ra_text_edit 0.1.0", 1037 "ra_text_edit 0.1.0",
1015 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1038 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1016 "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1039 "rayon 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1017 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1040 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1018 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1041 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1019 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1042 "superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1020 "test_utils 0.1.0", 1043 "test_utils 0.1.0",
@@ -1032,19 +1055,17 @@ dependencies = [
1032 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1055 "lsp-server 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1033 "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)", 1056 "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)",
1034 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1057 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1035 "ra_cfg 0.1.0",
1036 "ra_db 0.1.0",
1037 "ra_ide_api 0.1.0", 1058 "ra_ide_api 0.1.0",
1038 "ra_prof 0.1.0", 1059 "ra_prof 0.1.0",
1039 "ra_project_model 0.1.0", 1060 "ra_project_model 0.1.0",
1040 "ra_syntax 0.1.0", 1061 "ra_syntax 0.1.0",
1041 "ra_text_edit 0.1.0", 1062 "ra_text_edit 0.1.0",
1042 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1063 "ra_vfs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
1043 "ra_vfs_glob 0.1.0", 1064 "ra_vfs_glob 0.1.0",
1044 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1065 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1045 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1066 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1046 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 1067 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1047 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 1068 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
1048 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1069 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1049 "test_utils 0.1.0", 1070 "test_utils 0.1.0",
1050 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1071 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1054,7 +1075,6 @@ dependencies = [
1054name = "ra_mbe" 1075name = "ra_mbe"
1055version = "0.1.0" 1076version = "0.1.0"
1056dependencies = [ 1077dependencies = [
1057 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1058 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1078 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1059 "ra_parser 0.1.0", 1079 "ra_parser 0.1.0",
1060 "ra_syntax 0.1.0", 1080 "ra_syntax 0.1.0",
@@ -1075,7 +1095,7 @@ dependencies = [
1075name = "ra_prof" 1095name = "ra_prof"
1076version = "0.1.0" 1096version = "0.1.0"
1077dependencies = [ 1097dependencies = [
1078 "backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)", 1098 "backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)",
1079 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1099 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1080 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 1100 "jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
1081 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 1101 "jemallocator 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1086,21 +1106,21 @@ dependencies = [
1086name = "ra_project_model" 1106name = "ra_project_model"
1087version = "0.1.0" 1107version = "0.1.0"
1088dependencies = [ 1108dependencies = [
1089 "cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 1109 "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1090 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1110 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1091 "ra_arena 0.1.0", 1111 "ra_arena 0.1.0",
1092 "ra_cfg 0.1.0", 1112 "ra_cfg 0.1.0",
1093 "ra_db 0.1.0", 1113 "ra_db 0.1.0",
1094 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1114 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1095 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 1115 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1096 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 1116 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
1097] 1117]
1098 1118
1099[[package]] 1119[[package]]
1100name = "ra_syntax" 1120name = "ra_syntax"
1101version = "0.1.0" 1121version = "0.1.0"
1102dependencies = [ 1122dependencies = [
1103 "arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", 1123 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1104 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", 1124 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1105 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1125 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1106 "ra_parser 0.1.0", 1126 "ra_parser 0.1.0",
@@ -1108,7 +1128,7 @@ dependencies = [
1108 "rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", 1128 "rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
1109 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1129 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1110 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1130 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1111 "smol_str 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 1131 "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
1112 "test_utils 0.1.0", 1132 "test_utils 0.1.0",
1113 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 1133 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1114] 1134]
@@ -1123,36 +1143,23 @@ dependencies = [
1123] 1143]
1124 1144
1125[[package]] 1145[[package]]
1126name = "ra_tools"
1127version = "0.1.0"
1128dependencies = [
1129 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1130 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1131 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1132 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1133 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1134 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1135 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1136]
1137
1138[[package]]
1139name = "ra_tt" 1146name = "ra_tt"
1140version = "0.1.0" 1147version = "0.1.0"
1141dependencies = [ 1148dependencies = [
1142 "smol_str 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 1149 "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
1143] 1150]
1144 1151
1145[[package]] 1152[[package]]
1146name = "ra_vfs" 1153name = "ra_vfs"
1147version = "0.4.0" 1154version = "0.5.0"
1148source = "registry+https://github.com/rust-lang/crates.io-index" 1155source = "registry+https://github.com/rust-lang/crates.io-index"
1149dependencies = [ 1156dependencies = [
1150 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", 1157 "crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)",
1151 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1158 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1152 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1159 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1153 "notify 4.0.13 (registry+https://github.com/rust-lang/crates.io-index)", 1160 "notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)",
1154 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1161 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1155 "relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1162 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1156 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1163 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1157 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 1164 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1158] 1165]
@@ -1162,7 +1169,7 @@ name = "ra_vfs_glob"
1162version = "0.1.0" 1169version = "0.1.0"
1163dependencies = [ 1170dependencies = [
1164 "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1171 "globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1165 "ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1172 "ra_vfs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
1166] 1173]
1167 1174
1168[[package]] 1175[[package]]
@@ -1170,8 +1177,8 @@ name = "rand"
1170version = "0.6.5" 1177version = "0.6.5"
1171source = "registry+https://github.com/rust-lang/crates.io-index" 1178source = "registry+https://github.com/rust-lang/crates.io-index"
1172dependencies = [ 1179dependencies = [
1173 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1180 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
1174 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1181 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1175 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1182 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1176 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1183 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1177 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1184 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1189,7 +1196,7 @@ version = "0.7.2"
1189source = "registry+https://github.com/rust-lang/crates.io-index" 1196source = "registry+https://github.com/rust-lang/crates.io-index"
1190dependencies = [ 1197dependencies = [
1191 "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", 1198 "getrandom 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)",
1192 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1199 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1193 "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1200 "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1194 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1201 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1195 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1202 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1201,7 +1208,7 @@ name = "rand_chacha"
1201version = "0.1.1" 1208version = "0.1.1"
1202source = "registry+https://github.com/rust-lang/crates.io-index" 1209source = "registry+https://github.com/rust-lang/crates.io-index"
1203dependencies = [ 1210dependencies = [
1204 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1211 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
1205 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1212 "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1206] 1213]
1207 1214
@@ -1210,7 +1217,7 @@ name = "rand_chacha"
1210version = "0.2.1" 1217version = "0.2.1"
1211source = "registry+https://github.com/rust-lang/crates.io-index" 1218source = "registry+https://github.com/rust-lang/crates.io-index"
1212dependencies = [ 1219dependencies = [
1213 "c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 1220 "c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
1214 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1221 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1215] 1222]
1216 1223
@@ -1264,7 +1271,7 @@ name = "rand_jitter"
1264version = "0.1.4" 1271version = "0.1.4"
1265source = "registry+https://github.com/rust-lang/crates.io-index" 1272source = "registry+https://github.com/rust-lang/crates.io-index"
1266dependencies = [ 1273dependencies = [
1267 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1274 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1268 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1275 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1269 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1276 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1270] 1277]
@@ -1276,7 +1283,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1276dependencies = [ 1283dependencies = [
1277 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 1284 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
1278 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1285 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1279 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1286 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1280 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1287 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1281 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1288 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1282 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1289 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1287,7 +1294,7 @@ name = "rand_pcg"
1287version = "0.1.2" 1294version = "0.1.2"
1288source = "registry+https://github.com/rust-lang/crates.io-index" 1295source = "registry+https://github.com/rust-lang/crates.io-index"
1289dependencies = [ 1296dependencies = [
1290 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1297 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
1291 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1298 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1292] 1299]
1293 1300
@@ -1296,7 +1303,7 @@ name = "rand_pcg"
1296version = "0.2.0" 1303version = "0.2.0"
1297source = "registry+https://github.com/rust-lang/crates.io-index" 1304source = "registry+https://github.com/rust-lang/crates.io-index"
1298dependencies = [ 1305dependencies = [
1299 "autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 1306 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
1300 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1307 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1301] 1308]
1302 1309
@@ -1361,7 +1368,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1361 1368
1362[[package]] 1369[[package]]
1363name = "relative-path" 1370name = "relative-path"
1364version = "0.4.0" 1371version = "1.0.0"
1365source = "registry+https://github.com/rust-lang/crates.io-index" 1372source = "registry+https://github.com/rust-lang/crates.io-index"
1366 1373
1367[[package]] 1374[[package]]
@@ -1378,7 +1385,7 @@ version = "0.5.1"
1378source = "registry+https://github.com/rust-lang/crates.io-index" 1385source = "registry+https://github.com/rust-lang/crates.io-index"
1379dependencies = [ 1386dependencies = [
1380 "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 1387 "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
1381 "bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1388 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1382 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 1389 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1383] 1390]
1384 1391
@@ -1388,7 +1395,7 @@ version = "0.6.2"
1388source = "registry+https://github.com/rust-lang/crates.io-index" 1395source = "registry+https://github.com/rust-lang/crates.io-index"
1389dependencies = [ 1396dependencies = [
1390 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1397 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1391 "smol_str 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 1398 "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
1392 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1399 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1393] 1400]
1394 1401
@@ -1423,32 +1430,32 @@ dependencies = [
1423 1430
1424[[package]] 1431[[package]]
1425name = "ryu" 1432name = "ryu"
1426version = "1.0.0" 1433version = "1.0.2"
1427source = "registry+https://github.com/rust-lang/crates.io-index" 1434source = "registry+https://github.com/rust-lang/crates.io-index"
1428 1435
1429[[package]] 1436[[package]]
1430name = "salsa" 1437name = "salsa"
1431version = "0.13.1" 1438version = "0.13.2"
1432source = "registry+https://github.com/rust-lang/crates.io-index" 1439source = "registry+https://github.com/rust-lang/crates.io-index"
1433dependencies = [ 1440dependencies = [
1434 "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1441 "crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1435 "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)", 1442 "derive-new 0.5.8 (registry+https://github.com/rust-lang/crates.io-index)",
1436 "indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1443 "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1437 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1444 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1438 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1445 "parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
1439 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1446 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1440 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1447 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1441 "salsa-macros 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 1448 "salsa-macros 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)",
1442 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)", 1449 "smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
1443] 1450]
1444 1451
1445[[package]] 1452[[package]]
1446name = "salsa-macros" 1453name = "salsa-macros"
1447version = "0.13.1" 1454version = "0.13.2"
1448source = "registry+https://github.com/rust-lang/crates.io-index" 1455source = "registry+https://github.com/rust-lang/crates.io-index"
1449dependencies = [ 1456dependencies = [
1450 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1457 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1451 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1458 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1452 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1459 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1453 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1460 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1454] 1461]
@@ -1493,18 +1500,18 @@ name = "serde_derive"
1493version = "1.0.101" 1500version = "1.0.101"
1494source = "registry+https://github.com/rust-lang/crates.io-index" 1501source = "registry+https://github.com/rust-lang/crates.io-index"
1495dependencies = [ 1502dependencies = [
1496 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1503 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1497 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1504 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1498 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1505 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1499] 1506]
1500 1507
1501[[package]] 1508[[package]]
1502name = "serde_json" 1509name = "serde_json"
1503version = "1.0.40" 1510version = "1.0.41"
1504source = "registry+https://github.com/rust-lang/crates.io-index" 1511source = "registry+https://github.com/rust-lang/crates.io-index"
1505dependencies = [ 1512dependencies = [
1506 "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1513 "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1507 "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1514 "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1508 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 1515 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1509] 1516]
1510 1517
@@ -1513,14 +1520,14 @@ name = "serde_repr"
1513version = "0.1.5" 1520version = "0.1.5"
1514source = "registry+https://github.com/rust-lang/crates.io-index" 1521source = "registry+https://github.com/rust-lang/crates.io-index"
1515dependencies = [ 1522dependencies = [
1516 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1523 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1517 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1524 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1518 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1525 "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)",
1519] 1526]
1520 1527
1521[[package]] 1528[[package]]
1522name = "serde_yaml" 1529name = "serde_yaml"
1523version = "0.8.9" 1530version = "0.8.11"
1524source = "registry+https://github.com/rust-lang/crates.io-index" 1531source = "registry+https://github.com/rust-lang/crates.io-index"
1525dependencies = [ 1532dependencies = [
1526 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1533 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1541,7 +1548,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1541 1548
1542[[package]] 1549[[package]]
1543name = "smol_str" 1550name = "smol_str"
1544version = "0.1.13" 1551version = "0.1.15"
1545source = "registry+https://github.com/rust-lang/crates.io-index" 1552source = "registry+https://github.com/rust-lang/crates.io-index"
1546dependencies = [ 1553dependencies = [
1547 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)", 1554 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1549,12 +1556,13 @@ dependencies = [
1549 1556
1550[[package]] 1557[[package]]
1551name = "stacker" 1558name = "stacker"
1552version = "0.1.5" 1559version = "0.1.6"
1553source = "registry+https://github.com/rust-lang/crates.io-index" 1560source = "registry+https://github.com/rust-lang/crates.io-index"
1554dependencies = [ 1561dependencies = [
1555 "cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)", 1562 "cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)",
1556 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 1563 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1557 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1564 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1565 "psm 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
1558 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1566 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1559] 1567]
1560 1568
@@ -1568,7 +1576,7 @@ name = "syn"
1568version = "1.0.5" 1576version = "1.0.5"
1569source = "registry+https://github.com/rust-lang/crates.io-index" 1577source = "registry+https://github.com/rust-lang/crates.io-index"
1570dependencies = [ 1578dependencies = [
1571 "proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 1579 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1572 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1580 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1573 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1581 "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1574] 1582]
@@ -1579,7 +1587,7 @@ version = "3.1.0"
1579source = "registry+https://github.com/rust-lang/crates.io-index" 1587source = "registry+https://github.com/rust-lang/crates.io-index"
1580dependencies = [ 1588dependencies = [
1581 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 1589 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1582 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1590 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1583 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1591 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1584 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 1592 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
1585 "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1593 "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1591,7 +1599,7 @@ name = "termios"
1591version = "0.3.1" 1599version = "0.3.1"
1592source = "registry+https://github.com/rust-lang/crates.io-index" 1600source = "registry+https://github.com/rust-lang/crates.io-index"
1593dependencies = [ 1601dependencies = [
1594 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1602 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1595] 1603]
1596 1604
1597[[package]] 1605[[package]]
@@ -1599,7 +1607,7 @@ name = "test_utils"
1599version = "0.1.0" 1607version = "0.1.0"
1600dependencies = [ 1608dependencies = [
1601 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1609 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1602 "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", 1610 "serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)",
1603 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1611 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1604] 1612]
1605 1613
@@ -1629,7 +1637,7 @@ name = "time"
1629version = "0.1.42" 1637version = "0.1.42"
1630source = "registry+https://github.com/rust-lang/crates.io-index" 1638source = "registry+https://github.com/rust-lang/crates.io-index"
1631dependencies = [ 1639dependencies = [
1632 "libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)", 1640 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1633 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 1641 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
1634 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1642 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1635] 1643]
@@ -1714,13 +1722,6 @@ version = "0.7.0"
1714source = "registry+https://github.com/rust-lang/crates.io-index" 1722source = "registry+https://github.com/rust-lang/crates.io-index"
1715 1723
1716[[package]] 1724[[package]]
1717name = "website-gen"
1718version = "0.0.0"
1719dependencies = [
1720 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1721]
1722
1723[[package]]
1724name = "winapi" 1725name = "winapi"
1725version = "0.2.8" 1726version = "0.2.8"
1726source = "registry+https://github.com/rust-lang/crates.io-index" 1727source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1767,6 +1768,19 @@ dependencies = [
1767] 1768]
1768 1769
1769[[package]] 1770[[package]]
1771name = "xtask"
1772version = "0.1.0"
1773dependencies = [
1774 "itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
1775 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1776 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1777 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1778 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1779 "serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)",
1780 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1781]
1782
1783[[package]]
1770name = "yaml-rust" 1784name = "yaml-rust"
1771version = "0.4.3" 1785version = "0.4.3"
1772source = "registry+https://github.com/rust-lang/crates.io-index" 1786source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1781,20 +1795,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1781 1795
1782[metadata] 1796[metadata]
1783"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1797"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
1784"checksum arrayvec 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b8d73f9beda665eaa98ab9e4f7442bd4e7de6652587de55b2525e52e29c1b0ba" 1798"checksum arrayvec 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "cd9fd44efafa8690358b7408d253adf110036b88f55672a933f01d616ad9b1b9"
1799"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
1785"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1800"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
1786"checksum autocfg 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b671c8fb71b457dd4ae18c4ba1e59aa81793daacc361d82fcd410cef0d491875" 1801"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
1787"checksum backtrace 0.3.38 (registry+https://github.com/rust-lang/crates.io-index)" = "690a62be8920ccf773ee00ef0968649b0e724cda8bd5b12286302b4ae955fdf5" 1802"checksum backtrace 0.3.40 (registry+https://github.com/rust-lang/crates.io-index)" = "924c76597f0d9ca25d762c25a4d369d51267536465dc5064bdf0eb073ed477ea"
1788"checksum backtrace-sys 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "82a830b4ef2d1124a711c71d263c5abdc710ef8e907bd508c88be475cebc422b" 1803"checksum backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "5d6575f128516de27e3ce99689419835fce9643a9b215a14d2b5b685be018491"
1789"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e" 1804"checksum base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b25d992356d2eb0ed82172f5248873db5560c4721f564b13cb5193bda5e668e"
1790"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80" 1805"checksum bit-set 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e84c238982c4b1e1ee668d136c510c67a13465279c0cb367ea6baf6310620a80"
1791"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb" 1806"checksum bit-vec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f59bbe95d4e52a6398ec21238d31577f2b28a9d86807f06ca59d191d8440d0bb"
1792"checksum bitflags 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8a606a02debe2813760609f57a64a2ffd27d9fdf5b2f133eaca0b248dd92cdd2" 1807"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
1793"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" 1808"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
1794"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1809"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
1795"checksum c2-chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7d64d04786e0f528460fc884753cf8dddcc466be308f6026f8e355c41a0e4101" 1810"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
1796"checksum cargo_metadata 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "700b3731fd7d357223d0000f4dbf1808401b694609035c3c411fbc0cd375c426" 1811"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d"
1797"checksum cc 1.0.45 (registry+https://github.com/rust-lang/crates.io-index)" = "4fc9a35e1f4290eb9e5fc54ba6cf40671ed2a2514c3eeb2b2a908dda2ea5a1be" 1812"checksum cc 1.0.46 (registry+https://github.com/rust-lang/crates.io-index)" = "0213d356d3c4ea2c18c40b037c3be23cd639825c18f25ee670ac7813beeef99c"
1798"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 1813"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
1799"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1814"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
1800"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>" 1815"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git)" = "<none>"
@@ -1805,6 +1820,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1805"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1820"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1806"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1821"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1807"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242" 1822"checksum console 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b147390a412132d75d10dd3b7b175a69cf5fd95032f7503c7091b8831ba10242"
1823"checksum console 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "62828f51cfa18f8c31d3d55a43c6ce6af3f87f754cba9fbba7ff38089b9f5612"
1808"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c" 1824"checksum crossbeam 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2d818a4990769aac0c7ff1360e233ef3a41adcb009ebb2036bf6915eb0f6b23c"
1809"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa" 1825"checksum crossbeam-channel 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c8ec7fcd21571dc78f96cc96243cab8d8f035247c3efd16c687be154c3fa9efa"
1810"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" 1826"checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71"
@@ -1816,7 +1832,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1816"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f" 1832"checksum drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "69b26e475fd29098530e709294e94e661974c851aed42512793f120fed4e199f"
1817"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e" 1833"checksum dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "ea57b42383d091c85abcc2706240b94ab2a8fa1fc81c10ff23c4de06e2a90b5e"
1818"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 1834"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
1819"checksum ena 0.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dc01d68e08ca384955a3aeba9217102ca1aa85b6e168639bf27739f1d749d87" 1835"checksum ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
1820"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 1836"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
1821"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469" 1837"checksum filetime 0.2.7 (registry+https://github.com/rust-lang/crates.io-index)" = "6bd7380b54ced79dda72ecc35cc4fbbd1da6bba54afaa37e96fd1c2a308cd469"
1822"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" 1838"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
@@ -1835,12 +1851,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1835"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" 1851"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
1836"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1852"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1837"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 1853"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
1838"checksum indexmap 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a61202fbe46c4a951e9404a720a0180bcf3212c750d735cb5c4ba4dc551299f3" 1854"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
1839"checksum indicatif 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2c60da1c9abea75996b70a931bba6c750730399005b61ccd853cee50ef3d0d0c" 1855"checksum indicatif 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a8d596a9576eaa1446996092642d72bfef35cf47243129b7ab883baf5faec31e"
1840"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" 1856"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
1841"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0" 1857"checksum inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e74a1aa87c59aeff6ef2cc2fa62d41bc43f54952f55652656b18a02fd5e356c0"
1842"checksum insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23f83ab4ee86f38b292f0420c27fd412690a4baa9ea0ad4e3fa624bf34379b76" 1858"checksum insta 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23f83ab4ee86f38b292f0420c27fd412690a4baa9ea0ad4e3fa624bf34379b76"
1843"checksum iovec 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dbe6e417e7d0975db6512b90796e8ce223145ac4e33c377e4a42882a0e88bb08" 1859"checksum iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b2b3ea6ff95e175473f8ffe6a7eb7c00d054240321b84c57051175fe3c1e075e"
1844"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358" 1860"checksum itertools 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5b8467d9c1cebe26feb08c640139247fac215782d35371ade9a2136ed6085358"
1845"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" 1861"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f"
1846"checksum jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7" 1862"checksum jemalloc-ctl 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "c502a5ff9dd2924f1ed32ba96e3b65735d837b4bfd978d3161b1702e66aca4b7"
@@ -1852,7 +1868,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1852"checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0" 1868"checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0"
1853"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1869"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1854"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1870"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
1855"checksum libc 0.2.62 (registry+https://github.com/rust-lang/crates.io-index)" = "34fcd2c08d2f832f376f4173a231990fa5aef4e99fb569867318a227ef4c06ba" 1871"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8"
1856"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 1872"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
1857"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc" 1873"checksum lock_api 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f8912e782533a93a167888781b836336a6ca5da6175c05944c86cf28c31104dc"
1858"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1874"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
@@ -1865,12 +1881,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1865"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" 1881"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40"
1866"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1882"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
1867"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1883"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
1868"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" 1884"checksum nodrop 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "72ef4a56884ca558e5ddb05a1d1e7e1bfd9a68d9ed024c21704cc98872dae1bb"
1869"checksum notify 4.0.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1191efa2b8fe041decb55c238a125b7a1aeb6fad7a525133a02be5ec949ff3cb" 1885"checksum notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "199628fc33b21bc767baa057490b00b382ecbae030803a7b36292422d15b778b"
1870"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09" 1886"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
1871"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32" 1887"checksum num-traits 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "6ba9a427cfca2be13aa6f6403b0b7e7368fe982bfa16fccc450ce74c46cd9b32"
1872"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273" 1888"checksum num_cpus 1.10.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bcef43580c035376c0705c42792c294b66974abbfd2789b511784023f71f3273"
1873"checksum number_prefix 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "dbf9993e59c894e3c08aa1c2712914e9e6bf1fcbfc6bef283e2183df345a4fee" 1889"checksum number_prefix 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17b02fc0ff9a9e4b35b3342880f48e896ebf69f2967921fe8646bf5b7125956a"
1874"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed" 1890"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
1875"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063" 1891"checksum ordermap 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a86ed3f5f244b372d6b1a00b72ef7f8876d0bc6a78a4c9985c53614041512063"
1876"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252" 1892"checksum parking_lot 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f842b1982eb6c2fe34036a4fbfb06dd185a3f5c8edfaacdf7d1ea10b07de6252"
@@ -1880,13 +1896,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1880"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" 1896"checksum percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e"
1881"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f" 1897"checksum petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3659d1ee90221741f65dd128d9998311b0e40c5d3c23a62445938214abce4f"
1882"checksum pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22e32b0f3771287ebb436130477eabf0f11f934ed036099ad548bc885e708667" 1898"checksum pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "22e32b0f3771287ebb436130477eabf0f11f934ed036099ad548bc885e708667"
1883"checksum ppv-lite86 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e3cbf9f658cdb5000fcf6f362b8ea2ba154b9f146a61c7a20d647034c6b6561b" 1899"checksum ppv-lite86 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "74490b50b9fbe561ac330df47c08f3f33073d2d00c150f719147d7c54522fa1b"
1884"checksum proc-macro-hack 0.5.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e688f31d92ffd7c1ddc57a1b4e6d773c0f2a14ee437a4b0a4f5a69c80eb221c8" 1900"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
1885"checksum proc-macro2 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "90cf5f418035b98e655e9cdb225047638296b862b42411c4e45bb88d700f7fc0" 1901"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
1886"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" 1902"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
1903"checksum psm 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "54639efee26275dfadc49644039c31c73673edde0ef2815acf25a8db526ee193"
1887"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1904"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1888"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1905"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1889"checksum ra_vfs 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fdf6a0926414eb0c00866eb9274894182302f879cd06b5459c1d8ee7f1234aed" 1906"checksum ra_vfs 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc8f508bc7a9871b81b6ee75e15d0bbc9f81a96698364a090a8d10b0f8b970b7"
1890"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" 1907"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca"
1891"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412" 1908"checksum rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3ae1b169243eaf61759b8475a998f0a385e42042370f3a7dbaf35246eacc8412"
1892"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" 1909"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef"
@@ -1908,7 +1925,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1908"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84" 1925"checksum redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)" = "2439c63f3f6139d1b57529d16bc3b8bb855230c8efcc5d3a896c8bea7c3b1e84"
1909"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd" 1926"checksum regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dc220bd33bdce8f093101afe22a037b8eb0e5af33592e6a9caafff0d4cb81cbd"
1910"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716" 1927"checksum regex-syntax 0.6.12 (registry+https://github.com/rust-lang/crates.io-index)" = "11a7e20d1cce64ef2fed88b66d347f88bd9babb82845b2b858f3edbf59a4f716"
1911"checksum relative-path 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0e7790c7f1cc73d831d28dc5a7deb316a006e7848e6a7f467cdb10a0a9e0fb1c" 1928"checksum relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bedde000f40f2921ce439ea165c9c53fd629bfa115140c72e22aceacb4a21954"
1912"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 1929"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
1913"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" 1930"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
1914"checksum rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dc2b79612dedc9004083a61448eb669d336d56690aab29fbd7249e8c8ab41d8c" 1931"checksum rowan 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dc2b79612dedc9004083a61448eb669d336d56690aab29fbd7249e8c8ab41d8c"
@@ -1916,22 +1933,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1916"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1933"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
1917"checksum rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" 1934"checksum rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5"
1918"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" 1935"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
1919"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" 1936"checksum ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bfa8506c1de11c9c4e4c38863ccbe02a305c8188e85a05a784c9e11e1c3910c8"
1920"checksum salsa 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "df34c3a66ef408c3219c11dee2c928d52e679390d3ee6e0b87e96cc758d85377" 1937"checksum salsa 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ec0865bdd9d8e614686a0cbb76979c735810131d287eb1683e91e4e64a58c387"
1921"checksum salsa-macros 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c15f36e5c85b3f40b84283321f97ef2ceafa6f9996cffad06793a9e096ab695" 1938"checksum salsa-macros 0.13.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cac182212d3a1db75ddc42399ff1461b258a694b8318ee7e0baf6c976e39efee"
1922"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421" 1939"checksum same-file 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "585e8ddcedc187886a30fa705c47985c3fa88d06624095856b36ca0b82ff4421"
1923"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" 1940"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
1924"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1941"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1925"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1942"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1926"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd" 1943"checksum serde 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "9796c9b7ba2ffe7a9ce53c2287dfc48080f4b2b362fcc245a259b3a7201119dd"
1927"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e" 1944"checksum serde_derive 1.0.101 (registry+https://github.com/rust-lang/crates.io-index)" = "4b133a43a1ecd55d4086bd5b4dc6c1751c68b1bfbeba7a5040442022c7e7c02e"
1928"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" 1945"checksum serde_json 1.0.41 (registry+https://github.com/rust-lang/crates.io-index)" = "2f72eb2a68a7dc3f9a691bfda9305a1c017a6215e5a4545c258500d2099a37c2"
1929"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" 1946"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
1930"checksum serde_yaml 0.8.9 (registry+https://github.com/rust-lang/crates.io-index)" = "38b08a9a90e5260fe01c6480ec7c811606df6d3a660415808c3c3fa8ed95b582" 1947"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
1931"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1948"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1932"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7" 1949"checksum smallvec 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ab606a9c5e214920bb66c458cd7be8ef094f813f20fe77a54cc7dbfff220d4b7"
1933"checksum smol_str 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "378286eaa0fa9e6bbc351c9bfcc2320391c347e014f10cb177c26be18142e596" 1950"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
1934"checksum stacker 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "fb79482f57cf598af52094ec4cc3b3c42499d3ce5bd426f2ac41515b7e57404b" 1951"checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a"
1935"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1952"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1936"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" 1953"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf"
1937"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1954"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
diff --git a/Cargo.toml b/Cargo.toml
index 317c63795..97c02b40f 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,5 +1,8 @@
1[workspace] 1[workspace]
2members = [ "crates/*", "website/website-gen" ] 2members = [ "crates/*", "xtask/" ]
3
4[profile.dev]
5debug = 1 # only line info
3 6
4[profile.release] 7[profile.release]
5incremental = true 8incremental = true
diff --git a/README.md b/README.md
index e249c6486..f5ee4263d 100644
--- a/README.md
+++ b/README.md
@@ -33,10 +33,10 @@ To quickly install rust-analyzer with VS Code extension with standard setup
33$ git clone https://github.com/rust-analyzer/rust-analyzer && cd rust-analyzer 33$ git clone https://github.com/rust-analyzer/rust-analyzer && cd rust-analyzer
34 34
35# install both the language server and VS Code extension 35# install both the language server and VS Code extension
36$ cargo install-ra 36$ cargo xtask install
37 37
38# alternatively, install only the server. Binary name is `ra_lsp_server`. 38# alternatively, install only the server. Binary name is `ra_lsp_server`.
39$ cargo install-ra --server 39$ cargo xtask install --server
40``` 40```
41 41
42For non-standard setup of VS Code and other editors, see [./docs/user](./docs/user). 42For non-standard setup of VS Code and other editors, see [./docs/user](./docs/user).
@@ -59,7 +59,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
59## Quick Links 59## Quick Links
60 60
61* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y 61* Work List: https://paper.dropbox.com/doc/RLS-2.0-work-list--AZ3BgHKKCtqszbsi3gi6sjchAQ-42vbnxzuKq2lKwW0mkn8Y
62* API docs: https://rust-analyzer.github.io/rust-analyzer/api-docs/ra_ide_api/ 62* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/
63* CI: https://travis-ci.org/rust-analyzer/rust-analyzer 63* CI: https://travis-ci.org/rust-analyzer/rust-analyzer
64 64
65## License 65## License
diff --git a/crates/ra_assists/Cargo.toml b/crates/ra_assists/Cargo.toml
index 02966bbda..beebccbd9 100644
--- a/crates/ra_assists/Cargo.toml
+++ b/crates/ra_assists/Cargo.toml
@@ -6,11 +6,9 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8format-buf = "1.0.0" 8format-buf = "1.0.0"
9once_cell = "1.0.1"
10join_to_string = "0.1.3" 9join_to_string = "0.1.3"
11itertools = "0.8.0" 10itertools = "0.8.0"
12arrayvec = "0.4.10" 11rustc_lexer = "0.1.0"
13rustc-hash = "1.0.1"
14 12
15ra_syntax = { path = "../ra_syntax" } 13ra_syntax = { path = "../ra_syntax" }
16ra_text_edit = { path = "../ra_text_edit" } 14ra_text_edit = { path = "../ra_text_edit" }
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 189cad7d0..e270c5d60 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -138,6 +138,7 @@ impl AssistBuilder {
138 138
139 /// Replaces specified `node` of text with a given string, reindenting the 139 /// Replaces specified `node` of text with a given string, reindenting the
140 /// string to maintain `node`'s existing indent. 140 /// string to maintain `node`'s existing indent.
141 // FIXME: remove in favor of ra_syntax::edit::IndentLevel::increase_indent
141 pub(crate) fn replace_node_and_indent( 142 pub(crate) fn replace_node_and_indent(
142 &mut self, 143 &mut self,
143 node: &SyntaxNode, 144 node: &SyntaxNode,
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
new file mode 100644
index 000000000..8c975714c
--- /dev/null
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -0,0 +1,276 @@
1//! FIXME: write short doc here
2
3use crate::{
4 assist_ctx::{Assist, AssistCtx},
5 AssistId,
6};
7use hir::db::HirDatabase;
8use ra_syntax::{
9 algo::replace_children,
10 ast::edit::IndentLevel,
11 ast::make,
12 ast::Block,
13 ast::ContinueExpr,
14 ast::IfExpr,
15 ast::ReturnExpr,
16 AstNode,
17 SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE},
18};
19use std::ops::RangeInclusive;
20
21pub(crate) fn convert_to_guarded_return(mut ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
22 let if_expr: IfExpr = ctx.node_at_offset()?;
23 let expr = if_expr.condition()?.expr()?;
24 let then_block = if_expr.then_branch()?.block()?;
25 if if_expr.else_branch().is_some() {
26 return None;
27 }
28
29 let parent_block = if_expr.syntax().parent()?.ancestors().find_map(Block::cast)?;
30
31 if parent_block.expr()? != if_expr.clone().into() {
32 return None;
33 }
34
35 // check for early return and continue
36 let first_in_then_block = then_block.syntax().first_child()?.clone();
37 if ReturnExpr::can_cast(first_in_then_block.kind())
38 || ContinueExpr::can_cast(first_in_then_block.kind())
39 || first_in_then_block
40 .children()
41 .any(|x| ReturnExpr::can_cast(x.kind()) || ContinueExpr::can_cast(x.kind()))
42 {
43 return None;
44 }
45
46 let parent_container = parent_block.syntax().parent()?.parent()?;
47
48 let early_expression = match parent_container.kind() {
49 WHILE_EXPR | LOOP_EXPR => Some("continue;"),
50 FN_DEF => Some("return;"),
51 _ => None,
52 }?;
53
54 if then_block.syntax().first_child_or_token().map(|t| t.kind() == L_CURLY).is_none() {
55 return None;
56 }
57
58 then_block.syntax().last_child_or_token().filter(|t| t.kind() == R_CURLY)?;
59 let cursor_position = ctx.frange.range.start();
60
61 ctx.add_action(AssistId("convert_to_guarded_return"), "convert to guarded return", |edit| {
62 let if_indent_level = IndentLevel::from_node(&if_expr.syntax());
63 let new_if_expr =
64 if_indent_level.increase_indent(make::if_expression(&expr, early_expression));
65 let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone());
66 let end_of_then = then_block_items.syntax().last_child_or_token().unwrap();
67 let end_of_then =
68 if end_of_then.prev_sibling_or_token().map(|n| n.kind()) == Some(WHITESPACE) {
69 end_of_then.prev_sibling_or_token().unwrap()
70 } else {
71 end_of_then
72 };
73 let mut new_if_and_then_statements = new_if_expr.syntax().children_with_tokens().chain(
74 then_block_items
75 .syntax()
76 .children_with_tokens()
77 .skip(1)
78 .take_while(|i| *i != end_of_then),
79 );
80 let new_block = replace_children(
81 &parent_block.syntax(),
82 RangeInclusive::new(
83 if_expr.clone().syntax().clone().into(),
84 if_expr.syntax().clone().into(),
85 ),
86 &mut new_if_and_then_statements,
87 );
88 edit.target(if_expr.syntax().text_range());
89 edit.replace_ast(parent_block, Block::cast(new_block).unwrap());
90 edit.set_cursor(cursor_position);
91 });
92 ctx.build()
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::helpers::{check_assist, check_assist_not_applicable};
99
100 #[test]
101 fn convert_inside_fn() {
102 check_assist(
103 convert_to_guarded_return,
104 r#"
105 fn main() {
106 bar();
107 if<|> true {
108 foo();
109
110 //comment
111 bar();
112 }
113 }
114 "#,
115 r#"
116 fn main() {
117 bar();
118 if<|> !true {
119 return;
120 }
121 foo();
122
123 //comment
124 bar();
125 }
126 "#,
127 );
128 }
129
130 #[test]
131 fn convert_inside_while() {
132 check_assist(
133 convert_to_guarded_return,
134 r#"
135 fn main() {
136 while true {
137 if<|> true {
138 foo();
139 bar();
140 }
141 }
142 }
143 "#,
144 r#"
145 fn main() {
146 while true {
147 if<|> !true {
148 continue;
149 }
150 foo();
151 bar();
152 }
153 }
154 "#,
155 );
156 }
157
158 #[test]
159 fn convert_inside_loop() {
160 check_assist(
161 convert_to_guarded_return,
162 r#"
163 fn main() {
164 loop {
165 if<|> true {
166 foo();
167 bar();
168 }
169 }
170 }
171 "#,
172 r#"
173 fn main() {
174 loop {
175 if<|> !true {
176 continue;
177 }
178 foo();
179 bar();
180 }
181 }
182 "#,
183 );
184 }
185
186 #[test]
187 fn ignore_already_converted_if() {
188 check_assist_not_applicable(
189 convert_to_guarded_return,
190 r#"
191 fn main() {
192 if<|> true {
193 return;
194 }
195 }
196 "#,
197 );
198 }
199
200 #[test]
201 fn ignore_already_converted_loop() {
202 check_assist_not_applicable(
203 convert_to_guarded_return,
204 r#"
205 fn main() {
206 loop {
207 if<|> true {
208 continue;
209 }
210 }
211 }
212 "#,
213 );
214 }
215
216 #[test]
217 fn ignore_return() {
218 check_assist_not_applicable(
219 convert_to_guarded_return,
220 r#"
221 fn main() {
222 if<|> true {
223 return
224 }
225 }
226 "#,
227 );
228 }
229
230 #[test]
231 fn ignore_else_branch() {
232 check_assist_not_applicable(
233 convert_to_guarded_return,
234 r#"
235 fn main() {
236 if<|> true {
237 foo();
238 } else {
239 bar()
240 }
241 }
242 "#,
243 );
244 }
245
246 #[test]
247 fn ignore_statements_aftert_if() {
248 check_assist_not_applicable(
249 convert_to_guarded_return,
250 r#"
251 fn main() {
252 if<|> true {
253 foo();
254 }
255 bar();
256 }
257 "#,
258 );
259 }
260
261 #[test]
262 fn ignore_statements_inside_if() {
263 check_assist_not_applicable(
264 convert_to_guarded_return,
265 r#"
266 fn main() {
267 if false {
268 if<|> true {
269 foo();
270 }
271 }
272 }
273 "#,
274 );
275 }
276}
diff --git a/crates/ra_assists/src/assists/fill_match_arms.rs b/crates/ra_assists/src/assists/fill_match_arms.rs
index 7335cce09..e3f30b5de 100644
--- a/crates/ra_assists/src/assists/fill_match_arms.rs
+++ b/crates/ra_assists/src/assists/fill_match_arms.rs
@@ -3,7 +3,7 @@
3use std::iter; 3use std::iter;
4 4
5use hir::{db::HirDatabase, Adt, HasSource}; 5use hir::{db::HirDatabase, Adt, HasSource};
6use ra_syntax::ast::{self, make, AstNode, NameOwner}; 6use ra_syntax::ast::{self, edit::IndentLevel, make, AstNode, NameOwner};
7 7
8use crate::{Assist, AssistCtx, AssistId}; 8use crate::{Assist, AssistCtx, AssistId};
9 9
@@ -30,15 +30,19 @@ pub(crate) fn fill_match_arms(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
30 let variant_list = enum_def.variant_list()?; 30 let variant_list = enum_def.variant_list()?;
31 31
32 ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| { 32 ctx.add_action(AssistId("fill_match_arms"), "fill match arms", |edit| {
33 let variants = variant_list.variants(); 33 let indent_level = IndentLevel::from_node(match_arm_list.syntax());
34 let arms = variants 34
35 .filter_map(build_pat) 35 let new_arm_list = {
36 .map(|pat| make::match_arm(iter::once(pat), make::expr_unit())); 36 let variants = variant_list.variants();
37 let new_arm_list = make::match_arm_list(arms); 37 let arms = variants
38 .filter_map(build_pat)
39 .map(|pat| make::match_arm(iter::once(pat), make::expr_unit()));
40 indent_level.increase_indent(make::match_arm_list(arms))
41 };
38 42
39 edit.target(match_expr.syntax().text_range()); 43 edit.target(match_expr.syntax().text_range());
40 edit.set_cursor(expr.syntax().text_range().start()); 44 edit.set_cursor(expr.syntax().text_range().start());
41 edit.replace_node_and_indent(match_arm_list.syntax(), new_arm_list.syntax().text()); 45 edit.replace_ast(match_arm_list, new_arm_list);
42 }); 46 });
43 47
44 ctx.build() 48 ctx.build()
diff --git a/crates/ra_assists/src/assists/move_bounds.rs b/crates/ra_assists/src/assists/move_bounds.rs
index f791d22b0..d2444b6b9 100644
--- a/crates/ra_assists/src/assists/move_bounds.rs
+++ b/crates/ra_assists/src/assists/move_bounds.rs
@@ -18,7 +18,7 @@ pub(crate) fn move_bounds_to_where_clause(mut ctx: AssistCtx<impl HirDatabase>)
18 } 18 }
19 19
20 let parent = type_param_list.syntax().parent()?; 20 let parent = type_param_list.syntax().parent()?;
21 if parent.children_with_tokens().find(|it| it.kind() == WHERE_CLAUSE).is_some() { 21 if parent.children_with_tokens().any(|it| it.kind() == WHERE_CLAUSE) {
22 return None; 22 return None;
23 } 23 }
24 24
diff --git a/crates/ra_assists/src/assists/raw_string.rs b/crates/ra_assists/src/assists/raw_string.rs
index 388ee7e97..2d2e31e51 100644
--- a/crates/ra_assists/src/assists/raw_string.rs
+++ b/crates/ra_assists/src/assists/raw_string.rs
@@ -2,6 +2,7 @@
2 2
3use hir::db::HirDatabase; 3use hir::db::HirDatabase;
4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit}; 4use ra_syntax::{ast::AstNode, ast::Literal, TextRange, TextUnit};
5use rustc_lexer;
5 6
6use crate::{Assist, AssistCtx, AssistId}; 7use crate::{Assist, AssistCtx, AssistId};
7 8
@@ -10,13 +11,51 @@ pub(crate) fn make_raw_string(mut ctx: AssistCtx<impl HirDatabase>) -> Option<As
10 if literal.token().kind() != ra_syntax::SyntaxKind::STRING { 11 if literal.token().kind() != ra_syntax::SyntaxKind::STRING {
11 return None; 12 return None;
12 } 13 }
14 let token = literal.token();
15 let text = token.text().as_str();
16 let usual_string_range = find_usual_string_range(text)?;
17 let start_of_inside = usual_string_range.start().to_usize() + 1;
18 let end_of_inside = usual_string_range.end().to_usize();
19 let inside_str = &text[start_of_inside..end_of_inside];
20 let mut unescaped = String::with_capacity(inside_str.len());
21 let mut error = Ok(());
22 rustc_lexer::unescape::unescape_str(
23 inside_str,
24 &mut |_, unescaped_char| match unescaped_char {
25 Ok(c) => unescaped.push(c),
26 Err(_) => error = Err(()),
27 },
28 );
29 if error.is_err() {
30 return None;
31 }
13 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| { 32 ctx.add_action(AssistId("make_raw_string"), "make raw string", |edit| {
14 edit.target(literal.syntax().text_range()); 33 edit.target(literal.syntax().text_range());
15 edit.insert(literal.syntax().text_range().start(), "r"); 34 let max_hash_streak = count_hashes(&unescaped);
35 let mut hashes = String::with_capacity(max_hash_streak + 1);
36 for _ in 0..hashes.capacity() {
37 hashes.push('#');
38 }
39 edit.replace(
40 literal.syntax().text_range(),
41 format!("r{}\"{}\"{}", hashes, unescaped, hashes),
42 );
16 }); 43 });
17 ctx.build() 44 ctx.build()
18} 45}
19 46
47fn count_hashes(s: &str) -> usize {
48 let mut max_hash_streak = 0usize;
49 for idx in s.match_indices("\"#").map(|(i, _)| i) {
50 let (_, sub) = s.split_at(idx + 1);
51 let nb_hash = sub.chars().take_while(|c| *c == '#').count();
52 if nb_hash > max_hash_streak {
53 max_hash_streak = nb_hash;
54 }
55 }
56 max_hash_streak
57}
58
20fn find_usual_string_range(s: &str) -> Option<TextRange> { 59fn find_usual_string_range(s: &str) -> Option<TextRange> {
21 Some(TextRange::from_to( 60 Some(TextRange::from_to(
22 TextUnit::from(s.find('"')? as u32), 61 TextUnit::from(s.find('"')? as u32),
@@ -94,10 +133,10 @@ mod test {
94 make_raw_string, 133 make_raw_string,
95 r#" 134 r#"
96 fn f() { 135 fn f() {
97 let s = <|>"random string"; 136 let s = <|>"random\nstring";
98 } 137 }
99 "#, 138 "#,
100 r#""random string""#, 139 r#""random\nstring""#,
101 ); 140 );
102 } 141 }
103 142
@@ -107,44 +146,69 @@ mod test {
107 make_raw_string, 146 make_raw_string,
108 r#" 147 r#"
109 fn f() { 148 fn f() {
110 let s = <|>"random string"; 149 let s = <|>"random\nstring";
111 } 150 }
112 "#, 151 "#,
113 r#" 152 r##"
114 fn f() { 153 fn f() {
115 let s = <|>r"random string"; 154 let s = <|>r#"random
155string"#;
116 } 156 }
117 "#, 157 "##,
118 ) 158 )
119 } 159 }
120 160
121 #[test] 161 #[test]
122 fn make_raw_string_with_escaped_works() { 162 fn make_raw_string_hashes_inside_works() {
123 check_assist( 163 check_assist(
124 make_raw_string, 164 make_raw_string,
125 r#" 165 r###"
126 fn f() { 166 fn f() {
127 let s = <|>"random\nstring"; 167 let s = <|>"#random##\nstring";
128 } 168 }
129 "#, 169 "###,
130 r#" 170 r####"
131 fn f() { 171 fn f() {
132 let s = <|>r"random\nstring"; 172 let s = <|>r#"#random##
173string"#;
133 } 174 }
134 "#, 175 "####,
135 ) 176 )
136 } 177 }
137 178
138 #[test] 179 #[test]
139 fn make_raw_string_not_works() { 180 fn make_raw_string_closing_hashes_inside_works() {
140 check_assist_not_applicable( 181 check_assist(
182 make_raw_string,
183 r###"
184 fn f() {
185 let s = <|>"#random\"##\nstring";
186 }
187 "###,
188 r####"
189 fn f() {
190 let s = <|>r###"#random"##
191string"###;
192 }
193 "####,
194 )
195 }
196
197 #[test]
198 fn make_raw_string_nothing_to_unescape_works() {
199 check_assist(
141 make_raw_string, 200 make_raw_string,
142 r#" 201 r#"
143 fn f() { 202 fn f() {
144 let s = <|>r"random string"; 203 let s = <|>"random string";
145 } 204 }
146 "#, 205 "#,
147 ); 206 r##"
207 fn f() {
208 let s = <|>r#"random string"#;
209 }
210 "##,
211 )
148 } 212 }
149 213
150 #[test] 214 #[test]
@@ -369,4 +433,14 @@ mod test {
369 "#, 433 "#,
370 ); 434 );
371 } 435 }
436
437 #[test]
438 fn count_hashes_test() {
439 assert_eq!(0, count_hashes("abc"));
440 assert_eq!(0, count_hashes("###"));
441 assert_eq!(1, count_hashes("\"#abc"));
442 assert_eq!(0, count_hashes("#abc"));
443 assert_eq!(2, count_hashes("#ab\"##c"));
444 assert_eq!(4, count_hashes("#ab\"##\"####c"));
445 }
372} 446}
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index d2376c475..ab77b46a9 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -108,6 +108,7 @@ mod assists {
108 mod add_missing_impl_members; 108 mod add_missing_impl_members;
109 mod move_guard; 109 mod move_guard;
110 mod move_bounds; 110 mod move_bounds;
111 mod early_return;
111 112
112 pub(crate) fn all<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] { 113 pub(crate) fn all<DB: HirDatabase>() -> &'static [fn(AssistCtx<DB>) -> Option<Assist>] {
113 &[ 114 &[
@@ -135,6 +136,7 @@ mod assists {
135 raw_string::make_raw_string, 136 raw_string::make_raw_string,
136 raw_string::make_usual_string, 137 raw_string::make_usual_string,
137 raw_string::remove_hash, 138 raw_string::remove_hash,
139 early_return::convert_to_guarded_return,
138 ] 140 ]
139 } 141 }
140} 142}
diff --git a/crates/ra_batch/Cargo.toml b/crates/ra_batch/Cargo.toml
index 62850746f..c85da7a2c 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.4.0" 12ra_vfs = "0.5.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 a5fc2a23e..df49eb13d 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -43,8 +43,12 @@ pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId,
43 ); 43 );
44 44
45 // FIXME: cfg options? 45 // FIXME: cfg options?
46 let default_cfg_options = 46 let default_cfg_options = {
47 get_rustc_cfg_options().atom("test".into()).atom("debug_assertion".into()); 47 let mut opts = get_rustc_cfg_options();
48 opts.insert_atom("test".into());
49 opts.insert_atom("debug_assertion".into());
50 opts
51 };
48 52
49 let (crate_graph, _crate_names) = 53 let (crate_graph, _crate_names) =
50 ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| { 54 ws.to_crate_graph(&default_cfg_options, &mut |path: &Path| {
@@ -137,14 +141,8 @@ mod tests {
137 #[test] 141 #[test]
138 fn test_loading_rust_analyzer() { 142 fn test_loading_rust_analyzer() {
139 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); 143 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
140 let (host, roots) = load_cargo(path).unwrap(); 144 let (host, _roots) = load_cargo(path).unwrap();
141 let mut n_crates = 0; 145 let n_crates = Crate::all(host.raw_database()).len();
142 for (root, _) in roots {
143 for _krate in Crate::source_root_crates(host.raw_database(), root) {
144 n_crates += 1;
145 }
146 }
147
148 // RA has quite a few crates, but the exact count doesn't matter 146 // RA has quite a few crates, but the exact count doesn't matter
149 assert!(n_crates > 20); 147 assert!(n_crates > 20);
150 } 148 }
diff --git a/crates/ra_cfg/src/lib.rs b/crates/ra_cfg/src/lib.rs
index e1c92fbba..1bee3eb99 100644
--- a/crates/ra_cfg/src/lib.rs
+++ b/crates/ra_cfg/src/lib.rs
@@ -36,26 +36,20 @@ impl CfgOptions {
36 self.check(&parse_cfg(attr)) 36 self.check(&parse_cfg(attr))
37 } 37 }
38 38
39 pub fn atom(mut self, name: SmolStr) -> CfgOptions { 39 pub fn insert_atom(&mut self, key: SmolStr) {
40 self.atoms.insert(name); 40 self.atoms.insert(key);
41 self
42 } 41 }
43 42
44 pub fn key_value(mut self, key: SmolStr, value: SmolStr) -> CfgOptions { 43 pub fn remove_atom(&mut self, name: &str) {
45 self.key_values.insert((key, value)); 44 self.atoms.remove(name);
46 self
47 } 45 }
48 46
49 /// Shortcut to set features 47 pub fn insert_key_value(&mut self, key: SmolStr, value: SmolStr) {
50 pub fn features(mut self, iter: impl IntoIterator<Item = SmolStr>) -> CfgOptions { 48 self.key_values.insert((key, value));
51 for feat in iter {
52 self = self.key_value("feature".into(), feat);
53 }
54 self
55 } 49 }
56 50
57 pub fn remove_atom(mut self, name: &SmolStr) -> CfgOptions { 51 /// Shortcut to set features
58 self.atoms.remove(name); 52 pub fn insert_features(&mut self, iter: impl IntoIterator<Item = SmolStr>) {
59 self 53 iter.into_iter().for_each(|feat| self.insert_key_value("feature".into(), feat));
60 } 54 }
61} 55}
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index 67e727a88..fcd102e8b 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -8,7 +8,7 @@ publish = false
8[dependencies] 8[dependencies]
9pico-args = "0.3.0" 9pico-args = "0.3.0"
10flexi_logger = "0.14.0" 10flexi_logger = "0.14.0"
11indicatif = "0.11.0" 11indicatif = "0.12.0"
12 12
13ra_syntax = { path = "../ra_syntax" } 13ra_syntax = { path = "../ra_syntax" }
14ra_ide_api = { path = "../ra_ide_api" } 14ra_ide_api = { path = "../ra_ide_api" }
diff --git a/crates/ra_cli/src/analysis_bench.rs b/crates/ra_cli/src/analysis_bench.rs
index 727f1e62b..8bbe5d9e8 100644
--- a/crates/ra_cli/src/analysis_bench.rs
+++ b/crates/ra_cli/src/analysis_bench.rs
@@ -8,7 +8,7 @@ use std::{
8 8
9use ra_db::{ 9use ra_db::{
10 salsa::{Database, Durability}, 10 salsa::{Database, Durability},
11 FileId, SourceDatabase, 11 FileId, SourceDatabaseExt,
12}; 12};
13use ra_ide_api::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol}; 13use ra_ide_api::{Analysis, AnalysisChange, AnalysisHost, FilePosition, LineCol};
14 14
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index a8a110bd9..cda5cafb8 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,7 +2,7 @@
2 2
3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant}; 3use std::{collections::HashSet, fmt::Write, path::Path, time::Instant};
4 4
5use ra_db::SourceDatabase; 5use ra_db::SourceDatabaseExt;
6use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk}; 6use ra_hir::{AssocItem, Crate, HasBodySource, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
7use ra_syntax::AstNode; 7use ra_syntax::AstNode;
8 8
@@ -22,16 +22,29 @@ pub fn run(
22 let mut num_crates = 0; 22 let mut num_crates = 0;
23 let mut visited_modules = HashSet::new(); 23 let mut visited_modules = HashSet::new();
24 let mut visit_queue = Vec::new(); 24 let mut visit_queue = Vec::new();
25 for (source_root_id, project_root) in roots { 25
26 if project_root.is_member() { 26 let members = roots
27 for krate in Crate::source_root_crates(db, source_root_id) { 27 .into_iter()
28 num_crates += 1; 28 .filter_map(
29 let module = 29 |(source_root_id, project_root)| {
30 krate.root_module(db).expect("crate in source root without root module"); 30 if project_root.is_member() {
31 visit_queue.push(module); 31 Some(source_root_id)
32 } 32 } else {
33 None
34 }
35 },
36 )
37 .collect::<HashSet<_>>();
38
39 for krate in Crate::all(db) {
40 let module = krate.root_module(db).expect("crate without root module");
41 let file_id = module.definition_source(db).file_id;
42 if members.contains(&db.file_source_root(file_id.original_file(db))) {
43 num_crates += 1;
44 visit_queue.push(module);
33 } 45 }
34 } 46 }
47
35 println!("Crates in this dir: {}", num_crates); 48 println!("Crates in this dir: {}", num_crates);
36 let mut num_decls = 0; 49 let mut num_decls = 0;
37 let mut funcs = Vec::new(); 50 let mut funcs = Vec::new();
@@ -130,7 +143,7 @@ pub fn run(
130 ); 143 );
131 bar.println(format!( 144 bar.println(format!(
132 "{} {}:{}-{}:{}: Expected {}, got {}", 145 "{} {}:{}-{}:{}: Expected {}, got {}",
133 path.display(), 146 path,
134 start.line + 1, 147 start.line + 1,
135 start.col_utf16, 148 start.col_utf16,
136 end.line + 1, 149 end.line + 1,
diff --git a/crates/ra_db/Cargo.toml b/crates/ra_db/Cargo.toml
index c141f1a88..3394ae8ce 100644
--- a/crates/ra_db/Cargo.toml
+++ b/crates/ra_db/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8salsa = "0.13.0" 8salsa = "0.13.0"
9relative-path = "0.4.0" 9relative-path = "1.0.0"
10rustc-hash = "1.0" 10rustc-hash = "1.0"
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index 23148096c..eafa95921 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -48,9 +48,6 @@ impl SourceRoot {
48 pub fn new_library() -> SourceRoot { 48 pub fn new_library() -> SourceRoot {
49 SourceRoot { is_library: true, ..SourceRoot::new() } 49 SourceRoot { is_library: true, ..SourceRoot::new() }
50 } 50 }
51 pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
52 self.files.get(path).copied()
53 }
54 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) { 51 pub fn insert_file(&mut self, path: RelativePathBuf, file_id: FileId) {
55 self.files.insert(path, file_id); 52 self.files.insert(path, file_id);
56 } 53 }
@@ -60,6 +57,9 @@ impl SourceRoot {
60 pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ { 57 pub fn walk(&self) -> impl Iterator<Item = FileId> + '_ {
61 self.files.values().copied() 58 self.files.values().copied()
62 } 59 }
60 pub fn file_by_relative_path(&self, path: &RelativePath) -> Option<FileId> {
61 self.files.get(path).copied()
62 }
63} 63}
64 64
65/// `CrateGraph` is a bit of information which turns a set of text files into a 65/// `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 603daed37..fc5d6d396 100644
--- a/crates/ra_db/src/lib.rs
+++ b/crates/ra_db/src/lib.rs
@@ -6,7 +6,7 @@ use std::{panic, sync::Arc};
6 6
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit}; 8use ra_syntax::{ast, Parse, SourceFile, TextRange, TextUnit};
9use relative_path::RelativePathBuf; 9use relative_path::{RelativePath, RelativePathBuf};
10 10
11pub use crate::{ 11pub use crate::{
12 cancellation::Canceled, 12 cancellation::Canceled,
@@ -64,16 +64,39 @@ pub struct FileRange {
64 64
65pub const DEFAULT_LRU_CAP: usize = 128; 65pub const DEFAULT_LRU_CAP: usize = 128;
66 66
67pub trait FileLoader {
68 /// Text of the file.
69 fn file_text(&self, file_id: FileId) -> Arc<String>;
70 fn resolve_relative_path(&self, anchor: FileId, relative_path: &RelativePath)
71 -> Option<FileId>;
72 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>;
73}
74
67/// Database which stores all significant input facts: source code and project 75/// Database which stores all significant input facts: source code and project
68/// model. Everything else in rust-analyzer is derived from these queries. 76/// model. Everything else in rust-analyzer is derived from these queries.
69#[salsa::query_group(SourceDatabaseStorage)] 77#[salsa::query_group(SourceDatabaseStorage)]
70pub trait SourceDatabase: CheckCanceled + std::fmt::Debug { 78pub trait SourceDatabase: CheckCanceled + FileLoader + std::fmt::Debug {
71 /// Text of the file.
72 #[salsa::input]
73 fn file_text(&self, file_id: FileId) -> Arc<String>;
74 // Parses the file into the syntax tree. 79 // Parses the file into the syntax tree.
75 #[salsa::invoke(parse_query)] 80 #[salsa::invoke(parse_query)]
76 fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>; 81 fn parse(&self, file_id: FileId) -> Parse<ast::SourceFile>;
82
83 /// The crate graph.
84 #[salsa::input]
85 fn crate_graph(&self) -> Arc<CrateGraph>;
86}
87
88fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> {
89 let _p = profile("parse_query");
90 let text = db.file_text(file_id);
91 SourceFile::parse(&*text)
92}
93
94/// We don't want to give HIR knowledge of source roots, hence we extract these
95/// methods into a separate DB.
96#[salsa::query_group(SourceDatabaseExtStorage)]
97pub trait SourceDatabaseExt: SourceDatabase {
98 #[salsa::input]
99 fn file_text(&self, file_id: FileId) -> Arc<String>;
77 /// Path to a file, relative to the root of its source root. 100 /// Path to a file, relative to the root of its source root.
78 #[salsa::input] 101 #[salsa::input]
79 fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf; 102 fn file_relative_path(&self, file_id: FileId) -> RelativePathBuf;
@@ -83,21 +106,48 @@ pub trait SourceDatabase: CheckCanceled + std::fmt::Debug {
83 /// Contents of the source root. 106 /// Contents of the source root.
84 #[salsa::input] 107 #[salsa::input]
85 fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; 108 fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>;
109
86 fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>; 110 fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>;
87 /// The crate graph.
88 #[salsa::input]
89 fn crate_graph(&self) -> Arc<CrateGraph>;
90} 111}
91 112
92fn source_root_crates(db: &impl SourceDatabase, id: SourceRootId) -> Arc<Vec<CrateId>> { 113fn source_root_crates(
114 db: &(impl SourceDatabaseExt + SourceDatabase),
115 id: SourceRootId,
116) -> Arc<Vec<CrateId>> {
93 let root = db.source_root(id); 117 let root = db.source_root(id);
94 let graph = db.crate_graph(); 118 let graph = db.crate_graph();
95 let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>(); 119 let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>();
96 Arc::new(res) 120 Arc::new(res)
97} 121}
98 122
99fn parse_query(db: &impl SourceDatabase, file_id: FileId) -> Parse<ast::SourceFile> { 123/// Silly workaround for cyclic deps between the traits
100 let _p = profile("parse_query"); 124pub struct FileLoaderDelegate<T>(pub T);
101 let text = db.file_text(file_id); 125
102 SourceFile::parse(&*text) 126impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> {
127 fn file_text(&self, file_id: FileId) -> Arc<String> {
128 SourceDatabaseExt::file_text(self.0, file_id)
129 }
130 fn resolve_relative_path(
131 &self,
132 anchor: FileId,
133 relative_path: &RelativePath,
134 ) -> Option<FileId> {
135 let path = {
136 let mut path = self.0.file_relative_path(anchor);
137 // Workaround for relative path API: turn `lib.rs` into ``.
138 if !path.pop() {
139 path = RelativePathBuf::default();
140 }
141 path.push(relative_path);
142 path.normalize()
143 };
144 let source_root = self.0.file_source_root(anchor);
145 let source_root = self.0.source_root(source_root);
146 source_root.file_by_relative_path(&path)
147 }
148
149 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
150 let source_root = self.0.file_source_root(file_id);
151 self.0.source_root_crates(source_root)
152 }
103} 153}
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index cc117f84d..edf1fa49b 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -5,9 +5,9 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8arrayvec = "0.4.10" 8arrayvec = "0.5.1"
9log = "0.4.5" 9log = "0.4.5"
10relative-path = "0.4.0" 10relative-path = "1.0.0"
11rustc-hash = "1.0" 11rustc-hash = "1.0"
12parking_lot = "0.9.0" 12parking_lot = "0.9.0"
13ena = "0.13" 13ena = "0.13"
diff --git a/crates/ra_hir/src/adt.rs b/crates/ra_hir/src/adt.rs
index 99d286215..3e9cd3c63 100644
--- a/crates/ra_hir/src/adt.rs
+++ b/crates/ra_hir/src/adt.rs
@@ -9,7 +9,7 @@ use ra_syntax::ast::{self, NameOwner, StructKind, TypeAscriptionOwner};
9use crate::{ 9use crate::{
10 db::{AstDatabase, DefDatabase, HirDatabase}, 10 db::{AstDatabase, DefDatabase, HirDatabase},
11 type_ref::TypeRef, 11 type_ref::TypeRef,
12 AsName, Enum, EnumVariant, FieldSource, HasSource, Name, Source, Struct, StructField, 12 AsName, Enum, EnumVariant, FieldSource, HasSource, Module, Name, Source, Struct, StructField,
13}; 13};
14 14
15impl Struct { 15impl Struct {
@@ -170,12 +170,20 @@ impl VariantDef {
170 } 170 }
171 } 171 }
172 172
173 pub(crate) fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> { 173 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
174 match self { 174 match self {
175 VariantDef::Struct(it) => it.field(db, name), 175 VariantDef::Struct(it) => it.field(db, name),
176 VariantDef::EnumVariant(it) => it.field(db, name), 176 VariantDef::EnumVariant(it) => it.field(db, name),
177 } 177 }
178 } 178 }
179
180 pub fn module(self, db: &impl HirDatabase) -> Module {
181 match self {
182 VariantDef::Struct(it) => it.module(db),
183 VariantDef::EnumVariant(it) => it.module(db),
184 }
185 }
186
179 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 187 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
180 match self { 188 match self {
181 VariantDef::Struct(it) => it.variant_data(db), 189 VariantDef::Struct(it) => it.variant_data(db),
diff --git a/crates/ra_hir/src/attr.rs b/crates/ra_hir/src/attr.rs
index f67e80bfd..bd159a566 100644
--- a/crates/ra_hir/src/attr.rs
+++ b/crates/ra_hir/src/attr.rs
@@ -63,14 +63,24 @@ impl Attr {
63 self.path.as_ident().map_or(false, |s| s.to_string() == name) 63 self.path.as_ident().map_or(false, |s| s.to_string() == name)
64 } 64 }
65 65
66 // FIXME: handle cfg_attr :-)
66 pub(crate) fn as_cfg(&self) -> Option<&Subtree> { 67 pub(crate) fn as_cfg(&self) -> Option<&Subtree> {
67 if self.is_simple_atom("cfg") { 68 if !self.is_simple_atom("cfg") {
68 match &self.input { 69 return None;
69 Some(AttrInput::TokenTree(subtree)) => Some(subtree), 70 }
70 _ => None, 71 match &self.input {
71 } 72 Some(AttrInput::TokenTree(subtree)) => Some(subtree),
72 } else { 73 _ => None,
73 None 74 }
75 }
76
77 pub(crate) fn as_path(&self) -> Option<&SmolStr> {
78 if !self.is_simple_atom("path") {
79 return None;
80 }
81 match &self.input {
82 Some(AttrInput::Literal(it)) => Some(it),
83 _ => None,
74 } 84 }
75 } 85 }
76 86
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index e3a7e8e3c..8eb3c577d 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -5,7 +5,7 @@ pub(crate) mod docs;
5 5
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use ra_db::{CrateId, Edition, FileId, SourceRootId}; 8use ra_db::{CrateId, Edition, FileId};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
10 10
11use crate::{ 11use crate::{
@@ -24,7 +24,7 @@ use crate::{
24 U8, USIZE, 24 U8, USIZE,
25 }, 25 },
26 nameres::{CrateModuleId, ImportId, ModuleScope, Namespace}, 26 nameres::{CrateModuleId, ImportId, ModuleScope, Namespace},
27 resolve::{Resolver, TypeNs}, 27 resolve::{Resolver, Scope, TypeNs},
28 traits::TraitData, 28 traits::TraitData,
29 ty::{ 29 ty::{
30 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness}, 30 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness},
@@ -76,10 +76,8 @@ impl Crate {
76 crate_graph.edition(self.crate_id) 76 crate_graph.edition(self.crate_id)
77 } 77 }
78 78
79 // FIXME: should this be in source_binder? 79 pub fn all(db: &impl DefDatabase) -> Vec<Crate> {
80 pub fn source_root_crates(db: &impl DefDatabase, source_root: SourceRootId) -> Vec<Crate> { 80 db.crate_graph().iter().map(|crate_id| Crate { crate_id }).collect()
81 let crate_ids = db.source_root_crates(source_root);
82 crate_ids.iter().map(|&crate_id| Crate { crate_id }).collect()
83 } 81 }
84} 82}
85 83
@@ -465,7 +463,7 @@ impl Enum {
465 // ...and add generic params, if present 463 // ...and add generic params, if present
466 let p = self.generic_params(db); 464 let p = self.generic_params(db);
467 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r }; 465 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
468 r 466 r.push_scope(Scope::AdtScope(self.into()))
469 } 467 }
470} 468}
471 469
@@ -569,6 +567,14 @@ impl DefWithBody {
569 DefWithBody::Static(s) => s.krate(db), 567 DefWithBody::Static(s) => s.krate(db),
570 } 568 }
571 } 569 }
570
571 pub fn module(self, db: &impl HirDatabase) -> Module {
572 match self {
573 DefWithBody::Const(c) => c.module(db),
574 DefWithBody::Function(f) => f.module(db),
575 DefWithBody::Static(s) => s.module(db),
576 }
577 }
572} 578}
573 579
574pub trait HasBody: Copy { 580pub trait HasBody: Copy {
@@ -789,6 +795,20 @@ impl Const {
789 ImplBlock::containing(module_impls, self.into()) 795 ImplBlock::containing(module_impls, self.into())
790 } 796 }
791 797
798 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
799 db.trait_items_index(self.module(db)).get_parent_trait(self.into())
800 }
801
802 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
803 if let Some(impl_block) = self.impl_block(db) {
804 Some(impl_block.into())
805 } else if let Some(trait_) = self.parent_trait(db) {
806 Some(trait_.into())
807 } else {
808 None
809 }
810 }
811
792 // FIXME: move to a more general type for 'body-having' items 812 // FIXME: move to a more general type for 'body-having' items
793 /// Builds a resolver for code inside this item. 813 /// Builds a resolver for code inside this item.
794 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver { 814 pub(crate) fn resolver(self, db: &impl HirDatabase) -> Resolver {
@@ -1075,3 +1095,13 @@ impl From<AssocItem> for crate::generics::GenericDef {
1075 } 1095 }
1076 } 1096 }
1077} 1097}
1098
1099impl AssocItem {
1100 pub fn module(self, db: &impl DefDatabase) -> Module {
1101 match self {
1102 AssocItem::Function(f) => f.module(db),
1103 AssocItem::Const(c) => c.module(db),
1104 AssocItem::TypeAlias(t) => t.module(db),
1105 }
1106 }
1107}
diff --git a/crates/ra_hir/src/code_model/docs.rs b/crates/ra_hir/src/code_model/docs.rs
index 9675e397f..8533b4f5e 100644
--- a/crates/ra_hir/src/code_model/docs.rs
+++ b/crates/ra_hir/src/code_model/docs.rs
@@ -6,21 +6,19 @@ use ra_syntax::ast;
6 6
7use crate::{ 7use crate::{
8 db::{AstDatabase, DefDatabase, HirDatabase}, 8 db::{AstDatabase, DefDatabase, HirDatabase},
9 Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static, Struct, 9 Adt, Const, Enum, EnumVariant, FieldSource, Function, HasSource, MacroDef, Module, Static,
10 StructField, Trait, TypeAlias, Union, 10 Struct, StructField, Trait, TypeAlias, Union,
11}; 11};
12 12
13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 13#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
14pub enum DocDef { 14pub enum DocDef {
15 Module(Module), 15 Module(Module),
16 StructField(StructField), 16 StructField(StructField),
17 Struct(Struct), 17 Adt(Adt),
18 Enum(Enum),
19 EnumVariant(EnumVariant), 18 EnumVariant(EnumVariant),
20 Static(Static), 19 Static(Static),
21 Const(Const), 20 Const(Const),
22 Function(Function), 21 Function(Function),
23 Union(Union),
24 Trait(Trait), 22 Trait(Trait),
25 TypeAlias(TypeAlias), 23 TypeAlias(TypeAlias),
26 MacroDef(MacroDef), 24 MacroDef(MacroDef),
@@ -29,13 +27,11 @@ pub enum DocDef {
29impl_froms!( 27impl_froms!(
30 DocDef: Module, 28 DocDef: Module,
31 StructField, 29 StructField,
32 Struct, 30 Adt(Struct, Enum, Union),
33 Enum,
34 EnumVariant, 31 EnumVariant,
35 Static, 32 Static,
36 Const, 33 Const,
37 Function, 34 Function,
38 Union,
39 Trait, 35 Trait,
40 TypeAlias, 36 TypeAlias,
41 MacroDef 37 MacroDef
@@ -79,13 +75,15 @@ pub(crate) fn documentation_query(
79 FieldSource::Named(named) => docs_from_ast(&named), 75 FieldSource::Named(named) => docs_from_ast(&named),
80 FieldSource::Pos(..) => None, 76 FieldSource::Pos(..) => None,
81 }, 77 },
82 DocDef::Struct(it) => docs_from_ast(&it.source(db).ast), 78 DocDef::Adt(it) => match it {
83 DocDef::Enum(it) => docs_from_ast(&it.source(db).ast), 79 Adt::Struct(it) => docs_from_ast(&it.source(db).ast),
80 Adt::Enum(it) => docs_from_ast(&it.source(db).ast),
81 Adt::Union(it) => docs_from_ast(&it.source(db).ast),
82 },
84 DocDef::EnumVariant(it) => docs_from_ast(&it.source(db).ast), 83 DocDef::EnumVariant(it) => docs_from_ast(&it.source(db).ast),
85 DocDef::Static(it) => docs_from_ast(&it.source(db).ast), 84 DocDef::Static(it) => docs_from_ast(&it.source(db).ast),
86 DocDef::Const(it) => docs_from_ast(&it.source(db).ast), 85 DocDef::Const(it) => docs_from_ast(&it.source(db).ast),
87 DocDef::Function(it) => docs_from_ast(&it.source(db).ast), 86 DocDef::Function(it) => docs_from_ast(&it.source(db).ast),
88 DocDef::Union(it) => docs_from_ast(&it.source(db).ast),
89 DocDef::Trait(it) => docs_from_ast(&it.source(db).ast), 87 DocDef::Trait(it) => docs_from_ast(&it.source(db).ast),
90 DocDef::TypeAlias(it) => docs_from_ast(&it.source(db).ast), 88 DocDef::TypeAlias(it) => docs_from_ast(&it.source(db).ast),
91 DocDef::MacroDef(it) => docs_from_ast(&it.source(db).ast), 89 DocDef::MacroDef(it) => docs_from_ast(&it.source(db).ast),
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index 73d7d6fb6..489a3b19c 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -111,37 +111,37 @@ pub trait DefDatabase: InternDatabase + HirDebugDatabase {
111 #[salsa::invoke(CrateDefMap::crate_def_map_query)] 111 #[salsa::invoke(CrateDefMap::crate_def_map_query)]
112 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>; 112 fn crate_def_map(&self, krate: Crate) -> Arc<CrateDefMap>;
113 113
114 #[salsa::invoke(crate::impl_block::impls_in_module_with_source_map_query)] 114 #[salsa::invoke(ModuleImplBlocks::impls_in_module_with_source_map_query)]
115 fn impls_in_module_with_source_map( 115 fn impls_in_module_with_source_map(
116 &self, 116 &self,
117 module: Module, 117 module: Module,
118 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>); 118 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>);
119 119
120 #[salsa::invoke(crate::impl_block::impls_in_module)] 120 #[salsa::invoke(ModuleImplBlocks::impls_in_module_query)]
121 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>; 121 fn impls_in_module(&self, module: Module) -> Arc<ModuleImplBlocks>;
122 122
123 #[salsa::invoke(crate::generics::GenericParams::generic_params_query)] 123 #[salsa::invoke(crate::generics::GenericParams::generic_params_query)]
124 fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>; 124 fn generic_params(&self, def: GenericDef) -> Arc<GenericParams>;
125 125
126 #[salsa::invoke(crate::FnData::fn_data_query)] 126 #[salsa::invoke(FnData::fn_data_query)]
127 fn fn_data(&self, func: Function) -> Arc<FnData>; 127 fn fn_data(&self, func: Function) -> Arc<FnData>;
128 128
129 #[salsa::invoke(crate::type_alias::type_alias_data_query)] 129 #[salsa::invoke(TypeAliasData::type_alias_data_query)]
130 fn type_alias_data(&self, typ: TypeAlias) -> Arc<TypeAliasData>; 130 fn type_alias_data(&self, typ: TypeAlias) -> Arc<TypeAliasData>;
131 131
132 #[salsa::invoke(crate::ConstData::const_data_query)] 132 #[salsa::invoke(ConstData::const_data_query)]
133 fn const_data(&self, konst: Const) -> Arc<ConstData>; 133 fn const_data(&self, konst: Const) -> Arc<ConstData>;
134 134
135 #[salsa::invoke(crate::ConstData::static_data_query)] 135 #[salsa::invoke(ConstData::static_data_query)]
136 fn static_data(&self, konst: Static) -> Arc<ConstData>; 136 fn static_data(&self, konst: Static) -> Arc<ConstData>;
137 137
138 #[salsa::invoke(crate::lang_item::LangItems::module_lang_items_query)] 138 #[salsa::invoke(LangItems::module_lang_items_query)]
139 fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>; 139 fn module_lang_items(&self, module: Module) -> Option<Arc<LangItems>>;
140 140
141 #[salsa::invoke(crate::lang_item::LangItems::crate_lang_items_query)] 141 #[salsa::invoke(LangItems::crate_lang_items_query)]
142 fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>; 142 fn crate_lang_items(&self, krate: Crate) -> Arc<LangItems>;
143 143
144 #[salsa::invoke(crate::lang_item::LangItems::lang_item_query)] 144 #[salsa::invoke(LangItems::lang_item_query)]
145 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>; 145 fn lang_item(&self, start_crate: Crate, item: SmolStr) -> Option<LangItemTarget>;
146 146
147 #[salsa::invoke(crate::code_model::docs::documentation_query)] 147 #[salsa::invoke(crate::code_model::docs::documentation_query)]
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
index 87f3180c3..48b69000b 100644
--- a/crates/ra_hir/src/debug.rs
+++ b/crates/ra_hir/src/debug.rs
@@ -22,7 +22,7 @@ use std::fmt;
22 22
23use ra_db::{CrateId, FileId}; 23use ra_db::{CrateId, FileId};
24 24
25use crate::{db::HirDatabase, Crate, Module, Name}; 25use crate::{db::HirDatabase, Crate, HirFileId, Module, Name};
26 26
27impl Crate { 27impl Crate {
28 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ { 28 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
@@ -36,6 +36,12 @@ impl Module {
36 } 36 }
37} 37}
38 38
39impl HirFileId {
40 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
41 debug_fn(move |fmt| db.debug_hir_file_id(self, fmt))
42 }
43}
44
39pub trait HirDebugHelper: HirDatabase { 45pub trait HirDebugHelper: HirDatabase {
40 fn crate_name(&self, _krate: CrateId) -> Option<String> { 46 fn crate_name(&self, _krate: CrateId) -> Option<String> {
41 None 47 None
@@ -48,6 +54,7 @@ pub trait HirDebugHelper: HirDatabase {
48pub trait HirDebugDatabase { 54pub trait HirDebugDatabase {
49 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; 55 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
50 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result; 56 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
57 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
51} 58}
52 59
53impl<DB: HirDebugHelper> HirDebugDatabase for DB { 60impl<DB: HirDebugHelper> HirDebugDatabase for DB {
@@ -62,12 +69,19 @@ impl<DB: HirDebugHelper> HirDebugDatabase for DB {
62 69
63 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 70 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
64 let file_id = module.definition_source(self).file_id.original_file(self); 71 let file_id = module.definition_source(self).file_id.original_file(self);
65 let path = self.file_path(file_id); 72 let path = self.file_path(file_id).unwrap_or_else(|| "N/A".to_string());
66 fmt.debug_struct("Module") 73 fmt.debug_struct("Module")
67 .field("name", &module.name(self).unwrap_or_else(Name::missing)) 74 .field("name", &module.name(self).unwrap_or_else(Name::missing))
68 .field("path", &path.unwrap_or_else(|| "N/A".to_string())) 75 .field("path", &path)
69 .finish() 76 .finish()
70 } 77 }
78
79 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
80 let original = file_id.original_file(self);
81 let path = self.file_path(original).unwrap_or_else(|| "N/A".to_string());
82 let is_macro = file_id != original.into();
83 fmt.debug_struct("HirFileId").field("path", &path).field("macro", &is_macro).finish()
84 }
71} 85}
72 86
73fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug { 87fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index a012f33f7..f80d8eb5f 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -189,14 +189,14 @@ impl Module {
189 ModuleSource::SourceFile(_) => None, 189 ModuleSource::SourceFile(_) => None,
190 }; 190 };
191 191
192 let source_root_id = db.file_source_root(src.file_id.original_file(db)); 192 db.relevant_crates(src.file_id.original_file(db))
193 db.source_root_crates(source_root_id).iter().map(|&crate_id| Crate { crate_id }).find_map( 193 .iter()
194 |krate| { 194 .map(|&crate_id| Crate { crate_id })
195 .find_map(|krate| {
195 let def_map = db.crate_def_map(krate); 196 let def_map = db.crate_def_map(krate);
196 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?; 197 let module_id = def_map.find_module_by_source(src.file_id, decl_id)?;
197 Some(Module { krate, module_id }) 198 Some(Module { krate, module_id })
198 }, 199 })
199 )
200 } 200 }
201} 201}
202 202
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index a3b65cc79..499dcafea 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -50,16 +50,6 @@ impl HirFileId {
50 } 50 }
51 } 51 }
52 52
53 /// XXX: this is a temporary function, which should go away when we implement the
54 /// nameresolution+macro expansion combo. Prefer using `original_file` if
55 /// possible.
56 pub fn as_original_file(self) -> FileId {
57 match self.0 {
58 HirFileIdRepr::File(file_id) => file_id,
59 HirFileIdRepr::Macro(_r) => panic!("macro generated file: {:?}", self),
60 }
61 }
62
63 /// Get the crate which the macro lives in, if it is a macro file. 53 /// Get the crate which the macro lives in, if it is a macro file.
64 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> { 54 pub(crate) fn macro_crate(self, db: &impl AstDatabase) -> Option<Crate> {
65 match self.0 { 55 match self.0 {
@@ -95,11 +85,7 @@ impl HirFileId {
95 // Note: 85 // Note:
96 // The final goal we would like to make all parse_macro success, 86 // The final goal we would like to make all parse_macro success,
97 // such that the following log will not call anyway. 87 // such that the following log will not call anyway.
98 log::warn!( 88 log::warn!("fail on macro_parse: (reason: {})", err,);
99 "fail on macro_parse: (reason: {}) {}",
100 err,
101 macro_call_id.debug_dump(db)
102 );
103 }) 89 })
104 .ok()?; 90 .ok()?;
105 match macro_file.macro_file_kind { 91 match macro_file.macro_file_kind {
@@ -377,35 +363,6 @@ impl AstItemDef<ast::TypeAliasDef> for TypeAliasId {
377 } 363 }
378} 364}
379 365
380impl MacroCallId {
381 pub fn debug_dump(self, db: &impl AstDatabase) -> String {
382 let loc = self.loc(db);
383 let node = loc.ast_id.to_node(db);
384 let syntax_str = {
385 let mut res = String::new();
386 node.syntax().text().for_each_chunk(|chunk| {
387 if !res.is_empty() {
388 res.push(' ')
389 }
390 res.push_str(chunk)
391 });
392 res
393 };
394
395 // dump the file name
396 let file_id: HirFileId = self.loc(db).ast_id.file_id();
397 let original = file_id.original_file(db);
398 let macro_rules = db.macro_def(loc.def);
399
400 format!(
401 "macro call [file: {:?}] : {}\nhas rules: {}",
402 db.file_relative_path(original),
403 syntax_str,
404 macro_rules.is_some()
405 )
406 }
407}
408
409/// This exists just for Chalk, because Chalk just has a single `StructId` where 366/// This exists just for Chalk, because Chalk just has a single `StructId` where
410/// we have different kinds of ADTs, primitive types and special type 367/// we have different kinds of ADTs, primitive types and special type
411/// constructors like tuples and function pointers. 368/// constructors like tuples and function pointers.
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 55dfc393b..33ef87563 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -176,6 +176,25 @@ pub struct ModuleImplBlocks {
176} 176}
177 177
178impl ModuleImplBlocks { 178impl ModuleImplBlocks {
179 pub(crate) fn impls_in_module_with_source_map_query(
180 db: &(impl DefDatabase + AstDatabase),
181 module: Module,
182 ) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
183 let mut source_map = ImplSourceMap::default();
184 let crate_graph = db.crate_graph();
185 let cfg_options = crate_graph.cfg_options(module.krate.crate_id());
186
187 let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map);
188 (Arc::new(result), Arc::new(source_map))
189 }
190
191 pub(crate) fn impls_in_module_query(
192 db: &impl DefDatabase,
193 module: Module,
194 ) -> Arc<ModuleImplBlocks> {
195 db.impls_in_module_with_source_map(module).0
196 }
197
179 fn collect( 198 fn collect(
180 db: &(impl DefDatabase + AstDatabase), 199 db: &(impl DefDatabase + AstDatabase),
181 cfg_options: &CfgOptions, 200 cfg_options: &CfgOptions,
@@ -264,19 +283,3 @@ impl ModuleImplBlocks {
264 } 283 }
265 } 284 }
266} 285}
267
268pub(crate) fn impls_in_module_with_source_map_query(
269 db: &(impl DefDatabase + AstDatabase),
270 module: Module,
271) -> (Arc<ModuleImplBlocks>, Arc<ImplSourceMap>) {
272 let mut source_map = ImplSourceMap::default();
273 let crate_graph = db.crate_graph();
274 let cfg_options = crate_graph.cfg_options(module.krate.crate_id());
275
276 let result = ModuleImplBlocks::collect(db, cfg_options, module, &mut source_map);
277 (Arc::new(result), Arc::new(source_map))
278}
279
280pub(crate) fn impls_in_module(db: &impl DefDatabase, module: Module) -> Arc<ModuleImplBlocks> {
281 db.impls_in_module_with_source_map(module).0
282}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 4340e9d34..ca261e8f5 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -51,6 +51,7 @@ mod lang_item;
51mod generics; 51mod generics;
52mod resolve; 52mod resolve;
53pub mod diagnostics; 53pub mod diagnostics;
54mod util;
54 55
55mod code_model; 56mod code_model;
56 57
@@ -71,7 +72,7 @@ pub use self::{
71 either::Either, 72 either::Either,
72 expr::ExprScopes, 73 expr::ExprScopes,
73 from_source::FromSource, 74 from_source::FromSource,
74 generics::{GenericParam, GenericParams, HasGenericParams}, 75 generics::{GenericDef, GenericParam, GenericParams, HasGenericParams},
75 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile}, 76 ids::{HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile},
76 impl_block::ImplBlock, 77 impl_block::ImplBlock,
77 name::Name, 78 name::Name,
diff --git a/crates/ra_hir/src/mock.rs b/crates/ra_hir/src/mock.rs
index f750986b8..0b278deb3 100644
--- a/crates/ra_hir/src/mock.rs
+++ b/crates/ra_hir/src/mock.rs
@@ -5,10 +5,10 @@ use std::{panic, sync::Arc};
5use parking_lot::Mutex; 5use parking_lot::Mutex;
6use ra_cfg::CfgOptions; 6use ra_cfg::CfgOptions;
7use ra_db::{ 7use ra_db::{
8 salsa, CrateGraph, CrateId, Edition, FileId, FilePosition, SourceDatabase, SourceRoot, 8 salsa, CrateGraph, CrateId, Edition, FileId, FileLoader, FileLoaderDelegate, FilePosition,
9 SourceRootId, 9 SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
10}; 10};
11use relative_path::RelativePathBuf; 11use relative_path::{RelativePath, RelativePathBuf};
12use rustc_hash::FxHashMap; 12use rustc_hash::FxHashMap;
13use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER}; 13use test_utils::{extract_offset, parse_fixture, CURSOR_MARKER};
14 14
@@ -17,6 +17,7 @@ use crate::{db, debug::HirDebugHelper, diagnostics::DiagnosticSink};
17pub const WORKSPACE: SourceRootId = SourceRootId(0); 17pub const WORKSPACE: SourceRootId = SourceRootId(0);
18 18
19#[salsa::database( 19#[salsa::database(
20 ra_db::SourceDatabaseExtStorage,
20 ra_db::SourceDatabaseStorage, 21 ra_db::SourceDatabaseStorage,
21 db::InternDatabaseStorage, 22 db::InternDatabaseStorage,
22 db::AstDatabaseStorage, 23 db::AstDatabaseStorage,
@@ -34,6 +35,22 @@ pub struct MockDatabase {
34 35
35impl panic::RefUnwindSafe for MockDatabase {} 36impl panic::RefUnwindSafe for MockDatabase {}
36 37
38impl FileLoader for MockDatabase {
39 fn file_text(&self, file_id: FileId) -> Arc<String> {
40 FileLoaderDelegate(self).file_text(file_id)
41 }
42 fn resolve_relative_path(
43 &self,
44 anchor: FileId,
45 relative_path: &RelativePath,
46 ) -> Option<FileId> {
47 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
48 }
49 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
50 FileLoaderDelegate(self).relevant_crates(file_id)
51 }
52}
53
37impl HirDebugHelper for MockDatabase { 54impl HirDebugHelper for MockDatabase {
38 fn crate_name(&self, krate: CrateId) -> Option<String> { 55 fn crate_name(&self, krate: CrateId) -> Option<String> {
39 self.crate_names.get(&krate).cloned() 56 self.crate_names.get(&krate).cloned()
@@ -278,7 +295,10 @@ macro_rules! crate_graph {
278 $crate_path:literal, 295 $crate_path:literal,
279 $($edition:literal,)? 296 $($edition:literal,)?
280 [$($dep:literal),*] 297 [$($dep:literal),*]
281 $(,$cfg:expr)? 298 $(, cfg = {
299 $($key:literal $(= $value:literal)?),*
300 $(,)?
301 })?
282 ), 302 ),
283 )*) => {{ 303 )*) => {{
284 let mut res = $crate::mock::CrateGraphFixture::default(); 304 let mut res = $crate::mock::CrateGraphFixture::default();
@@ -286,7 +306,19 @@ macro_rules! crate_graph {
286 #[allow(unused_mut, unused_assignments)] 306 #[allow(unused_mut, unused_assignments)]
287 let mut edition = ra_db::Edition::Edition2018; 307 let mut edition = ra_db::Edition::Edition2018;
288 $(edition = ra_db::Edition::from_string($edition);)? 308 $(edition = ra_db::Edition::from_string($edition);)?
289 let cfg_options = { ::ra_cfg::CfgOptions::default() $(; $cfg)? }; 309 let cfg_options = {
310 #[allow(unused_mut)]
311 let mut cfg = ::ra_cfg::CfgOptions::default();
312 $(
313 $(
314 if 0 == 0 $(+ { drop($value); 1})? {
315 cfg.insert_atom($key.into());
316 }
317 $(cfg.insert_key_value($key.into(), $value.into());)?
318 )*
319 )?
320 cfg
321 };
290 res.0.push(( 322 res.0.push((
291 $crate_name.to_string(), 323 $crate_name.to_string(),
292 ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*]) 324 ($crate_path.to_string(), edition, cfg_options, vec![$($dep.to_string()),*])
diff --git a/crates/ra_hir/src/nameres/collector.rs b/crates/ra_hir/src/nameres/collector.rs
index cef2dc9d2..b5fe16bfa 100644
--- a/crates/ra_hir/src/nameres/collector.rs
+++ b/crates/ra_hir/src/nameres/collector.rs
@@ -7,14 +7,13 @@ use rustc_hash::FxHashMap;
7use test_utils::tested_by; 7use test_utils::tested_by;
8 8
9use crate::{ 9use crate::{
10 attr::Attr,
10 db::DefDatabase, 11 db::DefDatabase,
11 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind}, 12 ids::{AstItemDef, LocationCtx, MacroCallId, MacroCallLoc, MacroDefId, MacroFileKind},
12 name::MACRO_RULES, 13 name::MACRO_RULES,
13 nameres::{ 14 nameres::{
14 diagnostics::DefDiagnostic, 15 diagnostics::DefDiagnostic, mod_resolution::ModDir, raw, Crate, CrateDefMap, CrateModuleId,
15 mod_resolution::{resolve_submodule, ParentModule}, 16 ModuleData, ModuleDef, PerNs, ReachedFixedPoint, Resolution, ResolveMode,
16 raw, Crate, CrateDefMap, CrateModuleId, ModuleData, ModuleDef, PerNs, ReachedFixedPoint,
17 Resolution, ResolveMode,
18 }, 17 },
19 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static, 18 Adt, AstId, Const, Enum, Function, HirFileId, MacroDef, Module, Name, Path, PathKind, Static,
20 Struct, Trait, TypeAlias, Union, 19 Struct, Trait, TypeAlias, Union,
@@ -45,6 +44,7 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
45 glob_imports: FxHashMap::default(), 44 glob_imports: FxHashMap::default(),
46 unresolved_imports: Vec::new(), 45 unresolved_imports: Vec::new(),
47 unexpanded_macros: Vec::new(), 46 unexpanded_macros: Vec::new(),
47 mod_dirs: FxHashMap::default(),
48 macro_stack_monitor: MacroStackMonitor::default(), 48 macro_stack_monitor: MacroStackMonitor::default(),
49 cfg_options, 49 cfg_options,
50 }; 50 };
@@ -87,6 +87,7 @@ struct DefCollector<'a, DB> {
87 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>, 87 glob_imports: FxHashMap<CrateModuleId, Vec<(CrateModuleId, raw::ImportId)>>,
88 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>, 88 unresolved_imports: Vec<(CrateModuleId, raw::ImportId, raw::ImportData)>,
89 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>, 89 unexpanded_macros: Vec<(CrateModuleId, AstId<ast::MacroCall>, Path)>,
90 mod_dirs: FxHashMap<CrateModuleId, ModDir>,
90 91
91 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly 92 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
92 /// To prevent stack overflow, we add a deep counter here for prevent that. 93 /// To prevent stack overflow, we add a deep counter here for prevent that.
@@ -107,11 +108,10 @@ where
107 self.def_map.modules[module_id].definition = Some(file_id); 108 self.def_map.modules[module_id].definition = Some(file_id);
108 ModCollector { 109 ModCollector {
109 def_collector: &mut *self, 110 def_collector: &mut *self,
110 attr_path: None,
111 module_id, 111 module_id,
112 file_id: file_id.into(), 112 file_id: file_id.into(),
113 raw_items: &raw_items, 113 raw_items: &raw_items,
114 parent_module: None, 114 mod_dir: ModDir::root(),
115 } 115 }
116 .collect(raw_items.items()); 116 .collect(raw_items.items());
117 117
@@ -481,13 +481,13 @@ where
481 if !self.macro_stack_monitor.is_poison(macro_def_id) { 481 if !self.macro_stack_monitor.is_poison(macro_def_id) {
482 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items); 482 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
483 let raw_items = self.db.raw_items(file_id); 483 let raw_items = self.db.raw_items(file_id);
484 let mod_dir = self.mod_dirs[&module_id].clone();
484 ModCollector { 485 ModCollector {
485 def_collector: &mut *self, 486 def_collector: &mut *self,
486 file_id, 487 file_id,
487 attr_path: None,
488 module_id, 488 module_id,
489 raw_items: &raw_items, 489 raw_items: &raw_items,
490 parent_module: None, 490 mod_dir,
491 } 491 }
492 .collect(raw_items.items()); 492 .collect(raw_items.items());
493 } else { 493 } else {
@@ -508,9 +508,8 @@ struct ModCollector<'a, D> {
508 def_collector: D, 508 def_collector: D,
509 module_id: CrateModuleId, 509 module_id: CrateModuleId,
510 file_id: HirFileId, 510 file_id: HirFileId,
511 attr_path: Option<&'a SmolStr>,
512 raw_items: &'a raw::RawItems, 511 raw_items: &'a raw::RawItems,
513 parent_module: Option<ParentModule<'a>>, 512 mod_dir: ModDir,
514} 513}
515 514
516impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>> 515impl<DB> ModCollector<'_, &'_ mut DefCollector<'_, DB>>
@@ -518,6 +517,10 @@ where
518 DB: DefDatabase, 517 DB: DefDatabase,
519{ 518{
520 fn collect(&mut self, items: &[raw::RawItem]) { 519 fn collect(&mut self, items: &[raw::RawItem]) {
520 // Note: don't assert that inserted value is fresh: it's simply not true
521 // for macros.
522 self.def_collector.mod_dirs.insert(self.module_id, self.mod_dir.clone());
523
521 // Prelude module is always considered to be `#[macro_use]`. 524 // Prelude module is always considered to be `#[macro_use]`.
522 if let Some(prelude_module) = self.def_collector.def_map.prelude { 525 if let Some(prelude_module) = self.def_collector.def_map.prelude {
523 if prelude_module.krate != self.def_collector.def_map.krate { 526 if prelude_module.krate != self.def_collector.def_map.krate {
@@ -530,7 +533,7 @@ where
530 // `#[macro_use] extern crate` is hoisted to imports macros before collecting 533 // `#[macro_use] extern crate` is hoisted to imports macros before collecting
531 // any other items. 534 // any other items.
532 for item in items { 535 for item in items {
533 if self.is_cfg_enabled(&item.attrs) { 536 if self.is_cfg_enabled(item.attrs()) {
534 if let raw::RawItemKind::Import(import_id) = item.kind { 537 if let raw::RawItemKind::Import(import_id) = item.kind {
535 let import = self.raw_items[import_id].clone(); 538 let import = self.raw_items[import_id].clone();
536 if import.is_extern_crate && import.is_macro_use { 539 if import.is_extern_crate && import.is_macro_use {
@@ -541,9 +544,11 @@ where
541 } 544 }
542 545
543 for item in items { 546 for item in items {
544 if self.is_cfg_enabled(&item.attrs) { 547 if self.is_cfg_enabled(item.attrs()) {
545 match item.kind { 548 match item.kind {
546 raw::RawItemKind::Module(m) => self.collect_module(&self.raw_items[m]), 549 raw::RawItemKind::Module(m) => {
550 self.collect_module(&self.raw_items[m], item.attrs())
551 }
547 raw::RawItemKind::Import(import_id) => self 552 raw::RawItemKind::Import(import_id) => self
548 .def_collector 553 .def_collector
549 .unresolved_imports 554 .unresolved_imports
@@ -555,53 +560,48 @@ where
555 } 560 }
556 } 561 }
557 562
558 fn collect_module(&mut self, module: &raw::ModuleData) { 563 fn collect_module(&mut self, module: &raw::ModuleData, attrs: &[Attr]) {
564 let path_attr = self.path_attr(attrs);
565 let is_macro_use = self.is_macro_use(attrs);
559 match module { 566 match module {
560 // inline module, just recurse 567 // inline module, just recurse
561 raw::ModuleData::Definition { name, items, ast_id, attr_path, is_macro_use } => { 568 raw::ModuleData::Definition { name, items, ast_id } => {
562 let module_id = 569 let module_id =
563 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None); 570 self.push_child_module(name.clone(), ast_id.with_file_id(self.file_id), None);
564 let parent_module = ParentModule { name, attr_path: attr_path.as_ref() };
565 571
566 ModCollector { 572 ModCollector {
567 def_collector: &mut *self.def_collector, 573 def_collector: &mut *self.def_collector,
568 module_id, 574 module_id,
569 attr_path: attr_path.as_ref(),
570 file_id: self.file_id, 575 file_id: self.file_id,
571 raw_items: self.raw_items, 576 raw_items: self.raw_items,
572 parent_module: Some(parent_module), 577 mod_dir: self.mod_dir.descend_into_definition(name, path_attr),
573 } 578 }
574 .collect(&*items); 579 .collect(&*items);
575 if *is_macro_use { 580 if is_macro_use {
576 self.import_all_legacy_macros(module_id); 581 self.import_all_legacy_macros(module_id);
577 } 582 }
578 } 583 }
579 // out of line module, resolve, parse and recurse 584 // out of line module, resolve, parse and recurse
580 raw::ModuleData::Declaration { name, ast_id, attr_path, is_macro_use } => { 585 raw::ModuleData::Declaration { name, ast_id } => {
581 let ast_id = ast_id.with_file_id(self.file_id); 586 let ast_id = ast_id.with_file_id(self.file_id);
582 let is_root = self.def_collector.def_map.modules[self.module_id].parent.is_none(); 587 match self.mod_dir.resolve_declaration(
583 match resolve_submodule(
584 self.def_collector.db, 588 self.def_collector.db,
585 self.file_id, 589 self.file_id,
586 self.attr_path,
587 name, 590 name,
588 is_root, 591 path_attr,
589 attr_path.as_ref(),
590 self.parent_module,
591 ) { 592 ) {
592 Ok(file_id) => { 593 Ok((file_id, mod_dir)) => {
593 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id)); 594 let module_id = self.push_child_module(name.clone(), ast_id, Some(file_id));
594 let raw_items = self.def_collector.db.raw_items(file_id.into()); 595 let raw_items = self.def_collector.db.raw_items(file_id.into());
595 ModCollector { 596 ModCollector {
596 def_collector: &mut *self.def_collector, 597 def_collector: &mut *self.def_collector,
597 module_id, 598 module_id,
598 attr_path: attr_path.as_ref(),
599 file_id: file_id.into(), 599 file_id: file_id.into(),
600 raw_items: &raw_items, 600 raw_items: &raw_items,
601 parent_module: None, 601 mod_dir,
602 } 602 }
603 .collect(raw_items.items()); 603 .collect(raw_items.items());
604 if *is_macro_use { 604 if is_macro_use {
605 self.import_all_legacy_macros(module_id); 605 self.import_all_legacy_macros(module_id);
606 } 606 }
607 } 607 }
@@ -714,12 +714,16 @@ where
714 } 714 }
715 } 715 }
716 716
717 fn is_cfg_enabled(&self, attrs: &raw::Attrs) -> bool { 717 fn is_cfg_enabled(&self, attrs: &[Attr]) -> bool {
718 attrs.as_ref().map_or(true, |attrs| { 718 attrs.iter().all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false))
719 attrs 719 }
720 .iter() 720
721 .all(|attr| attr.is_cfg_enabled(&self.def_collector.cfg_options) != Some(false)) 721 fn path_attr<'a>(&self, attrs: &'a [Attr]) -> Option<&'a SmolStr> {
722 }) 722 attrs.iter().find_map(|attr| attr.as_path())
723 }
724
725 fn is_macro_use<'a>(&self, attrs: &'a [Attr]) -> bool {
726 attrs.iter().any(|attr| attr.is_simple_atom("macro_use"))
723 } 727 }
724} 728}
725 729
@@ -747,6 +751,7 @@ mod tests {
747 glob_imports: FxHashMap::default(), 751 glob_imports: FxHashMap::default(),
748 unresolved_imports: Vec::new(), 752 unresolved_imports: Vec::new(),
749 unexpanded_macros: Vec::new(), 753 unexpanded_macros: Vec::new(),
754 mod_dirs: FxHashMap::default(),
750 macro_stack_monitor: monitor, 755 macro_stack_monitor: monitor,
751 cfg_options: &CfgOptions::default(), 756 cfg_options: &CfgOptions::default(),
752 }; 757 };
diff --git a/crates/ra_hir/src/nameres/mod_resolution.rs b/crates/ra_hir/src/nameres/mod_resolution.rs
index 3aa32bd66..e8b808514 100644
--- a/crates/ra_hir/src/nameres/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/mod_resolution.rs
@@ -1,187 +1,87 @@
1//! This module resolves `mod foo;` declaration to file. 1//! This module resolves `mod foo;` declaration to file.
2 2use ra_db::FileId;
3use std::{borrow::Cow, sync::Arc};
4
5use ra_db::{FileId, SourceRoot};
6use ra_syntax::SmolStr; 3use ra_syntax::SmolStr;
7use relative_path::RelativePathBuf; 4use relative_path::RelativePathBuf;
8 5
9use crate::{db::DefDatabase, HirFileId, Name}; 6use crate::{db::DefDatabase, HirFileId, Name};
10 7
11#[derive(Clone, Copy)] 8#[derive(Clone, Debug)]
12pub(super) struct ParentModule<'a> { 9pub(super) struct ModDir {
13 pub(super) name: &'a Name, 10 /// `.` for `mod.rs`, `lib.rs`
14 pub(super) attr_path: Option<&'a SmolStr>, 11 /// `./foo` for `foo.rs`
12 /// `./foo/bar` for `mod bar { mod x; }` nested in `foo.rs`
13 path: RelativePathBuf,
14 /// inside `./foo.rs`, mods with `#[path]` should *not* be relative to `./foo/`
15 root_non_dir_owner: bool,
15} 16}
16 17
17impl<'a> ParentModule<'a> { 18impl ModDir {
18 fn attribute_path(&self) -> Option<&SmolStr> { 19 pub(super) fn root() -> ModDir {
19 self.attr_path.filter(|p| !p.is_empty()) 20 ModDir { path: RelativePathBuf::default(), root_non_dir_owner: false }
20 } 21 }
21}
22 22
23pub(super) fn resolve_submodule( 23 pub(super) fn descend_into_definition(
24 db: &impl DefDatabase, 24 &self,
25 file_id: HirFileId, 25 name: &Name,
26 mod_attr_path: Option<&SmolStr>, 26 attr_path: Option<&SmolStr>,
27 name: &Name, 27 ) -> ModDir {
28 is_root: bool, 28 let mut path = self.path.clone();
29 attr_path: Option<&SmolStr>, 29 match attr_to_path(attr_path) {
30 parent_module: Option<ParentModule<'_>>, 30 None => path.push(&name.to_string()),
31) -> Result<FileId, RelativePathBuf> { 31 Some(attr_path) => {
32 let file_id = file_id.original_file(db); 32 if self.root_non_dir_owner {
33 let source_root_id = db.file_source_root(file_id); 33 // Workaround for relative path API: turn `lib.rs` into ``.
34 let path = db.file_relative_path(file_id); 34 if !path.pop() {
35 let root = RelativePathBuf::default(); 35 path = RelativePathBuf::default();
36 let dir_path = path.parent().unwrap_or(&root); 36 }
37 let mod_name = path.file_stem().unwrap_or("unknown");
38
39 let resolve_mode = match (attr_path.filter(|p| !p.is_empty()), parent_module) {
40 (Some(file_path), Some(parent_module)) => {
41 let file_path = normalize_attribute_path(file_path);
42 match parent_module.attribute_path() {
43 Some(parent_module_attr_path) => {
44 let path = dir_path
45 .join(format!(
46 "{}/{}",
47 normalize_attribute_path(parent_module_attr_path),
48 file_path
49 ))
50 .normalize();
51 ResolutionMode::InlineModuleWithAttributePath(
52 InsideInlineModuleMode::WithAttributePath(path),
53 )
54 }
55 None => {
56 let path =
57 dir_path.join(format!("{}/{}", parent_module.name, file_path)).normalize();
58 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::WithAttributePath(
59 path,
60 ))
61 } 37 }
38 path.push(attr_path);
62 } 39 }
63 } 40 }
64 (None, Some(parent_module)) => match parent_module.attribute_path() { 41 ModDir { path, root_non_dir_owner: false }
65 Some(parent_module_attr_path) => { 42 }
66 let path = dir_path.join(format!( 43
67 "{}/{}.rs", 44 pub(super) fn resolve_declaration(
68 normalize_attribute_path(parent_module_attr_path), 45 &self,
69 name 46 db: &impl DefDatabase,
70 )); 47 file_id: HirFileId,
71 ResolutionMode::InlineModuleWithAttributePath(InsideInlineModuleMode::File(path)) 48 name: &Name,
49 attr_path: Option<&SmolStr>,
50 ) -> Result<(FileId, ModDir), RelativePathBuf> {
51 let empty_path = RelativePathBuf::default();
52 let file_id = file_id.original_file(db);
53
54 let mut candidate_files = Vec::new();
55 match attr_to_path(attr_path) {
56 Some(attr_path) => {
57 let base = if self.root_non_dir_owner {
58 self.path.parent().unwrap_or(&empty_path)
59 } else {
60 &self.path
61 };
62 candidate_files.push(base.join(attr_path))
72 } 63 }
73 None => { 64 None => {
74 let path = dir_path.join(format!("{}/{}.rs", parent_module.name, name)); 65 candidate_files.push(self.path.join(&format!("{}.rs", name)));
75 ResolutionMode::InsideInlineModule(InsideInlineModuleMode::File(path)) 66 candidate_files.push(self.path.join(&format!("{}/mod.rs", name)));
76 }
77 },
78 (Some(file_path), None) => {
79 let file_path = normalize_attribute_path(file_path);
80 let path = dir_path.join(file_path.as_ref()).normalize();
81 ResolutionMode::OutOfLine(OutOfLineMode::WithAttributePath(path))
82 }
83 (None, None) => {
84 let is_dir_owner = is_root || mod_name == "mod" || mod_attr_path.is_some();
85 if is_dir_owner {
86 let file_mod = dir_path.join(format!("{}.rs", name));
87 let dir_mod = dir_path.join(format!("{}/mod.rs", name));
88 ResolutionMode::OutOfLine(OutOfLineMode::RootOrModRs {
89 file: file_mod,
90 directory: dir_mod,
91 })
92 } else {
93 let path = dir_path.join(format!("{}/{}.rs", mod_name, name));
94 ResolutionMode::OutOfLine(OutOfLineMode::FileInDirectory(path))
95 } 67 }
96 } 68 };
97 }; 69
98 70 for candidate in candidate_files.iter() {
99 resolve_mode.resolve(db.source_root(source_root_id)) 71 if let Some(file_id) = db.resolve_relative_path(file_id, candidate) {
100} 72 let mut root_non_dir_owner = false;
101 73 let mut mod_path = RelativePathBuf::new();
102fn normalize_attribute_path(file_path: &SmolStr) -> Cow<str> { 74 if !(candidate.ends_with("mod.rs") || attr_path.is_some()) {
103 let current_dir = "./"; 75 root_non_dir_owner = true;
104 let windows_path_separator = r#"\"#; 76 mod_path.push(&name.to_string());
105 let current_dir_normalize = if file_path.starts_with(current_dir) {
106 &file_path[current_dir.len()..]
107 } else {
108 file_path.as_str()
109 };
110 if current_dir_normalize.contains(windows_path_separator) {
111 Cow::Owned(current_dir_normalize.replace(windows_path_separator, "/"))
112 } else {
113 Cow::Borrowed(current_dir_normalize)
114 }
115}
116
117enum OutOfLineMode {
118 RootOrModRs { file: RelativePathBuf, directory: RelativePathBuf },
119 FileInDirectory(RelativePathBuf),
120 WithAttributePath(RelativePathBuf),
121}
122
123impl OutOfLineMode {
124 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
125 match self {
126 OutOfLineMode::RootOrModRs { file, directory } => {
127 match source_root.file_by_relative_path(file) {
128 None => resolve_simple_path(source_root, directory).map_err(|_| file.clone()),
129 file_id => resolve_find_result(file_id, file),
130 } 77 }
78 return Ok((file_id, ModDir { path: mod_path, root_non_dir_owner }));
131 } 79 }
132 OutOfLineMode::FileInDirectory(path) => resolve_simple_path(source_root, path),
133 OutOfLineMode::WithAttributePath(path) => resolve_simple_path(source_root, path),
134 } 80 }
81 Err(candidate_files.remove(0))
135 } 82 }
136} 83}
137 84
138enum InsideInlineModuleMode { 85fn attr_to_path(attr: Option<&SmolStr>) -> Option<RelativePathBuf> {
139 File(RelativePathBuf), 86 attr.and_then(|it| RelativePathBuf::from_path(&it.replace("\\", "/")).ok())
140 WithAttributePath(RelativePathBuf),
141}
142
143impl InsideInlineModuleMode {
144 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
145 match self {
146 InsideInlineModuleMode::File(path) => resolve_simple_path(source_root, path),
147 InsideInlineModuleMode::WithAttributePath(path) => {
148 resolve_simple_path(source_root, path)
149 }
150 }
151 }
152}
153
154enum ResolutionMode {
155 OutOfLine(OutOfLineMode),
156 InsideInlineModule(InsideInlineModuleMode),
157 InlineModuleWithAttributePath(InsideInlineModuleMode),
158}
159
160impl ResolutionMode {
161 pub fn resolve(&self, source_root: Arc<SourceRoot>) -> Result<FileId, RelativePathBuf> {
162 use self::ResolutionMode::*;
163
164 match self {
165 OutOfLine(mode) => mode.resolve(source_root),
166 InsideInlineModule(mode) => mode.resolve(source_root),
167 InlineModuleWithAttributePath(mode) => mode.resolve(source_root),
168 }
169 }
170}
171
172fn resolve_simple_path(
173 source_root: Arc<SourceRoot>,
174 path: &RelativePathBuf,
175) -> Result<FileId, RelativePathBuf> {
176 resolve_find_result(source_root.file_by_relative_path(path), path)
177}
178
179fn resolve_find_result(
180 file_id: Option<FileId>,
181 path: &RelativePathBuf,
182) -> Result<FileId, RelativePathBuf> {
183 match file_id {
184 Some(file_id) => Ok(file_id.clone()),
185 None => Err(path.clone()),
186 }
187} 87}
diff --git a/crates/ra_hir/src/nameres/raw.rs b/crates/ra_hir/src/nameres/raw.rs
index 623b343c4..57f2929c3 100644
--- a/crates/ra_hir/src/nameres/raw.rs
+++ b/crates/ra_hir/src/nameres/raw.rs
@@ -5,7 +5,7 @@ use std::{ops::Index, sync::Arc};
5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 5use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId};
6use ra_syntax::{ 6use ra_syntax::{
7 ast::{self, AttrsOwner, NameOwner}, 7 ast::{self, AttrsOwner, NameOwner},
8 AstNode, AstPtr, SmolStr, SourceFile, 8 AstNode, AstPtr, SourceFile,
9}; 9};
10use test_utils::tested_by; 10use test_utils::tested_by;
11 11
@@ -121,14 +121,20 @@ impl Index<Macro> for RawItems {
121} 121}
122 122
123// Avoid heap allocation on items without attributes. 123// Avoid heap allocation on items without attributes.
124pub(super) type Attrs = Option<Arc<[Attr]>>; 124type Attrs = Option<Arc<[Attr]>>;
125 125
126#[derive(Debug, PartialEq, Eq, Clone)] 126#[derive(Debug, PartialEq, Eq, Clone)]
127pub(super) struct RawItem { 127pub(super) struct RawItem {
128 pub(super) attrs: Attrs, 128 attrs: Attrs,
129 pub(super) kind: RawItemKind, 129 pub(super) kind: RawItemKind,
130} 130}
131 131
132impl RawItem {
133 pub(super) fn attrs(&self) -> &[Attr] {
134 self.attrs.as_ref().map_or(&[], |it| &*it)
135 }
136}
137
132#[derive(Debug, PartialEq, Eq, Clone, Copy)] 138#[derive(Debug, PartialEq, Eq, Clone, Copy)]
133pub(super) enum RawItemKind { 139pub(super) enum RawItemKind {
134 Module(Module), 140 Module(Module),
@@ -143,19 +149,8 @@ impl_arena_id!(Module);
143 149
144#[derive(Debug, PartialEq, Eq)] 150#[derive(Debug, PartialEq, Eq)]
145pub(super) enum ModuleData { 151pub(super) enum ModuleData {
146 Declaration { 152 Declaration { name: Name, ast_id: FileAstId<ast::Module> },
147 name: Name, 153 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
148 ast_id: FileAstId<ast::Module>,
149 attr_path: Option<SmolStr>,
150 is_macro_use: bool,
151 },
152 Definition {
153 name: Name,
154 ast_id: FileAstId<ast::Module>,
155 items: Vec<RawItem>,
156 attr_path: Option<SmolStr>,
157 is_macro_use: bool,
158 },
159} 154}
160 155
161#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 156#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -286,28 +281,17 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
286 let attrs = self.parse_attrs(&module); 281 let attrs = self.parse_attrs(&module);
287 282
288 let ast_id = self.source_ast_id_map.ast_id(&module); 283 let ast_id = self.source_ast_id_map.ast_id(&module);
289 // FIXME: cfg_attr
290 let is_macro_use = module.has_atom_attr("macro_use");
291 if module.has_semi() { 284 if module.has_semi() {
292 let attr_path = extract_mod_path_attribute(&module); 285 let item = self.raw_items.modules.alloc(ModuleData::Declaration { name, ast_id });
293 let item = self.raw_items.modules.alloc(ModuleData::Declaration {
294 name,
295 ast_id,
296 attr_path,
297 is_macro_use,
298 });
299 self.push_item(current_module, attrs, RawItemKind::Module(item)); 286 self.push_item(current_module, attrs, RawItemKind::Module(item));
300 return; 287 return;
301 } 288 }
302 289
303 if let Some(item_list) = module.item_list() { 290 if let Some(item_list) = module.item_list() {
304 let attr_path = extract_mod_path_attribute(&module);
305 let item = self.raw_items.modules.alloc(ModuleData::Definition { 291 let item = self.raw_items.modules.alloc(ModuleData::Definition {
306 name, 292 name,
307 ast_id, 293 ast_id,
308 items: Vec::new(), 294 items: Vec::new(),
309 attr_path,
310 is_macro_use,
311 }); 295 });
312 self.process_module(Some(item), item_list); 296 self.process_module(Some(item), item_list);
313 self.push_item(current_module, attrs, RawItemKind::Module(item)); 297 self.push_item(current_module, attrs, RawItemKind::Module(item));
@@ -417,16 +401,3 @@ impl<DB: AstDatabase> RawItemsCollector<&DB> {
417 Attr::from_attrs_owner(self.file_id, item, self.db) 401 Attr::from_attrs_owner(self.file_id, item, self.db)
418 } 402 }
419} 403}
420
421fn extract_mod_path_attribute(module: &ast::Module) -> Option<SmolStr> {
422 module.attrs().into_iter().find_map(|attr| {
423 attr.as_simple_key_value().and_then(|(name, value)| {
424 let is_path = name == "path";
425 if is_path {
426 Some(value)
427 } else {
428 None
429 }
430 })
431 })
432}
diff --git a/crates/ra_hir/src/nameres/tests.rs b/crates/ra_hir/src/nameres/tests.rs
index 34dd79574..8c6b40aaf 100644
--- a/crates/ra_hir/src/nameres/tests.rs
+++ b/crates/ra_hir/src/nameres/tests.rs
@@ -7,7 +7,6 @@ mod mod_resolution;
7use std::sync::Arc; 7use std::sync::Arc;
8 8
9use insta::assert_snapshot; 9use insta::assert_snapshot;
10use ra_cfg::CfgOptions;
11use ra_db::SourceDatabase; 10use ra_db::SourceDatabase;
12use test_utils::covers; 11use test_utils::covers;
13 12
@@ -561,12 +560,12 @@ fn cfg_test() {
561 "#, 560 "#,
562 crate_graph! { 561 crate_graph! {
563 "main": ("/main.rs", ["std"]), 562 "main": ("/main.rs", ["std"]),
564 "std": ("/lib.rs", [], CfgOptions::default() 563 "std": ("/lib.rs", [], cfg = {
565 .atom("test".into()) 564 "test",
566 .key_value("feature".into(), "foo".into()) 565 "feature" = "foo",
567 .key_value("feature".into(), "bar".into()) 566 "feature" = "bar",
568 .key_value("opt".into(), "42".into()) 567 "opt" = "42",
569 ), 568 }),
570 }, 569 },
571 ); 570 );
572 571
diff --git a/crates/ra_hir/src/nameres/tests/incremental.rs b/crates/ra_hir/src/nameres/tests/incremental.rs
index c41862a0b..af9c39760 100644
--- a/crates/ra_hir/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir/src/nameres/tests/incremental.rs
@@ -2,7 +2,7 @@ use super::*;
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use ra_db::SourceDatabase; 5use ra_db::{SourceDatabase, SourceDatabaseExt};
6 6
7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) { 7fn check_def_map_is_not_recomputed(initial: &str, file_change: &str) {
8 let (mut db, pos) = MockDatabase::with_position(initial); 8 let (mut db, pos) = MockDatabase::with_position(initial);
diff --git a/crates/ra_hir/src/nameres/tests/macros.rs b/crates/ra_hir/src/nameres/tests/macros.rs
index e4b408394..4f52ad2c5 100644
--- a/crates/ra_hir/src/nameres/tests/macros.rs
+++ b/crates/ra_hir/src/nameres/tests/macros.rs
@@ -38,21 +38,34 @@ fn macro_rules_can_define_modules() {
38 } 38 }
39 m!(n1); 39 m!(n1);
40 40
41 mod m {
42 m!(n3)
43 }
44
41 //- /n1.rs 45 //- /n1.rs
42 m!(n2) 46 m!(n2)
43 //- /n1/n2.rs 47 //- /n1/n2.rs
44 struct X; 48 struct X;
49 //- /m/n3.rs
50 struct Y;
45 ", 51 ",
46 ); 52 );
47 assert_snapshot!(map, @r###" 53 assert_snapshot!(map, @r###"
48 â‹®crate 54 crate
49 â‹®n1: t 55 m: t
50 â‹® 56 n1: t
51 â‹®crate::n1 57
52 â‹®n2: t 58 crate::m
53 â‹® 59 n3: t
54 â‹®crate::n1::n2 60
55 â‹®X: t v 61 crate::m::n3
62 Y: t v
63
64 crate::n1
65 n2: t
66
67 crate::n1::n2
68 X: t v
56 "###); 69 "###);
57} 70}
58 71
diff --git a/crates/ra_hir/src/nameres/tests/mod_resolution.rs b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
index e3e6f1e95..f569aacdc 100644
--- a/crates/ra_hir/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir/src/nameres/tests/mod_resolution.rs
@@ -26,6 +26,33 @@ fn name_res_works_for_broken_modules() {
26} 26}
27 27
28#[test] 28#[test]
29fn nested_module_resolution() {
30 let map = def_map(
31 "
32 //- /lib.rs
33 mod n1;
34
35 //- /n1.rs
36 mod n2;
37
38 //- /n1/n2.rs
39 struct X;
40 ",
41 );
42
43 assert_snapshot!(map, @r###"
44 â‹®crate
45 â‹®n1: t
46 â‹®
47 â‹®crate::n1
48 â‹®n2: t
49 â‹®
50 â‹®crate::n1::n2
51 â‹®X: t v
52 "###);
53}
54
55#[test]
29fn module_resolution_works_for_non_standard_filenames() { 56fn module_resolution_works_for_non_standard_filenames() {
30 let map = def_map_with_crate_graph( 57 let map = def_map_with_crate_graph(
31 " 58 "
@@ -53,18 +80,15 @@ fn module_resolution_works_for_non_standard_filenames() {
53 80
54#[test] 81#[test]
55fn module_resolution_works_for_raw_modules() { 82fn module_resolution_works_for_raw_modules() {
56 let map = def_map_with_crate_graph( 83 let map = def_map(
57 " 84 "
58 //- /library.rs 85 //- /lib.rs
59 mod r#async; 86 mod r#async;
60 use self::r#async::Bar; 87 use self::r#async::Bar;
61 88
62 //- /async.rs 89 //- /async.rs
63 pub struct Bar; 90 pub struct Bar;
64 ", 91 ",
65 crate_graph! {
66 "library": ("/library.rs", []),
67 },
68 ); 92 );
69 93
70 assert_snapshot!(map, @r###" 94 assert_snapshot!(map, @r###"
@@ -79,9 +103,9 @@ fn module_resolution_works_for_raw_modules() {
79 103
80#[test] 104#[test]
81fn module_resolution_decl_path() { 105fn module_resolution_decl_path() {
82 let map = def_map_with_crate_graph( 106 let map = def_map(
83 r###" 107 r###"
84 //- /library.rs 108 //- /lib.rs
85 #[path = "bar/baz/foo.rs"] 109 #[path = "bar/baz/foo.rs"]
86 mod foo; 110 mod foo;
87 use self::foo::Bar; 111 use self::foo::Bar;
@@ -89,9 +113,6 @@ fn module_resolution_decl_path() {
89 //- /bar/baz/foo.rs 113 //- /bar/baz/foo.rs
90 pub struct Bar; 114 pub struct Bar;
91 "###, 115 "###,
92 crate_graph! {
93 "library": ("/library.rs", []),
94 },
95 ); 116 );
96 117
97 assert_snapshot!(map, @r###" 118 assert_snapshot!(map, @r###"
@@ -106,7 +127,7 @@ fn module_resolution_decl_path() {
106 127
107#[test] 128#[test]
108fn module_resolution_module_with_path_in_mod_rs() { 129fn module_resolution_module_with_path_in_mod_rs() {
109 let map = def_map_with_crate_graph( 130 let map = def_map(
110 r###" 131 r###"
111 //- /main.rs 132 //- /main.rs
112 mod foo; 133 mod foo;
@@ -120,9 +141,6 @@ fn module_resolution_module_with_path_in_mod_rs() {
120 //- /foo/baz.rs 141 //- /foo/baz.rs
121 pub struct Baz; 142 pub struct Baz;
122 "###, 143 "###,
123 crate_graph! {
124 "main": ("/main.rs", []),
125 },
126 ); 144 );
127 145
128 assert_snapshot!(map, @r###" 146 assert_snapshot!(map, @r###"
@@ -140,7 +158,7 @@ fn module_resolution_module_with_path_in_mod_rs() {
140 158
141#[test] 159#[test]
142fn module_resolution_module_with_path_non_crate_root() { 160fn module_resolution_module_with_path_non_crate_root() {
143 let map = def_map_with_crate_graph( 161 let map = def_map(
144 r###" 162 r###"
145 //- /main.rs 163 //- /main.rs
146 mod foo; 164 mod foo;
@@ -154,9 +172,6 @@ fn module_resolution_module_with_path_non_crate_root() {
154 //- /baz.rs 172 //- /baz.rs
155 pub struct Baz; 173 pub struct Baz;
156 "###, 174 "###,
157 crate_graph! {
158 "main": ("/main.rs", []),
159 },
160 ); 175 );
161 176
162 assert_snapshot!(map, @r###" 177 assert_snapshot!(map, @r###"
@@ -174,7 +189,7 @@ fn module_resolution_module_with_path_non_crate_root() {
174 189
175#[test] 190#[test]
176fn module_resolution_module_decl_path_super() { 191fn module_resolution_module_decl_path_super() {
177 let map = def_map_with_crate_graph( 192 let map = def_map(
178 r###" 193 r###"
179 //- /main.rs 194 //- /main.rs
180 #[path = "bar/baz/module.rs"] 195 #[path = "bar/baz/module.rs"]
@@ -184,9 +199,6 @@ fn module_resolution_module_decl_path_super() {
184 //- /bar/baz/module.rs 199 //- /bar/baz/module.rs
185 use super::Baz; 200 use super::Baz;
186 "###, 201 "###,
187 crate_graph! {
188 "main": ("/main.rs", []),
189 },
190 ); 202 );
191 203
192 assert_snapshot!(map, @r###" 204 assert_snapshot!(map, @r###"
@@ -201,7 +213,7 @@ fn module_resolution_module_decl_path_super() {
201 213
202#[test] 214#[test]
203fn module_resolution_explicit_path_mod_rs() { 215fn module_resolution_explicit_path_mod_rs() {
204 let map = def_map_with_crate_graph( 216 let map = def_map(
205 r###" 217 r###"
206 //- /main.rs 218 //- /main.rs
207 #[path = "module/mod.rs"] 219 #[path = "module/mod.rs"]
@@ -210,9 +222,6 @@ fn module_resolution_explicit_path_mod_rs() {
210 //- /module/mod.rs 222 //- /module/mod.rs
211 pub struct Baz; 223 pub struct Baz;
212 "###, 224 "###,
213 crate_graph! {
214 "main": ("/main.rs", []),
215 },
216 ); 225 );
217 226
218 assert_snapshot!(map, @r###" 227 assert_snapshot!(map, @r###"
@@ -226,7 +235,7 @@ fn module_resolution_explicit_path_mod_rs() {
226 235
227#[test] 236#[test]
228fn module_resolution_relative_path() { 237fn module_resolution_relative_path() {
229 let map = def_map_with_crate_graph( 238 let map = def_map(
230 r###" 239 r###"
231 //- /main.rs 240 //- /main.rs
232 mod foo; 241 mod foo;
@@ -238,9 +247,6 @@ fn module_resolution_relative_path() {
238 //- /sub.rs 247 //- /sub.rs
239 pub struct Baz; 248 pub struct Baz;
240 "###, 249 "###,
241 crate_graph! {
242 "main": ("/main.rs", []),
243 },
244 ); 250 );
245 251
246 assert_snapshot!(map, @r###" 252 assert_snapshot!(map, @r###"
@@ -257,7 +263,7 @@ fn module_resolution_relative_path() {
257 263
258#[test] 264#[test]
259fn module_resolution_relative_path_2() { 265fn module_resolution_relative_path_2() {
260 let map = def_map_with_crate_graph( 266 let map = def_map(
261 r###" 267 r###"
262 //- /main.rs 268 //- /main.rs
263 mod foo; 269 mod foo;
@@ -269,9 +275,6 @@ fn module_resolution_relative_path_2() {
269 //- /sub.rs 275 //- /sub.rs
270 pub struct Baz; 276 pub struct Baz;
271 "###, 277 "###,
272 crate_graph! {
273 "main": ("/main.rs", []),
274 },
275 ); 278 );
276 279
277 assert_snapshot!(map, @r###" 280 assert_snapshot!(map, @r###"
@@ -288,7 +291,7 @@ fn module_resolution_relative_path_2() {
288 291
289#[test] 292#[test]
290fn module_resolution_explicit_path_mod_rs_2() { 293fn module_resolution_explicit_path_mod_rs_2() {
291 let map = def_map_with_crate_graph( 294 let map = def_map(
292 r###" 295 r###"
293 //- /main.rs 296 //- /main.rs
294 #[path = "module/bar/mod.rs"] 297 #[path = "module/bar/mod.rs"]
@@ -297,9 +300,6 @@ fn module_resolution_explicit_path_mod_rs_2() {
297 //- /module/bar/mod.rs 300 //- /module/bar/mod.rs
298 pub struct Baz; 301 pub struct Baz;
299 "###, 302 "###,
300 crate_graph! {
301 "main": ("/main.rs", []),
302 },
303 ); 303 );
304 304
305 assert_snapshot!(map, @r###" 305 assert_snapshot!(map, @r###"
@@ -313,7 +313,7 @@ fn module_resolution_explicit_path_mod_rs_2() {
313 313
314#[test] 314#[test]
315fn module_resolution_explicit_path_mod_rs_with_win_separator() { 315fn module_resolution_explicit_path_mod_rs_with_win_separator() {
316 let map = def_map_with_crate_graph( 316 let map = def_map(
317 r###" 317 r###"
318 //- /main.rs 318 //- /main.rs
319 #[path = "module\bar\mod.rs"] 319 #[path = "module\bar\mod.rs"]
@@ -322,9 +322,6 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() {
322 //- /module/bar/mod.rs 322 //- /module/bar/mod.rs
323 pub struct Baz; 323 pub struct Baz;
324 "###, 324 "###,
325 crate_graph! {
326 "main": ("/main.rs", []),
327 },
328 ); 325 );
329 326
330 assert_snapshot!(map, @r###" 327 assert_snapshot!(map, @r###"
@@ -338,7 +335,7 @@ fn module_resolution_explicit_path_mod_rs_with_win_separator() {
338 335
339#[test] 336#[test]
340fn module_resolution_decl_inside_inline_module_with_path_attribute() { 337fn module_resolution_decl_inside_inline_module_with_path_attribute() {
341 let map = def_map_with_crate_graph( 338 let map = def_map(
342 r###" 339 r###"
343 //- /main.rs 340 //- /main.rs
344 #[path = "models"] 341 #[path = "models"]
@@ -349,9 +346,6 @@ fn module_resolution_decl_inside_inline_module_with_path_attribute() {
349 //- /models/bar.rs 346 //- /models/bar.rs
350 pub struct Baz; 347 pub struct Baz;
351 "###, 348 "###,
352 crate_graph! {
353 "main": ("/main.rs", []),
354 },
355 ); 349 );
356 350
357 assert_snapshot!(map, @r###" 351 assert_snapshot!(map, @r###"
@@ -368,7 +362,7 @@ fn module_resolution_decl_inside_inline_module_with_path_attribute() {
368 362
369#[test] 363#[test]
370fn module_resolution_decl_inside_inline_module() { 364fn module_resolution_decl_inside_inline_module() {
371 let map = def_map_with_crate_graph( 365 let map = def_map(
372 r###" 366 r###"
373 //- /main.rs 367 //- /main.rs
374 mod foo { 368 mod foo {
@@ -378,9 +372,6 @@ fn module_resolution_decl_inside_inline_module() {
378 //- /foo/bar.rs 372 //- /foo/bar.rs
379 pub struct Baz; 373 pub struct Baz;
380 "###, 374 "###,
381 crate_graph! {
382 "main": ("/main.rs", []),
383 },
384 ); 375 );
385 376
386 assert_snapshot!(map, @r###" 377 assert_snapshot!(map, @r###"
@@ -397,7 +388,7 @@ fn module_resolution_decl_inside_inline_module() {
397 388
398#[test] 389#[test]
399fn module_resolution_decl_inside_inline_module_2_with_path_attribute() { 390fn module_resolution_decl_inside_inline_module_2_with_path_attribute() {
400 let map = def_map_with_crate_graph( 391 let map = def_map(
401 r###" 392 r###"
402 //- /main.rs 393 //- /main.rs
403 #[path = "models/db"] 394 #[path = "models/db"]
@@ -408,9 +399,6 @@ fn module_resolution_decl_inside_inline_module_2_with_path_attribute() {
408 //- /models/db/bar.rs 399 //- /models/db/bar.rs
409 pub struct Baz; 400 pub struct Baz;
410 "###, 401 "###,
411 crate_graph! {
412 "main": ("/main.rs", []),
413 },
414 ); 402 );
415 403
416 assert_snapshot!(map, @r###" 404 assert_snapshot!(map, @r###"
@@ -427,7 +415,7 @@ fn module_resolution_decl_inside_inline_module_2_with_path_attribute() {
427 415
428#[test] 416#[test]
429fn module_resolution_decl_inside_inline_module_3() { 417fn module_resolution_decl_inside_inline_module_3() {
430 let map = def_map_with_crate_graph( 418 let map = def_map(
431 r###" 419 r###"
432 //- /main.rs 420 //- /main.rs
433 #[path = "models/db"] 421 #[path = "models/db"]
@@ -439,9 +427,6 @@ fn module_resolution_decl_inside_inline_module_3() {
439 //- /models/db/users.rs 427 //- /models/db/users.rs
440 pub struct Baz; 428 pub struct Baz;
441 "###, 429 "###,
442 crate_graph! {
443 "main": ("/main.rs", []),
444 },
445 ); 430 );
446 431
447 assert_snapshot!(map, @r###" 432 assert_snapshot!(map, @r###"
@@ -458,7 +443,7 @@ fn module_resolution_decl_inside_inline_module_3() {
458 443
459#[test] 444#[test]
460fn module_resolution_decl_inside_inline_module_empty_path() { 445fn module_resolution_decl_inside_inline_module_empty_path() {
461 let map = def_map_with_crate_graph( 446 let map = def_map(
462 r###" 447 r###"
463 //- /main.rs 448 //- /main.rs
464 #[path = ""] 449 #[path = ""]
@@ -467,12 +452,9 @@ fn module_resolution_decl_inside_inline_module_empty_path() {
467 mod bar; 452 mod bar;
468 } 453 }
469 454
470 //- /foo/users.rs 455 //- /users.rs
471 pub struct Baz; 456 pub struct Baz;
472 "###, 457 "###,
473 crate_graph! {
474 "main": ("/main.rs", []),
475 },
476 ); 458 );
477 459
478 assert_snapshot!(map, @r###" 460 assert_snapshot!(map, @r###"
@@ -489,32 +471,25 @@ fn module_resolution_decl_inside_inline_module_empty_path() {
489 471
490#[test] 472#[test]
491fn module_resolution_decl_empty_path() { 473fn module_resolution_decl_empty_path() {
492 let map = def_map_with_crate_graph( 474 let map = def_map(
493 r###" 475 r###"
494 //- /main.rs 476 //- /main.rs
495 #[path = ""] 477 #[path = ""] // Should try to read `/` (a directory)
496 mod foo; 478 mod foo;
497 479
498 //- /foo.rs 480 //- /foo.rs
499 pub struct Baz; 481 pub struct Baz;
500 "###, 482 "###,
501 crate_graph! {
502 "main": ("/main.rs", []),
503 },
504 ); 483 );
505 484
506 assert_snapshot!(map, @r###" 485 assert_snapshot!(map, @r###"
507 â‹®crate 486 â‹®crate
508 â‹®foo: t
509 â‹®
510 â‹®crate::foo
511 â‹®Baz: t v
512 "###); 487 "###);
513} 488}
514 489
515#[test] 490#[test]
516fn module_resolution_decl_inside_inline_module_relative_path() { 491fn module_resolution_decl_inside_inline_module_relative_path() {
517 let map = def_map_with_crate_graph( 492 let map = def_map(
518 r###" 493 r###"
519 //- /main.rs 494 //- /main.rs
520 #[path = "./models"] 495 #[path = "./models"]
@@ -525,9 +500,6 @@ fn module_resolution_decl_inside_inline_module_relative_path() {
525 //- /models/bar.rs 500 //- /models/bar.rs
526 pub struct Baz; 501 pub struct Baz;
527 "###, 502 "###,
528 crate_graph! {
529 "main": ("/main.rs", []),
530 },
531 ); 503 );
532 504
533 assert_snapshot!(map, @r###" 505 assert_snapshot!(map, @r###"
@@ -544,7 +516,7 @@ fn module_resolution_decl_inside_inline_module_relative_path() {
544 516
545#[test] 517#[test]
546fn module_resolution_decl_inside_inline_module_in_crate_root() { 518fn module_resolution_decl_inside_inline_module_in_crate_root() {
547 let map = def_map_with_crate_graph( 519 let map = def_map(
548 r###" 520 r###"
549 //- /main.rs 521 //- /main.rs
550 mod foo { 522 mod foo {
@@ -556,9 +528,6 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() {
556 //- /foo/baz.rs 528 //- /foo/baz.rs
557 pub struct Baz; 529 pub struct Baz;
558 "###, 530 "###,
559 crate_graph! {
560 "main": ("/main.rs", []),
561 },
562 ); 531 );
563 532
564 assert_snapshot!(map, @r###" 533 assert_snapshot!(map, @r###"
@@ -576,7 +545,7 @@ fn module_resolution_decl_inside_inline_module_in_crate_root() {
576 545
577#[test] 546#[test]
578fn module_resolution_decl_inside_inline_module_in_mod_rs() { 547fn module_resolution_decl_inside_inline_module_in_mod_rs() {
579 let map = def_map_with_crate_graph( 548 let map = def_map(
580 r###" 549 r###"
581 //- /main.rs 550 //- /main.rs
582 mod foo; 551 mod foo;
@@ -591,9 +560,6 @@ fn module_resolution_decl_inside_inline_module_in_mod_rs() {
591 //- /foo/bar/qwe.rs 560 //- /foo/bar/qwe.rs
592 pub struct Baz; 561 pub struct Baz;
593 "###, 562 "###,
594 crate_graph! {
595 "main": ("/main.rs", []),
596 },
597 ); 563 );
598 564
599 assert_snapshot!(map, @r###" 565 assert_snapshot!(map, @r###"
@@ -614,7 +580,7 @@ fn module_resolution_decl_inside_inline_module_in_mod_rs() {
614 580
615#[test] 581#[test]
616fn module_resolution_decl_inside_inline_module_in_non_crate_root() { 582fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
617 let map = def_map_with_crate_graph( 583 let map = def_map(
618 r###" 584 r###"
619 //- /main.rs 585 //- /main.rs
620 mod foo; 586 mod foo;
@@ -626,12 +592,9 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
626 } 592 }
627 use self::bar::baz::Baz; 593 use self::bar::baz::Baz;
628 594
629 //- /bar/qwe.rs 595 //- /foo/bar/qwe.rs
630 pub struct Baz; 596 pub struct Baz;
631 "###, 597 "###,
632 crate_graph! {
633 "main": ("/main.rs", []),
634 },
635 ); 598 );
636 599
637 assert_snapshot!(map, @r###" 600 assert_snapshot!(map, @r###"
@@ -652,7 +615,7 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root() {
652 615
653#[test] 616#[test]
654fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() { 617fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {
655 let map = def_map_with_crate_graph( 618 let map = def_map(
656 r###" 619 r###"
657 //- /main.rs 620 //- /main.rs
658 mod foo; 621 mod foo;
@@ -667,9 +630,6 @@ fn module_resolution_decl_inside_inline_module_in_non_crate_root_2() {
667 //- /bar/baz.rs 630 //- /bar/baz.rs
668 pub struct Baz; 631 pub struct Baz;
669 "###, 632 "###,
670 crate_graph! {
671 "main": ("/main.rs", []),
672 },
673 ); 633 );
674 634
675 assert_snapshot!(map, @r###" 635 assert_snapshot!(map, @r###"
@@ -709,7 +669,7 @@ fn unresolved_module_diagnostics() {
709 669
710#[test] 670#[test]
711fn module_resolution_decl_inside_module_in_non_crate_root_2() { 671fn module_resolution_decl_inside_module_in_non_crate_root_2() {
712 let map = def_map_with_crate_graph( 672 let map = def_map(
713 r###" 673 r###"
714 //- /main.rs 674 //- /main.rs
715 #[path="module/m2.rs"] 675 #[path="module/m2.rs"]
@@ -721,9 +681,6 @@ fn module_resolution_decl_inside_module_in_non_crate_root_2() {
721 //- /module/submod.rs 681 //- /module/submod.rs
722 pub struct Baz; 682 pub struct Baz;
723 "###, 683 "###,
724 crate_graph! {
725 "main": ("/main.rs", []),
726 },
727 ); 684 );
728 685
729 assert_snapshot!(map, @r###" 686 assert_snapshot!(map, @r###"
@@ -737,3 +694,66 @@ fn module_resolution_decl_inside_module_in_non_crate_root_2() {
737 â‹®Baz: t v 694 â‹®Baz: t v
738 "###); 695 "###);
739} 696}
697
698#[test]
699fn nested_out_of_line_module() {
700 let map = def_map(
701 r###"
702 //- /lib.rs
703 mod a {
704 mod b {
705 mod c;
706 }
707 }
708
709 //- /a/b/c.rs
710 struct X;
711 "###,
712 );
713
714 assert_snapshot!(map, @r###"
715 crate
716 a: t
717
718 crate::a
719 b: t
720
721 crate::a::b
722 c: t
723
724 crate::a::b::c
725 X: t v
726 "###);
727}
728
729#[test]
730fn nested_out_of_line_module_with_path() {
731 let map = def_map(
732 r###"
733 //- /lib.rs
734 mod a {
735 #[path = "d/e"]
736 mod b {
737 mod c;
738 }
739 }
740
741 //- /a/d/e/c.rs
742 struct X;
743 "###,
744 );
745
746 assert_snapshot!(map, @r###"
747 crate
748 a: t
749
750 crate::a
751 b: t
752
753 crate::a::b
754 c: t
755
756 crate::a::b::c
757 X: t v
758 "###);
759}
diff --git a/crates/ra_hir/src/resolve.rs b/crates/ra_hir/src/resolve.rs
index 39f8e1d8a..3c797c0c3 100644
--- a/crates/ra_hir/src/resolve.rs
+++ b/crates/ra_hir/src/resolve.rs
@@ -43,8 +43,10 @@ pub(crate) enum Scope {
43 ModuleScope(ModuleItemMap), 43 ModuleScope(ModuleItemMap),
44 /// Brings the generic parameters of an item into scope 44 /// Brings the generic parameters of an item into scope
45 GenericParams(Arc<GenericParams>), 45 GenericParams(Arc<GenericParams>),
46 /// Brings `Self` into scope 46 /// Brings `Self` in `impl` block into scope
47 ImplBlockScope(ImplBlock), 47 ImplBlockScope(ImplBlock),
48 /// Brings `Self` in enum, struct and union definitions into scope
49 AdtScope(Adt),
48 /// Local bindings 50 /// Local bindings
49 ExprScope(ExprScope), 51 ExprScope(ExprScope),
50} 52}
@@ -54,6 +56,7 @@ pub enum TypeNs {
54 SelfType(ImplBlock), 56 SelfType(ImplBlock),
55 GenericParam(u32), 57 GenericParam(u32),
56 Adt(Adt), 58 Adt(Adt),
59 AdtSelfType(Adt),
57 EnumVariant(EnumVariant), 60 EnumVariant(EnumVariant),
58 TypeAlias(TypeAlias), 61 TypeAlias(TypeAlias),
59 BuiltinType(BuiltinType), 62 BuiltinType(BuiltinType),
@@ -151,6 +154,12 @@ impl Resolver {
151 return Some((TypeNs::SelfType(*impl_), idx)); 154 return Some((TypeNs::SelfType(*impl_), idx));
152 } 155 }
153 } 156 }
157 Scope::AdtScope(adt) => {
158 if first_name == &SELF_TYPE {
159 let idx = if path.segments.len() == 1 { None } else { Some(1) };
160 return Some((TypeNs::AdtSelfType(*adt), idx));
161 }
162 }
154 Scope::ModuleScope(m) => { 163 Scope::ModuleScope(m) => {
155 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 164 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
156 let res = match module_def.take_types()? { 165 let res = match module_def.take_types()? {
@@ -200,7 +209,10 @@ impl Resolver {
200 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 209 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
201 for scope in self.scopes.iter().rev() { 210 for scope in self.scopes.iter().rev() {
202 match scope { 211 match scope {
203 Scope::ExprScope(_) | Scope::GenericParams(_) | Scope::ImplBlockScope(_) 212 Scope::AdtScope(_)
213 | Scope::ExprScope(_)
214 | Scope::GenericParams(_)
215 | Scope::ImplBlockScope(_)
204 if skip_to_mod => 216 if skip_to_mod =>
205 { 217 {
206 continue 218 continue
@@ -233,7 +245,13 @@ impl Resolver {
233 return Some(ResolveValueResult::Partial(ty, 1)); 245 return Some(ResolveValueResult::Partial(ty, 1));
234 } 246 }
235 } 247 }
236 Scope::ImplBlockScope(_) => continue, 248 Scope::AdtScope(adt) if n_segments > 1 => {
249 if first_name == &SELF_TYPE {
250 let ty = TypeNs::AdtSelfType(*adt);
251 return Some(ResolveValueResult::Partial(ty, 1));
252 }
253 }
254 Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
237 255
238 Scope::ModuleScope(m) => { 256 Scope::ModuleScope(m) => {
239 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 257 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path);
@@ -389,7 +407,8 @@ pub enum ScopeDef {
389 ModuleDef(ModuleDef), 407 ModuleDef(ModuleDef),
390 MacroDef(MacroDef), 408 MacroDef(MacroDef),
391 GenericParam(u32), 409 GenericParam(u32),
392 SelfType(ImplBlock), 410 ImplSelfType(ImplBlock),
411 AdtSelfType(Adt),
393 LocalBinding(PatId), 412 LocalBinding(PatId),
394 Unknown, 413 Unknown,
395} 414}
@@ -437,7 +456,10 @@ impl Scope {
437 } 456 }
438 } 457 }
439 Scope::ImplBlockScope(i) => { 458 Scope::ImplBlockScope(i) => {
440 f(SELF_TYPE, ScopeDef::SelfType(*i)); 459 f(SELF_TYPE, ScopeDef::ImplSelfType(*i));
460 }
461 Scope::AdtScope(i) => {
462 f(SELF_TYPE, ScopeDef::AdtSelfType(*i));
441 } 463 }
442 Scope::ExprScope(e) => { 464 Scope::ExprScope(e) => {
443 e.expr_scopes.entries(e.scope_id).iter().for_each(|e| { 465 e.expr_scopes.entries(e.scope_id).iter().for_each(|e| {
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 088335e66..a907d6a9f 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -216,7 +216,7 @@ impl SourceAnalyzer {
216 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 216 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty {
217 TypeNs::SelfType(it) => PathResolution::SelfType(it), 217 TypeNs::SelfType(it) => PathResolution::SelfType(it),
218 TypeNs::GenericParam(it) => PathResolution::GenericParam(it), 218 TypeNs::GenericParam(it) => PathResolution::GenericParam(it),
219 TypeNs::Adt(it) => PathResolution::Def(it.into()), 219 TypeNs::AdtSelfType(it) | TypeNs::Adt(it) => PathResolution::Def(it.into()),
220 TypeNs::EnumVariant(it) => PathResolution::Def(it.into()), 220 TypeNs::EnumVariant(it) => PathResolution::Def(it.into()),
221 TypeNs::TypeAlias(it) => PathResolution::Def(it.into()), 221 TypeNs::TypeAlias(it) => PathResolution::Def(it.into()),
222 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()), 222 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
index d161735e8..cc9746f6d 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -17,8 +17,8 @@ use std::sync::Arc;
17use std::{fmt, iter, mem}; 17use std::{fmt, iter, mem};
18 18
19use crate::{ 19use crate::{
20 db::HirDatabase, expr::ExprId, type_ref::Mutability, Adt, Crate, DefWithBody, GenericParams, 20 db::HirDatabase, expr::ExprId, type_ref::Mutability, util::make_mut_slice, Adt, Crate,
21 HasGenericParams, Name, Trait, TypeAlias, 21 DefWithBody, GenericParams, HasGenericParams, Name, Trait, TypeAlias,
22}; 22};
23use display::{HirDisplay, HirFormatter}; 23use display::{HirDisplay, HirFormatter};
24 24
@@ -308,12 +308,9 @@ impl Substs {
308 } 308 }
309 309
310 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 310 pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
311 // Without an Arc::make_mut_slice, we can't avoid the clone here: 311 for t in make_mut_slice(&mut self.0) {
312 let mut v: Vec<_> = self.0.iter().cloned().collect();
313 for t in &mut v {
314 t.walk_mut(f); 312 t.walk_mut(f);
315 } 313 }
316 self.0 = v.into();
317 } 314 }
318 315
319 pub fn as_single(&self) -> &Ty { 316 pub fn as_single(&self) -> &Ty {
@@ -330,8 +327,7 @@ impl Substs {
330 .params_including_parent() 327 .params_including_parent()
331 .into_iter() 328 .into_iter()
332 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() }) 329 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
333 .collect::<Vec<_>>() 330 .collect(),
334 .into(),
335 ) 331 )
336 } 332 }
337 333
@@ -342,8 +338,7 @@ impl Substs {
342 .params_including_parent() 338 .params_including_parent()
343 .into_iter() 339 .into_iter()
344 .map(|p| Ty::Bound(p.idx)) 340 .map(|p| Ty::Bound(p.idx))
345 .collect::<Vec<_>>() 341 .collect(),
346 .into(),
347 ) 342 )
348 } 343 }
349 344
@@ -541,12 +536,9 @@ impl TypeWalk for FnSig {
541 } 536 }
542 537
543 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) { 538 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
544 // Without an Arc::make_mut_slice, we can't avoid the clone here: 539 for t in make_mut_slice(&mut self.params_and_return) {
545 let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
546 for t in &mut v {
547 t.walk_mut(f); 540 t.walk_mut(f);
548 } 541 }
549 self.params_and_return = v.into();
550 } 542 }
551} 543}
552 544
@@ -756,11 +748,9 @@ impl TypeWalk for Ty {
756 p_ty.parameters.walk_mut(f); 748 p_ty.parameters.walk_mut(f);
757 } 749 }
758 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 750 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
759 let mut v: Vec<_> = predicates.iter().cloned().collect(); 751 for p in make_mut_slice(predicates) {
760 for p in &mut v {
761 p.walk_mut(f); 752 p.walk_mut(f);
762 } 753 }
763 *predicates = v.into();
764 } 754 }
765 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {} 755 Ty::Param { .. } | Ty::Bound(_) | Ty::Infer(_) | Ty::Unknown => {}
766 } 756 }
diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs
index ca9aefc42..ebaff998e 100644
--- a/crates/ra_hir/src/ty/infer.rs
+++ b/crates/ra_hir/src/ty/infer.rs
@@ -14,7 +14,6 @@
14//! the `ena` crate, which is extracted from rustc. 14//! the `ena` crate, which is extracted from rustc.
15 15
16use std::borrow::Cow; 16use std::borrow::Cow;
17use std::iter::{repeat, repeat_with};
18use std::mem; 17use std::mem;
19use std::ops::Index; 18use std::ops::Index;
20use std::sync::Arc; 19use std::sync::Arc;
@@ -27,33 +26,39 @@ use ra_prof::profile;
27use test_utils::tested_by; 26use test_utils::tested_by;
28 27
29use super::{ 28use super::{
30 autoderef, lower, method_resolution, op, primitive, 29 lower, primitive,
31 traits::{Guidance, Obligation, ProjectionPredicate, Solution}, 30 traits::{Guidance, Obligation, ProjectionPredicate, Solution},
32 ApplicationTy, CallableDef, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, 31 ApplicationTy, InEnvironment, ProjectionTy, Substs, TraitEnvironment, TraitRef, Ty, TypableDef,
33 Ty, TypableDef, TypeCtor, TypeWalk, 32 TypeCtor, TypeWalk,
34}; 33};
35use crate::{ 34use crate::{
36 adt::VariantDef, 35 adt::VariantDef,
37 code_model::TypeAlias, 36 code_model::TypeAlias,
38 db::HirDatabase, 37 db::HirDatabase,
39 diagnostics::DiagnosticSink, 38 diagnostics::DiagnosticSink,
40 expr::{ 39 expr::{BindingAnnotation, Body, ExprId, PatId},
41 self, Array, BinaryOp, BindingAnnotation, Body, Expr, ExprId, Literal, Pat, PatId,
42 RecordFieldPat, Statement, UnaryOp,
43 },
44 generics::{GenericParams, HasGenericParams},
45 lang_item::LangItemTarget,
46 name, 40 name,
47 nameres::Namespace, 41 path::known,
48 path::{known, GenericArg, GenericArgs},
49 resolve::{Resolver, TypeNs}, 42 resolve::{Resolver, TypeNs},
50 ty::infer::diagnostics::InferenceDiagnostic, 43 ty::infer::diagnostics::InferenceDiagnostic,
51 type_ref::{Mutability, TypeRef}, 44 type_ref::{Mutability, TypeRef},
52 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Name, Path, StructField, 45 Adt, AssocItem, ConstData, DefWithBody, FnData, Function, HasBody, Path, StructField,
53}; 46};
54 47
48macro_rules! ty_app {
49 ($ctor:pat, $param:pat) => {
50 crate::ty::Ty::Apply(crate::ty::ApplicationTy { ctor: $ctor, parameters: $param })
51 };
52 ($ctor:pat) => {
53 ty_app!($ctor, _)
54 };
55}
56
55mod unify; 57mod unify;
56mod path; 58mod path;
59mod expr;
60mod pat;
61mod coerce;
57 62
58/// The entry point of type inference. 63/// The entry point of type inference.
59pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> { 64pub fn infer_query(db: &impl HirDatabase, def: DefWithBody) -> Arc<InferenceResult> {
@@ -197,15 +202,6 @@ struct InferenceContext<'a, D: HirDatabase> {
197 coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>, 202 coerce_unsized_map: FxHashMap<(TypeCtor, TypeCtor), usize>,
198} 203}
199 204
200macro_rules! ty_app {
201 ($ctor:pat, $param:pat) => {
202 Ty::Apply(ApplicationTy { ctor: $ctor, parameters: $param })
203 };
204 ($ctor:pat) => {
205 ty_app!($ctor, _)
206 };
207}
208
209impl<'a, D: HirDatabase> InferenceContext<'a, D> { 205impl<'a, D: HirDatabase> InferenceContext<'a, D> {
210 fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self { 206 fn new(db: &'a D, body: Arc<Body>, resolver: Resolver) -> Self {
211 InferenceContext { 207 InferenceContext {
@@ -221,45 +217,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
221 } 217 }
222 } 218 }
223 219
224 fn init_coerce_unsized_map(
225 db: &'a D,
226 resolver: &Resolver,
227 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
228 let krate = resolver.krate().unwrap();
229 let impls = match db.lang_item(krate, "coerce_unsized".into()) {
230 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate, trait_),
231 _ => return FxHashMap::default(),
232 };
233
234 impls
235 .iter()
236 .filter_map(|impl_block| {
237 // `CoerseUnsized` has one generic parameter for the target type.
238 let trait_ref = impl_block.target_trait_ref(db)?;
239 let cur_from_ty = trait_ref.substs.0.get(0)?;
240 let cur_to_ty = trait_ref.substs.0.get(1)?;
241
242 match (&cur_from_ty, cur_to_ty) {
243 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => {
244 // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type.
245 // This works for smart-pointer-like coercion, which covers all impls from std.
246 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| {
247 match (ty1, ty2) {
248 (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. })
249 if p1 != p2 =>
250 {
251 Some(((*ctor1, *ctor2), i))
252 }
253 _ => None,
254 }
255 })
256 }
257 _ => None,
258 }
259 })
260 .collect()
261 }
262
263 fn resolve_all(mut self) -> InferenceResult { 220 fn resolve_all(mut self) -> InferenceResult {
264 // FIXME resolve obligations as well (use Guidance if necessary) 221 // FIXME resolve obligations as well (use Guidance if necessary)
265 let mut result = mem::replace(&mut self.result, InferenceResult::default()); 222 let mut result = mem::replace(&mut self.result, InferenceResult::default());
@@ -457,7 +414,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
457 // recursive type 414 // recursive type
458 return tv.fallback_value(); 415 return tv.fallback_value();
459 } 416 }
460 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 417 if let Some(known_ty) =
418 self.var_unification_table.inlined_probe_value(inner).known()
419 {
461 // known_ty may contain other variables that are known by now 420 // known_ty may contain other variables that are known by now
462 tv_stack.push(inner); 421 tv_stack.push(inner);
463 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone()); 422 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
@@ -485,7 +444,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
485 match &*ty { 444 match &*ty {
486 Ty::Infer(tv) => { 445 Ty::Infer(tv) => {
487 let inner = tv.to_inner(); 446 let inner = tv.to_inner();
488 match self.var_unification_table.probe_value(inner).known() { 447 match self.var_unification_table.inlined_probe_value(inner).known() {
489 Some(known_ty) => { 448 Some(known_ty) => {
490 // The known_ty can't be a type var itself 449 // The known_ty can't be a type var itself
491 ty = Cow::Owned(known_ty.clone()); 450 ty = Cow::Owned(known_ty.clone());
@@ -533,7 +492,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
533 // recursive type 492 // recursive type
534 return tv.fallback_value(); 493 return tv.fallback_value();
535 } 494 }
536 if let Some(known_ty) = self.var_unification_table.probe_value(inner).known() { 495 if let Some(known_ty) =
496 self.var_unification_table.inlined_probe_value(inner).known()
497 {
537 // known_ty may contain other variables that are known by now 498 // known_ty may contain other variables that are known by now
538 tv_stack.push(inner); 499 tv_stack.push(inner);
539 let result = self.resolve_ty_completely(tv_stack, known_ty.clone()); 500 let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
@@ -559,6 +520,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
559 match resolver.resolve_path_in_type_ns_fully(self.db, &path) { 520 match resolver.resolve_path_in_type_ns_fully(self.db, &path) {
560 Some(TypeNs::Adt(Adt::Struct(it))) => it.into(), 521 Some(TypeNs::Adt(Adt::Struct(it))) => it.into(),
561 Some(TypeNs::Adt(Adt::Union(it))) => it.into(), 522 Some(TypeNs::Adt(Adt::Union(it))) => it.into(),
523 Some(TypeNs::AdtSelfType(adt)) => adt.into(),
562 Some(TypeNs::EnumVariant(it)) => it.into(), 524 Some(TypeNs::EnumVariant(it)) => it.into(),
563 Some(TypeNs::TypeAlias(it)) => it.into(), 525 Some(TypeNs::TypeAlias(it)) => it.into(),
564 526
@@ -594,1080 +556,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
594 } 556 }
595 } 557 }
596 558
597 fn infer_tuple_struct_pat(
598 &mut self,
599 path: Option<&Path>,
600 subpats: &[PatId],
601 expected: &Ty,
602 default_bm: BindingMode,
603 ) -> Ty {
604 let (ty, def) = self.resolve_variant(path);
605
606 self.unify(&ty, expected);
607
608 let substs = ty.substs().unwrap_or_else(Substs::empty);
609
610 for (i, &subpat) in subpats.iter().enumerate() {
611 let expected_ty = def
612 .and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
613 .map_or(Ty::Unknown, |field| field.ty(self.db))
614 .subst(&substs);
615 let expected_ty = self.normalize_associated_types_in(expected_ty);
616 self.infer_pat(subpat, &expected_ty, default_bm);
617 }
618
619 ty
620 }
621
622 fn infer_record_pat(
623 &mut self,
624 path: Option<&Path>,
625 subpats: &[RecordFieldPat],
626 expected: &Ty,
627 default_bm: BindingMode,
628 id: PatId,
629 ) -> Ty {
630 let (ty, def) = self.resolve_variant(path);
631 if let Some(variant) = def {
632 self.write_variant_resolution(id.into(), variant);
633 }
634
635 self.unify(&ty, expected);
636
637 let substs = ty.substs().unwrap_or_else(Substs::empty);
638
639 for subpat in subpats {
640 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
641 let expected_ty =
642 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
643 let expected_ty = self.normalize_associated_types_in(expected_ty);
644 self.infer_pat(subpat.pat, &expected_ty, default_bm);
645 }
646
647 ty
648 }
649
650 fn infer_pat(&mut self, pat: PatId, mut expected: &Ty, mut default_bm: BindingMode) -> Ty {
651 let body = Arc::clone(&self.body); // avoid borrow checker problem
652
653 let is_non_ref_pat = match &body[pat] {
654 Pat::Tuple(..)
655 | Pat::TupleStruct { .. }
656 | Pat::Record { .. }
657 | Pat::Range { .. }
658 | Pat::Slice { .. } => true,
659 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
660 Pat::Path(..) | Pat::Lit(..) => true,
661 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
662 };
663 if is_non_ref_pat {
664 while let Some((inner, mutability)) = expected.as_reference() {
665 expected = inner;
666 default_bm = match default_bm {
667 BindingMode::Move => BindingMode::Ref(mutability),
668 BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
669 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
670 }
671 }
672 } else if let Pat::Ref { .. } = &body[pat] {
673 tested_by!(match_ergonomics_ref);
674 // When you encounter a `&pat` pattern, reset to Move.
675 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
676 default_bm = BindingMode::Move;
677 }
678
679 // Lose mutability.
680 let default_bm = default_bm;
681 let expected = expected;
682
683 let ty = match &body[pat] {
684 Pat::Tuple(ref args) => {
685 let expectations = match expected.as_tuple() {
686 Some(parameters) => &*parameters.0,
687 _ => &[],
688 };
689 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
690
691 let inner_tys = args
692 .iter()
693 .zip(expectations_iter)
694 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
695 .collect();
696
697 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
698 }
699 Pat::Ref { pat, mutability } => {
700 let expectation = match expected.as_reference() {
701 Some((inner_ty, exp_mut)) => {
702 if *mutability != exp_mut {
703 // FIXME: emit type error?
704 }
705 inner_ty
706 }
707 _ => &Ty::Unknown,
708 };
709 let subty = self.infer_pat(*pat, expectation, default_bm);
710 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
711 }
712 Pat::TupleStruct { path: p, args: subpats } => {
713 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
714 }
715 Pat::Record { path: p, args: fields } => {
716 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
717 }
718 Pat::Path(path) => {
719 // FIXME use correct resolver for the surrounding expression
720 let resolver = self.resolver.clone();
721 self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
722 }
723 Pat::Bind { mode, name: _, subpat } => {
724 let mode = if mode == &BindingAnnotation::Unannotated {
725 default_bm
726 } else {
727 BindingMode::convert(*mode)
728 };
729 let inner_ty = if let Some(subpat) = subpat {
730 self.infer_pat(*subpat, expected, default_bm)
731 } else {
732 expected.clone()
733 };
734 let inner_ty = self.insert_type_vars_shallow(inner_ty);
735
736 let bound_ty = match mode {
737 BindingMode::Ref(mutability) => {
738 Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone())
739 }
740 BindingMode::Move => inner_ty.clone(),
741 };
742 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
743 self.write_pat_ty(pat, bound_ty);
744 return inner_ty;
745 }
746 _ => Ty::Unknown,
747 };
748 // use a new type variable if we got Ty::Unknown here
749 let ty = self.insert_type_vars_shallow(ty);
750 self.unify(&ty, expected);
751 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
752 self.write_pat_ty(pat, ty.clone());
753 ty
754 }
755
756 fn substs_for_method_call(
757 &mut self,
758 def_generics: Option<Arc<GenericParams>>,
759 generic_args: Option<&GenericArgs>,
760 receiver_ty: &Ty,
761 ) -> Substs {
762 let (parent_param_count, param_count) =
763 def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
764 let mut substs = Vec::with_capacity(parent_param_count + param_count);
765 // Parent arguments are unknown, except for the receiver type
766 if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) {
767 for param in &parent_generics.params {
768 if param.name == name::SELF_TYPE {
769 substs.push(receiver_ty.clone());
770 } else {
771 substs.push(Ty::Unknown);
772 }
773 }
774 }
775 // handle provided type arguments
776 if let Some(generic_args) = generic_args {
777 // if args are provided, it should be all of them, but we can't rely on that
778 for arg in generic_args.args.iter().take(param_count) {
779 match arg {
780 GenericArg::Type(type_ref) => {
781 let ty = self.make_ty(type_ref);
782 substs.push(ty);
783 }
784 }
785 }
786 };
787 let supplied_params = substs.len();
788 for _ in supplied_params..parent_param_count + param_count {
789 substs.push(Ty::Unknown);
790 }
791 assert_eq!(substs.len(), parent_param_count + param_count);
792 Substs(substs.into())
793 }
794
795 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
796 if let Ty::Apply(a_ty) = callable_ty {
797 if let TypeCtor::FnDef(def) = a_ty.ctor {
798 let generic_predicates = self.db.generic_predicates(def.into());
799 for predicate in generic_predicates.iter() {
800 let predicate = predicate.clone().subst(&a_ty.parameters);
801 if let Some(obligation) = Obligation::from_predicate(predicate) {
802 self.obligations.push(obligation);
803 }
804 }
805 // add obligation for trait implementation, if this is a trait method
806 match def {
807 CallableDef::Function(f) => {
808 if let Some(trait_) = f.parent_trait(self.db) {
809 // construct a TraitDef
810 let substs = a_ty.parameters.prefix(
811 trait_.generic_params(self.db).count_params_including_parent(),
812 );
813 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
814 }
815 }
816 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {}
817 }
818 }
819 }
820 }
821
822 fn infer_method_call(
823 &mut self,
824 tgt_expr: ExprId,
825 receiver: ExprId,
826 args: &[ExprId],
827 method_name: &Name,
828 generic_args: Option<&GenericArgs>,
829 ) -> Ty {
830 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
831 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone());
832 let resolved = method_resolution::lookup_method(
833 &canonicalized_receiver.value,
834 self.db,
835 method_name,
836 &self.resolver,
837 );
838 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
839 Some((ty, func)) => {
840 let ty = canonicalized_receiver.decanonicalize_ty(ty);
841 self.write_method_resolution(tgt_expr, func);
842 (
843 ty,
844 self.db.type_for_def(func.into(), Namespace::Values),
845 Some(func.generic_params(self.db)),
846 )
847 }
848 None => (receiver_ty, Ty::Unknown, None),
849 };
850 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
851 let method_ty = method_ty.apply_substs(substs);
852 let method_ty = self.insert_type_vars(method_ty);
853 self.register_obligations_for_call(&method_ty);
854 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
855 Some(sig) => {
856 if !sig.params().is_empty() {
857 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
858 } else {
859 (Ty::Unknown, Vec::new(), sig.ret().clone())
860 }
861 }
862 None => (Ty::Unknown, Vec::new(), Ty::Unknown),
863 };
864 // Apply autoref so the below unification works correctly
865 // FIXME: return correct autorefs from lookup_method
866 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
867 Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty),
868 _ => derefed_receiver_ty,
869 };
870 self.unify(&expected_receiver_ty, &actual_receiver_ty);
871
872 self.check_call_arguments(args, &param_tys);
873 let ret_ty = self.normalize_associated_types_in(ret_ty);
874 ret_ty
875 }
876
877 /// Infer type of expression with possibly implicit coerce to the expected type.
878 /// Return the type after possible coercion.
879 fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
880 let ty = self.infer_expr_inner(expr, &expected);
881 let ty = if !self.coerce(&ty, &expected.ty) {
882 self.result
883 .type_mismatches
884 .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() });
885 // Return actual type when type mismatch.
886 // This is needed for diagnostic when return type mismatch.
887 ty
888 } else if expected.ty == Ty::Unknown {
889 ty
890 } else {
891 expected.ty.clone()
892 };
893
894 self.resolve_ty_as_possible(&mut vec![], ty)
895 }
896
897 /// Merge two types from different branches, with possible implicit coerce.
898 ///
899 /// Note that it is only possible that one type are coerced to another.
900 /// Coercing both types to another least upper bound type is not possible in rustc,
901 /// which will simply result in "incompatible types" error.
902 fn coerce_merge_branch<'t>(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
903 if self.coerce(ty1, ty2) {
904 ty2.clone()
905 } else if self.coerce(ty2, ty1) {
906 ty1.clone()
907 } else {
908 tested_by!(coerce_merge_fail_fallback);
909 // For incompatible types, we use the latter one as result
910 // to be better recovery for `if` without `else`.
911 ty2.clone()
912 }
913 }
914
915 /// Unify two types, but may coerce the first one to the second one
916 /// using "implicit coercion rules" if needed.
917 ///
918 /// See: https://doc.rust-lang.org/nomicon/coercions.html
919 fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
920 let from_ty = self.resolve_ty_shallow(from_ty).into_owned();
921 let to_ty = self.resolve_ty_shallow(to_ty);
922 self.coerce_inner(from_ty, &to_ty)
923 }
924
925 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
926 match (&from_ty, to_ty) {
927 // Never type will make type variable to fallback to Never Type instead of Unknown.
928 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => {
929 let var = self.new_maybe_never_type_var();
930 self.var_unification_table.union_value(*tv, TypeVarValue::Known(var));
931 return true;
932 }
933 (ty_app!(TypeCtor::Never), _) => return true,
934
935 // Trivial cases, this should go after `never` check to
936 // avoid infer result type to be never
937 _ => {
938 if self.unify_inner_trivial(&from_ty, &to_ty) {
939 return true;
940 }
941 }
942 }
943
944 // Pointer weakening and function to pointer
945 match (&mut from_ty, to_ty) {
946 // `*mut T`, `&mut T, `&T`` -> `*const T`
947 // `&mut T` -> `&T`
948 // `&mut T` -> `*mut T`
949 (ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
950 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
951 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared)))
952 | (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => {
953 *c1 = *c2;
954 }
955
956 // Illegal mutablity conversion
957 (
958 ty_app!(TypeCtor::RawPtr(Mutability::Shared)),
959 ty_app!(TypeCtor::RawPtr(Mutability::Mut)),
960 )
961 | (
962 ty_app!(TypeCtor::Ref(Mutability::Shared)),
963 ty_app!(TypeCtor::Ref(Mutability::Mut)),
964 ) => return false,
965
966 // `{function_type}` -> `fn()`
967 (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => {
968 match from_ty.callable_sig(self.db) {
969 None => return false,
970 Some(sig) => {
971 let num_args = sig.params_and_return.len() as u16 - 1;
972 from_ty =
973 Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
974 }
975 }
976 }
977
978 _ => {}
979 }
980
981 if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) {
982 return ret;
983 }
984
985 // Auto Deref if cannot coerce
986 match (&from_ty, to_ty) {
987 // FIXME: DerefMut
988 (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => {
989 self.unify_autoderef_behind_ref(&st1[0], &st2[0])
990 }
991
992 // Otherwise, normal unify
993 _ => self.unify(&from_ty, to_ty),
994 }
995 }
996
997 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
998 ///
999 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html
1000 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> {
1001 let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) {
1002 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2),
1003 _ => return None,
1004 };
1005
1006 let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?;
1007
1008 // Check `Unsize` first
1009 match self.check_unsize_and_coerce(
1010 st1.0.get(coerce_generic_index)?,
1011 st2.0.get(coerce_generic_index)?,
1012 0,
1013 ) {
1014 Some(true) => {}
1015 ret => return ret,
1016 }
1017
1018 let ret = st1
1019 .iter()
1020 .zip(st2.iter())
1021 .enumerate()
1022 .filter(|&(idx, _)| idx != coerce_generic_index)
1023 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
1024
1025 Some(ret)
1026 }
1027
1028 /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds.
1029 ///
1030 /// It should not be directly called. It is only used by `try_coerce_unsized`.
1031 ///
1032 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html
1033 fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> {
1034 if depth > 1000 {
1035 panic!("Infinite recursion in coercion");
1036 }
1037
1038 match (&from_ty, &to_ty) {
1039 // `[T; N]` -> `[T]`
1040 (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => {
1041 Some(self.unify(&st1[0], &st2[0]))
1042 }
1043
1044 // `T` -> `dyn Trait` when `T: Trait`
1045 (_, Ty::Dyn(_)) => {
1046 // FIXME: Check predicates
1047 Some(true)
1048 }
1049
1050 // `(..., T)` -> `(..., U)` when `T: Unsize<U>`
1051 (
1052 ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1),
1053 ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2),
1054 ) => {
1055 if len1 != len2 || *len1 == 0 {
1056 return None;
1057 }
1058
1059 match self.check_unsize_and_coerce(
1060 st1.last().unwrap(),
1061 st2.last().unwrap(),
1062 depth + 1,
1063 ) {
1064 Some(true) => {}
1065 ret => return ret,
1066 }
1067
1068 let ret = st1[..st1.len() - 1]
1069 .iter()
1070 .zip(&st2[..st2.len() - 1])
1071 .all(|(ty1, ty2)| self.unify(ty1, ty2));
1072
1073 Some(ret)
1074 }
1075
1076 // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if:
1077 // - T: Unsize<U>
1078 // - Foo is a struct
1079 // - Only the last field of Foo has a type involving T
1080 // - T is not part of the type of any other fields
1081 // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T>
1082 (
1083 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
1084 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
1085 ) if struct1 == struct2 => {
1086 let fields = struct1.fields(self.db);
1087 let (last_field, prev_fields) = fields.split_last()?;
1088
1089 // Get the generic parameter involved in the last field.
1090 let unsize_generic_index = {
1091 let mut index = None;
1092 let mut multiple_param = false;
1093 last_field.ty(self.db).walk(&mut |ty| match ty {
1094 &Ty::Param { idx, .. } => {
1095 if index.is_none() {
1096 index = Some(idx);
1097 } else if Some(idx) != index {
1098 multiple_param = true;
1099 }
1100 }
1101 _ => {}
1102 });
1103
1104 if multiple_param {
1105 return None;
1106 }
1107 index?
1108 };
1109
1110 // Check other fields do not involve it.
1111 let mut multiple_used = false;
1112 prev_fields.iter().for_each(|field| {
1113 field.ty(self.db).walk(&mut |ty| match ty {
1114 &Ty::Param { idx, .. } if idx == unsize_generic_index => {
1115 multiple_used = true
1116 }
1117 _ => {}
1118 })
1119 });
1120 if multiple_used {
1121 return None;
1122 }
1123
1124 let unsize_generic_index = unsize_generic_index as usize;
1125
1126 // Check `Unsize` first
1127 match self.check_unsize_and_coerce(
1128 st1.get(unsize_generic_index)?,
1129 st2.get(unsize_generic_index)?,
1130 depth + 1,
1131 ) {
1132 Some(true) => {}
1133 ret => return ret,
1134 }
1135
1136 // Then unify other parameters
1137 let ret = st1
1138 .iter()
1139 .zip(st2.iter())
1140 .enumerate()
1141 .filter(|&(idx, _)| idx != unsize_generic_index)
1142 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
1143
1144 Some(ret)
1145 }
1146
1147 _ => None,
1148 }
1149 }
1150
1151 /// Unify `from_ty` to `to_ty` with optional auto Deref
1152 ///
1153 /// Note that the parameters are already stripped the outer reference.
1154 fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
1155 let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone());
1156 let to_ty = self.resolve_ty_shallow(&to_ty);
1157 // FIXME: Auto DerefMut
1158 for derefed_ty in
1159 autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone())
1160 {
1161 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
1162 match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) {
1163 // Stop when constructor matches.
1164 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => {
1165 // It will not recurse to `coerce`.
1166 return self.unify_substs(st1, st2, 0);
1167 }
1168 _ => {}
1169 }
1170 }
1171
1172 false
1173 }
1174
1175 fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
1176 let ty = self.infer_expr_inner(tgt_expr, expected);
1177 let could_unify = self.unify(&ty, &expected.ty);
1178 if !could_unify {
1179 self.result.type_mismatches.insert(
1180 tgt_expr,
1181 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
1182 );
1183 }
1184 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1185 ty
1186 }
1187
1188 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
1189 let body = Arc::clone(&self.body); // avoid borrow checker problem
1190 let ty = match &body[tgt_expr] {
1191 Expr::Missing => Ty::Unknown,
1192 Expr::If { condition, then_branch, else_branch } => {
1193 // if let is desugared to match, so this is always simple if
1194 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
1195
1196 let then_ty = self.infer_expr_inner(*then_branch, &expected);
1197 let else_ty = match else_branch {
1198 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
1199 None => Ty::unit(),
1200 };
1201
1202 self.coerce_merge_branch(&then_ty, &else_ty)
1203 }
1204 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
1205 Expr::TryBlock { body } => {
1206 let _inner = self.infer_expr(*body, expected);
1207 // FIXME should be std::result::Result<{inner}, _>
1208 Ty::Unknown
1209 }
1210 Expr::Loop { body } => {
1211 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
1212 // FIXME handle break with value
1213 Ty::simple(TypeCtor::Never)
1214 }
1215 Expr::While { condition, body } => {
1216 // while let is desugared to a match loop, so this is always simple while
1217 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
1218 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
1219 Ty::unit()
1220 }
1221 Expr::For { iterable, body, pat } => {
1222 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
1223
1224 let pat_ty = match self.resolve_into_iter_item() {
1225 Some(into_iter_item_alias) => {
1226 let pat_ty = self.new_type_var();
1227 let projection = ProjectionPredicate {
1228 ty: pat_ty.clone(),
1229 projection_ty: ProjectionTy {
1230 associated_ty: into_iter_item_alias,
1231 parameters: Substs::single(iterable_ty),
1232 },
1233 };
1234 self.obligations.push(Obligation::Projection(projection));
1235 self.resolve_ty_as_possible(&mut vec![], pat_ty)
1236 }
1237 None => Ty::Unknown,
1238 };
1239
1240 self.infer_pat(*pat, &pat_ty, BindingMode::default());
1241 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
1242 Ty::unit()
1243 }
1244 Expr::Lambda { body, args, arg_types } => {
1245 assert_eq!(args.len(), arg_types.len());
1246
1247 let mut sig_tys = Vec::new();
1248
1249 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
1250 let expected = if let Some(type_ref) = arg_type {
1251 self.make_ty(type_ref)
1252 } else {
1253 Ty::Unknown
1254 };
1255 let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
1256 sig_tys.push(arg_ty);
1257 }
1258
1259 // add return type
1260 let ret_ty = self.new_type_var();
1261 sig_tys.push(ret_ty.clone());
1262 let sig_ty = Ty::apply(
1263 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
1264 Substs(sig_tys.into()),
1265 );
1266 let closure_ty = Ty::apply_one(
1267 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
1268 sig_ty,
1269 );
1270
1271 // Eagerly try to relate the closure type with the expected
1272 // type, otherwise we often won't have enough information to
1273 // infer the body.
1274 self.coerce(&closure_ty, &expected.ty);
1275
1276 self.infer_expr(*body, &Expectation::has_type(ret_ty));
1277 closure_ty
1278 }
1279 Expr::Call { callee, args } => {
1280 let callee_ty = self.infer_expr(*callee, &Expectation::none());
1281 let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) {
1282 Some(sig) => (sig.params().to_vec(), sig.ret().clone()),
1283 None => {
1284 // Not callable
1285 // FIXME: report an error
1286 (Vec::new(), Ty::Unknown)
1287 }
1288 };
1289 self.register_obligations_for_call(&callee_ty);
1290 self.check_call_arguments(args, &param_tys);
1291 let ret_ty = self.normalize_associated_types_in(ret_ty);
1292 ret_ty
1293 }
1294 Expr::MethodCall { receiver, args, method_name, generic_args } => self
1295 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
1296 Expr::Match { expr, arms } => {
1297 let input_ty = self.infer_expr(*expr, &Expectation::none());
1298
1299 let mut result_ty = self.new_maybe_never_type_var();
1300
1301 for arm in arms {
1302 for &pat in &arm.pats {
1303 let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
1304 }
1305 if let Some(guard_expr) = arm.guard {
1306 self.infer_expr(
1307 guard_expr,
1308 &Expectation::has_type(Ty::simple(TypeCtor::Bool)),
1309 );
1310 }
1311
1312 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
1313 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
1314 }
1315
1316 result_ty
1317 }
1318 Expr::Path(p) => {
1319 // FIXME this could be more efficient...
1320 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
1321 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
1322 }
1323 Expr::Continue => Ty::simple(TypeCtor::Never),
1324 Expr::Break { expr } => {
1325 if let Some(expr) = expr {
1326 // FIXME handle break with value
1327 self.infer_expr(*expr, &Expectation::none());
1328 }
1329 Ty::simple(TypeCtor::Never)
1330 }
1331 Expr::Return { expr } => {
1332 if let Some(expr) = expr {
1333 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()));
1334 }
1335 Ty::simple(TypeCtor::Never)
1336 }
1337 Expr::RecordLit { path, fields, spread } => {
1338 let (ty, def_id) = self.resolve_variant(path.as_ref());
1339 if let Some(variant) = def_id {
1340 self.write_variant_resolution(tgt_expr.into(), variant);
1341 }
1342
1343 self.unify(&ty, &expected.ty);
1344
1345 let substs = ty.substs().unwrap_or_else(Substs::empty);
1346 for (field_idx, field) in fields.iter().enumerate() {
1347 let field_ty = def_id
1348 .and_then(|it| match it.field(self.db, &field.name) {
1349 Some(field) => Some(field),
1350 None => {
1351 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
1352 expr: tgt_expr,
1353 field: field_idx,
1354 });
1355 None
1356 }
1357 })
1358 .map_or(Ty::Unknown, |field| field.ty(self.db))
1359 .subst(&substs);
1360 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
1361 }
1362 if let Some(expr) = spread {
1363 self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
1364 }
1365 ty
1366 }
1367 Expr::Field { expr, name } => {
1368 let receiver_ty = self.infer_expr(*expr, &Expectation::none());
1369 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty);
1370 let ty = autoderef::autoderef(
1371 self.db,
1372 &self.resolver.clone(),
1373 canonicalized.value.clone(),
1374 )
1375 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) {
1376 Ty::Apply(a_ty) => match a_ty.ctor {
1377 TypeCtor::Tuple { .. } => name
1378 .as_tuple_index()
1379 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
1380 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
1381 self.write_field_resolution(tgt_expr, field);
1382 field.ty(self.db).subst(&a_ty.parameters)
1383 }),
1384 _ => None,
1385 },
1386 _ => None,
1387 })
1388 .unwrap_or(Ty::Unknown);
1389 let ty = self.insert_type_vars(ty);
1390 self.normalize_associated_types_in(ty)
1391 }
1392 Expr::Await { expr } => {
1393 let inner_ty = self.infer_expr(*expr, &Expectation::none());
1394 let ty = match self.resolve_future_future_output() {
1395 Some(future_future_output_alias) => {
1396 let ty = self.new_type_var();
1397 let projection = ProjectionPredicate {
1398 ty: ty.clone(),
1399 projection_ty: ProjectionTy {
1400 associated_ty: future_future_output_alias,
1401 parameters: Substs::single(inner_ty),
1402 },
1403 };
1404 self.obligations.push(Obligation::Projection(projection));
1405 self.resolve_ty_as_possible(&mut vec![], ty)
1406 }
1407 None => Ty::Unknown,
1408 };
1409 ty
1410 }
1411 Expr::Try { expr } => {
1412 let inner_ty = self.infer_expr(*expr, &Expectation::none());
1413 let ty = match self.resolve_ops_try_ok() {
1414 Some(ops_try_ok_alias) => {
1415 let ty = self.new_type_var();
1416 let projection = ProjectionPredicate {
1417 ty: ty.clone(),
1418 projection_ty: ProjectionTy {
1419 associated_ty: ops_try_ok_alias,
1420 parameters: Substs::single(inner_ty),
1421 },
1422 };
1423 self.obligations.push(Obligation::Projection(projection));
1424 self.resolve_ty_as_possible(&mut vec![], ty)
1425 }
1426 None => Ty::Unknown,
1427 };
1428 ty
1429 }
1430 Expr::Cast { expr, type_ref } => {
1431 let _inner_ty = self.infer_expr(*expr, &Expectation::none());
1432 let cast_ty = self.make_ty(type_ref);
1433 // FIXME check the cast...
1434 cast_ty
1435 }
1436 Expr::Ref { expr, mutability } => {
1437 let expectation =
1438 if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() {
1439 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
1440 // FIXME: throw type error - expected mut reference but found shared ref,
1441 // which cannot be coerced
1442 }
1443 Expectation::has_type(Ty::clone(exp_inner))
1444 } else {
1445 Expectation::none()
1446 };
1447 // FIXME reference coercions etc.
1448 let inner_ty = self.infer_expr(*expr, &expectation);
1449 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
1450 }
1451 Expr::Box { expr } => {
1452 let inner_ty = self.infer_expr(*expr, &Expectation::none());
1453 if let Some(box_) = self.resolve_boxed_box() {
1454 Ty::apply_one(TypeCtor::Adt(box_), inner_ty)
1455 } else {
1456 Ty::Unknown
1457 }
1458 }
1459 Expr::UnaryOp { expr, op } => {
1460 let inner_ty = self.infer_expr(*expr, &Expectation::none());
1461 match op {
1462 UnaryOp::Deref => {
1463 let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty);
1464 if let Some(derefed_ty) =
1465 autoderef::deref(self.db, &self.resolver, &canonicalized.value)
1466 {
1467 canonicalized.decanonicalize_ty(derefed_ty.value)
1468 } else {
1469 Ty::Unknown
1470 }
1471 }
1472 UnaryOp::Neg => {
1473 match &inner_ty {
1474 Ty::Apply(a_ty) => match a_ty.ctor {
1475 TypeCtor::Int(primitive::UncertainIntTy::Unknown)
1476 | TypeCtor::Int(primitive::UncertainIntTy::Known(
1477 primitive::IntTy {
1478 signedness: primitive::Signedness::Signed,
1479 ..
1480 },
1481 ))
1482 | TypeCtor::Float(..) => inner_ty,
1483 _ => Ty::Unknown,
1484 },
1485 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
1486 inner_ty
1487 }
1488 // FIXME: resolve ops::Neg trait
1489 _ => Ty::Unknown,
1490 }
1491 }
1492 UnaryOp::Not => {
1493 match &inner_ty {
1494 Ty::Apply(a_ty) => match a_ty.ctor {
1495 TypeCtor::Bool | TypeCtor::Int(_) => inner_ty,
1496 _ => Ty::Unknown,
1497 },
1498 Ty::Infer(InferTy::IntVar(..)) => inner_ty,
1499 // FIXME: resolve ops::Not trait for inner_ty
1500 _ => Ty::Unknown,
1501 }
1502 }
1503 }
1504 }
1505 Expr::BinaryOp { lhs, rhs, op } => match op {
1506 Some(op) => {
1507 let lhs_expectation = match op {
1508 BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)),
1509 _ => Expectation::none(),
1510 };
1511 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
1512 // FIXME: find implementation of trait corresponding to operation
1513 // symbol and resolve associated `Output` type
1514 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty);
1515 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation));
1516
1517 // FIXME: similar as above, return ty is often associated trait type
1518 op::binary_op_return_ty(*op, rhs_ty)
1519 }
1520 _ => Ty::Unknown,
1521 },
1522 Expr::Index { base, index } => {
1523 let _base_ty = self.infer_expr(*base, &Expectation::none());
1524 let _index_ty = self.infer_expr(*index, &Expectation::none());
1525 // FIXME: use `std::ops::Index::Output` to figure out the real return type
1526 Ty::Unknown
1527 }
1528 Expr::Tuple { exprs } => {
1529 let mut tys = match &expected.ty {
1530 ty_app!(TypeCtor::Tuple { .. }, st) => st
1531 .iter()
1532 .cloned()
1533 .chain(repeat_with(|| self.new_type_var()))
1534 .take(exprs.len())
1535 .collect::<Vec<_>>(),
1536 _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(),
1537 };
1538
1539 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
1540 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
1541 }
1542
1543 Ty::apply(TypeCtor::Tuple { cardinality: tys.len() as u16 }, Substs(tys.into()))
1544 }
1545 Expr::Array(array) => {
1546 let elem_ty = match &expected.ty {
1547 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
1548 st.as_single().clone()
1549 }
1550 _ => self.new_type_var(),
1551 };
1552
1553 match array {
1554 Array::ElementList(items) => {
1555 for expr in items.iter() {
1556 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
1557 }
1558 }
1559 Array::Repeat { initializer, repeat } => {
1560 self.infer_expr_coerce(
1561 *initializer,
1562 &Expectation::has_type(elem_ty.clone()),
1563 );
1564 self.infer_expr(
1565 *repeat,
1566 &Expectation::has_type(Ty::simple(TypeCtor::Int(
1567 primitive::UncertainIntTy::Known(primitive::IntTy::usize()),
1568 ))),
1569 );
1570 }
1571 }
1572
1573 Ty::apply_one(TypeCtor::Array, elem_ty)
1574 }
1575 Expr::Literal(lit) => match lit {
1576 Literal::Bool(..) => Ty::simple(TypeCtor::Bool),
1577 Literal::String(..) => {
1578 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
1579 }
1580 Literal::ByteString(..) => {
1581 let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(
1582 primitive::IntTy::u8(),
1583 )));
1584 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type);
1585 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type)
1586 }
1587 Literal::Char(..) => Ty::simple(TypeCtor::Char),
1588 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int(*ty)),
1589 Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float(*ty)),
1590 },
1591 };
1592 // use a new type variable if we got Ty::Unknown here
1593 let ty = self.insert_type_vars_shallow(ty);
1594 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1595 self.write_expr_ty(tgt_expr, ty.clone());
1596 ty
1597 }
1598
1599 fn infer_block(
1600 &mut self,
1601 statements: &[Statement],
1602 tail: Option<ExprId>,
1603 expected: &Expectation,
1604 ) -> Ty {
1605 let mut diverges = false;
1606 for stmt in statements {
1607 match stmt {
1608 Statement::Let { pat, type_ref, initializer } => {
1609 let decl_ty =
1610 type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown);
1611
1612 // Always use the declared type when specified
1613 let mut ty = decl_ty.clone();
1614
1615 if let Some(expr) = initializer {
1616 let actual_ty =
1617 self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
1618 if decl_ty == Ty::Unknown {
1619 ty = actual_ty;
1620 }
1621 }
1622
1623 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
1624 self.infer_pat(*pat, &ty, BindingMode::default());
1625 }
1626 Statement::Expr(expr) => {
1627 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) {
1628 diverges = true;
1629 }
1630 }
1631 }
1632 }
1633
1634 let ty = if let Some(expr) = tail {
1635 self.infer_expr_coerce(expr, expected)
1636 } else {
1637 self.coerce(&Ty::unit(), &expected.ty);
1638 Ty::unit()
1639 };
1640 if diverges {
1641 Ty::simple(TypeCtor::Never)
1642 } else {
1643 ty
1644 }
1645 }
1646
1647 fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) {
1648 // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
1649 // We do this in a pretty awful way: first we type-check any arguments
1650 // that are not closures, then we type-check the closures. This is so
1651 // that we have more information about the types of arguments when we
1652 // type-check the functions. This isn't really the right way to do this.
1653 for &check_closures in &[false, true] {
1654 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
1655 for (&arg, param_ty) in args.iter().zip(param_iter) {
1656 let is_closure = match &self.body[arg] {
1657 Expr::Lambda { .. } => true,
1658 _ => false,
1659 };
1660
1661 if is_closure != check_closures {
1662 continue;
1663 }
1664
1665 let param_ty = self.normalize_associated_types_in(param_ty);
1666 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
1667 }
1668 }
1669 }
1670
1671 fn collect_const(&mut self, data: &ConstData) { 559 fn collect_const(&mut self, data: &ConstData) {
1672 self.return_ty = self.make_ty(data.type_ref()); 560 self.return_ty = self.make_ty(data.type_ref());
1673 } 561 }
diff --git a/crates/ra_hir/src/ty/infer/coerce.rs b/crates/ra_hir/src/ty/infer/coerce.rs
new file mode 100644
index 000000000..0429a9866
--- /dev/null
+++ b/crates/ra_hir/src/ty/infer/coerce.rs
@@ -0,0 +1,336 @@
1//! Coercion logic. Coercions are certain type conversions that can implicitly
2//! happen in certain places, e.g. weakening `&mut` to `&` or deref coercions
3//! like going from `&Vec<T>` to `&[T]`.
4//!
5//! See: https://doc.rust-lang.org/nomicon/coercions.html
6
7use rustc_hash::FxHashMap;
8
9use test_utils::tested_by;
10
11use super::{InferTy, InferenceContext, TypeVarValue};
12use crate::{
13 db::HirDatabase,
14 lang_item::LangItemTarget,
15 resolve::Resolver,
16 ty::{autoderef, Substs, Ty, TypeCtor, TypeWalk},
17 type_ref::Mutability,
18 Adt,
19};
20
21impl<'a, D: HirDatabase> InferenceContext<'a, D> {
22 /// Unify two types, but may coerce the first one to the second one
23 /// using "implicit coercion rules" if needed.
24 pub(super) fn coerce(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
25 let from_ty = self.resolve_ty_shallow(from_ty).into_owned();
26 let to_ty = self.resolve_ty_shallow(to_ty);
27 self.coerce_inner(from_ty, &to_ty)
28 }
29
30 /// Merge two types from different branches, with possible implicit coerce.
31 ///
32 /// Note that it is only possible that one type are coerced to another.
33 /// Coercing both types to another least upper bound type is not possible in rustc,
34 /// which will simply result in "incompatible types" error.
35 pub(super) fn coerce_merge_branch<'t>(&mut self, ty1: &Ty, ty2: &Ty) -> Ty {
36 if self.coerce(ty1, ty2) {
37 ty2.clone()
38 } else if self.coerce(ty2, ty1) {
39 ty1.clone()
40 } else {
41 tested_by!(coerce_merge_fail_fallback);
42 // For incompatible types, we use the latter one as result
43 // to be better recovery for `if` without `else`.
44 ty2.clone()
45 }
46 }
47
48 pub(super) fn init_coerce_unsized_map(
49 db: &'a D,
50 resolver: &Resolver,
51 ) -> FxHashMap<(TypeCtor, TypeCtor), usize> {
52 let krate = resolver.krate().unwrap();
53 let impls = match db.lang_item(krate, "coerce_unsized".into()) {
54 Some(LangItemTarget::Trait(trait_)) => db.impls_for_trait(krate, trait_),
55 _ => return FxHashMap::default(),
56 };
57
58 impls
59 .iter()
60 .filter_map(|impl_block| {
61 // `CoerseUnsized` has one generic parameter for the target type.
62 let trait_ref = impl_block.target_trait_ref(db)?;
63 let cur_from_ty = trait_ref.substs.0.get(0)?;
64 let cur_to_ty = trait_ref.substs.0.get(1)?;
65
66 match (&cur_from_ty, cur_to_ty) {
67 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => {
68 // FIXME: We return the first non-equal bound as the type parameter to coerce to unsized type.
69 // This works for smart-pointer-like coercion, which covers all impls from std.
70 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| {
71 match (ty1, ty2) {
72 (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. })
73 if p1 != p2 =>
74 {
75 Some(((*ctor1, *ctor2), i))
76 }
77 _ => None,
78 }
79 })
80 }
81 _ => None,
82 }
83 })
84 .collect()
85 }
86
87 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
88 match (&from_ty, to_ty) {
89 // Never type will make type variable to fallback to Never Type instead of Unknown.
90 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => {
91 let var = self.new_maybe_never_type_var();
92 self.var_unification_table.union_value(*tv, TypeVarValue::Known(var));
93 return true;
94 }
95 (ty_app!(TypeCtor::Never), _) => return true,
96
97 // Trivial cases, this should go after `never` check to
98 // avoid infer result type to be never
99 _ => {
100 if self.unify_inner_trivial(&from_ty, &to_ty) {
101 return true;
102 }
103 }
104 }
105
106 // Pointer weakening and function to pointer
107 match (&mut from_ty, to_ty) {
108 // `*mut T`, `&mut T, `&T`` -> `*const T`
109 // `&mut T` -> `&T`
110 // `&mut T` -> `*mut T`
111 (ty_app!(c1@TypeCtor::RawPtr(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
112 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::RawPtr(Mutability::Shared)))
113 | (ty_app!(c1@TypeCtor::Ref(_)), ty_app!(c2@TypeCtor::Ref(Mutability::Shared)))
114 | (ty_app!(c1@TypeCtor::Ref(Mutability::Mut)), ty_app!(c2@TypeCtor::RawPtr(_))) => {
115 *c1 = *c2;
116 }
117
118 // Illegal mutablity conversion
119 (
120 ty_app!(TypeCtor::RawPtr(Mutability::Shared)),
121 ty_app!(TypeCtor::RawPtr(Mutability::Mut)),
122 )
123 | (
124 ty_app!(TypeCtor::Ref(Mutability::Shared)),
125 ty_app!(TypeCtor::Ref(Mutability::Mut)),
126 ) => return false,
127
128 // `{function_type}` -> `fn()`
129 (ty_app!(TypeCtor::FnDef(_)), ty_app!(TypeCtor::FnPtr { .. })) => {
130 match from_ty.callable_sig(self.db) {
131 None => return false,
132 Some(sig) => {
133 let num_args = sig.params_and_return.len() as u16 - 1;
134 from_ty =
135 Ty::apply(TypeCtor::FnPtr { num_args }, Substs(sig.params_and_return));
136 }
137 }
138 }
139
140 _ => {}
141 }
142
143 if let Some(ret) = self.try_coerce_unsized(&from_ty, &to_ty) {
144 return ret;
145 }
146
147 // Auto Deref if cannot coerce
148 match (&from_ty, to_ty) {
149 // FIXME: DerefMut
150 (ty_app!(TypeCtor::Ref(_), st1), ty_app!(TypeCtor::Ref(_), st2)) => {
151 self.unify_autoderef_behind_ref(&st1[0], &st2[0])
152 }
153
154 // Otherwise, normal unify
155 _ => self.unify(&from_ty, to_ty),
156 }
157 }
158
159 /// Coerce a type using `from_ty: CoerceUnsized<ty_ty>`
160 ///
161 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.CoerceUnsized.html
162 fn try_coerce_unsized(&mut self, from_ty: &Ty, to_ty: &Ty) -> Option<bool> {
163 let (ctor1, st1, ctor2, st2) = match (from_ty, to_ty) {
164 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => (ctor1, st1, ctor2, st2),
165 _ => return None,
166 };
167
168 let coerce_generic_index = *self.coerce_unsized_map.get(&(*ctor1, *ctor2))?;
169
170 // Check `Unsize` first
171 match self.check_unsize_and_coerce(
172 st1.0.get(coerce_generic_index)?,
173 st2.0.get(coerce_generic_index)?,
174 0,
175 ) {
176 Some(true) => {}
177 ret => return ret,
178 }
179
180 let ret = st1
181 .iter()
182 .zip(st2.iter())
183 .enumerate()
184 .filter(|&(idx, _)| idx != coerce_generic_index)
185 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
186
187 Some(ret)
188 }
189
190 /// Check if `from_ty: Unsize<to_ty>`, and coerce to `to_ty` if it holds.
191 ///
192 /// It should not be directly called. It is only used by `try_coerce_unsized`.
193 ///
194 /// See: https://doc.rust-lang.org/nightly/std/marker/trait.Unsize.html
195 fn check_unsize_and_coerce(&mut self, from_ty: &Ty, to_ty: &Ty, depth: usize) -> Option<bool> {
196 if depth > 1000 {
197 panic!("Infinite recursion in coercion");
198 }
199
200 match (&from_ty, &to_ty) {
201 // `[T; N]` -> `[T]`
202 (ty_app!(TypeCtor::Array, st1), ty_app!(TypeCtor::Slice, st2)) => {
203 Some(self.unify(&st1[0], &st2[0]))
204 }
205
206 // `T` -> `dyn Trait` when `T: Trait`
207 (_, Ty::Dyn(_)) => {
208 // FIXME: Check predicates
209 Some(true)
210 }
211
212 // `(..., T)` -> `(..., U)` when `T: Unsize<U>`
213 (
214 ty_app!(TypeCtor::Tuple { cardinality: len1 }, st1),
215 ty_app!(TypeCtor::Tuple { cardinality: len2 }, st2),
216 ) => {
217 if len1 != len2 || *len1 == 0 {
218 return None;
219 }
220
221 match self.check_unsize_and_coerce(
222 st1.last().unwrap(),
223 st2.last().unwrap(),
224 depth + 1,
225 ) {
226 Some(true) => {}
227 ret => return ret,
228 }
229
230 let ret = st1[..st1.len() - 1]
231 .iter()
232 .zip(&st2[..st2.len() - 1])
233 .all(|(ty1, ty2)| self.unify(ty1, ty2));
234
235 Some(ret)
236 }
237
238 // Foo<..., T, ...> is Unsize<Foo<..., U, ...>> if:
239 // - T: Unsize<U>
240 // - Foo is a struct
241 // - Only the last field of Foo has a type involving T
242 // - T is not part of the type of any other fields
243 // - Bar<T>: Unsize<Bar<U>>, if the last field of Foo has type Bar<T>
244 (
245 ty_app!(TypeCtor::Adt(Adt::Struct(struct1)), st1),
246 ty_app!(TypeCtor::Adt(Adt::Struct(struct2)), st2),
247 ) if struct1 == struct2 => {
248 let fields = struct1.fields(self.db);
249 let (last_field, prev_fields) = fields.split_last()?;
250
251 // Get the generic parameter involved in the last field.
252 let unsize_generic_index = {
253 let mut index = None;
254 let mut multiple_param = false;
255 last_field.ty(self.db).walk(&mut |ty| match ty {
256 &Ty::Param { idx, .. } => {
257 if index.is_none() {
258 index = Some(idx);
259 } else if Some(idx) != index {
260 multiple_param = true;
261 }
262 }
263 _ => {}
264 });
265
266 if multiple_param {
267 return None;
268 }
269 index?
270 };
271
272 // Check other fields do not involve it.
273 let mut multiple_used = false;
274 prev_fields.iter().for_each(|field| {
275 field.ty(self.db).walk(&mut |ty| match ty {
276 &Ty::Param { idx, .. } if idx == unsize_generic_index => {
277 multiple_used = true
278 }
279 _ => {}
280 })
281 });
282 if multiple_used {
283 return None;
284 }
285
286 let unsize_generic_index = unsize_generic_index as usize;
287
288 // Check `Unsize` first
289 match self.check_unsize_and_coerce(
290 st1.get(unsize_generic_index)?,
291 st2.get(unsize_generic_index)?,
292 depth + 1,
293 ) {
294 Some(true) => {}
295 ret => return ret,
296 }
297
298 // Then unify other parameters
299 let ret = st1
300 .iter()
301 .zip(st2.iter())
302 .enumerate()
303 .filter(|&(idx, _)| idx != unsize_generic_index)
304 .all(|(_, (ty1, ty2))| self.unify(ty1, ty2));
305
306 Some(ret)
307 }
308
309 _ => None,
310 }
311 }
312
313 /// Unify `from_ty` to `to_ty` with optional auto Deref
314 ///
315 /// Note that the parameters are already stripped the outer reference.
316 fn unify_autoderef_behind_ref(&mut self, from_ty: &Ty, to_ty: &Ty) -> bool {
317 let canonicalized = self.canonicalizer().canonicalize_ty(from_ty.clone());
318 let to_ty = self.resolve_ty_shallow(&to_ty);
319 // FIXME: Auto DerefMut
320 for derefed_ty in
321 autoderef::autoderef(self.db, &self.resolver.clone(), canonicalized.value.clone())
322 {
323 let derefed_ty = canonicalized.decanonicalize_ty(derefed_ty.value);
324 match (&*self.resolve_ty_shallow(&derefed_ty), &*to_ty) {
325 // Stop when constructor matches.
326 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => {
327 // It will not recurse to `coerce`.
328 return self.unify_substs(st1, st2, 0);
329 }
330 _ => {}
331 }
332 }
333
334 false
335 }
336}
diff --git a/crates/ra_hir/src/ty/infer/expr.rs b/crates/ra_hir/src/ty/infer/expr.rs
new file mode 100644
index 000000000..f8807c742
--- /dev/null
+++ b/crates/ra_hir/src/ty/infer/expr.rs
@@ -0,0 +1,658 @@
1//! Type inference for expressions.
2
3use std::iter::{repeat, repeat_with};
4use std::sync::Arc;
5
6use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
7use crate::{
8 db::HirDatabase,
9 expr::{self, Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
10 generics::{GenericParams, HasGenericParams},
11 name,
12 nameres::Namespace,
13 path::{GenericArg, GenericArgs},
14 ty::{
15 autoderef, method_resolution, op, primitive, CallableDef, InferTy, Mutability, Obligation,
16 ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
17 },
18 Adt, Name,
19};
20
21impl<'a, D: HirDatabase> InferenceContext<'a, D> {
22 pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
23 let ty = self.infer_expr_inner(tgt_expr, expected);
24 let could_unify = self.unify(&ty, &expected.ty);
25 if !could_unify {
26 self.result.type_mismatches.insert(
27 tgt_expr,
28 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
29 );
30 }
31 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
32 ty
33 }
34
35 /// Infer type of expression with possibly implicit coerce to the expected type.
36 /// Return the type after possible coercion.
37 fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
38 let ty = self.infer_expr_inner(expr, &expected);
39 let ty = if !self.coerce(&ty, &expected.ty) {
40 self.result
41 .type_mismatches
42 .insert(expr, TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() });
43 // Return actual type when type mismatch.
44 // This is needed for diagnostic when return type mismatch.
45 ty
46 } else if expected.ty == Ty::Unknown {
47 ty
48 } else {
49 expected.ty.clone()
50 };
51
52 self.resolve_ty_as_possible(&mut vec![], ty)
53 }
54
55 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
56 let body = Arc::clone(&self.body); // avoid borrow checker problem
57 let ty = match &body[tgt_expr] {
58 Expr::Missing => Ty::Unknown,
59 Expr::If { condition, then_branch, else_branch } => {
60 // if let is desugared to match, so this is always simple if
61 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
62
63 let then_ty = self.infer_expr_inner(*then_branch, &expected);
64 let else_ty = match else_branch {
65 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
66 None => Ty::unit(),
67 };
68
69 self.coerce_merge_branch(&then_ty, &else_ty)
70 }
71 Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected),
72 Expr::TryBlock { body } => {
73 let _inner = self.infer_expr(*body, expected);
74 // FIXME should be std::result::Result<{inner}, _>
75 Ty::Unknown
76 }
77 Expr::Loop { body } => {
78 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
79 // FIXME handle break with value
80 Ty::simple(TypeCtor::Never)
81 }
82 Expr::While { condition, body } => {
83 // while let is desugared to a match loop, so this is always simple while
84 self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool)));
85 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
86 Ty::unit()
87 }
88 Expr::For { iterable, body, pat } => {
89 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
90
91 let pat_ty = match self.resolve_into_iter_item() {
92 Some(into_iter_item_alias) => {
93 let pat_ty = self.new_type_var();
94 let projection = ProjectionPredicate {
95 ty: pat_ty.clone(),
96 projection_ty: ProjectionTy {
97 associated_ty: into_iter_item_alias,
98 parameters: Substs::single(iterable_ty),
99 },
100 };
101 self.obligations.push(Obligation::Projection(projection));
102 self.resolve_ty_as_possible(&mut vec![], pat_ty)
103 }
104 None => Ty::Unknown,
105 };
106
107 self.infer_pat(*pat, &pat_ty, BindingMode::default());
108 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
109 Ty::unit()
110 }
111 Expr::Lambda { body, args, arg_types } => {
112 assert_eq!(args.len(), arg_types.len());
113
114 let mut sig_tys = Vec::new();
115
116 for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) {
117 let expected = if let Some(type_ref) = arg_type {
118 self.make_ty(type_ref)
119 } else {
120 Ty::Unknown
121 };
122 let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default());
123 sig_tys.push(arg_ty);
124 }
125
126 // add return type
127 let ret_ty = self.new_type_var();
128 sig_tys.push(ret_ty.clone());
129 let sig_ty = Ty::apply(
130 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
131 Substs(sig_tys.into()),
132 );
133 let closure_ty = Ty::apply_one(
134 TypeCtor::Closure { def: self.body.owner(), expr: tgt_expr },
135 sig_ty,
136 );
137
138 // Eagerly try to relate the closure type with the expected
139 // type, otherwise we often won't have enough information to
140 // infer the body.
141 self.coerce(&closure_ty, &expected.ty);
142
143 self.infer_expr(*body, &Expectation::has_type(ret_ty));
144 closure_ty
145 }
146 Expr::Call { callee, args } => {
147 let callee_ty = self.infer_expr(*callee, &Expectation::none());
148 let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) {
149 Some(sig) => (sig.params().to_vec(), sig.ret().clone()),
150 None => {
151 // Not callable
152 // FIXME: report an error
153 (Vec::new(), Ty::Unknown)
154 }
155 };
156 self.register_obligations_for_call(&callee_ty);
157 self.check_call_arguments(args, &param_tys);
158 let ret_ty = self.normalize_associated_types_in(ret_ty);
159 ret_ty
160 }
161 Expr::MethodCall { receiver, args, method_name, generic_args } => self
162 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()),
163 Expr::Match { expr, arms } => {
164 let input_ty = self.infer_expr(*expr, &Expectation::none());
165
166 let mut result_ty = self.new_maybe_never_type_var();
167
168 for arm in arms {
169 for &pat in &arm.pats {
170 let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
171 }
172 if let Some(guard_expr) = arm.guard {
173 self.infer_expr(
174 guard_expr,
175 &Expectation::has_type(Ty::simple(TypeCtor::Bool)),
176 );
177 }
178
179 let arm_ty = self.infer_expr_inner(arm.expr, &expected);
180 result_ty = self.coerce_merge_branch(&result_ty, &arm_ty);
181 }
182
183 result_ty
184 }
185 Expr::Path(p) => {
186 // FIXME this could be more efficient...
187 let resolver = expr::resolver_for_expr(self.body.clone(), self.db, tgt_expr);
188 self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown)
189 }
190 Expr::Continue => Ty::simple(TypeCtor::Never),
191 Expr::Break { expr } => {
192 if let Some(expr) = expr {
193 // FIXME handle break with value
194 self.infer_expr(*expr, &Expectation::none());
195 }
196 Ty::simple(TypeCtor::Never)
197 }
198 Expr::Return { expr } => {
199 if let Some(expr) = expr {
200 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone()));
201 }
202 Ty::simple(TypeCtor::Never)
203 }
204 Expr::RecordLit { path, fields, spread } => {
205 let (ty, def_id) = self.resolve_variant(path.as_ref());
206 if let Some(variant) = def_id {
207 self.write_variant_resolution(tgt_expr.into(), variant);
208 }
209
210 self.unify(&ty, &expected.ty);
211
212 let substs = ty.substs().unwrap_or_else(Substs::empty);
213 for (field_idx, field) in fields.iter().enumerate() {
214 let field_ty = def_id
215 .and_then(|it| match it.field(self.db, &field.name) {
216 Some(field) => Some(field),
217 None => {
218 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
219 expr: tgt_expr,
220 field: field_idx,
221 });
222 None
223 }
224 })
225 .map_or(Ty::Unknown, |field| field.ty(self.db))
226 .subst(&substs);
227 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
228 }
229 if let Some(expr) = spread {
230 self.infer_expr(*expr, &Expectation::has_type(ty.clone()));
231 }
232 ty
233 }
234 Expr::Field { expr, name } => {
235 let receiver_ty = self.infer_expr(*expr, &Expectation::none());
236 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty);
237 let ty = autoderef::autoderef(
238 self.db,
239 &self.resolver.clone(),
240 canonicalized.value.clone(),
241 )
242 .find_map(|derefed_ty| match canonicalized.decanonicalize_ty(derefed_ty.value) {
243 Ty::Apply(a_ty) => match a_ty.ctor {
244 TypeCtor::Tuple { .. } => name
245 .as_tuple_index()
246 .and_then(|idx| a_ty.parameters.0.get(idx).cloned()),
247 TypeCtor::Adt(Adt::Struct(s)) => s.field(self.db, name).map(|field| {
248 self.write_field_resolution(tgt_expr, field);
249 field.ty(self.db).subst(&a_ty.parameters)
250 }),
251 _ => None,
252 },
253 _ => None,
254 })
255 .unwrap_or(Ty::Unknown);
256 let ty = self.insert_type_vars(ty);
257 self.normalize_associated_types_in(ty)
258 }
259 Expr::Await { expr } => {
260 let inner_ty = self.infer_expr(*expr, &Expectation::none());
261 let ty = match self.resolve_future_future_output() {
262 Some(future_future_output_alias) => {
263 let ty = self.new_type_var();
264 let projection = ProjectionPredicate {
265 ty: ty.clone(),
266 projection_ty: ProjectionTy {
267 associated_ty: future_future_output_alias,
268 parameters: Substs::single(inner_ty),
269 },
270 };
271 self.obligations.push(Obligation::Projection(projection));
272 self.resolve_ty_as_possible(&mut vec![], ty)
273 }
274 None => Ty::Unknown,
275 };
276 ty
277 }
278 Expr::Try { expr } => {
279 let inner_ty = self.infer_expr(*expr, &Expectation::none());
280 let ty = match self.resolve_ops_try_ok() {
281 Some(ops_try_ok_alias) => {
282 let ty = self.new_type_var();
283 let projection = ProjectionPredicate {
284 ty: ty.clone(),
285 projection_ty: ProjectionTy {
286 associated_ty: ops_try_ok_alias,
287 parameters: Substs::single(inner_ty),
288 },
289 };
290 self.obligations.push(Obligation::Projection(projection));
291 self.resolve_ty_as_possible(&mut vec![], ty)
292 }
293 None => Ty::Unknown,
294 };
295 ty
296 }
297 Expr::Cast { expr, type_ref } => {
298 let _inner_ty = self.infer_expr(*expr, &Expectation::none());
299 let cast_ty = self.make_ty(type_ref);
300 // FIXME check the cast...
301 cast_ty
302 }
303 Expr::Ref { expr, mutability } => {
304 let expectation =
305 if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() {
306 if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared {
307 // FIXME: throw type error - expected mut reference but found shared ref,
308 // which cannot be coerced
309 }
310 Expectation::has_type(Ty::clone(exp_inner))
311 } else {
312 Expectation::none()
313 };
314 // FIXME reference coercions etc.
315 let inner_ty = self.infer_expr(*expr, &expectation);
316 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
317 }
318 Expr::Box { expr } => {
319 let inner_ty = self.infer_expr(*expr, &Expectation::none());
320 if let Some(box_) = self.resolve_boxed_box() {
321 Ty::apply_one(TypeCtor::Adt(box_), inner_ty)
322 } else {
323 Ty::Unknown
324 }
325 }
326 Expr::UnaryOp { expr, op } => {
327 let inner_ty = self.infer_expr(*expr, &Expectation::none());
328 match op {
329 UnaryOp::Deref => {
330 let canonicalized = self.canonicalizer().canonicalize_ty(inner_ty);
331 if let Some(derefed_ty) =
332 autoderef::deref(self.db, &self.resolver, &canonicalized.value)
333 {
334 canonicalized.decanonicalize_ty(derefed_ty.value)
335 } else {
336 Ty::Unknown
337 }
338 }
339 UnaryOp::Neg => {
340 match &inner_ty {
341 Ty::Apply(a_ty) => match a_ty.ctor {
342 TypeCtor::Int(primitive::UncertainIntTy::Unknown)
343 | TypeCtor::Int(primitive::UncertainIntTy::Known(
344 primitive::IntTy {
345 signedness: primitive::Signedness::Signed,
346 ..
347 },
348 ))
349 | TypeCtor::Float(..) => inner_ty,
350 _ => Ty::Unknown,
351 },
352 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => {
353 inner_ty
354 }
355 // FIXME: resolve ops::Neg trait
356 _ => Ty::Unknown,
357 }
358 }
359 UnaryOp::Not => {
360 match &inner_ty {
361 Ty::Apply(a_ty) => match a_ty.ctor {
362 TypeCtor::Bool | TypeCtor::Int(_) => inner_ty,
363 _ => Ty::Unknown,
364 },
365 Ty::Infer(InferTy::IntVar(..)) => inner_ty,
366 // FIXME: resolve ops::Not trait for inner_ty
367 _ => Ty::Unknown,
368 }
369 }
370 }
371 }
372 Expr::BinaryOp { lhs, rhs, op } => match op {
373 Some(op) => {
374 let lhs_expectation = match op {
375 BinaryOp::LogicOp(..) => Expectation::has_type(Ty::simple(TypeCtor::Bool)),
376 _ => Expectation::none(),
377 };
378 let lhs_ty = self.infer_expr(*lhs, &lhs_expectation);
379 // FIXME: find implementation of trait corresponding to operation
380 // symbol and resolve associated `Output` type
381 let rhs_expectation = op::binary_op_rhs_expectation(*op, lhs_ty);
382 let rhs_ty = self.infer_expr(*rhs, &Expectation::has_type(rhs_expectation));
383
384 // FIXME: similar as above, return ty is often associated trait type
385 op::binary_op_return_ty(*op, rhs_ty)
386 }
387 _ => Ty::Unknown,
388 },
389 Expr::Index { base, index } => {
390 let _base_ty = self.infer_expr(*base, &Expectation::none());
391 let _index_ty = self.infer_expr(*index, &Expectation::none());
392 // FIXME: use `std::ops::Index::Output` to figure out the real return type
393 Ty::Unknown
394 }
395 Expr::Tuple { exprs } => {
396 let mut tys = match &expected.ty {
397 ty_app!(TypeCtor::Tuple { .. }, st) => st
398 .iter()
399 .cloned()
400 .chain(repeat_with(|| self.new_type_var()))
401 .take(exprs.len())
402 .collect::<Vec<_>>(),
403 _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(),
404 };
405
406 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
407 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
408 }
409
410 Ty::apply(TypeCtor::Tuple { cardinality: tys.len() as u16 }, Substs(tys.into()))
411 }
412 Expr::Array(array) => {
413 let elem_ty = match &expected.ty {
414 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
415 st.as_single().clone()
416 }
417 _ => self.new_type_var(),
418 };
419
420 match array {
421 Array::ElementList(items) => {
422 for expr in items.iter() {
423 self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
424 }
425 }
426 Array::Repeat { initializer, repeat } => {
427 self.infer_expr_coerce(
428 *initializer,
429 &Expectation::has_type(elem_ty.clone()),
430 );
431 self.infer_expr(
432 *repeat,
433 &Expectation::has_type(Ty::simple(TypeCtor::Int(
434 primitive::UncertainIntTy::Known(primitive::IntTy::usize()),
435 ))),
436 );
437 }
438 }
439
440 Ty::apply_one(TypeCtor::Array, elem_ty)
441 }
442 Expr::Literal(lit) => match lit {
443 Literal::Bool(..) => Ty::simple(TypeCtor::Bool),
444 Literal::String(..) => {
445 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), Ty::simple(TypeCtor::Str))
446 }
447 Literal::ByteString(..) => {
448 let byte_type = Ty::simple(TypeCtor::Int(primitive::UncertainIntTy::Known(
449 primitive::IntTy::u8(),
450 )));
451 let slice_type = Ty::apply_one(TypeCtor::Slice, byte_type);
452 Ty::apply_one(TypeCtor::Ref(Mutability::Shared), slice_type)
453 }
454 Literal::Char(..) => Ty::simple(TypeCtor::Char),
455 Literal::Int(_v, ty) => Ty::simple(TypeCtor::Int(*ty)),
456 Literal::Float(_v, ty) => Ty::simple(TypeCtor::Float(*ty)),
457 },
458 };
459 // use a new type variable if we got Ty::Unknown here
460 let ty = self.insert_type_vars_shallow(ty);
461 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
462 self.write_expr_ty(tgt_expr, ty.clone());
463 ty
464 }
465
466 fn infer_block(
467 &mut self,
468 statements: &[Statement],
469 tail: Option<ExprId>,
470 expected: &Expectation,
471 ) -> Ty {
472 let mut diverges = false;
473 for stmt in statements {
474 match stmt {
475 Statement::Let { pat, type_ref, initializer } => {
476 let decl_ty =
477 type_ref.as_ref().map(|tr| self.make_ty(tr)).unwrap_or(Ty::Unknown);
478
479 // Always use the declared type when specified
480 let mut ty = decl_ty.clone();
481
482 if let Some(expr) = initializer {
483 let actual_ty =
484 self.infer_expr_coerce(*expr, &Expectation::has_type(decl_ty.clone()));
485 if decl_ty == Ty::Unknown {
486 ty = actual_ty;
487 }
488 }
489
490 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
491 self.infer_pat(*pat, &ty, BindingMode::default());
492 }
493 Statement::Expr(expr) => {
494 if let ty_app!(TypeCtor::Never) = self.infer_expr(*expr, &Expectation::none()) {
495 diverges = true;
496 }
497 }
498 }
499 }
500
501 let ty = if let Some(expr) = tail {
502 self.infer_expr_coerce(expr, expected)
503 } else {
504 self.coerce(&Ty::unit(), &expected.ty);
505 Ty::unit()
506 };
507 if diverges {
508 Ty::simple(TypeCtor::Never)
509 } else {
510 ty
511 }
512 }
513
514 fn infer_method_call(
515 &mut self,
516 tgt_expr: ExprId,
517 receiver: ExprId,
518 args: &[ExprId],
519 method_name: &Name,
520 generic_args: Option<&GenericArgs>,
521 ) -> Ty {
522 let receiver_ty = self.infer_expr(receiver, &Expectation::none());
523 let canonicalized_receiver = self.canonicalizer().canonicalize_ty(receiver_ty.clone());
524 let resolved = method_resolution::lookup_method(
525 &canonicalized_receiver.value,
526 self.db,
527 method_name,
528 &self.resolver,
529 );
530 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
531 Some((ty, func)) => {
532 let ty = canonicalized_receiver.decanonicalize_ty(ty);
533 self.write_method_resolution(tgt_expr, func);
534 (
535 ty,
536 self.db.type_for_def(func.into(), Namespace::Values),
537 Some(func.generic_params(self.db)),
538 )
539 }
540 None => (receiver_ty, Ty::Unknown, None),
541 };
542 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
543 let method_ty = method_ty.apply_substs(substs);
544 let method_ty = self.insert_type_vars(method_ty);
545 self.register_obligations_for_call(&method_ty);
546 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
547 Some(sig) => {
548 if !sig.params().is_empty() {
549 (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
550 } else {
551 (Ty::Unknown, Vec::new(), sig.ret().clone())
552 }
553 }
554 None => (Ty::Unknown, Vec::new(), Ty::Unknown),
555 };
556 // Apply autoref so the below unification works correctly
557 // FIXME: return correct autorefs from lookup_method
558 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
559 Some((_, mutability)) => Ty::apply_one(TypeCtor::Ref(mutability), derefed_receiver_ty),
560 _ => derefed_receiver_ty,
561 };
562 self.unify(&expected_receiver_ty, &actual_receiver_ty);
563
564 self.check_call_arguments(args, &param_tys);
565 let ret_ty = self.normalize_associated_types_in(ret_ty);
566 ret_ty
567 }
568
569 fn check_call_arguments(&mut self, args: &[ExprId], param_tys: &[Ty]) {
570 // Quoting https://github.com/rust-lang/rust/blob/6ef275e6c3cb1384ec78128eceeb4963ff788dca/src/librustc_typeck/check/mod.rs#L3325 --
571 // We do this in a pretty awful way: first we type-check any arguments
572 // that are not closures, then we type-check the closures. This is so
573 // that we have more information about the types of arguments when we
574 // type-check the functions. This isn't really the right way to do this.
575 for &check_closures in &[false, true] {
576 let param_iter = param_tys.iter().cloned().chain(repeat(Ty::Unknown));
577 for (&arg, param_ty) in args.iter().zip(param_iter) {
578 let is_closure = match &self.body[arg] {
579 Expr::Lambda { .. } => true,
580 _ => false,
581 };
582
583 if is_closure != check_closures {
584 continue;
585 }
586
587 let param_ty = self.normalize_associated_types_in(param_ty);
588 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
589 }
590 }
591 }
592
593 fn substs_for_method_call(
594 &mut self,
595 def_generics: Option<Arc<GenericParams>>,
596 generic_args: Option<&GenericArgs>,
597 receiver_ty: &Ty,
598 ) -> Substs {
599 let (parent_param_count, param_count) =
600 def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len()));
601 let mut substs = Vec::with_capacity(parent_param_count + param_count);
602 // Parent arguments are unknown, except for the receiver type
603 if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) {
604 for param in &parent_generics.params {
605 if param.name == name::SELF_TYPE {
606 substs.push(receiver_ty.clone());
607 } else {
608 substs.push(Ty::Unknown);
609 }
610 }
611 }
612 // handle provided type arguments
613 if let Some(generic_args) = generic_args {
614 // if args are provided, it should be all of them, but we can't rely on that
615 for arg in generic_args.args.iter().take(param_count) {
616 match arg {
617 GenericArg::Type(type_ref) => {
618 let ty = self.make_ty(type_ref);
619 substs.push(ty);
620 }
621 }
622 }
623 };
624 let supplied_params = substs.len();
625 for _ in supplied_params..parent_param_count + param_count {
626 substs.push(Ty::Unknown);
627 }
628 assert_eq!(substs.len(), parent_param_count + param_count);
629 Substs(substs.into())
630 }
631
632 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
633 if let Ty::Apply(a_ty) = callable_ty {
634 if let TypeCtor::FnDef(def) = a_ty.ctor {
635 let generic_predicates = self.db.generic_predicates(def.into());
636 for predicate in generic_predicates.iter() {
637 let predicate = predicate.clone().subst(&a_ty.parameters);
638 if let Some(obligation) = Obligation::from_predicate(predicate) {
639 self.obligations.push(obligation);
640 }
641 }
642 // add obligation for trait implementation, if this is a trait method
643 match def {
644 CallableDef::Function(f) => {
645 if let Some(trait_) = f.parent_trait(self.db) {
646 // construct a TraitDef
647 let substs = a_ty.parameters.prefix(
648 trait_.generic_params(self.db).count_params_including_parent(),
649 );
650 self.obligations.push(Obligation::Trait(TraitRef { trait_, substs }));
651 }
652 }
653 CallableDef::Struct(_) | CallableDef::EnumVariant(_) => {}
654 }
655 }
656 }
657 }
658}
diff --git a/crates/ra_hir/src/ty/infer/pat.rs b/crates/ra_hir/src/ty/infer/pat.rs
new file mode 100644
index 000000000..c125ddfbc
--- /dev/null
+++ b/crates/ra_hir/src/ty/infer/pat.rs
@@ -0,0 +1,180 @@
1//! Type inference for patterns.
2
3use std::iter::repeat;
4use std::sync::Arc;
5
6use test_utils::tested_by;
7
8use super::{BindingMode, InferenceContext};
9use crate::{
10 db::HirDatabase,
11 expr::{BindingAnnotation, Pat, PatId, RecordFieldPat},
12 ty::{Mutability, Substs, Ty, TypeCtor, TypeWalk},
13 Name, Path,
14};
15
16impl<'a, D: HirDatabase> InferenceContext<'a, D> {
17 fn infer_tuple_struct_pat(
18 &mut self,
19 path: Option<&Path>,
20 subpats: &[PatId],
21 expected: &Ty,
22 default_bm: BindingMode,
23 ) -> Ty {
24 let (ty, def) = self.resolve_variant(path);
25
26 self.unify(&ty, expected);
27
28 let substs = ty.substs().unwrap_or_else(Substs::empty);
29
30 for (i, &subpat) in subpats.iter().enumerate() {
31 let expected_ty = def
32 .and_then(|d| d.field(self.db, &Name::new_tuple_field(i)))
33 .map_or(Ty::Unknown, |field| field.ty(self.db))
34 .subst(&substs);
35 let expected_ty = self.normalize_associated_types_in(expected_ty);
36 self.infer_pat(subpat, &expected_ty, default_bm);
37 }
38
39 ty
40 }
41
42 fn infer_record_pat(
43 &mut self,
44 path: Option<&Path>,
45 subpats: &[RecordFieldPat],
46 expected: &Ty,
47 default_bm: BindingMode,
48 id: PatId,
49 ) -> Ty {
50 let (ty, def) = self.resolve_variant(path);
51 if let Some(variant) = def {
52 self.write_variant_resolution(id.into(), variant);
53 }
54
55 self.unify(&ty, expected);
56
57 let substs = ty.substs().unwrap_or_else(Substs::empty);
58
59 for subpat in subpats {
60 let matching_field = def.and_then(|it| it.field(self.db, &subpat.name));
61 let expected_ty =
62 matching_field.map_or(Ty::Unknown, |field| field.ty(self.db)).subst(&substs);
63 let expected_ty = self.normalize_associated_types_in(expected_ty);
64 self.infer_pat(subpat.pat, &expected_ty, default_bm);
65 }
66
67 ty
68 }
69
70 pub(super) fn infer_pat(
71 &mut self,
72 pat: PatId,
73 mut expected: &Ty,
74 mut default_bm: BindingMode,
75 ) -> Ty {
76 let body = Arc::clone(&self.body); // avoid borrow checker problem
77
78 let is_non_ref_pat = match &body[pat] {
79 Pat::Tuple(..)
80 | Pat::TupleStruct { .. }
81 | Pat::Record { .. }
82 | Pat::Range { .. }
83 | Pat::Slice { .. } => true,
84 // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented.
85 Pat::Path(..) | Pat::Lit(..) => true,
86 Pat::Wild | Pat::Bind { .. } | Pat::Ref { .. } | Pat::Missing => false,
87 };
88 if is_non_ref_pat {
89 while let Some((inner, mutability)) = expected.as_reference() {
90 expected = inner;
91 default_bm = match default_bm {
92 BindingMode::Move => BindingMode::Ref(mutability),
93 BindingMode::Ref(Mutability::Shared) => BindingMode::Ref(Mutability::Shared),
94 BindingMode::Ref(Mutability::Mut) => BindingMode::Ref(mutability),
95 }
96 }
97 } else if let Pat::Ref { .. } = &body[pat] {
98 tested_by!(match_ergonomics_ref);
99 // When you encounter a `&pat` pattern, reset to Move.
100 // This is so that `w` is by value: `let (_, &w) = &(1, &2);`
101 default_bm = BindingMode::Move;
102 }
103
104 // Lose mutability.
105 let default_bm = default_bm;
106 let expected = expected;
107
108 let ty = match &body[pat] {
109 Pat::Tuple(ref args) => {
110 let expectations = match expected.as_tuple() {
111 Some(parameters) => &*parameters.0,
112 _ => &[],
113 };
114 let expectations_iter = expectations.iter().chain(repeat(&Ty::Unknown));
115
116 let inner_tys = args
117 .iter()
118 .zip(expectations_iter)
119 .map(|(&pat, ty)| self.infer_pat(pat, ty, default_bm))
120 .collect();
121
122 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
123 }
124 Pat::Ref { pat, mutability } => {
125 let expectation = match expected.as_reference() {
126 Some((inner_ty, exp_mut)) => {
127 if *mutability != exp_mut {
128 // FIXME: emit type error?
129 }
130 inner_ty
131 }
132 _ => &Ty::Unknown,
133 };
134 let subty = self.infer_pat(*pat, expectation, default_bm);
135 Ty::apply_one(TypeCtor::Ref(*mutability), subty)
136 }
137 Pat::TupleStruct { path: p, args: subpats } => {
138 self.infer_tuple_struct_pat(p.as_ref(), subpats, expected, default_bm)
139 }
140 Pat::Record { path: p, args: fields } => {
141 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat)
142 }
143 Pat::Path(path) => {
144 // FIXME use correct resolver for the surrounding expression
145 let resolver = self.resolver.clone();
146 self.infer_path(&resolver, &path, pat.into()).unwrap_or(Ty::Unknown)
147 }
148 Pat::Bind { mode, name: _, subpat } => {
149 let mode = if mode == &BindingAnnotation::Unannotated {
150 default_bm
151 } else {
152 BindingMode::convert(*mode)
153 };
154 let inner_ty = if let Some(subpat) = subpat {
155 self.infer_pat(*subpat, expected, default_bm)
156 } else {
157 expected.clone()
158 };
159 let inner_ty = self.insert_type_vars_shallow(inner_ty);
160
161 let bound_ty = match mode {
162 BindingMode::Ref(mutability) => {
163 Ty::apply_one(TypeCtor::Ref(mutability), inner_ty.clone())
164 }
165 BindingMode::Move => inner_ty.clone(),
166 };
167 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty);
168 self.write_pat_ty(pat, bound_ty);
169 return inner_ty;
170 }
171 _ => Ty::Unknown,
172 };
173 // use a new type variable if we got Ty::Unknown here
174 let ty = self.insert_type_vars_shallow(ty);
175 self.unify(&ty, expected);
176 let ty = self.resolve_ty_as_possible(&mut vec![], ty);
177 self.write_pat_ty(pat, ty.clone());
178 ty
179 }
180}
diff --git a/crates/ra_hir/src/ty/infer/unify.rs b/crates/ra_hir/src/ty/infer/unify.rs
index d161aa6b3..ca33cc7f8 100644
--- a/crates/ra_hir/src/ty/infer/unify.rs
+++ b/crates/ra_hir/src/ty/infer/unify.rs
@@ -6,6 +6,7 @@ use crate::ty::{
6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty, 6 Canonical, InEnvironment, InferTy, ProjectionPredicate, ProjectionTy, Substs, TraitRef, Ty,
7 TypeWalk, 7 TypeWalk,
8}; 8};
9use crate::util::make_mut_slice;
9 10
10impl<'a, D: HirDatabase> InferenceContext<'a, D> { 11impl<'a, D: HirDatabase> InferenceContext<'a, D> {
11 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D> 12 pub(super) fn canonicalizer<'b>(&'b mut self) -> Canonicalizer<'a, 'b, D>
@@ -53,7 +54,9 @@ where
53 // recursive type 54 // recursive type
54 return tv.fallback_value(); 55 return tv.fallback_value();
55 } 56 }
56 if let Some(known_ty) = self.ctx.var_unification_table.probe_value(inner).known() { 57 if let Some(known_ty) =
58 self.ctx.var_unification_table.inlined_probe_value(inner).known()
59 {
57 self.var_stack.push(inner); 60 self.var_stack.push(inner);
58 let result = self.do_canonicalize_ty(known_ty.clone()); 61 let result = self.do_canonicalize_ty(known_ty.clone());
59 self.var_stack.pop(); 62 self.var_stack.pop();
@@ -74,10 +77,11 @@ where
74 }) 77 })
75 } 78 }
76 79
77 fn do_canonicalize_trait_ref(&mut self, trait_ref: TraitRef) -> TraitRef { 80 fn do_canonicalize_trait_ref(&mut self, mut trait_ref: TraitRef) -> TraitRef {
78 let substs = 81 for ty in make_mut_slice(&mut trait_ref.substs.0) {
79 trait_ref.substs.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect(); 82 *ty = self.do_canonicalize_ty(ty.clone());
80 TraitRef { trait_: trait_ref.trait_, substs: Substs(substs) } 83 }
84 trait_ref
81 } 85 }
82 86
83 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 87 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> {
@@ -87,10 +91,11 @@ where
87 } 91 }
88 } 92 }
89 93
90 fn do_canonicalize_projection_ty(&mut self, projection_ty: ProjectionTy) -> ProjectionTy { 94 fn do_canonicalize_projection_ty(&mut self, mut projection_ty: ProjectionTy) -> ProjectionTy {
91 let params = 95 for ty in make_mut_slice(&mut projection_ty.parameters.0) {
92 projection_ty.parameters.iter().map(|ty| self.do_canonicalize_ty(ty.clone())).collect(); 96 *ty = self.do_canonicalize_ty(ty.clone());
93 ProjectionTy { associated_ty: projection_ty.associated_ty, parameters: Substs(params) } 97 }
98 projection_ty
94 } 99 }
95 100
96 fn do_canonicalize_projection_predicate( 101 fn do_canonicalize_projection_predicate(
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs
index 4b67c82e7..366556134 100644
--- a/crates/ra_hir/src/ty/lower.rs
+++ b/crates/ra_hir/src/ty/lower.rs
@@ -22,6 +22,7 @@ use crate::{
22 resolve::{Resolver, TypeNs}, 22 resolve::{Resolver, TypeNs},
23 ty::Adt, 23 ty::Adt,
24 type_ref::{TypeBound, TypeRef}, 24 type_ref::{TypeBound, TypeRef},
25 util::make_mut_slice,
25 BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, 26 BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField,
26 Trait, TypeAlias, Union, 27 Trait, TypeAlias, Union,
27}; 28};
@@ -31,11 +32,11 @@ impl Ty {
31 match type_ref { 32 match type_ref {
32 TypeRef::Never => Ty::simple(TypeCtor::Never), 33 TypeRef::Never => Ty::simple(TypeCtor::Never),
33 TypeRef::Tuple(inner) => { 34 TypeRef::Tuple(inner) => {
34 let inner_tys = 35 let inner_tys: Arc<[Ty]> =
35 inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); 36 inner.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect();
36 Ty::apply( 37 Ty::apply(
37 TypeCtor::Tuple { cardinality: inner_tys.len() as u16 }, 38 TypeCtor::Tuple { cardinality: inner_tys.len() as u16 },
38 Substs(inner_tys.into()), 39 Substs(inner_tys),
39 ) 40 )
40 } 41 }
41 TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path), 42 TypeRef::Path(path) => Ty::from_hir_path(db, resolver, path),
@@ -57,9 +58,7 @@ impl Ty {
57 } 58 }
58 TypeRef::Placeholder => Ty::Unknown, 59 TypeRef::Placeholder => Ty::Unknown,
59 TypeRef::Fn(params) => { 60 TypeRef::Fn(params) => {
60 let inner_tys = 61 let sig = Substs(params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect());
61 params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
62 let sig = Substs(inner_tys.into());
63 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig) 62 Ty::apply(TypeCtor::FnPtr { num_args: sig.len() as u16 - 1 }, sig)
64 } 63 }
65 TypeRef::DynTrait(bounds) => { 64 TypeRef::DynTrait(bounds) => {
@@ -69,8 +68,8 @@ impl Ty {
69 .flat_map(|b| { 68 .flat_map(|b| {
70 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) 69 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
71 }) 70 })
72 .collect::<Vec<_>>(); 71 .collect();
73 Ty::Dyn(predicates.into()) 72 Ty::Dyn(predicates)
74 } 73 }
75 TypeRef::ImplTrait(bounds) => { 74 TypeRef::ImplTrait(bounds) => {
76 let self_ty = Ty::Bound(0); 75 let self_ty = Ty::Bound(0);
@@ -79,8 +78,8 @@ impl Ty {
79 .flat_map(|b| { 78 .flat_map(|b| {
80 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone()) 79 GenericPredicate::from_type_bound(db, resolver, b, self_ty.clone())
81 }) 80 })
82 .collect::<Vec<_>>(); 81 .collect();
83 Ty::Opaque(predicates.into()) 82 Ty::Opaque(predicates)
84 } 83 }
85 TypeRef::Error => Ty::Unknown, 84 TypeRef::Error => Ty::Unknown,
86 } 85 }
@@ -175,6 +174,7 @@ impl Ty {
175 Ty::Param { idx, name } 174 Ty::Param { idx, name }
176 } 175 }
177 TypeNs::SelfType(impl_block) => impl_block.target_ty(db), 176 TypeNs::SelfType(impl_block) => impl_block.target_ty(db),
177 TypeNs::AdtSelfType(adt) => adt.ty(db),
178 178
179 TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), 179 TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
180 TypeNs::BuiltinType(it) => { 180 TypeNs::BuiltinType(it) => {
@@ -391,10 +391,7 @@ impl TraitRef {
391 ) -> Self { 391 ) -> Self {
392 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); 392 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
393 if let Some(self_ty) = explicit_self_ty { 393 if let Some(self_ty) = explicit_self_ty {
394 // FIXME this could be nicer 394 make_mut_slice(&mut substs.0)[0] = self_ty;
395 let mut substs_vec = substs.0.to_vec();
396 substs_vec[0] = self_ty;
397 substs.0 = substs_vec.into();
398 } 395 }
399 TraitRef { trait_: resolved, substs } 396 TraitRef { trait_: resolved, substs }
400 } 397 }
@@ -557,13 +554,12 @@ pub(crate) fn generic_predicates_for_param_query(
557 param_idx: u32, 554 param_idx: u32,
558) -> Arc<[GenericPredicate]> { 555) -> Arc<[GenericPredicate]> {
559 let resolver = def.resolver(db); 556 let resolver = def.resolver(db);
560 let predicates = resolver 557 resolver
561 .where_predicates_in_scope() 558 .where_predicates_in_scope()
562 // we have to filter out all other predicates *first*, before attempting to lower them 559 // we have to filter out all other predicates *first*, before attempting to lower them
563 .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx)) 560 .filter(|pred| Ty::from_hir_only_param(db, &resolver, &pred.type_ref) == Some(param_idx))
564 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 561 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
565 .collect::<Vec<_>>(); 562 .collect()
566 predicates.into()
567} 563}
568 564
569pub(crate) fn trait_env( 565pub(crate) fn trait_env(
@@ -584,11 +580,10 @@ pub(crate) fn generic_predicates_query(
584 def: GenericDef, 580 def: GenericDef,
585) -> Arc<[GenericPredicate]> { 581) -> Arc<[GenericPredicate]> {
586 let resolver = def.resolver(db); 582 let resolver = def.resolver(db);
587 let predicates = resolver 583 resolver
588 .where_predicates_in_scope() 584 .where_predicates_in_scope()
589 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred)) 585 .flat_map(|pred| GenericPredicate::from_where_predicate(db, &resolver, pred))
590 .collect::<Vec<_>>(); 586 .collect()
591 predicates.into()
592} 587}
593 588
594/// Resolve the default type params from generics 589/// Resolve the default type params from generics
@@ -602,9 +597,9 @@ pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDef) ->
602 .map(|p| { 597 .map(|p| {
603 p.default.as_ref().map_or(Ty::Unknown, |path| Ty::from_hir_path(db, &resolver, path)) 598 p.default.as_ref().map_or(Ty::Unknown, |path| Ty::from_hir_path(db, &resolver, path))
604 }) 599 })
605 .collect::<Vec<_>>(); 600 .collect();
606 601
607 Substs(defaults.into()) 602 Substs(defaults)
608} 603}
609 604
610fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { 605fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 25dad81eb..c12326643 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -3,7 +3,6 @@ use std::sync::Arc;
3 3
4use insta::assert_snapshot; 4use insta::assert_snapshot;
5 5
6use ra_cfg::CfgOptions;
7use ra_db::{salsa::Database, FilePosition, SourceDatabase}; 6use ra_db::{salsa::Database, FilePosition, SourceDatabase};
8use ra_syntax::{ 7use ra_syntax::{
9 algo, 8 algo,
@@ -62,7 +61,7 @@ impl S {
62"#, 61"#,
63 ); 62 );
64 db.set_crate_graph_from_fixture(crate_graph! { 63 db.set_crate_graph_from_fixture(crate_graph! {
65 "main": ("/main.rs", ["foo"], CfgOptions::default().atom("test".into())), 64 "main": ("/main.rs", ["foo"], cfg = { "test" }),
66 "foo": ("/foo.rs", []), 65 "foo": ("/foo.rs", []),
67 }); 66 });
68 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos)); 67 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
@@ -135,6 +134,25 @@ mod boxed {
135} 134}
136 135
137#[test] 136#[test]
137fn infer_adt_self() {
138 let (db, pos) = MockDatabase::with_position(
139 r#"
140//- /main.rs
141enum Nat { Succ(Self), Demo(Nat), Zero }
142
143fn test() {
144 let foo: Nat = Nat::Zero;
145 if let Nat::Succ(x) = foo {
146 x<|>
147 }
148}
149
150"#,
151 );
152 assert_eq!("Nat", type_at_pos(&db, pos));
153}
154
155#[test]
138fn infer_try() { 156fn infer_try() {
139 let (mut db, pos) = MockDatabase::with_position( 157 let (mut db, pos) = MockDatabase::with_position(
140 r#" 158 r#"
diff --git a/crates/ra_hir/src/ty/traits.rs b/crates/ra_hir/src/ty/traits.rs
index b0f67ae50..0cb5c3798 100644
--- a/crates/ra_hir/src/ty/traits.rs
+++ b/crates/ra_hir/src/ty/traits.rs
@@ -89,7 +89,7 @@ pub(crate) fn impls_for_trait_query(
89 } 89 }
90 let crate_impl_blocks = db.impls_in_crate(krate); 90 let crate_impl_blocks = db.impls_in_crate(krate);
91 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(trait_)); 91 impls.extend(crate_impl_blocks.lookup_impl_blocks_for_trait(trait_));
92 impls.into_iter().collect::<Vec<_>>().into() 92 impls.into_iter().collect()
93} 93}
94 94
95/// A set of clauses that we assume to be true. E.g. if we are inside this function: 95/// A set of clauses that we assume to be true. E.g. if we are inside this function:
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs
index 2642a54bf..00aaf65d9 100644
--- a/crates/ra_hir/src/ty/traits/chalk.rs
+++ b/crates/ra_hir/src/ty/traits/chalk.rs
@@ -126,8 +126,7 @@ impl ToChalk for Substs {
126 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 126 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty),
127 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 127 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(),
128 }) 128 })
129 .collect::<Vec<_>>() 129 .collect();
130 .into();
131 Substs(tys) 130 Substs(tys)
132 } 131 }
133} 132}
@@ -491,15 +490,16 @@ pub(crate) fn trait_datum_query(
491 }, 490 },
492 associated_ty_ids: Vec::new(), 491 associated_ty_ids: Vec::new(),
493 where_clauses: Vec::new(), 492 where_clauses: Vec::new(),
494 flags: chalk_rust_ir::TraitFlags {
495 non_enumerable: true,
496 auto: false,
497 marker: false,
498 upstream: true,
499 fundamental: false,
500 },
501 }; 493 };
502 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) }); 494
495 let flags = chalk_rust_ir::TraitFlags {
496 auto: false,
497 marker: false,
498 upstream: true,
499 fundamental: false,
500 non_enumerable: true,
501 };
502 return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1), flags });
503 } 503 }
504 let trait_: Trait = from_chalk(db, trait_id); 504 let trait_: Trait = from_chalk(db, trait_id);
505 debug!("trait {:?} = {:?}", trait_id, trait_.name(db)); 505 debug!("trait {:?} = {:?}", trait_id, trait_.name(db));
@@ -525,8 +525,9 @@ pub(crate) fn trait_datum_query(
525 .map(|type_alias| type_alias.to_chalk(db)) 525 .map(|type_alias| type_alias.to_chalk(db))
526 .collect(); 526 .collect();
527 let trait_datum_bound = 527 let trait_datum_bound =
528 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; 528 chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, associated_ty_ids };
529 let trait_datum = TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()) }; 529 let trait_datum =
530 TraitDatum { binders: make_binders(trait_datum_bound, bound_vars.len()), flags };
530 Arc::new(trait_datum) 531 Arc::new(trait_datum)
531} 532}
532 533
@@ -632,18 +633,20 @@ fn impl_block_datum(
632 }) 633 })
633 .collect(); 634 .collect();
634 635
635 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 636 let polarity = if negative {
636 trait_ref: if negative { 637 chalk_rust_ir::Polarity::Negative
637 chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref) 638 } else {
638 } else { 639 chalk_rust_ir::Polarity::Positive
639 chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref)
640 },
641 where_clauses,
642 associated_ty_values,
643 impl_type,
644 }; 640 };
641
642 let impl_datum_bound =
643 chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses, associated_ty_values };
645 debug!("impl_datum: {:?}", impl_datum_bound); 644 debug!("impl_datum: {:?}", impl_datum_bound);
646 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, bound_vars.len()) }; 645 let impl_datum = ImplDatum {
646 binders: make_binders(impl_datum_bound, bound_vars.len()),
647 impl_type,
648 polarity,
649 };
647 Arc::new(impl_datum) 650 Arc::new(impl_datum)
648} 651}
649 652
@@ -653,12 +656,15 @@ fn invalid_impl_datum() -> Arc<ImplDatum> {
653 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], 656 parameters: vec![chalk_ir::Ty::BoundVar(0).cast()],
654 }; 657 };
655 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 658 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
656 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref), 659 trait_ref,
657 where_clauses: Vec::new(), 660 where_clauses: Vec::new(),
658 associated_ty_values: Vec::new(), 661 associated_ty_values: Vec::new(),
662 };
663 let impl_datum = ImplDatum {
664 binders: make_binders(impl_datum_bound, 1),
659 impl_type: chalk_rust_ir::ImplType::External, 665 impl_type: chalk_rust_ir::ImplType::External,
666 polarity: chalk_rust_ir::Polarity::Positive,
660 }; 667 };
661 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, 1) };
662 Arc::new(impl_datum) 668 Arc::new(impl_datum)
663} 669}
664 670
@@ -713,12 +719,15 @@ fn closure_fn_trait_impl_datum(
713 let impl_type = chalk_rust_ir::ImplType::External; 719 let impl_type = chalk_rust_ir::ImplType::External;
714 720
715 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { 721 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
716 trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(db)), 722 trait_ref: trait_ref.to_chalk(db),
717 where_clauses: Vec::new(), 723 where_clauses: Vec::new(),
718 associated_ty_values: vec![output_ty_value], 724 associated_ty_values: vec![output_ty_value],
725 };
726 let impl_datum = ImplDatum {
727 binders: make_binders(impl_datum_bound, num_args as usize + 1),
719 impl_type, 728 impl_type,
729 polarity: chalk_rust_ir::Polarity::Positive,
720 }; 730 };
721 let impl_datum = ImplDatum { binders: make_binders(impl_datum_bound, num_args as usize + 1) };
722 Some(Arc::new(impl_datum)) 731 Some(Arc::new(impl_datum))
723} 732}
724 733
diff --git a/crates/ra_hir/src/type_alias.rs b/crates/ra_hir/src/type_alias.rs
index 3b38c4740..674a46102 100644
--- a/crates/ra_hir/src/type_alias.rs
+++ b/crates/ra_hir/src/type_alias.rs
@@ -17,12 +17,14 @@ pub struct TypeAliasData {
17 pub(crate) type_ref: Option<TypeRef>, 17 pub(crate) type_ref: Option<TypeRef>,
18} 18}
19 19
20pub(crate) fn type_alias_data_query( 20impl TypeAliasData {
21 db: &(impl DefDatabase + AstDatabase), 21 pub(crate) fn type_alias_data_query(
22 typ: TypeAlias, 22 db: &(impl DefDatabase + AstDatabase),
23) -> Arc<TypeAliasData> { 23 typ: TypeAlias,
24 let node = typ.source(db).ast; 24 ) -> Arc<TypeAliasData> {
25 let name = node.name().map_or_else(Name::missing, |n| n.as_name()); 25 let node = typ.source(db).ast;
26 let type_ref = node.type_ref().map(TypeRef::from_ast); 26 let name = node.name().map_or_else(Name::missing, |n| n.as_name());
27 Arc::new(TypeAliasData { name, type_ref }) 27 let type_ref = node.type_ref().map(TypeRef::from_ast);
28 Arc::new(TypeAliasData { name, type_ref })
29 }
28} 30}
diff --git a/crates/ra_hir/src/util.rs b/crates/ra_hir/src/util.rs
new file mode 100644
index 000000000..0095ee45d
--- /dev/null
+++ b/crates/ra_hir/src/util.rs
@@ -0,0 +1,12 @@
1//! Internal utility functions.
2
3use std::sync::Arc;
4
5/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
6/// The underlying values are cloned if there are other strong references.
7pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
8 if Arc::get_mut(a).is_none() {
9 *a = a.iter().cloned().collect();
10 }
11 Arc::get_mut(a).unwrap()
12}
diff --git a/crates/ra_ide_api/Cargo.toml b/crates/ra_ide_api/Cargo.toml
index f919a2d61..f9bf0c686 100644
--- a/crates/ra_ide_api/Cargo.toml
+++ b/crates/ra_ide_api/Cargo.toml
@@ -12,13 +12,14 @@ format-buf = "1.0.0"
12itertools = "0.8.0" 12itertools = "0.8.0"
13join_to_string = "0.1.3" 13join_to_string = "0.1.3"
14log = "0.4.5" 14log = "0.4.5"
15relative-path = "0.4.0" 15relative-path = "1.0.0"
16rayon = "1.0.2" 16rayon = "1.0.2"
17fst = { version = "0.3.1", default-features = false } 17fst = { version = "0.3.1", default-features = false }
18rustc-hash = "1.0" 18rustc-hash = "1.0"
19unicase = "2.2.0" 19unicase = "2.2.0"
20superslice = "1.0.0" 20superslice = "1.0.0"
21rand = { version = "0.7.0", features = ["small_rng"] } 21rand = { version = "0.7.0", features = ["small_rng"] }
22once_cell = "1.2.0"
22 23
23ra_syntax = { path = "../ra_syntax" } 24ra_syntax = { path = "../ra_syntax" }
24ra_text_edit = { path = "../ra_text_edit" } 25ra_text_edit = { path = "../ra_text_edit" }
diff --git a/crates/ra_ide_api/src/change.rs b/crates/ra_ide_api/src/change.rs
index 09913787b..050249c0e 100644
--- a/crates/ra_ide_api/src/change.rs
+++ b/crates/ra_ide_api/src/change.rs
@@ -4,7 +4,7 @@ use std::{fmt, sync::Arc, time};
4 4
5use ra_db::{ 5use ra_db::{
6 salsa::{Database, Durability, SweepStrategy}, 6 salsa::{Database, Durability, SweepStrategy},
7 CrateGraph, CrateId, FileId, SourceDatabase, SourceRoot, SourceRootId, 7 CrateGraph, CrateId, FileId, SourceDatabase, SourceDatabaseExt, SourceRoot, SourceRootId,
8}; 8};
9use ra_prof::{memory_usage, profile, Bytes}; 9use ra_prof::{memory_usage, profile, Bytes};
10use ra_syntax::SourceFile; 10use ra_syntax::SourceFile;
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index 28c8324d0..b4df6ee2a 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -119,27 +119,28 @@ mod tests {
119 ", 119 ",
120 ), 120 ),
121 @r###" 121 @r###"
122 â‹®[ 122 [
123 â‹® CompletionItem { 123 CompletionItem {
124 â‹® label: "foo", 124 label: "foo()",
125 â‹® source_range: [187; 187), 125 source_range: [187; 187),
126 â‹® delete: [187; 187), 126 delete: [187; 187),
127 â‹® insert: "foo()$0", 127 insert: "foo()$0",
128 â‹® kind: Method, 128 kind: Method,
129 â‹® detail: "fn foo(self)", 129 lookup: "foo",
130 â‹® }, 130 detail: "fn foo(self)",
131 â‹® CompletionItem { 131 },
132 â‹® label: "the_field", 132 CompletionItem {
133 â‹® source_range: [187; 187), 133 label: "the_field",
134 â‹® delete: [187; 187), 134 source_range: [187; 187),
135 â‹® insert: "the_field", 135 delete: [187; 187),
136 â‹® kind: Field, 136 insert: "the_field",
137 â‹® detail: "(u32,)", 137 kind: Field,
138 â‹® documentation: Documentation( 138 detail: "(u32,)",
139 â‹® "This is the_field", 139 documentation: Documentation(
140 â‹® ), 140 "This is the_field",
141 â‹® }, 141 ),
142 â‹®] 142 },
143 ]
143 "### 144 "###
144 ); 145 );
145 } 146 }
@@ -158,24 +159,25 @@ mod tests {
158 ", 159 ",
159 ), 160 ),
160 @r###" 161 @r###"
161 â‹®[ 162 [
162 â‹® CompletionItem { 163 CompletionItem {
163 â‹® label: "foo", 164 label: "foo()",
164 â‹® source_range: [126; 126), 165 source_range: [126; 126),
165 â‹® delete: [126; 126), 166 delete: [126; 126),
166 â‹® insert: "foo()$0", 167 insert: "foo()$0",
167 â‹® kind: Method, 168 kind: Method,
168 â‹® detail: "fn foo(&self)", 169 lookup: "foo",
169 â‹® }, 170 detail: "fn foo(&self)",
170 â‹® CompletionItem { 171 },
171 â‹® label: "the_field", 172 CompletionItem {
172 â‹® source_range: [126; 126), 173 label: "the_field",
173 â‹® delete: [126; 126), 174 source_range: [126; 126),
174 â‹® insert: "the_field", 175 delete: [126; 126),
175 â‹® kind: Field, 176 insert: "the_field",
176 â‹® detail: "(u32, i32)", 177 kind: Field,
177 â‹® }, 178 detail: "(u32, i32)",
178 â‹®] 179 },
180 ]
179 "### 181 "###
180 ); 182 );
181 } 183 }
@@ -210,16 +212,17 @@ mod tests {
210 ", 212 ",
211 ), 213 ),
212 @r###" 214 @r###"
213 â‹®[ 215 [
214 â‹® CompletionItem { 216 CompletionItem {
215 â‹® label: "the_method", 217 label: "the_method()",
216 â‹® source_range: [144; 144), 218 source_range: [144; 144),
217 â‹® delete: [144; 144), 219 delete: [144; 144),
218 â‹® insert: "the_method()$0", 220 insert: "the_method()$0",
219 â‹® kind: Method, 221 kind: Method,
220 â‹® detail: "fn the_method(&self)", 222 lookup: "the_method",
221 â‹® }, 223 detail: "fn the_method(&self)",
222 â‹®] 224 },
225 ]
223 "### 226 "###
224 ); 227 );
225 } 228 }
@@ -238,16 +241,17 @@ mod tests {
238 ", 241 ",
239 ), 242 ),
240 @r###" 243 @r###"
241 â‹®[ 244 [
242 â‹® CompletionItem { 245 CompletionItem {
243 â‹® label: "the_method", 246 label: "the_method()",
244 â‹® source_range: [151; 151), 247 source_range: [151; 151),
245 â‹® delete: [151; 151), 248 delete: [151; 151),
246 â‹® insert: "the_method()$0", 249 insert: "the_method()$0",
247 â‹® kind: Method, 250 kind: Method,
248 â‹® detail: "fn the_method(&self)", 251 lookup: "the_method",
249 â‹® }, 252 detail: "fn the_method(&self)",
250 â‹®] 253 },
254 ]
251 "### 255 "###
252 ); 256 );
253 } 257 }
@@ -266,16 +270,17 @@ mod tests {
266 ", 270 ",
267 ), 271 ),
268 @r###" 272 @r###"
269 â‹®[ 273 [
270 â‹® CompletionItem { 274 CompletionItem {
271 â‹® label: "the_method", 275 label: "the_method()",
272 â‹® source_range: [155; 155), 276 source_range: [155; 155),
273 â‹® delete: [155; 155), 277 delete: [155; 155),
274 â‹® insert: "the_method()$0", 278 insert: "the_method()$0",
275 â‹® kind: Method, 279 kind: Method,
276 â‹® detail: "fn the_method(&self)", 280 lookup: "the_method",
277 â‹® }, 281 detail: "fn the_method(&self)",
278 â‹®] 282 },
283 ]
279 "### 284 "###
280 ); 285 );
281 } 286 }
@@ -317,16 +322,17 @@ mod tests {
317 ", 322 ",
318 ), 323 ),
319 @r###" 324 @r###"
320 â‹®[ 325 [
321 â‹® CompletionItem { 326 CompletionItem {
322 â‹® label: "the_method", 327 label: "the_method()",
323 â‹® source_range: [249; 249), 328 source_range: [249; 249),
324 â‹® delete: [249; 249), 329 delete: [249; 249),
325 â‹® insert: "the_method()$0", 330 insert: "the_method()$0",
326 â‹® kind: Method, 331 kind: Method,
327 â‹® detail: "fn the_method(&self)", 332 lookup: "the_method",
328 â‹® }, 333 detail: "fn the_method(&self)",
329 â‹®] 334 },
335 ]
330 "### 336 "###
331 ); 337 );
332 } 338 }
@@ -386,16 +392,17 @@ mod tests {
386 ", 392 ",
387 ), 393 ),
388 @r###" 394 @r###"
389 â‹®[ 395 [
390 â‹® CompletionItem { 396 CompletionItem {
391 â‹® label: "blah", 397 label: "blah()",
392 â‹® source_range: [299; 300), 398 source_range: [299; 300),
393 â‹® delete: [299; 300), 399 delete: [299; 300),
394 â‹® insert: "blah()$0", 400 insert: "blah()$0",
395 â‹® kind: Method, 401 kind: Method,
396 â‹® detail: "pub fn blah(&self)", 402 lookup: "blah",
397 â‹® }, 403 detail: "pub fn blah(&self)",
398 â‹®] 404 },
405 ]
399 "### 406 "###
400 ); 407 );
401 } 408 }
diff --git a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
index d808b2357..09f743c66 100644
--- a/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
+++ b/crates/ra_ide_api/src/completion/complete_macro_in_item_position.rs
@@ -56,6 +56,16 @@ mod tests {
56 do_reference_completion( 56 do_reference_completion(
57 " 57 "
58 //- /main.rs 58 //- /main.rs
59 /// Creates a [`Vec`] containing the arguments.
60 ///
61 /// - Create a [`Vec`] containing a given list of elements:
62 ///
63 /// ```
64 /// let v = vec![1, 2, 3];
65 /// assert_eq!(v[0], 1);
66 /// assert_eq!(v[1], 2);
67 /// assert_eq!(v[2], 3);
68 /// ```
59 macro_rules! vec { 69 macro_rules! vec {
60 () => {} 70 () => {}
61 } 71 }
@@ -68,13 +78,61 @@ mod tests {
68 @r##"[ 78 @r##"[
69 CompletionItem { 79 CompletionItem {
70 label: "vec!", 80 label: "vec!",
71 source_range: [46; 46), 81 source_range: [280; 280),
72 delete: [46; 46), 82 delete: [280; 280),
73 insert: "vec![$0]", 83 insert: "vec![$0]",
74 kind: Macro, 84 kind: Macro,
75 detail: "macro_rules! vec", 85 detail: "macro_rules! vec",
86 documentation: Documentation(
87 "Creates a [`Vec`] containing the arguments.\n\n- Create a [`Vec`] containing a given list of elements:\n\n```\nlet v = vec![1, 2, 3];\nassert_eq!(v[0], 1);\nassert_eq!(v[1], 2);\nassert_eq!(v[2], 3);\n```",
88 ),
76 }, 89 },
77]"## 90]"##
78 ); 91 );
79 } 92 }
93
94 #[test]
95 fn completes_macros_braces_guessing() {
96 assert_debug_snapshot!(
97 do_reference_completion(
98 "
99 //- /main.rs
100 /// Foo
101 ///
102 /// Not call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.
103 /// Call as `let _=foo! { hello world };`
104 macro_rules! foo {
105 () => {}
106 }
107
108 fn main() {
109 <|>
110 }
111 "
112 ),
113 @r###"[
114 CompletionItem {
115 label: "foo!",
116 source_range: [163; 163),
117 delete: [163; 163),
118 insert: "foo! {$0}",
119 kind: Macro,
120 detail: "macro_rules! foo",
121 documentation: Documentation(
122 "Foo\n\nNot call `fooo!()` `fooo!()`, or `_foo![]` `_foo![]`.\nCall as `let _=foo! { hello world };`",
123 ),
124 },
125 CompletionItem {
126 label: "main()",
127 source_range: [163; 163),
128 delete: [163; 163),
129 insert: "main()$0",
130 kind: Function,
131 lookup: "main",
132 detail: "fn main()",
133 },
134]
135 "###
136 );
137 }
80} 138}
diff --git a/crates/ra_ide_api/src/completion/complete_path.rs b/crates/ra_ide_api/src/completion/complete_path.rs
index e01197fe4..23dece73c 100644
--- a/crates/ra_ide_api/src/completion/complete_path.rs
+++ b/crates/ra_ide_api/src/completion/complete_path.rs
@@ -375,19 +375,22 @@ mod tests {
375 fn foo() { let _ = S::<|> } 375 fn foo() { let _ = S::<|> }
376 " 376 "
377 ), 377 ),
378 @r###"[ 378 @r###"
379 CompletionItem { 379 [
380 label: "m", 380 CompletionItem {
381 source_range: [100; 100), 381 label: "m()",
382 delete: [100; 100), 382 source_range: [100; 100),
383 insert: "m()$0", 383 delete: [100; 100),
384 kind: Function, 384 insert: "m()$0",
385 detail: "fn m()", 385 kind: Function,
386 documentation: Documentation( 386 lookup: "m",
387 "An associated method", 387 detail: "fn m()",
388 ), 388 documentation: Documentation(
389 }, 389 "An associated method",
390]"### 390 ),
391 },
392 ]
393 "###
391 ); 394 );
392 } 395 }
393 396
@@ -474,19 +477,22 @@ mod tests {
474 fn foo() { let _ = S::<|> } 477 fn foo() { let _ = S::<|> }
475 " 478 "
476 ), 479 ),
477 @r###"[ 480 @r###"
478 CompletionItem { 481 [
479 label: "m", 482 CompletionItem {
480 source_range: [100; 100), 483 label: "m()",
481 delete: [100; 100), 484 source_range: [100; 100),
482 insert: "m()$0", 485 delete: [100; 100),
483 kind: Function, 486 insert: "m()$0",
484 detail: "fn m()", 487 kind: Function,
485 documentation: Documentation( 488 lookup: "m",
486 "An associated method", 489 detail: "fn m()",
487 ), 490 documentation: Documentation(
488 }, 491 "An associated method",
489]"### 492 ),
493 },
494 ]
495 "###
490 ); 496 );
491 } 497 }
492 498
@@ -507,19 +513,22 @@ mod tests {
507 fn foo() { let _ = U::<|> } 513 fn foo() { let _ = U::<|> }
508 " 514 "
509 ), 515 ),
510 @r###"[ 516 @r###"
511 CompletionItem { 517 [
512 label: "m", 518 CompletionItem {
513 source_range: [101; 101), 519 label: "m()",
514 delete: [101; 101), 520 source_range: [101; 101),
515 insert: "m()$0", 521 delete: [101; 101),
516 kind: Function, 522 insert: "m()$0",
517 detail: "fn m()", 523 kind: Function,
518 documentation: Documentation( 524 lookup: "m",
519 "An associated method", 525 detail: "fn m()",
520 ), 526 documentation: Documentation(
521 }, 527 "An associated method",
522]"### 528 ),
529 },
530 ]
531 "###
523 ); 532 );
524 } 533 }
525 534
@@ -564,24 +573,28 @@ mod tests {
564 } 573 }
565 " 574 "
566 ), 575 ),
567 @r###"[ 576 @r###"
568 CompletionItem { 577 [
569 label: "bar", 578 CompletionItem {
570 source_range: [185; 185), 579 label: "bar()",
571 delete: [185; 185), 580 source_range: [185; 185),
572 insert: "bar()$0", 581 delete: [185; 185),
573 kind: Function, 582 insert: "bar()$0",
574 detail: "fn bar()", 583 kind: Function,
575 }, 584 lookup: "bar",
576 CompletionItem { 585 detail: "fn bar()",
577 label: "foo", 586 },
578 source_range: [185; 185), 587 CompletionItem {
579 delete: [185; 185), 588 label: "foo()",
580 insert: "foo()$0", 589 source_range: [185; 185),
581 kind: Function, 590 delete: [185; 185),
582 detail: "fn foo()", 591 insert: "foo()$0",
583 }, 592 kind: Function,
584]"### 593 lookup: "foo",
594 detail: "fn foo()",
595 },
596 ]
597 "###
585 ); 598 );
586 } 599 }
587 600
@@ -600,24 +613,27 @@ mod tests {
600 } 613 }
601 " 614 "
602 ), 615 ),
603 @r###"[ 616 @r###"
604 CompletionItem { 617 [
605 label: "foo!", 618 CompletionItem {
606 source_range: [179; 179), 619 label: "foo!",
607 delete: [179; 179), 620 source_range: [179; 179),
608 insert: "foo!($0)", 621 delete: [179; 179),
609 kind: Macro, 622 insert: "foo!($0)",
610 detail: "#[macro_export]\nmacro_rules! foo", 623 kind: Macro,
611 }, 624 detail: "#[macro_export]\nmacro_rules! foo",
612 CompletionItem { 625 },
613 label: "main", 626 CompletionItem {
614 source_range: [179; 179), 627 label: "main()",
615 delete: [179; 179), 628 source_range: [179; 179),
616 insert: "main()$0", 629 delete: [179; 179),
617 kind: Function, 630 insert: "main()$0",
618 detail: "fn main()", 631 kind: Function,
619 }, 632 lookup: "main",
620]"### 633 detail: "fn main()",
634 },
635 ]
636 "###
621 ); 637 );
622 } 638 }
623} 639}
diff --git a/crates/ra_ide_api/src/completion/complete_postfix.rs b/crates/ra_ide_api/src/completion/complete_postfix.rs
index 445a02676..555cecb73 100644
--- a/crates/ra_ide_api/src/completion/complete_postfix.rs
+++ b/crates/ra_ide_api/src/completion/complete_postfix.rs
@@ -8,7 +8,7 @@ use crate::{
8 CompletionItem, 8 CompletionItem,
9}; 9};
10use hir::{Ty, TypeCtor}; 10use hir::{Ty, TypeCtor};
11use ra_syntax::{ast::AstNode, TextRange}; 11use ra_syntax::{ast::AstNode, TextRange, TextUnit};
12use ra_text_edit::TextEditBuilder; 12use ra_text_edit::TextEditBuilder;
13 13
14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder { 14fn postfix_snippet(ctx: &CompletionContext, label: &str, detail: &str, snippet: &str) -> Builder {
@@ -42,7 +42,13 @@ fn is_bool_or_unknown(ty: Option<Ty>) -> bool {
42 42
43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 43pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
44 if let Some(dot_receiver) = &ctx.dot_receiver { 44 if let Some(dot_receiver) = &ctx.dot_receiver {
45 let receiver_text = dot_receiver.syntax().text().to_string(); 45 let receiver_text = if ctx.dot_receiver_is_ambiguous_float_literal {
46 let text = dot_receiver.syntax().text();
47 let without_dot = ..text.len() - TextUnit::of_char('.');
48 text.slice(without_dot).to_string()
49 } else {
50 dot_receiver.syntax().text().to_string()
51 };
46 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver); 52 let receiver_ty = ctx.analyzer.type_of(ctx.db, &dot_receiver);
47 if is_bool_or_unknown(receiver_ty) { 53 if is_bool_or_unknown(receiver_ty) {
48 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text)) 54 postfix_snippet(ctx, "if", "if expr {}", &format!("if {} {{$0}}", receiver_text))
@@ -209,4 +215,61 @@ mod tests {
209]"### 215]"###
210 ); 216 );
211 } 217 }
218
219 #[test]
220 fn postfix_completion_works_for_ambiguous_float_literal() {
221 assert_debug_snapshot!(
222 do_postfix_completion(
223 r#"
224 fn main() {
225 42.<|>
226 }
227 "#,
228 ),
229 @r###"[
230 CompletionItem {
231 label: "box",
232 source_range: [52; 52),
233 delete: [49; 52),
234 insert: "Box::new(42)",
235 detail: "Box::new(expr)",
236 },
237 CompletionItem {
238 label: "dbg",
239 source_range: [52; 52),
240 delete: [49; 52),
241 insert: "dbg!(42)",
242 detail: "dbg!(expr)",
243 },
244 CompletionItem {
245 label: "match",
246 source_range: [52; 52),
247 delete: [49; 52),
248 insert: "match 42 {\n ${1:_} => {$0\\},\n}",
249 detail: "match expr {}",
250 },
251 CompletionItem {
252 label: "not",
253 source_range: [52; 52),
254 delete: [49; 52),
255 insert: "!42",
256 detail: "!expr",
257 },
258 CompletionItem {
259 label: "ref",
260 source_range: [52; 52),
261 delete: [49; 52),
262 insert: "&42",
263 detail: "&expr",
264 },
265 CompletionItem {
266 label: "refm",
267 source_range: [52; 52),
268 delete: [49; 52),
269 insert: "&mut 42",
270 detail: "&mut expr",
271 },
272]"###
273 );
274 }
212} 275}
diff --git a/crates/ra_ide_api/src/completion/complete_scope.rs b/crates/ra_ide_api/src/completion/complete_scope.rs
index 515a6285c..4e56de3f5 100644
--- a/crates/ra_ide_api/src/completion/complete_scope.rs
+++ b/crates/ra_ide_api/src/completion/complete_scope.rs
@@ -145,32 +145,35 @@ mod tests {
145 } 145 }
146 " 146 "
147 ), 147 ),
148 @r###"[ 148 @r###"
149 CompletionItem { 149 [
150 label: "quux", 150 CompletionItem {
151 source_range: [91; 91), 151 label: "quux(…)",
152 delete: [91; 91), 152 source_range: [91; 91),
153 insert: "quux($0)", 153 delete: [91; 91),
154 kind: Function, 154 insert: "quux($0)",
155 detail: "fn quux(x: i32)", 155 kind: Function,
156 }, 156 lookup: "quux",
157 CompletionItem { 157 detail: "fn quux(x: i32)",
158 label: "x", 158 },
159 source_range: [91; 91), 159 CompletionItem {
160 delete: [91; 91), 160 label: "x",
161 insert: "x", 161 source_range: [91; 91),
162 kind: Binding, 162 delete: [91; 91),
163 detail: "i32", 163 insert: "x",
164 }, 164 kind: Binding,
165 CompletionItem { 165 detail: "i32",
166 label: "y", 166 },
167 source_range: [91; 91), 167 CompletionItem {
168 delete: [91; 91), 168 label: "y",
169 insert: "y", 169 source_range: [91; 91),
170 kind: Binding, 170 delete: [91; 91),
171 detail: "i32", 171 insert: "y",
172 }, 172 kind: Binding,
173]"### 173 detail: "i32",
174 },
175 ]
176 "###
174 ); 177 );
175 } 178 }
176 179
@@ -190,31 +193,34 @@ mod tests {
190 } 193 }
191 " 194 "
192 ), 195 ),
193 @r###"[ 196 @r###"
194 CompletionItem { 197 [
195 label: "a", 198 CompletionItem {
196 source_range: [242; 242), 199 label: "a",
197 delete: [242; 242), 200 source_range: [242; 242),
198 insert: "a", 201 delete: [242; 242),
199 kind: Binding, 202 insert: "a",
200 }, 203 kind: Binding,
201 CompletionItem { 204 },
202 label: "b", 205 CompletionItem {
203 source_range: [242; 242), 206 label: "b",
204 delete: [242; 242), 207 source_range: [242; 242),
205 insert: "b", 208 delete: [242; 242),
206 kind: Binding, 209 insert: "b",
207 detail: "i32", 210 kind: Binding,
208 }, 211 detail: "i32",
209 CompletionItem { 212 },
210 label: "quux", 213 CompletionItem {
211 source_range: [242; 242), 214 label: "quux()",
212 delete: [242; 242), 215 source_range: [242; 242),
213 insert: "quux()$0", 216 delete: [242; 242),
214 kind: Function, 217 insert: "quux()$0",
215 detail: "fn quux()", 218 kind: Function,
216 }, 219 lookup: "quux",
217]"### 220 detail: "fn quux()",
221 },
222 ]
223 "###
218 ); 224 );
219 } 225 }
220 226
@@ -230,23 +236,26 @@ mod tests {
230 } 236 }
231 " 237 "
232 ), 238 ),
233 @r###"[ 239 @r###"
234 CompletionItem { 240 [
235 label: "quux", 241 CompletionItem {
236 source_range: [95; 95), 242 label: "quux()",
237 delete: [95; 95), 243 source_range: [95; 95),
238 insert: "quux()$0", 244 delete: [95; 95),
239 kind: Function, 245 insert: "quux()$0",
240 detail: "fn quux()", 246 kind: Function,
241 }, 247 lookup: "quux",
242 CompletionItem { 248 detail: "fn quux()",
243 label: "x", 249 },
244 source_range: [95; 95), 250 CompletionItem {
245 delete: [95; 95), 251 label: "x",
246 insert: "x", 252 source_range: [95; 95),
247 kind: Binding, 253 delete: [95; 95),
248 }, 254 insert: "x",
249]"### 255 kind: Binding,
256 },
257 ]
258 "###
250 ); 259 );
251 } 260 }
252 261
@@ -260,23 +269,26 @@ mod tests {
260 } 269 }
261 " 270 "
262 ), 271 ),
263 @r###"[ 272 @r###"
264 CompletionItem { 273 [
265 label: "T", 274 CompletionItem {
266 source_range: [52; 52), 275 label: "T",
267 delete: [52; 52), 276 source_range: [52; 52),
268 insert: "T", 277 delete: [52; 52),
269 kind: TypeParam, 278 insert: "T",
270 }, 279 kind: TypeParam,
271 CompletionItem { 280 },
272 label: "quux", 281 CompletionItem {
273 source_range: [52; 52), 282 label: "quux()",
274 delete: [52; 52), 283 source_range: [52; 52),
275 insert: "quux()$0", 284 delete: [52; 52),
276 kind: Function, 285 insert: "quux()$0",
277 detail: "fn quux<T>()", 286 kind: Function,
278 }, 287 lookup: "quux",
279]"### 288 detail: "fn quux<T>()",
289 },
290 ]
291 "###
280 ); 292 );
281 } 293 }
282 294
@@ -290,22 +302,56 @@ mod tests {
290 } 302 }
291 " 303 "
292 ), 304 ),
293 @r###"[ 305 @r###"
294 CompletionItem { 306 [
295 label: "T", 307 CompletionItem {
296 source_range: [54; 54), 308 label: "T",
297 delete: [54; 54), 309 source_range: [54; 54),
298 insert: "T", 310 delete: [54; 54),
299 kind: TypeParam, 311 insert: "T",
300 }, 312 kind: TypeParam,
301 CompletionItem { 313 },
302 label: "X", 314 CompletionItem {
303 source_range: [54; 54), 315 label: "X<…>",
304 delete: [54; 54), 316 source_range: [54; 54),
305 insert: "X", 317 delete: [54; 54),
306 kind: Struct, 318 insert: "X<$0>",
307 }, 319 kind: Struct,
308]"### 320 lookup: "X",
321 },
322 ]
323 "###
324 );
325 }
326
327 #[test]
328 fn completes_self_in_enum() {
329 assert_debug_snapshot!(
330 do_reference_completion(
331 r"
332 enum X {
333 Y(<|>)
334 }
335 "
336 ),
337 @r###"
338 [
339 CompletionItem {
340 label: "Self",
341 source_range: [48; 48),
342 delete: [48; 48),
343 insert: "Self",
344 kind: TypeParam,
345 },
346 CompletionItem {
347 label: "X",
348 source_range: [48; 48),
349 delete: [48; 48),
350 insert: "X",
351 kind: Enum,
352 },
353 ]
354 "###
309 ); 355 );
310 } 356 }
311 357
@@ -321,30 +367,33 @@ mod tests {
321 } 367 }
322 " 368 "
323 ), 369 ),
324 @r###"[ 370 @r###"
325 CompletionItem { 371 [
326 label: "Baz", 372 CompletionItem {
327 source_range: [105; 105), 373 label: "Baz",
328 delete: [105; 105), 374 source_range: [105; 105),
329 insert: "Baz", 375 delete: [105; 105),
330 kind: Enum, 376 insert: "Baz",
331 }, 377 kind: Enum,
332 CompletionItem { 378 },
333 label: "Foo", 379 CompletionItem {
334 source_range: [105; 105), 380 label: "Foo",
335 delete: [105; 105), 381 source_range: [105; 105),
336 insert: "Foo", 382 delete: [105; 105),
337 kind: Struct, 383 insert: "Foo",
338 }, 384 kind: Struct,
339 CompletionItem { 385 },
340 label: "quux", 386 CompletionItem {
341 source_range: [105; 105), 387 label: "quux()",
342 delete: [105; 105), 388 source_range: [105; 105),
343 insert: "quux()$0", 389 delete: [105; 105),
344 kind: Function, 390 insert: "quux()$0",
345 detail: "fn quux()", 391 kind: Function,
346 }, 392 lookup: "quux",
347]"### 393 detail: "fn quux()",
394 },
395 ]
396 "###
348 ); 397 );
349 } 398 }
350 399
@@ -384,23 +433,26 @@ mod tests {
384 } 433 }
385 " 434 "
386 ), 435 ),
387 @r###"[ 436 @r###"
388 CompletionItem { 437 [
389 label: "Bar", 438 CompletionItem {
390 source_range: [117; 117), 439 label: "Bar",
391 delete: [117; 117), 440 source_range: [117; 117),
392 insert: "Bar", 441 delete: [117; 117),
393 kind: Struct, 442 insert: "Bar",
394 }, 443 kind: Struct,
395 CompletionItem { 444 },
396 label: "quux", 445 CompletionItem {
397 source_range: [117; 117), 446 label: "quux()",
398 delete: [117; 117), 447 source_range: [117; 117),
399 insert: "quux()$0", 448 delete: [117; 117),
400 kind: Function, 449 insert: "quux()$0",
401 detail: "fn quux()", 450 kind: Function,
402 }, 451 lookup: "quux",
403]"### 452 detail: "fn quux()",
453 },
454 ]
455 "###
404 ); 456 );
405 } 457 }
406 458
@@ -413,23 +465,26 @@ mod tests {
413 fn x() -> <|> 465 fn x() -> <|>
414 " 466 "
415 ), 467 ),
416 @r###"[ 468 @r###"
417 CompletionItem { 469 [
418 label: "Foo", 470 CompletionItem {
419 source_range: [55; 55), 471 label: "Foo",
420 delete: [55; 55), 472 source_range: [55; 55),
421 insert: "Foo", 473 delete: [55; 55),
422 kind: Struct, 474 insert: "Foo",
423 }, 475 kind: Struct,
424 CompletionItem { 476 },
425 label: "x", 477 CompletionItem {
426 source_range: [55; 55), 478 label: "x()",
427 delete: [55; 55), 479 source_range: [55; 55),
428 insert: "x()$0", 480 delete: [55; 55),
429 kind: Function, 481 insert: "x()$0",
430 detail: "fn x()", 482 kind: Function,
431 }, 483 lookup: "x",
432]"### 484 detail: "fn x()",
485 },
486 ]
487 "###
433 ); 488 );
434 } 489 }
435 490
@@ -447,24 +502,27 @@ mod tests {
447 } 502 }
448 " 503 "
449 ), 504 ),
450 @r###"[ 505 @r###"
451 CompletionItem { 506 [
452 label: "bar", 507 CompletionItem {
453 source_range: [146; 146), 508 label: "bar",
454 delete: [146; 146), 509 source_range: [146; 146),
455 insert: "bar", 510 delete: [146; 146),
456 kind: Binding, 511 insert: "bar",
457 detail: "i32", 512 kind: Binding,
458 }, 513 detail: "i32",
459 CompletionItem { 514 },
460 label: "foo", 515 CompletionItem {
461 source_range: [146; 146), 516 label: "foo()",
462 delete: [146; 146), 517 source_range: [146; 146),
463 insert: "foo()$0", 518 delete: [146; 146),
464 kind: Function, 519 insert: "foo()$0",
465 detail: "fn foo()", 520 kind: Function,
466 }, 521 lookup: "foo",
467]"### 522 detail: "fn foo()",
523 },
524 ]
525 "###
468 ); 526 );
469 } 527 }
470 528
@@ -509,30 +567,33 @@ mod tests {
509 } 567 }
510 " 568 "
511 ), 569 ),
512 @r#"[ 570 @r###"
513 CompletionItem { 571 [
514 label: "Option", 572 CompletionItem {
515 source_range: [18; 18), 573 label: "Option",
516 delete: [18; 18), 574 source_range: [18; 18),
517 insert: "Option", 575 delete: [18; 18),
518 kind: Struct, 576 insert: "Option",
519 }, 577 kind: Struct,
520 CompletionItem { 578 },
521 label: "foo", 579 CompletionItem {
522 source_range: [18; 18), 580 label: "foo()",
523 delete: [18; 18), 581 source_range: [18; 18),
524 insert: "foo()$0", 582 delete: [18; 18),
525 kind: Function, 583 insert: "foo()$0",
526 detail: "fn foo()", 584 kind: Function,
527 }, 585 lookup: "foo",
528 CompletionItem { 586 detail: "fn foo()",
529 label: "std", 587 },
530 source_range: [18; 18), 588 CompletionItem {
531 delete: [18; 18), 589 label: "std",
532 insert: "std", 590 source_range: [18; 18),
533 kind: Module, 591 delete: [18; 18),
534 }, 592 insert: "std",
535]"# 593 kind: Module,
594 },
595 ]
596 "###
536 ); 597 );
537 } 598 }
538 599
@@ -569,54 +630,57 @@ mod tests {
569 } 630 }
570 " 631 "
571 ), 632 ),
572 @r##"[ 633 @r###"
573 CompletionItem { 634 [
574 label: "bar!", 635 CompletionItem {
575 source_range: [252; 252), 636 label: "bar!",
576 delete: [252; 252), 637 source_range: [252; 252),
577 insert: "bar!($0)", 638 delete: [252; 252),
578 kind: Macro, 639 insert: "bar!($0)",
579 detail: "macro_rules! bar", 640 kind: Macro,
580 }, 641 detail: "macro_rules! bar",
581 CompletionItem { 642 },
582 label: "baz!", 643 CompletionItem {
583 source_range: [252; 252), 644 label: "baz!",
584 delete: [252; 252), 645 source_range: [252; 252),
585 insert: "baz!($0)", 646 delete: [252; 252),
586 kind: Macro, 647 insert: "baz!($0)",
587 detail: "#[macro_export]\nmacro_rules! baz", 648 kind: Macro,
588 }, 649 detail: "#[macro_export]\nmacro_rules! baz",
589 CompletionItem { 650 },
590 label: "foo!", 651 CompletionItem {
591 source_range: [252; 252), 652 label: "foo!",
592 delete: [252; 252), 653 source_range: [252; 252),
593 insert: "foo!($0)", 654 delete: [252; 252),
594 kind: Macro, 655 insert: "foo!($0)",
595 detail: "macro_rules! foo", 656 kind: Macro,
596 }, 657 detail: "macro_rules! foo",
597 CompletionItem { 658 },
598 label: "m1", 659 CompletionItem {
599 source_range: [252; 252), 660 label: "m1",
600 delete: [252; 252), 661 source_range: [252; 252),
601 insert: "m1", 662 delete: [252; 252),
602 kind: Module, 663 insert: "m1",
603 }, 664 kind: Module,
604 CompletionItem { 665 },
605 label: "m2", 666 CompletionItem {
606 source_range: [252; 252), 667 label: "m2",
607 delete: [252; 252), 668 source_range: [252; 252),
608 insert: "m2", 669 delete: [252; 252),
609 kind: Module, 670 insert: "m2",
610 }, 671 kind: Module,
611 CompletionItem { 672 },
612 label: "main", 673 CompletionItem {
613 source_range: [252; 252), 674 label: "main()",
614 delete: [252; 252), 675 source_range: [252; 252),
615 insert: "main()$0", 676 delete: [252; 252),
616 kind: Function, 677 insert: "main()$0",
617 detail: "fn main()", 678 kind: Function,
618 }, 679 lookup: "main",
619]"## 680 detail: "fn main()",
681 },
682 ]
683 "###
620 ); 684 );
621 } 685 }
622 686
@@ -635,24 +699,27 @@ mod tests {
635 } 699 }
636 " 700 "
637 ), 701 ),
638 @r##"[ 702 @r###"
639 CompletionItem { 703 [
640 label: "foo", 704 CompletionItem {
641 source_range: [49; 49), 705 label: "foo!",
642 delete: [49; 49), 706 source_range: [49; 49),
643 insert: "foo()$0", 707 delete: [49; 49),
644 kind: Function, 708 insert: "foo!($0)",
645 detail: "fn foo()", 709 kind: Macro,
646 }, 710 detail: "macro_rules! foo",
647 CompletionItem { 711 },
648 label: "foo!", 712 CompletionItem {
649 source_range: [49; 49), 713 label: "foo()",
650 delete: [49; 49), 714 source_range: [49; 49),
651 insert: "foo!($0)", 715 delete: [49; 49),
652 kind: Macro, 716 insert: "foo()$0",
653 detail: "macro_rules! foo", 717 kind: Function,
654 }, 718 lookup: "foo",
655]"## 719 detail: "fn foo()",
720 },
721 ]
722 "###
656 ); 723 );
657 } 724 }
658 725
@@ -671,24 +738,27 @@ mod tests {
671 } 738 }
672 " 739 "
673 ), 740 ),
674 @r##"[ 741 @r###"
675 CompletionItem { 742 [
676 label: "foo!", 743 CompletionItem {
677 source_range: [57; 57), 744 label: "foo!",
678 delete: [57; 57), 745 source_range: [57; 57),
679 insert: "foo!($0)", 746 delete: [57; 57),
680 kind: Macro, 747 insert: "foo!($0)",
681 detail: "macro_rules! foo", 748 kind: Macro,
682 }, 749 detail: "macro_rules! foo",
683 CompletionItem { 750 },
684 label: "main", 751 CompletionItem {
685 source_range: [57; 57), 752 label: "main()",
686 delete: [57; 57), 753 source_range: [57; 57),
687 insert: "main()$0", 754 delete: [57; 57),
688 kind: Function, 755 insert: "main()$0",
689 detail: "fn main()", 756 kind: Function,
690 }, 757 lookup: "main",
691]"## 758 detail: "fn main()",
759 },
760 ]
761 "###
692 ); 762 );
693 } 763 }
694 764
@@ -707,24 +777,27 @@ mod tests {
707 } 777 }
708 " 778 "
709 ), 779 ),
710 @r##"[ 780 @r###"
711 CompletionItem { 781 [
712 label: "foo!", 782 CompletionItem {
713 source_range: [50; 50), 783 label: "foo!",
714 delete: [50; 50), 784 source_range: [50; 50),
715 insert: "foo!($0)", 785 delete: [50; 50),
716 kind: Macro, 786 insert: "foo!($0)",
717 detail: "macro_rules! foo", 787 kind: Macro,
718 }, 788 detail: "macro_rules! foo",
719 CompletionItem { 789 },
720 label: "main", 790 CompletionItem {
721 source_range: [50; 50), 791 label: "main()",
722 delete: [50; 50), 792 source_range: [50; 50),
723 insert: "main()$0", 793 delete: [50; 50),
724 kind: Function, 794 insert: "main()$0",
725 detail: "fn main()", 795 kind: Function,
726 }, 796 lookup: "main",
727]"## 797 detail: "fn main()",
798 },
799 ]
800 "###
728 ); 801 );
729 } 802 }
730} 803}
diff --git a/crates/ra_ide_api/src/completion/completion_context.rs b/crates/ra_ide_api/src/completion/completion_context.rs
index e9ad06965..64cbc0f98 100644
--- a/crates/ra_ide_api/src/completion/completion_context.rs
+++ b/crates/ra_ide_api/src/completion/completion_context.rs
@@ -38,8 +38,11 @@ pub(crate) struct CompletionContext<'a> {
38 pub(super) is_new_item: bool, 38 pub(super) is_new_item: bool,
39 /// The receiver if this is a field or method access, i.e. writing something.<|> 39 /// The receiver if this is a field or method access, i.e. writing something.<|>
40 pub(super) dot_receiver: Option<ast::Expr>, 40 pub(super) dot_receiver: Option<ast::Expr>,
41 pub(super) dot_receiver_is_ambiguous_float_literal: bool,
41 /// If this is a call (method or function) in particular, i.e. the () are already there. 42 /// If this is a call (method or function) in particular, i.e. the () are already there.
42 pub(super) is_call: bool, 43 pub(super) is_call: bool,
44 pub(super) is_path_type: bool,
45 pub(super) has_type_args: bool,
43} 46}
44 47
45impl<'a> CompletionContext<'a> { 48impl<'a> CompletionContext<'a> {
@@ -76,6 +79,9 @@ impl<'a> CompletionContext<'a> {
76 is_new_item: false, 79 is_new_item: false,
77 dot_receiver: None, 80 dot_receiver: None,
78 is_call: false, 81 is_call: false,
82 is_path_type: false,
83 has_type_args: false,
84 dot_receiver_is_ambiguous_float_literal: false,
79 }; 85 };
80 ctx.fill(&original_parse, position.offset); 86 ctx.fill(&original_parse, position.offset);
81 Some(ctx) 87 Some(ctx)
@@ -176,6 +182,9 @@ impl<'a> CompletionContext<'a> {
176 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast)) 182 .and_then(|it| it.syntax().parent().and_then(ast::CallExpr::cast))
177 .is_some(); 183 .is_some();
178 184
185 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
186 self.has_type_args = segment.type_arg_list().is_some();
187
179 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 188 if let Some(mut path) = hir::Path::from_ast(path.clone()) {
180 if !path.is_ident() { 189 if !path.is_ident() {
181 path.segments.pop().unwrap(); 190 path.segments.pop().unwrap();
@@ -228,6 +237,16 @@ impl<'a> CompletionContext<'a> {
228 .expr() 237 .expr()
229 .map(|e| e.syntax().text_range()) 238 .map(|e| e.syntax().text_range())
230 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 239 .and_then(|r| find_node_with_range(original_file.syntax(), r));
240 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) =
241 &self.dot_receiver
242 {
243 match l.kind() {
244 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'),
245 _ => false,
246 }
247 } else {
248 false
249 }
231 } 250 }
232 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 251 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
233 // As above 252 // As above
diff --git a/crates/ra_ide_api/src/completion/completion_item.rs b/crates/ra_ide_api/src/completion/completion_item.rs
index b1f0390ec..3e6933bc1 100644
--- a/crates/ra_ide_api/src/completion/completion_item.rs
+++ b/crates/ra_ide_api/src/completion/completion_item.rs
@@ -216,6 +216,10 @@ impl Builder {
216 self.lookup = Some(lookup.into()); 216 self.lookup = Some(lookup.into());
217 self 217 self
218 } 218 }
219 pub(crate) fn label(mut self, label: impl Into<String>) -> Builder {
220 self.label = label.into();
221 self
222 }
219 pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder { 223 pub(crate) fn insert_text(mut self, insert_text: impl Into<String>) -> Builder {
220 self.insert_text = Some(insert_text.into()); 224 self.insert_text = Some(insert_text.into());
221 self 225 self
diff --git a/crates/ra_ide_api/src/completion/presentation.rs b/crates/ra_ide_api/src/completion/presentation.rs
index 48028a2f9..aed4ce6d4 100644
--- a/crates/ra_ide_api/src/completion/presentation.rs
+++ b/crates/ra_ide_api/src/completion/presentation.rs
@@ -1,12 +1,12 @@
1//! This modules takes care of rendering various definitions as completion items. 1//! This modules takes care of rendering various definitions as completion items.
2 2
3use hir::{Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk}; 3use hir::{db::HirDatabase, Docs, HasSource, HirDisplay, ScopeDef, Ty, TypeWalk};
4use join_to_string::join; 4use join_to_string::join;
5use ra_syntax::ast::NameOwner; 5use ra_syntax::ast::NameOwner;
6use test_utils::tested_by; 6use test_utils::tested_by;
7 7
8use crate::completion::{ 8use crate::completion::{
9 CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions, 9 db, CompletionContext, CompletionItem, CompletionItemKind, CompletionKind, Completions,
10}; 10};
11 11
12use crate::display::{const_label, function_label, macro_label, type_label}; 12use crate::display::{const_label, function_label, macro_label, type_label};
@@ -44,54 +44,56 @@ impl Completions {
44 ) { 44 ) {
45 use hir::ModuleDef::*; 45 use hir::ModuleDef::*;
46 46
47 let mut completion_kind = CompletionKind::Reference; 47 let completion_kind = match resolution {
48 let (kind, docs) = match resolution { 48 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionKind::BuiltinType,
49 ScopeDef::ModuleDef(Module(it)) => (CompletionItemKind::Module, it.docs(ctx.db)), 49 _ => CompletionKind::Reference,
50 };
51
52 let kind = match resolution {
53 ScopeDef::ModuleDef(Module(..)) => CompletionItemKind::Module,
50 ScopeDef::ModuleDef(Function(func)) => { 54 ScopeDef::ModuleDef(Function(func)) => {
51 return self.add_function_with_name(ctx, Some(local_name), *func); 55 return self.add_function_with_name(ctx, Some(local_name), *func);
52 } 56 }
53 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(it))) => { 57 ScopeDef::ModuleDef(Adt(hir::Adt::Struct(_))) => CompletionItemKind::Struct,
54 (CompletionItemKind::Struct, it.docs(ctx.db)) 58 // FIXME: add CompletionItemKind::Union
55 } 59 ScopeDef::ModuleDef(Adt(hir::Adt::Union(_))) => CompletionItemKind::Struct,
56 ScopeDef::ModuleDef(Adt(hir::Adt::Union(it))) => { 60 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(_))) => CompletionItemKind::Enum,
57 (CompletionItemKind::Struct, it.docs(ctx.db)) 61
58 } 62 ScopeDef::ModuleDef(EnumVariant(..)) => CompletionItemKind::EnumVariant,
59 ScopeDef::ModuleDef(Adt(hir::Adt::Enum(it))) => { 63 ScopeDef::ModuleDef(Const(..)) => CompletionItemKind::Const,
60 (CompletionItemKind::Enum, it.docs(ctx.db)) 64 ScopeDef::ModuleDef(Static(..)) => CompletionItemKind::Static,
61 } 65 ScopeDef::ModuleDef(Trait(..)) => CompletionItemKind::Trait,
62 ScopeDef::ModuleDef(EnumVariant(it)) => { 66 ScopeDef::ModuleDef(TypeAlias(..)) => CompletionItemKind::TypeAlias,
63 (CompletionItemKind::EnumVariant, it.docs(ctx.db)) 67 ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
64 } 68 ScopeDef::GenericParam(..) => CompletionItemKind::TypeParam,
65 ScopeDef::ModuleDef(Const(it)) => (CompletionItemKind::Const, it.docs(ctx.db)), 69 ScopeDef::LocalBinding(..) => CompletionItemKind::Binding,
66 ScopeDef::ModuleDef(Static(it)) => (CompletionItemKind::Static, it.docs(ctx.db)), 70 // (does this need its own kind?)
67 ScopeDef::ModuleDef(Trait(it)) => (CompletionItemKind::Trait, it.docs(ctx.db)), 71 ScopeDef::AdtSelfType(..) | ScopeDef::ImplSelfType(..) => CompletionItemKind::TypeParam,
68 ScopeDef::ModuleDef(TypeAlias(it)) => (CompletionItemKind::TypeAlias, it.docs(ctx.db)),
69 ScopeDef::ModuleDef(BuiltinType(..)) => {
70 completion_kind = CompletionKind::BuiltinType;
71 (CompletionItemKind::BuiltinType, None)
72 }
73 ScopeDef::GenericParam(..) => (CompletionItemKind::TypeParam, None),
74 ScopeDef::LocalBinding(..) => (CompletionItemKind::Binding, None),
75 ScopeDef::SelfType(..) => (
76 CompletionItemKind::TypeParam, // (does this need its own kind?)
77 None,
78 ),
79 ScopeDef::MacroDef(mac) => { 72 ScopeDef::MacroDef(mac) => {
80 self.add_macro(ctx, Some(local_name), *mac); 73 return self.add_macro(ctx, Some(local_name), *mac);
81 return;
82 } 74 }
83 ScopeDef::Unknown => { 75 ScopeDef::Unknown => {
84 self.add(CompletionItem::new( 76 return self.add(CompletionItem::new(
85 CompletionKind::Reference, 77 CompletionKind::Reference,
86 ctx.source_range(), 78 ctx.source_range(),
87 local_name, 79 local_name,
88 )); 80 ));
89 return;
90 } 81 }
91 }; 82 };
92 83
84 let docs = match resolution {
85 ScopeDef::ModuleDef(Module(it)) => it.docs(ctx.db),
86 ScopeDef::ModuleDef(Adt(it)) => it.docs(ctx.db),
87 ScopeDef::ModuleDef(EnumVariant(it)) => it.docs(ctx.db),
88 ScopeDef::ModuleDef(Const(it)) => it.docs(ctx.db),
89 ScopeDef::ModuleDef(Static(it)) => it.docs(ctx.db),
90 ScopeDef::ModuleDef(Trait(it)) => it.docs(ctx.db),
91 ScopeDef::ModuleDef(TypeAlias(it)) => it.docs(ctx.db),
92 _ => None,
93 };
94
93 let mut completion_item = 95 let mut completion_item =
94 CompletionItem::new(completion_kind, ctx.source_range(), local_name); 96 CompletionItem::new(completion_kind, ctx.source_range(), local_name.clone());
95 if let ScopeDef::LocalBinding(pat_id) = resolution { 97 if let ScopeDef::LocalBinding(pat_id) = resolution {
96 let ty = ctx 98 let ty = ctx
97 .analyzer 99 .analyzer
@@ -100,6 +102,28 @@ impl Completions {
100 .map(|t| t.display(ctx.db).to_string()); 102 .map(|t| t.display(ctx.db).to_string());
101 completion_item = completion_item.set_detail(ty); 103 completion_item = completion_item.set_detail(ty);
102 }; 104 };
105
106 // If not an import, add parenthesis automatically.
107 if ctx.is_path_type
108 && !ctx.has_type_args
109 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
110 {
111 let generic_def: Option<hir::GenericDef> = match resolution {
112 ScopeDef::ModuleDef(Adt(it)) => Some((*it).into()),
113 ScopeDef::ModuleDef(TypeAlias(it)) => Some((*it).into()),
114 _ => None,
115 };
116 if let Some(def) = generic_def {
117 if has_non_default_type_params(def, ctx.db) {
118 tested_by!(inserts_angle_brackets_for_generics);
119 completion_item = completion_item
120 .lookup_by(local_name.clone())
121 .label(format!("{}<…>", local_name))
122 .insert_snippet(format!("{}<$0>", local_name));
123 }
124 }
125 }
126
103 completion_item.kind(kind).set_documentation(docs).add_to(self) 127 completion_item.kind(kind).set_documentation(docs).add_to(self)
104 } 128 }
105 129
@@ -107,6 +131,33 @@ impl Completions {
107 self.add_function_with_name(ctx, None, func) 131 self.add_function_with_name(ctx, None, func)
108 } 132 }
109 133
134 fn guess_macro_braces(&self, macro_name: &str, docs: &str) -> &'static str {
135 let mut votes = [0, 0, 0];
136 for (idx, s) in docs.match_indices(&macro_name) {
137 let (before, after) = (&docs[..idx], &docs[idx + s.len()..]);
138 // Ensure to match the full word
139 if after.starts_with("!")
140 && before
141 .chars()
142 .rev()
143 .next()
144 .map_or(true, |c| c != '_' && !c.is_ascii_alphanumeric())
145 {
146 // It may have spaces before the braces like `foo! {}`
147 match after[1..].chars().find(|&c| !c.is_whitespace()) {
148 Some('{') => votes[0] += 1,
149 Some('[') => votes[1] += 1,
150 Some('(') => votes[2] += 1,
151 _ => {}
152 }
153 }
154 }
155
156 // Insert a space before `{}`.
157 // We prefer the last one when some votes equal.
158 *votes.iter().zip(&[" {$0}", "[$0]", "($0)"]).max_by_key(|&(&vote, _)| vote).unwrap().1
159 }
160
110 pub(crate) fn add_macro( 161 pub(crate) fn add_macro(
111 &mut self, 162 &mut self,
112 ctx: &CompletionContext, 163 ctx: &CompletionContext,
@@ -117,10 +168,9 @@ impl Completions {
117 if let Some(name) = name { 168 if let Some(name) = name {
118 let detail = macro_label(&ast_node); 169 let detail = macro_label(&ast_node);
119 170
120 let macro_braces_to_insert = match name.as_str() { 171 let docs = macro_.docs(ctx.db);
121 "vec" => "[$0]", 172 let macro_braces_to_insert =
122 _ => "($0)", 173 self.guess_macro_braces(&name, docs.as_ref().map_or("", |s| s.as_str()));
123 };
124 let macro_declaration = name + "!"; 174 let macro_declaration = name + "!";
125 175
126 let builder = CompletionItem::new( 176 let builder = CompletionItem::new(
@@ -129,7 +179,7 @@ impl Completions {
129 &macro_declaration, 179 &macro_declaration,
130 ) 180 )
131 .kind(CompletionItemKind::Macro) 181 .kind(CompletionItemKind::Macro)
132 .set_documentation(macro_.docs(ctx.db)) 182 .set_documentation(docs)
133 .detail(detail) 183 .detail(detail)
134 .insert_snippet(macro_declaration + macro_braces_to_insert); 184 .insert_snippet(macro_declaration + macro_braces_to_insert);
135 185
@@ -148,28 +198,31 @@ impl Completions {
148 let ast_node = func.source(ctx.db).ast; 198 let ast_node = func.source(ctx.db).ast;
149 let detail = function_label(&ast_node); 199 let detail = function_label(&ast_node);
150 200
151 let mut builder = CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name) 201 let mut builder =
152 .kind(if data.has_self_param() { 202 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.clone())
153 CompletionItemKind::Method 203 .kind(if data.has_self_param() {
154 } else { 204 CompletionItemKind::Method
155 CompletionItemKind::Function 205 } else {
156 }) 206 CompletionItemKind::Function
157 .set_documentation(func.docs(ctx.db)) 207 })
158 .detail(detail); 208 .set_documentation(func.docs(ctx.db))
159 // If not an import, add parenthesis automatically. 209 .detail(detail);
210
211 // Add `<>` for generic types
160 if ctx.use_item_syntax.is_none() 212 if ctx.use_item_syntax.is_none()
161 && !ctx.is_call 213 && !ctx.is_call
162 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis") 214 && ctx.db.feature_flags.get("completion.insertion.add-call-parenthesis")
163 { 215 {
164 tested_by!(inserts_parens_for_function_calls); 216 tested_by!(inserts_parens_for_function_calls);
165 let snippet = 217 let (snippet, label) =
166 if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 { 218 if data.params().is_empty() || data.has_self_param() && data.params().len() == 1 {
167 format!("{}()$0", data.name()) 219 (format!("{}()$0", data.name()), format!("{}()", name))
168 } else { 220 } else {
169 format!("{}($0)", data.name()) 221 (format!("{}($0)", data.name()), format!("{}(…)", name))
170 }; 222 };
171 builder = builder.insert_snippet(snippet); 223 builder = builder.lookup_by(name.clone()).label(label).insert_snippet(snippet);
172 } 224 }
225
173 self.add(builder) 226 self.add(builder)
174 } 227 }
175 228
@@ -213,7 +266,6 @@ impl Completions {
213 .separator(", ") 266 .separator(", ")
214 .surround_with("(", ")") 267 .surround_with("(", ")")
215 .to_string(); 268 .to_string();
216
217 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string()) 269 CompletionItem::new(CompletionKind::Reference, ctx.source_range(), name.to_string())
218 .kind(CompletionItemKind::EnumVariant) 270 .kind(CompletionItemKind::EnumVariant)
219 .set_documentation(variant.docs(ctx.db)) 271 .set_documentation(variant.docs(ctx.db))
@@ -222,6 +274,11 @@ impl Completions {
222 } 274 }
223} 275}
224 276
277fn has_non_default_type_params(def: hir::GenericDef, db: &db::RootDatabase) -> bool {
278 let subst = db.generic_defaults(def);
279 subst.iter().any(|ty| ty == &Ty::Unknown)
280}
281
225#[cfg(test)] 282#[cfg(test)]
226mod tests { 283mod tests {
227 use crate::completion::{do_completion, CompletionItem, CompletionKind}; 284 use crate::completion::{do_completion, CompletionItem, CompletionKind};
@@ -242,24 +299,28 @@ mod tests {
242 fn main() { no_<|> } 299 fn main() { no_<|> }
243 " 300 "
244 ), 301 ),
245 @r###"[ 302 @r###"
246 CompletionItem { 303 [
247 label: "main", 304 CompletionItem {
248 source_range: [61; 64), 305 label: "main()",
249 delete: [61; 64), 306 source_range: [61; 64),
250 insert: "main()$0", 307 delete: [61; 64),
251 kind: Function, 308 insert: "main()$0",
252 detail: "fn main()", 309 kind: Function,
253 }, 310 lookup: "main",
254 CompletionItem { 311 detail: "fn main()",
255 label: "no_args", 312 },
256 source_range: [61; 64), 313 CompletionItem {
257 delete: [61; 64), 314 label: "no_args()",
258 insert: "no_args()$0", 315 source_range: [61; 64),
259 kind: Function, 316 delete: [61; 64),
260 detail: "fn no_args()", 317 insert: "no_args()$0",
261 }, 318 kind: Function,
262]"### 319 lookup: "no_args",
320 detail: "fn no_args()",
321 },
322 ]
323 "###
263 ); 324 );
264 assert_debug_snapshot!( 325 assert_debug_snapshot!(
265 do_reference_completion( 326 do_reference_completion(
@@ -268,24 +329,28 @@ mod tests {
268 fn main() { with_<|> } 329 fn main() { with_<|> }
269 " 330 "
270 ), 331 ),
271 @r###"[ 332 @r###"
272 CompletionItem { 333 [
273 label: "main", 334 CompletionItem {
274 source_range: [80; 85), 335 label: "main()",
275 delete: [80; 85), 336 source_range: [80; 85),
276 insert: "main()$0", 337 delete: [80; 85),
277 kind: Function, 338 insert: "main()$0",
278 detail: "fn main()", 339 kind: Function,
279 }, 340 lookup: "main",
280 CompletionItem { 341 detail: "fn main()",
281 label: "with_args", 342 },
282 source_range: [80; 85), 343 CompletionItem {
283 delete: [80; 85), 344 label: "with_args(…)",
284 insert: "with_args($0)", 345 source_range: [80; 85),
285 kind: Function, 346 delete: [80; 85),
286 detail: "fn with_args(x: i32, y: String)", 347 insert: "with_args($0)",
287 }, 348 kind: Function,
288]"### 349 lookup: "with_args",
350 detail: "fn with_args(x: i32, y: String)",
351 },
352 ]
353 "###
289 ); 354 );
290 assert_debug_snapshot!( 355 assert_debug_snapshot!(
291 do_reference_completion( 356 do_reference_completion(
@@ -299,16 +364,19 @@ mod tests {
299 } 364 }
300 " 365 "
301 ), 366 ),
302 @r###"[ 367 @r###"
303 CompletionItem { 368 [
304 label: "foo", 369 CompletionItem {
305 source_range: [163; 164), 370 label: "foo()",
306 delete: [163; 164), 371 source_range: [163; 164),
307 insert: "foo()$0", 372 delete: [163; 164),
308 kind: Method, 373 insert: "foo()$0",
309 detail: "fn foo(&self)", 374 kind: Method,
310 }, 375 lookup: "foo",
311]"### 376 detail: "fn foo(&self)",
377 },
378 ]
379 "###
312 ); 380 );
313 } 381 }
314 382
@@ -389,4 +457,123 @@ mod tests {
389]"# 457]"#
390 ); 458 );
391 } 459 }
460
461 #[test]
462 fn inserts_angle_brackets_for_generics() {
463 covers!(inserts_angle_brackets_for_generics);
464 assert_debug_snapshot!(
465 do_reference_completion(
466 r"
467 struct Vec<T> {}
468 fn foo(xs: Ve<|>)
469 "
470 ),
471 @r###"
472 [
473 CompletionItem {
474 label: "Vec<…>",
475 source_range: [61; 63),
476 delete: [61; 63),
477 insert: "Vec<$0>",
478 kind: Struct,
479 lookup: "Vec",
480 },
481 CompletionItem {
482 label: "foo(…)",
483 source_range: [61; 63),
484 delete: [61; 63),
485 insert: "foo($0)",
486 kind: Function,
487 lookup: "foo",
488 detail: "fn foo(xs: Ve)",
489 },
490 ]
491 "###
492 );
493 assert_debug_snapshot!(
494 do_reference_completion(
495 r"
496 type Vec<T> = (T,);
497 fn foo(xs: Ve<|>)
498 "
499 ),
500 @r###"
501 [
502 CompletionItem {
503 label: "Vec<…>",
504 source_range: [64; 66),
505 delete: [64; 66),
506 insert: "Vec<$0>",
507 kind: TypeAlias,
508 lookup: "Vec",
509 },
510 CompletionItem {
511 label: "foo(…)",
512 source_range: [64; 66),
513 delete: [64; 66),
514 insert: "foo($0)",
515 kind: Function,
516 lookup: "foo",
517 detail: "fn foo(xs: Ve)",
518 },
519 ]
520 "###
521 );
522 assert_debug_snapshot!(
523 do_reference_completion(
524 r"
525 struct Vec<T = i128> {}
526 fn foo(xs: Ve<|>)
527 "
528 ),
529 @r###"
530 [
531 CompletionItem {
532 label: "Vec",
533 source_range: [68; 70),
534 delete: [68; 70),
535 insert: "Vec",
536 kind: Struct,
537 },
538 CompletionItem {
539 label: "foo(…)",
540 source_range: [68; 70),
541 delete: [68; 70),
542 insert: "foo($0)",
543 kind: Function,
544 lookup: "foo",
545 detail: "fn foo(xs: Ve)",
546 },
547 ]
548 "###
549 );
550 assert_debug_snapshot!(
551 do_reference_completion(
552 r"
553 struct Vec<T> {}
554 fn foo(xs: Ve<|><i128>)
555 "
556 ),
557 @r###"
558 [
559 CompletionItem {
560 label: "Vec",
561 source_range: [61; 63),
562 delete: [61; 63),
563 insert: "Vec",
564 kind: Struct,
565 },
566 CompletionItem {
567 label: "foo(…)",
568 source_range: [61; 63),
569 delete: [61; 63),
570 insert: "foo($0)",
571 kind: Function,
572 lookup: "foo",
573 detail: "fn foo(xs: Ve<i128>)",
574 },
575 ]
576 "###
577 );
578 }
392} 579}
diff --git a/crates/ra_ide_api/src/db.rs b/crates/ra_ide_api/src/db.rs
index ea0714add..9146b647a 100644
--- a/crates/ra_ide_api/src/db.rs
+++ b/crates/ra_ide_api/src/db.rs
@@ -4,8 +4,10 @@ use std::sync::Arc;
4 4
5use ra_db::{ 5use ra_db::{
6 salsa::{self, Database, Durability}, 6 salsa::{self, Database, Durability},
7 Canceled, CheckCanceled, CrateId, FileId, SourceDatabase, SourceRootId, 7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase,
8 SourceDatabaseExt, SourceRootId,
8}; 9};
10use relative_path::RelativePath;
9use rustc_hash::FxHashMap; 11use rustc_hash::FxHashMap;
10 12
11use crate::{ 13use crate::{
@@ -15,6 +17,7 @@ use crate::{
15 17
16#[salsa::database( 18#[salsa::database(
17 ra_db::SourceDatabaseStorage, 19 ra_db::SourceDatabaseStorage,
20 ra_db::SourceDatabaseExtStorage,
18 LineIndexDatabaseStorage, 21 LineIndexDatabaseStorage,
19 symbol_index::SymbolsDatabaseStorage, 22 symbol_index::SymbolsDatabaseStorage,
20 hir::db::InternDatabaseStorage, 23 hir::db::InternDatabaseStorage,
@@ -31,6 +34,22 @@ pub(crate) struct RootDatabase {
31 pub(crate) last_gc_check: crate::wasm_shims::Instant, 34 pub(crate) last_gc_check: crate::wasm_shims::Instant,
32} 35}
33 36
37impl FileLoader for RootDatabase {
38 fn file_text(&self, file_id: FileId) -> Arc<String> {
39 FileLoaderDelegate(self).file_text(file_id)
40 }
41 fn resolve_relative_path(
42 &self,
43 anchor: FileId,
44 relative_path: &RelativePath,
45 ) -> Option<FileId> {
46 FileLoaderDelegate(self).resolve_relative_path(anchor, relative_path)
47 }
48 fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> {
49 FileLoaderDelegate(self).relevant_crates(file_id)
50 }
51}
52
34impl hir::debug::HirDebugHelper for RootDatabase { 53impl hir::debug::HirDebugHelper for RootDatabase {
35 fn crate_name(&self, krate: CrateId) -> Option<String> { 54 fn crate_name(&self, krate: CrateId) -> Option<String> {
36 self.debug_data.crate_names.get(&krate).cloned() 55 self.debug_data.crate_names.get(&krate).cloned()
@@ -39,7 +58,7 @@ impl hir::debug::HirDebugHelper for RootDatabase {
39 let source_root_id = self.file_source_root(file_id); 58 let source_root_id = self.file_source_root(file_id);
40 let source_root_path = self.debug_data.root_paths.get(&source_root_id)?; 59 let source_root_path = self.debug_data.root_paths.get(&source_root_id)?;
41 let file_path = self.file_relative_path(file_id); 60 let file_path = self.file_relative_path(file_id);
42 Some(format!("{}/{}", source_root_path, file_path.display())) 61 Some(format!("{}/{}", source_root_path, file_path))
43 } 62 }
44} 63}
45 64
@@ -104,7 +123,7 @@ pub(crate) trait LineIndexDatabase: ra_db::SourceDatabase + CheckCanceled {
104 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>; 123 fn line_index(&self, file_id: FileId) -> Arc<LineIndex>;
105} 124}
106 125
107fn line_index(db: &impl ra_db::SourceDatabase, file_id: FileId) -> Arc<LineIndex> { 126fn line_index(db: &impl LineIndexDatabase, file_id: FileId) -> Arc<LineIndex> {
108 let text = db.file_text(file_id); 127 let text = db.file_text(file_id);
109 Arc::new(LineIndex::new(&*text)) 128 Arc::new(LineIndex::new(&*text))
110} 129}
diff --git a/crates/ra_ide_api/src/diagnostics.rs b/crates/ra_ide_api/src/diagnostics.rs
index 0435188c8..8743a3a79 100644
--- a/crates/ra_ide_api/src/diagnostics.rs
+++ b/crates/ra_ide_api/src/diagnostics.rs
@@ -4,7 +4,7 @@ use std::cell::RefCell;
4 4
5use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink}; 5use hir::diagnostics::{AstDiagnostic, Diagnostic as _, DiagnosticSink};
6use itertools::Itertools; 6use itertools::Itertools;
7use ra_db::SourceDatabase; 7use ra_db::{SourceDatabase, SourceDatabaseExt};
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{ 9use ra_syntax::{
10 algo, 10 algo,
@@ -12,6 +12,7 @@ use ra_syntax::{
12 Location, SyntaxNode, TextRange, T, 12 Location, SyntaxNode, TextRange, T,
13}; 13};
14use ra_text_edit::{TextEdit, TextEditBuilder}; 14use ra_text_edit::{TextEdit, TextEditBuilder};
15use relative_path::RelativePath;
15 16
16use crate::{db::RootDatabase, Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit}; 17use crate::{db::RootDatabase, Diagnostic, FileId, FileSystemEdit, SourceChange, SourceFileEdit};
17 18
@@ -47,8 +48,14 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
47 }) 48 })
48 }) 49 })
49 .on::<hir::diagnostics::UnresolvedModule, _>(|d| { 50 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
50 let source_root = db.file_source_root(d.source().file_id.original_file(db)); 51 let original_file = d.source().file_id.original_file(db);
51 let create_file = FileSystemEdit::CreateFile { source_root, path: d.candidate.clone() }; 52 let source_root = db.file_source_root(original_file);
53 let path = db
54 .file_relative_path(original_file)
55 .parent()
56 .unwrap_or_else(|| RelativePath::new(""))
57 .join(&d.candidate);
58 let create_file = FileSystemEdit::CreateFile { source_root, path };
52 let fix = SourceChange::file_system_edit("create module", create_file); 59 let fix = SourceChange::file_system_edit("create module", create_file);
53 res.borrow_mut().push(Diagnostic { 60 res.borrow_mut().push(Diagnostic {
54 range: d.highlight_range(), 61 range: d.highlight_range(),
diff --git a/crates/ra_ide_api/src/display/navigation_target.rs b/crates/ra_ide_api/src/display/navigation_target.rs
index d0b1a8a2a..5cb67fb95 100644
--- a/crates/ra_ide_api/src/display/navigation_target.rs
+++ b/crates/ra_ide_api/src/display/navigation_target.rs
@@ -119,7 +119,7 @@ impl NavigationTarget {
119 119
120 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 120 pub(crate) fn from_module(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
121 let src = module.definition_source(db); 121 let src = module.definition_source(db);
122 let file_id = src.file_id.as_original_file(); 122 let file_id = src.file_id.original_file(db);
123 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 123 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
124 match src.ast { 124 match src.ast {
125 ModuleSource::SourceFile(node) => { 125 ModuleSource::SourceFile(node) => {
@@ -139,7 +139,7 @@ impl NavigationTarget {
139 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget { 139 pub(crate) fn from_module_to_decl(db: &RootDatabase, module: hir::Module) -> NavigationTarget {
140 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 140 let name = module.name(db).map(|it| it.to_string().into()).unwrap_or_default();
141 if let Some(src) = module.declaration_source(db) { 141 if let Some(src) = module.declaration_source(db) {
142 let file_id = src.file_id.as_original_file(); 142 let file_id = src.file_id.original_file(db);
143 return NavigationTarget::from_syntax( 143 return NavigationTarget::from_syntax(
144 file_id, 144 file_id,
145 name, 145 name,
@@ -213,7 +213,7 @@ impl NavigationTarget {
213 ) -> NavigationTarget { 213 ) -> NavigationTarget {
214 let src = impl_block.source(db); 214 let src = impl_block.source(db);
215 NavigationTarget::from_syntax( 215 NavigationTarget::from_syntax(
216 src.file_id.as_original_file(), 216 src.file_id.original_file(db),
217 "impl".into(), 217 "impl".into(),
218 None, 218 None,
219 src.ast.syntax(), 219 src.ast.syntax(),
diff --git a/crates/ra_ide_api/src/extend_selection.rs b/crates/ra_ide_api/src/extend_selection.rs
index 33fefb541..602757e92 100644
--- a/crates/ra_ide_api/src/extend_selection.rs
+++ b/crates/ra_ide_api/src/extend_selection.rs
@@ -32,6 +32,7 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
32 PARAM_LIST, 32 PARAM_LIST,
33 ARG_LIST, 33 ARG_LIST,
34 ARRAY_EXPR, 34 ARRAY_EXPR,
35 TUPLE_EXPR,
35 ]; 36 ];
36 37
37 if range.is_empty() { 38 if range.is_empty() {
@@ -245,6 +246,8 @@ mod tests {
245 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); 246 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
246 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", ", 33"]); 247 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", ", 33"]);
247 248
249 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]);
250
248 do_check( 251 do_check(
249 r#" 252 r#"
250const FOO: [usize; 2] = [ 253const FOO: [usize; 2] = [
diff --git a/crates/ra_ide_api/src/goto_definition.rs b/crates/ra_ide_api/src/goto_definition.rs
index 41a88314f..1f3fa6c57 100644
--- a/crates/ra_ide_api/src/goto_definition.rs
+++ b/crates/ra_ide_api/src/goto_definition.rs
@@ -10,7 +10,7 @@ use ra_syntax::{
10use crate::{ 10use crate::{
11 db::RootDatabase, 11 db::RootDatabase,
12 display::ShortLabel, 12 display::ShortLabel,
13 name_ref_kind::{classify_name_ref, NameRefKind::*}, 13 references::{classify_name_ref, NameKind::*},
14 FilePosition, NavigationTarget, RangeInfo, 14 FilePosition, NavigationTarget, RangeInfo,
15}; 15};
16 16
@@ -54,13 +54,11 @@ pub(crate) fn reference_definition(
54) -> ReferenceResult { 54) -> ReferenceResult {
55 use self::ReferenceResult::*; 55 use self::ReferenceResult::*;
56 56
57 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 57 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
58 58 match name_kind {
59 match classify_name_ref(db, &analyzer, name_ref) {
60 Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)), 59 Some(Macro(mac)) => return Exact(NavigationTarget::from_macro_def(db, mac)),
61 Some(FieldAccess(field)) => return Exact(NavigationTarget::from_field(db, field)), 60 Some(Field(field)) => return Exact(NavigationTarget::from_field(db, field)),
62 Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)), 61 Some(AssocItem(assoc)) => return Exact(NavigationTarget::from_assoc_item(db, assoc)),
63 Some(Method(func)) => return Exact(NavigationTarget::from_def_source(db, func)),
64 Some(Def(def)) => match NavigationTarget::from_def(db, def) { 62 Some(Def(def)) => match NavigationTarget::from_def(db, def) {
65 Some(nav) => return Exact(nav), 63 Some(nav) => return Exact(nav),
66 None => return Approximate(vec![]), 64 None => return Approximate(vec![]),
@@ -70,7 +68,7 @@ pub(crate) fn reference_definition(
70 return Exact(NavigationTarget::from_adt_def(db, def_id)); 68 return Exact(NavigationTarget::from_adt_def(db, def_id));
71 } 69 }
72 } 70 }
73 Some(Pat(pat)) => return Exact(NavigationTarget::from_pat(db, file_id, pat)), 71 Some(Pat((_, pat))) => return Exact(NavigationTarget::from_pat(db, file_id, pat)),
74 Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)), 72 Some(SelfParam(par)) => return Exact(NavigationTarget::from_self_param(file_id, par)),
75 Some(GenericParam(_)) => { 73 Some(GenericParam(_)) => {
76 // FIXME: go to the generic param def 74 // FIXME: go to the generic param def
diff --git a/crates/ra_ide_api/src/hover.rs b/crates/ra_ide_api/src/hover.rs
index 24b161c5c..ba328efa1 100644
--- a/crates/ra_ide_api/src/hover.rs
+++ b/crates/ra_ide_api/src/hover.rs
@@ -14,7 +14,7 @@ use crate::{
14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup, 14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
15 rust_code_markup_with_doc, ShortLabel, 15 rust_code_markup_with_doc, ShortLabel,
16 }, 16 },
17 name_ref_kind::{classify_name_ref, NameRefKind::*}, 17 references::{classify_name_ref, NameKind::*},
18 FilePosition, FileRange, RangeInfo, 18 FilePosition, FileRange, RangeInfo,
19}; 19};
20 20
@@ -99,17 +99,14 @@ pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeIn
99 99
100 let mut range = None; 100 let mut range = None;
101 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) { 101 if let Some(name_ref) = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset) {
102 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
103
104 let mut no_fallback = false; 102 let mut no_fallback = false;
105 103 let name_kind = classify_name_ref(db, position.file_id, &name_ref).map(|d| d.kind);
106 match classify_name_ref(db, &analyzer, &name_ref) { 104 match name_kind {
107 Some(Method(it)) => res.extend(from_def_source(db, it)),
108 Some(Macro(it)) => { 105 Some(Macro(it)) => {
109 let src = it.source(db); 106 let src = it.source(db);
110 res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast)))); 107 res.extend(hover_text(src.ast.doc_comment_text(), Some(macro_label(&src.ast))));
111 } 108 }
112 Some(FieldAccess(it)) => { 109 Some(Field(it)) => {
113 let src = it.source(db); 110 let src = it.source(db);
114 if let hir::FieldSource::Named(it) = src.ast { 111 if let hir::FieldSource::Named(it) = src.ast {
115 res.extend(hover_text(it.doc_comment_text(), it.short_label())); 112 res.extend(hover_text(it.doc_comment_text(), it.short_label()));
diff --git a/crates/ra_ide_api/src/lib.rs b/crates/ra_ide_api/src/lib.rs
index 24f1b91f6..19669a7f0 100644
--- a/crates/ra_ide_api/src/lib.rs
+++ b/crates/ra_ide_api/src/lib.rs
@@ -19,7 +19,6 @@ mod feature_flags;
19mod status; 19mod status;
20mod completion; 20mod completion;
21mod runnables; 21mod runnables;
22mod name_ref_kind;
23mod goto_definition; 22mod goto_definition;
24mod goto_type_definition; 23mod goto_type_definition;
25mod extend_selection; 24mod extend_selection;
@@ -52,7 +51,7 @@ use std::sync::Arc;
52use ra_cfg::CfgOptions; 51use ra_cfg::CfgOptions;
53use ra_db::{ 52use ra_db::{
54 salsa::{self, ParallelDatabase}, 53 salsa::{self, ParallelDatabase},
55 CheckCanceled, SourceDatabase, 54 CheckCanceled, FileLoader, SourceDatabase,
56}; 55};
57use ra_syntax::{SourceFile, TextRange, TextUnit}; 56use ra_syntax::{SourceFile, TextRange, TextUnit};
58use ra_text_edit::TextEdit; 57use ra_text_edit::TextEdit;
@@ -289,10 +288,14 @@ impl AnalysisHost {
289 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> { 288 pub fn per_query_memory_usage(&mut self) -> Vec<(String, ra_prof::Bytes)> {
290 self.db.per_query_memory_usage() 289 self.db.per_query_memory_usage()
291 } 290 }
292 pub fn raw_database(&self) -> &(impl hir::db::HirDatabase + salsa::Database) { 291 pub fn raw_database(
292 &self,
293 ) -> &(impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
293 &self.db 294 &self.db
294 } 295 }
295 pub fn raw_database_mut(&mut self) -> &mut (impl hir::db::HirDatabase + salsa::Database) { 296 pub fn raw_database_mut(
297 &mut self,
298 ) -> &mut (impl hir::db::HirDatabase + salsa::Database + ra_db::SourceDatabaseExt) {
296 &mut self.db 299 &mut self.db
297 } 300 }
298} 301}
@@ -325,7 +328,8 @@ impl Analysis {
325 let file_id = FileId(0); 328 let file_id = FileId(0);
326 // FIXME: cfg options 329 // FIXME: cfg options
327 // Default to enable test for single file. 330 // Default to enable test for single file.
328 let cfg_options = CfgOptions::default().atom("test".into()); 331 let mut cfg_options = CfgOptions::default();
332 cfg_options.insert_atom("test".into());
329 crate_graph.add_crate_root(file_id, Edition::Edition2018, cfg_options); 333 crate_graph.add_crate_root(file_id, Edition::Edition2018, cfg_options);
330 change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text)); 334 change.add_file(source_root, file_id, "main.rs".into(), Arc::new(text));
331 change.set_crate_graph(crate_graph); 335 change.set_crate_graph(crate_graph);
diff --git a/crates/ra_ide_api/src/marks.rs b/crates/ra_ide_api/src/marks.rs
index 3f4ba248b..848ae4dc7 100644
--- a/crates/ra_ide_api/src/marks.rs
+++ b/crates/ra_ide_api/src/marks.rs
@@ -1,6 +1,7 @@
1//! See test_utils/src/marks.rs 1//! See test_utils/src/marks.rs
2 2
3test_utils::marks!( 3test_utils::marks!(
4 inserts_angle_brackets_for_generics
4 inserts_parens_for_function_calls 5 inserts_parens_for_function_calls
5 goto_definition_works_for_macros 6 goto_definition_works_for_macros
6 goto_definition_works_for_methods 7 goto_definition_works_for_methods
diff --git a/crates/ra_ide_api/src/name_ref_kind.rs b/crates/ra_ide_api/src/name_ref_kind.rs
deleted file mode 100644
index 149585971..000000000
--- a/crates/ra_ide_api/src/name_ref_kind.rs
+++ /dev/null
@@ -1,98 +0,0 @@
1//! FIXME: write short doc here
2
3use hir::Either;
4use ra_syntax::{ast, AstNode, AstPtr};
5use test_utils::tested_by;
6
7use crate::db::RootDatabase;
8
9pub enum NameRefKind {
10 Method(hir::Function),
11 Macro(hir::MacroDef),
12 FieldAccess(hir::StructField),
13 AssocItem(hir::AssocItem),
14 Def(hir::ModuleDef),
15 SelfType(hir::Ty),
16 Pat(AstPtr<ast::BindPat>),
17 SelfParam(AstPtr<ast::SelfParam>),
18 GenericParam(u32),
19}
20
21pub(crate) fn classify_name_ref(
22 db: &RootDatabase,
23 analyzer: &hir::SourceAnalyzer,
24 name_ref: &ast::NameRef,
25) -> Option<NameRefKind> {
26 use NameRefKind::*;
27
28 // Check if it is a method
29 if let Some(method_call) = name_ref.syntax().parent().and_then(ast::MethodCallExpr::cast) {
30 tested_by!(goto_definition_works_for_methods);
31 if let Some(func) = analyzer.resolve_method_call(&method_call) {
32 return Some(Method(func));
33 }
34 }
35
36 // It could be a macro call
37 if let Some(macro_call) = name_ref
38 .syntax()
39 .parent()
40 .and_then(|node| node.parent())
41 .and_then(|node| node.parent())
42 .and_then(ast::MacroCall::cast)
43 {
44 tested_by!(goto_definition_works_for_macros);
45 if let Some(mac) = analyzer.resolve_macro_call(db, &macro_call) {
46 return Some(Macro(mac));
47 }
48 }
49
50 // It could also be a field access
51 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::FieldExpr::cast) {
52 tested_by!(goto_definition_works_for_fields);
53 if let Some(field) = analyzer.resolve_field(&field_expr) {
54 return Some(FieldAccess(field));
55 };
56 }
57
58 // It could also be a named field
59 if let Some(field_expr) = name_ref.syntax().parent().and_then(ast::RecordField::cast) {
60 tested_by!(goto_definition_works_for_record_fields);
61
62 let record_lit = field_expr.syntax().ancestors().find_map(ast::RecordLit::cast);
63
64 if let Some(ty) = record_lit.and_then(|lit| analyzer.type_of(db, &lit.into())) {
65 if let Some((hir::Adt::Struct(s), _)) = ty.as_adt() {
66 let hir_path = hir::Path::from_name_ref(name_ref);
67 let hir_name = hir_path.as_ident().unwrap();
68
69 if let Some(field) = s.field(db, hir_name) {
70 return Some(FieldAccess(field));
71 }
72 }
73 }
74 }
75
76 // General case, a path or a local:
77 if let Some(path) = name_ref.syntax().ancestors().find_map(ast::Path::cast) {
78 if let Some(resolved) = analyzer.resolve_path(db, &path) {
79 return match resolved {
80 hir::PathResolution::Def(def) => Some(Def(def)),
81 hir::PathResolution::LocalBinding(Either::A(pat)) => Some(Pat(pat)),
82 hir::PathResolution::LocalBinding(Either::B(par)) => Some(SelfParam(par)),
83 hir::PathResolution::GenericParam(par) => {
84 // FIXME: get generic param def
85 Some(GenericParam(par))
86 }
87 hir::PathResolution::Macro(def) => Some(Macro(def)),
88 hir::PathResolution::SelfType(impl_block) => {
89 let ty = impl_block.target_ty(db);
90 Some(SelfType(ty))
91 }
92 hir::PathResolution::AssocItem(assoc) => Some(AssocItem(assoc)),
93 };
94 }
95 }
96
97 None
98}
diff --git a/crates/ra_ide_api/src/references.rs b/crates/ra_ide_api/src/references.rs
index 84c2eb793..f35d835ac 100644
--- a/crates/ra_ide_api/src/references.rs
+++ b/crates/ra_ide_api/src/references.rs
@@ -1,13 +1,29 @@
1//! FIXME: write short doc here 1//! This module implements a reference search.
2 2//! First, the element at the cursor position must be either an `ast::Name`
3use hir::{Either, ModuleSource}; 3//! or `ast::NameRef`. If it's a `ast::NameRef`, at the classification step we
4use ra_db::SourceDatabase; 4//! try to resolve the direct tree parent of this element, otherwise we
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode}; 5//! already have a definition and just need to get its HIR together with
6use relative_path::{RelativePath, RelativePathBuf}; 6//! some information that is needed for futher steps of searching.
7 7//! After that, we collect files that might contain references and look
8use crate::{ 8//! for text occurrences of the identifier. If there's an `ast::NameRef`
9 db::RootDatabase, FileId, FilePosition, FileRange, FileSystemEdit, NavigationTarget, RangeInfo, 9//! at the index that the match starts at and its tree parent is
10 SourceChange, SourceFileEdit, TextRange, 10//! resolved to the search element definition, we get a reference.
11
12mod classify;
13mod name_definition;
14mod rename;
15mod search_scope;
16
17use once_cell::unsync::Lazy;
18use ra_db::{SourceDatabase, SourceDatabaseExt};
19use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SourceFile, SyntaxNode, TextUnit};
20
21use crate::{db::RootDatabase, FilePosition, FileRange, NavigationTarget, RangeInfo};
22
23pub(crate) use self::{
24 classify::{classify_name, classify_name_ref},
25 name_definition::{NameDefinition, NameKind},
26 rename::rename,
11}; 27};
12 28
13#[derive(Debug, Clone)] 29#[derive(Debug, Clone)]
@@ -52,161 +68,82 @@ pub(crate) fn find_all_refs(
52 position: FilePosition, 68 position: FilePosition,
53) -> Option<RangeInfo<ReferenceSearchResult>> { 69) -> Option<RangeInfo<ReferenceSearchResult>> {
54 let parse = db.parse(position.file_id); 70 let parse = db.parse(position.file_id);
55 let RangeInfo { range, info: (binding, analyzer) } = find_binding(db, &parse.tree(), position)?; 71 let syntax = parse.tree().syntax().clone();
56 let declaration = NavigationTarget::from_bind_pat(position.file_id, &binding); 72 let RangeInfo { range, info: (name, def) } = find_name(db, &syntax, position)?;
57 73
58 let references = analyzer 74 let declaration = match def.kind {
59 .find_all_refs(&binding) 75 NameKind::Macro(mac) => NavigationTarget::from_macro_def(db, mac),
60 .into_iter() 76 NameKind::Field(field) => NavigationTarget::from_field(db, field),
61 .map(move |ref_desc| FileRange { file_id: position.file_id, range: ref_desc.range }) 77 NameKind::AssocItem(assoc) => NavigationTarget::from_assoc_item(db, assoc),
62 .collect::<Vec<_>>(); 78 NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
63 79 NameKind::SelfType(ref ty) => match ty.as_adt() {
64 return Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references })); 80 Some((def_id, _)) => NavigationTarget::from_adt_def(db, def_id),
65 81 None => return None,
66 fn find_binding<'a>( 82 },
67 db: &RootDatabase, 83 NameKind::Pat((_, pat)) => NavigationTarget::from_pat(db, position.file_id, pat),
68 source_file: &SourceFile, 84 NameKind::SelfParam(par) => NavigationTarget::from_self_param(position.file_id, par),
69 position: FilePosition, 85 NameKind::GenericParam(_) => return None,
70 ) -> Option<RangeInfo<(ast::BindPat, hir::SourceAnalyzer)>> { 86 };
71 let syntax = source_file.syntax();
72 if let Some(binding) = find_node_at_offset::<ast::BindPat>(syntax, position.offset) {
73 let range = binding.syntax().text_range();
74 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, binding.syntax(), None);
75 return Some(RangeInfo::new(range, (binding, analyzer)));
76 };
77 let name_ref = find_node_at_offset::<ast::NameRef>(syntax, position.offset)?;
78 let range = name_ref.syntax().text_range();
79 let analyzer = hir::SourceAnalyzer::new(db, position.file_id, name_ref.syntax(), None);
80 let resolved = analyzer.resolve_local_name(&name_ref)?;
81 if let Either::A(ptr) = resolved.ptr() {
82 if let ast::Pat::BindPat(binding) = ptr.to_node(source_file.syntax()) {
83 return Some(RangeInfo::new(range, (binding, analyzer)));
84 }
85 }
86 None
87 }
88}
89 87
90pub(crate) fn rename( 88 let references = process_definition(db, def, name);
91 db: &RootDatabase, 89
92 position: FilePosition, 90 Some(RangeInfo::new(range, ReferenceSearchResult { declaration, references }))
93 new_name: &str,
94) -> Option<RangeInfo<SourceChange>> {
95 let parse = db.parse(position.file_id);
96 if let Some((ast_name, ast_module)) =
97 find_name_and_module_at_offset(parse.tree().syntax(), position)
98 {
99 let range = ast_name.syntax().text_range();
100 rename_mod(db, &ast_name, &ast_module, position, new_name)
101 .map(|info| RangeInfo::new(range, info))
102 } else {
103 rename_reference(db, position, new_name)
104 }
105} 91}
106 92
107fn find_name_and_module_at_offset( 93fn find_name<'a>(
94 db: &RootDatabase,
108 syntax: &SyntaxNode, 95 syntax: &SyntaxNode,
109 position: FilePosition, 96 position: FilePosition,
110) -> Option<(ast::Name, ast::Module)> { 97) -> Option<RangeInfo<(String, NameDefinition)>> {
111 let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?; 98 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) {
112 let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?; 99 let def = classify_name(db, position.file_id, &name)?;
113 Some((ast_name, ast_module)) 100 let range = name.syntax().text_range();
114} 101 return Some(RangeInfo::new(range, (name.text().to_string(), def)));
115
116fn source_edit_from_file_id_range(
117 file_id: FileId,
118 range: TextRange,
119 new_name: &str,
120) -> SourceFileEdit {
121 SourceFileEdit {
122 file_id,
123 edit: {
124 let mut builder = ra_text_edit::TextEditBuilder::default();
125 builder.replace(range, new_name.into());
126 builder.finish()
127 },
128 } 102 }
103 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
104 let def = classify_name_ref(db, position.file_id, &name_ref)?;
105 let range = name_ref.syntax().text_range();
106 Some(RangeInfo::new(range, (name_ref.text().to_string(), def)))
129} 107}
130 108
131fn rename_mod( 109fn process_definition(db: &RootDatabase, def: NameDefinition, name: String) -> Vec<FileRange> {
132 db: &RootDatabase, 110 let pat = name.as_str();
133 ast_name: &ast::Name, 111 let scope = def.search_scope(db);
134 ast_module: &ast::Module, 112 let mut refs = vec![];
135 position: FilePosition, 113
136 new_name: &str, 114 for (file_id, search_range) in scope {
137) -> Option<SourceChange> { 115 let text = db.file_text(file_id);
138 let mut source_file_edits = Vec::new(); 116 let parse = Lazy::new(|| SourceFile::parse(&text));
139 let mut file_system_edits = Vec::new(); 117
140 let module_src = hir::Source { file_id: position.file_id.into(), ast: ast_module.clone() }; 118 for (idx, _) in text.match_indices(pat) {
141 if let Some(module) = hir::Module::from_declaration(db, module_src) { 119 let offset = TextUnit::from_usize(idx);
142 let src = module.definition_source(db); 120
143 let file_id = src.file_id.as_original_file(); 121 if let Some(name_ref) =
144 match src.ast { 122 find_node_at_offset::<ast::NameRef>(parse.tree().syntax(), offset)
145 ModuleSource::SourceFile(..) => { 123 {
146 let mod_path: RelativePathBuf = db.file_relative_path(file_id); 124 let range = name_ref.syntax().text_range();
147 // mod is defined in path/to/dir/mod.rs 125 if let Some(search_range) = search_range {
148 let dst_path = if mod_path.file_stem() == Some("mod") { 126 if !range.is_subrange(&search_range) {
149 mod_path 127 continue;
150 .parent() 128 }
151 .and_then(|p| p.parent()) 129 }
152 .or_else(|| Some(RelativePath::new(""))) 130 if let Some(d) = classify_name_ref(db, file_id, &name_ref) {
153 .map(|p| p.join(new_name).join("mod.rs")) 131 if d == def {
154 } else { 132 refs.push(FileRange { file_id, range });
155 Some(mod_path.with_file_name(new_name).with_extension("rs")) 133 }
156 };
157 if let Some(path) = dst_path {
158 let move_file = FileSystemEdit::MoveFile {
159 src: file_id,
160 dst_source_root: db.file_source_root(position.file_id),
161 dst_path: path,
162 };
163 file_system_edits.push(move_file);
164 } 134 }
165 } 135 }
166 ModuleSource::Module(..) => {}
167 } 136 }
168 } 137 }
169 138 refs
170 let edit = SourceFileEdit {
171 file_id: position.file_id,
172 edit: {
173 let mut builder = ra_text_edit::TextEditBuilder::default();
174 builder.replace(ast_name.syntax().text_range(), new_name.into());
175 builder.finish()
176 },
177 };
178 source_file_edits.push(edit);
179
180 Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
181}
182
183fn rename_reference(
184 db: &RootDatabase,
185 position: FilePosition,
186 new_name: &str,
187) -> Option<RangeInfo<SourceChange>> {
188 let RangeInfo { range, info: refs } = find_all_refs(db, position)?;
189
190 let edit = refs
191 .into_iter()
192 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
193 .collect::<Vec<_>>();
194
195 if edit.is_empty() {
196 return None;
197 }
198
199 Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit)))
200} 139}
201 140
202#[cfg(test)] 141#[cfg(test)]
203mod tests { 142mod tests {
204 use crate::{ 143 use crate::{
205 mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId, 144 mock_analysis::analysis_and_position, mock_analysis::single_file_with_position,
206 ReferenceSearchResult, 145 ReferenceSearchResult,
207 }; 146 };
208 use insta::assert_debug_snapshot;
209 use test_utils::assert_eq_text;
210 147
211 #[test] 148 #[test]
212 fn test_find_all_refs_for_local() { 149 fn test_find_all_refs_for_local() {
@@ -249,211 +186,144 @@ mod tests {
249 assert_eq!(refs.len(), 2); 186 assert_eq!(refs.len(), 2);
250 } 187 }
251 188
252 fn get_all_refs(text: &str) -> ReferenceSearchResult {
253 let (analysis, position) = single_file_with_position(text);
254 analysis.find_all_refs(position).unwrap().unwrap()
255 }
256
257 #[test] 189 #[test]
258 fn test_rename_for_local() { 190 fn test_find_all_refs_field_name() {
259 test_rename( 191 let code = r#"
260 r#" 192 //- /lib.rs
261 fn main() { 193 struct Foo {
262 let mut i = 1; 194 pub spam<|>: u32,
263 let j = 1; 195 }
264 i = i<|> + j;
265
266 {
267 i = 0;
268 }
269
270 i = 5;
271 }"#,
272 "k",
273 r#"
274 fn main() {
275 let mut k = 1;
276 let j = 1;
277 k = k + j;
278 196
279 { 197 fn main(s: Foo) {
280 k = 0; 198 let f = s.spam;
281 } 199 }
200 "#;
282 201
283 k = 5; 202 let refs = get_all_refs(code);
284 }"#, 203 assert_eq!(refs.len(), 2);
285 );
286 } 204 }
287 205
288 #[test] 206 #[test]
289 fn test_rename_for_param_inside() { 207 fn test_find_all_refs_impl_item_name() {
290 test_rename( 208 let code = r#"
291 r#" 209 //- /lib.rs
292 fn foo(i : u32) -> u32 { 210 struct Foo;
293 i<|> 211 impl Foo {
294 }"#, 212 fn f<|>(&self) { }
295 "j", 213 }
296 r#" 214 "#;
297 fn foo(j : u32) -> u32 {
298 j
299 }"#,
300 );
301 }
302 215
303 #[test] 216 let refs = get_all_refs(code);
304 fn test_rename_refs_for_fn_param() { 217 assert_eq!(refs.len(), 1);
305 test_rename(
306 r#"
307 fn foo(i<|> : u32) -> u32 {
308 i
309 }"#,
310 "new_name",
311 r#"
312 fn foo(new_name : u32) -> u32 {
313 new_name
314 }"#,
315 );
316 } 218 }
317 219
318 #[test] 220 #[test]
319 fn test_rename_for_mut_param() { 221 fn test_find_all_refs_enum_var_name() {
320 test_rename( 222 let code = r#"
321 r#" 223 //- /lib.rs
322 fn foo(mut i<|> : u32) -> u32 { 224 enum Foo {
323 i 225 A,
324 }"#, 226 B<|>,
325 "new_name", 227 C,
326 r#" 228 }
327 fn foo(mut new_name : u32) -> u32 { 229 "#;
328 new_name 230
329 }"#, 231 let refs = get_all_refs(code);
330 ); 232 assert_eq!(refs.len(), 1);
331 } 233 }
332 234
333 #[test] 235 #[test]
334 fn test_rename_mod() { 236 fn test_find_all_refs_two_modules() {
335 let (analysis, position) = analysis_and_position( 237 let code = r#"
336 "
337 //- /lib.rs 238 //- /lib.rs
338 mod bar; 239 pub mod foo;
240 pub mod bar;
241
242 fn f() {
243 let i = foo::Foo { n: 5 };
244 }
245
246 //- /foo.rs
247 use crate::bar;
248
249 pub struct Foo {
250 pub n: u32,
251 }
252
253 fn f() {
254 let i = bar::Bar { n: 5 };
255 }
339 256
340 //- /bar.rs 257 //- /bar.rs
258 use crate::foo;
259
260 pub struct Bar {
261 pub n: u32,
262 }
263
264 fn f() {
265 let i = foo::Foo<|> { n: 5 };
266 }
267 "#;
268
269 let (analysis, pos) = analysis_and_position(code);
270 let refs = analysis.find_all_refs(pos).unwrap().unwrap();
271 assert_eq!(refs.len(), 3);
272 }
273
274 // `mod foo;` is not in the results because `foo` is an `ast::Name`.
275 // So, there are two references: the first one is a definition of the `foo` module,
276 // which is the whole `foo.rs`, and the second one is in `use foo::Foo`.
277 #[test]
278 fn test_find_all_refs_decl_module() {
279 let code = r#"
280 //- /lib.rs
341 mod foo<|>; 281 mod foo<|>;
342 282
343 //- /bar/foo.rs 283 use foo::Foo;
344 // emtpy 284
345 ", 285 fn f() {
346 ); 286 let i = Foo { n: 5 };
347 let new_name = "foo2"; 287 }
348 let source_change = analysis.rename(position, new_name).unwrap(); 288
349 assert_debug_snapshot!(&source_change, 289 //- /foo.rs
350@r###" 290 pub struct Foo {
351 Some( 291 pub n: u32,
352 RangeInfo { 292 }
353 range: [4; 7), 293 "#;
354 info: SourceChange { 294
355 label: "rename", 295 let (analysis, pos) = analysis_and_position(code);
356 source_file_edits: [ 296 let refs = analysis.find_all_refs(pos).unwrap().unwrap();
357 SourceFileEdit { 297 assert_eq!(refs.len(), 2);
358 file_id: FileId(
359 2,
360 ),
361 edit: TextEdit {
362 atoms: [
363 AtomTextEdit {
364 delete: [4; 7),
365 insert: "foo2",
366 },
367 ],
368 },
369 },
370 ],
371 file_system_edits: [
372 MoveFile {
373 src: FileId(
374 3,
375 ),
376 dst_source_root: SourceRootId(
377 0,
378 ),
379 dst_path: "bar/foo2.rs",
380 },
381 ],
382 cursor_position: None,
383 },
384 },
385 )
386 "###);
387 } 298 }
388 299
389 #[test] 300 #[test]
390 fn test_rename_mod_in_dir() { 301 fn test_find_all_refs_super_mod_vis() {
391 let (analysis, position) = analysis_and_position( 302 let code = r#"
392 "
393 //- /lib.rs 303 //- /lib.rs
394 mod fo<|>o; 304 mod foo;
395 //- /foo/mod.rs 305
396 // emtpy 306 //- /foo.rs
397 ", 307 mod some;
398 ); 308 use some::Foo;
399 let new_name = "foo2"; 309
400 let source_change = analysis.rename(position, new_name).unwrap(); 310 fn f() {
401 assert_debug_snapshot!(&source_change, 311 let i = Foo { n: 5 };
402 @r###" 312 }
403 Some( 313
404 RangeInfo { 314 //- /foo/some.rs
405 range: [4; 7), 315 pub(super) struct Foo<|> {
406 info: SourceChange { 316 pub n: u32,
407 label: "rename", 317 }
408 source_file_edits: [ 318 "#;
409 SourceFileEdit { 319
410 file_id: FileId( 320 let (analysis, pos) = analysis_and_position(code);
411 1, 321 let refs = analysis.find_all_refs(pos).unwrap().unwrap();
412 ), 322 assert_eq!(refs.len(), 3);
413 edit: TextEdit {
414 atoms: [
415 AtomTextEdit {
416 delete: [4; 7),
417 insert: "foo2",
418 },
419 ],
420 },
421 },
422 ],
423 file_system_edits: [
424 MoveFile {
425 src: FileId(
426 2,
427 ),
428 dst_source_root: SourceRootId(
429 0,
430 ),
431 dst_path: "foo2/mod.rs",
432 },
433 ],
434 cursor_position: None,
435 },
436 },
437 )
438 "###
439 );
440 } 323 }
441 324
442 fn test_rename(text: &str, new_name: &str, expected: &str) { 325 fn get_all_refs(text: &str) -> ReferenceSearchResult {
443 let (analysis, position) = single_file_with_position(text); 326 let (analysis, position) = single_file_with_position(text);
444 let source_change = analysis.rename(position, new_name).unwrap(); 327 analysis.find_all_refs(position).unwrap().unwrap()
445 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
446 let mut file_id: Option<FileId> = None;
447 if let Some(change) = source_change {
448 for edit in change.info.source_file_edits {
449 file_id = Some(edit.file_id);
450 for atom in edit.edit.as_atoms() {
451 text_edit_builder.replace(atom.delete, atom.insert.clone());
452 }
453 }
454 }
455 let result =
456 text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()).unwrap());
457 assert_eq_text!(expected, &*result);
458 } 328 }
459} 329}
diff --git a/crates/ra_ide_api/src/references/classify.rs b/crates/ra_ide_api/src/references/classify.rs
new file mode 100644
index 000000000..c8daff9b1
--- /dev/null
+++ b/crates/ra_ide_api/src/references/classify.rs
@@ -0,0 +1,179 @@
1//! Functions that are used to classify an element from its definition or reference.
2
3use hir::{Either, FromSource, Module, ModuleSource, Path, PathResolution, Source, SourceAnalyzer};
4use ra_db::FileId;
5use ra_syntax::{ast, match_ast, AstNode, AstPtr};
6use test_utils::tested_by;
7
8use super::{
9 name_definition::{from_assoc_item, from_module_def, from_pat, from_struct_field},
10 NameDefinition, NameKind,
11};
12use crate::db::RootDatabase;
13
14pub(crate) fn classify_name(
15 db: &RootDatabase,
16 file_id: FileId,
17 name: &ast::Name,
18) -> Option<NameDefinition> {
19 let parent = name.syntax().parent()?;
20 let file_id = file_id.into();
21
22 // FIXME: add ast::MacroCall(it)
23 match_ast! {
24 match parent {
25 ast::BindPat(it) => {
26 from_pat(db, file_id, AstPtr::new(&it))
27 },
28 ast::RecordFieldDef(it) => {
29 let ast = hir::FieldSource::Named(it);
30 let src = hir::Source { file_id, ast };
31 let field = hir::StructField::from_source(db, src)?;
32 Some(from_struct_field(db, field))
33 },
34 ast::Module(it) => {
35 let def = {
36 if !it.has_semi() {
37 let ast = hir::ModuleSource::Module(it);
38 let src = hir::Source { file_id, ast };
39 hir::Module::from_definition(db, src)
40 } else {
41 let src = hir::Source { file_id, ast: it };
42 hir::Module::from_declaration(db, src)
43 }
44 }?;
45 Some(from_module_def(db, def.into(), None))
46 },
47 ast::StructDef(it) => {
48 let src = hir::Source { file_id, ast: it };
49 let def = hir::Struct::from_source(db, src)?;
50 Some(from_module_def(db, def.into(), None))
51 },
52 ast::EnumDef(it) => {
53 let src = hir::Source { file_id, ast: it };
54 let def = hir::Enum::from_source(db, src)?;
55 Some(from_module_def(db, def.into(), None))
56 },
57 ast::TraitDef(it) => {
58 let src = hir::Source { file_id, ast: it };
59 let def = hir::Trait::from_source(db, src)?;
60 Some(from_module_def(db, def.into(), None))
61 },
62 ast::StaticDef(it) => {
63 let src = hir::Source { file_id, ast: it };
64 let def = hir::Static::from_source(db, src)?;
65 Some(from_module_def(db, def.into(), None))
66 },
67 ast::EnumVariant(it) => {
68 let src = hir::Source { file_id, ast: it };
69 let def = hir::EnumVariant::from_source(db, src)?;
70 Some(from_module_def(db, def.into(), None))
71 },
72 ast::FnDef(it) => {
73 let src = hir::Source { file_id, ast: it };
74 let def = hir::Function::from_source(db, src)?;
75 if parent.parent().and_then(ast::ItemList::cast).is_some() {
76 Some(from_assoc_item(db, def.into()))
77 } else {
78 Some(from_module_def(db, def.into(), None))
79 }
80 },
81 ast::ConstDef(it) => {
82 let src = hir::Source { file_id, ast: it };
83 let def = hir::Const::from_source(db, src)?;
84 if parent.parent().and_then(ast::ItemList::cast).is_some() {
85 Some(from_assoc_item(db, def.into()))
86 } else {
87 Some(from_module_def(db, def.into(), None))
88 }
89 },
90 ast::TypeAliasDef(it) => {
91 let src = hir::Source { file_id, ast: it };
92 let def = hir::TypeAlias::from_source(db, src)?;
93 if parent.parent().and_then(ast::ItemList::cast).is_some() {
94 Some(from_assoc_item(db, def.into()))
95 } else {
96 Some(from_module_def(db, def.into(), None))
97 }
98 },
99 _ => None,
100 }
101 }
102}
103
104pub(crate) fn classify_name_ref(
105 db: &RootDatabase,
106 file_id: FileId,
107 name_ref: &ast::NameRef,
108) -> Option<NameDefinition> {
109 use PathResolution::*;
110
111 let parent = name_ref.syntax().parent()?;
112 let analyzer = SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
113
114 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
115 tested_by!(goto_definition_works_for_methods);
116 if let Some(func) = analyzer.resolve_method_call(&method_call) {
117 return Some(from_assoc_item(db, func.into()));
118 }
119 }
120
121 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
122 tested_by!(goto_definition_works_for_fields);
123 if let Some(field) = analyzer.resolve_field(&field_expr) {
124 return Some(from_struct_field(db, field));
125 }
126 }
127
128 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
129 tested_by!(goto_definition_works_for_record_fields);
130 if let Some(record_lit) = record_field.syntax().ancestors().find_map(ast::RecordLit::cast) {
131 let variant_def = analyzer.resolve_record_literal(&record_lit)?;
132 let hir_path = Path::from_name_ref(name_ref);
133 let hir_name = hir_path.as_ident()?;
134 let field = variant_def.field(db, hir_name)?;
135 return Some(from_struct_field(db, field));
136 }
137 }
138
139 let ast = ModuleSource::from_child_node(db, file_id, &parent);
140 let file_id = file_id.into();
141 // FIXME: find correct container and visibility for each case
142 let container = Module::from_definition(db, Source { file_id, ast })?;
143 let visibility = None;
144
145 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
146 tested_by!(goto_definition_works_for_macros);
147 if let Some(macro_def) = analyzer.resolve_macro_call(db, &macro_call) {
148 let kind = NameKind::Macro(macro_def);
149 return Some(NameDefinition { kind, container, visibility });
150 }
151 }
152
153 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
154 let resolved = analyzer.resolve_path(db, &path)?;
155 match resolved {
156 Def(def) => Some(from_module_def(db, def, Some(container))),
157 AssocItem(item) => Some(from_assoc_item(db, item)),
158 LocalBinding(Either::A(pat)) => from_pat(db, file_id, pat),
159 LocalBinding(Either::B(par)) => {
160 let kind = NameKind::SelfParam(par);
161 Some(NameDefinition { kind, container, visibility })
162 }
163 GenericParam(par) => {
164 // FIXME: get generic param def
165 let kind = NameKind::GenericParam(par);
166 Some(NameDefinition { kind, container, visibility })
167 }
168 Macro(def) => {
169 let kind = NameKind::Macro(def);
170 Some(NameDefinition { kind, container, visibility })
171 }
172 SelfType(impl_block) => {
173 let ty = impl_block.target_ty(db);
174 let kind = NameKind::SelfType(ty);
175 let container = impl_block.module();
176 Some(NameDefinition { kind, container, visibility })
177 }
178 }
179}
diff --git a/crates/ra_ide_api/src/references/name_definition.rs b/crates/ra_ide_api/src/references/name_definition.rs
new file mode 100644
index 000000000..4580bc789
--- /dev/null
+++ b/crates/ra_ide_api/src/references/name_definition.rs
@@ -0,0 +1,113 @@
1//! `NameDefinition` keeps information about the element we want to search references for.
2//! The element is represented by `NameKind`. It's located inside some `container` and
3//! has a `visibility`, which defines a search scope.
4//! Note that the reference search is possible for not all of the classified items.
5
6use hir::{
7 db::AstDatabase, Adt, AssocItem, DefWithBody, FromSource, HasSource, HirFileId, MacroDef,
8 Module, ModuleDef, StructField, Ty, VariantDef,
9};
10use ra_syntax::{ast, ast::VisibilityOwner, match_ast, AstNode, AstPtr};
11
12use crate::db::RootDatabase;
13
14#[derive(Debug, PartialEq, Eq)]
15pub enum NameKind {
16 Macro(MacroDef),
17 Field(StructField),
18 AssocItem(AssocItem),
19 Def(ModuleDef),
20 SelfType(Ty),
21 Pat((DefWithBody, AstPtr<ast::BindPat>)),
22 SelfParam(AstPtr<ast::SelfParam>),
23 GenericParam(u32),
24}
25
26#[derive(PartialEq, Eq)]
27pub(crate) struct NameDefinition {
28 pub visibility: Option<ast::Visibility>,
29 pub container: Module,
30 pub kind: NameKind,
31}
32
33pub(super) fn from_pat(
34 db: &RootDatabase,
35 file_id: HirFileId,
36 pat: AstPtr<ast::BindPat>,
37) -> Option<NameDefinition> {
38 let root = db.parse_or_expand(file_id)?;
39 let def = pat.to_node(&root).syntax().ancestors().find_map(|node| {
40 match_ast! {
41 match node {
42 ast::FnDef(it) => {
43 let src = hir::Source { file_id, ast: it };
44 Some(hir::Function::from_source(db, src)?.into())
45 },
46 ast::ConstDef(it) => {
47 let src = hir::Source { file_id, ast: it };
48 Some(hir::Const::from_source(db, src)?.into())
49 },
50 ast::StaticDef(it) => {
51 let src = hir::Source { file_id, ast: it };
52 Some(hir::Static::from_source(db, src)?.into())
53 },
54 _ => None,
55 }
56 }
57 })?;
58 let kind = NameKind::Pat((def, pat));
59 let container = def.module(db);
60 Some(NameDefinition { kind, container, visibility: None })
61}
62
63pub(super) fn from_assoc_item(db: &RootDatabase, item: AssocItem) -> NameDefinition {
64 let container = item.module(db);
65 let visibility = match item {
66 AssocItem::Function(f) => f.source(db).ast.visibility(),
67 AssocItem::Const(c) => c.source(db).ast.visibility(),
68 AssocItem::TypeAlias(a) => a.source(db).ast.visibility(),
69 };
70 let kind = NameKind::AssocItem(item);
71 NameDefinition { kind, container, visibility }
72}
73
74pub(super) fn from_struct_field(db: &RootDatabase, field: StructField) -> NameDefinition {
75 let kind = NameKind::Field(field);
76 let parent = field.parent_def(db);
77 let container = parent.module(db);
78 let visibility = match parent {
79 VariantDef::Struct(s) => s.source(db).ast.visibility(),
80 VariantDef::EnumVariant(e) => e.source(db).ast.parent_enum().visibility(),
81 };
82 NameDefinition { kind, container, visibility }
83}
84
85pub(super) fn from_module_def(
86 db: &RootDatabase,
87 def: ModuleDef,
88 module: Option<Module>,
89) -> NameDefinition {
90 let kind = NameKind::Def(def);
91 let (container, visibility) = match def {
92 ModuleDef::Module(it) => {
93 let container = it.parent(db).or_else(|| Some(it)).unwrap();
94 let visibility = it.declaration_source(db).and_then(|s| s.ast.visibility());
95 (container, visibility)
96 }
97 ModuleDef::EnumVariant(it) => {
98 let container = it.module(db);
99 let visibility = it.source(db).ast.parent_enum().visibility();
100 (container, visibility)
101 }
102 ModuleDef::Function(it) => (it.module(db), it.source(db).ast.visibility()),
103 ModuleDef::Const(it) => (it.module(db), it.source(db).ast.visibility()),
104 ModuleDef::Static(it) => (it.module(db), it.source(db).ast.visibility()),
105 ModuleDef::Trait(it) => (it.module(db), it.source(db).ast.visibility()),
106 ModuleDef::TypeAlias(it) => (it.module(db), it.source(db).ast.visibility()),
107 ModuleDef::Adt(Adt::Struct(it)) => (it.module(db), it.source(db).ast.visibility()),
108 ModuleDef::Adt(Adt::Union(it)) => (it.module(db), it.source(db).ast.visibility()),
109 ModuleDef::Adt(Adt::Enum(it)) => (it.module(db), it.source(db).ast.visibility()),
110 ModuleDef::BuiltinType(..) => (module.unwrap(), None),
111 };
112 NameDefinition { kind, container, visibility }
113}
diff --git a/crates/ra_ide_api/src/references/rename.rs b/crates/ra_ide_api/src/references/rename.rs
new file mode 100644
index 000000000..0e2e088e0
--- /dev/null
+++ b/crates/ra_ide_api/src/references/rename.rs
@@ -0,0 +1,469 @@
1//! FIXME: write short doc here
2
3use hir::ModuleSource;
4use ra_db::{SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode};
6use relative_path::{RelativePath, RelativePathBuf};
7
8use crate::{
9 db::RootDatabase, FileId, FilePosition, FileSystemEdit, RangeInfo, SourceChange,
10 SourceFileEdit, TextRange,
11};
12
13use super::find_all_refs;
14
15pub(crate) fn rename(
16 db: &RootDatabase,
17 position: FilePosition,
18 new_name: &str,
19) -> Option<RangeInfo<SourceChange>> {
20 let parse = db.parse(position.file_id);
21 if let Some((ast_name, ast_module)) =
22 find_name_and_module_at_offset(parse.tree().syntax(), position)
23 {
24 let range = ast_name.syntax().text_range();
25 rename_mod(db, &ast_name, &ast_module, position, new_name)
26 .map(|info| RangeInfo::new(range, info))
27 } else {
28 rename_reference(db, position, new_name)
29 }
30}
31
32fn find_name_and_module_at_offset(
33 syntax: &SyntaxNode,
34 position: FilePosition,
35) -> Option<(ast::Name, ast::Module)> {
36 let ast_name = find_node_at_offset::<ast::Name>(syntax, position.offset)?;
37 let ast_module = ast::Module::cast(ast_name.syntax().parent()?)?;
38 Some((ast_name, ast_module))
39}
40
41fn source_edit_from_file_id_range(
42 file_id: FileId,
43 range: TextRange,
44 new_name: &str,
45) -> SourceFileEdit {
46 SourceFileEdit {
47 file_id,
48 edit: {
49 let mut builder = ra_text_edit::TextEditBuilder::default();
50 builder.replace(range, new_name.into());
51 builder.finish()
52 },
53 }
54}
55
56fn rename_mod(
57 db: &RootDatabase,
58 ast_name: &ast::Name,
59 ast_module: &ast::Module,
60 position: FilePosition,
61 new_name: &str,
62) -> Option<SourceChange> {
63 let mut source_file_edits = Vec::new();
64 let mut file_system_edits = Vec::new();
65 let module_src = hir::Source { file_id: position.file_id.into(), ast: ast_module.clone() };
66 if let Some(module) = hir::Module::from_declaration(db, module_src) {
67 let src = module.definition_source(db);
68 let file_id = src.file_id.original_file(db);
69 match src.ast {
70 ModuleSource::SourceFile(..) => {
71 let mod_path: RelativePathBuf = db.file_relative_path(file_id);
72 // mod is defined in path/to/dir/mod.rs
73 let dst_path = if mod_path.file_stem() == Some("mod") {
74 mod_path
75 .parent()
76 .and_then(|p| p.parent())
77 .or_else(|| Some(RelativePath::new("")))
78 .map(|p| p.join(new_name).join("mod.rs"))
79 } else {
80 Some(mod_path.with_file_name(new_name).with_extension("rs"))
81 };
82 if let Some(path) = dst_path {
83 let move_file = FileSystemEdit::MoveFile {
84 src: file_id,
85 dst_source_root: db.file_source_root(position.file_id),
86 dst_path: path,
87 };
88 file_system_edits.push(move_file);
89 }
90 }
91 ModuleSource::Module(..) => {}
92 }
93 }
94
95 let edit = SourceFileEdit {
96 file_id: position.file_id,
97 edit: {
98 let mut builder = ra_text_edit::TextEditBuilder::default();
99 builder.replace(ast_name.syntax().text_range(), new_name.into());
100 builder.finish()
101 },
102 };
103 source_file_edits.push(edit);
104
105 Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits))
106}
107
108fn rename_reference(
109 db: &RootDatabase,
110 position: FilePosition,
111 new_name: &str,
112) -> Option<RangeInfo<SourceChange>> {
113 let RangeInfo { range, info: refs } = find_all_refs(db, position)?;
114
115 let edit = refs
116 .into_iter()
117 .map(|range| source_edit_from_file_id_range(range.file_id, range.range, new_name))
118 .collect::<Vec<_>>();
119
120 if edit.is_empty() {
121 return None;
122 }
123
124 Some(RangeInfo::new(range, SourceChange::source_file_edits("rename", edit)))
125}
126
127#[cfg(test)]
128mod tests {
129 use crate::{
130 mock_analysis::analysis_and_position, mock_analysis::single_file_with_position, FileId,
131 ReferenceSearchResult,
132 };
133 use insta::assert_debug_snapshot;
134 use test_utils::assert_eq_text;
135
136 #[test]
137 fn test_find_all_refs_for_local() {
138 let code = r#"
139 fn main() {
140 let mut i = 1;
141 let j = 1;
142 i = i<|> + j;
143
144 {
145 i = 0;
146 }
147
148 i = 5;
149 }"#;
150
151 let refs = get_all_refs(code);
152 assert_eq!(refs.len(), 5);
153 }
154
155 #[test]
156 fn test_find_all_refs_for_param_inside() {
157 let code = r#"
158 fn foo(i : u32) -> u32 {
159 i<|>
160 }"#;
161
162 let refs = get_all_refs(code);
163 assert_eq!(refs.len(), 2);
164 }
165
166 #[test]
167 fn test_find_all_refs_for_fn_param() {
168 let code = r#"
169 fn foo(i<|> : u32) -> u32 {
170 i
171 }"#;
172
173 let refs = get_all_refs(code);
174 assert_eq!(refs.len(), 2);
175 }
176
177 #[test]
178 fn test_find_all_refs_field_name() {
179 let code = r#"
180 //- /lib.rs
181 struct Foo {
182 pub spam<|>: u32,
183 }
184
185 fn main(s: Foo) {
186 let f = s.spam;
187 }
188 "#;
189
190 let refs = get_all_refs(code);
191 assert_eq!(refs.len(), 2);
192 }
193
194 #[test]
195 fn test_find_all_refs_impl_item_name() {
196 let code = r#"
197 //- /lib.rs
198 struct Foo;
199 impl Foo {
200 fn f<|>(&self) { }
201 }
202 "#;
203
204 let refs = get_all_refs(code);
205 assert_eq!(refs.len(), 1);
206 }
207
208 #[test]
209 fn test_find_all_refs_enum_var_name() {
210 let code = r#"
211 //- /lib.rs
212 enum Foo {
213 A,
214 B<|>,
215 C,
216 }
217 "#;
218
219 let refs = get_all_refs(code);
220 assert_eq!(refs.len(), 1);
221 }
222
223 #[test]
224 fn test_find_all_refs_modules() {
225 let code = r#"
226 //- /lib.rs
227 pub mod foo;
228 pub mod bar;
229
230 fn f() {
231 let i = foo::Foo { n: 5 };
232 }
233
234 //- /foo.rs
235 use crate::bar;
236
237 pub struct Foo {
238 pub n: u32,
239 }
240
241 fn f() {
242 let i = bar::Bar { n: 5 };
243 }
244
245 //- /bar.rs
246 use crate::foo;
247
248 pub struct Bar {
249 pub n: u32,
250 }
251
252 fn f() {
253 let i = foo::Foo<|> { n: 5 };
254 }
255 "#;
256
257 let (analysis, pos) = analysis_and_position(code);
258 let refs = analysis.find_all_refs(pos).unwrap().unwrap();
259 assert_eq!(refs.len(), 3);
260 }
261
262 fn get_all_refs(text: &str) -> ReferenceSearchResult {
263 let (analysis, position) = single_file_with_position(text);
264 analysis.find_all_refs(position).unwrap().unwrap()
265 }
266
267 #[test]
268 fn test_rename_for_local() {
269 test_rename(
270 r#"
271 fn main() {
272 let mut i = 1;
273 let j = 1;
274 i = i<|> + j;
275
276 {
277 i = 0;
278 }
279
280 i = 5;
281 }"#,
282 "k",
283 r#"
284 fn main() {
285 let mut k = 1;
286 let j = 1;
287 k = k + j;
288
289 {
290 k = 0;
291 }
292
293 k = 5;
294 }"#,
295 );
296 }
297
298 #[test]
299 fn test_rename_for_param_inside() {
300 test_rename(
301 r#"
302 fn foo(i : u32) -> u32 {
303 i<|>
304 }"#,
305 "j",
306 r#"
307 fn foo(j : u32) -> u32 {
308 j
309 }"#,
310 );
311 }
312
313 #[test]
314 fn test_rename_refs_for_fn_param() {
315 test_rename(
316 r#"
317 fn foo(i<|> : u32) -> u32 {
318 i
319 }"#,
320 "new_name",
321 r#"
322 fn foo(new_name : u32) -> u32 {
323 new_name
324 }"#,
325 );
326 }
327
328 #[test]
329 fn test_rename_for_mut_param() {
330 test_rename(
331 r#"
332 fn foo(mut i<|> : u32) -> u32 {
333 i
334 }"#,
335 "new_name",
336 r#"
337 fn foo(mut new_name : u32) -> u32 {
338 new_name
339 }"#,
340 );
341 }
342
343 #[test]
344 fn test_rename_mod() {
345 let (analysis, position) = analysis_and_position(
346 "
347 //- /lib.rs
348 mod bar;
349
350 //- /bar.rs
351 mod foo<|>;
352
353 //- /bar/foo.rs
354 // emtpy
355 ",
356 );
357 let new_name = "foo2";
358 let source_change = analysis.rename(position, new_name).unwrap();
359 assert_debug_snapshot!(&source_change,
360@r###"
361 Some(
362 RangeInfo {
363 range: [4; 7),
364 info: SourceChange {
365 label: "rename",
366 source_file_edits: [
367 SourceFileEdit {
368 file_id: FileId(
369 2,
370 ),
371 edit: TextEdit {
372 atoms: [
373 AtomTextEdit {
374 delete: [4; 7),
375 insert: "foo2",
376 },
377 ],
378 },
379 },
380 ],
381 file_system_edits: [
382 MoveFile {
383 src: FileId(
384 3,
385 ),
386 dst_source_root: SourceRootId(
387 0,
388 ),
389 dst_path: "bar/foo2.rs",
390 },
391 ],
392 cursor_position: None,
393 },
394 },
395 )
396 "###);
397 }
398
399 #[test]
400 fn test_rename_mod_in_dir() {
401 let (analysis, position) = analysis_and_position(
402 "
403 //- /lib.rs
404 mod fo<|>o;
405 //- /foo/mod.rs
406 // emtpy
407 ",
408 );
409 let new_name = "foo2";
410 let source_change = analysis.rename(position, new_name).unwrap();
411 assert_debug_snapshot!(&source_change,
412 @r###"
413 Some(
414 RangeInfo {
415 range: [4; 7),
416 info: SourceChange {
417 label: "rename",
418 source_file_edits: [
419 SourceFileEdit {
420 file_id: FileId(
421 1,
422 ),
423 edit: TextEdit {
424 atoms: [
425 AtomTextEdit {
426 delete: [4; 7),
427 insert: "foo2",
428 },
429 ],
430 },
431 },
432 ],
433 file_system_edits: [
434 MoveFile {
435 src: FileId(
436 2,
437 ),
438 dst_source_root: SourceRootId(
439 0,
440 ),
441 dst_path: "foo2/mod.rs",
442 },
443 ],
444 cursor_position: None,
445 },
446 },
447 )
448 "###
449 );
450 }
451
452 fn test_rename(text: &str, new_name: &str, expected: &str) {
453 let (analysis, position) = single_file_with_position(text);
454 let source_change = analysis.rename(position, new_name).unwrap();
455 let mut text_edit_builder = ra_text_edit::TextEditBuilder::default();
456 let mut file_id: Option<FileId> = None;
457 if let Some(change) = source_change {
458 for edit in change.info.source_file_edits {
459 file_id = Some(edit.file_id);
460 for atom in edit.edit.as_atoms() {
461 text_edit_builder.replace(atom.delete, atom.insert.clone());
462 }
463 }
464 }
465 let result =
466 text_edit_builder.finish().apply(&*analysis.file_text(file_id.unwrap()).unwrap());
467 assert_eq_text!(expected, &*result);
468 }
469}
diff --git a/crates/ra_ide_api/src/references/search_scope.rs b/crates/ra_ide_api/src/references/search_scope.rs
new file mode 100644
index 000000000..5cb69b8fc
--- /dev/null
+++ b/crates/ra_ide_api/src/references/search_scope.rs
@@ -0,0 +1,92 @@
1//! Generally, `search_scope` returns files that might contain references for the element.
2//! For `pub(crate)` things it's a crate, for `pub` things it's a crate and dependant crates.
3//! In some cases, the location of the references is known to within a `TextRange`,
4//! e.g. for things like local variables.
5
6use hir::{DefWithBody, HasSource, ModuleSource};
7use ra_db::{FileId, SourceDatabase, SourceDatabaseExt};
8use ra_syntax::{AstNode, TextRange};
9use rustc_hash::FxHashSet;
10
11use crate::db::RootDatabase;
12
13use super::{NameDefinition, NameKind};
14
15impl NameDefinition {
16 pub(crate) fn search_scope(&self, db: &RootDatabase) -> FxHashSet<(FileId, Option<TextRange>)> {
17 let module_src = self.container.definition_source(db);
18 let file_id = module_src.file_id.original_file(db);
19
20 if let NameKind::Pat((def, _)) = self.kind {
21 let mut res = FxHashSet::default();
22 let range = match def {
23 DefWithBody::Function(f) => f.source(db).ast.syntax().text_range(),
24 DefWithBody::Const(c) => c.source(db).ast.syntax().text_range(),
25 DefWithBody::Static(s) => s.source(db).ast.syntax().text_range(),
26 };
27 res.insert((file_id, Some(range)));
28 return res;
29 }
30
31 let vis =
32 self.visibility.as_ref().map(|v| v.syntax().to_string()).unwrap_or("".to_string());
33
34 if vis.as_str() == "pub(super)" {
35 if let Some(parent_module) = self.container.parent(db) {
36 let mut files = FxHashSet::default();
37 let parent_src = parent_module.definition_source(db);
38 let file_id = parent_src.file_id.original_file(db);
39
40 match parent_src.ast {
41 ModuleSource::Module(m) => {
42 let range = Some(m.syntax().text_range());
43 files.insert((file_id, range));
44 }
45 ModuleSource::SourceFile(_) => {
46 files.insert((file_id, None));
47 files.extend(parent_module.children(db).map(|m| {
48 let src = m.definition_source(db);
49 (src.file_id.original_file(db), None)
50 }));
51 }
52 }
53 return files;
54 }
55 }
56
57 if vis.as_str() != "" {
58 let source_root_id = db.file_source_root(file_id);
59 let source_root = db.source_root(source_root_id);
60 let mut files =
61 source_root.walk().map(|id| (id.into(), None)).collect::<FxHashSet<_>>();
62
63 // FIXME: add "pub(in path)"
64
65 if vis.as_str() == "pub(crate)" {
66 return files;
67 }
68 if vis.as_str() == "pub" {
69 let krate = self.container.krate(db).unwrap();
70 let crate_graph = db.crate_graph();
71 for crate_id in crate_graph.iter() {
72 let mut crate_deps = crate_graph.dependencies(crate_id);
73 if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) {
74 let root_file = crate_graph.crate_root(crate_id);
75 let source_root_id = db.file_source_root(root_file);
76 let source_root = db.source_root(source_root_id);
77 files.extend(source_root.walk().map(|id| (id.into(), None)));
78 }
79 }
80 return files;
81 }
82 }
83
84 let mut res = FxHashSet::default();
85 let range = match module_src.ast {
86 ModuleSource::Module(m) => Some(m.syntax().text_range()),
87 ModuleSource::SourceFile(_) => None,
88 };
89 res.insert((file_id, range));
90 res
91 }
92}
diff --git a/crates/ra_ide_api/src/snapshots/highlighting.html b/crates/ra_ide_api/src/snapshots/highlighting.html
index ae30ebba3..b39c4d371 100644
--- a/crates/ra_ide_api/src/snapshots/highlighting.html
+++ b/crates/ra_ide_api/src/snapshots/highlighting.html
@@ -19,7 +19,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
19.keyword\.unsafe { color: #DFAF8F; } 19.keyword\.unsafe { color: #DFAF8F; }
20.keyword\.control { color: #F0DFAF; font-weight: bold; } 20.keyword\.control { color: #F0DFAF; font-weight: bold; }
21</style> 21</style>
22<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute text">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span> 22<pre><code><span class="attribute">#</span><span class="attribute">[</span><span class="attribute">derive</span><span class="attribute">(</span><span class="attribute">Clone</span><span class="attribute">,</span><span class="attribute"> </span><span class="attribute">Debug</span><span class="attribute">)</span><span class="attribute">]</span>
23<span class="keyword">struct</span> <span class="type">Foo</span> { 23<span class="keyword">struct</span> <span class="type">Foo</span> {
24 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type">i32</span>, 24 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type">i32</span>,
25 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type">i32</span>, 25 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type">i32</span>,
diff --git a/crates/ra_ide_api/src/symbol_index.rs b/crates/ra_ide_api/src/symbol_index.rs
index 797e9926f..5729eb5b3 100644
--- a/crates/ra_ide_api/src/symbol_index.rs
+++ b/crates/ra_ide_api/src/symbol_index.rs
@@ -29,7 +29,7 @@ use std::{
29use fst::{self, Streamer}; 29use fst::{self, Streamer};
30use ra_db::{ 30use ra_db::{
31 salsa::{self, ParallelDatabase}, 31 salsa::{self, ParallelDatabase},
32 SourceDatabase, SourceRootId, 32 SourceDatabaseExt, SourceRootId,
33}; 33};
34use ra_syntax::{ 34use ra_syntax::{
35 ast::{self, NameOwner}, 35 ast::{self, NameOwner},
diff --git a/crates/ra_ide_api/src/syntax_highlighting.rs b/crates/ra_ide_api/src/syntax_highlighting.rs
index 9ae2dc061..33f3caceb 100644
--- a/crates/ra_ide_api/src/syntax_highlighting.rs
+++ b/crates/ra_ide_api/src/syntax_highlighting.rs
@@ -14,7 +14,7 @@ use ra_syntax::{
14 14
15use crate::{ 15use crate::{
16 db::RootDatabase, 16 db::RootDatabase,
17 name_ref_kind::{classify_name_ref, NameRefKind::*}, 17 references::{classify_name_ref, NameKind::*},
18 FileId, 18 FileId,
19}; 19};
20 20
@@ -97,13 +97,14 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
97 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 97 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string",
98 ATTR => "attribute", 98 ATTR => "attribute",
99 NAME_REF => { 99 NAME_REF => {
100 if node.ancestors().any(|it| it.kind() == ATTR) {
101 continue;
102 }
100 if let Some(name_ref) = node.as_node().cloned().and_then(ast::NameRef::cast) { 103 if let Some(name_ref) = node.as_node().cloned().and_then(ast::NameRef::cast) {
101 // FIXME: try to reuse the SourceAnalyzers 104 let name_kind = classify_name_ref(db, file_id, &name_ref).map(|d| d.kind);
102 let analyzer = hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None); 105 match name_kind {
103 match classify_name_ref(db, &analyzer, &name_ref) {
104 Some(Method(_)) => "function",
105 Some(Macro(_)) => "macro", 106 Some(Macro(_)) => "macro",
106 Some(FieldAccess(_)) => "field", 107 Some(Field(_)) => "field",
107 Some(AssocItem(hir::AssocItem::Function(_))) => "function", 108 Some(AssocItem(hir::AssocItem::Function(_))) => "function",
108 Some(AssocItem(hir::AssocItem::Const(_))) => "constant", 109 Some(AssocItem(hir::AssocItem::Const(_))) => "constant",
109 Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type", 110 Some(AssocItem(hir::AssocItem::TypeAlias(_))) => "type",
@@ -117,7 +118,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
117 Some(Def(hir::ModuleDef::TypeAlias(_))) => "type", 118 Some(Def(hir::ModuleDef::TypeAlias(_))) => "type",
118 Some(Def(hir::ModuleDef::BuiltinType(_))) => "type", 119 Some(Def(hir::ModuleDef::BuiltinType(_))) => "type",
119 Some(SelfType(_)) => "type", 120 Some(SelfType(_)) => "type",
120 Some(Pat(ptr)) => { 121 Some(Pat((_, ptr))) => {
121 let pat = ptr.to_node(&root); 122 let pat = ptr.to_node(&root);
122 if let Some(name) = pat.name() { 123 if let Some(name) = pat.name() {
123 let text = name.text(); 124 let text = name.text();
@@ -127,6 +128,8 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
127 Some(calc_binding_hash(file_id, &text, *shadow_count)) 128 Some(calc_binding_hash(file_id, &text, *shadow_count))
128 } 129 }
129 130
131 let analyzer =
132 hir::SourceAnalyzer::new(db, file_id, name_ref.syntax(), None);
130 if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) { 133 if is_variable_mutable(db, &analyzer, ptr.to_node(&root)) {
131 "variable.mut" 134 "variable.mut"
132 } else { 135 } else {
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index aedc55a95..dd4d3bf9a 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8threadpool = "1.7.1" 8threadpool = "1.7.1"
9relative-path = "0.4.0" 9relative-path = "1.0.0"
10serde_json = "1.0.34" 10serde_json = "1.0.34"
11serde = { version = "1.0.83", features = ["derive"] } 11serde = { version = "1.0.83", features = ["derive"] }
12crossbeam-channel = "0.3.5" 12crossbeam-channel = "0.3.5"
@@ -16,10 +16,8 @@ lsp-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.4.0" 19ra_vfs = "0.5.0"
20ra_syntax = { path = "../ra_syntax" } 20ra_syntax = { path = "../ra_syntax" }
21ra_db = { path = "../ra_db" }
22ra_cfg = { path = "../ra_cfg" }
23ra_text_edit = { path = "../ra_text_edit" } 21ra_text_edit = { path = "../ra_text_edit" }
24ra_ide_api = { path = "../ra_ide_api" } 22ra_ide_api = { path = "../ra_ide_api" }
25lsp-server = "0.2.0" 23lsp-server = "0.2.0"
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index 1318a1738..ee503633d 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -227,22 +227,57 @@ impl ConvWith<(&LineIndex, LineEndings)> for &AtomTextEdit {
227 } 227 }
228} 228}
229 229
230impl ConvWith<&LineIndex> for Fold { 230pub(crate) struct FoldConvCtx<'a> {
231 pub(crate) text: &'a str,
232 pub(crate) line_index: &'a LineIndex,
233 pub(crate) line_folding_only: bool,
234}
235
236impl ConvWith<&FoldConvCtx<'_>> for Fold {
231 type Output = lsp_types::FoldingRange; 237 type Output = lsp_types::FoldingRange;
232 238
233 fn conv_with(self, line_index: &LineIndex) -> lsp_types::FoldingRange { 239 fn conv_with(self, ctx: &FoldConvCtx) -> lsp_types::FoldingRange {
234 let range = self.range.conv_with(&line_index); 240 let kind = match self.kind {
235 lsp_types::FoldingRange { 241 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
236 start_line: range.start.line, 242 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
237 start_character: Some(range.start.character), 243 FoldKind::Mods => None,
238 end_line: range.end.line, 244 FoldKind::Block => None,
239 end_character: Some(range.end.character), 245 };
240 kind: match self.kind { 246
241 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 247 let range = self.range.conv_with(&ctx.line_index);
242 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 248
243 FoldKind::Mods => None, 249 if ctx.line_folding_only {
244 FoldKind::Block => None, 250 // Clients with line_folding_only == true (such as VSCode) will fold the whole end line
245 }, 251 // even if it contains text not in the folding range. To prevent that we exclude
252 // range.end.line from the folding region if there is more text after range.end
253 // on the same line.
254 let has_more_text_on_end_line = ctx.text
255 [TextRange::from_to(self.range.end(), TextUnit::of_str(ctx.text))]
256 .chars()
257 .take_while(|it| *it != '\n')
258 .any(|it| !it.is_whitespace());
259
260 let end_line = if has_more_text_on_end_line {
261 range.end.line.saturating_sub(1)
262 } else {
263 range.end.line
264 };
265
266 lsp_types::FoldingRange {
267 start_line: range.start.line,
268 start_character: None,
269 end_line,
270 end_character: None,
271 kind,
272 }
273 } else {
274 lsp_types::FoldingRange {
275 start_line: range.start.line,
276 start_character: Some(range.start.character),
277 end_line: range.end.line,
278 end_character: Some(range.end.character),
279 kind,
280 }
246 } 281 }
247 } 282 }
248} 283}
@@ -512,3 +547,46 @@ where
512 self.map(|it| it.try_conv_with(ctx)).collect() 547 self.map(|it| it.try_conv_with(ctx)).collect()
513 } 548 }
514} 549}
550
551#[cfg(test)]
552mod tests {
553 use super::*;
554 use test_utils::extract_ranges;
555
556 #[test]
557 fn conv_fold_line_folding_only_fixup() {
558 let text = r#"<fold>mod a;
559mod b;
560mod c;</fold>
561
562fn main() <fold>{
563 if cond <fold>{
564 a::do_a();
565 }</fold> else <fold>{
566 b::do_b();
567 }</fold>
568}</fold>"#;
569
570 let (ranges, text) = extract_ranges(text, "fold");
571 assert_eq!(ranges.len(), 4);
572 let folds = vec![
573 Fold { range: ranges[0], kind: FoldKind::Mods },
574 Fold { range: ranges[1], kind: FoldKind::Block },
575 Fold { range: ranges[2], kind: FoldKind::Block },
576 Fold { range: ranges[3], kind: FoldKind::Block },
577 ];
578
579 let line_index = LineIndex::new(&text);
580 let ctx = FoldConvCtx { text: &text, line_index: &line_index, line_folding_only: true };
581 let converted: Vec<_> = folds.into_iter().map_conv_with(&ctx).collect();
582
583 let expected_lines = [(0, 2), (4, 10), (5, 6), (7, 9)];
584 assert_eq!(converted.len(), expected_lines.len());
585 for (folding_range, (start_line, end_line)) in converted.iter().zip(expected_lines.iter()) {
586 assert_eq!(folding_range.start_line, *start_line);
587 assert_eq!(folding_range.start_character, None);
588 assert_eq!(folding_range.end_line, *end_line);
589 assert_eq!(folding_range.end_character, None);
590 }
591 }
592}
diff --git a/crates/ra_lsp_server/src/lib.rs b/crates/ra_lsp_server/src/lib.rs
index 7a71a90fb..0e5dbbbd5 100644
--- a/crates/ra_lsp_server/src/lib.rs
+++ b/crates/ra_lsp_server/src/lib.rs
@@ -7,7 +7,7 @@ mod conv;
7mod main_loop; 7mod main_loop;
8mod markdown; 8mod markdown;
9pub mod req; 9pub mod req;
10pub mod config; 10mod config;
11mod world; 11mod world;
12 12
13pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>; 13pub type Result<T> = std::result::Result<T, Box<dyn std::error::Error + Send + Sync>>;
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 35c35d32b..0b5d9c44d 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -111,6 +111,21 @@ pub fn main_loop(
111 connection.sender.send(request.into()).unwrap(); 111 connection.sender.send(request.into()).unwrap();
112 } 112 }
113 113
114 let options = {
115 let text_document_caps = client_caps.text_document.as_ref();
116 Options {
117 publish_decorations: config.publish_decorations,
118 supports_location_link: text_document_caps
119 .and_then(|it| it.definition)
120 .and_then(|it| it.link_support)
121 .unwrap_or(false),
122 line_folding_only: text_document_caps
123 .and_then(|it| it.folding_range.as_ref())
124 .and_then(|it| it.line_folding_only)
125 .unwrap_or(false),
126 }
127 };
128
114 let feature_flags = { 129 let feature_flags = {
115 let mut ff = FeatureFlags::default(); 130 let mut ff = FeatureFlags::default();
116 for (flag, value) in config.feature_flags { 131 for (flag, value) in config.feature_flags {
@@ -133,14 +148,7 @@ pub fn main_loop(
133 config.lru_capacity, 148 config.lru_capacity,
134 &globs, 149 &globs,
135 Watch(!config.use_client_watching), 150 Watch(!config.use_client_watching),
136 Options { 151 options,
137 publish_decorations: config.publish_decorations,
138 supports_location_link: client_caps
139 .text_document
140 .and_then(|it| it.definition)
141 .and_then(|it| it.link_support)
142 .unwrap_or(false),
143 },
144 feature_flags, 152 feature_flags,
145 ) 153 )
146 }; 154 };
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index 10e271376..307082865 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -18,7 +18,7 @@ use serde_json::to_value;
18 18
19use crate::{ 19use crate::{
20 cargo_target_spec::{runnable_args, CargoTargetSpec}, 20 cargo_target_spec::{runnable_args, CargoTargetSpec},
21 conv::{to_location, Conv, ConvWith, MapConvWith, TryConvWith, TryConvWithToVec}, 21 conv::{to_location, Conv, ConvWith, FoldConvCtx, MapConvWith, TryConvWith, TryConvWithToVec},
22 req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind}, 22 req::{self, Decoration, InlayHint, InlayHintsParams, InlayKind},
23 world::WorldSnapshot, 23 world::WorldSnapshot,
24 LspError, Result, 24 LspError, Result,
@@ -383,8 +383,14 @@ pub fn handle_folding_range(
383) -> Result<Option<Vec<FoldingRange>>> { 383) -> Result<Option<Vec<FoldingRange>>> {
384 let file_id = params.text_document.try_conv_with(&world)?; 384 let file_id = params.text_document.try_conv_with(&world)?;
385 let folds = world.analysis().folding_ranges(file_id)?; 385 let folds = world.analysis().folding_ranges(file_id)?;
386 let text = world.analysis().file_text(file_id)?;
386 let line_index = world.analysis().file_line_index(file_id)?; 387 let line_index = world.analysis().file_line_index(file_id)?;
387 let res = Some(folds.into_iter().map_conv_with(&*line_index).collect()); 388 let ctx = FoldConvCtx {
389 text: &text,
390 line_index: &line_index,
391 line_folding_only: world.options.line_folding_only,
392 };
393 let res = Some(folds.into_iter().map_conv_with(&ctx).collect());
388 Ok(res) 394 Ok(res)
389} 395}
390 396
@@ -475,7 +481,6 @@ pub fn handle_references(
475 params: req::ReferenceParams, 481 params: req::ReferenceParams,
476) -> Result<Option<Vec<Location>>> { 482) -> Result<Option<Vec<Location>>> {
477 let position = params.text_document_position.try_conv_with(&world)?; 483 let position = params.text_document_position.try_conv_with(&world)?;
478 let line_index = world.analysis().file_line_index(position.file_id)?;
479 484
480 let refs = match world.analysis().find_all_refs(position)? { 485 let refs = match world.analysis().find_all_refs(position)? {
481 None => return Ok(None), 486 None => return Ok(None),
@@ -484,13 +489,19 @@ pub fn handle_references(
484 489
485 let locations = if params.context.include_declaration { 490 let locations = if params.context.include_declaration {
486 refs.into_iter() 491 refs.into_iter()
487 .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) 492 .filter_map(|r| {
493 let line_index = world.analysis().file_line_index(r.file_id).ok()?;
494 to_location(r.file_id, r.range, &world, &line_index).ok()
495 })
488 .collect() 496 .collect()
489 } else { 497 } else {
490 // Only iterate over the references if include_declaration was false 498 // Only iterate over the references if include_declaration was false
491 refs.references() 499 refs.references()
492 .iter() 500 .iter()
493 .filter_map(|r| to_location(r.file_id, r.range, &world, &line_index).ok()) 501 .filter_map(|r| {
502 let line_index = world.analysis().file_line_index(r.file_id).ok()?;
503 to_location(r.file_id, r.range, &world, &line_index).ok()
504 })
494 .collect() 505 .collect()
495 }; 506 };
496 507
@@ -740,6 +751,7 @@ pub fn handle_document_highlight(
740 751
741 Ok(Some( 752 Ok(Some(
742 refs.into_iter() 753 refs.into_iter()
754 .filter(|r| r.file_id == file_id)
743 .map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None }) 755 .map(|r| DocumentHighlight { range: r.range.conv_with(&line_index), kind: None })
744 .collect(), 756 .collect(),
745 )) 757 ))
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 27da751ab..51824e7a3 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -27,6 +27,7 @@ use crate::{
27pub struct Options { 27pub struct Options {
28 pub publish_decorations: bool, 28 pub publish_decorations: bool,
29 pub supports_location_link: bool, 29 pub supports_location_link: bool,
30 pub line_folding_only: bool,
30} 31}
31 32
32/// `WorldState` is the primary mutable state of the language server 33/// `WorldState` is the primary mutable state of the language server
@@ -98,8 +99,12 @@ impl WorldState {
98 } 99 }
99 100
100 // FIXME: Read default cfgs from config 101 // FIXME: Read default cfgs from config
101 let default_cfg_options = 102 let default_cfg_options = {
102 get_rustc_cfg_options().atom("test".into()).atom("debug_assertion".into()); 103 let mut opts = get_rustc_cfg_options();
104 opts.insert_atom("test".into());
105 opts.insert_atom("debug_assertion".into());
106 opts
107 };
103 108
104 // Create crate graph from all the workspaces 109 // Create crate graph from all the workspaces
105 let mut crate_graph = CrateGraph::default(); 110 let mut crate_graph = CrateGraph::default();
diff --git a/crates/ra_mbe/Cargo.toml b/crates/ra_mbe/Cargo.toml
index b058dde91..e8ef2457b 100644
--- a/crates/ra_mbe/Cargo.toml
+++ b/crates/ra_mbe/Cargo.toml
@@ -8,7 +8,6 @@ authors = ["rust-analyzer developers"]
8ra_syntax = { path = "../ra_syntax" } 8ra_syntax = { path = "../ra_syntax" }
9ra_parser = { path = "../ra_parser" } 9ra_parser = { path = "../ra_parser" }
10tt = { path = "../ra_tt", package = "ra_tt" } 10tt = { path = "../ra_tt", package = "ra_tt" }
11itertools = "0.8.0"
12rustc-hash = "1.0.0" 11rustc-hash = "1.0.0"
13smallvec = "0.6.9" 12smallvec = "0.6.9"
14log = "0.4.5" 13log = "0.4.5"
diff --git a/crates/ra_parser/src/grammar/expressions.rs b/crates/ra_parser/src/grammar/expressions.rs
index 74b23e2f7..45f2e3de4 100644
--- a/crates/ra_parser/src/grammar/expressions.rs
+++ b/crates/ra_parser/src/grammar/expressions.rs
@@ -250,6 +250,7 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) {
250 T![!] if p.at(T![!=]) => (5, T![!=]), 250 T![!] if p.at(T![!=]) => (5, T![!=]),
251 T![-] if p.at(T![-=]) => (1, T![-=]), 251 T![-] if p.at(T![-=]) => (1, T![-=]),
252 T![-] => (10, T![-]), 252 T![-] => (10, T![-]),
253 T![as] => (12, T![as]),
253 254
254 _ => NOT_AN_OP 255 _ => NOT_AN_OP
255 } 256 }
@@ -278,6 +279,14 @@ fn expr_bp(p: &mut Parser, r: Restrictions, bp: u8) -> (Option<CompletedMarker>,
278 if op_bp < bp { 279 if op_bp < bp {
279 break; 280 break;
280 } 281 }
282 // test as_precedence
283 // fn foo() {
284 // let _ = &1 as *const i32;
285 // }
286 if p.at(T![as]) {
287 lhs = cast_expr(p, lhs);
288 continue;
289 }
281 let m = lhs.precede(p); 290 let m = lhs.precede(p);
282 p.bump(op); 291 p.bump(op);
283 292
@@ -344,6 +353,7 @@ fn lhs(p: &mut Parser, r: Restrictions) -> Option<(CompletedMarker, BlockLike)>
344 )); 353 ));
345 } 354 }
346 }; 355 };
356 // parse the interior of the unary expression
347 expr_bp(p, r, 255); 357 expr_bp(p, r, 255);
348 Some((m.complete(p, kind), BlockLike::NotBlock)) 358 Some((m.complete(p, kind), BlockLike::NotBlock))
349} 359}
@@ -378,7 +388,6 @@ fn postfix_expr(
378 } 388 }
379 }, 389 },
380 T![?] => try_expr(p, lhs), 390 T![?] => try_expr(p, lhs),
381 T![as] => cast_expr(p, lhs),
382 _ => break, 391 _ => break,
383 }; 392 };
384 allow_calls = true; 393 allow_calls = true;
diff --git a/crates/ra_project_model/Cargo.toml b/crates/ra_project_model/Cargo.toml
index a65100031..b31c95903 100644
--- a/crates/ra_project_model/Cargo.toml
+++ b/crates/ra_project_model/Cargo.toml
@@ -8,7 +8,7 @@ authors = ["rust-analyzer developers"]
8log = "0.4.5" 8log = "0.4.5"
9rustc-hash = "1.0" 9rustc-hash = "1.0"
10 10
11cargo_metadata = "0.8.2" 11cargo_metadata = "0.9.0"
12 12
13ra_arena = { path = "../ra_arena" } 13ra_arena = { path = "../ra_arena" }
14ra_db = { path = "../ra_db" } 14ra_db = { path = "../ra_db" }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 640a5ebd3..8b8663a78 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -134,13 +134,16 @@ impl ProjectWorkspace {
134 json_project::Edition::Edition2015 => Edition::Edition2015, 134 json_project::Edition::Edition2015 => Edition::Edition2015,
135 json_project::Edition::Edition2018 => Edition::Edition2018, 135 json_project::Edition::Edition2018 => Edition::Edition2018,
136 }; 136 };
137 let mut cfg_options = default_cfg_options.clone(); 137 let cfg_options = {
138 for name in &krate.atom_cfgs { 138 let mut opts = default_cfg_options.clone();
139 cfg_options = cfg_options.atom(name.into()); 139 for name in &krate.atom_cfgs {
140 } 140 opts.insert_atom(name.into());
141 for (key, value) in &krate.key_value_cfgs { 141 }
142 cfg_options = cfg_options.key_value(key.into(), value.into()); 142 for (key, value) in &krate.key_value_cfgs {
143 } 143 opts.insert_key_value(key.into(), value.into());
144 }
145 opts
146 };
144 crates.insert( 147 crates.insert(
145 crate_id, 148 crate_id,
146 crate_graph.add_crate_root(file_id, edition, cfg_options), 149 crate_graph.add_crate_root(file_id, edition, cfg_options),
@@ -171,7 +174,12 @@ impl ProjectWorkspace {
171 for krate in sysroot.crates() { 174 for krate in sysroot.crates() {
172 if let Some(file_id) = load(krate.root(&sysroot)) { 175 if let Some(file_id) = load(krate.root(&sysroot)) {
173 // Crates from sysroot have `cfg(test)` disabled 176 // Crates from sysroot have `cfg(test)` disabled
174 let cfg_options = default_cfg_options.clone().remove_atom(&"test".into()); 177 let cfg_options = {
178 let mut opts = default_cfg_options.clone();
179 opts.remove_atom("test");
180 opts
181 };
182
175 let crate_id = 183 let crate_id =
176 crate_graph.add_crate_root(file_id, Edition::Edition2018, cfg_options); 184 crate_graph.add_crate_root(file_id, Edition::Edition2018, cfg_options);
177 sysroot_crates.insert(krate, crate_id); 185 sysroot_crates.insert(krate, crate_id);
@@ -202,9 +210,11 @@ impl ProjectWorkspace {
202 let root = tgt.root(&cargo); 210 let root = tgt.root(&cargo);
203 if let Some(file_id) = load(root) { 211 if let Some(file_id) = load(root) {
204 let edition = pkg.edition(&cargo); 212 let edition = pkg.edition(&cargo);
205 let cfg_options = default_cfg_options 213 let cfg_options = {
206 .clone() 214 let mut opts = default_cfg_options.clone();
207 .features(pkg.features(&cargo).iter().map(Into::into)); 215 opts.insert_features(pkg.features(&cargo).iter().map(Into::into));
216 opts
217 };
208 let crate_id = 218 let crate_id =
209 crate_graph.add_crate_root(file_id, edition, cfg_options); 219 crate_graph.add_crate_root(file_id, edition, cfg_options);
210 names.insert(crate_id, pkg.name(&cargo).to_string()); 220 names.insert(crate_id, pkg.name(&cargo).to_string());
@@ -310,6 +320,14 @@ fn find_cargo_toml(path: &Path) -> Result<PathBuf> {
310pub fn get_rustc_cfg_options() -> CfgOptions { 320pub fn get_rustc_cfg_options() -> CfgOptions {
311 let mut cfg_options = CfgOptions::default(); 321 let mut cfg_options = CfgOptions::default();
312 322
323 // Some nightly-only cfgs, which are required for stdlib
324 {
325 cfg_options.insert_atom("target_thread_local".into());
326 for &target_has_atomic in ["16", "32", "64", "8", "cas", "ptr"].iter() {
327 cfg_options.insert_key_value("target_has_atomic".into(), target_has_atomic.into())
328 }
329 }
330
313 match (|| -> Result<_> { 331 match (|| -> Result<_> {
314 // `cfg(test)` and `cfg(debug_assertion)` are handled outside, so we suppress them here. 332 // `cfg(test)` and `cfg(debug_assertion)` are handled outside, so we suppress them here.
315 let output = Command::new("rustc").args(&["--print", "cfg", "-O"]).output()?; 333 let output = Command::new("rustc").args(&["--print", "cfg", "-O"]).output()?;
@@ -321,11 +339,11 @@ pub fn get_rustc_cfg_options() -> CfgOptions {
321 Ok(rustc_cfgs) => { 339 Ok(rustc_cfgs) => {
322 for line in rustc_cfgs.lines() { 340 for line in rustc_cfgs.lines() {
323 match line.find('=') { 341 match line.find('=') {
324 None => cfg_options = cfg_options.atom(line.into()), 342 None => cfg_options.insert_atom(line.into()),
325 Some(pos) => { 343 Some(pos) => {
326 let key = &line[..pos]; 344 let key = &line[..pos];
327 let value = line[pos + 1..].trim_matches('"'); 345 let value = line[pos + 1..].trim_matches('"');
328 cfg_options = cfg_options.key_value(key.into(), value.into()); 346 cfg_options.insert_key_value(key.into(), value.into());
329 } 347 }
330 } 348 }
331 } 349 }
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 9bc85404a..9c0e856e8 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -12,9 +12,10 @@ itertools = "0.8.0"
12rowan = "0.6.1" 12rowan = "0.6.1"
13rustc_lexer = "0.1.0" 13rustc_lexer = "0.1.0"
14rustc-hash = "1.0.1" 14rustc-hash = "1.0.1"
15arrayvec = "0.4.10" 15arrayvec = "0.5.1"
16once_cell = "1.2.0" 16once_cell = "1.2.0"
17 17
18# This crate transitively depends on `smol_str` via `rowan`.
18# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 19# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
19# to reduce number of compilations 20# to reduce number of compilations
20smol_str = { version = "0.1.12", features = ["serde"] } 21smol_str = { version = "0.1.12", features = ["serde"] }
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 03f3b5fbb..47bdbb81a 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -15,7 +15,7 @@ use crate::{
15 }, 15 },
16 AstToken, Direction, InsertPosition, SmolStr, SyntaxElement, 16 AstToken, Direction, InsertPosition, SmolStr, SyntaxElement,
17 SyntaxKind::{ATTR, COMMENT, WHITESPACE}, 17 SyntaxKind::{ATTR, COMMENT, WHITESPACE},
18 SyntaxNode, T, 18 SyntaxNode, SyntaxToken, T,
19}; 19};
20 20
21impl ast::FnDef { 21impl ast::FnDef {
@@ -231,12 +231,92 @@ pub fn replace_descendants<N: AstNode, D: AstNode>(
231 N::cast(new_syntax).unwrap() 231 N::cast(new_syntax).unwrap()
232} 232}
233 233
234// Note this is copy-pasted from fmt. It seems like fmt should be a separate 234#[derive(Debug, Clone, Copy)]
235// crate, but basic tree building should be this crate. However, tree building 235pub struct IndentLevel(pub u8);
236// might want to call into fmt... 236
237impl From<u8> for IndentLevel {
238 fn from(level: u8) -> IndentLevel {
239 IndentLevel(level)
240 }
241}
242
243impl IndentLevel {
244 pub fn from_node(node: &SyntaxNode) -> IndentLevel {
245 let first_token = match node.first_token() {
246 Some(it) => it,
247 None => return IndentLevel(0),
248 };
249 for ws in prev_tokens(first_token).filter_map(ast::Whitespace::cast) {
250 let text = ws.syntax().text();
251 if let Some(pos) = text.rfind('\n') {
252 let level = text[pos + 1..].chars().count() / 4;
253 return IndentLevel(level as u8);
254 }
255 }
256 IndentLevel(0)
257 }
258
259 pub fn increase_indent<N: AstNode>(self, node: N) -> N {
260 N::cast(self._increase_indent(node.syntax().clone())).unwrap()
261 }
262
263 fn _increase_indent(self, node: SyntaxNode) -> SyntaxNode {
264 let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node
265 .descendants_with_tokens()
266 .filter_map(|el| el.into_token())
267 .filter_map(ast::Whitespace::cast)
268 .filter(|ws| {
269 let text = ws.syntax().text();
270 text.contains('\n')
271 })
272 .map(|ws| {
273 (
274 ws.syntax().clone().into(),
275 make::tokens::whitespace(&format!(
276 "{}{:width$}",
277 ws.syntax().text(),
278 "",
279 width = self.0 as usize * 4
280 ))
281 .into(),
282 )
283 })
284 .collect();
285 algo::replace_descendants(&node, &replacements)
286 }
287
288 pub fn decrease_indent<N: AstNode>(self, node: N) -> N {
289 N::cast(self._decrease_indent(node.syntax().clone())).unwrap()
290 }
291
292 fn _decrease_indent(self, node: SyntaxNode) -> SyntaxNode {
293 let replacements: FxHashMap<SyntaxElement, SyntaxElement> = node
294 .descendants_with_tokens()
295 .filter_map(|el| el.into_token())
296 .filter_map(ast::Whitespace::cast)
297 .filter(|ws| {
298 let text = ws.syntax().text();
299 text.contains('\n')
300 })
301 .map(|ws| {
302 (
303 ws.syntax().clone().into(),
304 make::tokens::whitespace(
305 &ws.syntax()
306 .text()
307 .replace(&format!("\n{:1$}", "", self.0 as usize * 4), "\n"),
308 )
309 .into(),
310 )
311 })
312 .collect();
313 algo::replace_descendants(&node, &replacements)
314 }
315}
316
317// FIXME: replace usages with IndentLevel above
237fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> { 318fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> {
238 let prev_tokens = std::iter::successors(node.first_token(), |token| token.prev_token()); 319 for token in prev_tokens(node.first_token()?) {
239 for token in prev_tokens {
240 if let Some(ws) = ast::Whitespace::cast(token.clone()) { 320 if let Some(ws) = ast::Whitespace::cast(token.clone()) {
241 let ws_text = ws.text(); 321 let ws_text = ws.text();
242 if let Some(pos) = ws_text.rfind('\n') { 322 if let Some(pos) = ws_text.rfind('\n') {
@@ -250,6 +330,10 @@ fn leading_indent(node: &SyntaxNode) -> Option<SmolStr> {
250 None 330 None
251} 331}
252 332
333fn prev_tokens(token: SyntaxToken) -> impl Iterator<Item = SyntaxToken> {
334 iter::successors(Some(token), |token| token.prev_token())
335}
336
253#[must_use] 337#[must_use]
254fn insert_children<N: AstNode>( 338fn insert_children<N: AstNode>(
255 parent: &N, 339 parent: &N,
@@ -269,3 +353,26 @@ fn replace_children<N: AstNode>(
269 let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert); 353 let new_syntax = algo::replace_children(parent.syntax(), to_replace, &mut to_insert);
270 N::cast(new_syntax).unwrap() 354 N::cast(new_syntax).unwrap()
271} 355}
356
357#[test]
358fn test_increase_indent() {
359 let arm_list = {
360 let arm = make::match_arm(iter::once(make::placeholder_pat().into()), make::expr_unit());
361 make::match_arm_list(vec![arm.clone(), arm].into_iter())
362 };
363 assert_eq!(
364 arm_list.syntax().to_string(),
365 "{
366 _ => (),
367 _ => (),
368}"
369 );
370 let indented = IndentLevel(2).increase_indent(arm_list);
371 assert_eq!(
372 indented.syntax().to_string(),
373 "{
374 _ => (),
375 _ => (),
376 }"
377 );
378}
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 287a40bee..00422ea91 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -128,6 +128,14 @@ pub fn where_clause(preds: impl Iterator<Item = ast::WherePred>) -> ast::WhereCl
128 } 128 }
129} 129}
130 130
131pub fn if_expression(condition: &ast::Expr, statement: &str) -> ast::IfExpr {
132 return ast_from_text(&format!(
133 "fn f() {{ if !{} {{\n {}\n}}\n}}",
134 condition.syntax().text(),
135 statement
136 ));
137}
138
131fn ast_from_text<N: AstNode>(text: &str) -> N { 139fn ast_from_text<N: AstNode>(text: &str) -> N {
132 let parse = SourceFile::parse(text); 140 let parse = SourceFile::parse(text);
133 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 141 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap();
@@ -160,6 +168,12 @@ pub mod tokens {
160 .unwrap() 168 .unwrap()
161 } 169 }
162 170
171 pub fn whitespace(text: &str) -> SyntaxToken {
172 assert!(text.trim().is_empty());
173 let sf = SourceFile::parse(text).ok().unwrap();
174 sf.syntax().first_child_or_token().unwrap().into_token().unwrap()
175 }
176
163 pub fn single_newline() -> SyntaxToken { 177 pub fn single_newline() -> SyntaxToken {
164 SOURCE_FILE 178 SOURCE_FILE
165 .tree() 179 .tree()
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 25e6f64ce..0a8fd0612 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -1,5 +1,5 @@
1// Stores definitions which must be used in multiple places 1// Stores definitions which must be used in multiple places
2// See `cargo gen-syntax` (defined in crates/ra_tools/src/main.rs) 2// See `cargo xtask codegen` (defined in xtasks/src/main.rs)
3Grammar( 3Grammar(
4 punct: [ 4 punct: [
5 (";", "SEMI"), 5 (";", "SEMI"),
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs
new file mode 100644
index 000000000..a06dec1fa
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.rs
@@ -0,0 +1,3 @@
1fn foo() {
2 let _ = &1 as *const i32;
3}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt
new file mode 100644
index 000000000..9e3767fb7
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0146_as_precedence.txt
@@ -0,0 +1,43 @@
1SOURCE_FILE@[0; 43)
2 FN_DEF@[0; 42)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 42)
12 BLOCK@[9; 42)
13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n "
15 LET_STMT@[15; 40)
16 LET_KW@[15; 18) "let"
17 WHITESPACE@[18; 19) " "
18 PLACEHOLDER_PAT@[19; 20)
19 UNDERSCORE@[19; 20) "_"
20 WHITESPACE@[20; 21) " "
21 EQ@[21; 22) "="
22 WHITESPACE@[22; 23) " "
23 CAST_EXPR@[23; 39)
24 REF_EXPR@[23; 25)
25 AMP@[23; 24) "&"
26 LITERAL@[24; 25)
27 INT_NUMBER@[24; 25) "1"
28 WHITESPACE@[25; 26) " "
29 AS_KW@[26; 28) "as"
30 WHITESPACE@[28; 29) " "
31 POINTER_TYPE@[29; 39)
32 STAR@[29; 30) "*"
33 CONST_KW@[30; 35) "const"
34 WHITESPACE@[35; 36) " "
35 PATH_TYPE@[36; 39)
36 PATH@[36; 39)
37 PATH_SEGMENT@[36; 39)
38 NAME_REF@[36; 39)
39 IDENT@[36; 39) "i32"
40 SEMI@[39; 40) ";"
41 WHITESPACE@[40; 41) "\n"
42 R_CURLY@[41; 42) "}"
43 WHITESPACE@[42; 43) "\n"
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs
new file mode 100644
index 000000000..100fccc64
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.rs
@@ -0,0 +1,7 @@
1fn foo() {
2 1 + *&2 + 3;
3 *&1 as u64;
4 *x(1);
5 &x[1];
6 -1..2;
7}
diff --git a/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt
new file mode 100644
index 000000000..d30cb63ff
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0058_unary_expr_precedence.txt
@@ -0,0 +1,97 @@
1SOURCE_FILE@[0; 79)
2 FN_DEF@[0; 78)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 6)
6 IDENT@[3; 6) "foo"
7 PARAM_LIST@[6; 8)
8 L_PAREN@[6; 7) "("
9 R_PAREN@[7; 8) ")"
10 WHITESPACE@[8; 9) " "
11 BLOCK_EXPR@[9; 78)
12 BLOCK@[9; 78)
13 L_CURLY@[9; 10) "{"
14 WHITESPACE@[10; 15) "\n "
15 EXPR_STMT@[15; 27)
16 BIN_EXPR@[15; 26)
17 BIN_EXPR@[15; 22)
18 LITERAL@[15; 16)
19 INT_NUMBER@[15; 16) "1"
20 WHITESPACE@[16; 17) " "
21 PLUS@[17; 18) "+"
22 WHITESPACE@[18; 19) " "
23 PREFIX_EXPR@[19; 22)
24 STAR@[19; 20) "*"
25 REF_EXPR@[20; 22)
26 AMP@[20; 21) "&"
27 LITERAL@[21; 22)
28 INT_NUMBER@[21; 22) "2"
29 WHITESPACE@[22; 23) " "
30 PLUS@[23; 24) "+"
31 WHITESPACE@[24; 25) " "
32 LITERAL@[25; 26)
33 INT_NUMBER@[25; 26) "3"
34 SEMI@[26; 27) ";"
35 WHITESPACE@[27; 32) "\n "
36 EXPR_STMT@[32; 43)
37 CAST_EXPR@[32; 42)
38 PREFIX_EXPR@[32; 35)
39 STAR@[32; 33) "*"
40 REF_EXPR@[33; 35)
41 AMP@[33; 34) "&"
42 LITERAL@[34; 35)
43 INT_NUMBER@[34; 35) "1"
44 WHITESPACE@[35; 36) " "
45 AS_KW@[36; 38) "as"
46 WHITESPACE@[38; 39) " "
47 PATH_TYPE@[39; 42)
48 PATH@[39; 42)
49 PATH_SEGMENT@[39; 42)
50 NAME_REF@[39; 42)
51 IDENT@[39; 42) "u64"
52 SEMI@[42; 43) ";"
53 WHITESPACE@[43; 48) "\n "
54 EXPR_STMT@[48; 54)
55 PREFIX_EXPR@[48; 53)
56 STAR@[48; 49) "*"
57 CALL_EXPR@[49; 53)
58 PATH_EXPR@[49; 50)
59 PATH@[49; 50)
60 PATH_SEGMENT@[49; 50)
61 NAME_REF@[49; 50)
62 IDENT@[49; 50) "x"
63 ARG_LIST@[50; 53)
64 L_PAREN@[50; 51) "("
65 LITERAL@[51; 52)
66 INT_NUMBER@[51; 52) "1"
67 R_PAREN@[52; 53) ")"
68 SEMI@[53; 54) ";"
69 WHITESPACE@[54; 59) "\n "
70 EXPR_STMT@[59; 65)
71 REF_EXPR@[59; 64)
72 AMP@[59; 60) "&"
73 INDEX_EXPR@[60; 64)
74 PATH_EXPR@[60; 61)
75 PATH@[60; 61)
76 PATH_SEGMENT@[60; 61)
77 NAME_REF@[60; 61)
78 IDENT@[60; 61) "x"
79 L_BRACK@[61; 62) "["
80 LITERAL@[62; 63)
81 INT_NUMBER@[62; 63) "1"
82 R_BRACK@[63; 64) "]"
83 SEMI@[64; 65) ";"
84 WHITESPACE@[65; 70) "\n "
85 EXPR_STMT@[70; 76)
86 RANGE_EXPR@[70; 75)
87 PREFIX_EXPR@[70; 72)
88 MINUS@[70; 71) "-"
89 LITERAL@[71; 72)
90 INT_NUMBER@[71; 72) "1"
91 DOTDOT@[72; 74) ".."
92 LITERAL@[74; 75)
93 INT_NUMBER@[74; 75) "2"
94 SEMI@[75; 76) ";"
95 WHITESPACE@[76; 77) "\n"
96 R_CURLY@[77; 78) "}"
97 WHITESPACE@[78; 79) "\n"
diff --git a/crates/ra_tt/Cargo.toml b/crates/ra_tt/Cargo.toml
index 3328d312f..3fcc7f085 100644
--- a/crates/ra_tt/Cargo.toml
+++ b/crates/ra_tt/Cargo.toml
@@ -5,4 +5,6 @@ version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6 6
7[dependencies] 7[dependencies]
8smol_str = "0.1.9" 8# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
9# to reduce number of compilations
10smol_str = { version = "0.1.12", features = ["serde"] }
diff --git a/crates/ra_vfs_glob/Cargo.toml b/crates/ra_vfs_glob/Cargo.toml
index d1073b2be..83749675f 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.4.0" 8ra_vfs = "0.5.0"
9globset = "0.4.4" 9globset = "0.4.4"
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 0db3e731e..e5a7ea5f6 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -14,7 +14,7 @@ To learn more about how rust-analyzer works, see
14 14
15We also publish rustdoc docs to pages: 15We also publish rustdoc docs to pages:
16 16
17https://rust-analyzer.github.io/rust-analyzer/ra_ide_api/index.html 17https://rust-analyzer.github.io/rust-analyzer/api-docs/ra_ide_api/
18 18
19Various organizational and process issues are discussed in this document. 19Various organizational and process issues are discussed in this document.
20 20
@@ -65,8 +65,8 @@ integrating with editors. Currently, it contains plugins for VS Code (in
65typescript) and Emacs (in elisp). The `docs` top-level directory contains both 65typescript) and Emacs (in elisp). The `docs` top-level directory contains both
66developer and user documentation. 66developer and user documentation.
67 67
68We have some automation infra in Rust in the `crates/tool` package. It contains 68We have some automation infra in Rust in the `xtask` package. It contains
69stuff like formatting checking, code generation and powers `cargo install-ra`. 69stuff like formatting checking, code generation and powers `cargo xtask install`.
70The latter syntax is achieved with the help of cargo aliases (see `.cargo` 70The latter syntax is achieved with the help of cargo aliases (see `.cargo`
71directory). 71directory).
72 72
@@ -84,7 +84,7 @@ However, launching a VS Code instance with locally build language server is
84possible. There's even a VS Code task for this, so just <kbd>F5</kbd> should 84possible. There's even a VS Code task for this, so just <kbd>F5</kbd> should
85work (thanks, [@andrew-w-ross](https://github.com/andrew-w-ross)!). 85work (thanks, [@andrew-w-ross](https://github.com/andrew-w-ross)!).
86 86
87I often just install development version with `cargo install-ra --server --jemalloc` and 87I often just install development version with `cargo xtask install --server --jemalloc` and
88restart the host VS Code. 88restart the host VS Code.
89 89
90See [./debugging.md](./debugging.md) for how to attach to rust-analyzer with 90See [./debugging.md](./debugging.md) for how to attach to rust-analyzer with
@@ -116,7 +116,7 @@ Due to the requirements of running the tests inside VS Code they are **not run
116on CI**. When making changes to the extension please ensure the tests are not 116on CI**. When making changes to the extension please ensure the tests are not
117broken locally before opening a Pull Request. 117broken locally before opening a Pull Request.
118 118
119To install **only** the VS Code extension, use `cargo install-ra --client-code`. 119To install **only** the VS Code extension, use `cargo xtask install --client-code`.
120 120
121# Logging 121# Logging
122 122
@@ -153,7 +153,7 @@ There's also two VS Code commands which might be of interest:
153 $ cargo install --path crates/ra_lsp_server --force --features jemalloc 153 $ cargo install --path crates/ra_lsp_server --force --features jemalloc
154 ``` 154 ```
155 155
156 There's an alias for this: `cargo install-ra --server --jemalloc`. 156 There's an alias for this: `cargo xtask install --server --jemalloc`.
157 157
158* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection. 158* `Rust Analyzer: Syntax Tree` shows syntax tree of the current file/selection.
159 159
diff --git a/docs/dev/architecture.md b/docs/dev/architecture.md
index 1ffabc6ef..5ec5352e7 100644
--- a/docs/dev/architecture.md
+++ b/docs/dev/architecture.md
@@ -45,21 +45,15 @@ can be quickly updated for small modifications.
45Some of the components of this repository are generated through automatic 45Some of the components of this repository are generated through automatic
46processes. These are outlined below: 46processes. These are outlined below:
47 47
48- `gen-syntax`: The kinds of tokens that are reused in several places, so a generator 48- `cargo xtask codegen`: The kinds of tokens that are reused in several places, so a generator
49 is used. We use tera templates to generate the files listed below, based on 49 is used. We use `quote!` macro to generate the files listed below, based on
50 the grammar described in [grammar.ron]: 50 the grammar described in [grammar.ron]:
51 - [ast/generated.rs][ast generated] in `ra_syntax` based on 51 - [ast/generated.rs][ast generated]
52 [ast/generated.tera.rs][ast source] 52 - [syntax_kind/generated.rs][syntax_kind generated]
53 - [syntax_kind/generated.rs][syntax_kind generated] in `ra_syntax` based on
54 [syntax_kind/generated.tera.rs][syntax_kind source]
55 53
56[tera]: https://tera.netlify.com/
57[grammar.ron]: ../../crates/ra_syntax/src/grammar.ron 54[grammar.ron]: ../../crates/ra_syntax/src/grammar.ron
58[ast generated]: ../../crates/ra_syntax/src/ast/generated.rs 55[ast generated]: ../../crates/ra_syntax/src/ast/generated.rs
59[ast source]: ../../crates/ra_syntax/src/ast/generated.rs.tera
60[syntax_kind generated]: ../../crates/ra_parser/src/syntax_kind/generated.rs 56[syntax_kind generated]: ../../crates/ra_parser/src/syntax_kind/generated.rs
61[syntax_kind source]: ../../crates/ra_parser/src/syntax_kind/generated.rs.tera
62
63 57
64## Code Walk-Through 58## Code Walk-Through
65 59
@@ -77,7 +71,7 @@ Rust syntax tree structure and parser. See
77 This is the thing that turns a flat list of events into a tree (see `EventProcessor`) 71 This is the thing that turns a flat list of events into a tree (see `EventProcessor`)
78- `ast` provides a type safe API on top of the raw `rowan` tree. 72- `ast` provides a type safe API on top of the raw `rowan` tree.
79- `grammar.ron` RON description of the grammar, which is used to 73- `grammar.ron` RON description of the grammar, which is used to
80 generate `syntax_kinds` and `ast` modules, using `cargo gen-syntax` command. 74 generate `syntax_kinds` and `ast` modules, using `cargo xtask codegen` command.
81- `algo`: generic tree algorithms, including `walk` for O(1) stack 75- `algo`: generic tree algorithms, including `walk` for O(1) stack
82 space tree traversal (this is cool). 76 space tree traversal (this is cool).
83 77
diff --git a/docs/user/README.md b/docs/user/README.md
index 036b51d58..f1628d6a4 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -1,6 +1,6 @@
1The main interface to rust-analyzer is the 1The main interface to rust-analyzer is the
2[LSP](https://microsoft.github.io/language-server-protocol/) implementation. To 2[LSP](https://microsoft.github.io/language-server-protocol/) implementation. To
3install lsp server, use `cargo install-ra --server`, which is a shorthand for `cargo 3install lsp server, use `cargo xtask install --server`, which is a shorthand for `cargo
4install --package ra_lsp_server`. The binary is named `ra_lsp_server`, you 4install --package ra_lsp_server`. The binary is named `ra_lsp_server`, you
5should be able to use it with any LSP-compatible editor. We use custom 5should be able to use it with any LSP-compatible editor. We use custom
6extensions to LSP, so special client-side support is required to take full 6extensions to LSP, so special client-side support is required to take full
@@ -33,7 +33,7 @@ following commands:
33``` 33```
34$ git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1 34$ git clone https://github.com/rust-analyzer/rust-analyzer.git --depth 1
35$ cd rust-analyzer 35$ cd rust-analyzer
36$ cargo install-ra 36$ cargo xtask install
37``` 37```
38 38
39The automatic installation is expected to *just work* for common cases, if it 39The automatic installation is expected to *just work* for common cases, if it
@@ -58,9 +58,28 @@ Beyond basic LSP features, there are some extension commands which you can
58invoke via <kbd>Ctrl+Shift+P</kbd> or bind to a shortcut. See [./features.md](./features.md) 58invoke via <kbd>Ctrl+Shift+P</kbd> or bind to a shortcut. See [./features.md](./features.md)
59for details. 59for details.
60 60
61For updates, pull the latest changes from the master branch, run `cargo install-ra` again, and **restart** VS Code instance. 61For updates, pull the latest changes from the master branch, run `cargo xtask install` again, and **restart** VS Code instance.
62See [microsoft/vscode#72308](https://github.com/microsoft/vscode/issues/72308) for why a full restart is needed. 62See [microsoft/vscode#72308](https://github.com/microsoft/vscode/issues/72308) for why a full restart is needed.
63 63
64### VS Code Remote
65
66You can also use `rust-analyzer` with the Visual Studio Code Remote extensions
67(Remote SSH, Remote WSL, Remote Containers). In this case, however, you have to
68manually install the `.vsix` package:
69
701. Build the extension on the remote host using the instructions above (ignore the
71 error if `code` cannot be found in your PATH: VSCode doesn't need to be installed
72 on the remote host).
732. In Visual Studio Code open a connection to the remote host.
743. Open the Extensions View (`View > Extensions`, keyboard shortcut: `Ctrl+Shift+X`).
754. From the top-right kebab menu (`···`) select `Install from VSIX...`
765. Inside the `rust-analyzer` directory find the `editors/code` subdirectory and choose
77 the `ra-lsp-0.0.1.vsix` file.
786. Restart Visual Studio Code and re-establish the connection to the remote host.
79
80In case of errors please make sure that `~/.cargo/bin` is in your `PATH` on the remote
81host.
82
64### Settings 83### Settings
65 84
66* `rust-analyzer.highlightingOn`: enables experimental syntax highlighting 85* `rust-analyzer.highlightingOn`: enables experimental syntax highlighting
@@ -79,6 +98,7 @@ See [microsoft/vscode#72308](https://github.com/microsoft/vscode/issues/72308) f
79* `rust-analyzer.cargo-watch.command`: `cargo-watch` command. (e.g: `clippy` will run as `cargo watch -x clippy` ) 98* `rust-analyzer.cargo-watch.command`: `cargo-watch` command. (e.g: `clippy` will run as `cargo watch -x clippy` )
80* `rust-analyzer.cargo-watch.arguments`: cargo-watch check arguments. 99* `rust-analyzer.cargo-watch.arguments`: cargo-watch check arguments.
81 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` ) 100 (e.g: `--features="shumway,pdf"` will run as `cargo watch -x "check --features="shumway,pdf""` )
101* `rust-analyzer.cargo-watch.ignore`: list of patterns for cargo-watch to ignore (will be passed as `--ignore`)
82* `rust-analyzer.trace.server`: enables internal logging 102* `rust-analyzer.trace.server`: enables internal logging
83* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging 103* `rust-analyzer.trace.cargo-watch`: enables cargo-watch logging
84* `RUST_SRC_PATH`: environment variable that overwrites the sysroot 104* `RUST_SRC_PATH`: environment variable that overwrites the sysroot
diff --git a/docs/user/features.md b/docs/user/features.md
index 757a02838..8b7a8d7fc 100644
--- a/docs/user/features.md
+++ b/docs/user/features.md
@@ -459,17 +459,18 @@ fn foo<T: u32, F: FnOnce(T) -> T>() {}
459fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {} 459fn foo<T, F>() where T: u32, F: FnOnce(T) -> T {}
460``` 460```
461 461
462- Make raw string 462- Make raw string unescaped
463 463
464```rust 464```rust
465// before: 465// before:
466fn f() { 466fn f() {
467 let s = <|>"abcd"; 467 let s = <|>"ab\ncd";
468} 468}
469 469
470// after: 470// after:
471fn f() { 471fn f() {
472 let s = <|>r"abcd"; 472 let s = <|>r#"ab
473cd"#;
473} 474}
474``` 475```
475 476
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index e4b706ce6..e6bcbfa60 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -87,9 +87,9 @@
87 "dev": true 87 "dev": true
88 }, 88 },
89 "acorn": { 89 "acorn": {
90 "version": "7.0.0", 90 "version": "7.1.0",
91 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.0.0.tgz", 91 "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.0.tgz",
92 "integrity": "sha512-PaF/MduxijYYt7unVGRuds1vBC9bFxbNf+VWqhOClfdgy7RlVkQqt610ig1/yxTgsDIfW1cWDel5EBbOy3jdtQ==", 92 "integrity": "sha512-kL5CuoXA/dgxlBbVrflsflzQ3PAas7RYZB52NOm/6839iVYJgKMJ3cQJD+t2i5+qFa8h3MDpEOJiS64E8JLnSQ==",
93 "dev": true 93 "dev": true
94 }, 94 },
95 "agent-base": { 95 "agent-base": {
@@ -1212,22 +1212,14 @@
1212 } 1212 }
1213 }, 1213 },
1214 "rollup": { 1214 "rollup": {
1215 "version": "1.21.4", 1215 "version": "1.23.1",
1216 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.21.4.tgz", 1216 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.23.1.tgz",
1217 "integrity": "sha512-Pl512XVCmVzgcBz5h/3Li4oTaoDcmpuFZ+kdhS/wLreALz//WuDAMfomD3QEYl84NkDu6Z6wV9twlcREb4qQsw==", 1217 "integrity": "sha512-95C1GZQpr/NIA0kMUQmSjuMDQ45oZfPgDBcN0yZwBG7Kee//m7H68vgIyg+SPuyrTZ5PrXfyLK80OzXeKG5dAA==",
1218 "dev": true, 1218 "dev": true,
1219 "requires": { 1219 "requires": {
1220 "@types/estree": "0.0.39", 1220 "@types/estree": "*",
1221 "@types/node": "^12.7.5", 1221 "@types/node": "*",
1222 "acorn": "^7.0.0" 1222 "acorn": "^7.1.0"
1223 },
1224 "dependencies": {
1225 "@types/node": {
1226 "version": "12.7.5",
1227 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.7.5.tgz",
1228 "integrity": "sha512-9fq4jZVhPNW8r+UYKnxF1e2HkDWOWKM5bC2/7c9wPV835I0aOrVbS/Hw/pWPk2uKrNXQqg9Z959Kz+IYDd5p3w==",
1229 "dev": true
1230 }
1231 } 1223 }
1232 }, 1224 },
1233 "rollup-plugin-commonjs": { 1225 "rollup-plugin-commonjs": {
@@ -1315,9 +1307,9 @@
1315 } 1307 }
1316 }, 1308 },
1317 "safe-buffer": { 1309 "safe-buffer": {
1318 "version": "5.1.2", 1310 "version": "5.2.0",
1319 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", 1311 "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz",
1320 "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", 1312 "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==",
1321 "dev": true 1313 "dev": true
1322 }, 1314 },
1323 "seedrandom": { 1315 "seedrandom": {
@@ -1410,12 +1402,12 @@
1410 } 1402 }
1411 }, 1403 },
1412 "string_decoder": { 1404 "string_decoder": {
1413 "version": "1.2.0", 1405 "version": "1.3.0",
1414 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.2.0.tgz", 1406 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
1415 "integrity": "sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==", 1407 "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
1416 "dev": true, 1408 "dev": true,
1417 "requires": { 1409 "requires": {
1418 "safe-buffer": "~5.1.0" 1410 "safe-buffer": "~5.2.0"
1419 } 1411 }
1420 }, 1412 },
1421 "strip-ansi": { 1413 "strip-ansi": {
@@ -1546,9 +1538,9 @@
1546 "dev": true 1538 "dev": true
1547 }, 1539 },
1548 "vsce": { 1540 "vsce": {
1549 "version": "1.66.0", 1541 "version": "1.67.1",
1550 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.66.0.tgz", 1542 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.67.1.tgz",
1551 "integrity": "sha512-Zf4+WD4PhEcOr7jkU08SI9lwFqDhmhk73YOCGQ/tNLaBy+PnnX4eSdqj9LdzDLuI2dsyomJLXzDSNgxuaInxCQ==", 1543 "integrity": "sha512-Y/0fnfaLs2cCfytTGmy4Cp1bf9BaxHO7020YePdUwxjAlPlZ9+lm74M9yEFEWXTIug0L0sMax1WMz0TnozIqxg==",
1552 "dev": true, 1544 "dev": true,
1553 "requires": { 1545 "requires": {
1554 "azure-devops-node-api": "^7.2.0", 1546 "azure-devops-node-api": "^7.2.0",
diff --git a/editors/code/package.json b/editors/code/package.json
index 35211bcc2..4b719aada 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -39,11 +39,11 @@
39 "@types/mocha": "^5.2.7", 39 "@types/mocha": "^5.2.7",
40 "@types/node": "^10.14.13", 40 "@types/node": "^10.14.13",
41 "@types/seedrandom": "^2.4.28", 41 "@types/seedrandom": "^2.4.28",
42 "@types/vscode": "^1.36.0", 42 "@types/vscode": "^1.37.0",
43 "glob": "^7.1.4", 43 "glob": "^7.1.4",
44 "mocha": "^6.2.0", 44 "mocha": "^6.2.0",
45 "prettier": "^1.18.2", 45 "prettier": "^1.18.2",
46 "rollup": "^1.21.4", 46 "rollup": "^1.23.1",
47 "rollup-plugin-commonjs": "^10.1.0", 47 "rollup-plugin-commonjs": "^10.1.0",
48 "rollup-plugin-node-resolve": "^5.2.0", 48 "rollup-plugin-node-resolve": "^5.2.0",
49 "rollup-plugin-typescript": "^1.0.1", 49 "rollup-plugin-typescript": "^1.0.1",
@@ -51,7 +51,7 @@
51 "tslint": "^5.18.0", 51 "tslint": "^5.18.0",
52 "tslint-config-prettier": "^1.18.0", 52 "tslint-config-prettier": "^1.18.0",
53 "typescript": "^3.5.3", 53 "typescript": "^3.5.3",
54 "vsce": "^1.66.0", 54 "vsce": "^1.67.0",
55 "vscode-test": "^1.2.0" 55 "vscode-test": "^1.2.0"
56 }, 56 },
57 "activationEvents": [ 57 "activationEvents": [
@@ -224,6 +224,16 @@
224 "description": "`cargo-watch` command. (e.g: `clippy` will run as `cargo watch -x clippy` )", 224 "description": "`cargo-watch` command. (e.g: `clippy` will run as `cargo watch -x clippy` )",
225 "default": "check" 225 "default": "check"
226 }, 226 },
227 "rust-analyzer.cargo-watch.ignore": {
228 "type": "array",
229 "description": "A list of patterns for cargo-watch to ignore (will be passed as `--ignore`)",
230 "default": []
231 },
232 "rust-analyzer.showWorkspaceLoadedNotification": {
233 "type": "boolean",
234 "description": "Controls whether rust-analyzer displays a notification when a project is loaded.",
235 "default": false
236 },
227 "rust-analyzer.trace.server": { 237 "rust-analyzer.trace.server": {
228 "type": "string", 238 "type": "string",
229 "scope": "window", 239 "scope": "window",
diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts
index 00b24dbce..59d4ba97a 100644
--- a/editors/code/src/commands/cargo_watch.ts
+++ b/editors/code/src/commands/cargo_watch.ts
@@ -93,10 +93,15 @@ export class CargoWatchProvider implements vscode.Disposable {
93 args = '"' + args + '"'; 93 args = '"' + args + '"';
94 } 94 }
95 95
96 const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce(
97 (flags, pattern) => [...flags, '--ignore', pattern],
98 [] as string[]
99 );
100
96 // Start the cargo watch with json message 101 // Start the cargo watch with json message
97 this.cargoProcess = child_process.spawn( 102 this.cargoProcess = child_process.spawn(
98 'cargo', 103 'cargo',
99 ['watch', '-x', args], 104 ['watch', '-x', args, ...ignoreFlags],
100 { 105 {
101 stdio: ['ignore', 'pipe', 'pipe'], 106 stdio: ['ignore', 'pipe', 'pipe'],
102 cwd: vscode.workspace.rootPath, 107 cwd: vscode.workspace.rootPath,
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 2578bc6d1..331936b5e 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -12,6 +12,7 @@ export interface CargoWatchOptions {
12 arguments: string; 12 arguments: string;
13 command: string; 13 command: string;
14 trace: CargoWatchTraceOptions; 14 trace: CargoWatchTraceOptions;
15 ignore: string[];
15} 16}
16 17
17export class Config { 18export class Config {
@@ -30,7 +31,8 @@ export class Config {
30 enableOnStartup: 'ask', 31 enableOnStartup: 'ask',
31 trace: 'off', 32 trace: 'off',
32 arguments: '', 33 arguments: '',
33 command: '' 34 command: '',
35 ignore: []
34 }; 36 };
35 37
36 private prevEnhancedTyping: null | boolean = null; 38 private prevEnhancedTyping: null | boolean = null;
@@ -125,6 +127,13 @@ export class Config {
125 ); 127 );
126 } 128 }
127 129
130 if (config.has('cargo-watch.ignore')) {
131 this.cargoWatchOptions.ignore = config.get<string[]>(
132 'cargo-watch.ignore',
133 []
134 );
135 }
136
128 if (config.has('lruCapacity')) { 137 if (config.has('lruCapacity')) {
129 this.lruCapacity = config.get('lruCapacity') as number; 138 this.lruCapacity = config.get('lruCapacity') as number;
130 } 139 }
diff --git a/website/src/index.html b/website/src/index.html
deleted file mode 100644
index 6fe22227b..000000000
--- a/website/src/index.html
+++ /dev/null
@@ -1,21 +0,0 @@
1<!DOCTYPE HTML>
2<html>
3
4<head>
5 <meta charset="utf-8">
6 <title>Hello World! Site Title</title>
7</head>
8
9<body>
10 <h1>rust-analyzer</h1>
11 <ul>
12 <li>
13 <a href="./api-docs/ra_ide_api/">API Docs</a>
14 </li>
15 <li>
16 <a href="./wasm-demo/">WASM Demo</a>
17 </li>
18 </ul>
19</body>
20
21</html>
diff --git a/website/src/wasm-demo/index.html b/website/src/wasm-demo/index.html
deleted file mode 100644
index e81ccb0f7..000000000
--- a/website/src/wasm-demo/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
1<!DOCTYPE HTML>
2<html>
3
4<head>
5 <meta charset="utf-8">
6 <title>Hello World! Site Title</title>
7</head>
8
9<body>
10 TBD
11</body>
12
13</html>
diff --git a/website/website-gen/Cargo.toml b/website/website-gen/Cargo.toml
deleted file mode 100644
index b471a81fd..000000000
--- a/website/website-gen/Cargo.toml
+++ /dev/null
@@ -1,9 +0,0 @@
1[package]
2name = "website-gen"
3version = "0.0.0"
4authors = ["Aleksey Kladov <[email protected]>"]
5edition = "2018"
6publish = false
7
8[dependencies]
9walkdir = "2.2.0"
diff --git a/website/website-gen/src/main.rs b/website/website-gen/src/main.rs
deleted file mode 100644
index 7d35a37cf..000000000
--- a/website/website-gen/src/main.rs
+++ /dev/null
@@ -1,64 +0,0 @@
1use std::{fs, path::Path, process::Command};
2
3type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
4
5/// This tool builds the github-pages website to the `./target/website` folder
6fn main() {
7 if let Err(err) = try_main() {
8 eprintln!("{}", err);
9 std::process::exit(-1);
10 }
11}
12
13fn try_main() -> Result<()> {
14 check_cwd()?;
15 build_scaffold()?;
16 build_docs()?;
17 println!("Finished\n./target/website/index.html");
18 Ok(())
19}
20
21fn cargo() -> Command {
22 Command::new("cargo")
23}
24
25fn check_cwd() -> Result<()> {
26 let toml = std::fs::read_to_string("./Cargo.toml")?;
27 if !toml.contains("[workspace]") {
28 Err("website-gen should be run from the root of workspace")?;
29 }
30 Ok(())
31}
32
33fn build_docs() -> Result<()> {
34 let status = cargo().args(&["doc", "--all", "--no-deps"]).status()?;
35 if !status.success() {
36 Err("cargo doc failed")?;
37 }
38 sync_dir("./target/doc", "./target/website/api-docs")?;
39 Ok(())
40}
41
42fn build_scaffold() -> Result<()> {
43 sync_dir("./website/src", "./target/website")
44}
45
46fn sync_dir(src: impl AsRef<Path>, dst: impl AsRef<Path>) -> Result<()> {
47 return sync_dir(src.as_ref(), dst.as_ref());
48
49 fn sync_dir(src: &Path, dst: &Path) -> Result<()> {
50 let _ = fs::remove_dir_all(dst);
51 fs::create_dir_all(dst)?;
52 for entry in walkdir::WalkDir::new(src) {
53 let entry = entry?;
54 let src_path = entry.path();
55 let dst_path = dst.join(src_path.strip_prefix(src)?);
56 if src_path.is_dir() {
57 fs::create_dir_all(dst_path)?;
58 } else {
59 fs::copy(src_path, dst_path)?;
60 }
61 }
62 Ok(())
63 }
64}
diff --git a/crates/ra_tools/Cargo.toml b/xtask/Cargo.toml
index 9cceacee3..4fc1c744b 100644
--- a/crates/ra_tools/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -1,6 +1,6 @@
1[package] 1[package]
2edition = "2018" 2edition = "2018"
3name = "ra_tools" 3name = "xtask"
4version = "0.1.0" 4version = "0.1.0"
5authors = ["rust-analyzer developers"] 5authors = ["rust-analyzer developers"]
6publish = false 6publish = false
diff --git a/crates/ra_tools/src/bin/pre-commit.rs b/xtask/src/bin/pre-commit.rs
index 16bbf9cb2..4ee864756 100644
--- a/crates/ra_tools/src/bin/pre-commit.rs
+++ b/xtask/src/bin/pre-commit.rs
@@ -2,7 +2,7 @@
2 2
3use std::process::Command; 3use std::process::Command;
4 4
5use ra_tools::{project_root, run, run_rustfmt, Overwrite, Result}; 5use xtask::{project_root, run, run_rustfmt, Overwrite, Result};
6 6
7fn main() -> Result<()> { 7fn main() -> Result<()> {
8 run_rustfmt(Overwrite)?; 8 run_rustfmt(Overwrite)?;
diff --git a/crates/ra_tools/src/boilerplate_gen.rs b/xtask/src/boilerplate_gen.rs
index 39f1cae66..39f1cae66 100644
--- a/crates/ra_tools/src/boilerplate_gen.rs
+++ b/xtask/src/boilerplate_gen.rs
diff --git a/crates/ra_tools/src/help.rs b/xtask/src/help.rs
index 72dfabacd..4c6bf6b53 100644
--- a/crates/ra_tools/src/help.rs
+++ b/xtask/src/help.rs
@@ -12,15 +12,15 @@ SUBCOMMANDS:
12 format 12 format
13 format-hook 13 format-hook
14 fuzz-tests 14 fuzz-tests
15 gen-syntax 15 codegen
16 gen-tests 16 gen-tests
17 install-ra 17 install
18 lint"; 18 lint";
19 19
20pub const INSTALL_RA_HELP: &str = "ra_tools-install-ra 20pub const INSTALL_HELP: &str = "ra_tools-install
21 21
22USAGE: 22USAGE:
23 ra_tools.exe install-ra [FLAGS] 23 ra_tools.exe install [FLAGS]
24 24
25FLAGS: 25FLAGS:
26 --client-code 26 --client-code
@@ -43,5 +43,5 @@ FLAGS:
43 43
44pub const INSTALL_RA_CONFLICT: &str = 44pub const INSTALL_RA_CONFLICT: &str =
45 "error: The argument `--server` cannot be used with `--client-code` 45 "error: The argument `--server` cannot be used with `--client-code`
46 46
47For more information try --help"; 47For more information try --help";
diff --git a/crates/ra_tools/src/lib.rs b/xtask/src/lib.rs
index aa993a38a..a8685f567 100644
--- a/crates/ra_tools/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -78,7 +78,7 @@ pub fn collect_tests(s: &str) -> Vec<(usize, Test)> {
78} 78}
79 79
80pub fn project_root() -> PathBuf { 80pub fn project_root() -> PathBuf {
81 Path::new(&env!("CARGO_MANIFEST_DIR")).ancestors().nth(2).unwrap().to_path_buf() 81 Path::new(&env!("CARGO_MANIFEST_DIR")).ancestors().nth(1).unwrap().to_path_buf()
82} 82}
83 83
84pub struct Cmd<'a> { 84pub struct Cmd<'a> {
@@ -146,7 +146,7 @@ pub fn install_format_hook() -> Result<()> {
146 "./.git/hooks/pre-commit" 146 "./.git/hooks/pre-commit"
147 }); 147 });
148 if !result_path.exists() { 148 if !result_path.exists() {
149 run("cargo build --package ra_tools --bin pre-commit", ".")?; 149 run("cargo build --package xtask --bin pre-commit", ".")?;
150 if cfg!(windows) { 150 if cfg!(windows) {
151 fs::copy("./target/debug/pre-commit.exe", result_path)?; 151 fs::copy("./target/debug/pre-commit.exe", result_path)?;
152 } else { 152 } else {
diff --git a/crates/ra_tools/src/main.rs b/xtask/src/main.rs
index 161871ccf..c08915aac 100644
--- a/crates/ra_tools/src/main.rs
+++ b/xtask/src/main.rs
@@ -5,11 +5,14 @@ mod help;
5use core::fmt::Write; 5use core::fmt::Write;
6use core::str; 6use core::str;
7use pico_args::Arguments; 7use pico_args::Arguments;
8use ra_tools::{ 8use std::{env, path::PathBuf};
9use xtask::{
9 gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt, 10 gen_tests, generate_boilerplate, install_format_hook, run, run_clippy, run_fuzzer, run_rustfmt,
10 Cmd, Overwrite, Result, 11 run_with_output, Cmd, Overwrite, Result,
11}; 12};
12use std::{env, path::PathBuf}; 13
14// Latest stable, feel free to send a PR if this lags behind.
15const REQUIRED_RUST_VERSION: u32 = 38;
13 16
14struct InstallOpt { 17struct InstallOpt {
15 client: Option<ClientOpt>, 18 client: Option<ClientOpt>,
@@ -35,9 +38,9 @@ fn main() -> Result<()> {
35 let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect()); 38 let mut matches = Arguments::from_vec(std::env::args_os().skip(2).collect());
36 let subcommand = &*subcommand.to_string_lossy(); 39 let subcommand = &*subcommand.to_string_lossy();
37 match subcommand { 40 match subcommand {
38 "install-ra" | "install-code" => { 41 "install" => {
39 if matches.contains(["-h", "--help"]) { 42 if matches.contains(["-h", "--help"]) {
40 eprintln!("{}", help::INSTALL_RA_HELP); 43 eprintln!("{}", help::INSTALL_HELP);
41 return Ok(()); 44 return Ok(());
42 } 45 }
43 let server = matches.contains("--server"); 46 let server = matches.contains("--server");
@@ -61,7 +64,7 @@ fn main() -> Result<()> {
61 } 64 }
62 gen_tests(Overwrite)? 65 gen_tests(Overwrite)?
63 } 66 }
64 "gen-syntax" => { 67 "codegen" => {
65 if matches.contains(["-h", "--help"]) { 68 if matches.contains(["-h", "--help"]) {
66 help::print_no_param_subcommand_help(&subcommand); 69 help::print_no_param_subcommand_help(&subcommand);
67 return Ok(()); 70 return Ok(());
@@ -210,9 +213,44 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
210} 213}
211 214
212fn install_server(opts: ServerOpt) -> Result<()> { 215fn install_server(opts: ServerOpt) -> Result<()> {
213 if opts.jemalloc { 216 let mut old_rust = false;
217 if let Ok(output) = run_with_output("cargo --version", ".") {
218 if let Ok(stdout) = String::from_utf8(output.stdout) {
219 if !check_version(&stdout, REQUIRED_RUST_VERSION) {
220 old_rust = true;
221 }
222 }
223 }
224
225 if old_rust {
226 eprintln!(
227 "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
228 REQUIRED_RUST_VERSION
229 )
230 }
231
232 let res = if opts.jemalloc {
214 run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".") 233 run("cargo install --path crates/ra_lsp_server --locked --force --features jemalloc", ".")
215 } else { 234 } else {
216 run("cargo install --path crates/ra_lsp_server --locked --force", ".") 235 run("cargo install --path crates/ra_lsp_server --locked --force", ".")
236 };
237
238 if res.is_err() && old_rust {
239 eprintln!(
240 "\nWARNING: at least rust 1.{}.0 is required to compile rust-analyzer\n",
241 REQUIRED_RUST_VERSION
242 )
243 }
244
245 res
246}
247
248fn check_version(version_output: &str, min_minor_version: u32) -> bool {
249 // Parse second the number out of
250 // cargo 1.39.0-beta (1c6ec66d5 2019-09-30)
251 let minor: Option<u32> = version_output.split('.').nth(1).and_then(|it| it.parse().ok());
252 match minor {
253 None => true,
254 Some(minor) => minor >= min_minor_version,
217 } 255 }
218} 256}
diff --git a/crates/ra_tools/tests/cli.rs b/xtask/tests/tidy-tests/cli.rs
index 609fd4d8b..5d8ddea83 100644
--- a/crates/ra_tools/tests/cli.rs
+++ b/xtask/tests/tidy-tests/cli.rs
@@ -1,17 +1,17 @@
1use ra_tools::{gen_tests, generate_boilerplate, project_root, run_rustfmt, Verify};
2use walkdir::WalkDir; 1use walkdir::WalkDir;
2use xtask::{gen_tests, generate_boilerplate, project_root, run_rustfmt, Verify};
3 3
4#[test] 4#[test]
5fn generated_grammar_is_fresh() { 5fn generated_grammar_is_fresh() {
6 if let Err(error) = generate_boilerplate(Verify) { 6 if let Err(error) = generate_boilerplate(Verify) {
7 panic!("{}. Please update it by running `cargo gen-syntax`", error); 7 panic!("{}. Please update it by running `cargo xtask codegen`", error);
8 } 8 }
9} 9}
10 10
11#[test] 11#[test]
12fn generated_tests_are_fresh() { 12fn generated_tests_are_fresh() {
13 if let Err(error) = gen_tests(Verify) { 13 if let Err(error) = gen_tests(Verify) {
14 panic!("{}. Please update tests by running `cargo gen-tests`", error); 14 panic!("{}. Please update tests by running `cargo xtask gen-tests`", error);
15 } 15 }
16} 16}
17 17
diff --git a/crates/ra_tools/tests/docs.rs b/xtask/tests/tidy-tests/docs.rs
index ea3330175..fe5852bc6 100644
--- a/crates/ra_tools/tests/docs.rs
+++ b/xtask/tests/tidy-tests/docs.rs
@@ -5,7 +5,7 @@ use std::path::Path;
5 5
6use walkdir::{DirEntry, WalkDir}; 6use walkdir::{DirEntry, WalkDir};
7 7
8use ra_tools::project_root; 8use xtask::project_root;
9 9
10fn is_exclude_dir(p: &Path) -> bool { 10fn is_exclude_dir(p: &Path) -> bool {
11 let exclude_dirs = ["tests", "test_data"]; 11 let exclude_dirs = ["tests", "test_data"];
diff --git a/crates/ra_tools/tests/main.rs b/xtask/tests/tidy-tests/main.rs
index 56d1318d6..56d1318d6 100644
--- a/crates/ra_tools/tests/main.rs
+++ b/xtask/tests/tidy-tests/main.rs