aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/ci.yaml8
-rw-r--r--.vscode/launch.json2
-rw-r--r--Cargo.lock361
-rw-r--r--Cargo.toml1
-rw-r--r--README.md5
-rw-r--r--crates/ra_assists/src/assist_ctx.rs4
-rw-r--r--crates/ra_assists/src/assists/add_custom_impl.rs206
-rw-r--r--crates/ra_assists/src/assists/add_import.rs18
-rw-r--r--crates/ra_assists/src/assists/add_new.rs86
-rw-r--r--crates/ra_assists/src/assists/early_return.rs10
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs19
-rw-r--r--crates/ra_assists/src/lib.rs2
-rw-r--r--crates/ra_assists/src/test_db.rs2
-rw-r--r--crates/ra_batch/src/lib.rs2
-rw-r--r--crates/ra_cli/Cargo.toml6
-rw-r--r--crates/ra_cli/src/analysis_stats.rs15
-rw-r--r--crates/ra_cli/src/main.rs3
-rw-r--r--crates/ra_db/src/input.rs9
-rw-r--r--crates/ra_hir/Cargo.toml2
-rw-r--r--crates/ra_hir/src/code_model.rs409
-rw-r--r--crates/ra_hir/src/code_model/src.rs128
-rw-r--r--crates/ra_hir/src/db.rs4
-rw-r--r--crates/ra_hir/src/debug.rs94
-rw-r--r--crates/ra_hir/src/from_id.rs14
-rw-r--r--crates/ra_hir/src/from_source.rs362
-rw-r--r--crates/ra_hir/src/has_source.rs127
-rw-r--r--crates/ra_hir/src/lib.rs26
-rw-r--r--crates/ra_hir/src/source_binder.rs213
-rw-r--r--crates/ra_hir/src/ty.rs4
-rw-r--r--crates/ra_hir_def/Cargo.toml3
-rw-r--r--crates/ra_hir_def/src/adt.rs30
-rw-r--r--crates/ra_hir_def/src/attr.rs31
-rw-r--r--crates/ra_hir_def/src/body.rs108
-rw-r--r--crates/ra_hir_def/src/body/lower.rs108
-rw-r--r--crates/ra_hir_def/src/body/scope.rs10
-rw-r--r--crates/ra_hir_def/src/builtin_type.rs42
-rw-r--r--crates/ra_hir_def/src/child_by_source.rs177
-rw-r--r--crates/ra_hir_def/src/data.rs154
-rw-r--r--crates/ra_hir_def/src/db.rs29
-rw-r--r--crates/ra_hir_def/src/diagnostics.rs6
-rw-r--r--crates/ra_hir_def/src/docs.rs22
-rw-r--r--crates/ra_hir_def/src/dyn_map.rs108
-rw-r--r--crates/ra_hir_def/src/expr.rs15
-rw-r--r--crates/ra_hir_def/src/generics.rs174
-rw-r--r--crates/ra_hir_def/src/item_scope.rs172
-rw-r--r--crates/ra_hir_def/src/keys.rs56
-rw-r--r--crates/ra_hir_def/src/lang_item.rs2
-rw-r--r--crates/ra_hir_def/src/lib.rs346
-rw-r--r--crates/ra_hir_def/src/marks.rs1
-rw-r--r--crates/ra_hir_def/src/nameres.rs224
-rw-r--r--crates/ra_hir_def/src/nameres/collector.rs637
-rw-r--r--crates/ra_hir_def/src/nameres/path_resolution.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/raw.rs105
-rw-r--r--crates/ra_hir_def/src/nameres/tests.rs53
-rw-r--r--crates/ra_hir_def/src/nameres/tests/globs.rs21
-rw-r--r--crates/ra_hir_def/src/nameres/tests/incremental.rs4
-rw-r--r--crates/ra_hir_def/src/nameres/tests/macros.rs24
-rw-r--r--crates/ra_hir_def/src/nameres/tests/mod_resolution.rs4
-rw-r--r--crates/ra_hir_def/src/path.rs527
-rw-r--r--crates/ra_hir_def/src/path/lower.rs178
-rw-r--r--crates/ra_hir_def/src/path/lower/lower_use.rs118
-rw-r--r--crates/ra_hir_def/src/per_ns.rs2
-rw-r--r--crates/ra_hir_def/src/resolver.rs296
-rw-r--r--crates/ra_hir_def/src/src.rs36
-rw-r--r--crates/ra_hir_def/src/trace.rs8
-rw-r--r--crates/ra_hir_expand/Cargo.toml1
-rw-r--r--crates/ra_hir_expand/src/ast_id_map.rs12
-rw-r--r--crates/ra_hir_expand/src/builtin_derive.rs321
-rw-r--r--crates/ra_hir_expand/src/builtin_macro.rs244
-rw-r--r--crates/ra_hir_expand/src/db.rs66
-rw-r--r--crates/ra_hir_expand/src/diagnostics.rs4
-rw-r--r--crates/ra_hir_expand/src/either.rs54
-rw-r--r--crates/ra_hir_expand/src/hygiene.rs9
-rw-r--r--crates/ra_hir_expand/src/lib.rs217
-rw-r--r--crates/ra_hir_expand/src/name.rs158
-rw-r--r--crates/ra_hir_expand/src/quote.rs40
-rw-r--r--crates/ra_hir_ty/Cargo.toml7
-rw-r--r--crates/ra_hir_ty/src/autoderef.rs18
-rw-r--r--crates/ra_hir_ty/src/db.rs47
-rw-r--r--crates/ra_hir_ty/src/diagnostics.rs14
-rw-r--r--crates/ra_hir_ty/src/display.rs12
-rw-r--r--crates/ra_hir_ty/src/expr.rs8
-rw-r--r--crates/ra_hir_ty/src/infer.rs361
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs27
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs247
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs86
-rw-r--r--crates/ra_hir_ty/src/infer/unify.rs276
-rw-r--r--crates/ra_hir_ty/src/lib.rs96
-rw-r--r--crates/ra_hir_ty/src/lower.rs174
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs238
-rw-r--r--crates/ra_hir_ty/src/test_db.rs4
-rw-r--r--crates/ra_hir_ty/src/tests.rs4767
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs159
-rw-r--r--crates/ra_hir_ty/src/tests/macros.rs390
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs1005
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs238
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs333
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs1663
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs1598
-rw-r--r--crates/ra_hir_ty/src/traits.rs25
-rw-r--r--crates/ra_hir_ty/src/traits/builtin.rs178
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs667
-rw-r--r--crates/ra_hir_ty/src/utils.rs90
-rw-r--r--crates/ra_ide/Cargo.toml1
-rw-r--r--crates/ra_ide/src/call_info.rs43
-rw-r--r--crates/ra_ide/src/change.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_dot.rs35
-rw-r--r--crates/ra_ide/src/completion/complete_path.rs17
-rw-r--r--crates/ra_ide/src/completion/complete_postfix.rs2
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs37
-rw-r--r--crates/ra_ide/src/completion/completion_context.rs32
-rw-r--r--crates/ra_ide/src/db.rs14
-rw-r--r--crates/ra_ide/src/diagnostics.rs2
-rw-r--r--crates/ra_ide/src/display.rs2
-rw-r--r--crates/ra_ide/src/display/navigation_target.rs84
-rw-r--r--crates/ra_ide/src/expand.rs89
-rw-r--r--crates/ra_ide/src/expand_macro.rs21
-rw-r--r--crates/ra_ide/src/extend_selection.rs80
-rw-r--r--crates/ra_ide/src/goto_definition.rs393
-rw-r--r--crates/ra_ide/src/goto_type_definition.rs43
-rw-r--r--crates/ra_ide/src/hover.rs126
-rw-r--r--crates/ra_ide/src/impls.rs10
-rw-r--r--crates/ra_ide/src/inlay_hints.rs68
-rw-r--r--crates/ra_ide/src/lib.rs5
-rw-r--r--crates/ra_ide/src/marks.rs9
-rw-r--r--crates/ra_ide/src/parent_module.rs11
-rw-r--r--crates/ra_ide/src/references.rs10
-rw-r--r--crates/ra_ide/src/references/classify.rs29
-rw-r--r--crates/ra_ide/src/references/name_definition.rs6
-rw-r--r--crates/ra_ide/src/references/rename.rs54
-rw-r--r--crates/ra_ide/src/references/search_scope.rs16
-rw-r--r--crates/ra_ide/src/runnables.rs6
-rw-r--r--crates/ra_ide/src/snapshots/highlighting.html31
-rw-r--r--crates/ra_ide/src/snapshots/rainbow_highlighting.html6
-rw-r--r--crates/ra_ide/src/syntax_highlighting.rs129
-rw-r--r--crates/ra_lsp_server/Cargo.toml4
-rw-r--r--crates/ra_lsp_server/build.rs15
-rw-r--r--crates/ra_lsp_server/src/caps.rs20
-rw-r--r--crates/ra_lsp_server/src/config.rs5
-rw-r--r--crates/ra_lsp_server/src/conv.rs7
-rw-r--r--crates/ra_lsp_server/src/main.rs25
-rw-r--r--crates/ra_lsp_server/src/main_loop.rs19
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs18
-rw-r--r--crates/ra_lsp_server/src/main_loop/pending_requests.rs2
-rw-r--r--crates/ra_lsp_server/src/main_loop/subscriptions.rs2
-rw-r--r--crates/ra_lsp_server/src/markdown.rs2
-rw-r--r--crates/ra_lsp_server/src/req.rs29
-rw-r--r--crates/ra_lsp_server/src/world.rs75
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/main.rs118
-rw-r--r--crates/ra_lsp_server/tests/heavy_tests/support.rs3
-rw-r--r--crates/ra_mbe/src/lib.rs25
-rw-r--r--crates/ra_mbe/src/mbe_expander/matcher.rs8
-rw-r--r--crates/ra_mbe/src/mbe_expander/transcriber.rs17
-rw-r--r--crates/ra_mbe/src/subtree_source.rs14
-rw-r--r--crates/ra_mbe/src/syntax_bridge.rs242
-rw-r--r--crates/ra_mbe/src/tests.rs684
-rw-r--r--crates/ra_parser/src/grammar.rs2
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs10
-rw-r--r--crates/ra_parser/src/grammar/items.rs30
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs2
-rw-r--r--crates/ra_parser/src/grammar/type_params.rs11
-rw-r--r--crates/ra_parser/src/lib.rs1
-rw-r--r--crates/ra_parser/src/parser.rs2
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs9
-rw-r--r--crates/ra_parser/src/token_set.rs8
-rw-r--r--crates/ra_prof/src/lib.rs8
-rw-r--r--crates/ra_project_model/src/cargo_workspace.rs37
-rw-r--r--crates/ra_project_model/src/lib.rs14
-rw-r--r--crates/ra_syntax/Cargo.toml9
-rw-r--r--crates/ra_syntax/src/algo.rs12
-rw-r--r--crates/ra_syntax/src/ast/edit.rs4
-rw-r--r--crates/ra_syntax/src/ast/generated.rs34
-rw-r--r--crates/ra_syntax/src/ast/make.rs3
-rw-r--r--crates/ra_syntax/src/grammar.ron16
-rw-r--r--crates/ra_syntax/src/ptr.rs14
-rw-r--r--crates/ra_syntax/src/syntax_node.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt328
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs5
-rw-r--r--crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt83
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt9
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt23
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs2
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt45
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt21
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs (renamed from crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs)0
-rw-r--r--crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt176
-rw-r--r--crates/ra_tt/src/lib.rs43
-rw-r--r--crates/test_utils/src/lib.rs15
-rw-r--r--docs/dev/README.md5
-rw-r--r--docs/user/README.md63
-rw-r--r--docs/user/assists.md18
-rw-r--r--editors/code/package-lock.json731
-rw-r--r--editors/code/package.json141
-rw-r--r--editors/code/rollup.config.js3
-rw-r--r--editors/code/src/commands/analyzer_status.ts14
-rw-r--r--editors/code/src/commands/apply_source_change.ts8
-rw-r--r--editors/code/src/commands/cargo_watch.ts49
-rw-r--r--editors/code/src/commands/expand_macro.ts10
-rw-r--r--editors/code/src/commands/index.ts2
-rw-r--r--editors/code/src/commands/inlay_hints.ts34
-rw-r--r--editors/code/src/commands/join_lines.ts6
-rw-r--r--editors/code/src/commands/matching_brace.ts6
-rw-r--r--editors/code/src/commands/on_enter.ts8
-rw-r--r--editors/code/src/commands/parent_module.ts6
-rw-r--r--editors/code/src/commands/runnables.ts52
-rw-r--r--editors/code/src/commands/syntaxTree.ts10
-rw-r--r--editors/code/src/commands/watch_status.ts2
-rw-r--r--editors/code/src/config.ts113
-rw-r--r--editors/code/src/events/change_active_text_editor.ts6
-rw-r--r--editors/code/src/events/change_text_document.ts2
-rw-r--r--editors/code/src/extension.ts73
-rw-r--r--editors/code/src/highlighting.ts30
-rw-r--r--editors/code/src/notifications/publish_decorations.ts11
-rw-r--r--editors/code/src/server.ts39
-rw-r--r--editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json261
-rw-r--r--editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts29
-rw-r--r--editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts26
-rw-r--r--editors/code/src/test/utils/diagnotics/rust.test.ts92
-rw-r--r--editors/code/src/test/utils/diagnotics/vscode.test.ts24
-rw-r--r--editors/code/src/test/utils/index.ts2
-rw-r--r--editors/code/src/utils/diagnostics/SuggestedFix.ts4
-rw-r--r--editors/code/src/utils/diagnostics/SuggestedFixCollection.ts6
-rw-r--r--editors/code/src/utils/diagnostics/rust.ts58
-rw-r--r--editors/code/src/utils/diagnostics/vscode.ts2
-rw-r--r--editors/code/src/utils/processes.ts4
-rw-r--r--editors/code/tsconfig.json9
-rw-r--r--editors/code/tslint.json12
-rw-r--r--xtask/src/lib.rs5
-rw-r--r--xtask/src/main.rs5
233 files changed, 14882 insertions, 10763 deletions
diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml
index 5bc41533c..cb397ae14 100644
--- a/.github/workflows/ci.yaml
+++ b/.github/workflows/ci.yaml
@@ -14,6 +14,7 @@ jobs:
14 env: 14 env:
15 RUSTFLAGS: -D warnings 15 RUSTFLAGS: -D warnings
16 CARGO_INCREMENTAL: 0 16 CARGO_INCREMENTAL: 0
17 RUN_SLOW_TESTS: 1
17 steps: 18 steps:
18 19
19 - name: Checkout repository 20 - name: Checkout repository
@@ -46,9 +47,10 @@ jobs:
46 47
47 - name: Prepare build directory for cache 48 - name: Prepare build directory for cache
48 run: | 49 run: |
49 find ./target/debug -maxdepth 1 -type f -delete && \ 50 find ./target/debug -maxdepth 1 -type f -delete \
50 rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*heavy_test*,*gen_lsp*,*thread_worker*} && \ 51 && rm -fr ./target/debug/{deps,.fingerprint}/{*ra_*,*heavy_test*,*gen_lsp*,*thread_worker*} \
51 rm -f ./target/.rustc_info.json 52 && rm -f ./target/.rustc_info.json \
53 && rm ./target/.slow_tests_cookie
52 54
53 type-script: 55 type-script:
54 name: TypeScript 56 name: TypeScript
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 9aafc8bd3..0cf3984a9 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -16,7 +16,7 @@
16 "env": { 16 "env": {
17 "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server" 17 "__RA_LSP_SERVER_DEBUG": "${workspaceFolder}/target/debug/ra_lsp_server"
18 }, 18 },
19 "outFiles": ["${workspaceFolder}/editors/code/out/**/*.js"], 19 "outFiles": ["${workspaceFolder}/editors/code/bundle/**/*.js"],
20 "preLaunchTask": "Build All" 20 "preLaunchTask": "Build All"
21 }, 21 },
22 { 22 {
diff --git a/Cargo.lock b/Cargo.lock
index 2557b5e59..e724c1a76 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -10,7 +10,12 @@ dependencies = [
10 10
11[[package]] 11[[package]]
12name = "anyhow" 12name = "anyhow"
13version = "1.0.24" 13version = "1.0.25"
14source = "registry+https://github.com/rust-lang/crates.io-index"
15
16[[package]]
17name = "anymap"
18version = "0.12.1"
14source = "registry+https://github.com/rust-lang/crates.io-index" 19source = "registry+https://github.com/rust-lang/crates.io-index"
15 20
16[[package]] 21[[package]]
@@ -23,7 +28,7 @@ name = "atty"
23version = "0.2.13" 28version = "0.2.13"
24source = "registry+https://github.com/rust-lang/crates.io-index" 29source = "registry+https://github.com/rust-lang/crates.io-index"
25dependencies = [ 30dependencies = [
26 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 31 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
27 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 32 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
28] 33]
29 34
@@ -39,7 +44,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
39dependencies = [ 44dependencies = [
40 "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)", 45 "backtrace-sys 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
41 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 46 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
42 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 47 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
43 "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)", 48 "rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
44] 49]
45 50
@@ -48,8 +53,8 @@ name = "backtrace-sys"
48version = "0.1.32" 53version = "0.1.32"
49source = "registry+https://github.com/rust-lang/crates.io-index" 54source = "registry+https://github.com/rust-lang/crates.io-index"
50dependencies = [ 55dependencies = [
51 "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", 56 "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
52 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 57 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
53] 58]
54 59
55[[package]] 60[[package]]
@@ -101,18 +106,18 @@ dependencies = [
101 106
102[[package]] 107[[package]]
103name = "cargo_metadata" 108name = "cargo_metadata"
104version = "0.9.0" 109version = "0.9.1"
105source = "registry+https://github.com/rust-lang/crates.io-index" 110source = "registry+https://github.com/rust-lang/crates.io-index"
106dependencies = [ 111dependencies = [
107 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 112 "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
108 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 113 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
109 "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 114 "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
110 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 115 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
111] 116]
112 117
113[[package]] 118[[package]]
114name = "cc" 119name = "cc"
115version = "1.0.47" 120version = "1.0.48"
116source = "registry+https://github.com/rust-lang/crates.io-index" 121source = "registry+https://github.com/rust-lang/crates.io-index"
117 122
118[[package]] 123[[package]]
@@ -123,38 +128,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
123[[package]] 128[[package]]
124name = "chalk-derive" 129name = "chalk-derive"
125version = "0.1.0" 130version = "0.1.0"
126source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 131source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
127dependencies = [ 132dependencies = [
128 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 133 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
129 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 134 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
130 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 135 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
131] 136]
132 137
133[[package]] 138[[package]]
134name = "chalk-engine" 139name = "chalk-engine"
135version = "0.9.0" 140version = "0.9.0"
136source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 141source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
137dependencies = [ 142dependencies = [
138 "chalk-macros 0.1.1 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 143 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
139 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 144 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
140 "stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
141] 145]
142 146
143[[package]] 147[[package]]
144name = "chalk-ir" 148name = "chalk-ir"
145version = "0.1.0" 149version = "0.1.0"
146source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 150source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
147dependencies = [ 151dependencies = [
148 "chalk-derive 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 152 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
149 "chalk-engine 0.9.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 153 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
150 "chalk-macros 0.1.1 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 154 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
151 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 155 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
152] 156]
153 157
154[[package]] 158[[package]]
155name = "chalk-macros" 159name = "chalk-macros"
156version = "0.1.1" 160version = "0.1.1"
157source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 161source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
158dependencies = [ 162dependencies = [
159 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 163 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
160] 164]
@@ -162,24 +166,24 @@ dependencies = [
162[[package]] 166[[package]]
163name = "chalk-rust-ir" 167name = "chalk-rust-ir"
164version = "0.1.0" 168version = "0.1.0"
165source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 169source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
166dependencies = [ 170dependencies = [
167 "chalk-derive 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 171 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
168 "chalk-engine 0.9.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 172 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
169 "chalk-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 173 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
170 "chalk-macros 0.1.1 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 174 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
171] 175]
172 176
173[[package]] 177[[package]]
174name = "chalk-solve" 178name = "chalk-solve"
175version = "0.1.0" 179version = "0.1.0"
176source = "git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30#095cd38a4f16337913bba487f2055b9ca0179f30" 180source = "git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5#ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5"
177dependencies = [ 181dependencies = [
178 "chalk-derive 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 182 "chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
179 "chalk-engine 0.9.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 183 "chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
180 "chalk-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 184 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
181 "chalk-macros 0.1.1 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 185 "chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
182 "chalk-rust-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 186 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
183 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 187 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
184 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", 188 "itertools 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
185 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)", 189 "petgraph 0.4.13 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -187,23 +191,13 @@ dependencies = [
187] 191]
188 192
189[[package]] 193[[package]]
190name = "chrono"
191version = "0.4.10"
192source = "registry+https://github.com/rust-lang/crates.io-index"
193dependencies = [
194 "num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)",
195 "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
196 "time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
197]
198
199[[package]]
200name = "clicolors-control" 194name = "clicolors-control"
201version = "1.0.1" 195version = "1.0.1"
202source = "registry+https://github.com/rust-lang/crates.io-index" 196source = "registry+https://github.com/rust-lang/crates.io-index"
203dependencies = [ 197dependencies = [
204 "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", 198 "atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)",
205 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 199 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
206 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 200 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
207 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 201 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
208] 202]
209 203
@@ -223,7 +217,7 @@ dependencies = [
223 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 217 "clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
224 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", 218 "encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
225 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 219 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
226 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 220 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
227 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 221 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
228 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 222 "termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
229 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 223 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -324,12 +318,21 @@ version = "0.3.6"
324source = "registry+https://github.com/rust-lang/crates.io-index" 318source = "registry+https://github.com/rust-lang/crates.io-index"
325 319
326[[package]] 320[[package]]
321name = "env_logger"
322version = "0.7.1"
323source = "registry+https://github.com/rust-lang/crates.io-index"
324dependencies = [
325 "humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
326 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
327]
328
329[[package]]
327name = "filetime" 330name = "filetime"
328version = "0.2.8" 331version = "0.2.8"
329source = "registry+https://github.com/rust-lang/crates.io-index" 332source = "registry+https://github.com/rust-lang/crates.io-index"
330dependencies = [ 333dependencies = [
331 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 334 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
332 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 335 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
333 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 336 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
334 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 337 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
335] 338]
@@ -340,18 +343,6 @@ version = "0.1.9"
340source = "registry+https://github.com/rust-lang/crates.io-index" 343source = "registry+https://github.com/rust-lang/crates.io-index"
341 344
342[[package]] 345[[package]]
343name = "flexi_logger"
344version = "0.14.5"
345source = "registry+https://github.com/rust-lang/crates.io-index"
346dependencies = [
347 "chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)",
348 "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
349 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
350 "regex 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
351 "yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
352]
353
354[[package]]
355name = "fnv" 346name = "fnv"
356version = "1.0.6" 347version = "1.0.6"
357source = "registry+https://github.com/rust-lang/crates.io-index" 348source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -380,7 +371,7 @@ name = "fsevent-sys"
380version = "2.0.1" 371version = "2.0.1"
381source = "registry+https://github.com/rust-lang/crates.io-index" 372source = "registry+https://github.com/rust-lang/crates.io-index"
382dependencies = [ 373dependencies = [
383 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 374 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
384] 375]
385 376
386[[package]] 377[[package]]
@@ -416,16 +407,11 @@ version = "0.1.13"
416source = "registry+https://github.com/rust-lang/crates.io-index" 407source = "registry+https://github.com/rust-lang/crates.io-index"
417dependencies = [ 408dependencies = [
418 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 409 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
419 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 410 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
420 "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 411 "wasi 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
421] 412]
422 413
423[[package]] 414[[package]]
424name = "glob"
425version = "0.3.0"
426source = "registry+https://github.com/rust-lang/crates.io-index"
427
428[[package]]
429name = "globset" 415name = "globset"
430version = "0.4.4" 416version = "0.4.4"
431source = "registry+https://github.com/rust-lang/crates.io-index" 417source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -447,10 +433,18 @@ dependencies = [
447 433
448[[package]] 434[[package]]
449name = "hermit-abi" 435name = "hermit-abi"
450version = "0.1.3" 436version = "0.1.5"
451source = "registry+https://github.com/rust-lang/crates.io-index" 437source = "registry+https://github.com/rust-lang/crates.io-index"
452dependencies = [ 438dependencies = [
453 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 439 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
440]
441
442[[package]]
443name = "humantime"
444version = "1.3.0"
445source = "registry+https://github.com/rust-lang/crates.io-index"
446dependencies = [
447 "quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
454] 448]
455 449
456[[package]] 450[[package]]
@@ -478,7 +472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
478dependencies = [ 472dependencies = [
479 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 473 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
480 "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 474 "inotify-sys 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)",
481 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 475 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
482] 476]
483 477
484[[package]] 478[[package]]
@@ -486,7 +480,7 @@ name = "inotify-sys"
486version = "0.1.3" 480version = "0.1.3"
487source = "registry+https://github.com/rust-lang/crates.io-index" 481source = "registry+https://github.com/rust-lang/crates.io-index"
488dependencies = [ 482dependencies = [
489 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 483 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
490] 484]
491 485
492[[package]] 486[[package]]
@@ -497,8 +491,8 @@ dependencies = [
497 "console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", 491 "console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
498 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 492 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
499 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 493 "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
500 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 494 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
501 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 495 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
502 "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)", 496 "serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)",
503 "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", 497 "uuid 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
504] 498]
@@ -508,7 +502,7 @@ name = "iovec"
508version = "0.1.4" 502version = "0.1.4"
509source = "registry+https://github.com/rust-lang/crates.io-index" 503source = "registry+https://github.com/rust-lang/crates.io-index"
510dependencies = [ 504dependencies = [
511 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 505 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
512] 506]
513 507
514[[package]] 508[[package]]
@@ -530,7 +524,7 @@ version = "0.3.3"
530source = "registry+https://github.com/rust-lang/crates.io-index" 524source = "registry+https://github.com/rust-lang/crates.io-index"
531dependencies = [ 525dependencies = [
532 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 526 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
533 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 527 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
534 "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)", 528 "paste 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
535] 529]
536 530
@@ -539,9 +533,9 @@ name = "jemalloc-sys"
539version = "0.3.2" 533version = "0.3.2"
540source = "registry+https://github.com/rust-lang/crates.io-index" 534source = "registry+https://github.com/rust-lang/crates.io-index"
541dependencies = [ 535dependencies = [
542 "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)", 536 "cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)",
543 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 537 "fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
544 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 538 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
545] 539]
546 540
547[[package]] 541[[package]]
@@ -550,7 +544,7 @@ version = "0.3.2"
550source = "registry+https://github.com/rust-lang/crates.io-index" 544source = "registry+https://github.com/rust-lang/crates.io-index"
551dependencies = [ 545dependencies = [
552 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)", 546 "jemalloc-sys 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
553 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 547 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
554] 548]
555 549
556[[package]] 550[[package]]
@@ -589,7 +583,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
589 583
590[[package]] 584[[package]]
591name = "libc" 585name = "libc"
592version = "0.2.65" 586version = "0.2.66"
593source = "registry+https://github.com/rust-lang/crates.io-index" 587source = "registry+https://github.com/rust-lang/crates.io-index"
594 588
595[[package]] 589[[package]]
@@ -620,18 +614,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
620dependencies = [ 614dependencies = [
621 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 615 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
622 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 616 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
623 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 617 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
624 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 618 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
625] 619]
626 620
627[[package]] 621[[package]]
628name = "lsp-types" 622name = "lsp-types"
629version = "0.61.0" 623version = "0.66.0"
630source = "registry+https://github.com/rust-lang/crates.io-index" 624source = "registry+https://github.com/rust-lang/crates.io-index"
631dependencies = [ 625dependencies = [
632 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 626 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
633 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 627 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
634 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 628 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
635 "serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", 629 "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)", 630 "url 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
637] 631]
@@ -664,7 +658,7 @@ dependencies = [
664 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", 658 "fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
665 "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", 659 "iovec 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
666 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 660 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
667 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 661 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
668 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 662 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
669 "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 663 "miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
670 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)", 664 "net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -674,7 +668,7 @@ dependencies = [
674 668
675[[package]] 669[[package]]
676name = "mio-extras" 670name = "mio-extras"
677version = "2.0.5" 671version = "2.0.6"
678source = "registry+https://github.com/rust-lang/crates.io-index" 672source = "registry+https://github.com/rust-lang/crates.io-index"
679dependencies = [ 673dependencies = [
680 "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 674 "lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -700,7 +694,7 @@ version = "0.2.33"
700source = "registry+https://github.com/rust-lang/crates.io-index" 694source = "registry+https://github.com/rust-lang/crates.io-index"
701dependencies = [ 695dependencies = [
702 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 696 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
703 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 697 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
704 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 698 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
705] 699]
706 700
@@ -715,23 +709,14 @@ dependencies = [
715 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 709 "fsevent-sys 2.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
716 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)", 710 "inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)",
717 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", 711 "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
718 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 712 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
719 "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)", 713 "mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)",
720 "mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)", 714 "mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
721 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 715 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
722 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 716 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
723] 717]
724 718
725[[package]] 719[[package]]
726name = "num-integer"
727version = "0.1.41"
728source = "registry+https://github.com/rust-lang/crates.io-index"
729dependencies = [
730 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
731 "num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)",
732]
733
734[[package]]
735name = "num-traits" 720name = "num-traits"
736version = "0.2.10" 721version = "0.2.10"
737source = "registry+https://github.com/rust-lang/crates.io-index" 722source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -744,8 +729,8 @@ name = "num_cpus"
744version = "1.11.1" 729version = "1.11.1"
745source = "registry+https://github.com/rust-lang/crates.io-index" 730source = "registry+https://github.com/rust-lang/crates.io-index"
746dependencies = [ 731dependencies = [
747 "hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", 732 "hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
748 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 733 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
749] 734]
750 735
751[[package]] 736[[package]]
@@ -774,9 +759,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
774dependencies = [ 759dependencies = [
775 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 760 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
776 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 761 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
777 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 762 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
778 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 763 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
779 "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 764 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
780 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 765 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
781] 766]
782 767
@@ -797,7 +782,7 @@ dependencies = [
797 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)", 782 "proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)",
798 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 783 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
799 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 784 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
800 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 785 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
801] 786]
802 787
803[[package]] 788[[package]]
@@ -831,7 +816,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
831dependencies = [ 816dependencies = [
832 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 817 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
833 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 818 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
834 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 819 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
835] 820]
836 821
837[[package]] 822[[package]]
@@ -860,14 +845,6 @@ dependencies = [
860] 845]
861 846
862[[package]] 847[[package]]
863name = "psm"
864version = "0.1.6"
865source = "registry+https://github.com/rust-lang/crates.io-index"
866dependencies = [
867 "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
868]
869
870[[package]]
871name = "quick-error" 848name = "quick-error"
872version = "1.2.2" 849version = "1.2.2"
873source = "registry+https://github.com/rust-lang/crates.io-index" 850source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -928,11 +905,13 @@ dependencies = [
928name = "ra_cli" 905name = "ra_cli"
929version = "0.1.0" 906version = "0.1.0"
930dependencies = [ 907dependencies = [
931 "flexi_logger 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", 908 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
932 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 909 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
933 "ra_batch 0.1.0", 910 "ra_batch 0.1.0",
934 "ra_db 0.1.0", 911 "ra_db 0.1.0",
935 "ra_hir 0.1.0", 912 "ra_hir 0.1.0",
913 "ra_hir_def 0.1.0",
914 "ra_hir_ty 0.1.0",
936 "ra_ide 0.1.0", 915 "ra_ide 0.1.0",
937 "ra_prof 0.1.0", 916 "ra_prof 0.1.0",
938 "ra_syntax 0.1.0", 917 "ra_syntax 0.1.0",
@@ -963,11 +942,13 @@ dependencies = [
963name = "ra_hir" 942name = "ra_hir"
964version = "0.1.0" 943version = "0.1.0"
965dependencies = [ 944dependencies = [
945 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
966 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 946 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
967 "ra_db 0.1.0", 947 "ra_db 0.1.0",
968 "ra_hir_def 0.1.0", 948 "ra_hir_def 0.1.0",
969 "ra_hir_expand 0.1.0", 949 "ra_hir_expand 0.1.0",
970 "ra_hir_ty 0.1.0", 950 "ra_hir_ty 0.1.0",
951 "ra_prof 0.1.0",
971 "ra_syntax 0.1.0", 952 "ra_syntax 0.1.0",
972 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 953 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
973] 954]
@@ -976,6 +957,9 @@ dependencies = [
976name = "ra_hir_def" 957name = "ra_hir_def"
977version = "0.1.0" 958version = "0.1.0"
978dependencies = [ 959dependencies = [
960 "anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)",
961 "drop_bomb 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)",
962 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
979 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 963 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
980 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 964 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
981 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 965 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -995,6 +979,7 @@ dependencies = [
995name = "ra_hir_expand" 979name = "ra_hir_expand"
996version = "0.1.0" 980version = "0.1.0"
997dependencies = [ 981dependencies = [
982 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
998 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 983 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
999 "ra_arena 0.1.0", 984 "ra_arena 0.1.0",
1000 "ra_db 0.1.0", 985 "ra_db 0.1.0",
@@ -1010,9 +995,9 @@ name = "ra_hir_ty"
1010version = "0.1.0" 995version = "0.1.0"
1011dependencies = [ 996dependencies = [
1012 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 997 "arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1013 "chalk-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 998 "chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
1014 "chalk-rust-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 999 "chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
1015 "chalk-solve 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)", 1000 "chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)",
1016 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)", 1001 "ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)",
1017 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1002 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
1018 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)", 1003 "lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1031,6 +1016,7 @@ dependencies = [
1031name = "ra_ide" 1016name = "ra_ide"
1032version = "0.1.0" 1017version = "0.1.0"
1033dependencies = [ 1018dependencies = [
1019 "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)",
1034 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1020 "format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1035 "fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)", 1021 "fst 0.3.5 (registry+https://github.com/rust-lang/crates.io-index)",
1036 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", 1022 "insta 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1060,11 +1046,11 @@ name = "ra_lsp_server"
1060version = "0.1.0" 1046version = "0.1.0"
1061dependencies = [ 1047dependencies = [
1062 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1048 "crossbeam-channel 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1063 "flexi_logger 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)", 1049 "env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
1064 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1050 "jod-thread 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1065 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1051 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1066 "lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1052 "lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1067 "lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)", 1053 "lsp-types 0.66.0 (registry+https://github.com/rust-lang/crates.io-index)",
1068 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", 1054 "parking_lot 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
1069 "ra_ide 0.1.0", 1055 "ra_ide 0.1.0",
1070 "ra_prof 0.1.0", 1056 "ra_prof 0.1.0",
@@ -1075,8 +1061,8 @@ dependencies = [
1075 "ra_vfs_glob 0.1.0", 1061 "ra_vfs_glob 0.1.0",
1076 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1062 "relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1077 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1063 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1078 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1064 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1079 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 1065 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
1080 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1066 "tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1081 "test_utils 0.1.0", 1067 "test_utils 0.1.0",
1082 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1068 "threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1091,7 +1077,7 @@ dependencies = [
1091 "ra_syntax 0.1.0", 1077 "ra_syntax 0.1.0",
1092 "ra_tt 0.1.0", 1078 "ra_tt 0.1.0",
1093 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1079 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1094 "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1080 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1095 "test_utils 0.1.0", 1081 "test_utils 0.1.0",
1096] 1082]
1097 1083
@@ -1117,14 +1103,14 @@ dependencies = [
1117name = "ra_project_model" 1103name = "ra_project_model"
1118version = "0.1.0" 1104version = "0.1.0"
1119dependencies = [ 1105dependencies = [
1120 "cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", 1106 "cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)",
1121 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", 1107 "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)",
1122 "ra_arena 0.1.0", 1108 "ra_arena 0.1.0",
1123 "ra_cfg 0.1.0", 1109 "ra_cfg 0.1.0",
1124 "ra_db 0.1.0", 1110 "ra_db 0.1.0",
1125 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1111 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1126 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1112 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1127 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 1113 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
1128] 1114]
1129 1115
1130[[package]] 1116[[package]]
@@ -1136,9 +1122,10 @@ dependencies = [
1136 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1122 "once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1137 "ra_parser 0.1.0", 1123 "ra_parser 0.1.0",
1138 "ra_text_edit 0.1.0", 1124 "ra_text_edit 0.1.0",
1139 "rowan 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)", 1125 "rowan 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)",
1140 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1126 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1141 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1127 "rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1128 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1142 "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", 1129 "smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)",
1143 "test_utils 0.1.0", 1130 "test_utils 0.1.0",
1144 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 1131 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1189,7 +1176,7 @@ version = "0.6.5"
1189source = "registry+https://github.com/rust-lang/crates.io-index" 1176source = "registry+https://github.com/rust-lang/crates.io-index"
1190dependencies = [ 1177dependencies = [
1191 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", 1178 "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)",
1192 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1179 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1193 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1180 "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1194 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1181 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1195 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1182 "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1207,7 +1194,7 @@ version = "0.7.2"
1207source = "registry+https://github.com/rust-lang/crates.io-index" 1194source = "registry+https://github.com/rust-lang/crates.io-index"
1208dependencies = [ 1195dependencies = [
1209 "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", 1196 "getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)",
1210 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1197 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1211 "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1198 "rand_chacha 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1212 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1199 "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1213 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1200 "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1282,7 +1269,7 @@ name = "rand_jitter"
1282version = "0.1.4" 1269version = "0.1.4"
1283source = "registry+https://github.com/rust-lang/crates.io-index" 1270source = "registry+https://github.com/rust-lang/crates.io-index"
1284dependencies = [ 1271dependencies = [
1285 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1272 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1286 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1273 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1287 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1274 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1288] 1275]
@@ -1294,7 +1281,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1294dependencies = [ 1281dependencies = [
1295 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", 1282 "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
1296 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", 1283 "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
1297 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1284 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1298 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", 1285 "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
1299 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", 1286 "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
1300 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", 1287 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1396,12 +1383,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1396dependencies = [ 1383dependencies = [
1397 "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)", 1384 "base64 0.10.1 (registry+https://github.com/rust-lang/crates.io-index)",
1398 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", 1385 "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
1399 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1386 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1400] 1387]
1401 1388
1402[[package]] 1389[[package]]
1403name = "rowan" 1390name = "rowan"
1404version = "0.7.1" 1391version = "0.8.2"
1405source = "registry+https://github.com/rust-lang/crates.io-index" 1392source = "registry+https://github.com/rust-lang/crates.io-index"
1406dependencies = [ 1393dependencies = [
1407 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1394 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1456,7 +1443,7 @@ dependencies = [
1456 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1443 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1457 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", 1444 "rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)",
1458 "salsa-macros 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", 1445 "salsa-macros 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)",
1459 "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1446 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1460] 1447]
1461 1448
1462[[package]] 1449[[package]]
@@ -1467,7 +1454,7 @@ dependencies = [
1467 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", 1454 "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)",
1468 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1455 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1469 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1456 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1470 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1457 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
1471] 1458]
1472 1459
1473[[package]] 1460[[package]]
@@ -1489,7 +1476,7 @@ version = "0.9.0"
1489source = "registry+https://github.com/rust-lang/crates.io-index" 1476source = "registry+https://github.com/rust-lang/crates.io-index"
1490dependencies = [ 1477dependencies = [
1491 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", 1478 "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
1492 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1479 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1493] 1480]
1494 1481
1495[[package]] 1482[[package]]
@@ -1499,30 +1486,30 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1499 1486
1500[[package]] 1487[[package]]
1501name = "serde" 1488name = "serde"
1502version = "1.0.103" 1489version = "1.0.104"
1503source = "registry+https://github.com/rust-lang/crates.io-index" 1490source = "registry+https://github.com/rust-lang/crates.io-index"
1504dependencies = [ 1491dependencies = [
1505 "serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1492 "serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1506] 1493]
1507 1494
1508[[package]] 1495[[package]]
1509name = "serde_derive" 1496name = "serde_derive"
1510version = "1.0.103" 1497version = "1.0.104"
1511source = "registry+https://github.com/rust-lang/crates.io-index" 1498source = "registry+https://github.com/rust-lang/crates.io-index"
1512dependencies = [ 1499dependencies = [
1513 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1500 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1514 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1501 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1515 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1502 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
1516] 1503]
1517 1504
1518[[package]] 1505[[package]]
1519name = "serde_json" 1506name = "serde_json"
1520version = "1.0.42" 1507version = "1.0.44"
1521source = "registry+https://github.com/rust-lang/crates.io-index" 1508source = "registry+https://github.com/rust-lang/crates.io-index"
1522dependencies = [ 1509dependencies = [
1523 "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1510 "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1524 "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1511 "ryu 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1525 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1512 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1526] 1513]
1527 1514
1528[[package]] 1515[[package]]
@@ -1532,7 +1519,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1532dependencies = [ 1519dependencies = [
1533 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1520 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1534 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1521 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1535 "syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)", 1522 "syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)",
1536] 1523]
1537 1524
1538[[package]] 1525[[package]]
@@ -1542,7 +1529,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1542dependencies = [ 1529dependencies = [
1543 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", 1530 "dtoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
1544 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1531 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1545 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1532 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1546 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", 1533 "yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
1547] 1534]
1548 1535
@@ -1553,7 +1540,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1553 1540
1554[[package]] 1541[[package]]
1555name = "smallvec" 1542name = "smallvec"
1556version = "1.0.0" 1543version = "1.1.0"
1557source = "registry+https://github.com/rust-lang/crates.io-index" 1544source = "registry+https://github.com/rust-lang/crates.io-index"
1558 1545
1559[[package]] 1546[[package]]
@@ -1561,19 +1548,7 @@ name = "smol_str"
1561version = "0.1.15" 1548version = "0.1.15"
1562source = "registry+https://github.com/rust-lang/crates.io-index" 1549source = "registry+https://github.com/rust-lang/crates.io-index"
1563dependencies = [ 1550dependencies = [
1564 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1551 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1565]
1566
1567[[package]]
1568name = "stacker"
1569version = "0.1.6"
1570source = "registry+https://github.com/rust-lang/crates.io-index"
1571dependencies = [
1572 "cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)",
1573 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1574 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1575 "psm 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
1576 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1577] 1552]
1578 1553
1579[[package]] 1554[[package]]
@@ -1583,7 +1558,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1583 1558
1584[[package]] 1559[[package]]
1585name = "syn" 1560name = "syn"
1586version = "1.0.8" 1561version = "1.0.11"
1587source = "registry+https://github.com/rust-lang/crates.io-index" 1562source = "registry+https://github.com/rust-lang/crates.io-index"
1588dependencies = [ 1563dependencies = [
1589 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1564 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1597,7 +1572,7 @@ version = "3.1.0"
1597source = "registry+https://github.com/rust-lang/crates.io-index" 1572source = "registry+https://github.com/rust-lang/crates.io-index"
1598dependencies = [ 1573dependencies = [
1599 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", 1574 "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)",
1600 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1575 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1601 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1576 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1602 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)", 1577 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
1603 "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1578 "remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
@@ -1609,7 +1584,7 @@ name = "termios"
1609version = "0.3.1" 1584version = "0.3.1"
1610source = "registry+https://github.com/rust-lang/crates.io-index" 1585source = "registry+https://github.com/rust-lang/crates.io-index"
1611dependencies = [ 1586dependencies = [
1612 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", 1587 "libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)",
1613] 1588]
1614 1589
1615[[package]] 1590[[package]]
@@ -1617,7 +1592,7 @@ name = "test_utils"
1617version = "0.1.0" 1592version = "0.1.0"
1618dependencies = [ 1593dependencies = [
1619 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1594 "difference 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)",
1620 "serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)", 1595 "serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)",
1621 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", 1596 "text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)",
1622] 1597]
1623 1598
@@ -1648,16 +1623,6 @@ dependencies = [
1648] 1623]
1649 1624
1650[[package]] 1625[[package]]
1651name = "time"
1652version = "0.1.42"
1653source = "registry+https://github.com/rust-lang/crates.io-index"
1654dependencies = [
1655 "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)",
1656 "redox_syscall 0.1.56 (registry+https://github.com/rust-lang/crates.io-index)",
1657 "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)",
1658]
1659
1660[[package]]
1661name = "unicase" 1626name = "unicase"
1662version = "2.6.0" 1627version = "2.6.0"
1663source = "registry+https://github.com/rust-lang/crates.io-index" 1628source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1678,7 +1643,7 @@ name = "unicode-normalization"
1678version = "0.1.11" 1643version = "0.1.11"
1679source = "registry+https://github.com/rust-lang/crates.io-index" 1644source = "registry+https://github.com/rust-lang/crates.io-index"
1680dependencies = [ 1645dependencies = [
1681 "smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1646 "smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1682] 1647]
1683 1648
1684[[package]] 1649[[package]]
@@ -1699,7 +1664,7 @@ dependencies = [
1699 "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", 1664 "idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
1700 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", 1665 "matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)",
1701 "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)", 1666 "percent-encoding 2.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
1702 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1667 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1703] 1668]
1704 1669
1705[[package]] 1670[[package]]
@@ -1708,7 +1673,7 @@ version = "0.8.1"
1708source = "registry+https://github.com/rust-lang/crates.io-index" 1673source = "registry+https://github.com/rust-lang/crates.io-index"
1709dependencies = [ 1674dependencies = [
1710 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", 1675 "rand 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)",
1711 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1676 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1712] 1677]
1713 1678
1714[[package]] 1679[[package]]
@@ -1781,12 +1746,12 @@ dependencies = [
1781name = "xtask" 1746name = "xtask"
1782version = "0.1.0" 1747version = "0.1.0"
1783dependencies = [ 1748dependencies = [
1784 "anyhow 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)", 1749 "anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
1785 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", 1750 "pico-args 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
1786 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", 1751 "proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)",
1787 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", 1752 "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
1788 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", 1753 "ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
1789 "serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)", 1754 "serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)",
1790 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)", 1755 "walkdir 2.2.9 (registry+https://github.com/rust-lang/crates.io-index)",
1791] 1756]
1792 1757
@@ -1798,14 +1763,10 @@ dependencies = [
1798 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", 1763 "linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)",
1799] 1764]
1800 1765
1801[[package]]
1802name = "yansi"
1803version = "0.5.0"
1804source = "registry+https://github.com/rust-lang/crates.io-index"
1805
1806[metadata] 1766[metadata]
1807"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d" 1767"checksum aho-corasick 0.7.6 (registry+https://github.com/rust-lang/crates.io-index)" = "58fb5e95d83b38284460a5fda7d6470aa0b8844d283a0b614b8535e880800d2d"
1808"checksum anyhow 1.0.24 (registry+https://github.com/rust-lang/crates.io-index)" = "b412394828b7ca486b362f300b762d8e43dafd6f0d727b63f1cd2ade207c6cef" 1768"checksum anyhow 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)" = "9267dff192e68f3399525901e709a48c1d3982c9c072fa32f2127a0cb0babf14"
1769"checksum anymap 0.12.1 (registry+https://github.com/rust-lang/crates.io-index)" = "33954243bd79057c2de7338850b85983a44588021f8a5fee574a8888c6de4344"
1809"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8" 1770"checksum arrayvec 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cff77d8686867eceff3105329d4698d96c2391c176d5d03adc90c7389162b5b8"
1810"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90" 1771"checksum atty 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "1803c647a3ec87095e7ae7acfca019e98de5ec9a7d01343f611cf3152ed71a90"
1811"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" 1772"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2"
@@ -1818,16 +1779,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1818"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245" 1779"checksum bstr 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8d6c2c5b58ab920a4f5aeaaca34b4488074e8cc7596af94e6f8c6ff247c60245"
1819"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 1780"checksum byteorder 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5"
1820"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb" 1781"checksum c2-chacha 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "214238caa1bf3a496ec3392968969cab8549f96ff30652c9e56885329315f6bb"
1821"checksum cargo_metadata 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8d2d1617e838936c0d2323a65cc151e03ae19a7678dd24f72bccf27119b90a5d" 1782"checksum cargo_metadata 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202"
1822"checksum cc 1.0.47 (registry+https://github.com/rust-lang/crates.io-index)" = "aa87058dce70a3ff5621797f1506cb837edd02ac4c0ae642b4542dce802908b8" 1783"checksum cc 1.0.48 (registry+https://github.com/rust-lang/crates.io-index)" = "f52a465a666ca3d838ebbf08b241383421412fe7ebb463527bba275526d89f76"
1823"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" 1784"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822"
1824"checksum chalk-derive 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1785"checksum chalk-derive 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1825"checksum chalk-engine 0.9.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1786"checksum chalk-engine 0.9.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1826"checksum chalk-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1787"checksum chalk-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1827"checksum chalk-macros 0.1.1 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1788"checksum chalk-macros 0.1.1 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1828"checksum chalk-rust-ir 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1789"checksum chalk-rust-ir 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1829"checksum chalk-solve 0.1.0 (git+https://github.com/jackh726/chalk.git?rev=095cd38a4f16337913bba487f2055b9ca0179f30)" = "<none>" 1790"checksum chalk-solve 0.1.0 (git+https://github.com/rust-lang/chalk.git?rev=ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5)" = "<none>"
1830"checksum chrono 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "31850b4a4d6bae316f7a09e691c944c28299298837edc0a03f755618c23cbc01"
1831"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e" 1791"checksum clicolors-control 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90082ee5dcdd64dc4e9e0d37fbf3ee325419e39c0092191e0393df65518f741e"
1832"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" 1792"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
1833"checksum console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5d540c2d34ac9dd0deb5f3b5f54c36c79efa78f6b3ad19106a554d07a7b5d9f" 1793"checksum console 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f5d540c2d34ac9dd0deb5f3b5f54c36c79efa78f6b3ad19106a554d07a7b5d9f"
@@ -1843,9 +1803,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1843"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" 1803"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3"
1844"checksum ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36" 1804"checksum ena 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8944dc8fa28ce4a38f778bd46bf7d923fe73eed5a439398507246c8e017e6f36"
1845"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" 1805"checksum encode_unicode 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f"
1806"checksum env_logger 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "44533bbbb3bb3c1fa17d9f2e4e38bbbaf8396ba82193c4cb1b6445d711445d36"
1846"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d" 1807"checksum filetime 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "1ff6d4dab0aa0c8e6346d46052e93b13a16cf847b54ed357087c35011048cc7d"
1847"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33" 1808"checksum fixedbitset 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "86d4de0081402f5e88cdac65c8dcdcc73118c1a7a465e2a05f0da05843a8ea33"
1848"checksum flexi_logger 0.14.5 (registry+https://github.com/rust-lang/crates.io-index)" = "a13ea6b8a4debecf47bf3966d56db0e21366bc3a3649ba159e1a9e6fdd36a4f4"
1849"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3" 1809"checksum fnv 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "2fad85553e09a6f881f739c29f0b00b0f01357c743266d478b68951ce23285f3"
1850"checksum format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f7aea5a5909a74969507051a3b17adc84737e31a5f910559892aedce026f4d53" 1810"checksum format-buf 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f7aea5a5909a74969507051a3b17adc84737e31a5f910559892aedce026f4d53"
1851"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674" 1811"checksum fs_extra 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5f2a4a2034423744d2cc7ca2068453168dcdb82c438419e639a26bd87839c674"
@@ -1856,10 +1816,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1856"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82" 1816"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
1857"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" 1817"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
1858"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407" 1818"checksum getrandom 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "e7db7ca94ed4cd01190ceee0d8a8052f08a247aa1b469a7f68c6a3b71afcf407"
1859"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574"
1860"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2" 1819"checksum globset 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "925aa2cac82d8834e2b2a4415b6f6879757fb5c0928fc445ae76461a12eed8f2"
1861"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" 1820"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205"
1862"checksum hermit-abi 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "307c3c9f937f38e3534b1d6447ecf090cafcc9744e4a6360e8b037b2cf5af120" 1821"checksum hermit-abi 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "f629dc602392d3ec14bfc8a09b5e644d7ffd725102b48b81e59f90f2633621d7"
1822"checksum humantime 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df004cfca50ef23c36850aaaa59ad52cc70d0e90243c3c7737a4dd32dc7a3c4f"
1863"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9" 1823"checksum idna 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "02e2673c30ee86b5b96a9cb52ad15718aa1f966f5ab9ad54a8b95d5ca33120a9"
1864"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" 1824"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2"
1865"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718" 1825"checksum inotify 0.6.1 (registry+https://github.com/rust-lang/crates.io-index)" = "40b54539f3910d6f84fbf9a643efd6e3aa6e4f001426c0329576128255994718"
@@ -1877,21 +1837,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1877"checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0" 1837"checksum lalrpop-intern 0.15.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cc4fd87be4a815fd373e02773983940f0d75fb26fde8c098e9e45f7af03154c0"
1878"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" 1838"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
1879"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f" 1839"checksum lazycell 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b294d6fa9ee409a054354afc4352b0b9ef7ca222c69b8812cbea9e7d2bf3783f"
1880"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" 1840"checksum libc 0.2.66 (registry+https://github.com/rust-lang/crates.io-index)" = "d515b1f41455adea1313a4a2ac8a8a477634fbae63cc6100e3aebb207ce61558"
1881"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83" 1841"checksum linked-hash-map 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "ae91b68aebc4ddb91978b11a1b02ddd8602a05ec19002801c5666000e05e0f83"
1882"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586" 1842"checksum lock_api 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e57b3997725d2b60dbec1297f6c2e2957cc383db1cebd6be812163f969c7d586"
1883"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" 1843"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7"
1884"checksum lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba36405bd742139ab79c246ca5adb7fde2fe1a0f495e2c8e2f607b607dedb12" 1844"checksum lsp-server 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0ba36405bd742139ab79c246ca5adb7fde2fe1a0f495e2c8e2f607b607dedb12"
1885"checksum lsp-types 0.61.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fa3268fbe8beb2795c2fb327bf44f4f3d24f5fe9ebc18d7e2980afd444d72bcf" 1845"checksum lsp-types 0.66.0 (registry+https://github.com/rust-lang/crates.io-index)" = "49a2dddfe2791cbf4b5eff5a581e45becf47a24b128a62de80e7cc135bf50064"
1886"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" 1846"checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08"
1887"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" 1847"checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e"
1888"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9" 1848"checksum memoffset 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "75189eb85871ea5c2e2c15abbdd541185f63b408415e5051f5cac122d8c774b9"
1889"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f" 1849"checksum mio 0.6.21 (registry+https://github.com/rust-lang/crates.io-index)" = "302dec22bcf6bae6dfb69c647187f4b4d0fb6f535521f7bc022430ce8e12008f"
1890"checksum mio-extras 2.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "46e73a04c2fa6250b8d802134d56d554a9ec2922bf977777c805ea5def61ce40" 1850"checksum mio-extras 2.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "52403fe290012ce777c4626790c8951324a2b9e3316b3143779c72b029742f19"
1891"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919" 1851"checksum miow 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f2f3b1cf331de6896aabf6e9d55dca90356cc9960cca7eaaf408a355ae919"
1892"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" 1852"checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88"
1893"checksum notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "199628fc33b21bc767baa057490b00b382ecbae030803a7b36292422d15b778b" 1853"checksum notify 4.0.14 (registry+https://github.com/rust-lang/crates.io-index)" = "199628fc33b21bc767baa057490b00b382ecbae030803a7b36292422d15b778b"
1894"checksum num-integer 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)" = "b85e541ef8255f6cf42bbfe4ef361305c6c135d10919ecc26126c4e5ae94bc09"
1895"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4" 1854"checksum num-traits 0.2.10 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c81ffc11c212fa327657cb19dd85eb7419e163b5b076bede2bdb5c974c07e4"
1896"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72" 1855"checksum num_cpus 1.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "76dac5ed2a876980778b8b85f75a71b6cbf0db0b1232ee12f826bccb00d09d72"
1897"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed" 1856"checksum once_cell 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "891f486f630e5c5a4916c7e16c4b24a53e78c860b646e9f8e005e4f16847bfed"
@@ -1907,7 +1866,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1907"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5" 1866"checksum proc-macro-hack 0.5.11 (registry+https://github.com/rust-lang/crates.io-index)" = "ecd45702f76d6d3c75a80564378ae228a85f0b59d2f3ed43c91b4a69eb2ebfc5"
1908"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27" 1867"checksum proc-macro2 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "9c9e470a8dc4aeae2dee2f335e8f533e2d4b347e1434e5671afc49b054592f27"
1909"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f" 1868"checksum proptest 0.9.4 (registry+https://github.com/rust-lang/crates.io-index)" = "cf147e022eacf0c8a054ab864914a7602618adba841d800a9a9868a5237a529f"
1910"checksum psm 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "b14fc68b454f875abc8354c2555e1d56596f74833ddc0f77f87f4871ed6a30e0"
1911"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" 1869"checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0"
1912"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" 1870"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
1913"checksum ra_vfs 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc898f237e4b4498959ae0100c688793a23e77624d44ef710ba70094217f98e0" 1871"checksum ra_vfs 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "bc898f237e4b4498959ae0100c688793a23e77624d44ef710ba70094217f98e0"
@@ -1935,7 +1893,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1935"checksum relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bedde000f40f2921ce439ea165c9c53fd629bfa115140c72e22aceacb4a21954" 1893"checksum relative-path 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bedde000f40f2921ce439ea165c9c53fd629bfa115140c72e22aceacb4a21954"
1936"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e" 1894"checksum remove_dir_all 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "4a83fa3702a688b9359eccba92d153ac33fd2e8462f9e0e3fdf155239ea7792e"
1937"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5" 1895"checksum ron 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2ece421e0c4129b90e4a35b6f625e472e96c552136f5093a2f4fa2bbb75a62d5"
1938"checksum rowan 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ca620bbf9c48c92b5cef19f96354a309ac36b7d8ef7c591e66117335c8b1988b" 1896"checksum rowan 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3eb10a10a48f0f809a217bcf074b85a03dcf79831bae80e7f1a043d0897463e2"
1939"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783" 1897"checksum rustc-demangle 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)" = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
1940"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1898"checksum rustc-hash 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8"
1941"checksum rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5" 1899"checksum rustc_lexer 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c86aae0c77166108c01305ee1a36a1e77289d7dc6ca0a3cd91ff4992de2d16a5"
@@ -1947,24 +1905,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1947"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d" 1905"checksum scopeguard 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b42e15e59b18a828bbf5c58ea01debb36b9b096346de35d941dcb89009f24a0d"
1948"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" 1906"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
1949"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" 1907"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
1950"checksum serde 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "1217f97ab8e8904b57dd22eb61cde455fa7446a9c1cf43966066da047c1f3702" 1908"checksum serde 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "414115f25f818d7dfccec8ee535d76949ae78584fc4f79a6f45a904bf8ab4449"
1951"checksum serde_derive 1.0.103 (registry+https://github.com/rust-lang/crates.io-index)" = "a8c6faef9a2e64b0064f48570289b4bf8823b7581f1d6157c1b52152306651d0" 1909"checksum serde_derive 1.0.104 (registry+https://github.com/rust-lang/crates.io-index)" = "128f9e303a5a29922045a830221b8f78ec74a5f544944f3d5984f8ec3895ef64"
1952"checksum serde_json 1.0.42 (registry+https://github.com/rust-lang/crates.io-index)" = "1a3351dcbc1f067e2c92ab7c3c1f288ad1a4cffc470b5aaddb4c2e0a3ae80043" 1910"checksum serde_json 1.0.44 (registry+https://github.com/rust-lang/crates.io-index)" = "48c575e0cc52bdd09b47f330f646cf59afc586e9c4e3ccd6fc1f625b8ea1dad7"
1953"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573" 1911"checksum serde_repr 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "cd02c7587ec314570041b2754829f84d873ced14a96d1fd1823531e11db40573"
1954"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35" 1912"checksum serde_yaml 0.8.11 (registry+https://github.com/rust-lang/crates.io-index)" = "691b17f19fc1ec9d94ec0b5864859290dff279dbd7b03f017afda54eb36c3c35"
1955"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8" 1913"checksum slab 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
1956"checksum smallvec 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4ecf3b85f68e8abaa7555aa5abdb1153079387e60b718283d732f03897fcfc86" 1914"checksum smallvec 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44e59e0c9fa00817912ae6e4e6e3c4fe04455e75699d06eedc7d85917ed8e8f4"
1957"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b" 1915"checksum smol_str 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "34836c9a295c62c2ce3514471117c5cb269891e8421b2aafdd910050576c4d8b"
1958"checksum stacker 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "d96fc4f13a0ac088e9a3cd9af1cc8c5cc1ab5deb2145cef661267dfc9c542f8a"
1959"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f" 1916"checksum superslice 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ab16ced94dbd8a46c82fd81e3ed9a8727dac2977ea869d217bcc4ea1f122e81f"
1960"checksum syn 1.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "661641ea2aa15845cddeb97dad000d22070bb5c1fb456b96c1cba883ec691e92" 1917"checksum syn 1.0.11 (registry+https://github.com/rust-lang/crates.io-index)" = "dff0acdb207ae2fe6d5976617f887eb1e35a2ba52c13c7234c790960cdad9238"
1961"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" 1918"checksum tempfile 3.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9"
1962"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625" 1919"checksum termios 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "72b620c5ea021d75a735c943269bb07d30c9b77d6ac6b236bc8b5c496ef05625"
1963"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579" 1920"checksum text_unit 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e08bbcb7a3adbda0eb23431206b653bdad3d8dea311e72d36bf2215e27a42579"
1964"checksum thin-dst 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c52fd98a9e4913c466d83381a59245691875d2f3e04611fca57f964bd8aa96e1" 1921"checksum thin-dst 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c52fd98a9e4913c466d83381a59245691875d2f3e04611fca57f964bd8aa96e1"
1965"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" 1922"checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b"
1966"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865" 1923"checksum threadpool 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e2f0c90a5f3459330ac8bc0d2f879c693bb7a2f59689c1083fc4ef83834da865"
1967"checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f"
1968"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" 1924"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6"
1969"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5" 1925"checksum unicode-bidi 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "49f2bd0c6468a8230e1db229cff8029217cf623c767ea5d60bfbd42729ea54d5"
1970"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf" 1926"checksum unicode-normalization 0.1.11 (registry+https://github.com/rust-lang/crates.io-index)" = "b561e267b2326bb4cebfc0ef9e68355c7abe6c6f522aeac2f5bf95d56c59bdcf"
@@ -1983,4 +1939,3 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
1983"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 1939"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
1984"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e" 1940"checksum ws2_32-sys 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d59cefebd0c892fa2dd6de581e937301d8552cb44489cdff035c6187cb63fa5e"
1985"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d" 1941"checksum yaml-rust 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "65923dd1784f44da1d2c3dbbc5e822045628c590ba72123e1c73d3c230c4434d"
1986"checksum yansi 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71"
diff --git a/Cargo.toml b/Cargo.toml
index 92e3228f0..97508c57b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,3 +11,4 @@ incremental = true
11debug = 0 # set this to 1 or 2 to get more useful backtraces in debugger 11debug = 0 # set this to 1 or 2 to get more useful backtraces in debugger
12 12
13[patch.'crates-io'] 13[patch.'crates-io']
14# rowan = { path = "../rowan" } \ No newline at end of file
diff --git a/README.md b/README.md
index 74c971c0d..deaa147ba 100644
--- a/README.md
+++ b/README.md
@@ -37,7 +37,8 @@ $ cargo xtask install
37$ cargo xtask install --server 37$ cargo xtask install --server
38``` 38```
39 39
40For non-standard setup of VS Code and other editors, see [./docs/user](./docs/user). 40For non-standard setup of VS Code and other editors, or if the language server
41cannot start, see [./docs/user](./docs/user).
41 42
42## Documentation 43## Documentation
43 44
@@ -57,7 +58,7 @@ https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Frls-2.2E0
57## Quick Links 58## Quick Links
58 59
59* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide/ 60* API docs: https://rust-analyzer.github.io/rust-analyzer/ra_ide/
60 61* Website: https://rust-analyzer.github.io/
61 62
62## License 63## License
63 64
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 0ea84d548..993aebc47 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +1,5 @@
1//! This module defines `AssistCtx` -- the API surface that is exposed to assists. 1//! This module defines `AssistCtx` -- the API surface that is exposed to assists.
2use hir::{db::HirDatabase, SourceAnalyzer}; 2use hir::{db::HirDatabase, InFile, SourceAnalyzer};
3use ra_db::FileRange; 3use ra_db::FileRange;
4use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
5use ra_syntax::{ 5use ra_syntax::{
@@ -117,7 +117,7 @@ impl<'a, DB: HirDatabase> AssistCtx<'a, DB> {
117 node: &SyntaxNode, 117 node: &SyntaxNode,
118 offset: Option<TextUnit>, 118 offset: Option<TextUnit>,
119 ) -> SourceAnalyzer { 119 ) -> SourceAnalyzer {
120 SourceAnalyzer::new(self.db, hir::Source::new(self.frange.file_id.into(), node), offset) 120 SourceAnalyzer::new(self.db, InFile::new(self.frange.file_id.into(), node), offset)
121 } 121 }
122 122
123 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement { 123 pub(crate) fn covering_node_for_range(&self, range: TextRange) -> SyntaxElement {
diff --git a/crates/ra_assists/src/assists/add_custom_impl.rs b/crates/ra_assists/src/assists/add_custom_impl.rs
new file mode 100644
index 000000000..037306fd6
--- /dev/null
+++ b/crates/ra_assists/src/assists/add_custom_impl.rs
@@ -0,0 +1,206 @@
1//! FIXME: write short doc here
2
3use crate::{Assist, AssistCtx, AssistId};
4use hir::db::HirDatabase;
5use join_to_string::join;
6use ra_syntax::{
7 ast::{self, AstNode},
8 Direction, SmolStr,
9 SyntaxKind::{IDENT, WHITESPACE},
10 TextRange, TextUnit,
11};
12
13const DERIVE_TRAIT: &'static str = "derive";
14
15// Assist: add_custom_impl
16//
17// Adds impl block for derived trait.
18//
19// ```
20// #[derive(Deb<|>ug, Display)]
21// struct S;
22// ```
23// ->
24// ```
25// #[derive(Display)]
26// struct S;
27//
28// impl Debug for S {
29//
30// }
31// ```
32pub(crate) fn add_custom_impl(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
33 let input = ctx.find_node_at_offset::<ast::AttrInput>()?;
34 let attr = input.syntax().parent().and_then(ast::Attr::cast)?;
35
36 let attr_name = attr
37 .syntax()
38 .descendants_with_tokens()
39 .filter(|t| t.kind() == IDENT)
40 .find_map(|i| i.into_token())
41 .filter(|t| *t.text() == DERIVE_TRAIT)?
42 .text()
43 .clone();
44
45 let trait_token =
46 ctx.token_at_offset().filter(|t| t.kind() == IDENT && *t.text() != attr_name).next()?;
47
48 let annotated = attr.syntax().siblings(Direction::Next).find_map(|s| ast::Name::cast(s))?;
49 let annotated_name = annotated.syntax().text().to_string();
50 let start_offset = annotated.syntax().parent()?.text_range().end();
51
52 ctx.add_assist(AssistId("add_custom_impl"), "add custom impl", |edit| {
53 edit.target(attr.syntax().text_range());
54
55 let new_attr_input = input
56 .syntax()
57 .descendants_with_tokens()
58 .filter(|t| t.kind() == IDENT)
59 .filter_map(|t| t.into_token().map(|t| t.text().clone()))
60 .filter(|t| t != trait_token.text())
61 .collect::<Vec<SmolStr>>();
62 let has_more_derives = new_attr_input.len() > 0;
63 let new_attr_input =
64 join(new_attr_input.iter()).separator(", ").surround_with("(", ")").to_string();
65 let new_attr_input_len = new_attr_input.len();
66
67 let mut buf = String::new();
68 buf.push_str("\n\nimpl ");
69 buf.push_str(trait_token.text().as_str());
70 buf.push_str(" for ");
71 buf.push_str(annotated_name.as_str());
72 buf.push_str(" {\n");
73
74 let cursor_delta = if has_more_derives {
75 edit.replace(input.syntax().text_range(), new_attr_input);
76 input.syntax().text_range().len() - TextUnit::from_usize(new_attr_input_len)
77 } else {
78 let attr_range = attr.syntax().text_range();
79 edit.delete(attr_range);
80
81 let line_break_range = attr
82 .syntax()
83 .next_sibling_or_token()
84 .filter(|t| t.kind() == WHITESPACE)
85 .map(|t| t.text_range())
86 .unwrap_or(TextRange::from_to(TextUnit::from(0), TextUnit::from(0)));
87 edit.delete(line_break_range);
88
89 attr_range.len() + line_break_range.len()
90 };
91
92 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - cursor_delta);
93 buf.push_str("\n}");
94 edit.insert(start_offset, buf);
95 })
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101 use crate::helpers::{check_assist, check_assist_not_applicable};
102
103 #[test]
104 fn add_custom_impl_for_unique_input() {
105 check_assist(
106 add_custom_impl,
107 "
108#[derive(Debu<|>g)]
109struct Foo {
110 bar: String,
111}
112 ",
113 "
114struct Foo {
115 bar: String,
116}
117
118impl Debug for Foo {
119<|>
120}
121 ",
122 )
123 }
124
125 #[test]
126 fn add_custom_impl_for_with_visibility_modifier() {
127 check_assist(
128 add_custom_impl,
129 "
130#[derive(Debug<|>)]
131pub struct Foo {
132 bar: String,
133}
134 ",
135 "
136pub struct Foo {
137 bar: String,
138}
139
140impl Debug for Foo {
141<|>
142}
143 ",
144 )
145 }
146
147 #[test]
148 fn add_custom_impl_when_multiple_inputs() {
149 check_assist(
150 add_custom_impl,
151 "
152#[derive(Display, Debug<|>, Serialize)]
153struct Foo {}
154 ",
155 "
156#[derive(Display, Serialize)]
157struct Foo {}
158
159impl Debug for Foo {
160<|>
161}
162 ",
163 )
164 }
165
166 #[test]
167 fn test_ignore_derive_macro_without_input() {
168 check_assist_not_applicable(
169 add_custom_impl,
170 "
171#[derive(<|>)]
172struct Foo {}
173 ",
174 )
175 }
176
177 #[test]
178 fn test_ignore_if_cursor_on_param() {
179 check_assist_not_applicable(
180 add_custom_impl,
181 "
182#[derive<|>(Debug)]
183struct Foo {}
184 ",
185 );
186
187 check_assist_not_applicable(
188 add_custom_impl,
189 "
190#[derive(Debug)<|>]
191struct Foo {}
192 ",
193 )
194 }
195
196 #[test]
197 fn test_ignore_if_not_derive() {
198 check_assist_not_applicable(
199 add_custom_impl,
200 "
201#[allow(non_camel_<|>case_types)]
202struct Foo {}
203 ",
204 )
205 }
206}
diff --git a/crates/ra_assists/src/assists/add_import.rs b/crates/ra_assists/src/assists/add_import.rs
index 363ade016..b8752cbad 100644
--- a/crates/ra_assists/src/assists/add_import.rs
+++ b/crates/ra_assists/src/assists/add_import.rs
@@ -578,17 +578,21 @@ fn apply_auto_import(
578 578
579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { 579fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> {
580 let mut ps = Vec::<SmolStr>::with_capacity(10); 580 let mut ps = Vec::<SmolStr>::with_capacity(10);
581 match path.kind { 581 match path.kind() {
582 hir::PathKind::Abs => ps.push("".into()), 582 hir::PathKind::Abs => ps.push("".into()),
583 hir::PathKind::Crate => ps.push("crate".into()), 583 hir::PathKind::Crate => ps.push("crate".into()),
584 hir::PathKind::Plain => {} 584 hir::PathKind::Plain => {}
585 hir::PathKind::Self_ => ps.push("self".into()), 585 hir::PathKind::Super(0) => ps.push("self".into()),
586 hir::PathKind::Super => ps.push("super".into()), 586 hir::PathKind::Super(lvl) => {
587 hir::PathKind::Type(_) | hir::PathKind::DollarCrate(_) => return None, 587 let mut chain = "super".to_string();
588 } 588 for _ in 0..*lvl {
589 for s in path.segments.iter() { 589 chain += "::super";
590 ps.push(s.name.to_string().into()); 590 }
591 ps.push(chain.into());
592 }
593 hir::PathKind::DollarCrate(_) => return None,
591 } 594 }
595 ps.extend(path.segments().iter().map(|it| it.name.to_string().into()));
592 Some(ps) 596 Some(ps)
593} 597}
594 598
diff --git a/crates/ra_assists/src/assists/add_new.rs b/crates/ra_assists/src/assists/add_new.rs
index 8f68bd5fb..b2f946fac 100644
--- a/crates/ra_assists/src/assists/add_new.rs
+++ b/crates/ra_assists/src/assists/add_new.rs
@@ -1,5 +1,5 @@
1use format_buf::format; 1use format_buf::format;
2use hir::{db::HirDatabase, FromSource}; 2use hir::{db::HirDatabase, FromSource, InFile};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{ 5 ast::{
@@ -56,42 +56,39 @@ pub(crate) fn add_new(ctx: AssistCtx<impl HirDatabase>) -> Option<Assist> {
56 let vis = vis.as_ref().map(String::as_str).unwrap_or(""); 56 let vis = vis.as_ref().map(String::as_str).unwrap_or("");
57 write!(&mut buf, " {}fn new(", vis).unwrap(); 57 write!(&mut buf, " {}fn new(", vis).unwrap();
58 58
59 join(field_list.fields().map(|f| { 59 join(field_list.fields().filter_map(|f| {
60 format!( 60 Some(format!("{}: {}", f.name()?.syntax().text(), f.ascribed_type()?.syntax().text()))
61 "{}: {}",
62 f.name().unwrap().syntax().text(),
63 f.ascribed_type().unwrap().syntax().text()
64 )
65 })) 61 }))
66 .separator(", ") 62 .separator(", ")
67 .to_buf(&mut buf); 63 .to_buf(&mut buf);
68 64
69 buf.push_str(") -> Self { Self {"); 65 buf.push_str(") -> Self { Self {");
70 66
71 join(field_list.fields().map(|f| f.name().unwrap().syntax().text())) 67 join(field_list.fields().filter_map(|f| Some(f.name()?.syntax().text())))
72 .separator(", ") 68 .separator(", ")
73 .surround_with(" ", " ") 69 .surround_with(" ", " ")
74 .to_buf(&mut buf); 70 .to_buf(&mut buf);
75 71
76 buf.push_str("} }"); 72 buf.push_str("} }");
77 73
78 let (start_offset, end_offset) = if let Some(impl_block) = impl_block { 74 let (start_offset, end_offset) = impl_block
79 buf.push('\n'); 75 .and_then(|impl_block| {
80 let start = impl_block 76 buf.push('\n');
81 .syntax() 77 let start = impl_block
82 .descendants_with_tokens() 78 .syntax()
83 .find(|t| t.kind() == T!['{']) 79 .descendants_with_tokens()
84 .unwrap() 80 .find(|t| t.kind() == T!['{'])?
85 .text_range() 81 .text_range()
86 .end(); 82 .end();
87 83
88 (start, TextUnit::from_usize(1)) 84 Some((start, TextUnit::from_usize(1)))
89 } else { 85 })
90 buf = generate_impl_text(&strukt, &buf); 86 .unwrap_or_else(|| {
91 let start = strukt.syntax().text_range().end(); 87 buf = generate_impl_text(&strukt, &buf);
92 88 let start = strukt.syntax().text_range().end();
93 (start, TextUnit::from_usize(3)) 89
94 }; 90 (start, TextUnit::from_usize(3))
91 });
95 92
96 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset); 93 edit.set_cursor(start_offset + TextUnit::of_str(&buf) - end_offset);
97 edit.insert(start_offset, buf); 94 edit.insert(start_offset, buf);
@@ -141,44 +138,41 @@ fn find_struct_impl(
141 })?; 138 })?;
142 139
143 let struct_ty = { 140 let struct_ty = {
144 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: strukt.clone() }; 141 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
145 hir::Struct::from_source(db, src).unwrap().ty(db) 142 hir::Struct::from_source(db, src)?.ty(db)
146 }; 143 };
147 144
148 let mut found_new_fn = false; 145 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
149 146 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
150 let block = module.descendants().filter_map(ast::ImplBlock::cast).find(|impl_blk| { 147 let blk = hir::ImplBlock::from_source(db, src)?;
151 if found_new_fn {
152 return false;
153 }
154
155 let src = hir::Source { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
156 let blk = hir::ImplBlock::from_source(db, src).unwrap();
157 148
158 let same_ty = blk.target_ty(db) == struct_ty; 149 let same_ty = blk.target_ty(db) == struct_ty;
159 let not_trait_impl = blk.target_trait(db).is_none(); 150 let not_trait_impl = blk.target_trait(db).is_none();
160 151
161 if !(same_ty && not_trait_impl) { 152 if !(same_ty && not_trait_impl) {
162 return false; 153 None
154 } else {
155 Some(impl_blk)
163 } 156 }
164
165 found_new_fn = has_new_fn(impl_blk);
166 true
167 }); 157 });
168 158
169 if found_new_fn { 159 if let Some(ref impl_blk) = block {
170 None 160 if has_new_fn(impl_blk) {
171 } else { 161 return None;
172 Some(block) 162 }
173 } 163 }
164
165 Some(block)
174} 166}
175 167
176fn has_new_fn(imp: &ast::ImplBlock) -> bool { 168fn has_new_fn(imp: &ast::ImplBlock) -> bool {
177 if let Some(il) = imp.item_list() { 169 if let Some(il) = imp.item_list() {
178 for item in il.impl_items() { 170 for item in il.impl_items() {
179 if let ast::ImplItem::FnDef(f) = item { 171 if let ast::ImplItem::FnDef(f) = item {
180 if f.name().unwrap().text().eq_ignore_ascii_case("new") { 172 if let Some(name) = f.name() {
181 return true; 173 if name.text().eq_ignore_ascii_case("new") {
174 return true;
175 }
182 } 176 }
183 } 177 }
184 } 178 }
diff --git a/crates/ra_assists/src/assists/early_return.rs b/crates/ra_assists/src/assists/early_return.rs
index 264412526..023917aca 100644
--- a/crates/ra_assists/src/assists/early_return.rs
+++ b/crates/ra_assists/src/assists/early_return.rs
@@ -83,8 +83,8 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
83 let parent_container = parent_block.syntax().parent()?.parent()?; 83 let parent_container = parent_block.syntax().parent()?.parent()?;
84 84
85 let early_expression: ast::Expr = match parent_container.kind() { 85 let early_expression: ast::Expr = match parent_container.kind() {
86 WHILE_EXPR | LOOP_EXPR => make::expr_continue().into(), 86 WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
87 FN_DEF => make::expr_return().into(), 87 FN_DEF => make::expr_return(),
88 _ => return None, 88 _ => return None,
89 }; 89 };
90 90
@@ -116,13 +116,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
116 ) 116 )
117 .into(), 117 .into(),
118 ), 118 ),
119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))).into(), 119 make::expr_path(make::path_from_name_ref(make::name_ref("it"))),
120 ); 120 );
121 121
122 let sad_arm = make::match_arm( 122 let sad_arm = make::match_arm(
123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate 123 // FIXME: would be cool to use `None` or `Err(_)` if appropriate
124 once(make::placeholder_pat().into()), 124 once(make::placeholder_pat().into()),
125 early_expression.into(), 125 early_expression,
126 ); 126 );
127 127
128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm])) 128 make::expr_match(cond_expr, make::match_arm_list(vec![happy_arm, sad_arm]))
@@ -130,7 +130,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx<impl HirDatabase>) -> Opt
130 130
131 let let_stmt = make::let_stmt( 131 let let_stmt = make::let_stmt(
132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(), 132 make::bind_pat(make::name(&bound_ident.syntax().to_string())).into(),
133 Some(match_expr.into()), 133 Some(match_expr),
134 ); 134 );
135 let let_stmt = if_indent_level.increase_indent(let_stmt); 135 let let_stmt = if_indent_level.increase_indent(let_stmt);
136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr) 136 replace(let_stmt.syntax(), &then_block, &parent_block, &if_expr)
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 3c716c2d1..4586eeb59 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -3,6 +3,25 @@
3use super::check; 3use super::check;
4 4
5#[test] 5#[test]
6fn doctest_add_custom_impl() {
7 check(
8 "add_custom_impl",
9 r#####"
10#[derive(Deb<|>ug, Display)]
11struct S;
12"#####,
13 r#####"
14#[derive(Display)]
15struct S;
16
17impl Debug for S {
18
19}
20"#####,
21 )
22}
23
24#[test]
6fn doctest_add_derive() { 25fn doctest_add_derive() {
7 check( 26 check(
8 "add_derive", 27 "add_derive",
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index a372bd8b9..98fb20b22 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -95,6 +95,7 @@ mod assists {
95 mod add_derive; 95 mod add_derive;
96 mod add_explicit_type; 96 mod add_explicit_type;
97 mod add_impl; 97 mod add_impl;
98 mod add_custom_impl;
98 mod add_new; 99 mod add_new;
99 mod apply_demorgan; 100 mod apply_demorgan;
100 mod invert_if; 101 mod invert_if;
@@ -121,6 +122,7 @@ mod assists {
121 add_derive::add_derive, 122 add_derive::add_derive,
122 add_explicit_type::add_explicit_type, 123 add_explicit_type::add_explicit_type,
123 add_impl::add_impl, 124 add_impl::add_impl,
125 add_custom_impl::add_custom_impl,
124 add_new::add_new, 126 add_new::add_new,
125 apply_demorgan::apply_demorgan, 127 apply_demorgan::apply_demorgan,
126 invert_if::invert_if, 128 invert_if::invert_if,
diff --git a/crates/ra_assists/src/test_db.rs b/crates/ra_assists/src/test_db.rs
index 523259fd4..d5249f308 100644
--- a/crates/ra_assists/src/test_db.rs
+++ b/crates/ra_assists/src/test_db.rs
@@ -43,5 +43,3 @@ impl FileLoader for TestDB {
43 FileLoaderDelegate(self).relevant_crates(file_id) 43 FileLoaderDelegate(self).relevant_crates(file_id)
44 } 44 }
45} 45}
46
47impl hir::debug::HirDebugHelper for TestDB {}
diff --git a/crates/ra_batch/src/lib.rs b/crates/ra_batch/src/lib.rs
index 2c9645c00..7744ba85a 100644
--- a/crates/ra_batch/src/lib.rs
+++ b/crates/ra_batch/src/lib.rs
@@ -22,7 +22,7 @@ fn vfs_root_to_id(r: ra_vfs::VfsRoot) -> SourceRootId {
22 22
23pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> { 23pub fn load_cargo(root: &Path) -> Result<(AnalysisHost, FxHashMap<SourceRootId, PackageRoot>)> {
24 let root = std::env::current_dir()?.join(root); 24 let root = std::env::current_dir()?.join(root);
25 let ws = ProjectWorkspace::discover(root.as_ref())?; 25 let ws = ProjectWorkspace::discover(root.as_ref(), &Default::default())?;
26 let project_roots = ws.to_roots(); 26 let project_roots = ws.to_roots();
27 let (sender, receiver) = unbounded(); 27 let (sender, receiver) = unbounded();
28 let sender = Box::new(move |t| sender.send(t).unwrap()); 28 let sender = Box::new(move |t| sender.send(t).unwrap());
diff --git a/crates/ra_cli/Cargo.toml b/crates/ra_cli/Cargo.toml
index c7e0d0f0f..12af075f7 100644
--- a/crates/ra_cli/Cargo.toml
+++ b/crates/ra_cli/Cargo.toml
@@ -7,12 +7,14 @@ publish = false
7 7
8[dependencies] 8[dependencies]
9pico-args = "0.3.0" 9pico-args = "0.3.0"
10flexi_logger = "0.14.0" 10env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] }
11 11
12ra_syntax = { path = "../ra_syntax" } 12ra_syntax = { path = "../ra_syntax" }
13ra_ide = { path = "../ra_ide" } 13ra_ide = { path = "../ra_ide" }
14ra_batch = { path = "../ra_batch" } 14ra_batch = { path = "../ra_batch" }
15ra_hir = { path = "../ra_hir" } 15hir = { path = "../ra_hir", package = "ra_hir" }
16hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
17hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
16ra_db = { path = "../ra_db" } 18ra_db = { path = "../ra_db" }
17 19
18[dependencies.ra_prof] 20[dependencies.ra_prof]
diff --git a/crates/ra_cli/src/analysis_stats.rs b/crates/ra_cli/src/analysis_stats.rs
index 9b1802a5f..ac65415a5 100644
--- a/crates/ra_cli/src/analysis_stats.rs
+++ b/crates/ra_cli/src/analysis_stats.rs
@@ -2,8 +2,13 @@
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 hir::{
6 db::{DefDatabase, HirDatabase},
7 AssocItem, Crate, HasSource, HirDisplay, ModuleDef,
8};
9use hir_def::FunctionId;
10use hir_ty::{Ty, TypeWalk};
5use ra_db::SourceDatabaseExt; 11use ra_db::SourceDatabaseExt;
6use ra_hir::{AssocItem, Crate, HasSource, HirDisplay, ModuleDef, Ty, TypeWalk};
7use ra_syntax::AstNode; 12use ra_syntax::AstNode;
8 13
9use crate::{progress_report::ProgressReport, Result, Verbosity}; 14use crate::{progress_report::ProgressReport, Result, Verbosity};
@@ -101,8 +106,9 @@ pub fn run(
101 continue; 106 continue;
102 } 107 }
103 } 108 }
104 let body = f.body(db); 109 let f_id = FunctionId::from(f);
105 let inference_result = f.infer(db); 110 let body = db.body(f_id.into());
111 let inference_result = db.infer(f_id.into());
106 for (expr_id, _) in body.exprs.iter() { 112 for (expr_id, _) in body.exprs.iter() {
107 let ty = &inference_result[expr_id]; 113 let ty = &inference_result[expr_id];
108 num_exprs += 1; 114 num_exprs += 1;
@@ -122,7 +128,8 @@ pub fn run(
122 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) { 128 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr_id) {
123 num_type_mismatches += 1; 129 num_type_mismatches += 1;
124 if verbosity.is_verbose() { 130 if verbosity.is_verbose() {
125 let src = f.body_source_map(db).expr_syntax(expr_id); 131 let (_, sm) = db.body_with_source_map(f_id.into());
132 let src = sm.expr_syntax(expr_id);
126 if let Some(src) = src { 133 if let Some(src) = src {
127 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly 134 // FIXME: it might be nice to have a function (on Analysis?) that goes from Source<T> -> (LineCol, LineCol) directly
128 let original_file = src.file_id.original_file(db); 135 let original_file = src.file_id.original_file(db);
diff --git a/crates/ra_cli/src/main.rs b/crates/ra_cli/src/main.rs
index fe847e611..3808590ab 100644
--- a/crates/ra_cli/src/main.rs
+++ b/crates/ra_cli/src/main.rs
@@ -7,7 +7,6 @@ mod progress_report;
7 7
8use std::{error::Error, fmt::Write, io::Read}; 8use std::{error::Error, fmt::Write, io::Read};
9 9
10use flexi_logger::Logger;
11use pico_args::Arguments; 10use pico_args::Arguments;
12use ra_ide::{file_structure, Analysis}; 11use ra_ide::{file_structure, Analysis};
13use ra_prof::profile; 12use ra_prof::profile;
@@ -32,7 +31,7 @@ impl Verbosity {
32} 31}
33 32
34fn main() -> Result<()> { 33fn main() -> Result<()> {
35 Logger::with_env_or_str("error").start()?; 34 env_logger::try_init()?;
36 35
37 let subcommand = match std::env::args_os().nth(1) { 36 let subcommand = match std::env::args_os().nth(1) {
38 None => { 37 None => {
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs
index b6d851776..2a7ed20d1 100644
--- a/crates/ra_db/src/input.rs
+++ b/crates/ra_db/src/input.rs
@@ -235,6 +235,15 @@ impl FromStr for Edition {
235 } 235 }
236} 236}
237 237
238impl fmt::Display for Edition {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 f.write_str(match self {
241 Edition::Edition2015 => "2015",
242 Edition::Edition2018 => "2018",
243 })
244 }
245}
246
238impl Dependency { 247impl Dependency {
239 pub fn crate_id(&self) -> CrateId { 248 pub fn crate_id(&self) -> CrateId {
240 self.crate_id 249 self.crate_id
diff --git a/crates/ra_hir/Cargo.toml b/crates/ra_hir/Cargo.toml
index e79361e7c..7dc31ad3c 100644
--- a/crates/ra_hir/Cargo.toml
+++ b/crates/ra_hir/Cargo.toml
@@ -10,9 +10,11 @@ doctest = false
10[dependencies] 10[dependencies]
11log = "0.4.5" 11log = "0.4.5"
12rustc-hash = "1.0" 12rustc-hash = "1.0"
13either = "1.5"
13 14
14ra_syntax = { path = "../ra_syntax" } 15ra_syntax = { path = "../ra_syntax" }
15ra_db = { path = "../ra_db" } 16ra_db = { path = "../ra_db" }
17ra_prof = { path = "../ra_prof" }
16hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" } 18hir_expand = { path = "../ra_hir_expand", package = "ra_hir_expand" }
17hir_def = { path = "../ra_hir_def", package = "ra_hir_def" } 19hir_def = { path = "../ra_hir_def", package = "ra_hir_def" }
18hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" } 20hir_ty = { path = "../ra_hir_ty", package = "ra_hir_ty" }
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index 38d66c2a7..bcfc0d03e 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -1,36 +1,35 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2
3pub(crate) mod src;
4
5use std::sync::Arc; 2use std::sync::Arc;
6 3
4use either::Either;
7use hir_def::{ 5use hir_def::{
8 adt::VariantData, 6 adt::VariantData,
9 body::{Body, BodySourceMap},
10 builtin_type::BuiltinType, 7 builtin_type::BuiltinType,
11 docs::Documentation, 8 docs::Documentation,
12 expr::{BindingAnnotation, Pat, PatId}, 9 expr::{BindingAnnotation, Pat, PatId},
10 nameres::ModuleSource,
13 per_ns::PerNs, 11 per_ns::PerNs,
14 resolver::HasResolver, 12 resolver::HasResolver,
15 type_ref::{Mutability, TypeRef}, 13 type_ref::{Mutability, TypeRef},
16 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, FunctionId, GenericDefId, 14 AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId,
17 HasModule, ImplId, LocalEnumVariantId, LocalImportId, LocalModuleId, LocalStructFieldId, 15 LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
18 Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, UnionId, 16 TypeParamId, UnionId,
19}; 17};
20use hir_expand::{ 18use hir_expand::{
21 diagnostics::DiagnosticSink, 19 diagnostics::DiagnosticSink,
22 name::{self, AsName}, 20 name::{name, AsName},
23 AstId, MacroDefId, 21 MacroDefId,
22};
23use hir_ty::{
24 autoderef, display::HirFormatter, expr::ExprValidator, ApplicationTy, Canonical, InEnvironment,
25 TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk,
24}; 26};
25use hir_ty::expr::ExprValidator; 27use ra_db::{CrateId, Edition, FileId};
26use ra_db::{CrateId, Edition, FileId, FilePosition}; 28use ra_syntax::ast;
27use ra_syntax::{ast, AstNode, SyntaxNode};
28 29
29use crate::{ 30use crate::{
30 db::{DefDatabase, HirDatabase}, 31 db::{DefDatabase, HirDatabase},
31 ty::display::HirFormatter, 32 CallableDef, HirDisplay, InFile, Name,
32 ty::{self, InEnvironment, InferenceResult, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk},
33 CallableDef, Either, HirDisplay, Name, Source,
34}; 33};
35 34
36/// hir::Crate describes a single crate. It's the main interface with which 35/// hir::Crate describes a single crate. It's the main interface with which
@@ -38,7 +37,7 @@ use crate::{
38/// root module. 37/// root module.
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 38#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub struct Crate { 39pub struct Crate {
41 pub(crate) crate_id: CrateId, 40 pub(crate) id: CrateId,
42} 41}
43 42
44#[derive(Debug)] 43#[derive(Debug)]
@@ -48,91 +47,43 @@ pub struct CrateDependency {
48} 47}
49 48
50impl Crate { 49impl Crate {
51 pub fn crate_id(self) -> CrateId {
52 self.crate_id
53 }
54
55 pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> { 50 pub fn dependencies(self, db: &impl DefDatabase) -> Vec<CrateDependency> {
56 db.crate_graph() 51 db.crate_graph()
57 .dependencies(self.crate_id) 52 .dependencies(self.id)
58 .map(|dep| { 53 .map(|dep| {
59 let krate = Crate { crate_id: dep.crate_id() }; 54 let krate = Crate { id: dep.crate_id() };
60 let name = dep.as_name(); 55 let name = dep.as_name();
61 CrateDependency { krate, name } 56 CrateDependency { krate, name }
62 }) 57 })
63 .collect() 58 .collect()
64 } 59 }
65 60
66 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> { 61 // FIXME: add `transitive_reverse_dependencies`.
67 let module_id = db.crate_def_map(self.crate_id).root; 62 pub fn reverse_dependencies(self, db: &impl DefDatabase) -> Vec<Crate> {
68 Some(Module::new(self, module_id))
69 }
70
71 pub fn edition(self, db: &impl DefDatabase) -> Edition {
72 let crate_graph = db.crate_graph(); 63 let crate_graph = db.crate_graph();
73 crate_graph.edition(self.crate_id) 64 crate_graph
74 } 65 .iter()
75 66 .filter(|&krate| crate_graph.dependencies(krate).any(|it| it.crate_id == self.id))
76 pub fn all(db: &impl DefDatabase) -> Vec<Crate> { 67 .map(|id| Crate { id })
77 db.crate_graph().iter().map(|crate_id| Crate { crate_id }).collect() 68 .collect()
78 } 69 }
79}
80
81pub enum ModuleSource {
82 SourceFile(ast::SourceFile),
83 Module(ast::Module),
84}
85 70
86impl ModuleSource { 71 pub fn root_module(self, db: &impl DefDatabase) -> Option<Module> {
87 pub fn new( 72 let module_id = db.crate_def_map(self.id).root;
88 db: &impl DefDatabase, 73 Some(Module::new(self, module_id))
89 file_id: Option<FileId>,
90 decl_id: Option<AstId<ast::Module>>,
91 ) -> ModuleSource {
92 match (file_id, decl_id) {
93 (Some(file_id), _) => {
94 let source_file = db.parse(file_id).tree();
95 ModuleSource::SourceFile(source_file)
96 }
97 (None, Some(item_id)) => {
98 let module = item_id.to_node(db);
99 assert!(module.item_list().is_some(), "expected inline module");
100 ModuleSource::Module(module)
101 }
102 (None, None) => panic!(),
103 }
104 } 74 }
105 75
106 // FIXME: this methods do not belong here 76 pub fn root_file(self, db: &impl DefDatabase) -> FileId {
107 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource { 77 db.crate_graph().crate_root(self.id)
108 let parse = db.parse(position.file_id);
109 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
110 parse.tree().syntax(),
111 position.offset,
112 ) {
113 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
114 _ => {
115 let source_file = parse.tree();
116 ModuleSource::SourceFile(source_file)
117 }
118 }
119 } 78 }
120 79
121 pub fn from_child_node(db: &impl DefDatabase, child: Source<&SyntaxNode>) -> ModuleSource { 80 pub fn edition(self, db: &impl DefDatabase) -> Edition {
122 if let Some(m) = 81 let crate_graph = db.crate_graph();
123 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi()) 82 crate_graph.edition(self.id)
124 {
125 ModuleSource::Module(m)
126 } else {
127 let file_id = child.file_id.original_file(db);
128 let source_file = db.parse(file_id).tree();
129 ModuleSource::SourceFile(source_file)
130 }
131 } 83 }
132 84
133 pub fn from_file_id(db: &impl DefDatabase, file_id: FileId) -> ModuleSource { 85 pub fn all(db: &impl DefDatabase) -> Vec<Crate> {
134 let source_file = db.parse(file_id).tree(); 86 db.crate_graph().iter().map(|id| Crate { id }).collect()
135 ModuleSource::SourceFile(source_file)
136 } 87 }
137} 88}
138 89
@@ -171,7 +122,7 @@ pub use hir_def::attr::Attrs;
171 122
172impl Module { 123impl Module {
173 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module { 124 pub(crate) fn new(krate: Crate, crate_module_id: LocalModuleId) -> Module {
174 Module { id: ModuleId { krate: krate.crate_id, local_id: crate_module_id } } 125 Module { id: ModuleId { krate: krate.id, local_id: crate_module_id } }
175 } 126 }
176 127
177 /// Name of this module. 128 /// Name of this module.
@@ -189,7 +140,7 @@ impl Module {
189 140
190 /// Returns the crate this module is part of. 141 /// Returns the crate this module is part of.
191 pub fn krate(self) -> Crate { 142 pub fn krate(self) -> Crate {
192 Crate { crate_id: self.id.krate } 143 Crate { id: self.id.krate }
193 } 144 }
194 145
195 /// Topmost parent of this module. Every module has a `crate_root`, but some 146 /// Topmost parent of this module. Every module has a `crate_root`, but some
@@ -200,13 +151,6 @@ impl Module {
200 self.with_module_id(def_map.root) 151 self.with_module_id(def_map.root)
201 } 152 }
202 153
203 /// Finds a child module with the specified name.
204 pub fn child(self, db: &impl DefDatabase, name: &Name) -> Option<Module> {
205 let def_map = db.crate_def_map(self.id.krate);
206 let child_id = def_map[self.id.local_id].children.get(name)?;
207 Some(self.with_module_id(*child_id))
208 }
209
210 /// Iterates over all child modules. 154 /// Iterates over all child modules.
211 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> { 155 pub fn children(self, db: &impl DefDatabase) -> impl Iterator<Item = Module> {
212 let def_map = db.crate_def_map(self.id.krate); 156 let def_map = db.crate_def_map(self.id.krate);
@@ -236,13 +180,11 @@ impl Module {
236 } 180 }
237 181
238 /// Returns a `ModuleScope`: a set of items, visible in this module. 182 /// Returns a `ModuleScope`: a set of items, visible in this module.
239 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef, Option<Import>)> { 183 pub fn scope(self, db: &impl HirDatabase) -> Vec<(Name, ScopeDef)> {
240 db.crate_def_map(self.id.krate)[self.id.local_id] 184 db.crate_def_map(self.id.krate)[self.id.local_id]
241 .scope 185 .scope
242 .entries() 186 .entries()
243 .map(|(name, res)| { 187 .map(|(name, def)| (name.clone(), def.into()))
244 (name.clone(), res.def.into(), res.import.map(|id| Import { parent: self, id }))
245 })
246 .collect() 188 .collect()
247 } 189 }
248 190
@@ -277,19 +219,14 @@ impl Module {
277 219
278 pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> { 220 pub fn impl_blocks(self, db: &impl DefDatabase) -> Vec<ImplBlock> {
279 let def_map = db.crate_def_map(self.id.krate); 221 let def_map = db.crate_def_map(self.id.krate);
280 def_map[self.id.local_id].impls.iter().copied().map(ImplBlock::from).collect() 222 def_map[self.id.local_id].scope.impls().map(ImplBlock::from).collect()
281 } 223 }
282 224
283 fn with_module_id(self, module_id: LocalModuleId) -> Module { 225 pub(crate) fn with_module_id(self, module_id: LocalModuleId) -> Module {
284 Module::new(self.krate(), module_id) 226 Module::new(self.krate(), module_id)
285 } 227 }
286} 228}
287 229
288pub struct Import {
289 pub(crate) parent: Module,
290 pub(crate) id: LocalImportId,
291}
292
293#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 230#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct StructField { 231pub struct StructField {
295 pub(crate) parent: VariantDef, 232 pub(crate) parent: VariantDef,
@@ -307,8 +244,10 @@ impl StructField {
307 self.parent.variant_data(db).fields()[self.id].name.clone() 244 self.parent.variant_data(db).fields()[self.id].name.clone()
308 } 245 }
309 246
310 pub fn ty(&self, db: &impl HirDatabase) -> Ty { 247 pub fn ty(&self, db: &impl HirDatabase) -> Type {
311 db.field_types(self.parent.into())[self.id].clone() 248 let var_id = self.parent.into();
249 let ty = db.field_types(var_id)[self.id].clone();
250 Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty)
312 } 251 }
313 252
314 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef { 253 pub fn parent_def(&self, _db: &impl HirDatabase) -> VariantDef {
@@ -323,7 +262,7 @@ pub struct Struct {
323 262
324impl Struct { 263impl Struct {
325 pub fn module(self, db: &impl DefDatabase) -> Module { 264 pub fn module(self, db: &impl DefDatabase) -> Module {
326 Module { id: self.id.module(db) } 265 Module { id: self.id.lookup(db).container.module(db) }
327 } 266 }
328 267
329 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 268 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -343,21 +282,8 @@ impl Struct {
343 .collect() 282 .collect()
344 } 283 }
345 284
346 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
347 db.struct_data(self.id.into())
348 .variant_data
349 .fields()
350 .iter()
351 .find(|(_id, data)| data.name == *name)
352 .map(|(id, _)| StructField { parent: self.into(), id })
353 }
354
355 pub fn ty(self, db: &impl HirDatabase) -> Type { 285 pub fn ty(self, db: &impl HirDatabase) -> Type {
356 Type::from_def(db, self.id.module(db).krate, self.id) 286 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
357 }
358
359 pub fn constructor_ty(self, db: &impl HirDatabase) -> Ty {
360 db.value_ty(self.id.into())
361 } 287 }
362 288
363 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 289 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
@@ -376,11 +302,11 @@ impl Union {
376 } 302 }
377 303
378 pub fn module(self, db: &impl DefDatabase) -> Module { 304 pub fn module(self, db: &impl DefDatabase) -> Module {
379 Module { id: self.id.module(db) } 305 Module { id: self.id.lookup(db).container.module(db) }
380 } 306 }
381 307
382 pub fn ty(self, db: &impl HirDatabase) -> Type { 308 pub fn ty(self, db: &impl HirDatabase) -> Type {
383 Type::from_def(db, self.id.module(db).krate, self.id) 309 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
384 } 310 }
385 311
386 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> { 312 pub fn fields(self, db: &impl HirDatabase) -> Vec<StructField> {
@@ -392,15 +318,6 @@ impl Union {
392 .collect() 318 .collect()
393 } 319 }
394 320
395 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
396 db.union_data(self.id)
397 .variant_data
398 .fields()
399 .iter()
400 .find(|(_id, data)| data.name == *name)
401 .map(|(id, _)| StructField { parent: self.into(), id })
402 }
403
404 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 321 fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
405 db.union_data(self.id).variant_data.clone() 322 db.union_data(self.id).variant_data.clone()
406 } 323 }
@@ -413,7 +330,7 @@ pub struct Enum {
413 330
414impl Enum { 331impl Enum {
415 pub fn module(self, db: &impl DefDatabase) -> Module { 332 pub fn module(self, db: &impl DefDatabase) -> Module {
416 Module { id: self.id.module(db) } 333 Module { id: self.id.lookup(db).container.module(db) }
417 } 334 }
418 335
419 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 336 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
@@ -432,13 +349,8 @@ impl Enum {
432 .collect() 349 .collect()
433 } 350 }
434 351
435 pub fn variant(self, db: &impl DefDatabase, name: &Name) -> Option<EnumVariant> {
436 let id = db.enum_data(self.id).variant(name)?;
437 Some(EnumVariant { parent: self, id })
438 }
439
440 pub fn ty(self, db: &impl HirDatabase) -> Type { 352 pub fn ty(self, db: &impl HirDatabase) -> Type {
441 Type::from_def(db, self.id.module(db).krate, self.id) 353 Type::from_def(db, self.id.lookup(db).container.module(db).krate, self.id)
442 } 354 }
443} 355}
444 356
@@ -468,14 +380,6 @@ impl EnumVariant {
468 .collect() 380 .collect()
469 } 381 }
470 382
471 pub fn field(self, db: &impl HirDatabase, name: &Name) -> Option<StructField> {
472 self.variant_data(db)
473 .fields()
474 .iter()
475 .find(|(_id, data)| data.name == *name)
476 .map(|(id, _)| StructField { parent: self.into(), id })
477 }
478
479 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> { 383 pub(crate) fn variant_data(self, db: &impl DefDatabase) -> Arc<VariantData> {
480 db.enum_data(self.parent.id).variants[self.id].variant_data.clone() 384 db.enum_data(self.parent.id).variants[self.id].variant_data.clone()
481 } 385 }
@@ -593,48 +497,8 @@ impl Function {
593 db.function_data(self.id).params.clone() 497 db.function_data(self.id).params.clone()
594 } 498 }
595 499
596 pub fn body_source_map(self, db: &impl HirDatabase) -> Arc<BodySourceMap> {
597 db.body_with_source_map(self.id.into()).1
598 }
599
600 pub fn body(self, db: &impl HirDatabase) -> Arc<Body> {
601 db.body(self.id.into())
602 }
603
604 pub fn ty(self, db: &impl HirDatabase) -> Ty {
605 db.value_ty(self.id.into())
606 }
607
608 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
609 db.infer(self.id.into())
610 }
611
612 /// The containing impl block, if this is a method.
613 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
614 match self.container(db) {
615 Some(Container::ImplBlock(it)) => Some(it),
616 _ => None,
617 }
618 }
619
620 /// The containing trait, if this is a trait method definition.
621 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
622 match self.container(db) {
623 Some(Container::Trait(it)) => Some(it),
624 _ => None,
625 }
626 }
627
628 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
629 match self.id.lookup(db).container {
630 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
631 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
632 ContainerId::ModuleId(_) => None,
633 }
634 }
635
636 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) { 500 pub fn diagnostics(self, db: &impl HirDatabase, sink: &mut DiagnosticSink) {
637 let infer = self.infer(db); 501 let infer = db.infer(self.id.into());
638 infer.add_diagnostics(db, self.id, sink); 502 infer.add_diagnostics(db, self.id, sink);
639 let mut validator = ExprValidator::new(self.id, infer, sink); 503 let mut validator = ExprValidator::new(self.id, infer, sink);
640 validator.validate_body(db); 504 validator.validate_body(db);
@@ -658,34 +522,6 @@ impl Const {
658 pub fn name(self, db: &impl HirDatabase) -> Option<Name> { 522 pub fn name(self, db: &impl HirDatabase) -> Option<Name> {
659 db.const_data(self.id).name.clone() 523 db.const_data(self.id).name.clone()
660 } 524 }
661
662 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
663 db.infer(self.id.into())
664 }
665
666 /// The containing impl block, if this is a type alias.
667 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
668 match self.container(db) {
669 Some(Container::ImplBlock(it)) => Some(it),
670 _ => None,
671 }
672 }
673
674 /// The containing trait, if this is a trait type alias definition.
675 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
676 match self.container(db) {
677 Some(Container::Trait(it)) => Some(it),
678 _ => None,
679 }
680 }
681
682 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
683 match self.id.lookup(db).container {
684 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
685 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
686 ContainerId::ModuleId(_) => None,
687 }
688 }
689} 525}
690 526
691#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 527#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -701,10 +537,6 @@ impl Static {
701 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> { 537 pub fn krate(self, db: &impl DefDatabase) -> Option<Crate> {
702 Some(self.module(db).krate()) 538 Some(self.module(db).krate())
703 } 539 }
704
705 pub fn infer(self, db: &impl HirDatabase) -> Arc<InferenceResult> {
706 db.infer(self.id.into())
707 }
708} 540}
709 541
710#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 542#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -714,7 +546,7 @@ pub struct Trait {
714 546
715impl Trait { 547impl Trait {
716 pub fn module(self, db: &impl DefDatabase) -> Module { 548 pub fn module(self, db: &impl DefDatabase) -> Module {
717 Module { id: self.id.module(db) } 549 Module { id: self.id.lookup(db).container.module(db) }
718 } 550 }
719 551
720 pub fn name(self, db: &impl DefDatabase) -> Name { 552 pub fn name(self, db: &impl DefDatabase) -> Name {
@@ -749,30 +581,6 @@ impl TypeAlias {
749 Some(self.module(db).krate()) 581 Some(self.module(db).krate())
750 } 582 }
751 583
752 /// The containing impl block, if this is a type alias.
753 pub fn impl_block(self, db: &impl DefDatabase) -> Option<ImplBlock> {
754 match self.container(db) {
755 Some(Container::ImplBlock(it)) => Some(it),
756 _ => None,
757 }
758 }
759
760 /// The containing trait, if this is a trait type alias definition.
761 pub fn parent_trait(self, db: &impl DefDatabase) -> Option<Trait> {
762 match self.container(db) {
763 Some(Container::Trait(it)) => Some(it),
764 _ => None,
765 }
766 }
767
768 pub fn container(self, db: &impl DefDatabase) -> Option<Container> {
769 match self.id.lookup(db).container {
770 ContainerId::TraitId(it) => Some(Container::Trait(it.into())),
771 ContainerId::ImplId(it) => Some(Container::ImplBlock(it.into())),
772 ContainerId::ModuleId(_) => None,
773 }
774 }
775
776 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> { 584 pub fn type_ref(self, db: &impl DefDatabase) -> Option<TypeRef> {
777 db.type_alias_data(self.id).type_ref.clone() 585 db.type_alias_data(self.id).type_ref.clone()
778 } 586 }
@@ -791,14 +599,6 @@ pub struct MacroDef {
791 pub(crate) id: MacroDefId, 599 pub(crate) id: MacroDefId,
792} 600}
793 601
794impl MacroDef {}
795
796pub enum Container {
797 Trait(Trait),
798 ImplBlock(ImplBlock),
799}
800impl_froms!(Container: Trait, ImplBlock);
801
802#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 602#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
803pub enum AssocItem { 603pub enum AssocItem {
804 Function(Function), 604 Function(Function),
@@ -819,15 +619,6 @@ impl AssocItem {
819 AssocItem::TypeAlias(t) => t.module(db), 619 AssocItem::TypeAlias(t) => t.module(db),
820 } 620 }
821 } 621 }
822
823 pub fn container(self, db: &impl DefDatabase) -> Container {
824 match self {
825 AssocItem::Function(f) => f.container(db),
826 AssocItem::Const(c) => c.container(db),
827 AssocItem::TypeAlias(t) => t.container(db),
828 }
829 .expect("AssocItem without container")
830 }
831} 622}
832 623
833#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)] 624#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
@@ -869,7 +660,7 @@ impl Local {
869 } 660 }
870 661
871 pub fn is_self(self, db: &impl HirDatabase) -> bool { 662 pub fn is_self(self, db: &impl HirDatabase) -> bool {
872 self.name(db) == Some(name::SELF_PARAM) 663 self.name(db) == Some(name![self])
873 } 664 }
874 665
875 pub fn is_mut(self, db: &impl HirDatabase) -> bool { 666 pub fn is_mut(self, db: &impl HirDatabase) -> bool {
@@ -901,18 +692,30 @@ impl Local {
901 Type { krate, ty: InEnvironment { value: ty, environment } } 692 Type { krate, ty: InEnvironment { value: ty, environment } }
902 } 693 }
903 694
904 pub fn source(self, db: &impl HirDatabase) -> Source<Either<ast::BindPat, ast::SelfParam>> { 695 pub fn source(self, db: &impl HirDatabase) -> InFile<Either<ast::BindPat, ast::SelfParam>> {
905 let (_body, source_map) = db.body_with_source_map(self.parent.into()); 696 let (_body, source_map) = db.body_with_source_map(self.parent.into());
906 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm... 697 let src = source_map.pat_syntax(self.pat_id).unwrap(); // Hmm...
907 let root = src.file_syntax(db); 698 let root = src.file_syntax(db);
908 src.map(|ast| ast.map(|it| it.cast().unwrap().to_node(&root), |it| it.to_node(&root))) 699 src.map(|ast| {
700 ast.map_left(|it| it.cast().unwrap().to_node(&root)).map_right(|it| it.to_node(&root))
701 })
909 } 702 }
910} 703}
911 704
912#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 705#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
913pub struct GenericParam { 706pub struct TypeParam {
914 pub(crate) parent: GenericDefId, 707 pub(crate) id: TypeParamId,
915 pub(crate) idx: u32, 708}
709
710impl TypeParam {
711 pub fn name(self, db: &impl HirDatabase) -> Name {
712 let params = db.generic_params(self.id.parent);
713 params.types[self.id.local_id].name.clone()
714 }
715
716 pub fn module(self, db: &impl HirDatabase) -> Module {
717 self.id.parent.module(db).into()
718 }
916} 719}
917 720
918#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 721#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -922,11 +725,11 @@ pub struct ImplBlock {
922 725
923impl ImplBlock { 726impl ImplBlock {
924 pub fn all_in_crate(db: &impl HirDatabase, krate: Crate) -> Vec<ImplBlock> { 727 pub fn all_in_crate(db: &impl HirDatabase, krate: Crate) -> Vec<ImplBlock> {
925 let impls = db.impls_in_crate(krate.crate_id); 728 let impls = db.impls_in_crate(krate.id);
926 impls.all_impls().map(Self::from).collect() 729 impls.all_impls().map(Self::from).collect()
927 } 730 }
928 pub fn for_trait(db: &impl HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplBlock> { 731 pub fn for_trait(db: &impl HirDatabase, krate: Crate, trait_: Trait) -> Vec<ImplBlock> {
929 let impls = db.impls_in_crate(krate.crate_id); 732 let impls = db.impls_in_crate(krate.id);
930 impls.lookup_impl_blocks_for_trait(trait_.id).map(Self::from).collect() 733 impls.lookup_impl_blocks_for_trait(trait_.id).map(Self::from).collect()
931 } 734 }
932 735
@@ -943,7 +746,10 @@ impl ImplBlock {
943 let resolver = self.id.resolver(db); 746 let resolver = self.id.resolver(db);
944 let environment = TraitEnvironment::lower(db, &resolver); 747 let environment = TraitEnvironment::lower(db, &resolver);
945 let ty = Ty::from_hir(db, &resolver, &impl_data.target_type); 748 let ty = Ty::from_hir(db, &resolver, &impl_data.target_type);
946 Type { krate: self.id.module(db).krate, ty: InEnvironment { value: ty, environment } } 749 Type {
750 krate: self.id.lookup(db).container.module(db).krate,
751 ty: InEnvironment { value: ty, environment },
752 }
947 } 753 }
948 754
949 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> { 755 pub fn items(&self, db: &impl DefDatabase) -> Vec<AssocItem> {
@@ -955,11 +761,11 @@ impl ImplBlock {
955 } 761 }
956 762
957 pub fn module(&self, db: &impl DefDatabase) -> Module { 763 pub fn module(&self, db: &impl DefDatabase) -> Module {
958 self.id.module(db).into() 764 self.id.lookup(db).container.module(db).into()
959 } 765 }
960 766
961 pub fn krate(&self, db: &impl DefDatabase) -> Crate { 767 pub fn krate(&self, db: &impl DefDatabase) -> Crate {
962 Crate { crate_id: self.module(db).id.krate } 768 Crate { id: self.module(db).id.krate }
963 } 769 }
964} 770}
965 771
@@ -970,15 +776,19 @@ pub struct Type {
970} 776}
971 777
972impl Type { 778impl Type {
779 fn new(db: &impl HirDatabase, krate: CrateId, lexical_env: impl HasResolver, ty: Ty) -> Type {
780 let resolver = lexical_env.resolver(db);
781 let environment = TraitEnvironment::lower(db, &resolver);
782 Type { krate, ty: InEnvironment { value: ty, environment } }
783 }
784
973 fn from_def( 785 fn from_def(
974 db: &impl HirDatabase, 786 db: &impl HirDatabase,
975 krate: CrateId, 787 krate: CrateId,
976 def: impl HasResolver + Into<TyDefId>, 788 def: impl HasResolver + Into<TyDefId>,
977 ) -> Type { 789 ) -> Type {
978 let resolver = def.resolver(db);
979 let environment = TraitEnvironment::lower(db, &resolver);
980 let ty = db.ty(def.into()); 790 let ty = db.ty(def.into());
981 Type { krate, ty: InEnvironment { value: ty, environment } } 791 Type::new(db, krate, def, ty)
982 } 792 }
983 793
984 pub fn is_bool(&self) -> bool { 794 pub fn is_bool(&self) -> bool {
@@ -1028,7 +838,7 @@ impl Type {
1028 pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> { 838 pub fn fields(&self, db: &impl HirDatabase) -> Vec<(StructField, Type)> {
1029 if let Ty::Apply(a_ty) = &self.ty.value { 839 if let Ty::Apply(a_ty) = &self.ty.value {
1030 match a_ty.ctor { 840 match a_ty.ctor {
1031 ty::TypeCtor::Adt(AdtId::StructId(s)) => { 841 TypeCtor::Adt(AdtId::StructId(s)) => {
1032 let var_def = s.into(); 842 let var_def = s.into();
1033 return db 843 return db
1034 .field_types(var_def) 844 .field_types(var_def)
@@ -1050,7 +860,7 @@ impl Type {
1050 let mut res = Vec::new(); 860 let mut res = Vec::new();
1051 if let Ty::Apply(a_ty) = &self.ty.value { 861 if let Ty::Apply(a_ty) = &self.ty.value {
1052 match a_ty.ctor { 862 match a_ty.ctor {
1053 ty::TypeCtor::Tuple { .. } => { 863 TypeCtor::Tuple { .. } => {
1054 for ty in a_ty.parameters.iter() { 864 for ty in a_ty.parameters.iter() {
1055 let ty = ty.clone().subst(&a_ty.parameters); 865 let ty = ty.clone().subst(&a_ty.parameters);
1056 res.push(self.derived(ty)); 866 res.push(self.derived(ty));
@@ -1069,11 +879,16 @@ impl Type {
1069 ) -> Vec<(StructField, Type)> { 879 ) -> Vec<(StructField, Type)> {
1070 // FIXME: check that ty and def match 880 // FIXME: check that ty and def match
1071 match &self.ty.value { 881 match &self.ty.value {
1072 Ty::Apply(a_ty) => def 882 Ty::Apply(a_ty) => {
1073 .fields(db) 883 let field_types = db.field_types(def.into());
1074 .into_iter() 884 def.fields(db)
1075 .map(|it| (it, self.derived(it.ty(db).subst(&a_ty.parameters)))) 885 .into_iter()
1076 .collect(), 886 .map(|it| {
887 let ty = field_types[it.id].clone().subst(&a_ty.parameters);
888 (it, self.derived(ty))
889 })
890 .collect()
891 }
1077 _ => Vec::new(), 892 _ => Vec::new(),
1078 } 893 }
1079 } 894 }
@@ -1081,10 +896,10 @@ impl Type {
1081 pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a { 896 pub fn autoderef<'a>(&'a self, db: &'a impl HirDatabase) -> impl Iterator<Item = Type> + 'a {
1082 // There should be no inference vars in types passed here 897 // There should be no inference vars in types passed here
1083 // FIXME check that? 898 // FIXME check that?
1084 let canonical = crate::ty::Canonical { value: self.ty.value.clone(), num_vars: 0 }; 899 let canonical = Canonical { value: self.ty.value.clone(), num_vars: 0 };
1085 let environment = self.ty.environment.clone(); 900 let environment = self.ty.environment.clone();
1086 let ty = InEnvironment { value: canonical, environment: environment.clone() }; 901 let ty = InEnvironment { value: canonical, environment: environment.clone() };
1087 ty::autoderef(db, Some(self.krate), ty) 902 autoderef(db, Some(self.krate), ty)
1088 .map(|canonical| canonical.value) 903 .map(|canonical| canonical.value)
1089 .map(move |ty| self.derived(ty)) 904 .map(move |ty| self.derived(ty))
1090 } 905 }
@@ -1097,7 +912,7 @@ impl Type {
1097 krate: Crate, 912 krate: Crate,
1098 mut callback: impl FnMut(AssocItem) -> Option<T>, 913 mut callback: impl FnMut(AssocItem) -> Option<T>,
1099 ) -> Option<T> { 914 ) -> Option<T> {
1100 for krate in self.ty.value.def_crates(db, krate.crate_id)? { 915 for krate in self.ty.value.def_crates(db, krate.id)? {
1101 let impls = db.impls_in_crate(krate); 916 let impls = db.impls_in_crate(krate);
1102 917
1103 for impl_block in impls.lookup_impl_blocks(&self.ty.value) { 918 for impl_block in impls.lookup_impl_blocks(&self.ty.value) {
@@ -1111,11 +926,6 @@ impl Type {
1111 None 926 None
1112 } 927 }
1113 928
1114 // FIXME: remove
1115 pub fn into_ty(self) -> Ty {
1116 self.ty.value
1117 }
1118
1119 pub fn as_adt(&self) -> Option<Adt> { 929 pub fn as_adt(&self) -> Option<Adt> {
1120 let (adt, _subst) = self.ty.value.as_adt()?; 930 let (adt, _subst) = self.ty.value.as_adt()?;
1121 Some(adt.into()) 931 Some(adt.into())
@@ -1124,15 +934,14 @@ impl Type {
1124 // FIXME: provide required accessors such that it becomes implementable from outside. 934 // FIXME: provide required accessors such that it becomes implementable from outside.
1125 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool { 935 pub fn is_equal_for_find_impls(&self, other: &Type) -> bool {
1126 match (&self.ty.value, &other.ty.value) { 936 match (&self.ty.value, &other.ty.value) {
1127 (Ty::Apply(a_original_ty), Ty::Apply(ty::ApplicationTy { ctor, parameters })) => { 937 (Ty::Apply(a_original_ty), Ty::Apply(ApplicationTy { ctor, parameters })) => match ctor
1128 match ctor { 938 {
1129 TypeCtor::Ref(..) => match parameters.as_single() { 939 TypeCtor::Ref(..) => match parameters.as_single() {
1130 Ty::Apply(a_ty) => a_original_ty.ctor == a_ty.ctor, 940 Ty::Apply(a_ty) => a_original_ty.ctor == a_ty.ctor,
1131 _ => false, 941 _ => false,
1132 }, 942 },
1133 _ => a_original_ty.ctor == *ctor, 943 _ => a_original_ty.ctor == *ctor,
1134 } 944 },
1135 }
1136 _ => false, 945 _ => false,
1137 } 946 }
1138 } 947 }
@@ -1155,7 +964,7 @@ impl HirDisplay for Type {
1155pub enum ScopeDef { 964pub enum ScopeDef {
1156 ModuleDef(ModuleDef), 965 ModuleDef(ModuleDef),
1157 MacroDef(MacroDef), 966 MacroDef(MacroDef),
1158 GenericParam(GenericParam), 967 GenericParam(TypeParam),
1159 ImplSelfType(ImplBlock), 968 ImplSelfType(ImplBlock),
1160 AdtSelfType(Adt), 969 AdtSelfType(Adt),
1161 Local(Local), 970 Local(Local),
diff --git a/crates/ra_hir/src/code_model/src.rs b/crates/ra_hir/src/code_model/src.rs
deleted file mode 100644
index bf3ee0834..000000000
--- a/crates/ra_hir/src/code_model/src.rs
+++ /dev/null
@@ -1,128 +0,0 @@
1//! FIXME: write short doc here
2
3use hir_def::{AstItemDef, HasChildSource, HasSource as _, Lookup, VariantId};
4use hir_expand::either::Either;
5use ra_syntax::ast;
6
7use crate::{
8 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, Import, MacroDef,
9 Module, ModuleSource, Static, Struct, StructField, Trait, TypeAlias, Union,
10};
11
12pub use hir_expand::Source;
13
14pub trait HasSource {
15 type Ast;
16 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast>;
17}
18
19/// NB: Module is !HasSource, because it has two source nodes at the same time:
20/// definition and declaration.
21impl Module {
22 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
23 pub fn definition_source(self, db: &impl DefDatabase) -> Source<ModuleSource> {
24 let def_map = db.crate_def_map(self.id.krate);
25 let src = def_map[self.id.local_id].definition_source(db);
26 src.map(|it| match it {
27 Either::A(it) => ModuleSource::SourceFile(it),
28 Either::B(it) => ModuleSource::Module(it),
29 })
30 }
31
32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
33 /// `None` for the crate root.
34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<Source<ast::Module>> {
35 let def_map = db.crate_def_map(self.id.krate);
36 def_map[self.id.local_id].declaration_source(db)
37 }
38}
39
40impl HasSource for StructField {
41 type Ast = FieldSource;
42 fn source(self, db: &impl DefDatabase) -> Source<FieldSource> {
43 let var = VariantId::from(self.parent);
44 let src = var.child_source(db);
45 src.map(|it| match it[self.id].clone() {
46 Either::A(it) => FieldSource::Pos(it),
47 Either::B(it) => FieldSource::Named(it),
48 })
49 }
50}
51impl HasSource for Struct {
52 type Ast = ast::StructDef;
53 fn source(self, db: &impl DefDatabase) -> Source<ast::StructDef> {
54 self.id.source(db)
55 }
56}
57impl HasSource for Union {
58 type Ast = ast::UnionDef;
59 fn source(self, db: &impl DefDatabase) -> Source<ast::UnionDef> {
60 self.id.source(db)
61 }
62}
63impl HasSource for Enum {
64 type Ast = ast::EnumDef;
65 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumDef> {
66 self.id.source(db)
67 }
68}
69impl HasSource for EnumVariant {
70 type Ast = ast::EnumVariant;
71 fn source(self, db: &impl DefDatabase) -> Source<ast::EnumVariant> {
72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
73 }
74}
75impl HasSource for Function {
76 type Ast = ast::FnDef;
77 fn source(self, db: &impl DefDatabase) -> Source<ast::FnDef> {
78 self.id.lookup(db).source(db)
79 }
80}
81impl HasSource for Const {
82 type Ast = ast::ConstDef;
83 fn source(self, db: &impl DefDatabase) -> Source<ast::ConstDef> {
84 self.id.lookup(db).source(db)
85 }
86}
87impl HasSource for Static {
88 type Ast = ast::StaticDef;
89 fn source(self, db: &impl DefDatabase) -> Source<ast::StaticDef> {
90 self.id.lookup(db).source(db)
91 }
92}
93impl HasSource for Trait {
94 type Ast = ast::TraitDef;
95 fn source(self, db: &impl DefDatabase) -> Source<ast::TraitDef> {
96 self.id.source(db)
97 }
98}
99impl HasSource for TypeAlias {
100 type Ast = ast::TypeAliasDef;
101 fn source(self, db: &impl DefDatabase) -> Source<ast::TypeAliasDef> {
102 self.id.lookup(db).source(db)
103 }
104}
105impl HasSource for MacroDef {
106 type Ast = ast::MacroCall;
107 fn source(self, db: &impl DefDatabase) -> Source<ast::MacroCall> {
108 Source { file_id: self.id.ast_id.file_id(), value: self.id.ast_id.to_node(db) }
109 }
110}
111impl HasSource for ImplBlock {
112 type Ast = ast::ImplBlock;
113 fn source(self, db: &impl DefDatabase) -> Source<ast::ImplBlock> {
114 self.id.source(db)
115 }
116}
117impl HasSource for Import {
118 type Ast = Either<ast::UseTree, ast::ExternCrateItem>;
119
120 /// Returns the syntax of the last path segment corresponding to this import
121 fn source(self, db: &impl DefDatabase) -> Source<Self::Ast> {
122 let src = self.parent.definition_source(db);
123 let (_, source_map) = db.raw_items_with_source_map(src.file_id);
124 let root = db.parse_or_expand(src.file_id).unwrap();
125 let ptr = source_map.get(self.id);
126 src.with_value(ptr.map(|it| it.to_node(&root), |it| it.to_node(&root)))
127 }
128}
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs
index bfae3660b..f5ffd64fa 100644
--- a/crates/ra_hir/src/db.rs
+++ b/crates/ra_hir/src/db.rs
@@ -4,8 +4,8 @@ pub use hir_def::db::{
4 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery, 4 BodyQuery, BodyWithSourceMapQuery, ConstDataQuery, CrateDefMapQuery, CrateLangItemsQuery,
5 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery, 5 DefDatabase, DefDatabaseStorage, DocumentationQuery, EnumDataQuery, ExprScopesQuery,
6 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage, 6 FunctionDataQuery, GenericParamsQuery, ImplDataQuery, InternDatabase, InternDatabaseStorage,
7 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, RawItemsWithSourceMapQuery, 7 LangItemQuery, ModuleLangItemsQuery, RawItemsQuery, StaticDataQuery, StructDataQuery,
8 StaticDataQuery, StructDataQuery, TraitDataQuery, TypeAliasDataQuery, 8 TraitDataQuery, TypeAliasDataQuery,
9}; 9};
10pub use hir_expand::db::{ 10pub use hir_expand::db::{
11 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery, 11 AstDatabase, AstDatabaseStorage, AstIdMapQuery, MacroArgQuery, MacroDefQuery, MacroExpandQuery,
diff --git a/crates/ra_hir/src/debug.rs b/crates/ra_hir/src/debug.rs
deleted file mode 100644
index 7a2810f71..000000000
--- a/crates/ra_hir/src/debug.rs
+++ /dev/null
@@ -1,94 +0,0 @@
1//! XXX: This does not work at the moment.
2//!
3//! printf debugging infrastructure for rust-analyzer.
4//!
5//! When you print a hir type, like a module, using `eprintln!("{:?}", module)`,
6//! you usually get back a numeric ID, which doesn't tell you much:
7//! `Module(92)`.
8//!
9//! This module adds convenience `debug` methods to various types, which resolve
10//! the id to a human-readable location info:
11//!
12//! ```not_rust
13//! eprintln!("{:?}", module.debug(db));
14//! =>
15//! Module { name: collections, path: "liballoc/collections/mod.rs" }
16//! ```
17//!
18//! Note that to get this info, we might need to execute queries! So
19//!
20//! * don't use the `debug` methods for logging
21//! * when debugging, be aware that interference is possible.
22
23use std::fmt;
24
25use hir_expand::HirFileId;
26use ra_db::{CrateId, FileId};
27
28use crate::{db::HirDatabase, Crate, Module, Name};
29
30impl Crate {
31 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
32 debug_fn(move |fmt| db.debug_crate(self, fmt))
33 }
34}
35
36impl Module {
37 pub fn debug(self, db: &impl HirDebugDatabase) -> impl fmt::Debug + '_ {
38 debug_fn(move |fmt| db.debug_module(self, fmt))
39 }
40}
41
42pub trait HirDebugHelper: HirDatabase {
43 fn crate_name(&self, _krate: CrateId) -> Option<String> {
44 None
45 }
46 fn file_path(&self, _file_id: FileId) -> Option<String> {
47 None
48 }
49}
50
51pub trait HirDebugDatabase {
52 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
53 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
54 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result;
55}
56
57impl<DB: HirDebugHelper> HirDebugDatabase for DB {
58 fn debug_crate(&self, krate: Crate, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
59 let mut builder = fmt.debug_tuple("Crate");
60 match self.crate_name(krate.crate_id) {
61 Some(name) => builder.field(&name),
62 None => builder.field(&krate.crate_id),
63 }
64 .finish()
65 }
66
67 fn debug_module(&self, module: Module, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
68 let file_id = module.definition_source(self).file_id.original_file(self);
69 let path = self.file_path(file_id).unwrap_or_else(|| "N/A".to_string());
70 fmt.debug_struct("Module")
71 .field("name", &module.name(self).unwrap_or_else(Name::missing))
72 .field("path", &path)
73 .finish()
74 }
75
76 fn debug_hir_file_id(&self, file_id: HirFileId, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
77 let original = file_id.original_file(self);
78 let path = self.file_path(original).unwrap_or_else(|| "N/A".to_string());
79 let is_macro = file_id != original.into();
80 fmt.debug_struct("HirFileId").field("path", &path).field("macro", &is_macro).finish()
81 }
82}
83
84fn debug_fn(f: impl Fn(&mut fmt::Formatter<'_>) -> fmt::Result) -> impl fmt::Debug {
85 struct DebugFn<F>(F);
86
87 impl<F: Fn(&mut fmt::Formatter<'_>) -> fmt::Result> fmt::Debug for DebugFn<F> {
88 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
89 (&self.0)(fmt)
90 }
91 }
92
93 DebugFn(f)
94}
diff --git a/crates/ra_hir/src/from_id.rs b/crates/ra_hir/src/from_id.rs
index e96a18d12..75a1a7772 100644
--- a/crates/ra_hir/src/from_id.rs
+++ b/crates/ra_hir/src/from_id.rs
@@ -9,16 +9,10 @@ use hir_def::{
9}; 9};
10 10
11use crate::{ 11use crate::{
12 Adt, AssocItem, AttrDef, Crate, DefWithBody, EnumVariant, GenericDef, ModuleDef, StructField, 12 Adt, AssocItem, AttrDef, DefWithBody, EnumVariant, GenericDef, ModuleDef, StructField,
13 VariantDef, 13 VariantDef,
14}; 14};
15 15
16impl From<ra_db::CrateId> for Crate {
17 fn from(crate_id: ra_db::CrateId) -> Self {
18 Crate { crate_id }
19 }
20}
21
22macro_rules! from_id { 16macro_rules! from_id {
23 ($(($id:path, $ty:path)),*) => {$( 17 ($(($id:path, $ty:path)),*) => {$(
24 impl From<$id> for $ty { 18 impl From<$id> for $ty {
@@ -26,10 +20,16 @@ macro_rules! from_id {
26 $ty { id } 20 $ty { id }
27 } 21 }
28 } 22 }
23 impl From<$ty> for $id {
24 fn from(ty: $ty) -> $id {
25 ty.id
26 }
27 }
29 )*} 28 )*}
30} 29}
31 30
32from_id![ 31from_id![
32 (ra_db::CrateId, crate::Crate),
33 (hir_def::ModuleId, crate::Module), 33 (hir_def::ModuleId, crate::Module),
34 (hir_def::StructId, crate::Struct), 34 (hir_def::StructId, crate::Struct),
35 (hir_def::UnionId, crate::Union), 35 (hir_def::UnionId, crate::Union),
diff --git a/crates/ra_hir/src/from_source.rs b/crates/ra_hir/src/from_source.rs
index 9f7c22b21..6314be8d4 100644
--- a/crates/ra_hir/src/from_source.rs
+++ b/crates/ra_hir/src/from_source.rs
@@ -1,219 +1,140 @@
1//! FIXME: write short doc here 1//! Finds a corresponding hir data structure for a syntax node in a specific
2//! file.
2 3
3use hir_def::{AstItemDef, LocationCtx, ModuleId}; 4use hir_def::{
5 child_by_source::ChildBySource, dyn_map::DynMap, keys, keys::Key, nameres::ModuleSource,
6 ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, GenericDefId, ImplId, ModuleId,
7 StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
8};
4use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind}; 9use hir_expand::{name::AsName, AstId, MacroDefId, MacroDefKind};
10use ra_db::FileId;
11use ra_prof::profile;
5use ra_syntax::{ 12use ra_syntax::{
6 ast::{self, AstNode, NameOwner}, 13 ast::{self, AstNode, NameOwner},
7 match_ast, AstPtr, SyntaxNode, 14 match_ast, SyntaxNode,
8}; 15};
9 16
10use crate::{ 17use crate::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 18 db::{DefDatabase, HirDatabase},
12 AssocItem, Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, HasSource, ImplBlock, 19 Const, DefWithBody, Enum, EnumVariant, FieldSource, Function, ImplBlock, InFile, Local,
13 Local, MacroDef, Module, ModuleDef, ModuleSource, Source, Static, Struct, StructField, Trait, 20 MacroDef, Module, Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
14 TypeAlias, Union, VariantDef,
15}; 21};
16 22
17pub trait FromSource: Sized { 23pub trait FromSource: Sized {
18 type Ast; 24 type Ast;
19 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self>; 25 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self>;
20} 26}
21 27
22impl FromSource for Struct { 28pub trait FromSourceByContainer: Sized {
23 type Ast = ast::StructDef; 29 type Ast: AstNode + 'static;
24 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 30 type Id: Copy + 'static;
25 let id = from_source(db, src)?; 31 const KEY: Key<Self::Ast, Self::Id>;
26 Some(Struct { id })
27 }
28}
29impl FromSource for Union {
30 type Ast = ast::UnionDef;
31 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
32 let id = from_source(db, src)?;
33 Some(Union { id })
34 }
35}
36impl FromSource for Enum {
37 type Ast = ast::EnumDef;
38 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
39 let id = from_source(db, src)?;
40 Some(Enum { id })
41 }
42}
43impl FromSource for Trait {
44 type Ast = ast::TraitDef;
45 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
46 let id = from_source(db, src)?;
47 Some(Trait { id })
48 }
49}
50impl FromSource for Function {
51 type Ast = ast::FnDef;
52 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
53 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
54 Container::Trait(it) => it.items(db),
55 Container::ImplBlock(it) => it.items(db),
56 Container::Module(m) => {
57 return m
58 .declarations(db)
59 .into_iter()
60 .filter_map(|it| match it {
61 ModuleDef::Function(it) => Some(it),
62 _ => None,
63 })
64 .find(|it| same_source(&it.source(db), &src))
65 }
66 };
67 items
68 .into_iter()
69 .filter_map(|it| match it {
70 AssocItem::Function(it) => Some(it),
71 _ => None,
72 })
73 .find(|it| same_source(&it.source(db), &src))
74 }
75} 32}
76 33
77impl FromSource for Const { 34impl<T: FromSourceByContainer> FromSource for T
78 type Ast = ast::ConstDef; 35where
79 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 36 T: From<<T as FromSourceByContainer>::Id>,
80 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 37{
81 Container::Trait(it) => it.items(db), 38 type Ast = <T as FromSourceByContainer>::Ast;
82 Container::ImplBlock(it) => it.items(db), 39 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
83 Container::Module(m) => { 40 analyze_container(db, src.as_ref().map(|it| it.syntax()))[T::KEY]
84 return m 41 .get(&src)
85 .declarations(db) 42 .copied()
86 .into_iter() 43 .map(Self::from)
87 .filter_map(|it| match it {
88 ModuleDef::Const(it) => Some(it),
89 _ => None,
90 })
91 .find(|it| same_source(&it.source(db), &src))
92 }
93 };
94 items
95 .into_iter()
96 .filter_map(|it| match it {
97 AssocItem::Const(it) => Some(it),
98 _ => None,
99 })
100 .find(|it| same_source(&it.source(db), &src))
101 }
102}
103impl FromSource for Static {
104 type Ast = ast::StaticDef;
105 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
106 let module = match Container::find(db, src.as_ref().map(|it| it.syntax()))? {
107 Container::Module(it) => it,
108 Container::Trait(_) | Container::ImplBlock(_) => return None,
109 };
110 module
111 .declarations(db)
112 .into_iter()
113 .filter_map(|it| match it {
114 ModuleDef::Static(it) => Some(it),
115 _ => None,
116 })
117 .find(|it| same_source(&it.source(db), &src))
118 } 44 }
119} 45}
120 46
121impl FromSource for TypeAlias { 47macro_rules! from_source_by_container_impls {
122 type Ast = ast::TypeAliasDef; 48 ($(($hir:ident, $id:ident, $ast:path, $key:path)),* ,) => {$(
123 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 49 impl FromSourceByContainer for $hir {
124 let items = match Container::find(db, src.as_ref().map(|it| it.syntax()))? { 50 type Ast = $ast;
125 Container::Trait(it) => it.items(db), 51 type Id = $id;
126 Container::ImplBlock(it) => it.items(db), 52 const KEY: Key<Self::Ast, Self::Id> = $key;
127 Container::Module(m) => { 53 }
128 return m 54 )*}
129 .declarations(db)
130 .into_iter()
131 .filter_map(|it| match it {
132 ModuleDef::TypeAlias(it) => Some(it),
133 _ => None,
134 })
135 .find(|it| same_source(&it.source(db), &src))
136 }
137 };
138 items
139 .into_iter()
140 .filter_map(|it| match it {
141 AssocItem::TypeAlias(it) => Some(it),
142 _ => None,
143 })
144 .find(|it| same_source(&it.source(db), &src))
145 }
146} 55}
147 56
57from_source_by_container_impls![
58 (Struct, StructId, ast::StructDef, keys::STRUCT),
59 (Union, UnionId, ast::UnionDef, keys::UNION),
60 (Enum, EnumId, ast::EnumDef, keys::ENUM),
61 (Trait, TraitId, ast::TraitDef, keys::TRAIT),
62 (Function, FunctionId, ast::FnDef, keys::FUNCTION),
63 (Static, StaticId, ast::StaticDef, keys::STATIC),
64 (Const, ConstId, ast::ConstDef, keys::CONST),
65 (TypeAlias, TypeAliasId, ast::TypeAliasDef, keys::TYPE_ALIAS),
66 (ImplBlock, ImplId, ast::ImplBlock, keys::IMPL),
67];
68
148impl FromSource for MacroDef { 69impl FromSource for MacroDef {
149 type Ast = ast::MacroCall; 70 type Ast = ast::MacroCall;
150 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 71 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
151 let kind = MacroDefKind::Declarative; 72 let kind = MacroDefKind::Declarative;
152 73
153 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax())); 74 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
154 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?; 75 let module = Module::from_definition(db, InFile::new(src.file_id, module_src))?;
155 let krate = module.krate().crate_id(); 76 let krate = Some(module.krate().id);
156 77
157 let ast_id = AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)); 78 let ast_id = Some(AstId::new(src.file_id, db.ast_id_map(src.file_id).ast_id(&src.value)));
158 79
159 let id: MacroDefId = MacroDefId { krate, ast_id, kind }; 80 let id: MacroDefId = MacroDefId { krate, ast_id, kind };
160 Some(MacroDef { id }) 81 Some(MacroDef { id })
161 } 82 }
162} 83}
163 84
164impl FromSource for ImplBlock {
165 type Ast = ast::ImplBlock;
166 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> {
167 let id = from_source(db, src)?;
168 Some(ImplBlock { id })
169 }
170}
171
172impl FromSource for EnumVariant { 85impl FromSource for EnumVariant {
173 type Ast = ast::EnumVariant; 86 type Ast = ast::EnumVariant;
174 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 87 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
175 let parent_enum = src.value.parent_enum(); 88 let parent_enum = src.value.parent_enum();
176 let src_enum = Source { file_id: src.file_id, value: parent_enum }; 89 let src_enum = InFile { file_id: src.file_id, value: parent_enum };
177 let variants = Enum::from_source(db, src_enum)?.variants(db); 90 let parent_enum = Enum::from_source(db, src_enum)?;
178 variants.into_iter().find(|v| same_source(&v.source(db), &src)) 91 parent_enum.id.child_by_source(db)[keys::ENUM_VARIANT]
92 .get(&src)
93 .copied()
94 .map(EnumVariant::from)
179 } 95 }
180} 96}
181 97
182impl FromSource for StructField { 98impl FromSource for StructField {
183 type Ast = FieldSource; 99 type Ast = FieldSource;
184 fn from_source(db: &(impl DefDatabase + AstDatabase), src: Source<Self::Ast>) -> Option<Self> { 100 fn from_source(db: &impl DefDatabase, src: InFile<Self::Ast>) -> Option<Self> {
185 let variant_def: VariantDef = match src.value { 101 let src = src.as_ref();
186 FieldSource::Named(ref field) => { 102
103 // FIXME this is buggy
104 let variant_id: VariantId = match src.value {
105 FieldSource::Named(field) => {
187 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?; 106 let value = field.syntax().ancestors().find_map(ast::StructDef::cast)?;
188 let src = Source { file_id: src.file_id, value }; 107 let src = InFile { file_id: src.file_id, value };
189 let def = Struct::from_source(db, src)?; 108 let def = Struct::from_source(db, src)?;
190 VariantDef::from(def) 109 def.id.into()
191 } 110 }
192 FieldSource::Pos(ref field) => { 111 FieldSource::Pos(field) => {
193 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?; 112 let value = field.syntax().ancestors().find_map(ast::EnumVariant::cast)?;
194 let src = Source { file_id: src.file_id, value }; 113 let src = InFile { file_id: src.file_id, value };
195 let def = EnumVariant::from_source(db, src)?; 114 let def = EnumVariant::from_source(db, src)?;
196 VariantDef::from(def) 115 EnumVariantId::from(def).into()
197 } 116 }
198 }; 117 };
199 variant_def 118
200 .variant_data(db) 119 let dyn_map = variant_id.child_by_source(db);
201 .fields() 120 match src.value {
202 .iter() 121 FieldSource::Pos(it) => dyn_map[keys::TUPLE_FIELD].get(&src.with_value(it.clone())),
203 .map(|(id, _)| StructField { parent: variant_def, id }) 122 FieldSource::Named(it) => dyn_map[keys::RECORD_FIELD].get(&src.with_value(it.clone())),
204 .find(|f| f.source(db) == src) 123 }
124 .copied()
125 .map(StructField::from)
205 } 126 }
206} 127}
207 128
208impl Local { 129impl Local {
209 pub fn from_source(db: &impl HirDatabase, src: Source<ast::BindPat>) -> Option<Self> { 130 pub fn from_source(db: &impl HirDatabase, src: InFile<ast::BindPat>) -> Option<Self> {
210 let file_id = src.file_id; 131 let file_id = src.file_id;
211 let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| { 132 let parent: DefWithBody = src.value.syntax().ancestors().find_map(|it| {
212 let res = match_ast! { 133 let res = match_ast! {
213 match it { 134 match it {
214 ast::ConstDef(value) => { Const::from_source(db, Source { value, file_id})?.into() }, 135 ast::ConstDef(value) => { Const::from_source(db, InFile { value, file_id})?.into() },
215 ast::StaticDef(value) => { Static::from_source(db, Source { value, file_id})?.into() }, 136 ast::StaticDef(value) => { Static::from_source(db, InFile { value, file_id})?.into() },
216 ast::FnDef(value) => { Function::from_source(db, Source { value, file_id})?.into() }, 137 ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.into() },
217 _ => return None, 138 _ => return None,
218 } 139 }
219 }; 140 };
@@ -226,84 +147,111 @@ impl Local {
226 } 147 }
227} 148}
228 149
150impl TypeParam {
151 pub fn from_source(db: &impl HirDatabase, src: InFile<ast::TypeParam>) -> Option<Self> {
152 let file_id = src.file_id;
153 let parent: GenericDefId = src.value.syntax().ancestors().find_map(|it| {
154 let res = match_ast! {
155 match it {
156 ast::FnDef(value) => { Function::from_source(db, InFile { value, file_id})?.id.into() },
157 ast::StructDef(value) => { Struct::from_source(db, InFile { value, file_id})?.id.into() },
158 ast::EnumDef(value) => { Enum::from_source(db, InFile { value, file_id})?.id.into() },
159 ast::TraitDef(value) => { Trait::from_source(db, InFile { value, file_id})?.id.into() },
160 ast::TypeAliasDef(value) => { TypeAlias::from_source(db, InFile { value, file_id})?.id.into() },
161 ast::ImplBlock(value) => { ImplBlock::from_source(db, InFile { value, file_id})?.id.into() },
162 _ => return None,
163 }
164 };
165 Some(res)
166 })?;
167 let &id = parent.child_by_source(db)[keys::TYPE_PARAM].get(&src)?;
168 Some(TypeParam { id })
169 }
170}
171
229impl Module { 172impl Module {
230 pub fn from_declaration(db: &impl DefDatabase, src: Source<ast::Module>) -> Option<Self> { 173 pub fn from_declaration(db: &impl DefDatabase, src: InFile<ast::Module>) -> Option<Self> {
174 let _p = profile("Module::from_declaration");
231 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast); 175 let parent_declaration = src.value.syntax().ancestors().skip(1).find_map(ast::Module::cast);
232 176
233 let parent_module = match parent_declaration { 177 let parent_module = match parent_declaration {
234 Some(parent_declaration) => { 178 Some(parent_declaration) => {
235 let src_parent = Source { file_id: src.file_id, value: parent_declaration }; 179 let src_parent = InFile { file_id: src.file_id, value: parent_declaration };
236 Module::from_declaration(db, src_parent) 180 Module::from_declaration(db, src_parent)
237 } 181 }
238 _ => { 182 None => {
239 let src_parent = Source { 183 let source_file = db.parse(src.file_id.original_file(db)).tree();
240 file_id: src.file_id, 184 let src_parent =
241 value: ModuleSource::new(db, Some(src.file_id.original_file(db)), None), 185 InFile { file_id: src.file_id, value: ModuleSource::SourceFile(source_file) };
242 };
243 Module::from_definition(db, src_parent) 186 Module::from_definition(db, src_parent)
244 } 187 }
245 }?; 188 }?;
246 189
247 let child_name = src.value.name()?; 190 let child_name = src.value.name()?.as_name();
248 parent_module.child(db, &child_name.as_name()) 191 let def_map = db.crate_def_map(parent_module.id.krate);
192 let child_id = def_map[parent_module.id.local_id].children.get(&child_name)?;
193 Some(parent_module.with_module_id(*child_id))
249 } 194 }
250 195
251 pub fn from_definition(db: &impl DefDatabase, src: Source<ModuleSource>) -> Option<Self> { 196 pub fn from_definition(db: &impl DefDatabase, src: InFile<ModuleSource>) -> Option<Self> {
197 let _p = profile("Module::from_definition");
252 match src.value { 198 match src.value {
253 ModuleSource::Module(ref module) => { 199 ModuleSource::Module(ref module) => {
254 assert!(!module.has_semi()); 200 assert!(!module.has_semi());
255 return Module::from_declaration( 201 return Module::from_declaration(
256 db, 202 db,
257 Source { file_id: src.file_id, value: module.clone() }, 203 InFile { file_id: src.file_id, value: module.clone() },
258 ); 204 );
259 } 205 }
260 ModuleSource::SourceFile(_) => (), 206 ModuleSource::SourceFile(_) => (),
261 }; 207 };
262 208
263 let original_file = src.file_id.original_file(db); 209 let original_file = src.file_id.original_file(db);
210 Module::from_file(db, original_file)
211 }
264 212
265 let (krate, local_id) = db.relevant_crates(original_file).iter().find_map(|&crate_id| { 213 fn from_file(db: &impl DefDatabase, file: FileId) -> Option<Self> {
214 let _p = profile("Module::from_file");
215 let (krate, local_id) = db.relevant_crates(file).iter().find_map(|&crate_id| {
266 let crate_def_map = db.crate_def_map(crate_id); 216 let crate_def_map = db.crate_def_map(crate_id);
267 let local_id = crate_def_map.modules_for_file(original_file).next()?; 217 let local_id = crate_def_map.modules_for_file(file).next()?;
268 Some((crate_id, local_id)) 218 Some((crate_id, local_id))
269 })?; 219 })?;
270 Some(Module { id: ModuleId { krate, local_id } }) 220 Some(Module { id: ModuleId { krate, local_id } })
271 } 221 }
272} 222}
273 223
274fn from_source<N, DEF>(db: &(impl DefDatabase + AstDatabase), src: Source<N>) -> Option<DEF> 224fn analyze_container(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> DynMap {
275where 225 let _p = profile("analyze_container");
276 N: AstNode, 226 return child_by_source(db, src).unwrap_or_default();
277 DEF: AstItemDef<N>,
278{
279 let module_src = ModuleSource::from_child_node(db, src.as_ref().map(|it| it.syntax()));
280 let module = Module::from_definition(db, Source::new(src.file_id, module_src))?;
281 let ctx = LocationCtx::new(db, module.id, src.file_id);
282 let items = db.ast_id_map(src.file_id);
283 let item_id = items.ast_id(&src.value);
284 Some(DEF::from_ast_id(ctx, item_id))
285}
286
287enum Container {
288 Trait(Trait),
289 ImplBlock(ImplBlock),
290 Module(Module),
291}
292 227
293impl Container { 228 fn child_by_source(db: &impl DefDatabase, src: InFile<&SyntaxNode>) -> Option<DynMap> {
294 fn find(db: &impl DefDatabase, src: Source<&SyntaxNode>) -> Option<Container> { 229 for container in src.value.ancestors().skip(1) {
295 // FIXME: this doesn't try to handle nested declarations
296 for container in src.value.ancestors() {
297 let res = match_ast! { 230 let res = match_ast! {
298 match container { 231 match container {
299 ast::TraitDef(it) => { 232 ast::TraitDef(it) => {
300 let c = Trait::from_source(db, src.with_value(it))?; 233 let def = Trait::from_source(db, src.with_value(it))?;
301 Container::Trait(c) 234 def.id.child_by_source(db)
302 }, 235 },
303 ast::ImplBlock(it) => { 236 ast::ImplBlock(it) => {
304 let c = ImplBlock::from_source(db, src.with_value(it))?; 237 let def = ImplBlock::from_source(db, src.with_value(it))?;
305 Container::ImplBlock(c) 238 def.id.child_by_source(db)
306 }, 239 },
240 ast::FnDef(it) => {
241 let def = Function::from_source(db, src.with_value(it))?;
242 DefWithBodyId::from(def.id)
243 .child_by_source(db)
244 },
245 ast::StaticDef(it) => {
246 let def = Static::from_source(db, src.with_value(it))?;
247 DefWithBodyId::from(def.id)
248 .child_by_source(db)
249 },
250 ast::ConstDef(it) => {
251 let def = Const::from_source(db, src.with_value(it))?;
252 DefWithBodyId::from(def.id)
253 .child_by_source(db)
254 },
307 _ => { continue }, 255 _ => { continue },
308 } 256 }
309 }; 257 };
@@ -312,16 +260,6 @@ impl Container {
312 260
313 let module_source = ModuleSource::from_child_node(db, src); 261 let module_source = ModuleSource::from_child_node(db, src);
314 let c = Module::from_definition(db, src.with_value(module_source))?; 262 let c = Module::from_definition(db, src.with_value(module_source))?;
315 Some(Container::Module(c)) 263 Some(c.id.child_by_source(db))
316 } 264 }
317} 265}
318
319/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
320/// equal if they point to exactly the same object.
321///
322/// In general, we do not guarantee that we have exactly one instance of a
323/// syntax tree for each file. We probably should add such guarantee, but, for
324/// the time being, we will use identity-less AstPtr comparison.
325fn same_source<N: AstNode>(s1: &Source<N>, s2: &Source<N>) -> bool {
326 s1.as_ref().map(AstPtr::new) == s2.as_ref().map(AstPtr::new)
327}
diff --git a/crates/ra_hir/src/has_source.rs b/crates/ra_hir/src/has_source.rs
new file mode 100644
index 000000000..5541266e2
--- /dev/null
+++ b/crates/ra_hir/src/has_source.rs
@@ -0,0 +1,127 @@
1//! FIXME: write short doc here
2
3use either::Either;
4use hir_def::{
5 nameres::ModuleSource,
6 src::{HasChildSource, HasSource as _},
7 Lookup, VariantId,
8};
9use ra_syntax::ast;
10
11use crate::{
12 db::DefDatabase, Const, Enum, EnumVariant, FieldSource, Function, ImplBlock, MacroDef, Module,
13 Static, Struct, StructField, Trait, TypeAlias, TypeParam, Union,
14};
15
16pub use hir_expand::InFile;
17
18pub trait HasSource {
19 type Ast;
20 fn source(self, db: &impl DefDatabase) -> InFile<Self::Ast>;
21}
22
23/// NB: Module is !HasSource, because it has two source nodes at the same time:
24/// definition and declaration.
25impl Module {
26 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
27 pub fn definition_source(self, db: &impl DefDatabase) -> InFile<ModuleSource> {
28 let def_map = db.crate_def_map(self.id.krate);
29 def_map[self.id.local_id].definition_source(db)
30 }
31
32 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
33 /// `None` for the crate root.
34 pub fn declaration_source(self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> {
35 let def_map = db.crate_def_map(self.id.krate);
36 def_map[self.id.local_id].declaration_source(db)
37 }
38}
39
40impl HasSource for StructField {
41 type Ast = FieldSource;
42 fn source(self, db: &impl DefDatabase) -> InFile<FieldSource> {
43 let var = VariantId::from(self.parent);
44 let src = var.child_source(db);
45 src.map(|it| match it[self.id].clone() {
46 Either::Left(it) => FieldSource::Pos(it),
47 Either::Right(it) => FieldSource::Named(it),
48 })
49 }
50}
51impl HasSource for Struct {
52 type Ast = ast::StructDef;
53 fn source(self, db: &impl DefDatabase) -> InFile<ast::StructDef> {
54 self.id.lookup(db).source(db)
55 }
56}
57impl HasSource for Union {
58 type Ast = ast::UnionDef;
59 fn source(self, db: &impl DefDatabase) -> InFile<ast::UnionDef> {
60 self.id.lookup(db).source(db)
61 }
62}
63impl HasSource for Enum {
64 type Ast = ast::EnumDef;
65 fn source(self, db: &impl DefDatabase) -> InFile<ast::EnumDef> {
66 self.id.lookup(db).source(db)
67 }
68}
69impl HasSource for EnumVariant {
70 type Ast = ast::EnumVariant;
71 fn source(self, db: &impl DefDatabase) -> InFile<ast::EnumVariant> {
72 self.parent.id.child_source(db).map(|map| map[self.id].clone())
73 }
74}
75impl HasSource for Function {
76 type Ast = ast::FnDef;
77 fn source(self, db: &impl DefDatabase) -> InFile<ast::FnDef> {
78 self.id.lookup(db).source(db)
79 }
80}
81impl HasSource for Const {
82 type Ast = ast::ConstDef;
83 fn source(self, db: &impl DefDatabase) -> InFile<ast::ConstDef> {
84 self.id.lookup(db).source(db)
85 }
86}
87impl HasSource for Static {
88 type Ast = ast::StaticDef;
89 fn source(self, db: &impl DefDatabase) -> InFile<ast::StaticDef> {
90 self.id.lookup(db).source(db)
91 }
92}
93impl HasSource for Trait {
94 type Ast = ast::TraitDef;
95 fn source(self, db: &impl DefDatabase) -> InFile<ast::TraitDef> {
96 self.id.lookup(db).source(db)
97 }
98}
99impl HasSource for TypeAlias {
100 type Ast = ast::TypeAliasDef;
101 fn source(self, db: &impl DefDatabase) -> InFile<ast::TypeAliasDef> {
102 self.id.lookup(db).source(db)
103 }
104}
105impl HasSource for MacroDef {
106 type Ast = ast::MacroCall;
107 fn source(self, db: &impl DefDatabase) -> InFile<ast::MacroCall> {
108 InFile {
109 file_id: self.id.ast_id.expect("MacroDef without ast_id").file_id,
110 value: self.id.ast_id.expect("MacroDef without ast_id").to_node(db),
111 }
112 }
113}
114impl HasSource for ImplBlock {
115 type Ast = ast::ImplBlock;
116 fn source(self, db: &impl DefDatabase) -> InFile<ast::ImplBlock> {
117 self.id.lookup(db).source(db)
118 }
119}
120
121impl HasSource for TypeParam {
122 type Ast = Either<ast::TraitDef, ast::TypeParam>;
123 fn source(self, db: &impl DefDatabase) -> InFile<Self::Ast> {
124 let child_source = self.id.parent.child_source(db);
125 child_source.map(|it| it[self.id.local_id].clone())
126 }
127}
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 3c12c61f0..0008a8858 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -26,42 +26,38 @@ macro_rules! impl_froms {
26 } 26 }
27} 27}
28 28
29pub mod debug;
30
31pub mod db; 29pub mod db;
32pub mod source_binder; 30pub mod source_binder;
33 31
34mod ty;
35pub mod diagnostics; 32pub mod diagnostics;
36 33
37mod from_id; 34mod from_id;
38mod code_model; 35mod code_model;
39 36
40pub mod from_source; 37mod has_source;
38mod from_source;
41 39
42pub use crate::{ 40pub use crate::{
43 code_model::{ 41 code_model::{
44 src::HasSource, Adt, AssocItem, AttrDef, Const, Container, Crate, CrateDependency, 42 Adt, AssocItem, AttrDef, Const, Crate, CrateDependency, DefWithBody, Docs, Enum,
45 DefWithBody, Docs, Enum, EnumVariant, FieldSource, Function, GenericDef, GenericParam, 43 EnumVariant, FieldSource, Function, GenericDef, HasAttrs, ImplBlock, Local, MacroDef,
46 HasAttrs, ImplBlock, Import, Local, MacroDef, Module, ModuleDef, ModuleSource, ScopeDef, 44 Module, ModuleDef, ScopeDef, Static, Struct, StructField, Trait, Type, TypeAlias,
47 Static, Struct, StructField, Trait, Type, TypeAlias, Union, VariantDef, 45 TypeParam, Union, VariantDef,
48 }, 46 },
49 from_source::FromSource, 47 from_source::FromSource,
48 has_source::HasSource,
50 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer}, 49 source_binder::{PathResolution, ScopeEntryWithSyntax, SourceAnalyzer},
51 ty::{
52 display::HirDisplay,
53 primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain},
54 ApplicationTy, CallableDef, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
55 },
56}; 50};
57 51
58pub use hir_def::{ 52pub use hir_def::{
59 body::scope::ExprScopes, 53 body::scope::ExprScopes,
60 builtin_type::BuiltinType, 54 builtin_type::BuiltinType,
61 docs::Documentation, 55 docs::Documentation,
62 path::{Path, PathKind}, 56 nameres::ModuleSource,
57 path::{ModPath, Path, PathKind},
63 type_ref::Mutability, 58 type_ref::Mutability,
64}; 59};
65pub use hir_expand::{ 60pub use hir_expand::{
66 either::Either, name::Name, HirFileId, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Source, 61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
67}; 62};
63pub use hir_ty::{display::HirDisplay, CallableDef};
diff --git a/crates/ra_hir/src/source_binder.rs b/crates/ra_hir/src/source_binder.rs
index 76c493f1a..85b378483 100644
--- a/crates/ra_hir/src/source_binder.rs
+++ b/crates/ra_hir/src/source_binder.rs
@@ -7,19 +7,26 @@
7//! purely for "IDE needs". 7//! purely for "IDE needs".
8use std::sync::Arc; 8use std::sync::Arc;
9 9
10use either::Either;
10use hir_def::{ 11use hir_def::{
11 body::{ 12 body::{
12 scope::{ExprScopes, ScopeId}, 13 scope::{ExprScopes, ScopeId},
13 BodySourceMap, 14 BodySourceMap,
14 }, 15 },
15 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
16 path::known, 17 nameres::ModuleSource,
18 path::path,
17 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs}, 19 resolver::{self, resolver_for_scope, HasResolver, Resolver, TypeNs, ValueNs},
18 AssocItemId, DefWithBodyId, 20 AssocItemId, DefWithBodyId,
19}; 21};
20use hir_expand::{ 22use hir_expand::{
21 hygiene::Hygiene, name::AsName, AstId, HirFileId, MacroCallId, MacroFileKind, Source, 23 hygiene::Hygiene, name::AsName, AstId, HirFileId, InFile, MacroCallId, MacroCallKind,
22}; 24};
25use hir_ty::{
26 method_resolution::{self, implements_trait},
27 Canonical, InEnvironment, InferenceResult, TraitEnvironment, Ty,
28};
29use ra_prof::profile;
23use ra_syntax::{ 30use ra_syntax::{
24 ast::{self, AstNode}, 31 ast::{self, AstNode},
25 match_ast, AstPtr, 32 match_ast, AstPtr,
@@ -28,16 +35,12 @@ use ra_syntax::{
28}; 35};
29 36
30use crate::{ 37use crate::{
31 db::HirDatabase, 38 db::HirDatabase, Adt, AssocItem, Const, DefWithBody, Enum, EnumVariant, FromSource, Function,
32 ty::{ 39 ImplBlock, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
33 method_resolution::{self, implements_trait}, 40 TypeParam,
34 InEnvironment, TraitEnvironment, Ty,
35 },
36 Adt, AssocItem, Const, DefWithBody, Either, Enum, EnumVariant, FromSource, Function,
37 GenericParam, Local, MacroDef, Name, Path, ScopeDef, Static, Struct, Trait, Type, TypeAlias,
38}; 41};
39 42
40fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -> Option<Resolver> { 43fn try_get_resolver_for_node(db: &impl HirDatabase, node: InFile<&SyntaxNode>) -> Option<Resolver> {
41 match_ast! { 44 match_ast! {
42 match (node.value) { 45 match (node.value) {
43 ast::Module(it) => { 46 ast::Module(it) => {
@@ -45,7 +48,7 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
45 Some(crate::Module::from_declaration(db, src)?.id.resolver(db)) 48 Some(crate::Module::from_declaration(db, src)?.id.resolver(db))
46 }, 49 },
47 ast::SourceFile(it) => { 50 ast::SourceFile(it) => {
48 let src = node.with_value(crate::ModuleSource::SourceFile(it)); 51 let src = node.with_value(ModuleSource::SourceFile(it));
49 Some(crate::Module::from_definition(db, src)?.id.resolver(db)) 52 Some(crate::Module::from_definition(db, src)?.id.resolver(db))
50 }, 53 },
51 ast::StructDef(it) => { 54 ast::StructDef(it) => {
@@ -56,6 +59,14 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
56 let src = node.with_value(it); 59 let src = node.with_value(it);
57 Some(Enum::from_source(db, src)?.id.resolver(db)) 60 Some(Enum::from_source(db, src)?.id.resolver(db))
58 }, 61 },
62 ast::ImplBlock(it) => {
63 let src = node.with_value(it);
64 Some(ImplBlock::from_source(db, src)?.id.resolver(db))
65 },
66 ast::TraitDef(it) => {
67 let src = node.with_value(it);
68 Some(Trait::from_source(db, src)?.id.resolver(db))
69 },
59 _ => match node.value.kind() { 70 _ => match node.value.kind() {
60 FN_DEF | CONST_DEF | STATIC_DEF => { 71 FN_DEF | CONST_DEF | STATIC_DEF => {
61 let def = def_with_body_from_child_node(db, node)?; 72 let def = def_with_body_from_child_node(db, node)?;
@@ -71,14 +82,16 @@ fn try_get_resolver_for_node(db: &impl HirDatabase, node: Source<&SyntaxNode>) -
71 82
72fn def_with_body_from_child_node( 83fn def_with_body_from_child_node(
73 db: &impl HirDatabase, 84 db: &impl HirDatabase,
74 child: Source<&SyntaxNode>, 85 child: InFile<&SyntaxNode>,
75) -> Option<DefWithBody> { 86) -> Option<DefWithBody> {
76 child.value.ancestors().find_map(|node| { 87 let _p = profile("def_with_body_from_child_node");
88 child.cloned().ancestors_with_macros(db).find_map(|node| {
89 let n = &node.value;
77 match_ast! { 90 match_ast! {
78 match node { 91 match n {
79 ast::FnDef(def) => { return Function::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 92 ast::FnDef(def) => { return Function::from_source(db, node.with_value(def)).map(DefWithBody::from); },
80 ast::ConstDef(def) => { return Const::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 93 ast::ConstDef(def) => { return Const::from_source(db, node.with_value(def)).map(DefWithBody::from); },
81 ast::StaticDef(def) => { return Static::from_source(db, child.with_value(def)).map(DefWithBody::from); }, 94 ast::StaticDef(def) => { return Static::from_source(db, node.with_value(def)).map(DefWithBody::from); },
82 _ => { None }, 95 _ => { None },
83 } 96 }
84 } 97 }
@@ -93,7 +106,7 @@ pub struct SourceAnalyzer {
93 resolver: Resolver, 106 resolver: Resolver,
94 body_owner: Option<DefWithBody>, 107 body_owner: Option<DefWithBody>,
95 body_source_map: Option<Arc<BodySourceMap>>, 108 body_source_map: Option<Arc<BodySourceMap>>,
96 infer: Option<Arc<crate::ty::InferenceResult>>, 109 infer: Option<Arc<InferenceResult>>,
97 scopes: Option<Arc<ExprScopes>>, 110 scopes: Option<Arc<ExprScopes>>,
98} 111}
99 112
@@ -104,7 +117,7 @@ pub enum PathResolution {
104 /// A local binding (only value namespace) 117 /// A local binding (only value namespace)
105 Local(Local), 118 Local(Local),
106 /// A generic parameter 119 /// A generic parameter
107 GenericParam(GenericParam), 120 TypeParam(TypeParam),
108 SelfType(crate::ImplBlock), 121 SelfType(crate::ImplBlock),
109 Macro(MacroDef), 122 Macro(MacroDef),
110 AssocItem(crate::AssocItem), 123 AssocItem(crate::AssocItem),
@@ -132,8 +145,8 @@ pub struct ReferenceDescriptor {
132 pub name: String, 145 pub name: String,
133} 146}
134 147
148#[derive(Debug)]
135pub struct Expansion { 149pub struct Expansion {
136 macro_file_kind: MacroFileKind,
137 macro_call_id: MacroCallId, 150 macro_call_id: MacroCallId,
138} 151}
139 152
@@ -141,23 +154,24 @@ impl Expansion {
141 pub fn map_token_down( 154 pub fn map_token_down(
142 &self, 155 &self,
143 db: &impl HirDatabase, 156 db: &impl HirDatabase,
144 token: Source<&SyntaxToken>, 157 token: InFile<&SyntaxToken>,
145 ) -> Option<Source<SyntaxToken>> { 158 ) -> Option<InFile<SyntaxToken>> {
146 let exp_info = self.file_id().expansion_info(db)?; 159 let exp_info = self.file_id().expansion_info(db)?;
147 exp_info.map_token_down(token) 160 exp_info.map_token_down(token)
148 } 161 }
149 162
150 pub fn file_id(&self) -> HirFileId { 163 pub fn file_id(&self) -> HirFileId {
151 self.macro_call_id.as_file(self.macro_file_kind) 164 self.macro_call_id.as_file()
152 } 165 }
153} 166}
154 167
155impl SourceAnalyzer { 168impl SourceAnalyzer {
156 pub fn new( 169 pub fn new(
157 db: &impl HirDatabase, 170 db: &impl HirDatabase,
158 node: Source<&SyntaxNode>, 171 node: InFile<&SyntaxNode>,
159 offset: Option<TextUnit>, 172 offset: Option<TextUnit>,
160 ) -> SourceAnalyzer { 173 ) -> SourceAnalyzer {
174 let _p = profile("SourceAnalyzer::new");
161 let def_with_body = def_with_body_from_child_node(db, node); 175 let def_with_body = def_with_body_from_child_node(db, node);
162 if let Some(def) = def_with_body { 176 if let Some(def) = def_with_body {
163 let (_body, source_map) = db.body_with_source_map(def.into()); 177 let (_body, source_map) = db.body_with_source_map(def.into());
@@ -192,12 +206,12 @@ impl SourceAnalyzer {
192 } 206 }
193 207
194 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> { 208 fn expr_id(&self, expr: &ast::Expr) -> Option<ExprId> {
195 let src = Source { file_id: self.file_id, value: expr }; 209 let src = InFile { file_id: self.file_id, value: expr };
196 self.body_source_map.as_ref()?.node_expr(src) 210 self.body_source_map.as_ref()?.node_expr(src)
197 } 211 }
198 212
199 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> { 213 fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
200 let src = Source { file_id: self.file_id, value: pat }; 214 let src = InFile { file_id: self.file_id, value: pat };
201 self.body_source_map.as_ref()?.node_pat(src) 215 self.body_source_map.as_ref()?.node_pat(src)
202 } 216 }
203 217
@@ -226,7 +240,13 @@ impl SourceAnalyzer {
226 } 240 }
227 241
228 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> { 242 pub fn resolve_record_field(&self, field: &ast::RecordField) -> Option<crate::StructField> {
229 let expr_id = self.expr_id(&field.expr()?)?; 243 let expr_id = match field.expr() {
244 Some(it) => self.expr_id(&it)?,
245 None => {
246 let src = InFile { file_id: self.file_id, value: field };
247 self.body_source_map.as_ref()?.field_init_shorthand_expr(src)?
248 }
249 };
230 self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into()) 250 self.infer.as_ref()?.record_field_resolution(expr_id).map(|it| it.into())
231 } 251 }
232 252
@@ -243,11 +263,11 @@ impl SourceAnalyzer {
243 pub fn resolve_macro_call( 263 pub fn resolve_macro_call(
244 &self, 264 &self,
245 db: &impl HirDatabase, 265 db: &impl HirDatabase,
246 macro_call: Source<&ast::MacroCall>, 266 macro_call: InFile<&ast::MacroCall>,
247 ) -> Option<MacroDef> { 267 ) -> Option<MacroDef> {
248 let hygiene = Hygiene::new(db, macro_call.file_id); 268 let hygiene = Hygiene::new(db, macro_call.file_id);
249 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; 269 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?;
250 self.resolver.resolve_path_as_macro(db, &path).map(|it| it.into()) 270 self.resolver.resolve_path_as_macro(db, path.mod_path()).map(|it| it.into())
251 } 271 }
252 272
253 pub fn resolve_hir_path( 273 pub fn resolve_hir_path(
@@ -255,43 +275,42 @@ impl SourceAnalyzer {
255 db: &impl HirDatabase, 275 db: &impl HirDatabase,
256 path: &crate::Path, 276 path: &crate::Path,
257 ) -> Option<PathResolution> { 277 ) -> Option<PathResolution> {
258 let types = self.resolver.resolve_path_in_type_ns_fully(db, &path).map(|ty| match ty { 278 let types =
259 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), 279 self.resolver.resolve_path_in_type_ns_fully(db, path.mod_path()).map(|ty| match ty {
260 TypeNs::GenericParam(idx) => PathResolution::GenericParam(GenericParam { 280 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
261 parent: self.resolver.generic_def().unwrap(), 281 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
262 idx, 282 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
263 }), 283 PathResolution::Def(Adt::from(it).into())
264 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
265 PathResolution::Def(Adt::from(it).into())
266 }
267 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
268 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
269 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
270 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
271 });
272 let values = self.resolver.resolve_path_in_value_ns_fully(db, &path).and_then(|val| {
273 let res = match val {
274 ValueNs::LocalBinding(pat_id) => {
275 let var = Local { parent: self.body_owner?, pat_id };
276 PathResolution::Local(var)
277 } 284 }
278 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()), 285 TypeNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
279 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()), 286 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
280 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()), 287 TypeNs::BuiltinType(it) => PathResolution::Def(it.into()),
281 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()), 288 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
282 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()), 289 });
283 }; 290 let values =
284 Some(res) 291 self.resolver.resolve_path_in_value_ns_fully(db, path.mod_path()).and_then(|val| {
285 }); 292 let res = match val {
293 ValueNs::LocalBinding(pat_id) => {
294 let var = Local { parent: self.body_owner?, pat_id };
295 PathResolution::Local(var)
296 }
297 ValueNs::FunctionId(it) => PathResolution::Def(Function::from(it).into()),
298 ValueNs::ConstId(it) => PathResolution::Def(Const::from(it).into()),
299 ValueNs::StaticId(it) => PathResolution::Def(Static::from(it).into()),
300 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
301 ValueNs::EnumVariantId(it) => PathResolution::Def(EnumVariant::from(it).into()),
302 };
303 Some(res)
304 });
286 305
287 let items = self 306 let items = self
288 .resolver 307 .resolver
289 .resolve_module_path(db, &path) 308 .resolve_module_path_in_items(db, path.mod_path())
290 .take_types() 309 .take_types()
291 .map(|it| PathResolution::Def(it.into())); 310 .map(|it| PathResolution::Def(it.into()));
292 types.or(values).or(items).or_else(|| { 311 types.or(values).or(items).or_else(|| {
293 self.resolver 312 self.resolver
294 .resolve_path_as_macro(db, &path) 313 .resolve_path_as_macro(db, path.mod_path())
295 .map(|def| PathResolution::Macro(def.into())) 314 .map(|def| PathResolution::Macro(def.into()))
296 }) 315 })
297 } 316 }
@@ -318,7 +337,7 @@ impl SourceAnalyzer {
318 let name = name_ref.as_name(); 337 let name = name_ref.as_name();
319 let source_map = self.body_source_map.as_ref()?; 338 let source_map = self.body_source_map.as_ref()?;
320 let scopes = self.scopes.as_ref()?; 339 let scopes = self.scopes.as_ref()?;
321 let scope = scope_for(scopes, source_map, Source::new(self.file_id, name_ref.syntax()))?; 340 let scope = scope_for(scopes, source_map, InFile::new(self.file_id, name_ref.syntax()))?;
322 let entry = scopes.resolve_name_in_scope(scope, &name)?; 341 let entry = scopes.resolve_name_in_scope(scope, &name)?;
323 Some(ScopeEntryWithSyntax { 342 Some(ScopeEntryWithSyntax {
324 name: entry.name().clone(), 343 name: entry.name().clone(),
@@ -332,10 +351,7 @@ impl SourceAnalyzer {
332 resolver::ScopeDef::PerNs(it) => it.into(), 351 resolver::ScopeDef::PerNs(it) => it.into(),
333 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()), 352 resolver::ScopeDef::ImplSelfType(it) => ScopeDef::ImplSelfType(it.into()),
334 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()), 353 resolver::ScopeDef::AdtSelfType(it) => ScopeDef::AdtSelfType(it.into()),
335 resolver::ScopeDef::GenericParam(idx) => { 354 resolver::ScopeDef::GenericParam(id) => ScopeDef::GenericParam(TypeParam { id }),
336 let parent = self.resolver.generic_def().unwrap();
337 ScopeDef::GenericParam(GenericParam { parent, idx })
338 }
339 resolver::ScopeDef::Local(pat_id) => { 355 resolver::ScopeDef::Local(pat_id) => {
340 let parent = self.resolver.body_owner().unwrap().into(); 356 let parent = self.resolver.body_owner().unwrap().into();
341 ScopeDef::Local(Local { parent, pat_id }) 357 ScopeDef::Local(Local { parent, pat_id })
@@ -349,7 +365,7 @@ impl SourceAnalyzer {
349 // should switch to general reference search infra there. 365 // should switch to general reference search infra there.
350 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> { 366 pub fn find_all_refs(&self, pat: &ast::BindPat) -> Vec<ReferenceDescriptor> {
351 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap(); 367 let fn_def = pat.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
352 let ptr = Either::A(AstPtr::new(&ast::Pat::from(pat.clone()))); 368 let ptr = Either::Left(AstPtr::new(&ast::Pat::from(pat.clone())));
353 fn_def 369 fn_def
354 .syntax() 370 .syntax()
355 .descendants() 371 .descendants()
@@ -375,7 +391,7 @@ impl SourceAnalyzer {
375 // There should be no inference vars in types passed here 391 // There should be no inference vars in types passed here
376 // FIXME check that? 392 // FIXME check that?
377 // FIXME replace Unknown by bound vars here 393 // FIXME replace Unknown by bound vars here
378 let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; 394 let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
379 method_resolution::iterate_method_candidates( 395 method_resolution::iterate_method_candidates(
380 &canonical, 396 &canonical,
381 db, 397 db,
@@ -399,7 +415,7 @@ impl SourceAnalyzer {
399 // There should be no inference vars in types passed here 415 // There should be no inference vars in types passed here
400 // FIXME check that? 416 // FIXME check that?
401 // FIXME replace Unknown by bound vars here 417 // FIXME replace Unknown by bound vars here
402 let canonical = crate::ty::Canonical { value: ty.ty.value.clone(), num_vars: 0 }; 418 let canonical = Canonical { value: ty.ty.value.clone(), num_vars: 0 };
403 method_resolution::iterate_method_candidates( 419 method_resolution::iterate_method_candidates(
404 &canonical, 420 &canonical,
405 db, 421 db,
@@ -410,24 +426,10 @@ impl SourceAnalyzer {
410 ) 426 )
411 } 427 }
412 428
413 // pub fn autoderef<'a>(
414 // &'a self,
415 // db: &'a impl HirDatabase,
416 // ty: Ty,
417 // ) -> impl Iterator<Item = Ty> + 'a {
418 // // There should be no inference vars in types passed here
419 // // FIXME check that?
420 // let canonical = crate::ty::Canonical { value: ty, num_vars: 0 };
421 // let krate = self.resolver.krate();
422 // let environment = TraitEnvironment::lower(db, &self.resolver);
423 // let ty = crate::ty::InEnvironment { value: canonical, environment };
424 // crate::ty::autoderef(db, krate, ty).map(|canonical| canonical.value)
425 // }
426
427 /// Checks that particular type `ty` implements `std::future::Future`. 429 /// Checks that particular type `ty` implements `std::future::Future`.
428 /// This function is used in `.await` syntax completion. 430 /// This function is used in `.await` syntax completion.
429 pub fn impls_future(&self, db: &impl HirDatabase, ty: Ty) -> bool { 431 pub fn impls_future(&self, db: &impl HirDatabase, ty: Type) -> bool {
430 let std_future_path = known::std_future_future(); 432 let std_future_path = path![std::future::Future];
431 433
432 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) { 434 let std_future_trait = match self.resolver.resolve_known_trait(db, &std_future_path) {
433 Some(it) => it.into(), 435 Some(it) => it.into(),
@@ -439,43 +441,40 @@ impl SourceAnalyzer {
439 _ => return false, 441 _ => return false,
440 }; 442 };
441 443
442 let canonical_ty = crate::ty::Canonical { value: ty, num_vars: 0 }; 444 let canonical_ty = Canonical { value: ty.ty.value, num_vars: 0 };
443 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait) 445 implements_trait(&canonical_ty, db, &self.resolver, krate.into(), std_future_trait)
444 } 446 }
445 447
446 pub fn expand( 448 pub fn expand(
447 &self, 449 &self,
448 db: &impl HirDatabase, 450 db: &impl HirDatabase,
449 macro_call: Source<&ast::MacroCall>, 451 macro_call: InFile<&ast::MacroCall>,
450 ) -> Option<Expansion> { 452 ) -> Option<Expansion> {
451 let def = self.resolve_macro_call(db, macro_call)?.id; 453 let def = self.resolve_macro_call(db, macro_call)?.id;
452 let ast_id = AstId::new( 454 let ast_id = AstId::new(
453 macro_call.file_id, 455 macro_call.file_id,
454 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value), 456 db.ast_id_map(macro_call.file_id).ast_id(macro_call.value),
455 ); 457 );
456 Some(Expansion { 458 Some(Expansion { macro_call_id: def.as_call_id(db, MacroCallKind::FnLike(ast_id)) })
457 macro_call_id: def.as_call_id(db, ast_id),
458 macro_file_kind: to_macro_file_kind(macro_call.value),
459 })
460 } 459 }
461} 460}
462 461
463fn scope_for( 462fn scope_for(
464 scopes: &ExprScopes, 463 scopes: &ExprScopes,
465 source_map: &BodySourceMap, 464 source_map: &BodySourceMap,
466 node: Source<&SyntaxNode>, 465 node: InFile<&SyntaxNode>,
467) -> Option<ScopeId> { 466) -> Option<ScopeId> {
468 node.value 467 node.value
469 .ancestors() 468 .ancestors()
470 .filter_map(ast::Expr::cast) 469 .filter_map(ast::Expr::cast)
471 .filter_map(|it| source_map.node_expr(Source::new(node.file_id, &it))) 470 .filter_map(|it| source_map.node_expr(InFile::new(node.file_id, &it)))
472 .find_map(|it| scopes.scope_for(it)) 471 .find_map(|it| scopes.scope_for(it))
473} 472}
474 473
475fn scope_for_offset( 474fn scope_for_offset(
476 scopes: &ExprScopes, 475 scopes: &ExprScopes,
477 source_map: &BodySourceMap, 476 source_map: &BodySourceMap,
478 offset: Source<TextUnit>, 477 offset: InFile<TextUnit>,
479) -> Option<ScopeId> { 478) -> Option<ScopeId> {
480 scopes 479 scopes
481 .scope_by_expr() 480 .scope_by_expr()
@@ -540,35 +539,3 @@ fn adjust(
540 }) 539 })
541 .map(|(_ptr, scope)| *scope) 540 .map(|(_ptr, scope)| *scope)
542} 541}
543
544/// Given a `ast::MacroCall`, return what `MacroKindFile` it belongs to.
545/// FIXME: Not completed
546fn to_macro_file_kind(macro_call: &ast::MacroCall) -> MacroFileKind {
547 let syn = macro_call.syntax();
548 let parent = match syn.parent() {
549 Some(it) => it,
550 None => {
551 // FIXME:
552 // If it is root, which means the parent HirFile
553 // MacroKindFile must be non-items
554 // return expr now.
555 return MacroFileKind::Expr;
556 }
557 };
558
559 match parent.kind() {
560 MACRO_ITEMS | SOURCE_FILE => MacroFileKind::Items,
561 LET_STMT => {
562 // FIXME: Handle Pattern
563 MacroFileKind::Expr
564 }
565 EXPR_STMT => MacroFileKind::Statements,
566 BLOCK => MacroFileKind::Statements,
567 ARG_LIST => MacroFileKind::Expr,
568 TRY_EXPR => MacroFileKind::Expr,
569 _ => {
570 // Unknown , Just guess it is `Items`
571 MacroFileKind::Items
572 }
573 }
574}
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs
deleted file mode 100644
index 4ed69c00d..000000000
--- a/crates/ra_hir/src/ty.rs
+++ /dev/null
@@ -1,4 +0,0 @@
1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists.
3
4pub use hir_ty::*;
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml
index 7e65f4c1d..2c368f690 100644
--- a/crates/ra_hir_def/Cargo.toml
+++ b/crates/ra_hir_def/Cargo.toml
@@ -11,6 +11,9 @@ doctest = false
11log = "0.4.5" 11log = "0.4.5"
12once_cell = "1.0.1" 12once_cell = "1.0.1"
13rustc-hash = "1.0" 13rustc-hash = "1.0"
14either = "1.5"
15anymap = "0.12"
16drop_bomb = "0.1.4"
14 17
15ra_arena = { path = "../ra_arena" } 18ra_arena = { path = "../ra_arena" }
16ra_db = { path = "../ra_db" } 19ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs
index 3666529b0..d9ea693e3 100644
--- a/crates/ra_hir_def/src/adt.rs
+++ b/crates/ra_hir_def/src/adt.rs
@@ -2,17 +2,18 @@
2 2
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use either::Either;
5use hir_expand::{ 6use hir_expand::{
6 either::Either,
7 name::{AsName, Name}, 7 name::{AsName, Name},
8 Source, 8 InFile,
9}; 9};
10use ra_arena::{map::ArenaMap, Arena}; 10use ra_arena::{map::ArenaMap, Arena};
11use ra_prof::profile;
11use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 12use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner};
12 13
13use crate::{ 14use crate::{
14 db::DefDatabase, trace::Trace, type_ref::TypeRef, AstItemDef, EnumId, HasChildSource, 15 db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, type_ref::TypeRef, EnumId,
15 LocalEnumVariantId, LocalStructFieldId, StructId, UnionId, VariantId, 16 LocalEnumVariantId, LocalStructFieldId, Lookup, StructId, UnionId, VariantId,
16}; 17};
17 18
18/// Note that we use `StructData` for unions as well! 19/// Note that we use `StructData` for unions as well!
@@ -50,14 +51,14 @@ pub struct StructFieldData {
50 51
51impl StructData { 52impl StructData {
52 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> { 53 pub(crate) fn struct_data_query(db: &impl DefDatabase, id: StructId) -> Arc<StructData> {
53 let src = id.source(db); 54 let src = id.lookup(db).source(db);
54 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 55 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
55 let variant_data = VariantData::new(src.value.kind()); 56 let variant_data = VariantData::new(src.value.kind());
56 let variant_data = Arc::new(variant_data); 57 let variant_data = Arc::new(variant_data);
57 Arc::new(StructData { name, variant_data }) 58 Arc::new(StructData { name, variant_data })
58 } 59 }
59 pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> { 60 pub(crate) fn union_data_query(db: &impl DefDatabase, id: UnionId) -> Arc<StructData> {
60 let src = id.source(db); 61 let src = id.lookup(db).source(db);
61 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 62 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
62 let variant_data = VariantData::new( 63 let variant_data = VariantData::new(
63 src.value 64 src.value
@@ -72,7 +73,8 @@ impl StructData {
72 73
73impl EnumData { 74impl EnumData {
74 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> { 75 pub(crate) fn enum_data_query(db: &impl DefDatabase, e: EnumId) -> Arc<EnumData> {
75 let src = e.source(db); 76 let _p = profile("enum_data_query");
77 let src = e.lookup(db).source(db);
76 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 78 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
77 let mut trace = Trace::new_for_arena(); 79 let mut trace = Trace::new_for_arena();
78 lower_enum(&mut trace, &src.value); 80 lower_enum(&mut trace, &src.value);
@@ -88,8 +90,8 @@ impl EnumData {
88impl HasChildSource for EnumId { 90impl HasChildSource for EnumId {
89 type ChildId = LocalEnumVariantId; 91 type ChildId = LocalEnumVariantId;
90 type Value = ast::EnumVariant; 92 type Value = ast::EnumVariant;
91 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { 93 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
92 let src = self.source(db); 94 let src = self.lookup(db).source(db);
93 let mut trace = Trace::new_for_map(); 95 let mut trace = Trace::new_for_map();
94 lower_enum(&mut trace, &src.value); 96 lower_enum(&mut trace, &src.value);
95 src.with_value(trace.into_map()) 97 src.with_value(trace.into_map())
@@ -145,7 +147,7 @@ impl HasChildSource for VariantId {
145 type ChildId = LocalStructFieldId; 147 type ChildId = LocalStructFieldId;
146 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>; 148 type Value = Either<ast::TupleFieldDef, ast::RecordFieldDef>;
147 149
148 fn child_source(&self, db: &impl DefDatabase) -> Source<ArenaMap<Self::ChildId, Self::Value>> { 150 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>> {
149 let src = match self { 151 let src = match self {
150 VariantId::EnumVariantId(it) => { 152 VariantId::EnumVariantId(it) => {
151 // I don't really like the fact that we call into parent source 153 // I don't really like the fact that we call into parent source
@@ -153,8 +155,8 @@ impl HasChildSource for VariantId {
153 let src = it.parent.child_source(db); 155 let src = it.parent.child_source(db);
154 src.map(|map| map[it.local_id].kind()) 156 src.map(|map| map[it.local_id].kind())
155 } 157 }
156 VariantId::StructId(it) => it.source(db).map(|it| it.kind()), 158 VariantId::StructId(it) => it.lookup(db).source(db).map(|it| it.kind()),
157 VariantId::UnionId(it) => it.source(db).map(|it| { 159 VariantId::UnionId(it) => it.lookup(db).source(db).map(|it| {
158 it.record_field_def_list() 160 it.record_field_def_list()
159 .map(ast::StructKind::Record) 161 .map(ast::StructKind::Record)
160 .unwrap_or(ast::StructKind::Unit) 162 .unwrap_or(ast::StructKind::Unit)
@@ -184,7 +186,7 @@ fn lower_struct(
184 ast::StructKind::Tuple(fl) => { 186 ast::StructKind::Tuple(fl) => {
185 for (i, fd) in fl.fields().enumerate() { 187 for (i, fd) in fl.fields().enumerate() {
186 trace.alloc( 188 trace.alloc(
187 || Either::A(fd.clone()), 189 || Either::Left(fd.clone()),
188 || StructFieldData { 190 || StructFieldData {
189 name: Name::new_tuple_field(i), 191 name: Name::new_tuple_field(i),
190 type_ref: TypeRef::from_ast_opt(fd.type_ref()), 192 type_ref: TypeRef::from_ast_opt(fd.type_ref()),
@@ -196,7 +198,7 @@ fn lower_struct(
196 ast::StructKind::Record(fl) => { 198 ast::StructKind::Record(fl) => {
197 for fd in fl.fields() { 199 for fd in fl.fields() {
198 trace.alloc( 200 trace.alloc(
199 || Either::B(fd.clone()), 201 || Either::Right(fd.clone()),
200 || StructFieldData { 202 || StructFieldData {
201 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 203 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
202 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), 204 type_ref: TypeRef::from_ast_opt(fd.ascribed_type()),
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs
index fffb22201..9efa4970c 100644
--- a/crates/ra_hir_def/src/attr.rs
+++ b/crates/ra_hir_def/src/attr.rs
@@ -2,7 +2,8 @@
2 2
3use std::{ops, sync::Arc}; 3use std::{ops, sync::Arc};
4 4
5use hir_expand::{either::Either, hygiene::Hygiene, AstId, Source}; 5use either::Either;
6use hir_expand::{hygiene::Hygiene, AstId, InFile};
6use mbe::ast_to_token_tree; 7use mbe::ast_to_token_tree;
7use ra_syntax::{ 8use ra_syntax::{
8 ast::{self, AstNode, AttrsOwner}, 9 ast::{self, AstNode, AttrsOwner},
@@ -11,7 +12,7 @@ use ra_syntax::{
11use tt::Subtree; 12use tt::Subtree;
12 13
13use crate::{ 14use crate::{
14 db::DefDatabase, path::Path, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup, 15 db::DefDatabase, path::ModPath, src::HasChildSource, src::HasSource, AdtId, AttrDefId, Lookup,
15}; 16};
16 17
17#[derive(Default, Debug, Clone, PartialEq, Eq)] 18#[derive(Default, Debug, Clone, PartialEq, Eq)]
@@ -44,8 +45,8 @@ impl Attrs {
44 AttrDefId::StructFieldId(it) => { 45 AttrDefId::StructFieldId(it) => {
45 let src = it.parent.child_source(db); 46 let src = it.parent.child_source(db);
46 match &src.value[it.local_id] { 47 match &src.value[it.local_id] {
47 Either::A(_tuple) => Attrs::default(), 48 Either::Left(_tuple) => Attrs::default(),
48 Either::B(record) => Attrs::from_attrs_owner(db, src.with_value(record)), 49 Either::Right(record) => Attrs::from_attrs_owner(db, src.with_value(record)),
49 } 50 }
50 } 51 }
51 AttrDefId::EnumVariantId(var_id) => { 52 AttrDefId::EnumVariantId(var_id) => {
@@ -54,13 +55,15 @@ impl Attrs {
54 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner)) 55 Attrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
55 } 56 }
56 AttrDefId::AdtId(it) => match it { 57 AttrDefId::AdtId(it) => match it {
57 AdtId::StructId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 58 AdtId::StructId(it) => attrs_from_loc(it.lookup(db), db),
58 AdtId::EnumId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 59 AdtId::EnumId(it) => attrs_from_loc(it.lookup(db), db),
59 AdtId::UnionId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 60 AdtId::UnionId(it) => attrs_from_loc(it.lookup(db), db),
60 }, 61 },
61 AttrDefId::TraitId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 62 AttrDefId::TraitId(it) => attrs_from_loc(it.lookup(db), db),
62 AttrDefId::MacroDefId(it) => attrs_from_ast(it.ast_id, db), 63 AttrDefId::MacroDefId(it) => {
63 AttrDefId::ImplId(it) => attrs_from_ast(it.lookup_intern(db).ast_id, db), 64 it.ast_id.map_or_else(Default::default, |ast_id| attrs_from_ast(ast_id, db))
65 }
66 AttrDefId::ImplId(it) => attrs_from_loc(it.lookup(db), db),
64 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db), 67 AttrDefId::ConstId(it) => attrs_from_loc(it.lookup(db), db),
65 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db), 68 AttrDefId::StaticId(it) => attrs_from_loc(it.lookup(db), db),
66 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db), 69 AttrDefId::FunctionId(it) => attrs_from_loc(it.lookup(db), db),
@@ -68,7 +71,7 @@ impl Attrs {
68 } 71 }
69 } 72 }
70 73
71 fn from_attrs_owner(db: &impl DefDatabase, owner: Source<&dyn AttrsOwner>) -> Attrs { 74 fn from_attrs_owner(db: &impl DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs {
72 let hygiene = Hygiene::new(db, owner.file_id); 75 let hygiene = Hygiene::new(db, owner.file_id);
73 Attrs::new(owner.value, &hygiene) 76 Attrs::new(owner.value, &hygiene)
74 } 77 }
@@ -91,7 +94,7 @@ impl Attrs {
91 94
92#[derive(Debug, Clone, PartialEq, Eq)] 95#[derive(Debug, Clone, PartialEq, Eq)]
93pub struct Attr { 96pub struct Attr {
94 pub(crate) path: Path, 97 pub(crate) path: ModPath,
95 pub(crate) input: Option<AttrInput>, 98 pub(crate) input: Option<AttrInput>,
96} 99}
97 100
@@ -103,7 +106,7 @@ pub enum AttrInput {
103 106
104impl Attr { 107impl Attr {
105 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> { 108 fn from_src(ast: ast::Attr, hygiene: &Hygiene) -> Option<Attr> {
106 let path = Path::from_src(ast.path()?, hygiene)?; 109 let path = ModPath::from_src(ast.path()?, hygiene)?;
107 let input = match ast.input() { 110 let input = match ast.input() {
108 None => None, 111 None => None,
109 Some(ast::AttrInput::Literal(lit)) => { 112 Some(ast::AttrInput::Literal(lit)) => {
@@ -157,7 +160,7 @@ where
157 N: ast::AttrsOwner, 160 N: ast::AttrsOwner,
158 D: DefDatabase, 161 D: DefDatabase,
159{ 162{
160 let src = Source::new(src.file_id(), src.to_node(db)); 163 let src = InFile::new(src.file_id, src.to_node(db));
161 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner)) 164 Attrs::from_attrs_owner(db, src.as_ref().map(|it| it as &dyn AttrsOwner))
162} 165}
163 166
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs
index a57a0176d..d3e4c50ae 100644
--- a/crates/ra_hir_def/src/body.rs
+++ b/crates/ra_hir_def/src/body.rs
@@ -3,58 +3,75 @@
3mod lower; 3mod lower;
4pub mod scope; 4pub mod scope;
5 5
6use std::{ops::Index, sync::Arc}; 6use std::{mem, ops::Index, sync::Arc};
7 7
8use drop_bomb::DropBomb;
9use either::Either;
8use hir_expand::{ 10use hir_expand::{
9 either::Either, hygiene::Hygiene, AstId, HirFileId, MacroDefId, MacroFileKind, Source, 11 ast_id_map::AstIdMap, hygiene::Hygiene, AstId, HirFileId, InFile, MacroCallKind, MacroDefId,
10}; 12};
11use ra_arena::{map::ArenaMap, Arena}; 13use ra_arena::{map::ArenaMap, Arena};
14use ra_prof::profile;
12use ra_syntax::{ast, AstNode, AstPtr}; 15use ra_syntax::{ast, AstNode, AstPtr};
13use rustc_hash::FxHashMap; 16use rustc_hash::FxHashMap;
14 17
15use crate::{ 18use crate::{
16 db::DefDatabase, 19 db::DefDatabase,
17 expr::{Expr, ExprId, Pat, PatId}, 20 expr::{Expr, ExprId, Pat, PatId},
21 item_scope::BuiltinShadowMode,
22 item_scope::ItemScope,
18 nameres::CrateDefMap, 23 nameres::CrateDefMap,
19 path::Path, 24 path::{ModPath, Path},
20 DefWithBodyId, HasModule, HasSource, Lookup, ModuleId, 25 src::HasSource,
26 DefWithBodyId, HasModule, Lookup, ModuleId,
21}; 27};
22 28
23struct Expander { 29pub(crate) struct Expander {
24 crate_def_map: Arc<CrateDefMap>, 30 crate_def_map: Arc<CrateDefMap>,
25 current_file_id: HirFileId, 31 current_file_id: HirFileId,
26 hygiene: Hygiene, 32 hygiene: Hygiene,
33 ast_id_map: Arc<AstIdMap>,
27 module: ModuleId, 34 module: ModuleId,
28} 35}
29 36
30impl Expander { 37impl Expander {
31 fn new(db: &impl DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander { 38 pub(crate) fn new(
39 db: &impl DefDatabase,
40 current_file_id: HirFileId,
41 module: ModuleId,
42 ) -> Expander {
32 let crate_def_map = db.crate_def_map(module.krate); 43 let crate_def_map = db.crate_def_map(module.krate);
33 let hygiene = Hygiene::new(db, current_file_id); 44 let hygiene = Hygiene::new(db, current_file_id);
34 Expander { crate_def_map, current_file_id, hygiene, module } 45 let ast_id_map = db.ast_id_map(current_file_id);
46 Expander { crate_def_map, current_file_id, hygiene, ast_id_map, module }
35 } 47 }
36 48
37 fn enter_expand( 49 pub(crate) fn enter_expand<T: ast::AstNode, DB: DefDatabase>(
38 &mut self, 50 &mut self,
39 db: &impl DefDatabase, 51 db: &DB,
40 macro_call: ast::MacroCall, 52 macro_call: ast::MacroCall,
41 ) -> Option<(Mark, ast::Expr)> { 53 ) -> Option<(Mark, T)> {
42 let ast_id = AstId::new( 54 let ast_id = AstId::new(
43 self.current_file_id, 55 self.current_file_id,
44 db.ast_id_map(self.current_file_id).ast_id(&macro_call), 56 db.ast_id_map(self.current_file_id).ast_id(&macro_call),
45 ); 57 );
46 58
47 if let Some(path) = macro_call.path().and_then(|path| self.parse_path(path)) { 59 if let Some(path) = macro_call.path().and_then(|path| self.parse_mod_path(path)) {
48 if let Some(def) = self.resolve_path_as_macro(db, &path) { 60 if let Some(def) = self.resolve_path_as_macro(db, &path) {
49 let call_id = def.as_call_id(db, ast_id); 61 let call_id = def.as_call_id(db, MacroCallKind::FnLike(ast_id));
50 let file_id = call_id.as_file(MacroFileKind::Expr); 62 let file_id = call_id.as_file();
51 if let Some(node) = db.parse_or_expand(file_id) { 63 if let Some(node) = db.parse_or_expand(file_id) {
52 if let Some(expr) = ast::Expr::cast(node) { 64 if let Some(expr) = T::cast(node) {
53 log::debug!("macro expansion {:#?}", expr.syntax()); 65 log::debug!("macro expansion {:#?}", expr.syntax());
54 66
55 let mark = Mark { file_id: self.current_file_id }; 67 let mark = Mark {
68 file_id: self.current_file_id,
69 ast_id_map: mem::take(&mut self.ast_id_map),
70 bomb: DropBomb::new("expansion mark dropped"),
71 };
56 self.hygiene = Hygiene::new(db, file_id); 72 self.hygiene = Hygiene::new(db, file_id);
57 self.current_file_id = file_id; 73 self.current_file_id = file_id;
74 self.ast_id_map = db.ast_id_map(file_id);
58 75
59 return Some((mark, expr)); 76 return Some((mark, expr));
60 } 77 }
@@ -67,37 +84,44 @@ impl Expander {
67 None 84 None
68 } 85 }
69 86
70 fn exit(&mut self, db: &impl DefDatabase, mark: Mark) { 87 pub(crate) fn exit(&mut self, db: &impl DefDatabase, mut mark: Mark) {
71 self.hygiene = Hygiene::new(db, mark.file_id); 88 self.hygiene = Hygiene::new(db, mark.file_id);
72 self.current_file_id = mark.file_id; 89 self.current_file_id = mark.file_id;
73 std::mem::forget(mark); 90 self.ast_id_map = mem::take(&mut mark.ast_id_map);
91 mark.bomb.defuse();
74 } 92 }
75 93
76 fn to_source<T>(&self, value: T) -> Source<T> { 94 pub(crate) fn to_source<T>(&self, value: T) -> InFile<T> {
77 Source { file_id: self.current_file_id, value } 95 InFile { file_id: self.current_file_id, value }
78 } 96 }
79 97
80 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 98 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
81 Path::from_src(path, &self.hygiene) 99 Path::from_src(path, &self.hygiene)
82 } 100 }
83 101
84 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 102 fn parse_mod_path(&mut self, path: ast::Path) -> Option<ModPath> {
85 self.crate_def_map.resolve_path(db, self.module.local_id, path).0.take_macros() 103 ModPath::from_src(path, &self.hygiene)
86 } 104 }
87}
88 105
89struct Mark { 106 fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &ModPath) -> Option<MacroDefId> {
90 file_id: HirFileId, 107 self.crate_def_map
91} 108 .resolve_path(db, self.module.local_id, path, BuiltinShadowMode::Other)
109 .0
110 .take_macros()
111 }
92 112
93impl Drop for Mark { 113 fn ast_id<N: AstNode>(&self, item: &N) -> AstId<N> {
94 fn drop(&mut self) { 114 let file_local_id = self.ast_id_map.ast_id(item);
95 if !std::thread::panicking() { 115 AstId::new(self.current_file_id, file_local_id)
96 panic!("dropped mark")
97 }
98 } 116 }
99} 117}
100 118
119pub(crate) struct Mark {
120 file_id: HirFileId,
121 ast_id_map: Arc<AstIdMap>,
122 bomb: DropBomb,
123}
124
101/// The body of an item (function, const etc.). 125/// The body of an item (function, const etc.).
102#[derive(Debug, Eq, PartialEq)] 126#[derive(Debug, Eq, PartialEq)]
103pub struct Body { 127pub struct Body {
@@ -112,13 +136,14 @@ pub struct Body {
112 pub params: Vec<PatId>, 136 pub params: Vec<PatId>,
113 /// The `ExprId` of the actual body expression. 137 /// The `ExprId` of the actual body expression.
114 pub body_expr: ExprId, 138 pub body_expr: ExprId,
139 pub item_scope: ItemScope,
115} 140}
116 141
117pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>; 142pub type ExprPtr = Either<AstPtr<ast::Expr>, AstPtr<ast::RecordField>>;
118pub type ExprSource = Source<ExprPtr>; 143pub type ExprSource = InFile<ExprPtr>;
119 144
120pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>; 145pub type PatPtr = Either<AstPtr<ast::Pat>, AstPtr<ast::SelfParam>>;
121pub type PatSource = Source<PatPtr>; 146pub type PatSource = InFile<PatPtr>;
122 147
123/// An item body together with the mapping from syntax nodes to HIR expression 148/// An item body together with the mapping from syntax nodes to HIR expression
124/// IDs. This is needed to go from e.g. a position in a file to the HIR 149/// IDs. This is needed to go from e.g. a position in a file to the HIR
@@ -145,6 +170,7 @@ impl Body {
145 db: &impl DefDatabase, 170 db: &impl DefDatabase,
146 def: DefWithBodyId, 171 def: DefWithBodyId,
147 ) -> (Arc<Body>, Arc<BodySourceMap>) { 172 ) -> (Arc<Body>, Arc<BodySourceMap>) {
173 let _p = profile("body_with_source_map_query");
148 let mut params = None; 174 let mut params = None;
149 175
150 let (file_id, module, body) = match def { 176 let (file_id, module, body) = match def {
@@ -166,7 +192,7 @@ impl Body {
166 } 192 }
167 }; 193 };
168 let expander = Expander::new(db, file_id, module); 194 let expander = Expander::new(db, file_id, module);
169 let (body, source_map) = Body::new(db, expander, params, body); 195 let (body, source_map) = Body::new(db, def, expander, params, body);
170 (Arc::new(body), Arc::new(source_map)) 196 (Arc::new(body), Arc::new(source_map))
171 } 197 }
172 198
@@ -176,11 +202,12 @@ impl Body {
176 202
177 fn new( 203 fn new(
178 db: &impl DefDatabase, 204 db: &impl DefDatabase,
205 def: DefWithBodyId,
179 expander: Expander, 206 expander: Expander,
180 params: Option<ast::ParamList>, 207 params: Option<ast::ParamList>,
181 body: Option<ast::Expr>, 208 body: Option<ast::Expr>,
182 ) -> (Body, BodySourceMap) { 209 ) -> (Body, BodySourceMap) {
183 lower::lower(db, expander, params, body) 210 lower::lower(db, def, expander, params, body)
184 } 211 }
185} 212}
186 213
@@ -205,8 +232,13 @@ impl BodySourceMap {
205 self.expr_map_back.get(expr).copied() 232 self.expr_map_back.get(expr).copied()
206 } 233 }
207 234
208 pub fn node_expr(&self, node: Source<&ast::Expr>) -> Option<ExprId> { 235 pub fn node_expr(&self, node: InFile<&ast::Expr>) -> Option<ExprId> {
209 let src = node.map(|it| Either::A(AstPtr::new(it))); 236 let src = node.map(|it| Either::Left(AstPtr::new(it)));
237 self.expr_map.get(&src).cloned()
238 }
239
240 pub fn field_init_shorthand_expr(&self, node: InFile<&ast::RecordField>) -> Option<ExprId> {
241 let src = node.map(|it| Either::Right(AstPtr::new(it)));
210 self.expr_map.get(&src).cloned() 242 self.expr_map.get(&src).cloned()
211 } 243 }
212 244
@@ -214,8 +246,8 @@ impl BodySourceMap {
214 self.pat_map_back.get(pat).copied() 246 self.pat_map_back.get(pat).copied()
215 } 247 }
216 248
217 pub fn node_pat(&self, node: Source<&ast::Pat>) -> Option<PatId> { 249 pub fn node_pat(&self, node: InFile<&ast::Pat>) -> Option<PatId> {
218 let src = node.map(|it| Either::A(AstPtr::new(it))); 250 let src = node.map(|it| Either::Left(AstPtr::new(it)));
219 self.pat_map.get(&src).cloned() 251 self.pat_map.get(&src).cloned()
220 } 252 }
221 253
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index 331736cb2..5323af097 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -1,14 +1,13 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use hir_expand::{ 4use either::Either;
5 either::Either, 5
6 name::{self, AsName, Name}, 6use hir_expand::name::{name, AsName, Name};
7};
8use ra_arena::Arena; 7use ra_arena::Arena;
9use ra_syntax::{ 8use ra_syntax::{
10 ast::{ 9 ast::{
11 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, NameOwner, 10 self, ArgListOwner, ArrayExprKind, LiteralKind, LoopBodyOwner, ModuleItemOwner, NameOwner,
12 TypeAscriptionOwner, 11 TypeAscriptionOwner,
13 }, 12 },
14 AstNode, AstPtr, 13 AstNode, AstPtr,
@@ -26,23 +25,28 @@ use crate::{
26 path::GenericArgs, 25 path::GenericArgs,
27 path::Path, 26 path::Path,
28 type_ref::{Mutability, TypeRef}, 27 type_ref::{Mutability, TypeRef},
28 ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc,
29 StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
29}; 30};
30 31
31pub(super) fn lower( 32pub(super) fn lower(
32 db: &impl DefDatabase, 33 db: &impl DefDatabase,
34 def: DefWithBodyId,
33 expander: Expander, 35 expander: Expander,
34 params: Option<ast::ParamList>, 36 params: Option<ast::ParamList>,
35 body: Option<ast::Expr>, 37 body: Option<ast::Expr>,
36) -> (Body, BodySourceMap) { 38) -> (Body, BodySourceMap) {
37 ExprCollector { 39 ExprCollector {
38 expander,
39 db, 40 db,
41 def,
42 expander,
40 source_map: BodySourceMap::default(), 43 source_map: BodySourceMap::default(),
41 body: Body { 44 body: Body {
42 exprs: Arena::default(), 45 exprs: Arena::default(),
43 pats: Arena::default(), 46 pats: Arena::default(),
44 params: Vec::new(), 47 params: Vec::new(),
45 body_expr: ExprId::dummy(), 48 body_expr: ExprId::dummy(),
49 item_scope: Default::default(),
46 }, 50 },
47 } 51 }
48 .collect(params, body) 52 .collect(params, body)
@@ -50,6 +54,7 @@ pub(super) fn lower(
50 54
51struct ExprCollector<DB> { 55struct ExprCollector<DB> {
52 db: DB, 56 db: DB,
57 def: DefWithBodyId,
53 expander: Expander, 58 expander: Expander,
54 59
55 body: Body, 60 body: Body,
@@ -70,11 +75,11 @@ where
70 let ptr = AstPtr::new(&self_param); 75 let ptr = AstPtr::new(&self_param);
71 let param_pat = self.alloc_pat( 76 let param_pat = self.alloc_pat(
72 Pat::Bind { 77 Pat::Bind {
73 name: name::SELF_PARAM, 78 name: name![self],
74 mode: BindingAnnotation::Unannotated, 79 mode: BindingAnnotation::Unannotated,
75 subpat: None, 80 subpat: None,
76 }, 81 },
77 Either::B(ptr), 82 Either::Right(ptr),
78 ); 83 );
79 self.body.params.push(param_pat); 84 self.body.params.push(param_pat);
80 } 85 }
@@ -94,7 +99,7 @@ where
94 } 99 }
95 100
96 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId { 101 fn alloc_expr(&mut self, expr: Expr, ptr: AstPtr<ast::Expr>) -> ExprId {
97 let ptr = Either::A(ptr); 102 let ptr = Either::Left(ptr);
98 let id = self.body.exprs.alloc(expr); 103 let id = self.body.exprs.alloc(expr);
99 let src = self.expander.to_source(ptr); 104 let src = self.expander.to_source(ptr);
100 self.source_map.expr_map.insert(src, id); 105 self.source_map.expr_map.insert(src, id);
@@ -107,7 +112,7 @@ where
107 self.body.exprs.alloc(expr) 112 self.body.exprs.alloc(expr)
108 } 113 }
109 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId { 114 fn alloc_expr_field_shorthand(&mut self, expr: Expr, ptr: AstPtr<ast::RecordField>) -> ExprId {
110 let ptr = Either::B(ptr); 115 let ptr = Either::Right(ptr);
111 let id = self.body.exprs.alloc(expr); 116 let id = self.body.exprs.alloc(expr);
112 let src = self.expander.to_source(ptr); 117 let src = self.expander.to_source(ptr);
113 self.source_map.expr_map.insert(src, id); 118 self.source_map.expr_map.insert(src, id);
@@ -277,7 +282,7 @@ where
277 ast::Expr::ParenExpr(e) => { 282 ast::Expr::ParenExpr(e) => {
278 let inner = self.collect_expr_opt(e.expr()); 283 let inner = self.collect_expr_opt(e.expr());
279 // make the paren expr point to the inner expression as well 284 // make the paren expr point to the inner expression as well
280 let src = self.expander.to_source(Either::A(syntax_ptr)); 285 let src = self.expander.to_source(Either::Left(syntax_ptr));
281 self.source_map.expr_map.insert(src, inner); 286 self.source_map.expr_map.insert(src, inner);
282 inner 287 inner
283 } 288 }
@@ -367,8 +372,9 @@ where
367 arg_types.push(type_ref); 372 arg_types.push(type_ref);
368 } 373 }
369 } 374 }
375 let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast);
370 let body = self.collect_expr_opt(e.body()); 376 let body = self.collect_expr_opt(e.body());
371 self.alloc_expr(Expr::Lambda { args, arg_types, body }, syntax_ptr) 377 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
372 } 378 }
373 ast::Expr::BinExpr(e) => { 379 ast::Expr::BinExpr(e) => {
374 let lhs = self.collect_expr_opt(e.lhs()); 380 let lhs = self.collect_expr_opt(e.lhs());
@@ -429,10 +435,17 @@ where
429 let index = self.collect_expr_opt(e.index()); 435 let index = self.collect_expr_opt(e.index());
430 self.alloc_expr(Expr::Index { base, index }, syntax_ptr) 436 self.alloc_expr(Expr::Index { base, index }, syntax_ptr)
431 } 437 }
432 438 ast::Expr::RangeExpr(e) => {
433 // FIXME implement HIR for these: 439 let lhs = e.start().map(|lhs| self.collect_expr(lhs));
434 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 440 let rhs = e.end().map(|rhs| self.collect_expr(rhs));
435 ast::Expr::RangeExpr(_e) => self.alloc_expr(Expr::Missing, syntax_ptr), 441 match e.op_kind() {
442 Some(range_type) => {
443 self.alloc_expr(Expr::Range { lhs, rhs, range_type }, syntax_ptr)
444 }
445 None => self.alloc_expr(Expr::Missing, syntax_ptr),
446 }
447 }
448 // FIXME expand to statements in statement position
436 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) { 449 ast::Expr::MacroCall(e) => match self.expander.enter_expand(self.db, e) {
437 Some((mark, expansion)) => { 450 Some((mark, expansion)) => {
438 let id = self.collect_expr(expansion); 451 let id = self.collect_expr(expansion);
@@ -441,6 +454,9 @@ where
441 } 454 }
442 None => self.alloc_expr(Expr::Missing, syntax_ptr), 455 None => self.alloc_expr(Expr::Missing, syntax_ptr),
443 }, 456 },
457
458 // FIXME implement HIR for these:
459 ast::Expr::Label(_e) => self.alloc_expr(Expr::Missing, syntax_ptr),
444 } 460 }
445 } 461 }
446 462
@@ -458,6 +474,7 @@ where
458 Some(block) => block, 474 Some(block) => block,
459 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), 475 None => return self.alloc_expr(Expr::Missing, syntax_node_ptr),
460 }; 476 };
477 self.collect_block_items(&block);
461 let statements = block 478 let statements = block
462 .statements() 479 .statements()
463 .map(|s| match s { 480 .map(|s| match s {
@@ -474,6 +491,63 @@ where
474 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) 491 self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr)
475 } 492 }
476 493
494 fn collect_block_items(&mut self, block: &ast::Block) {
495 let container = ContainerId::DefWithBodyId(self.def);
496 for item in block.items() {
497 let (def, name): (ModuleDefId, Option<ast::Name>) = match item {
498 ast::ModuleItem::FnDef(def) => {
499 let ast_id = self.expander.ast_id(&def);
500 (
501 FunctionLoc { container: container.into(), ast_id }.intern(self.db).into(),
502 def.name(),
503 )
504 }
505 ast::ModuleItem::TypeAliasDef(def) => {
506 let ast_id = self.expander.ast_id(&def);
507 (
508 TypeAliasLoc { container: container.into(), ast_id }.intern(self.db).into(),
509 def.name(),
510 )
511 }
512 ast::ModuleItem::ConstDef(def) => {
513 let ast_id = self.expander.ast_id(&def);
514 (
515 ConstLoc { container: container.into(), ast_id }.intern(self.db).into(),
516 def.name(),
517 )
518 }
519 ast::ModuleItem::StaticDef(def) => {
520 let ast_id = self.expander.ast_id(&def);
521 (StaticLoc { container, ast_id }.intern(self.db).into(), def.name())
522 }
523 ast::ModuleItem::StructDef(def) => {
524 let ast_id = self.expander.ast_id(&def);
525 (StructLoc { container, ast_id }.intern(self.db).into(), def.name())
526 }
527 ast::ModuleItem::EnumDef(def) => {
528 let ast_id = self.expander.ast_id(&def);
529 (EnumLoc { container, ast_id }.intern(self.db).into(), def.name())
530 }
531 ast::ModuleItem::UnionDef(def) => {
532 let ast_id = self.expander.ast_id(&def);
533 (UnionLoc { container, ast_id }.intern(self.db).into(), def.name())
534 }
535 ast::ModuleItem::TraitDef(def) => {
536 let ast_id = self.expander.ast_id(&def);
537 (TraitLoc { container, ast_id }.intern(self.db).into(), def.name())
538 }
539 ast::ModuleItem::ImplBlock(_)
540 | ast::ModuleItem::UseItem(_)
541 | ast::ModuleItem::ExternCrateItem(_)
542 | ast::ModuleItem::Module(_) => continue,
543 };
544 self.body.item_scope.define_def(def);
545 if let Some(name) = name {
546 self.body.item_scope.push_res(name.as_name(), def.into());
547 }
548 }
549 }
550
477 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId { 551 fn collect_block_opt(&mut self, expr: Option<ast::BlockExpr>) -> ExprId {
478 if let Some(block) = expr { 552 if let Some(block) = expr {
479 self.collect_block(block) 553 self.collect_block(block)
@@ -541,7 +615,7 @@ where
541 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing, 615 ast::Pat::SlicePat(_) | ast::Pat::RangePat(_) => Pat::Missing,
542 }; 616 };
543 let ptr = AstPtr::new(&pat); 617 let ptr = AstPtr::new(&pat);
544 self.alloc_pat(pattern, Either::A(ptr)) 618 self.alloc_pat(pattern, Either::Left(ptr))
545 } 619 }
546 620
547 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId { 621 fn collect_pat_opt(&mut self, pat: Option<ast::Pat>) -> PatId {
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index 625aa39dd..a63552327 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -171,7 +171,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
171 171
172#[cfg(test)] 172#[cfg(test)]
173mod tests { 173mod tests {
174 use hir_expand::{name::AsName, Source}; 174 use hir_expand::{name::AsName, InFile};
175 use ra_db::{fixture::WithFixture, FileId, SourceDatabase}; 175 use ra_db::{fixture::WithFixture, FileId, SourceDatabase};
176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode}; 176 use ra_syntax::{algo::find_node_at_offset, ast, AstNode};
177 use test_utils::{assert_eq_text, covers, extract_offset}; 177 use test_utils::{assert_eq_text, covers, extract_offset};
@@ -183,8 +183,8 @@ mod tests {
183 let crate_def_map = db.crate_def_map(krate); 183 let crate_def_map = db.crate_def_map(krate);
184 184
185 let module = crate_def_map.modules_for_file(file_id).next().unwrap(); 185 let module = crate_def_map.modules_for_file(file_id).next().unwrap();
186 let (_, res) = crate_def_map[module].scope.entries().next().unwrap(); 186 let (_, def) = crate_def_map[module].scope.entries().next().unwrap();
187 match res.def.take_values().unwrap() { 187 match def.take_values().unwrap() {
188 ModuleDefId::FunctionId(it) => it, 188 ModuleDefId::FunctionId(it) => it,
189 _ => panic!(), 189 _ => panic!(),
190 } 190 }
@@ -211,7 +211,7 @@ mod tests {
211 let (_body, source_map) = db.body_with_source_map(function.into()); 211 let (_body, source_map) = db.body_with_source_map(function.into());
212 212
213 let expr_id = source_map 213 let expr_id = source_map
214 .node_expr(Source { file_id: file_id.into(), value: &marker.into() }) 214 .node_expr(InFile { file_id: file_id.into(), value: &marker.into() })
215 .unwrap(); 215 .unwrap();
216 let scope = scopes.scope_for(expr_id); 216 let scope = scopes.scope_for(expr_id);
217 217
@@ -318,7 +318,7 @@ mod tests {
318 let expr_scope = { 318 let expr_scope = {
319 let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap(); 319 let expr_ast = name_ref.syntax().ancestors().find_map(ast::Expr::cast).unwrap();
320 let expr_id = 320 let expr_id =
321 source_map.node_expr(Source { file_id: file_id.into(), value: &expr_ast }).unwrap(); 321 source_map.node_expr(InFile { file_id: file_id.into(), value: &expr_ast }).unwrap();
322 scopes.scope_for(expr_id).unwrap() 322 scopes.scope_for(expr_id).unwrap()
323 }; 323 };
324 324
diff --git a/crates/ra_hir_def/src/builtin_type.rs b/crates/ra_hir_def/src/builtin_type.rs
index 5e8157144..d14901a9b 100644
--- a/crates/ra_hir_def/src/builtin_type.rs
+++ b/crates/ra_hir_def/src/builtin_type.rs
@@ -5,7 +5,7 @@
5 5
6use std::fmt; 6use std::fmt;
7 7
8use hir_expand::name::{self, Name}; 8use hir_expand::name::{name, Name};
9 9
10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)] 10#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
11pub enum Signedness { 11pub enum Signedness {
@@ -52,26 +52,26 @@ pub enum BuiltinType {
52impl BuiltinType { 52impl BuiltinType {
53 #[rustfmt::skip] 53 #[rustfmt::skip]
54 pub const ALL: &'static [(Name, BuiltinType)] = &[ 54 pub const ALL: &'static [(Name, BuiltinType)] = &[
55 (name::CHAR, BuiltinType::Char), 55 (name![char], BuiltinType::Char),
56 (name::BOOL, BuiltinType::Bool), 56 (name![bool], BuiltinType::Bool),
57 (name::STR, BuiltinType::Str ), 57 (name![str], BuiltinType::Str),
58 58
59 (name::ISIZE, BuiltinType::Int(BuiltinInt::ISIZE)), 59 (name![isize], BuiltinType::Int(BuiltinInt::ISIZE)),
60 (name::I8, BuiltinType::Int(BuiltinInt::I8)), 60 (name![i8], BuiltinType::Int(BuiltinInt::I8)),
61 (name::I16, BuiltinType::Int(BuiltinInt::I16)), 61 (name![i16], BuiltinType::Int(BuiltinInt::I16)),
62 (name::I32, BuiltinType::Int(BuiltinInt::I32)), 62 (name![i32], BuiltinType::Int(BuiltinInt::I32)),
63 (name::I64, BuiltinType::Int(BuiltinInt::I64)), 63 (name![i64], BuiltinType::Int(BuiltinInt::I64)),
64 (name::I128, BuiltinType::Int(BuiltinInt::I128)), 64 (name![i128], BuiltinType::Int(BuiltinInt::I128)),
65 65
66 (name::USIZE, BuiltinType::Int(BuiltinInt::USIZE)), 66 (name![usize], BuiltinType::Int(BuiltinInt::USIZE)),
67 (name::U8, BuiltinType::Int(BuiltinInt::U8)), 67 (name![u8], BuiltinType::Int(BuiltinInt::U8)),
68 (name::U16, BuiltinType::Int(BuiltinInt::U16)), 68 (name![u16], BuiltinType::Int(BuiltinInt::U16)),
69 (name::U32, BuiltinType::Int(BuiltinInt::U32)), 69 (name![u32], BuiltinType::Int(BuiltinInt::U32)),
70 (name::U64, BuiltinType::Int(BuiltinInt::U64)), 70 (name![u64], BuiltinType::Int(BuiltinInt::U64)),
71 (name::U128, BuiltinType::Int(BuiltinInt::U128)), 71 (name![u128], BuiltinType::Int(BuiltinInt::U128)),
72 72
73 (name::F32, BuiltinType::Float(BuiltinFloat::F32)), 73 (name![f32], BuiltinType::Float(BuiltinFloat::F32)),
74 (name::F64, BuiltinType::Float(BuiltinFloat::F64)), 74 (name![f64], BuiltinType::Float(BuiltinFloat::F64)),
75 ]; 75 ];
76} 76}
77 77
diff --git a/crates/ra_hir_def/src/child_by_source.rs b/crates/ra_hir_def/src/child_by_source.rs
new file mode 100644
index 000000000..8b6c773ee
--- /dev/null
+++ b/crates/ra_hir_def/src/child_by_source.rs
@@ -0,0 +1,177 @@
1//! When *constructing* `hir`, we start at some parent syntax node and recursively
2//! lower the children.
3//!
4//! This modules allows one to go in the opposite direction: start with a syntax
5//! node for a *child*, and get its hir.
6
7use either::Either;
8
9use crate::{
10 db::DefDatabase,
11 dyn_map::DynMap,
12 item_scope::ItemScope,
13 keys,
14 src::{HasChildSource, HasSource},
15 AdtId, AssocItemId, DefWithBodyId, EnumId, EnumVariantId, ImplId, Lookup, ModuleDefId,
16 ModuleId, StructFieldId, TraitId, VariantId,
17};
18
19pub trait ChildBySource {
20 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap;
21}
22
23impl ChildBySource for TraitId {
24 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
25 let mut res = DynMap::default();
26
27 let data = db.trait_data(*self);
28 for (_name, item) in data.items.iter() {
29 match *item {
30 AssocItemId::FunctionId(func) => {
31 let src = func.lookup(db).source(db);
32 res[keys::FUNCTION].insert(src, func)
33 }
34 AssocItemId::ConstId(konst) => {
35 let src = konst.lookup(db).source(db);
36 res[keys::CONST].insert(src, konst)
37 }
38 AssocItemId::TypeAliasId(ty) => {
39 let src = ty.lookup(db).source(db);
40 res[keys::TYPE_ALIAS].insert(src, ty)
41 }
42 }
43 }
44
45 res
46 }
47}
48
49impl ChildBySource for ImplId {
50 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
51 let mut res = DynMap::default();
52
53 let data = db.impl_data(*self);
54 for &item in data.items.iter() {
55 match item {
56 AssocItemId::FunctionId(func) => {
57 let src = func.lookup(db).source(db);
58 res[keys::FUNCTION].insert(src, func)
59 }
60 AssocItemId::ConstId(konst) => {
61 let src = konst.lookup(db).source(db);
62 res[keys::CONST].insert(src, konst)
63 }
64 AssocItemId::TypeAliasId(ty) => {
65 let src = ty.lookup(db).source(db);
66 res[keys::TYPE_ALIAS].insert(src, ty)
67 }
68 }
69 }
70
71 res
72 }
73}
74
75impl ChildBySource for ModuleId {
76 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
77 let crate_def_map = db.crate_def_map(self.krate);
78 let module_data = &crate_def_map[self.local_id];
79 module_data.scope.child_by_source(db)
80 }
81}
82
83impl ChildBySource for ItemScope {
84 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
85 let mut res = DynMap::default();
86 self.declarations().for_each(|item| add_module_def(db, &mut res, item));
87 self.impls().for_each(|imp| add_impl(db, &mut res, imp));
88 return res;
89
90 fn add_module_def(db: &impl DefDatabase, map: &mut DynMap, item: ModuleDefId) {
91 match item {
92 ModuleDefId::FunctionId(func) => {
93 let src = func.lookup(db).source(db);
94 map[keys::FUNCTION].insert(src, func)
95 }
96 ModuleDefId::ConstId(konst) => {
97 let src = konst.lookup(db).source(db);
98 map[keys::CONST].insert(src, konst)
99 }
100 ModuleDefId::StaticId(statik) => {
101 let src = statik.lookup(db).source(db);
102 map[keys::STATIC].insert(src, statik)
103 }
104 ModuleDefId::TypeAliasId(ty) => {
105 let src = ty.lookup(db).source(db);
106 map[keys::TYPE_ALIAS].insert(src, ty)
107 }
108 ModuleDefId::TraitId(trait_) => {
109 let src = trait_.lookup(db).source(db);
110 map[keys::TRAIT].insert(src, trait_)
111 }
112 ModuleDefId::AdtId(adt) => match adt {
113 AdtId::StructId(strukt) => {
114 let src = strukt.lookup(db).source(db);
115 map[keys::STRUCT].insert(src, strukt)
116 }
117 AdtId::UnionId(union_) => {
118 let src = union_.lookup(db).source(db);
119 map[keys::UNION].insert(src, union_)
120 }
121 AdtId::EnumId(enum_) => {
122 let src = enum_.lookup(db).source(db);
123 map[keys::ENUM].insert(src, enum_)
124 }
125 },
126 _ => (),
127 }
128 }
129 fn add_impl(db: &impl DefDatabase, map: &mut DynMap, imp: ImplId) {
130 let src = imp.lookup(db).source(db);
131 map[keys::IMPL].insert(src, imp)
132 }
133 }
134}
135
136impl ChildBySource for VariantId {
137 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
138 let mut res = DynMap::default();
139
140 let arena_map = self.child_source(db);
141 let arena_map = arena_map.as_ref();
142 for (local_id, source) in arena_map.value.iter() {
143 let id = StructFieldId { parent: *self, local_id };
144 match source {
145 Either::Left(source) => {
146 res[keys::TUPLE_FIELD].insert(arena_map.with_value(source.clone()), id)
147 }
148 Either::Right(source) => {
149 res[keys::RECORD_FIELD].insert(arena_map.with_value(source.clone()), id)
150 }
151 }
152 }
153 res
154 }
155}
156
157impl ChildBySource for EnumId {
158 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
159 let mut res = DynMap::default();
160
161 let arena_map = self.child_source(db);
162 let arena_map = arena_map.as_ref();
163 for (local_id, source) in arena_map.value.iter() {
164 let id = EnumVariantId { parent: *self, local_id };
165 res[keys::ENUM_VARIANT].insert(arena_map.with_value(source.clone()), id)
166 }
167
168 res
169 }
170}
171
172impl ChildBySource for DefWithBodyId {
173 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
174 let body = db.body(*self);
175 body.item_scope.child_by_source(db)
176 }
177}
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs
index fee10b237..1aa9a9b7d 100644
--- a/crates/ra_hir_def/src/data.rs
+++ b/crates/ra_hir_def/src/data.rs
@@ -3,16 +3,17 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_expand::{ 5use hir_expand::{
6 name::{self, AsName, Name}, 6 name::{name, AsName, Name},
7 AstId, 7 AstId, InFile,
8}; 8};
9use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner}; 9use ra_syntax::ast::{self, AstNode, ImplItem, ModuleItemOwner, NameOwner, TypeAscriptionOwner};
10 10
11use crate::{ 11use crate::{
12 db::DefDatabase, 12 db::DefDatabase,
13 src::HasSource,
13 type_ref::{Mutability, TypeRef}, 14 type_ref::{Mutability, TypeRef},
14 AssocItemId, AstItemDef, ConstId, ConstLoc, ContainerId, FunctionId, FunctionLoc, HasSource, 15 AssocContainerId, AssocItemId, ConstId, ConstLoc, Expander, FunctionId, FunctionLoc, HasModule,
15 ImplId, Intern, Lookup, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 16 ImplId, Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
16}; 17};
17 18
18#[derive(Debug, Clone, PartialEq, Eq)] 19#[derive(Debug, Clone, PartialEq, Eq)]
@@ -36,7 +37,7 @@ impl FunctionData {
36 let self_type = if let Some(type_ref) = self_param.ascribed_type() { 37 let self_type = if let Some(type_ref) = self_param.ascribed_type() {
37 TypeRef::from_ast(type_ref) 38 TypeRef::from_ast(type_ref)
38 } else { 39 } else {
39 let self_type = TypeRef::Path(name::SELF_TYPE.into()); 40 let self_type = TypeRef::Path(name![Self].into());
40 match self_param.kind() { 41 match self_param.kind() {
41 ast::SelfParamKind::Owned => self_type, 42 ast::SelfParamKind::Owned => self_type,
42 ast::SelfParamKind::Ref => { 43 ast::SelfParamKind::Ref => {
@@ -93,12 +94,12 @@ pub struct TraitData {
93 94
94impl TraitData { 95impl TraitData {
95 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> { 96 pub(crate) fn trait_data_query(db: &impl DefDatabase, tr: TraitId) -> Arc<TraitData> {
96 let src = tr.source(db); 97 let src = tr.lookup(db).source(db);
97 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name()); 98 let name = src.value.name().map_or_else(Name::missing, |n| n.as_name());
98 let auto = src.value.is_auto(); 99 let auto = src.value.is_auto();
99 let ast_id_map = db.ast_id_map(src.file_id); 100 let ast_id_map = db.ast_id_map(src.file_id);
100 101
101 let container = ContainerId::TraitId(tr); 102 let container = AssocContainerId::TraitId(tr);
102 let items = if let Some(item_list) = src.value.item_list() { 103 let items = if let Some(item_list) = src.value.item_list() {
103 item_list 104 item_list
104 .impl_items() 105 .impl_items()
@@ -166,46 +167,24 @@ pub struct ImplData {
166 167
167impl ImplData { 168impl ImplData {
168 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> { 169 pub(crate) fn impl_data_query(db: &impl DefDatabase, id: ImplId) -> Arc<ImplData> {
169 let src = id.source(db); 170 let impl_loc = id.lookup(db);
170 let items = db.ast_id_map(src.file_id); 171 let src = impl_loc.source(db);
171 172
172 let target_trait = src.value.target_trait().map(TypeRef::from_ast); 173 let target_trait = src.value.target_trait().map(TypeRef::from_ast);
173 let target_type = TypeRef::from_ast_opt(src.value.target_type()); 174 let target_type = TypeRef::from_ast_opt(src.value.target_type());
174 let is_negative = src.value.is_negative(); 175 let is_negative = src.value.is_negative();
176 let module_id = impl_loc.container.module(db);
175 177
176 let items = if let Some(item_list) = src.value.item_list() { 178 let mut items = Vec::new();
177 item_list 179 if let Some(item_list) = src.value.item_list() {
178 .impl_items() 180 items.extend(collect_impl_items(db, item_list.impl_items(), src.file_id, id));
179 .map(|item_node| match item_node { 181 items.extend(collect_impl_items_in_macros(
180 ast::ImplItem::FnDef(it) => { 182 db,
181 let def = FunctionLoc { 183 module_id,
182 container: ContainerId::ImplId(id), 184 &src.with_value(item_list),
183 ast_id: AstId::new(src.file_id, items.ast_id(&it)), 185 id,
184 } 186 ));
185 .intern(db); 187 }
186 def.into()
187 }
188 ast::ImplItem::ConstDef(it) => {
189 let def = ConstLoc {
190 container: ContainerId::ImplId(id),
191 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
192 }
193 .intern(db);
194 def.into()
195 }
196 ast::ImplItem::TypeAliasDef(it) => {
197 let def = TypeAliasLoc {
198 container: ContainerId::ImplId(id),
199 ast_id: AstId::new(src.file_id, items.ast_id(&it)),
200 }
201 .intern(db);
202 def.into()
203 }
204 })
205 .collect()
206 } else {
207 Vec::new()
208 };
209 188
210 let res = ImplData { target_trait, target_type, items, is_negative }; 189 let res = ImplData { target_trait, target_type, items, is_negative };
211 Arc::new(res) 190 Arc::new(res)
@@ -236,3 +215,92 @@ impl ConstData {
236 ConstData { name, type_ref } 215 ConstData { name, type_ref }
237 } 216 }
238} 217}
218
219fn collect_impl_items_in_macros(
220 db: &impl DefDatabase,
221 module_id: ModuleId,
222 impl_block: &InFile<ast::ItemList>,
223 id: ImplId,
224) -> Vec<AssocItemId> {
225 let mut expander = Expander::new(db, impl_block.file_id, module_id);
226 let mut res = Vec::new();
227
228 // We set a limit to protect against infinite recursion
229 let limit = 100;
230
231 for m in impl_block.value.syntax().children().filter_map(ast::MacroCall::cast) {
232 res.extend(collect_impl_items_in_macro(db, &mut expander, m, id, limit))
233 }
234
235 res
236}
237
238fn collect_impl_items_in_macro(
239 db: &impl DefDatabase,
240 expander: &mut Expander,
241 m: ast::MacroCall,
242 id: ImplId,
243 limit: usize,
244) -> Vec<AssocItemId> {
245 if limit == 0 {
246 return Vec::new();
247 }
248
249 if let Some((mark, items)) = expander.enter_expand(db, m) {
250 let items: InFile<ast::MacroItems> = expander.to_source(items);
251 let mut res = collect_impl_items(
252 db,
253 items.value.items().filter_map(|it| ImplItem::cast(it.syntax().clone())),
254 items.file_id,
255 id,
256 );
257 // Recursive collect macros
258 // Note that ast::ModuleItem do not include ast::MacroCall
259 // We cannot use ModuleItemOwner::items here
260 for it in items.value.syntax().children().filter_map(ast::MacroCall::cast) {
261 res.extend(collect_impl_items_in_macro(db, expander, it, id, limit - 1))
262 }
263 expander.exit(db, mark);
264 res
265 } else {
266 Vec::new()
267 }
268}
269
270fn collect_impl_items(
271 db: &impl DefDatabase,
272 impl_items: impl Iterator<Item = ImplItem>,
273 file_id: crate::HirFileId,
274 id: ImplId,
275) -> Vec<AssocItemId> {
276 let items = db.ast_id_map(file_id);
277
278 impl_items
279 .map(|item_node| match item_node {
280 ast::ImplItem::FnDef(it) => {
281 let def = FunctionLoc {
282 container: AssocContainerId::ImplId(id),
283 ast_id: AstId::new(file_id, items.ast_id(&it)),
284 }
285 .intern(db);
286 def.into()
287 }
288 ast::ImplItem::ConstDef(it) => {
289 let def = ConstLoc {
290 container: AssocContainerId::ImplId(id),
291 ast_id: AstId::new(file_id, items.ast_id(&it)),
292 }
293 .intern(db);
294 def.into()
295 }
296 ast::ImplItem::TypeAliasDef(it) => {
297 let def = TypeAliasLoc {
298 container: AssocContainerId::ImplId(id),
299 ast_id: AstId::new(file_id, items.ast_id(&it)),
300 }
301 .intern(db);
302 def.into()
303 }
304 })
305 .collect()
306}
diff --git a/crates/ra_hir_def/src/db.rs b/crates/ra_hir_def/src/db.rs
index ef5611ffc..c55fd4111 100644
--- a/crates/ra_hir_def/src/db.rs
+++ b/crates/ra_hir_def/src/db.rs
@@ -3,7 +3,7 @@ use std::sync::Arc;
3 3
4use hir_expand::{db::AstDatabase, HirFileId}; 4use hir_expand::{db::AstDatabase, HirFileId};
5use ra_db::{salsa, CrateId, SourceDatabase}; 5use ra_db::{salsa, CrateId, SourceDatabase};
6use ra_syntax::{ast, SmolStr}; 6use ra_syntax::SmolStr;
7 7
8use crate::{ 8use crate::{
9 adt::{EnumData, StructData}, 9 adt::{EnumData, StructData},
@@ -13,13 +13,10 @@ use crate::{
13 docs::Documentation, 13 docs::Documentation,
14 generics::GenericParams, 14 generics::GenericParams,
15 lang_item::{LangItemTarget, LangItems}, 15 lang_item::{LangItemTarget, LangItems},
16 nameres::{ 16 nameres::{raw::RawItems, CrateDefMap},
17 raw::{ImportSourceMap, RawItems}, 17 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
18 CrateDefMap, 18 GenericDefId, ImplId, ImplLoc, ModuleId, StaticId, StaticLoc, StructId, StructLoc, TraitId,
19 }, 19 TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
20 AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, FunctionId, FunctionLoc, GenericDefId,
21 ImplId, ItemLoc, ModuleId, StaticId, StaticLoc, StructId, TraitId, TypeAliasId, TypeAliasLoc,
22 UnionId,
23}; 20};
24 21
25#[salsa::query_group(InternDatabaseStorage)] 22#[salsa::query_group(InternDatabaseStorage)]
@@ -27,31 +24,25 @@ pub trait InternDatabase: SourceDatabase {
27 #[salsa::interned] 24 #[salsa::interned]
28 fn intern_function(&self, loc: FunctionLoc) -> FunctionId; 25 fn intern_function(&self, loc: FunctionLoc) -> FunctionId;
29 #[salsa::interned] 26 #[salsa::interned]
30 fn intern_struct(&self, loc: ItemLoc<ast::StructDef>) -> StructId; 27 fn intern_struct(&self, loc: StructLoc) -> StructId;
31 #[salsa::interned] 28 #[salsa::interned]
32 fn intern_union(&self, loc: ItemLoc<ast::UnionDef>) -> UnionId; 29 fn intern_union(&self, loc: UnionLoc) -> UnionId;
33 #[salsa::interned] 30 #[salsa::interned]
34 fn intern_enum(&self, loc: ItemLoc<ast::EnumDef>) -> EnumId; 31 fn intern_enum(&self, loc: EnumLoc) -> EnumId;
35 #[salsa::interned] 32 #[salsa::interned]
36 fn intern_const(&self, loc: ConstLoc) -> ConstId; 33 fn intern_const(&self, loc: ConstLoc) -> ConstId;
37 #[salsa::interned] 34 #[salsa::interned]
38 fn intern_static(&self, loc: StaticLoc) -> StaticId; 35 fn intern_static(&self, loc: StaticLoc) -> StaticId;
39 #[salsa::interned] 36 #[salsa::interned]
40 fn intern_trait(&self, loc: ItemLoc<ast::TraitDef>) -> TraitId; 37 fn intern_trait(&self, loc: TraitLoc) -> TraitId;
41 #[salsa::interned] 38 #[salsa::interned]
42 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId; 39 fn intern_type_alias(&self, loc: TypeAliasLoc) -> TypeAliasId;
43 #[salsa::interned] 40 #[salsa::interned]
44 fn intern_impl(&self, loc: ItemLoc<ast::ImplBlock>) -> ImplId; 41 fn intern_impl(&self, loc: ImplLoc) -> ImplId;
45} 42}
46 43
47#[salsa::query_group(DefDatabaseStorage)] 44#[salsa::query_group(DefDatabaseStorage)]
48pub trait DefDatabase: InternDatabase + AstDatabase { 45pub trait DefDatabase: InternDatabase + AstDatabase {
49 #[salsa::invoke(RawItems::raw_items_with_source_map_query)]
50 fn raw_items_with_source_map(
51 &self,
52 file_id: HirFileId,
53 ) -> (Arc<RawItems>, Arc<ImportSourceMap>);
54
55 #[salsa::invoke(RawItems::raw_items_query)] 46 #[salsa::invoke(RawItems::raw_items_query)]
56 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>; 47 fn raw_items(&self, file_id: HirFileId) -> Arc<RawItems>;
57 48
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs
index eda9b2269..095498429 100644
--- a/crates/ra_hir_def/src/diagnostics.rs
+++ b/crates/ra_hir_def/src/diagnostics.rs
@@ -6,7 +6,7 @@ use hir_expand::diagnostics::Diagnostic;
6use ra_db::RelativePathBuf; 6use ra_db::RelativePathBuf;
7use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; 7use ra_syntax::{ast, AstPtr, SyntaxNodePtr};
8 8
9use hir_expand::{HirFileId, Source}; 9use hir_expand::{HirFileId, InFile};
10 10
11#[derive(Debug)] 11#[derive(Debug)]
12pub struct UnresolvedModule { 12pub struct UnresolvedModule {
@@ -19,8 +19,8 @@ impl Diagnostic for UnresolvedModule {
19 fn message(&self) -> String { 19 fn message(&self) -> String {
20 "unresolved module".to_string() 20 "unresolved module".to_string()
21 } 21 }
22 fn source(&self) -> Source<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 Source { file_id: self.file, value: self.decl.into() } 23 InFile { file_id: self.file, value: self.decl.into() }
24 } 24 }
25 fn as_any(&self) -> &(dyn Any + Send + 'static) { 25 fn as_any(&self) -> &(dyn Any + Send + 'static) {
26 self 26 self
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs
index 34ed9b7a5..b29f142e3 100644
--- a/crates/ra_hir_def/src/docs.rs
+++ b/crates/ra_hir_def/src/docs.rs
@@ -5,10 +5,14 @@
5 5
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use hir_expand::either::Either; 8use either::Either;
9use ra_syntax::ast; 9use ra_syntax::ast;
10 10
11use crate::{db::DefDatabase, AdtId, AstItemDef, AttrDefId, HasChildSource, HasSource, Lookup}; 11use crate::{
12 db::DefDatabase,
13 src::{HasChildSource, HasSource},
14 AdtId, AttrDefId, Lookup,
15};
12 16
13/// Holds documentation 17/// Holds documentation
14#[derive(Debug, Clone, PartialEq, Eq)] 18#[derive(Debug, Clone, PartialEq, Eq)]
@@ -42,21 +46,21 @@ impl Documentation {
42 AttrDefId::StructFieldId(it) => { 46 AttrDefId::StructFieldId(it) => {
43 let src = it.parent.child_source(db); 47 let src = it.parent.child_source(db);
44 match &src.value[it.local_id] { 48 match &src.value[it.local_id] {
45 Either::A(_tuple) => None, 49 Either::Left(_tuple) => None,
46 Either::B(record) => docs_from_ast(record), 50 Either::Right(record) => docs_from_ast(record),
47 } 51 }
48 } 52 }
49 AttrDefId::AdtId(it) => match it { 53 AttrDefId::AdtId(it) => match it {
50 AdtId::StructId(it) => docs_from_ast(&it.source(db).value), 54 AdtId::StructId(it) => docs_from_ast(&it.lookup(db).source(db).value),
51 AdtId::EnumId(it) => docs_from_ast(&it.source(db).value), 55 AdtId::EnumId(it) => docs_from_ast(&it.lookup(db).source(db).value),
52 AdtId::UnionId(it) => docs_from_ast(&it.source(db).value), 56 AdtId::UnionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
53 }, 57 },
54 AttrDefId::EnumVariantId(it) => { 58 AttrDefId::EnumVariantId(it) => {
55 let src = it.parent.child_source(db); 59 let src = it.parent.child_source(db);
56 docs_from_ast(&src.value[it.local_id]) 60 docs_from_ast(&src.value[it.local_id])
57 } 61 }
58 AttrDefId::TraitId(it) => docs_from_ast(&it.source(db).value), 62 AttrDefId::TraitId(it) => docs_from_ast(&it.lookup(db).source(db).value),
59 AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id.to_node(db)), 63 AttrDefId::MacroDefId(it) => docs_from_ast(&it.ast_id?.to_node(db)),
60 AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value), 64 AttrDefId::ConstId(it) => docs_from_ast(&it.lookup(db).source(db).value),
61 AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value), 65 AttrDefId::StaticId(it) => docs_from_ast(&it.lookup(db).source(db).value),
62 AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value), 66 AttrDefId::FunctionId(it) => docs_from_ast(&it.lookup(db).source(db).value),
diff --git a/crates/ra_hir_def/src/dyn_map.rs b/crates/ra_hir_def/src/dyn_map.rs
new file mode 100644
index 000000000..6f269d7b0
--- /dev/null
+++ b/crates/ra_hir_def/src/dyn_map.rs
@@ -0,0 +1,108 @@
1//! This module defines a `DynMap` -- a container for heterogeneous maps.
2//!
3//! This means that `DynMap` stores a bunch of hash maps inside, and those maps
4//! can be of different types.
5//!
6//! It is used like this:
7//!
8//! ```
9//! // keys define submaps of a `DynMap`
10//! const STRING_TO_U32: Key<String, u32> = Key::new();
11//! const U32_TO_VEC: Key<u32, Vec<bool>> = Key::new();
12//!
13//! // Note: concrete type, no type params!
14//! let mut map = DynMap::new();
15//!
16//! // To access a specific map, index the `DynMap` by `Key`:
17//! map[STRING_TO_U32].insert("hello".to_string(), 92);
18//! let value = map[U32_TO_VEC].get(92);
19//! assert!(value.is_none());
20//! ```
21//!
22//! This is a work of fiction. Any similarities to Kotlin's `BindingContext` are
23//! a coincidence.
24use std::{
25 hash::Hash,
26 marker::PhantomData,
27 ops::{Index, IndexMut},
28};
29
30use anymap::Map;
31use rustc_hash::FxHashMap;
32
33pub struct Key<K, V, P = (K, V)> {
34 _phantom: PhantomData<(K, V, P)>,
35}
36
37impl<K, V, P> Key<K, V, P> {
38 pub(crate) const fn new() -> Key<K, V, P> {
39 Key { _phantom: PhantomData }
40 }
41}
42
43impl<K, V, P> Copy for Key<K, V, P> {}
44
45impl<K, V, P> Clone for Key<K, V, P> {
46 fn clone(&self) -> Key<K, V, P> {
47 *self
48 }
49}
50
51pub trait Policy {
52 type K;
53 type V;
54
55 fn insert(map: &mut DynMap, key: Self::K, value: Self::V);
56 fn get<'a>(map: &'a DynMap, key: &Self::K) -> Option<&'a Self::V>;
57}
58
59impl<K: Hash + Eq + 'static, V: 'static> Policy for (K, V) {
60 type K = K;
61 type V = V;
62 fn insert(map: &mut DynMap, key: K, value: V) {
63 map.map.entry::<FxHashMap<K, V>>().or_insert_with(Default::default).insert(key, value);
64 }
65 fn get<'a>(map: &'a DynMap, key: &K) -> Option<&'a V> {
66 map.map.get::<FxHashMap<K, V>>()?.get(key)
67 }
68}
69
70pub struct DynMap {
71 pub(crate) map: Map,
72}
73
74impl Default for DynMap {
75 fn default() -> Self {
76 DynMap { map: Map::new() }
77 }
78}
79
80#[repr(transparent)]
81pub struct KeyMap<KEY> {
82 map: DynMap,
83 _phantom: PhantomData<KEY>,
84}
85
86impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
87 pub fn insert(&mut self, key: P::K, value: P::V) {
88 P::insert(&mut self.map, key, value)
89 }
90 pub fn get(&self, key: &P::K) -> Option<&P::V> {
91 P::get(&self.map, key)
92 }
93}
94
95impl<P: Policy> Index<Key<P::K, P::V, P>> for DynMap {
96 type Output = KeyMap<Key<P::K, P::V, P>>;
97 fn index(&self, _key: Key<P::K, P::V, P>) -> &Self::Output {
98 // Safe due to `#[repr(transparent)]`.
99 unsafe { std::mem::transmute::<&DynMap, &KeyMap<Key<P::K, P::V, P>>>(self) }
100 }
101}
102
103impl<P: Policy> IndexMut<Key<P::K, P::V, P>> for DynMap {
104 fn index_mut(&mut self, _key: Key<P::K, P::V, P>) -> &mut Self::Output {
105 // Safe due to `#[repr(transparent)]`.
106 unsafe { std::mem::transmute::<&mut DynMap, &mut KeyMap<Key<P::K, P::V, P>>>(self) }
107 }
108}
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index 04c1d8f69..a75ef9970 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -14,6 +14,7 @@
14 14
15use hir_expand::name::Name; 15use hir_expand::name::Name;
16use ra_arena::{impl_arena_id, RawId}; 16use ra_arena::{impl_arena_id, RawId};
17use ra_syntax::ast::RangeOp;
17 18
18use crate::{ 19use crate::{
19 builtin_type::{BuiltinFloat, BuiltinInt}, 20 builtin_type::{BuiltinFloat, BuiltinInt},
@@ -130,6 +131,11 @@ pub enum Expr {
130 rhs: ExprId, 131 rhs: ExprId,
131 op: Option<BinaryOp>, 132 op: Option<BinaryOp>,
132 }, 133 },
134 Range {
135 lhs: Option<ExprId>,
136 rhs: Option<ExprId>,
137 range_type: RangeOp,
138 },
133 Index { 139 Index {
134 base: ExprId, 140 base: ExprId,
135 index: ExprId, 141 index: ExprId,
@@ -137,6 +143,7 @@ pub enum Expr {
137 Lambda { 143 Lambda {
138 args: Vec<PatId>, 144 args: Vec<PatId>,
139 arg_types: Vec<Option<TypeRef>>, 145 arg_types: Vec<Option<TypeRef>>,
146 ret_type: Option<TypeRef>,
140 body: ExprId, 147 body: ExprId,
141 }, 148 },
142 Tuple { 149 Tuple {
@@ -288,6 +295,14 @@ impl Expr {
288 f(*lhs); 295 f(*lhs);
289 f(*rhs); 296 f(*rhs);
290 } 297 }
298 Expr::Range { lhs, rhs, .. } => {
299 if let Some(lhs) = rhs {
300 f(*lhs);
301 }
302 if let Some(rhs) = lhs {
303 f(*rhs);
304 }
305 }
291 Expr::Index { base, index } => { 306 Expr::Index { base, index } => {
292 f(*base); 307 f(*base);
293 f(*index); 308 f(*index);
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index 3f94e40e4..e9c28c730 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -4,20 +4,29 @@
4//! in rustc. 4//! in rustc.
5use std::sync::Arc; 5use std::sync::Arc;
6 6
7use hir_expand::name::{self, AsName, Name}; 7use either::Either;
8use hir_expand::{
9 name::{name, AsName, Name},
10 InFile,
11};
12use ra_arena::{map::ArenaMap, Arena};
13use ra_db::FileId;
8use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; 14use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner};
9 15
10use crate::{ 16use crate::{
17 child_by_source::ChildBySource,
11 db::DefDatabase, 18 db::DefDatabase,
19 dyn_map::DynMap,
20 keys,
21 src::HasChildSource,
22 src::HasSource,
12 type_ref::{TypeBound, TypeRef}, 23 type_ref::{TypeBound, TypeRef},
13 AdtId, AstItemDef, ContainerId, GenericDefId, HasSource, Lookup, 24 AdtId, GenericDefId, LocalTypeParamId, Lookup, TypeParamId,
14}; 25};
15 26
16/// Data about a generic parameter (to a function, struct, impl, ...). 27/// Data about a generic parameter (to a function, struct, impl, ...).
17#[derive(Clone, PartialEq, Eq, Debug)] 28#[derive(Clone, PartialEq, Eq, Debug)]
18pub struct GenericParam { 29pub struct TypeParamData {
19 // FIXME: give generic params proper IDs
20 pub idx: u32,
21 pub name: Name, 30 pub name: Name,
22 pub default: Option<TypeRef>, 31 pub default: Option<TypeRef>,
23} 32}
@@ -25,8 +34,8 @@ pub struct GenericParam {
25/// Data about the generic parameters of a function, struct, impl, etc. 34/// Data about the generic parameters of a function, struct, impl, etc.
26#[derive(Clone, PartialEq, Eq, Debug)] 35#[derive(Clone, PartialEq, Eq, Debug)]
27pub struct GenericParams { 36pub struct GenericParams {
28 pub parent_params: Option<Arc<GenericParams>>, 37 pub types: Arena<LocalTypeParamId, TypeParamData>,
29 pub params: Vec<GenericParam>, 38 // lifetimes: Arena<LocalLifetimeParamId, LifetimeParamData>,
30 pub where_predicates: Vec<WherePredicate>, 39 pub where_predicates: Vec<WherePredicate>,
31} 40}
32 41
@@ -40,63 +49,87 @@ pub struct WherePredicate {
40 pub bound: TypeBound, 49 pub bound: TypeBound,
41} 50}
42 51
52type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
53
43impl GenericParams { 54impl GenericParams {
44 pub(crate) fn generic_params_query( 55 pub(crate) fn generic_params_query(
45 db: &impl DefDatabase, 56 db: &impl DefDatabase,
46 def: GenericDefId, 57 def: GenericDefId,
47 ) -> Arc<GenericParams> { 58 ) -> Arc<GenericParams> {
48 let parent_generics = parent_generic_def(db, def).map(|it| db.generic_params(it)); 59 let (params, _source_map) = GenericParams::new(db, def.into());
49 Arc::new(GenericParams::new(db, def.into(), parent_generics)) 60 Arc::new(params)
50 } 61 }
51 62
52 fn new( 63 fn new(db: &impl DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
53 db: &impl DefDatabase, 64 let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() };
54 def: GenericDefId, 65 let mut sm = ArenaMap::default();
55 parent_params: Option<Arc<GenericParams>>,
56 ) -> GenericParams {
57 let mut generics =
58 GenericParams { params: Vec::new(), parent_params, where_predicates: Vec::new() };
59 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
60 // FIXME: add `: Sized` bound for everything except for `Self` in traits 66 // FIXME: add `: Sized` bound for everything except for `Self` in traits
61 match def { 67 let file_id = match def {
62 GenericDefId::FunctionId(it) => generics.fill(&it.lookup(db).source(db).value, start), 68 GenericDefId::FunctionId(it) => {
63 GenericDefId::AdtId(AdtId::StructId(it)) => generics.fill(&it.source(db).value, start), 69 let src = it.lookup(db).source(db);
64 GenericDefId::AdtId(AdtId::UnionId(it)) => generics.fill(&it.source(db).value, start), 70 generics.fill(&mut sm, &src.value);
65 GenericDefId::AdtId(AdtId::EnumId(it)) => generics.fill(&it.source(db).value, start), 71 src.file_id
72 }
73 GenericDefId::AdtId(AdtId::StructId(it)) => {
74 let src = it.lookup(db).source(db);
75 generics.fill(&mut sm, &src.value);
76 src.file_id
77 }
78 GenericDefId::AdtId(AdtId::UnionId(it)) => {
79 let src = it.lookup(db).source(db);
80 generics.fill(&mut sm, &src.value);
81 src.file_id
82 }
83 GenericDefId::AdtId(AdtId::EnumId(it)) => {
84 let src = it.lookup(db).source(db);
85 generics.fill(&mut sm, &src.value);
86 src.file_id
87 }
66 GenericDefId::TraitId(it) => { 88 GenericDefId::TraitId(it) => {
89 let src = it.lookup(db).source(db);
90
67 // traits get the Self type as an implicit first type parameter 91 // traits get the Self type as an implicit first type parameter
68 generics.params.push(GenericParam { 92 let self_param_id =
69 idx: start, 93 generics.types.alloc(TypeParamData { name: name![Self], default: None });
70 name: name::SELF_TYPE, 94 sm.insert(self_param_id, Either::Left(src.value.clone()));
71 default: None,
72 });
73 generics.fill(&it.source(db).value, start + 1);
74 // add super traits as bounds on Self 95 // add super traits as bounds on Self
75 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
76 let self_param = TypeRef::Path(name::SELF_TYPE.into()); 97 let self_param = TypeRef::Path(name![Self].into());
77 generics.fill_bounds(&it.source(db).value, self_param); 98 generics.fill_bounds(&src.value, self_param);
99
100 generics.fill(&mut sm, &src.value);
101 src.file_id
102 }
103 GenericDefId::TypeAliasId(it) => {
104 let src = it.lookup(db).source(db);
105 generics.fill(&mut sm, &src.value);
106 src.file_id
78 } 107 }
79 GenericDefId::TypeAliasId(it) => generics.fill(&it.lookup(db).source(db).value, start),
80 // Note that we don't add `Self` here: in `impl`s, `Self` is not a 108 // Note that we don't add `Self` here: in `impl`s, `Self` is not a
81 // type-parameter, but rather is a type-alias for impl's target 109 // type-parameter, but rather is a type-alias for impl's target
82 // type, so this is handled by the resolver. 110 // type, so this is handled by the resolver.
83 GenericDefId::ImplId(it) => generics.fill(&it.source(db).value, start), 111 GenericDefId::ImplId(it) => {
84 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {} 112 let src = it.lookup(db).source(db);
85 } 113 generics.fill(&mut sm, &src.value);
114 src.file_id
115 }
116 // We won't be using this ID anyway
117 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
118 };
86 119
87 generics 120 (generics, InFile::new(file_id, sm))
88 } 121 }
89 122
90 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { 123 fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) {
91 if let Some(params) = node.type_param_list() { 124 if let Some(params) = node.type_param_list() {
92 self.fill_params(params, start) 125 self.fill_params(sm, params)
93 } 126 }
94 if let Some(where_clause) = node.where_clause() { 127 if let Some(where_clause) = node.where_clause() {
95 self.fill_where_predicates(where_clause); 128 self.fill_where_predicates(where_clause);
96 } 129 }
97 } 130 }
98 131
99 fn fill_bounds(&mut self, node: &impl ast::TypeBoundsOwner, type_ref: TypeRef) { 132 fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) {
100 for bound in 133 for bound in
101 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) 134 node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds())
102 { 135 {
@@ -104,13 +137,14 @@ impl GenericParams {
104 } 137 }
105 } 138 }
106 139
107 fn fill_params(&mut self, params: ast::TypeParamList, start: u32) { 140 fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) {
108 for (idx, type_param) in params.type_params().enumerate() { 141 for type_param in params.type_params() {
109 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 142 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
110 // FIXME: Use `Path::from_src` 143 // FIXME: Use `Path::from_src`
111 let default = type_param.default_type().map(TypeRef::from_ast); 144 let default = type_param.default_type().map(TypeRef::from_ast);
112 let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; 145 let param = TypeParamData { name: name.clone(), default };
113 self.params.push(param); 146 let param_id = self.types.alloc(param);
147 sm.insert(param_id, Either::Right(type_param.clone()));
114 148
115 let type_ref = TypeRef::Path(name.into()); 149 let type_ref = TypeRef::Path(name.into());
116 self.fill_bounds(&type_param, type_ref); 150 self.fill_bounds(&type_param, type_ref);
@@ -139,45 +173,31 @@ impl GenericParams {
139 self.where_predicates.push(WherePredicate { type_ref, bound }); 173 self.where_predicates.push(WherePredicate { type_ref, bound });
140 } 174 }
141 175
142 pub fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 176 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
143 self.params.iter().find(|p| &p.name == name) 177 self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None })
144 }
145
146 pub fn count_parent_params(&self) -> usize {
147 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
148 }
149
150 pub fn count_params_including_parent(&self) -> usize {
151 let parent_count = self.count_parent_params();
152 parent_count + self.params.len()
153 }
154
155 fn for_each_param<'a>(&'a self, f: &mut impl FnMut(&'a GenericParam)) {
156 if let Some(parent) = &self.parent_params {
157 parent.for_each_param(f);
158 }
159 self.params.iter().for_each(f);
160 } 178 }
179}
161 180
162 pub fn params_including_parent(&self) -> Vec<&GenericParam> { 181impl HasChildSource for GenericDefId {
163 let mut vec = Vec::with_capacity(self.count_params_including_parent()); 182 type ChildId = LocalTypeParamId;
164 self.for_each_param(&mut |p| vec.push(p)); 183 type Value = Either<ast::TraitDef, ast::TypeParam>;
165 vec 184 fn child_source(&self, db: &impl DefDatabase) -> InFile<SourceMap> {
185 let (_, sm) = GenericParams::new(db, *self);
186 sm
166 } 187 }
167} 188}
168 189
169fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> { 190impl ChildBySource for GenericDefId {
170 let container = match def { 191 fn child_by_source(&self, db: &impl DefDatabase) -> DynMap {
171 GenericDefId::FunctionId(it) => it.lookup(db).container, 192 let mut res = DynMap::default();
172 GenericDefId::TypeAliasId(it) => it.lookup(db).container, 193 let arena_map = self.child_source(db);
173 GenericDefId::ConstId(it) => it.lookup(db).container, 194 let arena_map = arena_map.as_ref();
174 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()), 195 for (local_id, src) in arena_map.value.iter() {
175 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None, 196 let id = TypeParamId { parent: *self, local_id };
176 }; 197 if let Either::Right(type_param) = src {
177 198 res[keys::TYPE_PARAM].insert(arena_map.with_value(type_param.clone()), id)
178 match container { 199 }
179 ContainerId::ImplId(it) => Some(it.into()), 200 }
180 ContainerId::TraitId(it) => Some(it.into()), 201 res
181 ContainerId::ModuleId(_) => None,
182 } 202 }
183} 203}
diff --git a/crates/ra_hir_def/src/item_scope.rs b/crates/ra_hir_def/src/item_scope.rs
new file mode 100644
index 000000000..b0288ee8d
--- /dev/null
+++ b/crates/ra_hir_def/src/item_scope.rs
@@ -0,0 +1,172 @@
1//! Describes items defined or visible (ie, imported) in a certain scope.
2//! This is shared between modules and blocks.
3
4use hir_expand::name::Name;
5use once_cell::sync::Lazy;
6use rustc_hash::FxHashMap;
7
8use crate::{per_ns::PerNs, AdtId, BuiltinType, ImplId, MacroDefId, ModuleDefId, TraitId};
9
10#[derive(Debug, Default, PartialEq, Eq)]
11pub struct ItemScope {
12 visible: FxHashMap<Name, PerNs>,
13 defs: Vec<ModuleDefId>,
14 impls: Vec<ImplId>,
15 /// Macros visible in current module in legacy textual scope
16 ///
17 /// For macros invoked by an unqualified identifier like `bar!()`, `legacy_macros` will be searched in first.
18 /// If it yields no result, then it turns to module scoped `macros`.
19 /// It macros with name qualified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
20 /// and only normal scoped `macros` will be searched in.
21 ///
22 /// Note that this automatically inherit macros defined textually before the definition of module itself.
23 ///
24 /// Module scoped macros will be inserted into `items` instead of here.
25 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
26 // be all resolved to the last one defined if shadowing happens.
27 legacy_macros: FxHashMap<Name, MacroDefId>,
28}
29
30static BUILTIN_SCOPE: Lazy<FxHashMap<Name, PerNs>> = Lazy::new(|| {
31 BuiltinType::ALL
32 .iter()
33 .map(|(name, ty)| (name.clone(), PerNs::types(ty.clone().into())))
34 .collect()
35});
36
37/// Shadow mode for builtin type which can be shadowed by module.
38#[derive(Debug, Copy, Clone, PartialEq, Eq)]
39pub(crate) enum BuiltinShadowMode {
40 // Prefer Module
41 Module,
42 // Prefer Other Types
43 Other,
44}
45
46/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
47/// Other methods will only resolve values, types and module scoped macros only.
48impl ItemScope {
49 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
50 //FIXME: shadowing
51 self.visible.iter().chain(BUILTIN_SCOPE.iter()).map(|(n, def)| (n, *def))
52 }
53
54 pub fn entries_without_primitives<'a>(
55 &'a self,
56 ) -> impl Iterator<Item = (&'a Name, PerNs)> + 'a {
57 self.visible.iter().map(|(n, def)| (n, *def))
58 }
59
60 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
61 self.defs.iter().copied()
62 }
63
64 pub fn impls(&self) -> impl Iterator<Item = ImplId> + ExactSizeIterator + '_ {
65 self.impls.iter().copied()
66 }
67
68 /// Iterate over all module scoped macros
69 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
70 self.visible.iter().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
71 }
72
73 /// Iterate over all legacy textual scoped macros visible at the end of the module
74 pub(crate) fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
75 self.legacy_macros.iter().map(|(name, def)| (name, *def))
76 }
77
78 /// Get a name from current module scope, legacy macros are not included
79 pub(crate) fn get(&self, name: &Name, shadow: BuiltinShadowMode) -> PerNs {
80 match shadow {
81 BuiltinShadowMode::Module => self
82 .visible
83 .get(name)
84 .or_else(|| BUILTIN_SCOPE.get(name))
85 .copied()
86 .unwrap_or_else(PerNs::none),
87 BuiltinShadowMode::Other => {
88 let item = self.visible.get(name).copied();
89 if let Some(def) = item {
90 if let Some(ModuleDefId::ModuleId(_)) = def.take_types() {
91 return BUILTIN_SCOPE
92 .get(name)
93 .copied()
94 .or(item)
95 .unwrap_or_else(PerNs::none);
96 }
97 }
98
99 item.or_else(|| BUILTIN_SCOPE.get(name).copied()).unwrap_or_else(PerNs::none)
100 }
101 }
102 }
103
104 pub(crate) fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a {
105 self.visible.values().filter_map(|def| match def.take_types() {
106 Some(ModuleDefId::TraitId(t)) => Some(t),
107 _ => None,
108 })
109 }
110
111 pub(crate) fn define_def(&mut self, def: ModuleDefId) {
112 self.defs.push(def)
113 }
114
115 pub(crate) fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> {
116 self.legacy_macros.get(name).copied()
117 }
118
119 pub(crate) fn define_impl(&mut self, imp: ImplId) {
120 self.impls.push(imp)
121 }
122
123 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
124 self.legacy_macros.insert(name, mac);
125 }
126
127 pub(crate) fn push_res(&mut self, name: Name, def: PerNs) -> bool {
128 let mut changed = false;
129 let existing = self.visible.entry(name.clone()).or_default();
130
131 if existing.types.is_none() && def.types.is_some() {
132 existing.types = def.types;
133 changed = true;
134 }
135 if existing.values.is_none() && def.values.is_some() {
136 existing.values = def.values;
137 changed = true;
138 }
139 if existing.macros.is_none() && def.macros.is_some() {
140 existing.macros = def.macros;
141 changed = true;
142 }
143
144 changed
145 }
146
147 pub(crate) fn collect_resolutions(&self) -> Vec<(Name, PerNs)> {
148 self.visible.iter().map(|(name, res)| (name.clone(), res.clone())).collect()
149 }
150
151 pub(crate) fn collect_legacy_macros(&self) -> FxHashMap<Name, MacroDefId> {
152 self.legacy_macros.clone()
153 }
154}
155
156impl From<ModuleDefId> for PerNs {
157 fn from(def: ModuleDefId) -> PerNs {
158 match def {
159 ModuleDefId::ModuleId(_) => PerNs::types(def),
160 ModuleDefId::FunctionId(_) => PerNs::values(def),
161 ModuleDefId::AdtId(adt) => match adt {
162 AdtId::StructId(_) | AdtId::UnionId(_) => PerNs::both(def, def),
163 AdtId::EnumId(_) => PerNs::types(def),
164 },
165 ModuleDefId::EnumVariantId(_) => PerNs::both(def, def),
166 ModuleDefId::ConstId(_) | ModuleDefId::StaticId(_) => PerNs::values(def),
167 ModuleDefId::TraitId(_) => PerNs::types(def),
168 ModuleDefId::TypeAliasId(_) => PerNs::types(def),
169 ModuleDefId::BuiltinType(_) => PerNs::types(def),
170 }
171 }
172}
diff --git a/crates/ra_hir_def/src/keys.rs b/crates/ra_hir_def/src/keys.rs
new file mode 100644
index 000000000..d844f7a62
--- /dev/null
+++ b/crates/ra_hir_def/src/keys.rs
@@ -0,0 +1,56 @@
1//! keys to be used with `DynMap`
2
3use std::marker::PhantomData;
4
5use hir_expand::InFile;
6use ra_syntax::{ast, AstNode, AstPtr};
7use rustc_hash::FxHashMap;
8
9use crate::{
10 dyn_map::{DynMap, Policy},
11 ConstId, EnumId, EnumVariantId, FunctionId, ImplId, StaticId, StructFieldId, StructId, TraitId,
12 TypeAliasId, TypeParamId, UnionId,
13};
14
15pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
16
17pub const FUNCTION: Key<ast::FnDef, FunctionId> = Key::new();
18pub const CONST: Key<ast::ConstDef, ConstId> = Key::new();
19pub const STATIC: Key<ast::StaticDef, StaticId> = Key::new();
20pub const TYPE_ALIAS: Key<ast::TypeAliasDef, TypeAliasId> = Key::new();
21pub const IMPL: Key<ast::ImplBlock, ImplId> = Key::new();
22pub const TRAIT: Key<ast::TraitDef, TraitId> = Key::new();
23pub const STRUCT: Key<ast::StructDef, StructId> = Key::new();
24pub const UNION: Key<ast::UnionDef, UnionId> = Key::new();
25pub const ENUM: Key<ast::EnumDef, EnumId> = Key::new();
26
27pub const ENUM_VARIANT: Key<ast::EnumVariant, EnumVariantId> = Key::new();
28pub const TUPLE_FIELD: Key<ast::TupleFieldDef, StructFieldId> = Key::new();
29pub const RECORD_FIELD: Key<ast::RecordFieldDef, StructFieldId> = Key::new();
30pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
31
32/// XXX: AST Nodes and SyntaxNodes have identity equality semantics: nodes are
33/// equal if they point to exactly the same object.
34///
35/// In general, we do not guarantee that we have exactly one instance of a
36/// syntax tree for each file. We probably should add such guarantee, but, for
37/// the time being, we will use identity-less AstPtr comparison.
38pub struct AstPtrPolicy<AST, ID> {
39 _phantom: PhantomData<(AST, ID)>,
40}
41
42impl<AST: AstNode + 'static, ID: 'static> Policy for AstPtrPolicy<AST, ID> {
43 type K = InFile<AST>;
44 type V = ID;
45 fn insert(map: &mut DynMap, key: InFile<AST>, value: ID) {
46 let key = key.as_ref().map(AstPtr::new);
47 map.map
48 .entry::<FxHashMap<InFile<AstPtr<AST>>, ID>>()
49 .or_insert_with(Default::default)
50 .insert(key, value);
51 }
52 fn get<'a>(map: &'a DynMap, key: &InFile<AST>) -> Option<&'a ID> {
53 let key = key.as_ref().map(AstPtr::new);
54 map.map.get::<FxHashMap<InFile<AstPtr<AST>>, ID>>()?.get(&key)
55 }
56}
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs
index f4fdbdcfc..cef061837 100644
--- a/crates/ra_hir_def/src/lang_item.rs
+++ b/crates/ra_hir_def/src/lang_item.rs
@@ -81,7 +81,7 @@ impl LangItems {
81 // Look for impl targets 81 // Look for impl targets
82 let def_map = db.crate_def_map(module.krate); 82 let def_map = db.crate_def_map(module.krate);
83 let module_data = &def_map[module.local_id]; 83 let module_data = &def_map[module.local_id];
84 for &impl_block in module_data.impls.iter() { 84 for impl_block in module_data.scope.impls() {
85 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId) 85 self.collect_lang_item(db, impl_block, LangItemTarget::ImplBlockId)
86 } 86 }
87 87
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs
index bc5530896..f6c7f38d1 100644
--- a/crates/ra_hir_def/src/lib.rs
+++ b/crates/ra_hir_def/src/lib.rs
@@ -15,6 +15,10 @@ pub mod type_ref;
15pub mod builtin_type; 15pub mod builtin_type;
16pub mod diagnostics; 16pub mod diagnostics;
17pub mod per_ns; 17pub mod per_ns;
18pub mod item_scope;
19
20pub mod dyn_map;
21pub mod keys;
18 22
19pub mod adt; 23pub mod adt;
20pub mod data; 24pub mod data;
@@ -29,23 +33,23 @@ pub mod resolver;
29mod trace; 33mod trace;
30pub mod nameres; 34pub mod nameres;
31 35
36pub mod src;
37pub mod child_by_source;
38
32#[cfg(test)] 39#[cfg(test)]
33mod test_db; 40mod test_db;
34#[cfg(test)] 41#[cfg(test)]
35mod marks; 42mod marks;
36 43
37use std::hash::{Hash, Hasher}; 44use std::hash::Hash;
38 45
39use hir_expand::{ast_id_map::FileAstId, db::AstDatabase, AstId, HirFileId, MacroDefId, Source}; 46use hir_expand::{ast_id_map::FileAstId, AstId, HirFileId, InFile, MacroDefId};
40use ra_arena::{impl_arena_id, map::ArenaMap, RawId}; 47use ra_arena::{impl_arena_id, RawId};
41use ra_db::{impl_intern_key, salsa, CrateId}; 48use ra_db::{impl_intern_key, salsa, CrateId};
42use ra_syntax::{ast, AstNode}; 49use ra_syntax::{ast, AstNode};
43 50
44use crate::{builtin_type::BuiltinType, db::InternDatabase}; 51use crate::body::Expander;
45 52use crate::builtin_type::BuiltinType;
46#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
47pub struct LocalImportId(RawId);
48impl_arena_id!(LocalImportId);
49 53
50#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 54#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
51pub struct ModuleId { 55pub struct ModuleId {
@@ -59,122 +63,57 @@ pub struct ModuleId {
59pub struct LocalModuleId(RawId); 63pub struct LocalModuleId(RawId);
60impl_arena_id!(LocalModuleId); 64impl_arena_id!(LocalModuleId);
61 65
62#[derive(Debug)] 66#[derive(Debug, Clone, PartialEq, Eq, Hash)]
63pub struct ItemLoc<N: AstNode> { 67pub struct ItemLoc<N: AstNode> {
64 pub(crate) module: ModuleId, 68 pub container: ContainerId,
65 ast_id: AstId<N>, 69 pub ast_id: AstId<N>,
66}
67
68impl<N: AstNode> PartialEq for ItemLoc<N> {
69 fn eq(&self, other: &Self) -> bool {
70 self.module == other.module && self.ast_id == other.ast_id
71 }
72}
73impl<N: AstNode> Eq for ItemLoc<N> {}
74impl<N: AstNode> Hash for ItemLoc<N> {
75 fn hash<H: Hasher>(&self, hasher: &mut H) {
76 self.module.hash(hasher);
77 self.ast_id.hash(hasher);
78 }
79}
80
81impl<N: AstNode> Clone for ItemLoc<N> {
82 fn clone(&self) -> ItemLoc<N> {
83 ItemLoc { module: self.module, ast_id: self.ast_id }
84 }
85} 70}
86 71
87#[derive(Clone, Copy)] 72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
88pub struct LocationCtx<DB> { 73pub struct AssocItemLoc<N: AstNode> {
89 db: DB, 74 pub container: AssocContainerId,
90 module: ModuleId, 75 pub ast_id: AstId<N>,
91 file_id: HirFileId,
92} 76}
93 77
94impl<'a, DB> LocationCtx<&'a DB> { 78macro_rules! impl_intern {
95 pub fn new(db: &'a DB, module: ModuleId, file_id: HirFileId) -> LocationCtx<&'a DB> { 79 ($id:ident, $loc:ident, $intern:ident, $lookup:ident) => {
96 LocationCtx { db, module, file_id } 80 impl_intern_key!($id);
97 }
98}
99 81
100pub trait AstItemDef<N: AstNode>: salsa::InternKey + Clone { 82 impl Intern for $loc {
101 fn intern(db: &impl InternDatabase, loc: ItemLoc<N>) -> Self; 83 type ID = $id;
102 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<N>; 84 fn intern(self, db: &impl db::DefDatabase) -> $id {
85 db.$intern(self)
86 }
87 }
103 88
104 fn from_ast_id(ctx: LocationCtx<&impl InternDatabase>, ast_id: FileAstId<N>) -> Self { 89 impl Lookup for $id {
105 let loc = ItemLoc { module: ctx.module, ast_id: AstId::new(ctx.file_id, ast_id) }; 90 type Data = $loc;
106 Self::intern(ctx.db, loc) 91 fn lookup(&self, db: &impl db::DefDatabase) -> $loc {
107 } 92 db.$lookup(*self)
108 fn source(self, db: &(impl AstDatabase + InternDatabase)) -> Source<N> { 93 }
109 let loc = self.lookup_intern(db); 94 }
110 let value = loc.ast_id.to_node(db); 95 };
111 Source { file_id: loc.ast_id.file_id(), value }
112 }
113 fn module(self, db: &impl InternDatabase) -> ModuleId {
114 let loc = self.lookup_intern(db);
115 loc.module
116 }
117} 96}
118 97
119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 98#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
120pub struct FunctionId(salsa::InternId); 99pub struct FunctionId(salsa::InternId);
121impl_intern_key!(FunctionId); 100type FunctionLoc = AssocItemLoc<ast::FnDef>;
122 101impl_intern!(FunctionId, FunctionLoc, intern_function, lookup_intern_function);
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
124pub struct FunctionLoc {
125 pub container: ContainerId,
126 pub ast_id: AstId<ast::FnDef>,
127}
128
129impl Intern for FunctionLoc {
130 type ID = FunctionId;
131 fn intern(self, db: &impl db::DefDatabase) -> FunctionId {
132 db.intern_function(self)
133 }
134}
135
136impl Lookup for FunctionId {
137 type Data = FunctionLoc;
138 fn lookup(&self, db: &impl db::DefDatabase) -> FunctionLoc {
139 db.lookup_intern_function(*self)
140 }
141}
142 102
143#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 103#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
144pub struct StructId(salsa::InternId); 104pub struct StructId(salsa::InternId);
145impl_intern_key!(StructId); 105type StructLoc = ItemLoc<ast::StructDef>;
146impl AstItemDef<ast::StructDef> for StructId { 106impl_intern!(StructId, StructLoc, intern_struct, lookup_intern_struct);
147 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::StructDef>) -> Self {
148 db.intern_struct(loc)
149 }
150 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::StructDef> {
151 db.lookup_intern_struct(self)
152 }
153}
154 107
155#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 108#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
156pub struct UnionId(salsa::InternId); 109pub struct UnionId(salsa::InternId);
157impl_intern_key!(UnionId); 110pub type UnionLoc = ItemLoc<ast::UnionDef>;
158impl AstItemDef<ast::UnionDef> for UnionId { 111impl_intern!(UnionId, UnionLoc, intern_union, lookup_intern_union);
159 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::UnionDef>) -> Self {
160 db.intern_union(loc)
161 }
162 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::UnionDef> {
163 db.lookup_intern_union(self)
164 }
165}
166 112
167#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 113#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
168pub struct EnumId(salsa::InternId); 114pub struct EnumId(salsa::InternId);
169impl_intern_key!(EnumId); 115pub type EnumLoc = ItemLoc<ast::EnumDef>;
170impl AstItemDef<ast::EnumDef> for EnumId { 116impl_intern!(EnumId, EnumLoc, intern_enum, lookup_intern_enum);
171 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::EnumDef>) -> Self {
172 db.intern_enum(loc)
173 }
174 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::EnumDef> {
175 db.lookup_intern_enum(self)
176 }
177}
178 117
179// FIXME: rename to `VariantId`, only enums can ave variants 118// FIXME: rename to `VariantId`, only enums can ave variants
180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 119#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
@@ -199,98 +138,38 @@ impl_arena_id!(LocalStructFieldId);
199 138
200#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 139#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
201pub struct ConstId(salsa::InternId); 140pub struct ConstId(salsa::InternId);
202impl_intern_key!(ConstId); 141type ConstLoc = AssocItemLoc<ast::ConstDef>;
203#[derive(Debug, Clone, PartialEq, Eq, Hash)] 142impl_intern!(ConstId, ConstLoc, intern_const, lookup_intern_const);
204pub struct ConstLoc {
205 pub container: ContainerId,
206 pub ast_id: AstId<ast::ConstDef>,
207}
208
209impl Intern for ConstLoc {
210 type ID = ConstId;
211 fn intern(self, db: &impl db::DefDatabase) -> ConstId {
212 db.intern_const(self)
213 }
214}
215
216impl Lookup for ConstId {
217 type Data = ConstLoc;
218 fn lookup(&self, db: &impl db::DefDatabase) -> ConstLoc {
219 db.lookup_intern_const(*self)
220 }
221}
222 143
223#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 144#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
224pub struct StaticId(salsa::InternId); 145pub struct StaticId(salsa::InternId);
225impl_intern_key!(StaticId); 146pub type StaticLoc = ItemLoc<ast::StaticDef>;
226 147impl_intern!(StaticId, StaticLoc, intern_static, lookup_intern_static);
227#[derive(Debug, Clone, PartialEq, Eq, Hash)]
228pub struct StaticLoc {
229 pub container: ModuleId,
230 pub ast_id: AstId<ast::StaticDef>,
231}
232
233impl Intern for StaticLoc {
234 type ID = StaticId;
235 fn intern(self, db: &impl db::DefDatabase) -> StaticId {
236 db.intern_static(self)
237 }
238}
239
240impl Lookup for StaticId {
241 type Data = StaticLoc;
242 fn lookup(&self, db: &impl db::DefDatabase) -> StaticLoc {
243 db.lookup_intern_static(*self)
244 }
245}
246 148
247#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
248pub struct TraitId(salsa::InternId); 150pub struct TraitId(salsa::InternId);
249impl_intern_key!(TraitId); 151pub type TraitLoc = ItemLoc<ast::TraitDef>;
250impl AstItemDef<ast::TraitDef> for TraitId { 152impl_intern!(TraitId, TraitLoc, intern_trait, lookup_intern_trait);
251 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::TraitDef>) -> Self {
252 db.intern_trait(loc)
253 }
254 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::TraitDef> {
255 db.lookup_intern_trait(self)
256 }
257}
258 153
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 154#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
260pub struct TypeAliasId(salsa::InternId); 155pub struct TypeAliasId(salsa::InternId);
261impl_intern_key!(TypeAliasId); 156type TypeAliasLoc = AssocItemLoc<ast::TypeAliasDef>;
262 157impl_intern!(TypeAliasId, TypeAliasLoc, intern_type_alias, lookup_intern_type_alias);
263#[derive(Debug, Clone, PartialEq, Eq, Hash)]
264pub struct TypeAliasLoc {
265 pub container: ContainerId,
266 pub ast_id: AstId<ast::TypeAliasDef>,
267}
268 158
269impl Intern for TypeAliasLoc { 159#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
270 type ID = TypeAliasId; 160pub struct ImplId(salsa::InternId);
271 fn intern(self, db: &impl db::DefDatabase) -> TypeAliasId { 161type ImplLoc = ItemLoc<ast::ImplBlock>;
272 db.intern_type_alias(self) 162impl_intern!(ImplId, ImplLoc, intern_impl, lookup_intern_impl);
273 }
274}
275 163
276impl Lookup for TypeAliasId { 164#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
277 type Data = TypeAliasLoc; 165pub struct TypeParamId {
278 fn lookup(&self, db: &impl db::DefDatabase) -> TypeAliasLoc { 166 pub parent: GenericDefId,
279 db.lookup_intern_type_alias(*self) 167 pub local_id: LocalTypeParamId,
280 }
281} 168}
282 169
283#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 170#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
284pub struct ImplId(salsa::InternId); 171pub struct LocalTypeParamId(RawId);
285impl_intern_key!(ImplId); 172impl_arena_id!(LocalTypeParamId);
286impl AstItemDef<ast::ImplBlock> for ImplId {
287 fn intern(db: &impl InternDatabase, loc: ItemLoc<ast::ImplBlock>) -> Self {
288 db.intern_impl(loc)
289 }
290 fn lookup_intern(self, db: &impl InternDatabase) -> ItemLoc<ast::ImplBlock> {
291 db.lookup_intern_impl(self)
292 }
293}
294 173
295macro_rules! impl_froms { 174macro_rules! impl_froms {
296 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => { 175 ($e:ident: $($v:ident $(($($sv:ident),*))?),*) => {
@@ -314,9 +193,16 @@ macro_rules! impl_froms {
314#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
315pub enum ContainerId { 194pub enum ContainerId {
316 ModuleId(ModuleId), 195 ModuleId(ModuleId),
196 DefWithBodyId(DefWithBodyId),
197}
198
199#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
200pub enum AssocContainerId {
201 ContainerId(ContainerId),
317 ImplId(ImplId), 202 ImplId(ImplId),
318 TraitId(TraitId), 203 TraitId(TraitId),
319} 204}
205impl_froms!(AssocContainerId: ContainerId);
320 206
321/// A Data Type 207/// A Data Type
322#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 208#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
@@ -459,43 +345,39 @@ pub trait HasModule {
459 fn module(&self, db: &impl db::DefDatabase) -> ModuleId; 345 fn module(&self, db: &impl db::DefDatabase) -> ModuleId;
460} 346}
461 347
462impl HasModule for FunctionLoc { 348impl HasModule for ContainerId {
463 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 349 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
464 match self.container { 350 match *self {
465 ContainerId::ModuleId(it) => it, 351 ContainerId::ModuleId(it) => it,
466 ContainerId::ImplId(it) => it.module(db), 352 ContainerId::DefWithBodyId(it) => it.module(db),
467 ContainerId::TraitId(it) => it.module(db),
468 } 353 }
469 } 354 }
470} 355}
471 356
472impl HasModule for TypeAliasLoc { 357impl HasModule for AssocContainerId {
473 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 358 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
474 match self.container { 359 match *self {
475 ContainerId::ModuleId(it) => it, 360 AssocContainerId::ContainerId(it) => it.module(db),
476 ContainerId::ImplId(it) => it.module(db), 361 AssocContainerId::ImplId(it) => it.lookup(db).container.module(db),
477 ContainerId::TraitId(it) => it.module(db), 362 AssocContainerId::TraitId(it) => it.lookup(db).container.module(db),
478 } 363 }
479 } 364 }
480} 365}
481 366
482impl HasModule for ConstLoc { 367impl<N: AstNode> HasModule for AssocItemLoc<N> {
483 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 368 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
484 match self.container { 369 self.container.module(db)
485 ContainerId::ModuleId(it) => it,
486 ContainerId::ImplId(it) => it.module(db),
487 ContainerId::TraitId(it) => it.module(db),
488 }
489 } 370 }
490} 371}
491 372
492impl HasModule for AdtId { 373impl HasModule for AdtId {
493 fn module(&self, db: &impl db::DefDatabase) -> ModuleId { 374 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
494 match self { 375 match self {
495 AdtId::StructId(it) => it.module(db), 376 AdtId::StructId(it) => it.lookup(db).container,
496 AdtId::UnionId(it) => it.module(db), 377 AdtId::UnionId(it) => it.lookup(db).container,
497 AdtId::EnumId(it) => it.module(db), 378 AdtId::EnumId(it) => it.lookup(db).container,
498 } 379 }
380 .module(db)
499 } 381 }
500} 382}
501 383
@@ -509,58 +391,22 @@ impl HasModule for DefWithBodyId {
509 } 391 }
510} 392}
511 393
512impl HasModule for StaticLoc { 394impl HasModule for GenericDefId {
513 fn module(&self, _db: &impl db::DefDatabase) -> ModuleId { 395 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
514 self.container 396 match self {
515 } 397 GenericDefId::FunctionId(it) => it.lookup(db).module(db),
516} 398 GenericDefId::AdtId(it) => it.module(db),
517 399 GenericDefId::TraitId(it) => it.lookup(db).container.module(db),
518pub trait HasSource { 400 GenericDefId::TypeAliasId(it) => it.lookup(db).module(db),
519 type Value; 401 GenericDefId::ImplId(it) => it.lookup(db).container.module(db),
520 fn source(&self, db: &impl db::DefDatabase) -> Source<Self::Value>; 402 GenericDefId::EnumVariantId(it) => it.parent.lookup(db).container.module(db),
521} 403 GenericDefId::ConstId(it) => it.lookup(db).module(db),
522 404 }
523impl HasSource for FunctionLoc {
524 type Value = ast::FnDef;
525
526 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::FnDef> {
527 let node = self.ast_id.to_node(db);
528 Source::new(self.ast_id.file_id(), node)
529 }
530}
531
532impl HasSource for TypeAliasLoc {
533 type Value = ast::TypeAliasDef;
534
535 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::TypeAliasDef> {
536 let node = self.ast_id.to_node(db);
537 Source::new(self.ast_id.file_id(), node)
538 }
539}
540
541impl HasSource for ConstLoc {
542 type Value = ast::ConstDef;
543
544 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::ConstDef> {
545 let node = self.ast_id.to_node(db);
546 Source::new(self.ast_id.file_id(), node)
547 } 405 }
548} 406}
549 407
550impl HasSource for StaticLoc { 408impl HasModule for StaticLoc {
551 type Value = ast::StaticDef; 409 fn module(&self, db: &impl db::DefDatabase) -> ModuleId {
552 410 self.container.module(db)
553 fn source(&self, db: &impl db::DefDatabase) -> Source<ast::StaticDef> {
554 let node = self.ast_id.to_node(db);
555 Source::new(self.ast_id.file_id(), node)
556 } 411 }
557} 412}
558
559pub trait HasChildSource {
560 type ChildId;
561 type Value;
562 fn child_source(
563 &self,
564 db: &impl db::DefDatabase,
565 ) -> Source<ArenaMap<Self::ChildId, Self::Value>>;
566}
diff --git a/crates/ra_hir_def/src/marks.rs b/crates/ra_hir_def/src/marks.rs
index 65239ca0a..457ba4abe 100644
--- a/crates/ra_hir_def/src/marks.rs
+++ b/crates/ra_hir_def/src/marks.rs
@@ -5,6 +5,7 @@ test_utils::marks!(
5 name_res_works_for_broken_modules 5 name_res_works_for_broken_modules
6 can_import_enum_variant 6 can_import_enum_variant
7 glob_enum 7 glob_enum
8 glob_enum_group
8 glob_across_crates 9 glob_across_crates
9 std_prelude 10 std_prelude
10 macro_rules_from_other_crates_are_visible_with_macro_use 11 macro_rules_from_other_crates_are_visible_with_macro_use
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs
index 2359386c2..5d4ca73a3 100644
--- a/crates/ra_hir_def/src/nameres.rs
+++ b/crates/ra_hir_def/src/nameres.rs
@@ -57,24 +57,23 @@ mod tests;
57 57
58use std::sync::Arc; 58use std::sync::Arc;
59 59
60use hir_expand::{ 60use hir_expand::{diagnostics::DiagnosticSink, name::Name, InFile};
61 ast_id_map::FileAstId, diagnostics::DiagnosticSink, either::Either, name::Name, MacroDefId,
62 Source,
63};
64use once_cell::sync::Lazy;
65use ra_arena::Arena; 61use ra_arena::Arena;
66use ra_db::{CrateId, Edition, FileId}; 62use ra_db::{CrateId, Edition, FileId, FilePosition};
67use ra_prof::profile; 63use ra_prof::profile;
68use ra_syntax::ast; 64use ra_syntax::{
65 ast::{self, AstNode},
66 SyntaxNode,
67};
69use rustc_hash::FxHashMap; 68use rustc_hash::FxHashMap;
70 69
71use crate::{ 70use crate::{
72 builtin_type::BuiltinType,
73 db::DefDatabase, 71 db::DefDatabase,
72 item_scope::{BuiltinShadowMode, ItemScope},
74 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode}, 73 nameres::{diagnostics::DefDiagnostic, path_resolution::ResolveMode},
75 path::Path, 74 path::ModPath,
76 per_ns::PerNs, 75 per_ns::PerNs,
77 AstId, FunctionId, ImplId, LocalImportId, LocalModuleId, ModuleDefId, ModuleId, TraitId, 76 AstId, LocalModuleId, ModuleDefId, ModuleId,
78}; 77};
79 78
80/// Contains all top-level defs from a macro-expanded crate 79/// Contains all top-level defs from a macro-expanded crate
@@ -100,106 +99,76 @@ impl std::ops::Index<LocalModuleId> for CrateDefMap {
100 } 99 }
101} 100}
102 101
103#[derive(Default, Debug, PartialEq, Eq)] 102#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
104pub struct ModuleData { 103pub enum ModuleOrigin {
105 pub parent: Option<LocalModuleId>, 104 CrateRoot {
106 pub children: FxHashMap<Name, LocalModuleId>, 105 definition: FileId,
107 pub scope: ModuleScope, 106 },
108
109 // FIXME: these can't be both null, we need a three-state enum here.
110 /// None for root
111 pub declaration: Option<AstId<ast::Module>>,
112 /// None for inline modules.
113 ///
114 /// Note that non-inline modules, by definition, live inside non-macro file. 107 /// Note that non-inline modules, by definition, live inside non-macro file.
115 pub definition: Option<FileId>, 108 File {
116 109 declaration: AstId<ast::Module>,
117 pub impls: Vec<ImplId>, 110 definition: FileId,
118} 111 },
119 112 Inline {
120#[derive(Default, Debug, PartialEq, Eq)] 113 definition: AstId<ast::Module>,
121pub(crate) struct Declarations { 114 },
122 fns: FxHashMap<FileAstId<ast::FnDef>, FunctionId>,
123} 115}
124 116
125#[derive(Debug, Default, PartialEq, Eq)] 117impl Default for ModuleOrigin {
126pub struct ModuleScope { 118 fn default() -> Self {
127 items: FxHashMap<Name, Resolution>, 119 ModuleOrigin::CrateRoot { definition: FileId(0) }
128 /// Macros visable in current module in legacy textual scope
129 ///
130 /// For macros invoked by an unquatified identifier like `bar!()`, `legacy_macros` will be searched in first.
131 /// If it yields no result, then it turns to module scoped `macros`.
132 /// It macros with name quatified with a path like `crate::foo::bar!()`, `legacy_macros` will be skipped,
133 /// and only normal scoped `macros` will be searched in.
134 ///
135 /// Note that this automatically inherit macros defined textually before the definition of module itself.
136 ///
137 /// Module scoped macros will be inserted into `items` instead of here.
138 // FIXME: Macro shadowing in one module is not properly handled. Non-item place macros will
139 // be all resolved to the last one defined if shadowing happens.
140 legacy_macros: FxHashMap<Name, MacroDefId>,
141}
142
143static BUILTIN_SCOPE: Lazy<FxHashMap<Name, Resolution>> = Lazy::new(|| {
144 BuiltinType::ALL
145 .iter()
146 .map(|(name, ty)| {
147 (name.clone(), Resolution { def: PerNs::types(ty.clone().into()), import: None })
148 })
149 .collect()
150});
151
152/// Legacy macros can only be accessed through special methods like `get_legacy_macros`.
153/// Other methods will only resolve values, types and module scoped macros only.
154impl ModuleScope {
155 pub fn entries<'a>(&'a self) -> impl Iterator<Item = (&'a Name, &'a Resolution)> + 'a {
156 //FIXME: shadowing
157 self.items.iter().chain(BUILTIN_SCOPE.iter())
158 }
159
160 pub fn declarations(&self) -> impl Iterator<Item = ModuleDefId> + '_ {
161 self.entries()
162 .filter_map(|(_name, res)| if res.import.is_none() { Some(res.def) } else { None })
163 .flat_map(|per_ns| {
164 per_ns.take_types().into_iter().chain(per_ns.take_values().into_iter())
165 })
166 }
167
168 /// Iterate over all module scoped macros
169 pub fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
170 self.items
171 .iter()
172 .filter_map(|(name, res)| res.def.take_macros().map(|macro_| (name, macro_)))
173 } 120 }
121}
174 122
175 /// Iterate over all legacy textual scoped macros visable at the end of the module 123impl ModuleOrigin {
176 pub fn legacy_macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 124 pub(crate) fn not_sure_file(file: Option<FileId>, declaration: AstId<ast::Module>) -> Self {
177 self.legacy_macros.iter().map(|(name, def)| (name, *def)) 125 match file {
126 None => ModuleOrigin::Inline { definition: declaration },
127 Some(definition) => ModuleOrigin::File { declaration, definition },
128 }
178 } 129 }
179 130
180 /// Get a name from current module scope, legacy macros are not included 131 fn declaration(&self) -> Option<AstId<ast::Module>> {
181 pub fn get(&self, name: &Name) -> Option<&Resolution> { 132 match self {
182 self.items.get(name).or_else(|| BUILTIN_SCOPE.get(name)) 133 ModuleOrigin::File { declaration: module, .. }
134 | ModuleOrigin::Inline { definition: module, .. } => Some(*module),
135 ModuleOrigin::CrateRoot { .. } => None,
136 }
183 } 137 }
184 138
185 pub fn traits<'a>(&'a self) -> impl Iterator<Item = TraitId> + 'a { 139 pub fn file_id(&self) -> Option<FileId> {
186 self.items.values().filter_map(|r| match r.def.take_types() { 140 match self {
187 Some(ModuleDefId::TraitId(t)) => Some(t), 141 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
142 Some(*definition)
143 }
188 _ => None, 144 _ => None,
189 }) 145 }
190 } 146 }
191 147
192 fn get_legacy_macro(&self, name: &Name) -> Option<MacroDefId> { 148 /// Returns a node which defines this module.
193 self.legacy_macros.get(name).copied() 149 /// That is, a file or a `mod foo {}` with items.
150 fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
151 match self {
152 ModuleOrigin::File { definition, .. } | ModuleOrigin::CrateRoot { definition } => {
153 let file_id = *definition;
154 let sf = db.parse(file_id).tree();
155 return InFile::new(file_id.into(), ModuleSource::SourceFile(sf));
156 }
157 ModuleOrigin::Inline { definition } => {
158 InFile::new(definition.file_id, ModuleSource::Module(definition.to_node(db)))
159 }
160 }
194 } 161 }
195} 162}
196 163
197#[derive(Debug, Clone, PartialEq, Eq, Default)] 164#[derive(Default, Debug, PartialEq, Eq)]
198pub struct Resolution { 165pub struct ModuleData {
199 /// None for unresolved 166 pub parent: Option<LocalModuleId>,
200 pub def: PerNs, 167 pub children: FxHashMap<Name, LocalModuleId>,
201 /// ident by which this is imported into local scope. 168 pub scope: ItemScope,
202 pub import: Option<LocalImportId>, 169
170 /// Where does this module come from?
171 pub origin: ModuleOrigin,
203} 172}
204 173
205impl CrateDefMap { 174impl CrateDefMap {
@@ -241,7 +210,7 @@ impl CrateDefMap {
241 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ { 210 pub fn modules_for_file(&self, file_id: FileId) -> impl Iterator<Item = LocalModuleId> + '_ {
242 self.modules 211 self.modules
243 .iter() 212 .iter()
244 .filter(move |(_id, data)| data.definition == Some(file_id)) 213 .filter(move |(_id, data)| data.origin.file_id() == Some(file_id))
245 .map(|(id, _data)| id) 214 .map(|(id, _data)| id)
246 } 215 }
247 216
@@ -249,33 +218,62 @@ impl CrateDefMap {
249 &self, 218 &self,
250 db: &impl DefDatabase, 219 db: &impl DefDatabase,
251 original_module: LocalModuleId, 220 original_module: LocalModuleId,
252 path: &Path, 221 path: &ModPath,
222 shadow: BuiltinShadowMode,
253 ) -> (PerNs, Option<usize>) { 223 ) -> (PerNs, Option<usize>) {
254 let res = self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path); 224 let res =
225 self.resolve_path_fp_with_macro(db, ResolveMode::Other, original_module, path, shadow);
255 (res.resolved_def, res.segment_index) 226 (res.resolved_def, res.segment_index)
256 } 227 }
257} 228}
258 229
259impl ModuleData { 230impl ModuleData {
260 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items. 231 /// Returns a node which defines this module. That is, a file or a `mod foo {}` with items.
261 pub fn definition_source( 232 pub fn definition_source(&self, db: &impl DefDatabase) -> InFile<ModuleSource> {
262 &self, 233 self.origin.definition_source(db)
263 db: &impl DefDatabase,
264 ) -> Source<Either<ast::SourceFile, ast::Module>> {
265 if let Some(file_id) = self.definition {
266 let sf = db.parse(file_id).tree();
267 return Source::new(file_id.into(), Either::A(sf));
268 }
269 let decl = self.declaration.unwrap();
270 Source::new(decl.file_id(), Either::B(decl.to_node(db)))
271 } 234 }
272 235
273 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`. 236 /// Returns a node which declares this module, either a `mod foo;` or a `mod foo {}`.
274 /// `None` for the crate root. 237 /// `None` for the crate root or block.
275 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<Source<ast::Module>> { 238 pub fn declaration_source(&self, db: &impl DefDatabase) -> Option<InFile<ast::Module>> {
276 let decl = self.declaration?; 239 let decl = self.origin.declaration()?;
277 let value = decl.to_node(db); 240 let value = decl.to_node(db);
278 Some(Source { file_id: decl.file_id(), value }) 241 Some(InFile { file_id: decl.file_id, value })
242 }
243}
244
245#[derive(Debug, Clone, PartialEq, Eq)]
246pub enum ModuleSource {
247 SourceFile(ast::SourceFile),
248 Module(ast::Module),
249}
250
251impl ModuleSource {
252 // FIXME: this methods do not belong here
253 pub fn from_position(db: &impl DefDatabase, position: FilePosition) -> ModuleSource {
254 let parse = db.parse(position.file_id);
255 match &ra_syntax::algo::find_node_at_offset::<ast::Module>(
256 parse.tree().syntax(),
257 position.offset,
258 ) {
259 Some(m) if !m.has_semi() => ModuleSource::Module(m.clone()),
260 _ => {
261 let source_file = parse.tree();
262 ModuleSource::SourceFile(source_file)
263 }
264 }
265 }
266
267 pub fn from_child_node(db: &impl DefDatabase, child: InFile<&SyntaxNode>) -> ModuleSource {
268 if let Some(m) =
269 child.value.ancestors().filter_map(ast::Module::cast).find(|it| !it.has_semi())
270 {
271 ModuleSource::Module(m)
272 } else {
273 let file_id = child.file_id.original_file(db);
274 let source_file = db.parse(file_id).tree();
275 ModuleSource::SourceFile(source_file)
276 }
279 } 277 }
280} 278}
281 279
@@ -309,7 +307,7 @@ mod diagnostics {
309 } 307 }
310 let decl = declaration.to_node(db); 308 let decl = declaration.to_node(db);
311 sink.push(UnresolvedModule { 309 sink.push(UnresolvedModule {
312 file: declaration.file_id(), 310 file: declaration.file_id,
313 decl: AstPtr::new(&decl), 311 decl: AstPtr::new(&decl),
314 candidate: candidate.clone(), 312 candidate: candidate.clone(),
315 }) 313 })
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs
index fd8245113..b9f40d3dd 100644
--- a/crates/ra_hir_def/src/nameres/collector.rs
+++ b/crates/ra_hir_def/src/nameres/collector.rs
@@ -4,14 +4,15 @@
4//! resolves imports and expands macros. 4//! resolves imports and expands macros.
5 5
6use hir_expand::{ 6use hir_expand::{
7 builtin_derive::find_builtin_derive,
7 builtin_macro::find_builtin_macro, 8 builtin_macro::find_builtin_macro,
8 name::{self, AsName, Name}, 9 name::{name, AsName, Name},
9 HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 10 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
10}; 11};
11use ra_cfg::CfgOptions; 12use ra_cfg::CfgOptions;
12use ra_db::{CrateId, FileId}; 13use ra_db::{CrateId, FileId};
13use ra_syntax::ast; 14use ra_syntax::ast;
14use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::FxHashMap;
15use test_utils::tested_by; 16use test_utils::tested_by;
16 17
17use crate::{ 18use crate::{
@@ -19,13 +20,12 @@ use crate::{
19 db::DefDatabase, 20 db::DefDatabase,
20 nameres::{ 21 nameres::{
21 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint, 22 diagnostics::DefDiagnostic, mod_resolution::ModDir, path_resolution::ReachedFixedPoint,
22 raw, CrateDefMap, ModuleData, Resolution, ResolveMode, 23 raw, BuiltinShadowMode, CrateDefMap, ModuleData, ModuleOrigin, ResolveMode,
23 }, 24 },
24 path::{Path, PathKind}, 25 path::{ModPath, PathKind},
25 per_ns::PerNs, 26 per_ns::PerNs,
26 AdtId, AstId, AstItemDef, ConstLoc, ContainerId, EnumId, EnumVariantId, FunctionLoc, ImplId, 27 AdtId, AstId, ConstLoc, ContainerId, EnumLoc, EnumVariantId, FunctionLoc, ImplLoc, Intern,
27 Intern, LocalImportId, LocalModuleId, LocationCtx, ModuleDefId, ModuleId, StaticLoc, StructId, 28 LocalModuleId, ModuleDefId, ModuleId, StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc,
28 TraitId, TypeAliasLoc, UnionId,
29}; 29};
30 30
31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap { 31pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> CrateDefMap {
@@ -57,68 +57,63 @@ pub(super) fn collect_defs(db: &impl DefDatabase, mut def_map: CrateDefMap) -> C
57 def_map, 57 def_map,
58 glob_imports: FxHashMap::default(), 58 glob_imports: FxHashMap::default(),
59 unresolved_imports: Vec::new(), 59 unresolved_imports: Vec::new(),
60 resolved_imports: Vec::new(),
61
60 unexpanded_macros: Vec::new(), 62 unexpanded_macros: Vec::new(),
63 unexpanded_attribute_macros: Vec::new(),
61 mod_dirs: FxHashMap::default(), 64 mod_dirs: FxHashMap::default(),
62 macro_stack_monitor: MacroStackMonitor::default(),
63 poison_macros: FxHashSet::default(),
64 cfg_options, 65 cfg_options,
65 }; 66 };
66 collector.collect(); 67 collector.collect();
67 collector.finish() 68 collector.finish()
68} 69}
69 70
70#[derive(Default)] 71#[derive(Copy, Clone, Debug, Eq, PartialEq)]
71struct MacroStackMonitor { 72enum PartialResolvedImport {
72 counts: FxHashMap<MacroDefId, u32>, 73 /// None of any namespaces is resolved
73 74 Unresolved,
74 /// Mainly use for test 75 /// One of namespaces is resolved
75 validator: Option<Box<dyn Fn(u32) -> bool>>, 76 Indeterminate(PerNs),
77 /// All namespaces are resolved, OR it is came from other crate
78 Resolved(PerNs),
76} 79}
77 80
78impl MacroStackMonitor { 81impl PartialResolvedImport {
79 fn increase(&mut self, macro_def_id: MacroDefId) { 82 fn namespaces(&self) -> PerNs {
80 *self.counts.entry(macro_def_id).or_default() += 1; 83 match self {
81 } 84 PartialResolvedImport::Unresolved => PerNs::none(),
82 85 PartialResolvedImport::Indeterminate(ns) => *ns,
83 fn decrease(&mut self, macro_def_id: MacroDefId) { 86 PartialResolvedImport::Resolved(ns) => *ns,
84 *self.counts.entry(macro_def_id).or_default() -= 1; 87 }
85 } 88 }
89}
86 90
87 fn is_poison(&self, macro_def_id: MacroDefId) -> bool { 91#[derive(Clone, Debug, Eq, PartialEq)]
88 let cur = *self.counts.get(&macro_def_id).unwrap_or(&0); 92struct ImportDirective {
93 module_id: LocalModuleId,
94 import_id: raw::Import,
95 import: raw::ImportData,
96 status: PartialResolvedImport,
97}
89 98
90 if let Some(validator) = &self.validator { 99#[derive(Clone, Debug, Eq, PartialEq)]
91 validator(cur) 100struct MacroDirective {
92 } else { 101 module_id: LocalModuleId,
93 cur > 100 102 ast_id: AstId<ast::MacroCall>,
94 } 103 path: ModPath,
95 } 104 legacy: Option<MacroCallId>,
96} 105}
97 106
98/// Walks the tree of module recursively 107/// Walks the tree of module recursively
99struct DefCollector<'a, DB> { 108struct DefCollector<'a, DB> {
100 db: &'a DB, 109 db: &'a DB,
101 def_map: CrateDefMap, 110 def_map: CrateDefMap,
102 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, LocalImportId)>>, 111 glob_imports: FxHashMap<LocalModuleId, Vec<(LocalModuleId, raw::Import)>>,
103 unresolved_imports: Vec<(LocalModuleId, LocalImportId, raw::ImportData)>, 112 unresolved_imports: Vec<ImportDirective>,
104 unexpanded_macros: Vec<(LocalModuleId, AstId<ast::MacroCall>, Path)>, 113 resolved_imports: Vec<ImportDirective>,
114 unexpanded_macros: Vec<MacroDirective>,
115 unexpanded_attribute_macros: Vec<(LocalModuleId, AstId<ast::ModuleItem>, ModPath)>,
105 mod_dirs: FxHashMap<LocalModuleId, ModDir>, 116 mod_dirs: FxHashMap<LocalModuleId, ModDir>,
106
107 /// Some macro use `$tt:tt which mean we have to handle the macro perfectly
108 /// To prevent stack overflow, we add a deep counter here for prevent that.
109 macro_stack_monitor: MacroStackMonitor,
110 /// Some macros are not well-behavior, which leads to infinite loop
111 /// e.g. macro_rules! foo { ($ty:ty) => { foo!($ty); } }
112 /// We mark it down and skip it in collector
113 ///
114 /// FIXME:
115 /// Right now it only handle a poison macro in a single crate,
116 /// such that if other crate try to call that macro,
117 /// the whole process will do again until it became poisoned in that crate.
118 /// We should handle this macro set globally
119 /// However, do we want to put it as a global variable?
120 poison_macros: FxHashSet<MacroDefId>,
121
122 cfg_options: &'a CfgOptions, 117 cfg_options: &'a CfgOptions,
123} 118}
124 119
@@ -131,7 +126,7 @@ where
131 let file_id = crate_graph.crate_root(self.def_map.krate); 126 let file_id = crate_graph.crate_root(self.def_map.krate);
132 let raw_items = self.db.raw_items(file_id.into()); 127 let raw_items = self.db.raw_items(file_id.into());
133 let module_id = self.def_map.root; 128 let module_id = self.def_map.root;
134 self.def_map.modules[module_id].definition = Some(file_id); 129 self.def_map.modules[module_id].origin = ModuleOrigin::CrateRoot { definition: file_id };
135 ModCollector { 130 ModCollector {
136 def_collector: &mut *self, 131 def_collector: &mut *self,
137 module_id, 132 module_id,
@@ -145,9 +140,11 @@ where
145 let mut i = 0; 140 let mut i = 0;
146 loop { 141 loop {
147 self.db.check_canceled(); 142 self.db.check_canceled();
148 match (self.resolve_imports(), self.resolve_macros()) { 143 self.resolve_imports();
149 (ReachedFixedPoint::Yes, ReachedFixedPoint::Yes) => break, 144
150 _ => i += 1, 145 match self.resolve_macros() {
146 ReachedFixedPoint::Yes => break,
147 ReachedFixedPoint::No => i += 1,
151 } 148 }
152 if i == 1000 { 149 if i == 1000 {
153 log::error!("name resolution is stuck"); 150 log::error!("name resolution is stuck");
@@ -155,10 +152,26 @@ where
155 } 152 }
156 } 153 }
157 154
155 // Resolve all indeterminate resolved imports again
156 // As some of the macros will expand newly import shadowing partial resolved imports
157 // FIXME: We maybe could skip this, if we handle the Indetermine imports in `resolve_imports`
158 // correctly
159 let partial_resolved = self.resolved_imports.iter().filter_map(|directive| {
160 if let PartialResolvedImport::Indeterminate(_) = directive.status {
161 let mut directive = directive.clone();
162 directive.status = PartialResolvedImport::Unresolved;
163 Some(directive)
164 } else {
165 None
166 }
167 });
168 self.unresolved_imports.extend(partial_resolved);
169 self.resolve_imports();
170
158 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 171 let unresolved_imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
159 // show unresolved imports in completion, etc 172 // show unresolved imports in completion, etc
160 for (module_id, import, import_data) in unresolved_imports { 173 for directive in unresolved_imports {
161 self.record_resolved_import(module_id, PerNs::none(), import, &import_data) 174 self.record_resolved_import(&directive)
162 } 175 }
163 } 176 }
164 177
@@ -201,24 +214,20 @@ where
201 // In Rust, `#[macro_export]` macros are unconditionally visible at the 214 // In Rust, `#[macro_export]` macros are unconditionally visible at the
202 // crate root, even if the parent modules is **not** visible. 215 // crate root, even if the parent modules is **not** visible.
203 if export { 216 if export {
204 self.update( 217 self.update(self.def_map.root, &[(name, PerNs::macros(macro_))]);
205 self.def_map.root,
206 None,
207 &[(name, Resolution { def: PerNs::macros(macro_), import: None })],
208 );
209 } 218 }
210 } 219 }
211 220
212 /// Define a legacy textual scoped macro in module 221 /// Define a legacy textual scoped macro in module
213 /// 222 ///
214 /// We use a map `legacy_macros` to store all legacy textual scoped macros visable per module. 223 /// We use a map `legacy_macros` to store all legacy textual scoped macros visible per module.
215 /// It will clone all macros from parent legacy scope, whose definition is prior to 224 /// It will clone all macros from parent legacy scope, whose definition is prior to
216 /// the definition of current module. 225 /// the definition of current module.
217 /// And also, `macro_use` on a module will import all legacy macros visable inside to 226 /// And also, `macro_use` on a module will import all legacy macros visible inside to
218 /// current legacy scope, with possible shadowing. 227 /// current legacy scope, with possible shadowing.
219 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, macro_: MacroDefId) { 228 fn define_legacy_macro(&mut self, module_id: LocalModuleId, name: Name, mac: MacroDefId) {
220 // Always shadowing 229 // Always shadowing
221 self.def_map.modules[module_id].scope.legacy_macros.insert(name, macro_); 230 self.def_map.modules[module_id].scope.define_legacy_macro(name, mac);
222 } 231 }
223 232
224 /// Import macros from `#[macro_use] extern crate`. 233 /// Import macros from `#[macro_use] extern crate`.
@@ -259,31 +268,43 @@ where
259 } 268 }
260 } 269 }
261 270
262 fn resolve_imports(&mut self) -> ReachedFixedPoint { 271 /// Import resolution
263 let mut imports = std::mem::replace(&mut self.unresolved_imports, Vec::new()); 272 ///
264 let mut resolved = Vec::new(); 273 /// This is a fix point algorithm. We resolve imports until no forward
265 imports.retain(|(module_id, import, import_data)| { 274 /// progress in resolving imports is made
266 let (def, fp) = self.resolve_import(*module_id, import_data); 275 fn resolve_imports(&mut self) {
267 if fp == ReachedFixedPoint::Yes { 276 let mut n_previous_unresolved = self.unresolved_imports.len() + 1;
268 resolved.push((*module_id, def, *import, import_data.clone())) 277
278 while self.unresolved_imports.len() < n_previous_unresolved {
279 n_previous_unresolved = self.unresolved_imports.len();
280 let imports = std::mem::replace(&mut self.unresolved_imports, Vec::new());
281 for mut directive in imports {
282 directive.status = self.resolve_import(directive.module_id, &directive.import);
283
284 match directive.status {
285 PartialResolvedImport::Indeterminate(_) => {
286 self.record_resolved_import(&directive);
287 // FIXME: For avoid performance regression,
288 // we consider an imported resolved if it is indeterminate (i.e not all namespace resolved)
289 self.resolved_imports.push(directive)
290 }
291 PartialResolvedImport::Resolved(_) => {
292 self.record_resolved_import(&directive);
293 self.resolved_imports.push(directive)
294 }
295 PartialResolvedImport::Unresolved => {
296 self.unresolved_imports.push(directive);
297 }
298 }
269 } 299 }
270 fp == ReachedFixedPoint::No
271 });
272 self.unresolved_imports = imports;
273 // Resolves imports, filling-in module scopes
274 let result =
275 if resolved.is_empty() { ReachedFixedPoint::Yes } else { ReachedFixedPoint::No };
276 for (module_id, def, import, import_data) in resolved {
277 self.record_resolved_import(module_id, def, import, &import_data)
278 } 300 }
279 result
280 } 301 }
281 302
282 fn resolve_import( 303 fn resolve_import(
283 &self, 304 &self,
284 module_id: LocalModuleId, 305 module_id: LocalModuleId,
285 import: &raw::ImportData, 306 import: &raw::ImportData,
286 ) -> (PerNs, ReachedFixedPoint) { 307 ) -> PartialResolvedImport {
287 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 308 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
288 if import.is_extern_crate { 309 if import.is_extern_crate {
289 let res = self.def_map.resolve_name_in_extern_prelude( 310 let res = self.def_map.resolve_name_in_extern_prelude(
@@ -292,26 +313,45 @@ where
292 .as_ident() 313 .as_ident()
293 .expect("extern crate should have been desugared to one-element path"), 314 .expect("extern crate should have been desugared to one-element path"),
294 ); 315 );
295 (res, ReachedFixedPoint::Yes) 316 PartialResolvedImport::Resolved(res)
296 } else { 317 } else {
297 let res = self.def_map.resolve_path_fp_with_macro( 318 let res = self.def_map.resolve_path_fp_with_macro(
298 self.db, 319 self.db,
299 ResolveMode::Import, 320 ResolveMode::Import,
300 module_id, 321 module_id,
301 &import.path, 322 &import.path,
323 BuiltinShadowMode::Module,
302 ); 324 );
303 325
304 (res.resolved_def, res.reached_fixedpoint) 326 let def = res.resolved_def;
327 if res.reached_fixedpoint == ReachedFixedPoint::No {
328 return PartialResolvedImport::Unresolved;
329 }
330
331 if let Some(krate) = res.krate {
332 if krate != self.def_map.krate {
333 return PartialResolvedImport::Resolved(def);
334 }
335 }
336
337 // Check whether all namespace is resolved
338 if def.take_types().is_some()
339 && def.take_values().is_some()
340 && def.take_macros().is_some()
341 {
342 PartialResolvedImport::Resolved(def)
343 } else {
344 PartialResolvedImport::Indeterminate(def)
345 }
305 } 346 }
306 } 347 }
307 348
308 fn record_resolved_import( 349 fn record_resolved_import(&mut self, directive: &ImportDirective) {
309 &mut self, 350 let module_id = directive.module_id;
310 module_id: LocalModuleId, 351 let import_id = directive.import_id;
311 def: PerNs, 352 let import = &directive.import;
312 import_id: LocalImportId, 353 let def = directive.status.namespaces();
313 import: &raw::ImportData, 354
314 ) {
315 if import.is_glob { 355 if import.is_glob {
316 log::debug!("glob import: {:?}", import); 356 log::debug!("glob import: {:?}", import);
317 match def.take_types() { 357 match def.take_types() {
@@ -326,13 +366,9 @@ where
326 let scope = &item_map[m.local_id].scope; 366 let scope = &item_map[m.local_id].scope;
327 367
328 // Module scoped macros is included 368 // Module scoped macros is included
329 let items = scope 369 let items = scope.collect_resolutions();
330 .items
331 .iter()
332 .map(|(name, res)| (name.clone(), res.clone()))
333 .collect::<Vec<_>>();
334 370
335 self.update(module_id, Some(import_id), &items); 371 self.update(module_id, &items);
336 } else { 372 } else {
337 // glob import from same crate => we do an initial 373 // glob import from same crate => we do an initial
338 // import, and then need to propagate any further 374 // import, and then need to propagate any further
@@ -340,18 +376,14 @@ where
340 let scope = &self.def_map[m.local_id].scope; 376 let scope = &self.def_map[m.local_id].scope;
341 377
342 // Module scoped macros is included 378 // Module scoped macros is included
343 let items = scope 379 let items = scope.collect_resolutions();
344 .items
345 .iter()
346 .map(|(name, res)| (name.clone(), res.clone()))
347 .collect::<Vec<_>>();
348 380
349 self.update(module_id, Some(import_id), &items); 381 self.update(module_id, &items);
350 // record the glob import in case we add further items 382 // record the glob import in case we add further items
351 self.glob_imports 383 let glob = self.glob_imports.entry(m.local_id).or_default();
352 .entry(m.local_id) 384 if !glob.iter().any(|it| *it == (module_id, import_id)) {
353 .or_default() 385 glob.push((module_id, import_id));
354 .push((module_id, import_id)); 386 }
355 } 387 }
356 } 388 }
357 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => { 389 Some(ModuleDefId::AdtId(AdtId::EnumId(e))) => {
@@ -361,17 +393,14 @@ where
361 let resolutions = enum_data 393 let resolutions = enum_data
362 .variants 394 .variants
363 .iter() 395 .iter()
364 .filter_map(|(local_id, variant_data)| { 396 .map(|(local_id, variant_data)| {
365 let name = variant_data.name.clone(); 397 let name = variant_data.name.clone();
366 let variant = EnumVariantId { parent: e, local_id }; 398 let variant = EnumVariantId { parent: e, local_id };
367 let res = Resolution { 399 let res = PerNs::both(variant.into(), variant.into());
368 def: PerNs::both(variant.into(), variant.into()), 400 (name, res)
369 import: Some(import_id),
370 };
371 Some((name, res))
372 }) 401 })
373 .collect::<Vec<_>>(); 402 .collect::<Vec<_>>();
374 self.update(module_id, Some(import_id), &resolutions); 403 self.update(module_id, &resolutions);
375 } 404 }
376 Some(d) => { 405 Some(d) => {
377 log::debug!("glob import {:?} from non-module/enum {:?}", import, d); 406 log::debug!("glob import {:?} from non-module/enum {:?}", import, d);
@@ -383,7 +412,7 @@ where
383 } else { 412 } else {
384 match import.path.segments.last() { 413 match import.path.segments.last() {
385 Some(last_segment) => { 414 Some(last_segment) => {
386 let name = import.alias.clone().unwrap_or_else(|| last_segment.name.clone()); 415 let name = import.alias.clone().unwrap_or_else(|| last_segment.clone());
387 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def); 416 log::debug!("resolved import {:?} ({:?}) to {:?}", name, import, def);
388 417
389 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658 418 // extern crates in the crate root are special-cased to insert entries into the extern prelude: rust-lang/rust#54658
@@ -393,62 +422,31 @@ where
393 } 422 }
394 } 423 }
395 424
396 let resolution = Resolution { def, import: Some(import_id) }; 425 self.update(module_id, &[(name, def)]);
397 self.update(module_id, Some(import_id), &[(name, resolution)]);
398 } 426 }
399 None => tested_by!(bogus_paths), 427 None => tested_by!(bogus_paths),
400 } 428 }
401 } 429 }
402 } 430 }
403 431
404 fn update( 432 fn update(&mut self, module_id: LocalModuleId, resolutions: &[(Name, PerNs)]) {
405 &mut self, 433 self.update_recursive(module_id, resolutions, 0)
406 module_id: LocalModuleId,
407 import: Option<LocalImportId>,
408 resolutions: &[(Name, Resolution)],
409 ) {
410 self.update_recursive(module_id, import, resolutions, 0)
411 } 434 }
412 435
413 fn update_recursive( 436 fn update_recursive(
414 &mut self, 437 &mut self,
415 module_id: LocalModuleId, 438 module_id: LocalModuleId,
416 import: Option<LocalImportId>, 439 resolutions: &[(Name, PerNs)],
417 resolutions: &[(Name, Resolution)],
418 depth: usize, 440 depth: usize,
419 ) { 441 ) {
420 if depth > 100 { 442 if depth > 100 {
421 // prevent stack overflows (but this shouldn't be possible) 443 // prevent stack overflows (but this shouldn't be possible)
422 panic!("infinite recursion in glob imports!"); 444 panic!("infinite recursion in glob imports!");
423 } 445 }
424 let module_items = &mut self.def_map.modules[module_id].scope; 446 let scope = &mut self.def_map.modules[module_id].scope;
425 let mut changed = false; 447 let mut changed = false;
426 for (name, res) in resolutions { 448 for (name, res) in resolutions {
427 let existing = module_items.items.entry(name.clone()).or_default(); 449 changed |= scope.push_res(name.clone(), *res);
428
429 if existing.def.types.is_none() && res.def.types.is_some() {
430 existing.def.types = res.def.types;
431 existing.import = import.or(res.import);
432 changed = true;
433 }
434 if existing.def.values.is_none() && res.def.values.is_some() {
435 existing.def.values = res.def.values;
436 existing.import = import.or(res.import);
437 changed = true;
438 }
439 if existing.def.macros.is_none() && res.def.macros.is_some() {
440 existing.def.macros = res.def.macros;
441 existing.import = import.or(res.import);
442 changed = true;
443 }
444
445 if existing.def.is_none()
446 && res.def.is_none()
447 && existing.import.is_none()
448 && res.import.is_some()
449 {
450 existing.import = res.import;
451 }
452 } 450 }
453 451
454 if !changed { 452 if !changed {
@@ -461,27 +459,48 @@ where
461 .flat_map(|v| v.iter()) 459 .flat_map(|v| v.iter())
462 .cloned() 460 .cloned()
463 .collect::<Vec<_>>(); 461 .collect::<Vec<_>>();
464 for (glob_importing_module, glob_import) in glob_imports { 462 for (glob_importing_module, _glob_import) in glob_imports {
465 // We pass the glob import so that the tracked import in those modules is that glob import 463 // We pass the glob import so that the tracked import in those modules is that glob import
466 self.update_recursive(glob_importing_module, Some(glob_import), resolutions, depth + 1); 464 self.update_recursive(glob_importing_module, resolutions, depth + 1);
467 } 465 }
468 } 466 }
469 467
470 fn resolve_macros(&mut self) -> ReachedFixedPoint { 468 fn resolve_macros(&mut self) -> ReachedFixedPoint {
471 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new()); 469 let mut macros = std::mem::replace(&mut self.unexpanded_macros, Vec::new());
470 let mut attribute_macros =
471 std::mem::replace(&mut self.unexpanded_attribute_macros, Vec::new());
472 let mut resolved = Vec::new(); 472 let mut resolved = Vec::new();
473 let mut res = ReachedFixedPoint::Yes; 473 let mut res = ReachedFixedPoint::Yes;
474 macros.retain(|(module_id, ast_id, path)| { 474 macros.retain(|directive| {
475 if let Some(call_id) = directive.legacy {
476 res = ReachedFixedPoint::No;
477 resolved.push((directive.module_id, call_id));
478 return false;
479 }
480
475 let resolved_res = self.def_map.resolve_path_fp_with_macro( 481 let resolved_res = self.def_map.resolve_path_fp_with_macro(
476 self.db, 482 self.db,
477 ResolveMode::Other, 483 ResolveMode::Other,
478 *module_id, 484 directive.module_id,
479 path, 485 &directive.path,
486 BuiltinShadowMode::Module,
480 ); 487 );
481 488
482 if let Some(def) = resolved_res.resolved_def.take_macros() { 489 if let Some(def) = resolved_res.resolved_def.take_macros() {
483 let call_id = def.as_call_id(self.db, *ast_id); 490 let call_id = def.as_call_id(self.db, MacroCallKind::FnLike(directive.ast_id));
484 resolved.push((*module_id, call_id, def)); 491 resolved.push((directive.module_id, call_id));
492 res = ReachedFixedPoint::No;
493 return false;
494 }
495
496 true
497 });
498 attribute_macros.retain(|(module_id, ast_id, path)| {
499 let resolved_res = self.resolve_attribute_macro(path);
500
501 if let Some(def) = resolved_res {
502 let call_id = def.as_call_id(self.db, MacroCallKind::Attr(*ast_id));
503 resolved.push((*module_id, call_id));
485 res = ReachedFixedPoint::No; 504 res = ReachedFixedPoint::No;
486 return false; 505 return false;
487 } 506 }
@@ -490,44 +509,41 @@ where
490 }); 509 });
491 510
492 self.unexpanded_macros = macros; 511 self.unexpanded_macros = macros;
512 self.unexpanded_attribute_macros = attribute_macros;
493 513
494 for (module_id, macro_call_id, macro_def_id) in resolved { 514 for (module_id, macro_call_id) in resolved {
495 self.collect_macro_expansion(module_id, macro_call_id, macro_def_id); 515 self.collect_macro_expansion(module_id, macro_call_id);
496 } 516 }
497 517
498 res 518 res
499 } 519 }
500 520
501 fn collect_macro_expansion( 521 fn resolve_attribute_macro(&self, path: &ModPath) -> Option<MacroDefId> {
502 &mut self, 522 // FIXME this is currently super hacky, just enough to support the
503 module_id: LocalModuleId, 523 // built-in derives
504 macro_call_id: MacroCallId, 524 if let Some(name) = path.as_ident() {
505 macro_def_id: MacroDefId, 525 // FIXME this should actually be handled with the normal name
506 ) { 526 // resolution; the std lib defines built-in stubs for the derives,
507 if self.poison_macros.contains(&macro_def_id) { 527 // but these are new-style `macro`s, which we don't support yet
508 return; 528 if let Some(def_id) = find_builtin_derive(name) {
509 } 529 return Some(def_id);
510
511 self.macro_stack_monitor.increase(macro_def_id);
512
513 if !self.macro_stack_monitor.is_poison(macro_def_id) {
514 let file_id: HirFileId = macro_call_id.as_file(MacroFileKind::Items);
515 let raw_items = self.db.raw_items(file_id);
516 let mod_dir = self.mod_dirs[&module_id].clone();
517 ModCollector {
518 def_collector: &mut *self,
519 file_id,
520 module_id,
521 raw_items: &raw_items,
522 mod_dir,
523 } 530 }
524 .collect(raw_items.items());
525 } else {
526 log::error!("Too deep macro expansion: {:?}", macro_call_id);
527 self.poison_macros.insert(macro_def_id);
528 } 531 }
532 None
533 }
529 534
530 self.macro_stack_monitor.decrease(macro_def_id); 535 fn collect_macro_expansion(&mut self, module_id: LocalModuleId, macro_call_id: MacroCallId) {
536 let file_id: HirFileId = macro_call_id.as_file();
537 let raw_items = self.db.raw_items(file_id);
538 let mod_dir = self.mod_dirs[&module_id].clone();
539 ModCollector {
540 def_collector: &mut *self,
541 file_id,
542 module_id,
543 raw_items: &raw_items,
544 mod_dir,
545 }
546 .collect(raw_items.items());
531 } 547 }
532 548
533 fn finish(self) -> CrateDefMap { 549 fn finish(self) -> CrateDefMap {
@@ -581,20 +597,31 @@ where
581 raw::RawItemKind::Module(m) => { 597 raw::RawItemKind::Module(m) => {
582 self.collect_module(&self.raw_items[m], &item.attrs) 598 self.collect_module(&self.raw_items[m], &item.attrs)
583 } 599 }
584 raw::RawItemKind::Import(import_id) => self 600 raw::RawItemKind::Import(import_id) => {
585 .def_collector 601 self.def_collector.unresolved_imports.push(ImportDirective {
586 .unresolved_imports 602 module_id: self.module_id,
587 .push((self.module_id, import_id, self.raw_items[import_id].clone())), 603 import_id,
588 raw::RawItemKind::Def(def) => self.define_def(&self.raw_items[def]), 604 import: self.raw_items[import_id].clone(),
605 status: PartialResolvedImport::Unresolved,
606 })
607 }
608 raw::RawItemKind::Def(def) => {
609 self.define_def(&self.raw_items[def], &item.attrs)
610 }
589 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]), 611 raw::RawItemKind::Macro(mac) => self.collect_macro(&self.raw_items[mac]),
590 raw::RawItemKind::Impl(imp) => { 612 raw::RawItemKind::Impl(imp) => {
591 let module = ModuleId { 613 let module = ModuleId {
592 krate: self.def_collector.def_map.krate, 614 krate: self.def_collector.def_map.krate,
593 local_id: self.module_id, 615 local_id: self.module_id,
594 }; 616 };
595 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 617 let container = ContainerId::ModuleId(module);
596 let imp_id = ImplId::from_ast_id(ctx, self.raw_items[imp].ast_id); 618 let ast_id = self.raw_items[imp].ast_id;
597 self.def_collector.def_map.modules[self.module_id].impls.push(imp_id) 619 let impl_id =
620 ImplLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
621 .intern(self.def_collector.db);
622 self.def_collector.def_map.modules[self.module_id]
623 .scope
624 .define_impl(impl_id)
598 } 625 }
599 } 626 }
600 } 627 }
@@ -667,72 +694,91 @@ where
667 let modules = &mut self.def_collector.def_map.modules; 694 let modules = &mut self.def_collector.def_map.modules;
668 let res = modules.alloc(ModuleData::default()); 695 let res = modules.alloc(ModuleData::default());
669 modules[res].parent = Some(self.module_id); 696 modules[res].parent = Some(self.module_id);
670 modules[res].declaration = Some(declaration); 697 modules[res].origin = ModuleOrigin::not_sure_file(definition, declaration);
671 modules[res].definition = definition; 698 for (name, mac) in modules[self.module_id].scope.collect_legacy_macros() {
672 modules[res].scope.legacy_macros = modules[self.module_id].scope.legacy_macros.clone(); 699 modules[res].scope.define_legacy_macro(name, mac)
700 }
673 modules[self.module_id].children.insert(name.clone(), res); 701 modules[self.module_id].children.insert(name.clone(), res);
674 let resolution = Resolution { 702 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: res };
675 def: PerNs::types( 703 let def: ModuleDefId = module.into();
676 ModuleId { krate: self.def_collector.def_map.krate, local_id: res }.into(), 704 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
677 ), 705 self.def_collector.update(self.module_id, &[(name, def.into())]);
678 import: None,
679 };
680 self.def_collector.update(self.module_id, None, &[(name, resolution)]);
681 res 706 res
682 } 707 }
683 708
684 fn define_def(&mut self, def: &raw::DefData) { 709 fn define_def(&mut self, def: &raw::DefData, attrs: &Attrs) {
685 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id }; 710 let module = ModuleId { krate: self.def_collector.def_map.krate, local_id: self.module_id };
686 let ctx = LocationCtx::new(self.def_collector.db, module, self.file_id); 711 // FIXME: check attrs to see if this is an attribute macro invocation;
712 // in which case we don't add the invocation, just a single attribute
713 // macro invocation
687 714
688 let name = def.name.clone(); 715 self.collect_derives(attrs, def);
689 let def: PerNs = match def.kind {
690 raw::DefKind::Function(ast_id) => {
691 let def = FunctionLoc {
692 container: ContainerId::ModuleId(module),
693 ast_id: AstId::new(self.file_id, ast_id),
694 }
695 .intern(self.def_collector.db);
696 716
697 PerNs::values(def.into()) 717 let name = def.name.clone();
718 let container = ContainerId::ModuleId(module);
719 let def: ModuleDefId = match def.kind {
720 raw::DefKind::Function(ast_id) => FunctionLoc {
721 container: container.into(),
722 ast_id: AstId::new(self.file_id, ast_id),
698 } 723 }
724 .intern(self.def_collector.db)
725 .into(),
699 raw::DefKind::Struct(ast_id) => { 726 raw::DefKind::Struct(ast_id) => {
700 let id = StructId::from_ast_id(ctx, ast_id).into(); 727 StructLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
701 PerNs::both(id, id) 728 .intern(self.def_collector.db)
729 .into()
702 } 730 }
703 raw::DefKind::Union(ast_id) => { 731 raw::DefKind::Union(ast_id) => {
704 let id = UnionId::from_ast_id(ctx, ast_id).into(); 732 UnionLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
705 PerNs::both(id, id) 733 .intern(self.def_collector.db)
734 .into()
735 }
736 raw::DefKind::Enum(ast_id) => {
737 EnumLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
738 .intern(self.def_collector.db)
739 .into()
706 } 740 }
707 raw::DefKind::Enum(ast_id) => PerNs::types(EnumId::from_ast_id(ctx, ast_id).into()),
708 raw::DefKind::Const(ast_id) => { 741 raw::DefKind::Const(ast_id) => {
709 let def = ConstLoc { 742 ConstLoc { container: container.into(), ast_id: AstId::new(self.file_id, ast_id) }
710 container: ContainerId::ModuleId(module), 743 .intern(self.def_collector.db)
711 ast_id: AstId::new(self.file_id, ast_id), 744 .into()
712 }
713 .intern(self.def_collector.db);
714
715 PerNs::values(def.into())
716 } 745 }
717 raw::DefKind::Static(ast_id) => { 746 raw::DefKind::Static(ast_id) => {
718 let def = StaticLoc { container: module, ast_id: AstId::new(self.file_id, ast_id) } 747 StaticLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
719 .intern(self.def_collector.db); 748 .intern(self.def_collector.db)
720 749 .into()
721 PerNs::values(def.into())
722 } 750 }
723 raw::DefKind::Trait(ast_id) => PerNs::types(TraitId::from_ast_id(ctx, ast_id).into()), 751 raw::DefKind::Trait(ast_id) => {
724 raw::DefKind::TypeAlias(ast_id) => { 752 TraitLoc { container, ast_id: AstId::new(self.file_id, ast_id) }
725 let def = TypeAliasLoc { 753 .intern(self.def_collector.db)
726 container: ContainerId::ModuleId(module), 754 .into()
727 ast_id: AstId::new(self.file_id, ast_id),
728 }
729 .intern(self.def_collector.db);
730
731 PerNs::types(def.into())
732 } 755 }
756 raw::DefKind::TypeAlias(ast_id) => TypeAliasLoc {
757 container: container.into(),
758 ast_id: AstId::new(self.file_id, ast_id),
759 }
760 .intern(self.def_collector.db)
761 .into(),
733 }; 762 };
734 let resolution = Resolution { def, import: None }; 763 self.def_collector.def_map.modules[self.module_id].scope.define_def(def);
735 self.def_collector.update(self.module_id, None, &[(name, resolution)]) 764 self.def_collector.update(self.module_id, &[(name, def.into())])
765 }
766
767 fn collect_derives(&mut self, attrs: &Attrs, def: &raw::DefData) {
768 for derive_subtree in attrs.by_key("derive").tt_values() {
769 // for #[derive(Copy, Clone)], `derive_subtree` is the `(Copy, Clone)` subtree
770 for tt in &derive_subtree.token_trees {
771 let ident = match &tt {
772 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => ident,
773 tt::TokenTree::Leaf(tt::Leaf::Punct(_)) => continue, // , is ok
774 _ => continue, // anything else would be an error (which we currently ignore)
775 };
776 let path = ModPath::from_tt_ident(ident);
777
778 let ast_id = AstId::new(self.file_id, def.kind.ast_id());
779 self.def_collector.unexpanded_attribute_macros.push((self.module_id, ast_id, path));
780 }
781 }
736 } 782 }
737 783
738 fn collect_macro(&mut self, mac: &raw::MacroData) { 784 fn collect_macro(&mut self, mac: &raw::MacroData) {
@@ -758,8 +804,8 @@ where
758 if is_macro_rules(&mac.path) { 804 if is_macro_rules(&mac.path) {
759 if let Some(name) = &mac.name { 805 if let Some(name) = &mac.name {
760 let macro_id = MacroDefId { 806 let macro_id = MacroDefId {
761 ast_id, 807 ast_id: Some(ast_id),
762 krate: self.def_collector.def_map.krate, 808 krate: Some(self.def_collector.def_map.krate),
763 kind: MacroDefKind::Declarative, 809 kind: MacroDefKind::Declarative,
764 }; 810 };
765 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); 811 self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export);
@@ -767,14 +813,20 @@ where
767 return; 813 return;
768 } 814 }
769 815
770 // Case 2: try to resolve in legacy scope and expand macro_rules, triggering 816 // Case 2: try to resolve in legacy scope and expand macro_rules
771 // recursive item collection.
772 if let Some(macro_def) = mac.path.as_ident().and_then(|name| { 817 if let Some(macro_def) = mac.path.as_ident().and_then(|name| {
773 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) 818 self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name)
774 }) { 819 }) {
775 let macro_call_id = macro_def.as_call_id(self.def_collector.db, ast_id); 820 let macro_call_id =
821 macro_def.as_call_id(self.def_collector.db, MacroCallKind::FnLike(ast_id));
822
823 self.def_collector.unexpanded_macros.push(MacroDirective {
824 module_id: self.module_id,
825 path: mac.path.clone(),
826 ast_id,
827 legacy: Some(macro_call_id),
828 });
776 829
777 self.def_collector.collect_macro_expansion(self.module_id, macro_call_id, macro_def);
778 return; 830 return;
779 } 831 }
780 832
@@ -782,13 +834,19 @@ where
782 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only. 834 // We rewrite simple path `macro_name` to `self::macro_name` to force resolve in module scope only.
783 let mut path = mac.path.clone(); 835 let mut path = mac.path.clone();
784 if path.is_ident() { 836 if path.is_ident() {
785 path.kind = PathKind::Self_; 837 path.kind = PathKind::Super(0);
786 } 838 }
787 self.def_collector.unexpanded_macros.push((self.module_id, ast_id, path)); 839
840 self.def_collector.unexpanded_macros.push(MacroDirective {
841 module_id: self.module_id,
842 path,
843 ast_id,
844 legacy: None,
845 });
788 } 846 }
789 847
790 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) { 848 fn import_all_legacy_macros(&mut self, module_id: LocalModuleId) {
791 let macros = self.def_collector.def_map[module_id].scope.legacy_macros.clone(); 849 let macros = self.def_collector.def_map[module_id].scope.collect_legacy_macros();
792 for (name, macro_) in macros { 850 for (name, macro_) in macros {
793 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_); 851 self.def_collector.define_legacy_macro(self.module_id, name.clone(), macro_);
794 } 852 }
@@ -803,45 +861,35 @@ where
803 } 861 }
804} 862}
805 863
806fn is_macro_rules(path: &Path) -> bool { 864fn is_macro_rules(path: &ModPath) -> bool {
807 path.as_ident() == Some(&name::MACRO_RULES) 865 path.as_ident() == Some(&name![macro_rules])
808} 866}
809 867
810#[cfg(test)] 868#[cfg(test)]
811mod tests { 869mod tests {
870 use crate::{db::DefDatabase, test_db::TestDB};
812 use ra_arena::Arena; 871 use ra_arena::Arena;
813 use ra_db::{fixture::WithFixture, SourceDatabase}; 872 use ra_db::{fixture::WithFixture, SourceDatabase};
814 use rustc_hash::FxHashSet;
815
816 use crate::{db::DefDatabase, test_db::TestDB};
817 873
818 use super::*; 874 use super::*;
819 875
820 fn do_collect_defs( 876 fn do_collect_defs(db: &impl DefDatabase, def_map: CrateDefMap) -> CrateDefMap {
821 db: &impl DefDatabase,
822 def_map: CrateDefMap,
823 monitor: MacroStackMonitor,
824 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
825 let mut collector = DefCollector { 877 let mut collector = DefCollector {
826 db, 878 db,
827 def_map, 879 def_map,
828 glob_imports: FxHashMap::default(), 880 glob_imports: FxHashMap::default(),
829 unresolved_imports: Vec::new(), 881 unresolved_imports: Vec::new(),
882 resolved_imports: Vec::new(),
830 unexpanded_macros: Vec::new(), 883 unexpanded_macros: Vec::new(),
884 unexpanded_attribute_macros: Vec::new(),
831 mod_dirs: FxHashMap::default(), 885 mod_dirs: FxHashMap::default(),
832 macro_stack_monitor: monitor,
833 poison_macros: FxHashSet::default(),
834 cfg_options: &CfgOptions::default(), 886 cfg_options: &CfgOptions::default(),
835 }; 887 };
836 collector.collect(); 888 collector.collect();
837 (collector.def_map, collector.poison_macros) 889 collector.def_map
838 } 890 }
839 891
840 fn do_limited_resolve( 892 fn do_resolve(code: &str) -> CrateDefMap {
841 code: &str,
842 limit: u32,
843 poison_limit: u32,
844 ) -> (CrateDefMap, FxHashSet<MacroDefId>) {
845 let (db, _file_id) = TestDB::with_single_file(&code); 893 let (db, _file_id) = TestDB::with_single_file(&code);
846 let krate = db.test_crate(); 894 let krate = db.test_crate();
847 895
@@ -859,59 +907,18 @@ mod tests {
859 diagnostics: Vec::new(), 907 diagnostics: Vec::new(),
860 } 908 }
861 }; 909 };
862 910 do_collect_defs(&db, def_map)
863 let mut monitor = MacroStackMonitor::default();
864 monitor.validator = Some(Box::new(move |count| {
865 assert!(count < limit);
866 count >= poison_limit
867 }));
868
869 do_collect_defs(&db, def_map, monitor)
870 } 911 }
871 912
872 #[test] 913 #[test]
873 fn test_macro_expand_limit_width() { 914 fn test_macro_expand_will_stop() {
874 do_limited_resolve( 915 do_resolve(
875 r#" 916 r#"
876 macro_rules! foo { 917 macro_rules! foo {
877 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); } 918 ($($ty:ty)*) => { foo!($($ty)*, $($ty)*); }
878 } 919 }
879foo!(KABOOM); 920foo!(KABOOM);
880 "#, 921 "#,
881 16,
882 1000,
883 ); 922 );
884 } 923 }
885
886 #[test]
887 fn test_macro_expand_poisoned() {
888 let (_, poison_macros) = do_limited_resolve(
889 r#"
890 macro_rules! foo {
891 ($ty:ty) => { foo!($ty); }
892 }
893foo!(KABOOM);
894 "#,
895 100,
896 16,
897 );
898
899 assert_eq!(poison_macros.len(), 1);
900 }
901
902 #[test]
903 fn test_macro_expand_normal() {
904 let (_, poison_macros) = do_limited_resolve(
905 r#"
906 macro_rules! foo {
907 ($ident:ident) => { struct $ident {} }
908 }
909foo!(Bar);
910 "#,
911 16,
912 16,
913 );
914
915 assert_eq!(poison_macros.len(), 0);
916 }
917} 924}
diff --git a/crates/ra_hir_def/src/nameres/path_resolution.rs b/crates/ra_hir_def/src/nameres/path_resolution.rs
index b72c55bd1..695014c7b 100644
--- a/crates/ra_hir_def/src/nameres/path_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/path_resolution.rs
@@ -10,16 +10,18 @@
10//! 10//!
11//! `ReachedFixedPoint` signals about this. 11//! `ReachedFixedPoint` signals about this.
12 12
13use std::iter::successors;
14
13use hir_expand::name::Name; 15use hir_expand::name::Name;
14use ra_db::Edition; 16use ra_db::Edition;
15use test_utils::tested_by; 17use test_utils::tested_by;
16 18
17use crate::{ 19use crate::{
18 db::DefDatabase, 20 db::DefDatabase,
19 nameres::CrateDefMap, 21 nameres::{BuiltinShadowMode, CrateDefMap},
20 path::{Path, PathKind}, 22 path::{ModPath, PathKind},
21 per_ns::PerNs, 23 per_ns::PerNs,
22 AdtId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId, 24 AdtId, CrateId, EnumVariantId, LocalModuleId, ModuleDefId, ModuleId,
23}; 25};
24 26
25#[derive(Debug, Clone, Copy, PartialEq, Eq)] 27#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -39,19 +41,21 @@ pub(super) struct ResolvePathResult {
39 pub(super) resolved_def: PerNs, 41 pub(super) resolved_def: PerNs,
40 pub(super) segment_index: Option<usize>, 42 pub(super) segment_index: Option<usize>,
41 pub(super) reached_fixedpoint: ReachedFixedPoint, 43 pub(super) reached_fixedpoint: ReachedFixedPoint,
44 pub(super) krate: Option<CrateId>,
42} 45}
43 46
44impl ResolvePathResult { 47impl ResolvePathResult {
45 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult { 48 fn empty(reached_fixedpoint: ReachedFixedPoint) -> ResolvePathResult {
46 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None) 49 ResolvePathResult::with(PerNs::none(), reached_fixedpoint, None, None)
47 } 50 }
48 51
49 fn with( 52 fn with(
50 resolved_def: PerNs, 53 resolved_def: PerNs,
51 reached_fixedpoint: ReachedFixedPoint, 54 reached_fixedpoint: ReachedFixedPoint,
52 segment_index: Option<usize>, 55 segment_index: Option<usize>,
56 krate: Option<CrateId>,
53 ) -> ResolvePathResult { 57 ) -> ResolvePathResult {
54 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index } 58 ResolvePathResult { resolved_def, reached_fixedpoint, segment_index, krate }
55 } 59 }
56} 60}
57 61
@@ -67,8 +71,18 @@ impl CrateDefMap {
67 db: &impl DefDatabase, 71 db: &impl DefDatabase,
68 mode: ResolveMode, 72 mode: ResolveMode,
69 original_module: LocalModuleId, 73 original_module: LocalModuleId,
70 path: &Path, 74 path: &ModPath,
75 shadow: BuiltinShadowMode,
71 ) -> ResolvePathResult { 76 ) -> ResolvePathResult {
77 // if it is not the last segment, we prefer the module to the builtin
78 let prefer_module = |index| {
79 if index == path.segments.len() - 1 {
80 shadow
81 } else {
82 BuiltinShadowMode::Module
83 }
84 };
85
72 let mut segments = path.segments.iter().enumerate(); 86 let mut segments = path.segments.iter().enumerate();
73 let mut curr_per_ns: PerNs = match path.kind { 87 let mut curr_per_ns: PerNs = match path.kind {
74 PathKind::DollarCrate(krate) => { 88 PathKind::DollarCrate(krate) => {
@@ -85,9 +99,6 @@ impl CrateDefMap {
85 PathKind::Crate => { 99 PathKind::Crate => {
86 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into()) 100 PerNs::types(ModuleId { krate: self.krate, local_id: self.root }.into())
87 } 101 }
88 PathKind::Self_ => {
89 PerNs::types(ModuleId { krate: self.krate, local_id: original_module }.into())
90 }
91 // plain import or absolute path in 2015: crate-relative with 102 // plain import or absolute path in 2015: crate-relative with
92 // fallback to extern prelude (with the simplification in 103 // fallback to extern prelude (with the simplification in
93 // rust-lang/rust#57745) 104 // rust-lang/rust#57745)
@@ -96,24 +107,26 @@ impl CrateDefMap {
96 if self.edition == Edition::Edition2015 107 if self.edition == Edition::Edition2015
97 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) => 108 && (path.kind == PathKind::Abs || mode == ResolveMode::Import) =>
98 { 109 {
99 let segment = match segments.next() { 110 let (idx, segment) = match segments.next() {
100 Some((_, segment)) => segment, 111 Some((idx, segment)) => (idx, segment),
101 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 112 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
102 }; 113 };
103 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 114 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
104 self.resolve_name_in_crate_root_or_extern_prelude(&segment.name) 115 self.resolve_name_in_crate_root_or_extern_prelude(&segment, prefer_module(idx))
105 } 116 }
106 PathKind::Plain => { 117 PathKind::Plain => {
107 let segment = match segments.next() { 118 let (idx, segment) = match segments.next() {
108 Some((_, segment)) => segment, 119 Some((idx, segment)) => (idx, segment),
109 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 120 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
110 }; 121 };
111 log::debug!("resolving {:?} in module", segment); 122 log::debug!("resolving {:?} in module", segment);
112 self.resolve_name_in_module(db, original_module, &segment.name) 123 self.resolve_name_in_module(db, original_module, &segment, prefer_module(idx))
113 } 124 }
114 PathKind::Super => { 125 PathKind::Super(lvl) => {
115 if let Some(p) = self.modules[original_module].parent { 126 let m = successors(Some(original_module), |m| self.modules[*m].parent)
116 PerNs::types(ModuleId { krate: self.krate, local_id: p }.into()) 127 .nth(lvl as usize);
128 if let Some(local_id) = m {
129 PerNs::types(ModuleId { krate: self.krate, local_id }.into())
117 } else { 130 } else {
118 log::debug!("super path in root module"); 131 log::debug!("super path in root module");
119 return ResolvePathResult::empty(ReachedFixedPoint::Yes); 132 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
@@ -125,18 +138,13 @@ impl CrateDefMap {
125 Some((_, segment)) => segment, 138 Some((_, segment)) => segment,
126 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 139 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
127 }; 140 };
128 if let Some(def) = self.extern_prelude.get(&segment.name) { 141 if let Some(def) = self.extern_prelude.get(&segment) {
129 log::debug!("absolute path {:?} resolved to crate {:?}", path, def); 142 log::debug!("absolute path {:?} resolved to crate {:?}", path, def);
130 PerNs::types(*def) 143 PerNs::types(*def)
131 } else { 144 } else {
132 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude 145 return ResolvePathResult::empty(ReachedFixedPoint::No); // extern crate declarations can add to the extern prelude
133 } 146 }
134 } 147 }
135 PathKind::Type(_) => {
136 // This is handled in `infer::infer_path_expr`
137 // The result returned here does not matter
138 return ResolvePathResult::empty(ReachedFixedPoint::Yes);
139 }
140 }; 148 };
141 149
142 for (i, segment) in segments { 150 for (i, segment) in segments {
@@ -156,32 +164,29 @@ impl CrateDefMap {
156 curr_per_ns = match curr { 164 curr_per_ns = match curr {
157 ModuleDefId::ModuleId(module) => { 165 ModuleDefId::ModuleId(module) => {
158 if module.krate != self.krate { 166 if module.krate != self.krate {
159 let path = 167 let path = ModPath {
160 Path { segments: path.segments[i..].to_vec(), kind: PathKind::Self_ }; 168 segments: path.segments[i..].to_vec(),
169 kind: PathKind::Super(0),
170 };
161 log::debug!("resolving {:?} in other crate", path); 171 log::debug!("resolving {:?} in other crate", path);
162 let defp_map = db.crate_def_map(module.krate); 172 let defp_map = db.crate_def_map(module.krate);
163 let (def, s) = defp_map.resolve_path(db, module.local_id, &path); 173 let (def, s) = defp_map.resolve_path(db, module.local_id, &path, shadow);
164 return ResolvePathResult::with( 174 return ResolvePathResult::with(
165 def, 175 def,
166 ReachedFixedPoint::Yes, 176 ReachedFixedPoint::Yes,
167 s.map(|s| s + i), 177 s.map(|s| s + i),
178 Some(module.krate),
168 ); 179 );
169 } 180 }
170 181
171 // Since it is a qualified path here, it should not contains legacy macros 182 // Since it is a qualified path here, it should not contains legacy macros
172 match self[module.local_id].scope.get(&segment.name) { 183 self[module.local_id].scope.get(&segment, prefer_module(i))
173 Some(res) => res.def,
174 _ => {
175 log::debug!("path segment {:?} not found", segment.name);
176 return ResolvePathResult::empty(ReachedFixedPoint::No);
177 }
178 }
179 } 184 }
180 ModuleDefId::AdtId(AdtId::EnumId(e)) => { 185 ModuleDefId::AdtId(AdtId::EnumId(e)) => {
181 // enum variant 186 // enum variant
182 tested_by!(can_import_enum_variant); 187 tested_by!(can_import_enum_variant);
183 let enum_data = db.enum_data(e); 188 let enum_data = db.enum_data(e);
184 match enum_data.variant(&segment.name) { 189 match enum_data.variant(&segment) {
185 Some(local_id) => { 190 Some(local_id) => {
186 let variant = EnumVariantId { parent: e, local_id }; 191 let variant = EnumVariantId { parent: e, local_id };
187 PerNs::both(variant.into(), variant.into()) 192 PerNs::both(variant.into(), variant.into())
@@ -191,6 +196,7 @@ impl CrateDefMap {
191 PerNs::types(e.into()), 196 PerNs::types(e.into()),
192 ReachedFixedPoint::Yes, 197 ReachedFixedPoint::Yes,
193 Some(i), 198 Some(i),
199 Some(self.krate),
194 ); 200 );
195 } 201 }
196 } 202 }
@@ -200,7 +206,7 @@ impl CrateDefMap {
200 // (`Struct::method`), or some other kind of associated item 206 // (`Struct::method`), or some other kind of associated item
201 log::debug!( 207 log::debug!(
202 "path segment {:?} resolved to non-module {:?}, but is not last", 208 "path segment {:?} resolved to non-module {:?}, but is not last",
203 segment.name, 209 segment,
204 curr, 210 curr,
205 ); 211 );
206 212
@@ -208,11 +214,13 @@ impl CrateDefMap {
208 PerNs::types(s), 214 PerNs::types(s),
209 ReachedFixedPoint::Yes, 215 ReachedFixedPoint::Yes,
210 Some(i), 216 Some(i),
217 Some(self.krate),
211 ); 218 );
212 } 219 }
213 }; 220 };
214 } 221 }
215 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None) 222
223 ResolvePathResult::with(curr_per_ns, ReachedFixedPoint::Yes, None, Some(self.krate))
216 } 224 }
217 225
218 fn resolve_name_in_module( 226 fn resolve_name_in_module(
@@ -220,6 +228,7 @@ impl CrateDefMap {
220 db: &impl DefDatabase, 228 db: &impl DefDatabase,
221 module: LocalModuleId, 229 module: LocalModuleId,
222 name: &Name, 230 name: &Name,
231 shadow: BuiltinShadowMode,
223 ) -> PerNs { 232 ) -> PerNs {
224 // Resolve in: 233 // Resolve in:
225 // - legacy scope of macro 234 // - legacy scope of macro
@@ -228,23 +237,31 @@ impl CrateDefMap {
228 // - std prelude 237 // - std prelude
229 let from_legacy_macro = 238 let from_legacy_macro =
230 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros); 239 self[module].scope.get_legacy_macro(name).map_or_else(PerNs::none, PerNs::macros);
231 let from_scope = self[module].scope.get(name).map_or_else(PerNs::none, |res| res.def); 240 let from_scope = self[module].scope.get(name, shadow);
232 let from_extern_prelude = 241 let from_extern_prelude =
233 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it)); 242 self.extern_prelude.get(name).map_or(PerNs::none(), |&it| PerNs::types(it));
234 let from_prelude = self.resolve_in_prelude(db, name); 243 let from_prelude = self.resolve_in_prelude(db, name, shadow);
235 244
236 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude) 245 from_legacy_macro.or(from_scope).or(from_extern_prelude).or(from_prelude)
237 } 246 }
238 247
239 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 248 fn resolve_name_in_crate_root_or_extern_prelude(
240 let from_crate_root = 249 &self,
241 self[self.root].scope.get(name).map_or_else(PerNs::none, |res| res.def); 250 name: &Name,
251 shadow: BuiltinShadowMode,
252 ) -> PerNs {
253 let from_crate_root = self[self.root].scope.get(name, shadow);
242 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 254 let from_extern_prelude = self.resolve_name_in_extern_prelude(name);
243 255
244 from_crate_root.or(from_extern_prelude) 256 from_crate_root.or(from_extern_prelude)
245 } 257 }
246 258
247 fn resolve_in_prelude(&self, db: &impl DefDatabase, name: &Name) -> PerNs { 259 fn resolve_in_prelude(
260 &self,
261 db: &impl DefDatabase,
262 name: &Name,
263 shadow: BuiltinShadowMode,
264 ) -> PerNs {
248 if let Some(prelude) = self.prelude { 265 if let Some(prelude) = self.prelude {
249 let keep; 266 let keep;
250 let def_map = if prelude.krate == self.krate { 267 let def_map = if prelude.krate == self.krate {
@@ -254,7 +271,7 @@ impl CrateDefMap {
254 keep = db.crate_def_map(prelude.krate); 271 keep = db.crate_def_map(prelude.krate);
255 &keep 272 &keep
256 }; 273 };
257 def_map[prelude.local_id].scope.get(name).map_or_else(PerNs::none, |res| res.def) 274 def_map[prelude.local_id].scope.get(name, shadow)
258 } else { 275 } else {
259 PerNs::none() 276 PerNs::none()
260 } 277 }
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs
index 6eb106094..73dc08745 100644
--- a/crates/ra_hir_def/src/nameres/raw.rs
+++ b/crates/ra_hir_def/src/nameres/raw.rs
@@ -10,21 +10,18 @@ use std::{ops::Index, sync::Arc};
10use hir_expand::{ 10use hir_expand::{
11 ast_id_map::AstIdMap, 11 ast_id_map::AstIdMap,
12 db::AstDatabase, 12 db::AstDatabase,
13 either::Either,
14 hygiene::Hygiene, 13 hygiene::Hygiene,
15 name::{AsName, Name}, 14 name::{AsName, Name},
16}; 15};
17use ra_arena::{impl_arena_id, map::ArenaMap, Arena, RawId}; 16use ra_arena::{impl_arena_id, Arena, RawId};
17use ra_prof::profile;
18use ra_syntax::{ 18use ra_syntax::{
19 ast::{self, AttrsOwner, NameOwner}, 19 ast::{self, AttrsOwner, NameOwner},
20 AstNode, AstPtr, 20 AstNode,
21}; 21};
22use test_utils::tested_by; 22use test_utils::tested_by;
23 23
24use crate::{ 24use crate::{attr::Attrs, db::DefDatabase, path::ModPath, FileAstId, HirFileId, InFile};
25 attr::Attrs, db::DefDatabase, path::Path, trace::Trace, FileAstId, HirFileId, LocalImportId,
26 Source,
27};
28 25
29/// `RawItems` is a set of top-level items in a file (except for impls). 26/// `RawItems` is a set of top-level items in a file (except for impls).
30/// 27///
@@ -33,7 +30,7 @@ use crate::{
33#[derive(Debug, Default, PartialEq, Eq)] 30#[derive(Debug, Default, PartialEq, Eq)]
34pub struct RawItems { 31pub struct RawItems {
35 modules: Arena<Module, ModuleData>, 32 modules: Arena<Module, ModuleData>,
36 imports: Arena<LocalImportId, ImportData>, 33 imports: Arena<Import, ImportData>,
37 defs: Arena<Def, DefData>, 34 defs: Arena<Def, DefData>,
38 macros: Arena<Macro, MacroData>, 35 macros: Arena<Macro, MacroData>,
39 impls: Arena<Impl, ImplData>, 36 impls: Arena<Impl, ImplData>,
@@ -41,35 +38,15 @@ pub struct RawItems {
41 items: Vec<RawItem>, 38 items: Vec<RawItem>,
42} 39}
43 40
44#[derive(Debug, Default, PartialEq, Eq)]
45pub struct ImportSourceMap {
46 map: ArenaMap<LocalImportId, ImportSourcePtr>,
47}
48
49type ImportSourcePtr = Either<AstPtr<ast::UseTree>, AstPtr<ast::ExternCrateItem>>;
50
51impl ImportSourceMap {
52 pub fn get(&self, import: LocalImportId) -> ImportSourcePtr {
53 self.map[import].clone()
54 }
55}
56
57impl RawItems { 41impl RawItems {
58 pub(crate) fn raw_items_query( 42 pub(crate) fn raw_items_query(
59 db: &(impl DefDatabase + AstDatabase), 43 db: &(impl DefDatabase + AstDatabase),
60 file_id: HirFileId, 44 file_id: HirFileId,
61 ) -> Arc<RawItems> { 45 ) -> Arc<RawItems> {
62 db.raw_items_with_source_map(file_id).0 46 let _p = profile("raw_items_query");
63 }
64
65 pub(crate) fn raw_items_with_source_map_query(
66 db: &(impl DefDatabase + AstDatabase),
67 file_id: HirFileId,
68 ) -> (Arc<RawItems>, Arc<ImportSourceMap>) {
69 let mut collector = RawItemsCollector { 47 let mut collector = RawItemsCollector {
70 raw_items: RawItems::default(), 48 raw_items: RawItems::default(),
71 source_ast_id_map: db.ast_id_map(file_id), 49 source_ast_id_map: db.ast_id_map(file_id),
72 imports: Trace::new(),
73 file_id, 50 file_id,
74 hygiene: Hygiene::new(db, file_id), 51 hygiene: Hygiene::new(db, file_id),
75 }; 52 };
@@ -80,11 +57,8 @@ impl RawItems {
80 collector.process_module(None, item_list); 57 collector.process_module(None, item_list);
81 } 58 }
82 } 59 }
83 let mut raw_items = collector.raw_items; 60 let raw_items = collector.raw_items;
84 let (arena, map) = collector.imports.into_arena_and_map(); 61 Arc::new(raw_items)
85 raw_items.imports = arena;
86 let source_map = ImportSourceMap { map };
87 (Arc::new(raw_items), Arc::new(source_map))
88 } 62 }
89 63
90 pub(super) fn items(&self) -> &[RawItem] { 64 pub(super) fn items(&self) -> &[RawItem] {
@@ -99,9 +73,9 @@ impl Index<Module> for RawItems {
99 } 73 }
100} 74}
101 75
102impl Index<LocalImportId> for RawItems { 76impl Index<Import> for RawItems {
103 type Output = ImportData; 77 type Output = ImportData;
104 fn index(&self, idx: LocalImportId) -> &ImportData { 78 fn index(&self, idx: Import) -> &ImportData {
105 &self.imports[idx] 79 &self.imports[idx]
106 } 80 }
107} 81}
@@ -136,7 +110,7 @@ pub(super) struct RawItem {
136#[derive(Debug, PartialEq, Eq, Clone, Copy)] 110#[derive(Debug, PartialEq, Eq, Clone, Copy)]
137pub(super) enum RawItemKind { 111pub(super) enum RawItemKind {
138 Module(Module), 112 Module(Module),
139 Import(LocalImportId), 113 Import(Import),
140 Def(Def), 114 Def(Def),
141 Macro(Macro), 115 Macro(Macro),
142 Impl(Impl), 116 Impl(Impl),
@@ -152,9 +126,13 @@ pub(super) enum ModuleData {
152 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> }, 126 Definition { name: Name, ast_id: FileAstId<ast::Module>, items: Vec<RawItem> },
153} 127}
154 128
129#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
130pub(crate) struct Import(RawId);
131impl_arena_id!(Import);
132
155#[derive(Debug, Clone, PartialEq, Eq)] 133#[derive(Debug, Clone, PartialEq, Eq)]
156pub struct ImportData { 134pub struct ImportData {
157 pub(super) path: Path, 135 pub(super) path: ModPath,
158 pub(super) alias: Option<Name>, 136 pub(super) alias: Option<Name>,
159 pub(super) is_glob: bool, 137 pub(super) is_glob: bool,
160 pub(super) is_prelude: bool, 138 pub(super) is_prelude: bool,
@@ -184,6 +162,21 @@ pub(super) enum DefKind {
184 TypeAlias(FileAstId<ast::TypeAliasDef>), 162 TypeAlias(FileAstId<ast::TypeAliasDef>),
185} 163}
186 164
165impl DefKind {
166 pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> {
167 match self {
168 DefKind::Function(it) => it.upcast(),
169 DefKind::Struct(it) => it.upcast(),
170 DefKind::Union(it) => it.upcast(),
171 DefKind::Enum(it) => it.upcast(),
172 DefKind::Const(it) => it.upcast(),
173 DefKind::Static(it) => it.upcast(),
174 DefKind::Trait(it) => it.upcast(),
175 DefKind::TypeAlias(it) => it.upcast(),
176 }
177 }
178}
179
187#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 180#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
188pub(super) struct Macro(RawId); 181pub(super) struct Macro(RawId);
189impl_arena_id!(Macro); 182impl_arena_id!(Macro);
@@ -191,7 +184,7 @@ impl_arena_id!(Macro);
191#[derive(Debug, PartialEq, Eq)] 184#[derive(Debug, PartialEq, Eq)]
192pub(super) struct MacroData { 185pub(super) struct MacroData {
193 pub(super) ast_id: FileAstId<ast::MacroCall>, 186 pub(super) ast_id: FileAstId<ast::MacroCall>,
194 pub(super) path: Path, 187 pub(super) path: ModPath,
195 pub(super) name: Option<Name>, 188 pub(super) name: Option<Name>,
196 pub(super) export: bool, 189 pub(super) export: bool,
197 pub(super) builtin: bool, 190 pub(super) builtin: bool,
@@ -208,7 +201,6 @@ pub(super) struct ImplData {
208 201
209struct RawItemsCollector { 202struct RawItemsCollector {
210 raw_items: RawItems, 203 raw_items: RawItems,
211 imports: Trace<LocalImportId, ImportData, ImportSourcePtr>,
212 source_ast_id_map: Arc<AstIdMap>, 204 source_ast_id_map: Arc<AstIdMap>,
213 file_id: HirFileId, 205 file_id: HirFileId,
214 hygiene: Hygiene, 206 hygiene: Hygiene,
@@ -312,10 +304,10 @@ impl RawItemsCollector {
312 let attrs = self.parse_attrs(&use_item); 304 let attrs = self.parse_attrs(&use_item);
313 305
314 let mut buf = Vec::new(); 306 let mut buf = Vec::new();
315 Path::expand_use_item( 307 ModPath::expand_use_item(
316 Source { value: use_item, file_id: self.file_id }, 308 InFile { value: use_item, file_id: self.file_id },
317 &self.hygiene, 309 &self.hygiene,
318 |path, use_tree, is_glob, alias| { 310 |path, _use_tree, is_glob, alias| {
319 let import_data = ImportData { 311 let import_data = ImportData {
320 path, 312 path,
321 alias, 313 alias,
@@ -324,11 +316,11 @@ impl RawItemsCollector {
324 is_extern_crate: false, 316 is_extern_crate: false,
325 is_macro_use: false, 317 is_macro_use: false,
326 }; 318 };
327 buf.push((import_data, Either::A(AstPtr::new(use_tree)))); 319 buf.push(import_data);
328 }, 320 },
329 ); 321 );
330 for (import_data, ptr) in buf { 322 for import_data in buf {
331 self.push_import(current_module, attrs.clone(), import_data, ptr); 323 self.push_import(current_module, attrs.clone(), import_data);
332 } 324 }
333 } 325 }
334 326
@@ -338,7 +330,7 @@ impl RawItemsCollector {
338 extern_crate: ast::ExternCrateItem, 330 extern_crate: ast::ExternCrateItem,
339 ) { 331 ) {
340 if let Some(name_ref) = extern_crate.name_ref() { 332 if let Some(name_ref) = extern_crate.name_ref() {
341 let path = Path::from_name_ref(&name_ref); 333 let path = ModPath::from_name_ref(&name_ref);
342 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name()); 334 let alias = extern_crate.alias().and_then(|a| a.name()).map(|it| it.as_name());
343 let attrs = self.parse_attrs(&extern_crate); 335 let attrs = self.parse_attrs(&extern_crate);
344 // FIXME: cfg_attr 336 // FIXME: cfg_attr
@@ -351,18 +343,13 @@ impl RawItemsCollector {
351 is_extern_crate: true, 343 is_extern_crate: true,
352 is_macro_use, 344 is_macro_use,
353 }; 345 };
354 self.push_import( 346 self.push_import(current_module, attrs, import_data);
355 current_module,
356 attrs,
357 import_data,
358 Either::B(AstPtr::new(&extern_crate)),
359 );
360 } 347 }
361 } 348 }
362 349
363 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) { 350 fn add_macro(&mut self, current_module: Option<Module>, m: ast::MacroCall) {
364 let attrs = self.parse_attrs(&m); 351 let attrs = self.parse_attrs(&m);
365 let path = match m.path().and_then(|path| Path::from_src(path, &self.hygiene)) { 352 let path = match m.path().and_then(|path| ModPath::from_src(path, &self.hygiene)) {
366 Some(it) => it, 353 Some(it) => it,
367 _ => return, 354 _ => return,
368 }; 355 };
@@ -387,14 +374,8 @@ impl RawItemsCollector {
387 self.push_item(current_module, attrs, RawItemKind::Impl(imp)) 374 self.push_item(current_module, attrs, RawItemKind::Impl(imp))
388 } 375 }
389 376
390 fn push_import( 377 fn push_import(&mut self, current_module: Option<Module>, attrs: Attrs, data: ImportData) {
391 &mut self, 378 let import = self.raw_items.imports.alloc(data);
392 current_module: Option<Module>,
393 attrs: Attrs,
394 data: ImportData,
395 source: ImportSourcePtr,
396 ) {
397 let import = self.imports.alloc(|| source, || data);
398 self.push_item(current_module, attrs, RawItemKind::Import(import)) 379 self.push_item(current_module, attrs, RawItemKind::Import(import))
399 } 380 }
400 381
diff --git a/crates/ra_hir_def/src/nameres/tests.rs b/crates/ra_hir_def/src/nameres/tests.rs
index 87fcd617c..ff474b53b 100644
--- a/crates/ra_hir_def/src/nameres/tests.rs
+++ b/crates/ra_hir_def/src/nameres/tests.rs
@@ -32,27 +32,22 @@ fn render_crate_def_map(map: &CrateDefMap) -> String {
32 *buf += path; 32 *buf += path;
33 *buf += "\n"; 33 *buf += "\n";
34 34
35 let mut entries = map.modules[module] 35 let mut entries = map.modules[module].scope.collect_resolutions();
36 .scope 36 entries.sort_by_key(|(name, _)| name.clone());
37 .items 37
38 .iter() 38 for (name, def) in entries {
39 .map(|(name, res)| (name, res.def))
40 .collect::<Vec<_>>();
41 entries.sort_by_key(|(name, _)| *name);
42
43 for (name, res) in entries {
44 *buf += &format!("{}:", name); 39 *buf += &format!("{}:", name);
45 40
46 if res.types.is_some() { 41 if def.types.is_some() {
47 *buf += " t"; 42 *buf += " t";
48 } 43 }
49 if res.values.is_some() { 44 if def.values.is_some() {
50 *buf += " v"; 45 *buf += " v";
51 } 46 }
52 if res.macros.is_some() { 47 if def.macros.is_some() {
53 *buf += " m"; 48 *buf += " m";
54 } 49 }
55 if res.is_none() { 50 if def.is_none() {
56 *buf += " _"; 51 *buf += " _";
57 } 52 }
58 53
@@ -558,3 +553,35 @@ fn cfg_test() {
558 â‹®Foo: t v 553 â‹®Foo: t v
559 "###); 554 "###);
560} 555}
556
557#[test]
558fn infer_multiple_namespace() {
559 let map = def_map(
560 r#"
561//- /main.rs
562mod a {
563 pub type T = ();
564 pub use crate::b::*;
565}
566
567use crate::a::T;
568
569mod b {
570 pub const T: () = ();
571}
572"#,
573 );
574
575 assert_snapshot!(map, @r###"
576 â‹®crate
577 â‹®T: t v
578 â‹®a: t
579 â‹®b: t
580 â‹®
581 â‹®crate::b
582 â‹®T: v
583 â‹®
584 â‹®crate::a
585 â‹®T: t v
586"###);
587}
diff --git a/crates/ra_hir_def/src/nameres/tests/globs.rs b/crates/ra_hir_def/src/nameres/tests/globs.rs
index 5b03fe365..5e24cb94d 100644
--- a/crates/ra_hir_def/src/nameres/tests/globs.rs
+++ b/crates/ra_hir_def/src/nameres/tests/globs.rs
@@ -112,3 +112,24 @@ fn glob_enum() {
112 "### 112 "###
113 ); 113 );
114} 114}
115
116#[test]
117fn glob_enum_group() {
118 covers!(glob_enum_group);
119 let map = def_map(
120 "
121 //- /lib.rs
122 enum Foo {
123 Bar, Baz
124 }
125 use self::Foo::{*};
126 ",
127 );
128 assert_snapshot!(map, @r###"
129 â‹®crate
130 â‹®Bar: t v
131 â‹®Baz: t v
132 â‹®Foo: t
133 "###
134 );
135}
diff --git a/crates/ra_hir_def/src/nameres/tests/incremental.rs b/crates/ra_hir_def/src/nameres/tests/incremental.rs
index 903a22771..ef2e9435c 100644
--- a/crates/ra_hir_def/src/nameres/tests/incremental.rs
+++ b/crates/ra_hir_def/src/nameres/tests/incremental.rs
@@ -116,7 +116,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
116 let events = db.log_executed(|| { 116 let events = db.log_executed(|| {
117 let crate_def_map = db.crate_def_map(krate); 117 let crate_def_map = db.crate_def_map(krate);
118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 118 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
119 assert_eq!(module_data.scope.items.len(), 1); 119 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
120 }); 120 });
121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 121 assert!(format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
122 } 122 }
@@ -126,7 +126,7 @@ fn typing_inside_a_macro_should_not_invalidate_def_map() {
126 let events = db.log_executed(|| { 126 let events = db.log_executed(|| {
127 let crate_def_map = db.crate_def_map(krate); 127 let crate_def_map = db.crate_def_map(krate);
128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap(); 128 let (_, module_data) = crate_def_map.modules.iter().last().unwrap();
129 assert_eq!(module_data.scope.items.len(), 1); 129 assert_eq!(module_data.scope.collect_resolutions().len(), 1);
130 }); 130 });
131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events) 131 assert!(!format!("{:?}", events).contains("crate_def_map"), "{:#?}", events)
132 } 132 }
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs
index 704065633..d104f5993 100644
--- a/crates/ra_hir_def/src/nameres/tests/macros.rs
+++ b/crates/ra_hir_def/src/nameres/tests/macros.rs
@@ -600,3 +600,27 @@ fn macro_dollar_crate_is_correct_in_indirect_deps() {
600 â‹®bar: t v 600 â‹®bar: t v
601 "###); 601 "###);
602} 602}
603
604#[test]
605fn expand_derive() {
606 let map = compute_crate_def_map(
607 "
608 //- /main.rs
609 #[derive(Clone)]
610 struct Foo;
611 ",
612 );
613 assert_eq!(map.modules[map.root].scope.impls().len(), 1);
614}
615
616#[test]
617fn expand_multiple_derive() {
618 let map = compute_crate_def_map(
619 "
620 //- /main.rs
621 #[derive(Copy, Clone)]
622 struct Foo;
623 ",
624 );
625 assert_eq!(map.modules[map.root].scope.impls().len(), 2);
626}
diff --git a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
index e11530062..e800cc68e 100644
--- a/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
+++ b/crates/ra_hir_def/src/nameres/tests/mod_resolution.rs
@@ -668,7 +668,7 @@ fn unresolved_module_diagnostics() {
668 module: LocalModuleId( 668 module: LocalModuleId(
669 0, 669 0,
670 ), 670 ),
671 declaration: AstId { 671 declaration: InFile {
672 file_id: HirFileId( 672 file_id: HirFileId(
673 FileId( 673 FileId(
674 FileId( 674 FileId(
@@ -676,7 +676,7 @@ fn unresolved_module_diagnostics() {
676 ), 676 ),
677 ), 677 ),
678 ), 678 ),
679 file_ast_id: FileAstId { 679 value: FileAstId {
680 raw: ErasedFileAstId( 680 raw: ErasedFileAstId(
681 1, 681 1,
682 ), 682 ),
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs
index 6810a26db..8e1294201 100644
--- a/crates/ra_hir_def/src/path.rs
+++ b/crates/ra_hir_def/src/path.rs
@@ -1,35 +1,97 @@
1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`. 1//! A desugared representation of paths like `crate::foo` or `<Type as Trait>::bar`.
2mod lower;
2 3
3use std::{iter, sync::Arc}; 4use std::{iter, sync::Arc};
4 5
5use hir_expand::{ 6use hir_expand::{
6 either::Either,
7 hygiene::Hygiene, 7 hygiene::Hygiene,
8 name::{self, AsName, Name}, 8 name::{AsName, Name},
9}; 9};
10use ra_db::CrateId; 10use ra_db::CrateId;
11use ra_syntax::{ 11use ra_syntax::ast;
12 ast::{self, NameOwner, TypeAscriptionOwner},
13 AstNode,
14};
15 12
16use crate::{type_ref::TypeRef, Source}; 13use crate::{type_ref::TypeRef, InFile};
17 14
18#[derive(Debug, Clone, PartialEq, Eq, Hash)] 15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
19pub struct Path { 16pub struct ModPath {
20 pub kind: PathKind, 17 pub kind: PathKind,
21 pub segments: Vec<PathSegment>, 18 pub segments: Vec<Name>,
22} 19}
23 20
24#[derive(Debug, Clone, PartialEq, Eq, Hash)] 21#[derive(Debug, Clone, PartialEq, Eq, Hash)]
25pub struct PathSegment { 22pub enum PathKind {
26 pub name: Name, 23 Plain,
27 pub args_and_bindings: Option<Arc<GenericArgs>>, 24 /// `self::` is `Super(0)`
25 Super(u8),
26 Crate,
27 /// Absolute path (::foo)
28 Abs,
29 /// `$crate` from macro expansion
30 DollarCrate(CrateId),
31}
32
33impl ModPath {
34 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
35 lower::lower_path(path, hygiene).map(|it| it.mod_path)
36 }
37
38 pub fn from_simple_segments(
39 kind: PathKind,
40 segments: impl IntoIterator<Item = Name>,
41 ) -> ModPath {
42 let segments = segments.into_iter().collect::<Vec<_>>();
43 ModPath { kind, segments }
44 }
45
46 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> ModPath {
47 name_ref.as_name().into()
48 }
49
50 /// Converts an `tt::Ident` into a single-identifier `Path`.
51 pub(crate) fn from_tt_ident(ident: &tt::Ident) -> ModPath {
52 ident.as_name().into()
53 }
54
55 /// Calls `cb` with all paths, represented by this use item.
56 pub(crate) fn expand_use_item(
57 item_src: InFile<ast::UseItem>,
58 hygiene: &Hygiene,
59 mut cb: impl FnMut(ModPath, &ast::UseTree, /* is_glob */ bool, Option<Name>),
60 ) {
61 if let Some(tree) = item_src.value.use_tree() {
62 lower::lower_use_tree(None, tree, hygiene, &mut cb);
63 }
64 }
65
66 pub fn is_ident(&self) -> bool {
67 self.kind == PathKind::Plain && self.segments.len() == 1
68 }
69
70 pub fn is_self(&self) -> bool {
71 self.kind == PathKind::Super(0) && self.segments.is_empty()
72 }
73
74 /// If this path is a single identifier, like `foo`, return its name.
75 pub fn as_ident(&self) -> Option<&Name> {
76 if self.kind != PathKind::Plain || self.segments.len() > 1 {
77 return None;
78 }
79 self.segments.first()
80 }
81}
82
83#[derive(Debug, Clone, PartialEq, Eq, Hash)]
84pub struct Path {
85 /// Type based path like `<T>::foo`.
86 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
87 type_anchor: Option<Box<TypeRef>>,
88 mod_path: ModPath,
89 /// Invariant: the same len as self.path.segments
90 generic_args: Vec<Option<Arc<GenericArgs>>>,
28} 91}
29 92
30/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This 93/// Generic arguments to a path segment (e.g. the `i32` in `Option<i32>`). This
31/// can (in the future) also include bindings of associated types, like in 94/// also includes bindings of associated types, like in `Iterator<Item = Foo>`.
32/// `Iterator<Item = Foo>`.
33#[derive(Debug, Clone, PartialEq, Eq, Hash)] 95#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub struct GenericArgs { 96pub struct GenericArgs {
35 pub args: Vec<GenericArg>, 97 pub args: Vec<GenericArg>,
@@ -50,234 +112,111 @@ pub enum GenericArg {
50 // or lifetime... 112 // or lifetime...
51} 113}
52 114
53#[derive(Debug, Clone, PartialEq, Eq, Hash)]
54pub enum PathKind {
55 Plain,
56 Self_,
57 Super,
58 Crate,
59 // Absolute path
60 Abs,
61 // Type based path like `<T>::foo`
62 Type(Box<TypeRef>),
63 // `$crate` from macro expansion
64 DollarCrate(CrateId),
65}
66
67impl Path { 115impl Path {
68 /// Calls `cb` with all paths, represented by this use item.
69 pub(crate) fn expand_use_item(
70 item_src: Source<ast::UseItem>,
71 hygiene: &Hygiene,
72 mut cb: impl FnMut(Path, &ast::UseTree, bool, Option<Name>),
73 ) {
74 if let Some(tree) = item_src.value.use_tree() {
75 expand_use_tree(None, tree, hygiene, &mut cb);
76 }
77 }
78
79 pub(crate) fn from_simple_segments(
80 kind: PathKind,
81 segments: impl IntoIterator<Item = Name>,
82 ) -> Path {
83 Path {
84 kind,
85 segments: segments
86 .into_iter()
87 .map(|name| PathSegment { name, args_and_bindings: None })
88 .collect(),
89 }
90 }
91
92 /// Converts an `ast::Path` to `Path`. Works with use trees. 116 /// Converts an `ast::Path` to `Path`. Works with use trees.
93 /// DEPRECATED: It does not handle `$crate` from macro call. 117 /// DEPRECATED: It does not handle `$crate` from macro call.
94 pub fn from_ast(path: ast::Path) -> Option<Path> { 118 pub fn from_ast(path: ast::Path) -> Option<Path> {
95 Path::from_src(path, &Hygiene::new_unhygienic()) 119 lower::lower_path(path, &Hygiene::new_unhygienic())
96 } 120 }
97 121
98 /// Converts an `ast::Path` to `Path`. Works with use trees. 122 /// Converts an `ast::Path` to `Path`. Works with use trees.
99 /// It correctly handles `$crate` based path from macro call. 123 /// It correctly handles `$crate` based path from macro call.
100 pub fn from_src(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 124 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
101 let mut kind = PathKind::Plain; 125 lower::lower_path(path, hygiene)
102 let mut segments = Vec::new();
103 loop {
104 let segment = path.segment()?;
105
106 if segment.has_colon_colon() {
107 kind = PathKind::Abs;
108 }
109
110 match segment.kind()? {
111 ast::PathSegmentKind::Name(name_ref) => {
112 // FIXME: this should just return name
113 match hygiene.name_ref_to_name(name_ref) {
114 Either::A(name) => {
115 let args = segment
116 .type_arg_list()
117 .and_then(GenericArgs::from_ast)
118 .or_else(|| {
119 GenericArgs::from_fn_like_path_ast(
120 segment.param_list(),
121 segment.ret_type(),
122 )
123 })
124 .map(Arc::new);
125 let segment = PathSegment { name, args_and_bindings: args };
126 segments.push(segment);
127 }
128 Either::B(crate_id) => {
129 kind = PathKind::DollarCrate(crate_id);
130 break;
131 }
132 }
133 }
134 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
135 assert!(path.qualifier().is_none()); // this can only occur at the first segment
136
137 let self_type = TypeRef::from_ast(type_ref?);
138
139 match trait_ref {
140 // <T>::foo
141 None => {
142 kind = PathKind::Type(Box::new(self_type));
143 }
144 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
145 Some(trait_ref) => {
146 let path = Path::from_src(trait_ref.path()?, hygiene)?;
147 kind = path.kind;
148 let mut prefix_segments = path.segments;
149 prefix_segments.reverse();
150 segments.extend(prefix_segments);
151 // Insert the type reference (T in the above example) as Self parameter for the trait
152 let mut last_segment = segments.last_mut()?;
153 if last_segment.args_and_bindings.is_none() {
154 last_segment.args_and_bindings =
155 Some(Arc::new(GenericArgs::empty()));
156 };
157 let args = last_segment.args_and_bindings.as_mut().unwrap();
158 let mut args_inner = Arc::make_mut(args);
159 args_inner.has_self_type = true;
160 args_inner.args.insert(0, GenericArg::Type(self_type));
161 }
162 }
163 }
164 ast::PathSegmentKind::CrateKw => {
165 kind = PathKind::Crate;
166 break;
167 }
168 ast::PathSegmentKind::SelfKw => {
169 kind = PathKind::Self_;
170 break;
171 }
172 ast::PathSegmentKind::SuperKw => {
173 kind = PathKind::Super;
174 break;
175 }
176 }
177 path = match qualifier(&path) {
178 Some(it) => it,
179 None => break,
180 };
181 }
182 segments.reverse();
183 return Some(Path { kind, segments });
184
185 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
186 if let Some(q) = path.qualifier() {
187 return Some(q);
188 }
189 // FIXME: this bottom up traversal is not too precise.
190 // Should we handle do a top-down analysis, recording results?
191 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
192 let use_tree = use_tree_list.parent_use_tree();
193 use_tree.path()
194 }
195 } 126 }
196 127
197 /// Converts an `ast::NameRef` into a single-identifier `Path`. 128 /// Converts an `ast::NameRef` into a single-identifier `Path`.
198 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path { 129 pub(crate) fn from_name_ref(name_ref: &ast::NameRef) -> Path {
199 name_ref.as_name().into() 130 Path { type_anchor: None, mod_path: name_ref.as_name().into(), generic_args: vec![None] }
200 } 131 }
201 132
202 /// `true` is this path is a single identifier, like `foo` 133 pub fn kind(&self) -> &PathKind {
203 pub fn is_ident(&self) -> bool { 134 &self.mod_path.kind
204 self.kind == PathKind::Plain && self.segments.len() == 1
205 } 135 }
206 136
207 /// `true` if this path is just a standalone `self` 137 pub fn type_anchor(&self) -> Option<&TypeRef> {
208 pub fn is_self(&self) -> bool { 138 self.type_anchor.as_deref()
209 self.kind == PathKind::Self_ && self.segments.is_empty()
210 } 139 }
211 140
212 /// If this path is a single identifier, like `foo`, return its name. 141 pub fn segments(&self) -> PathSegments<'_> {
213 pub fn as_ident(&self) -> Option<&Name> { 142 PathSegments {
214 if self.kind != PathKind::Plain || self.segments.len() > 1 { 143 segments: self.mod_path.segments.as_slice(),
215 return None; 144 generic_args: self.generic_args.as_slice(),
216 } 145 }
217 self.segments.first().map(|s| &s.name)
218 } 146 }
219 147
220 pub fn expand_macro_expr(&self) -> Option<Name> { 148 pub fn mod_path(&self) -> &ModPath {
221 self.as_ident().and_then(|name| Some(name.clone())) 149 &self.mod_path
222 } 150 }
223 151
224 pub fn is_type_relative(&self) -> bool { 152 pub fn qualifier(&self) -> Option<Path> {
225 match self.kind { 153 if self.mod_path.is_ident() {
226 PathKind::Type(_) => true, 154 return None;
227 _ => false,
228 } 155 }
156 let res = Path {
157 type_anchor: self.type_anchor.clone(),
158 mod_path: ModPath {
159 kind: self.mod_path.kind.clone(),
160 segments: self.mod_path.segments[..self.mod_path.segments.len() - 1].to_vec(),
161 },
162 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
163 };
164 Some(res)
229 } 165 }
230} 166}
231 167
232impl GenericArgs { 168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
233 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { 169pub struct PathSegment<'a> {
234 let mut args = Vec::new(); 170 pub name: &'a Name,
235 for type_arg in node.type_args() { 171 pub args_and_bindings: Option<&'a GenericArgs>,
236 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 172}
237 args.push(GenericArg::Type(type_ref)); 173
238 } 174pub struct PathSegments<'a> {
239 // lifetimes ignored for now 175 segments: &'a [Name],
240 let mut bindings = Vec::new(); 176 generic_args: &'a [Option<Arc<GenericArgs>>],
241 for assoc_type_arg in node.assoc_type_args() { 177}
242 if let Some(name_ref) = assoc_type_arg.name_ref() { 178
243 let name = name_ref.as_name(); 179impl<'a> PathSegments<'a> {
244 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref()); 180 pub const EMPTY: PathSegments<'static> = PathSegments { segments: &[], generic_args: &[] };
245 bindings.push((name, type_ref)); 181 pub fn is_empty(&self) -> bool {
246 } 182 self.len() == 0
247 } 183 }
248 if args.is_empty() && bindings.is_empty() { 184 pub fn len(&self) -> usize {
249 None 185 self.segments.len()
250 } else { 186 }
251 Some(GenericArgs { args, has_self_type: false, bindings }) 187 pub fn first(&self) -> Option<PathSegment<'a>> {
252 } 188 self.get(0)
189 }
190 pub fn last(&self) -> Option<PathSegment<'a>> {
191 self.get(self.len().checked_sub(1)?)
192 }
193 pub fn get(&self, idx: usize) -> Option<PathSegment<'a>> {
194 assert_eq!(self.segments.len(), self.generic_args.len());
195 let res = PathSegment {
196 name: self.segments.get(idx)?,
197 args_and_bindings: self.generic_args.get(idx).unwrap().as_ref().map(|it| &**it),
198 };
199 Some(res)
200 }
201 pub fn skip(&self, len: usize) -> PathSegments<'a> {
202 assert_eq!(self.segments.len(), self.generic_args.len());
203 PathSegments { segments: &self.segments[len..], generic_args: &self.generic_args[len..] }
204 }
205 pub fn take(&self, len: usize) -> PathSegments<'a> {
206 assert_eq!(self.segments.len(), self.generic_args.len());
207 PathSegments { segments: &self.segments[..len], generic_args: &self.generic_args[..len] }
208 }
209 pub fn iter(&self) -> impl Iterator<Item = PathSegment<'a>> {
210 self.segments.iter().zip(self.generic_args.iter()).map(|(name, args)| PathSegment {
211 name,
212 args_and_bindings: args.as_ref().map(|it| &**it),
213 })
253 } 214 }
215}
254 216
255 /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) 217impl GenericArgs {
256 /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). 218 pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> {
257 pub(crate) fn from_fn_like_path_ast( 219 lower::lower_generic_args(node)
258 params: Option<ast::ParamList>,
259 ret_type: Option<ast::RetType>,
260 ) -> Option<GenericArgs> {
261 let mut args = Vec::new();
262 let mut bindings = Vec::new();
263 if let Some(params) = params {
264 let mut param_types = Vec::new();
265 for param in params.params() {
266 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
267 param_types.push(type_ref);
268 }
269 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
270 args.push(arg);
271 }
272 if let Some(ret_type) = ret_type {
273 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
274 bindings.push((name::OUTPUT_TYPE, type_ref))
275 }
276 if args.is_empty() && bindings.is_empty() {
277 None
278 } else {
279 Some(GenericArgs { args, has_self_type: false, bindings })
280 }
281 } 220 }
282 221
283 pub(crate) fn empty() -> GenericArgs { 222 pub(crate) fn empty() -> GenericArgs {
@@ -287,137 +226,51 @@ impl GenericArgs {
287 226
288impl From<Name> for Path { 227impl From<Name> for Path {
289 fn from(name: Name) -> Path { 228 fn from(name: Name) -> Path {
290 Path::from_simple_segments(PathKind::Plain, iter::once(name)) 229 Path {
230 type_anchor: None,
231 mod_path: ModPath::from_simple_segments(PathKind::Plain, iter::once(name)),
232 generic_args: vec![None],
233 }
291 } 234 }
292} 235}
293 236
294fn expand_use_tree( 237impl From<Name> for ModPath {
295 prefix: Option<Path>, 238 fn from(name: Name) -> ModPath {
296 tree: ast::UseTree, 239 ModPath::from_simple_segments(PathKind::Plain, iter::once(name))
297 hygiene: &Hygiene,
298 cb: &mut dyn FnMut(Path, &ast::UseTree, bool, Option<Name>),
299) {
300 if let Some(use_tree_list) = tree.use_tree_list() {
301 let prefix = match tree.path() {
302 // E.g. use something::{{{inner}}};
303 None => prefix,
304 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
305 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
306 Some(path) => match convert_path(prefix, path, hygiene) {
307 Some(it) => Some(it),
308 None => return, // FIXME: report errors somewhere
309 },
310 };
311 for child_tree in use_tree_list.use_trees() {
312 expand_use_tree(prefix.clone(), child_tree, hygiene, cb);
313 }
314 } else {
315 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
316 if let Some(ast_path) = tree.path() {
317 // Handle self in a path.
318 // E.g. `use something::{self, <...>}`
319 if ast_path.qualifier().is_none() {
320 if let Some(segment) = ast_path.segment() {
321 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
322 if let Some(prefix) = prefix {
323 cb(prefix, &tree, false, alias);
324 return;
325 }
326 }
327 }
328 }
329 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
330 let is_glob = tree.has_star();
331 cb(path, &tree, is_glob, alias)
332 }
333 // FIXME: report errors somewhere
334 // We get here if we do
335 }
336 } 240 }
337} 241}
338 242
339fn convert_path(prefix: Option<Path>, path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 243pub use hir_expand::name as __name;
340 let prefix = if let Some(qual) = path.qualifier() { 244
341 Some(convert_path(prefix, qual, hygiene)?) 245#[macro_export]
342 } else { 246macro_rules! __known_path {
343 prefix 247 (std::iter::IntoIterator) => {};
344 }; 248 (std::result::Result) => {};
345 249 (std::ops::Range) => {};
346 let segment = path.segment()?; 250 (std::ops::RangeFrom) => {};
347 let res = match segment.kind()? { 251 (std::ops::RangeFull) => {};
348 ast::PathSegmentKind::Name(name_ref) => { 252 (std::ops::RangeTo) => {};
349 match hygiene.name_ref_to_name(name_ref) { 253 (std::ops::RangeToInclusive) => {};
350 Either::A(name) => { 254 (std::ops::RangeInclusive) => {};
351 // no type args in use 255 (std::boxed::Box) => {};
352 let mut res = prefix.unwrap_or_else(|| Path { 256 (std::future::Future) => {};
353 kind: PathKind::Plain, 257 (std::ops::Try) => {};
354 segments: Vec::with_capacity(1), 258 (std::ops::Neg) => {};
355 }); 259 (std::ops::Not) => {};
356 res.segments.push(PathSegment { 260 (std::ops::Index) => {};
357 name, 261 ($path:path) => {
358 args_and_bindings: None, // no type args in use 262 compile_error!("Please register your known path in the path module")
359 });
360 res
361 }
362 Either::B(crate_id) => {
363 return Some(Path::from_simple_segments(
364 PathKind::DollarCrate(crate_id),
365 iter::empty(),
366 ))
367 }
368 }
369 }
370 ast::PathSegmentKind::CrateKw => {
371 if prefix.is_some() {
372 return None;
373 }
374 Path::from_simple_segments(PathKind::Crate, iter::empty())
375 }
376 ast::PathSegmentKind::SelfKw => {
377 if prefix.is_some() {
378 return None;
379 }
380 Path::from_simple_segments(PathKind::Self_, iter::empty())
381 }
382 ast::PathSegmentKind::SuperKw => {
383 if prefix.is_some() {
384 return None;
385 }
386 Path::from_simple_segments(PathKind::Super, iter::empty())
387 }
388 ast::PathSegmentKind::Type { .. } => {
389 // not allowed in imports
390 return None;
391 }
392 }; 263 };
393 Some(res)
394} 264}
395 265
396pub mod known { 266#[macro_export]
397 use hir_expand::name; 267macro_rules! __path {
398 268 ($start:ident $(:: $seg:ident)*) => ({
399 use super::{Path, PathKind}; 269 $crate::__known_path!($start $(:: $seg)*);
400 270 $crate::path::ModPath::from_simple_segments($crate::path::PathKind::Abs, vec![
401 pub fn std_iter_into_iterator() -> Path { 271 $crate::path::__name![$start], $($crate::path::__name![$seg],)*
402 Path::from_simple_segments( 272 ])
403 PathKind::Abs, 273 });
404 vec![name::STD, name::ITER, name::INTO_ITERATOR_TYPE],
405 )
406 }
407
408 pub fn std_ops_try() -> Path {
409 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::OPS, name::TRY_TYPE])
410 }
411
412 pub fn std_result_result() -> Path {
413 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::RESULT, name::RESULT_TYPE])
414 }
415
416 pub fn std_future_future() -> Path {
417 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::FUTURE, name::FUTURE_TYPE])
418 }
419
420 pub fn std_boxed_box() -> Path {
421 Path::from_simple_segments(PathKind::Abs, vec![name::STD, name::BOXED, name::BOX_TYPE])
422 }
423} 274}
275
276pub use crate::__path as path;
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs
new file mode 100644
index 000000000..62aafd508
--- /dev/null
+++ b/crates/ra_hir_def/src/path/lower.rs
@@ -0,0 +1,178 @@
1//! Transforms syntax into `Path` objects, ideally with accounting for hygiene
2
3mod lower_use;
4
5use std::sync::Arc;
6
7use either::Either;
8use hir_expand::{
9 hygiene::Hygiene,
10 name::{name, AsName},
11};
12use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner};
13
14use crate::{
15 path::{GenericArg, GenericArgs, ModPath, Path, PathKind},
16 type_ref::TypeRef,
17};
18
19pub(super) use lower_use::lower_use_tree;
20
21/// Converts an `ast::Path` to `Path`. Works with use trees.
22/// It correctly handles `$crate` based path from macro call.
23pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> {
24 let mut kind = PathKind::Plain;
25 let mut type_anchor = None;
26 let mut segments = Vec::new();
27 let mut generic_args = Vec::new();
28 loop {
29 let segment = path.segment()?;
30
31 if segment.has_colon_colon() {
32 kind = PathKind::Abs;
33 }
34
35 match segment.kind()? {
36 ast::PathSegmentKind::Name(name_ref) => {
37 // FIXME: this should just return name
38 match hygiene.name_ref_to_name(name_ref) {
39 Either::Left(name) => {
40 let args = segment
41 .type_arg_list()
42 .and_then(lower_generic_args)
43 .or_else(|| {
44 lower_generic_args_from_fn_path(
45 segment.param_list(),
46 segment.ret_type(),
47 )
48 })
49 .map(Arc::new);
50 segments.push(name);
51 generic_args.push(args)
52 }
53 Either::Right(crate_id) => {
54 kind = PathKind::DollarCrate(crate_id);
55 break;
56 }
57 }
58 }
59 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
60 assert!(path.qualifier().is_none()); // this can only occur at the first segment
61
62 let self_type = TypeRef::from_ast(type_ref?);
63
64 match trait_ref {
65 // <T>::foo
66 None => {
67 type_anchor = Some(Box::new(self_type));
68 kind = PathKind::Plain;
69 }
70 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
71 Some(trait_ref) => {
72 let path = Path::from_src(trait_ref.path()?, hygiene)?;
73 kind = path.mod_path.kind;
74
75 let mut prefix_segments = path.mod_path.segments;
76 prefix_segments.reverse();
77 segments.extend(prefix_segments);
78
79 let mut prefix_args = path.generic_args;
80 prefix_args.reverse();
81 generic_args.extend(prefix_args);
82
83 // Insert the type reference (T in the above example) as Self parameter for the trait
84 let last_segment = generic_args.last_mut()?;
85 if last_segment.is_none() {
86 *last_segment = Some(Arc::new(GenericArgs::empty()));
87 };
88 let args = last_segment.as_mut().unwrap();
89 let mut args_inner = Arc::make_mut(args);
90 args_inner.has_self_type = true;
91 args_inner.args.insert(0, GenericArg::Type(self_type));
92 }
93 }
94 }
95 ast::PathSegmentKind::CrateKw => {
96 kind = PathKind::Crate;
97 break;
98 }
99 ast::PathSegmentKind::SelfKw => {
100 kind = PathKind::Super(0);
101 break;
102 }
103 ast::PathSegmentKind::SuperKw => {
104 kind = PathKind::Super(1);
105 break;
106 }
107 }
108 path = match qualifier(&path) {
109 Some(it) => it,
110 None => break,
111 };
112 }
113 segments.reverse();
114 generic_args.reverse();
115 let mod_path = ModPath { kind, segments };
116 return Some(Path { type_anchor, mod_path, generic_args });
117
118 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
119 if let Some(q) = path.qualifier() {
120 return Some(q);
121 }
122 // FIXME: this bottom up traversal is not too precise.
123 // Should we handle do a top-down analysis, recording results?
124 let use_tree_list = path.syntax().ancestors().find_map(ast::UseTreeList::cast)?;
125 let use_tree = use_tree_list.parent_use_tree();
126 use_tree.path()
127 }
128}
129
130pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> {
131 let mut args = Vec::new();
132 for type_arg in node.type_args() {
133 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
134 args.push(GenericArg::Type(type_ref));
135 }
136 // lifetimes ignored for now
137 let mut bindings = Vec::new();
138 for assoc_type_arg in node.assoc_type_args() {
139 if let Some(name_ref) = assoc_type_arg.name_ref() {
140 let name = name_ref.as_name();
141 let type_ref = TypeRef::from_ast_opt(assoc_type_arg.type_ref());
142 bindings.push((name, type_ref));
143 }
144 }
145 if args.is_empty() && bindings.is_empty() {
146 None
147 } else {
148 Some(GenericArgs { args, has_self_type: false, bindings })
149 }
150}
151
152/// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y)
153/// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`).
154fn lower_generic_args_from_fn_path(
155 params: Option<ast::ParamList>,
156 ret_type: Option<ast::RetType>,
157) -> Option<GenericArgs> {
158 let mut args = Vec::new();
159 let mut bindings = Vec::new();
160 if let Some(params) = params {
161 let mut param_types = Vec::new();
162 for param in params.params() {
163 let type_ref = TypeRef::from_ast_opt(param.ascribed_type());
164 param_types.push(type_ref);
165 }
166 let arg = GenericArg::Type(TypeRef::Tuple(param_types));
167 args.push(arg);
168 }
169 if let Some(ret_type) = ret_type {
170 let type_ref = TypeRef::from_ast_opt(ret_type.type_ref());
171 bindings.push((name![Output], type_ref))
172 }
173 if args.is_empty() && bindings.is_empty() {
174 None
175 } else {
176 Some(GenericArgs { args, has_self_type: false, bindings })
177 }
178}
diff --git a/crates/ra_hir_def/src/path/lower/lower_use.rs b/crates/ra_hir_def/src/path/lower/lower_use.rs
new file mode 100644
index 000000000..3218eaf0a
--- /dev/null
+++ b/crates/ra_hir_def/src/path/lower/lower_use.rs
@@ -0,0 +1,118 @@
1//! Lowers a single complex use like `use foo::{bar, baz};` into a list of paths like
2//! `foo::bar`, `foo::baz`;
3
4use std::iter;
5
6use either::Either;
7use hir_expand::{
8 hygiene::Hygiene,
9 name::{AsName, Name},
10};
11use ra_syntax::ast::{self, NameOwner};
12use test_utils::tested_by;
13
14use crate::path::{ModPath, PathKind};
15
16pub(crate) fn lower_use_tree(
17 prefix: Option<ModPath>,
18 tree: ast::UseTree,
19 hygiene: &Hygiene,
20 cb: &mut dyn FnMut(ModPath, &ast::UseTree, bool, Option<Name>),
21) {
22 if let Some(use_tree_list) = tree.use_tree_list() {
23 let prefix = match tree.path() {
24 // E.g. use something::{{{inner}}};
25 None => prefix,
26 // E.g. `use something::{inner}` (prefix is `None`, path is `something`)
27 // or `use something::{path::{inner::{innerer}}}` (prefix is `something::path`, path is `inner`)
28 Some(path) => match convert_path(prefix, path, hygiene) {
29 Some(it) => Some(it),
30 None => return, // FIXME: report errors somewhere
31 },
32 };
33 for child_tree in use_tree_list.use_trees() {
34 lower_use_tree(prefix.clone(), child_tree, hygiene, cb);
35 }
36 } else {
37 let alias = tree.alias().and_then(|a| a.name()).map(|a| a.as_name());
38 let is_glob = tree.has_star();
39 if let Some(ast_path) = tree.path() {
40 // Handle self in a path.
41 // E.g. `use something::{self, <...>}`
42 if ast_path.qualifier().is_none() {
43 if let Some(segment) = ast_path.segment() {
44 if segment.kind() == Some(ast::PathSegmentKind::SelfKw) {
45 if let Some(prefix) = prefix {
46 cb(prefix, &tree, false, alias);
47 return;
48 }
49 }
50 }
51 }
52 if let Some(path) = convert_path(prefix, ast_path, hygiene) {
53 cb(path, &tree, is_glob, alias)
54 }
55 // FIXME: report errors somewhere
56 // We get here if we do
57 } else if is_glob {
58 tested_by!(glob_enum_group);
59 if let Some(prefix) = prefix {
60 cb(prefix, &tree, is_glob, None)
61 }
62 }
63 }
64}
65
66fn convert_path(prefix: Option<ModPath>, path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
67 let prefix = if let Some(qual) = path.qualifier() {
68 Some(convert_path(prefix, qual, hygiene)?)
69 } else {
70 prefix
71 };
72
73 let segment = path.segment()?;
74 let res = match segment.kind()? {
75 ast::PathSegmentKind::Name(name_ref) => {
76 match hygiene.name_ref_to_name(name_ref) {
77 Either::Left(name) => {
78 // no type args in use
79 let mut res = prefix.unwrap_or_else(|| ModPath {
80 kind: PathKind::Plain,
81 segments: Vec::with_capacity(1),
82 });
83 res.segments.push(name);
84 res
85 }
86 Either::Right(crate_id) => {
87 return Some(ModPath::from_simple_segments(
88 PathKind::DollarCrate(crate_id),
89 iter::empty(),
90 ))
91 }
92 }
93 }
94 ast::PathSegmentKind::CrateKw => {
95 if prefix.is_some() {
96 return None;
97 }
98 ModPath::from_simple_segments(PathKind::Crate, iter::empty())
99 }
100 ast::PathSegmentKind::SelfKw => {
101 if prefix.is_some() {
102 return None;
103 }
104 ModPath::from_simple_segments(PathKind::Super(0), iter::empty())
105 }
106 ast::PathSegmentKind::SuperKw => {
107 if prefix.is_some() {
108 return None;
109 }
110 ModPath::from_simple_segments(PathKind::Super(1), iter::empty())
111 }
112 ast::PathSegmentKind::Type { .. } => {
113 // not allowed in imports
114 return None;
115 }
116 };
117 Some(res)
118}
diff --git a/crates/ra_hir_def/src/per_ns.rs b/crates/ra_hir_def/src/per_ns.rs
index 00e866bf9..3a5105028 100644
--- a/crates/ra_hir_def/src/per_ns.rs
+++ b/crates/ra_hir_def/src/per_ns.rs
@@ -11,8 +11,6 @@ use crate::ModuleDefId;
11pub struct PerNs { 11pub struct PerNs {
12 pub types: Option<ModuleDefId>, 12 pub types: Option<ModuleDefId>,
13 pub values: Option<ModuleDefId>, 13 pub values: Option<ModuleDefId>,
14 /// Since macros has different type, many methods simply ignore it.
15 /// We can only use special method like `get_macros` to access it.
16 pub macros: Option<MacroDefId>, 14 pub macros: Option<MacroDefId>,
17} 15}
18 16
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index 0847f6dcf..cf3c33d78 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -2,7 +2,7 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use hir_expand::{ 4use hir_expand::{
5 name::{self, Name}, 5 name::{name, Name},
6 MacroDefId, 6 MacroDefId,
7}; 7};
8use ra_db::CrateId; 8use ra_db::CrateId;
@@ -10,20 +10,23 @@ use rustc_hash::FxHashSet;
10 10
11use crate::{ 11use crate::{
12 body::scope::{ExprScopes, ScopeId}, 12 body::scope::{ExprScopes, ScopeId},
13 body::Body,
13 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
14 db::DefDatabase, 15 db::DefDatabase,
15 expr::{ExprId, PatId}, 16 expr::{ExprId, PatId},
16 generics::GenericParams, 17 generics::GenericParams,
18 item_scope::BuiltinShadowMode,
17 nameres::CrateDefMap, 19 nameres::CrateDefMap,
18 path::{Path, PathKind}, 20 path::{ModPath, PathKind},
19 per_ns::PerNs, 21 per_ns::PerNs,
20 AdtId, AstItemDef, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, 22 AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId,
21 GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, 23 FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
22 StructId, TraitId, TypeAliasId, 24 StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
23}; 25};
24 26
25#[derive(Debug, Clone, Default)] 27#[derive(Debug, Clone, Default)]
26pub struct Resolver { 28pub struct Resolver {
29 // FIXME: all usages generally call `.rev`, so maybe reverse once in consturciton?
27 scopes: Vec<Scope>, 30 scopes: Vec<Scope>,
28} 31}
29 32
@@ -53,12 +56,14 @@ enum Scope {
53 AdtScope(AdtId), 56 AdtScope(AdtId),
54 /// Local bindings 57 /// Local bindings
55 ExprScope(ExprScope), 58 ExprScope(ExprScope),
59 /// Temporary hack to support local items.
60 LocalItemsScope(Arc<Body>),
56} 61}
57 62
58#[derive(Debug, Clone, PartialEq, Eq, Hash)] 63#[derive(Debug, Clone, PartialEq, Eq, Hash)]
59pub enum TypeNs { 64pub enum TypeNs {
60 SelfType(ImplId), 65 SelfType(ImplId),
61 GenericParam(u32), 66 GenericParam(TypeParamId),
62 AdtId(AdtId), 67 AdtId(AdtId),
63 AdtSelfType(AdtId), 68 AdtSelfType(AdtId),
64 // Yup, enum variants are added to the types ns, but any usage of variant as 69 // Yup, enum variants are added to the types ns, but any usage of variant as
@@ -90,8 +95,8 @@ pub enum ValueNs {
90 95
91impl Resolver { 96impl Resolver {
92 /// Resolve known trait from std, like `std::futures::Future` 97 /// Resolve known trait from std, like `std::futures::Future`
93 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &Path) -> Option<TraitId> { 98 pub fn resolve_known_trait(&self, db: &impl DefDatabase, path: &ModPath) -> Option<TraitId> {
94 let res = self.resolve_module_path(db, path).take_types()?; 99 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
95 match res { 100 match res {
96 ModuleDefId::TraitId(it) => Some(it), 101 ModuleDefId::TraitId(it) => Some(it),
97 _ => None, 102 _ => None,
@@ -99,8 +104,8 @@ impl Resolver {
99 } 104 }
100 105
101 /// Resolve known struct from std, like `std::boxed::Box` 106 /// Resolve known struct from std, like `std::boxed::Box`
102 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &Path) -> Option<StructId> { 107 pub fn resolve_known_struct(&self, db: &impl DefDatabase, path: &ModPath) -> Option<StructId> {
103 let res = self.resolve_module_path(db, path).take_types()?; 108 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
104 match res { 109 match res {
105 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it), 110 ModuleDefId::AdtId(AdtId::StructId(it)) => Some(it),
106 _ => None, 111 _ => None,
@@ -108,87 +113,116 @@ impl Resolver {
108 } 113 }
109 114
110 /// Resolve known enum from std, like `std::result::Result` 115 /// Resolve known enum from std, like `std::result::Result`
111 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &Path) -> Option<EnumId> { 116 pub fn resolve_known_enum(&self, db: &impl DefDatabase, path: &ModPath) -> Option<EnumId> {
112 let res = self.resolve_module_path(db, path).take_types()?; 117 let res = self.resolve_module_path(db, path, BuiltinShadowMode::Other).take_types()?;
113 match res { 118 match res {
114 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it), 119 ModuleDefId::AdtId(AdtId::EnumId(it)) => Some(it),
115 _ => None, 120 _ => None,
116 } 121 }
117 } 122 }
118 123
119 /// pub only for source-binder 124 fn resolve_module_path(
120 pub fn resolve_module_path(&self, db: &impl DefDatabase, path: &Path) -> PerNs { 125 &self,
126 db: &impl DefDatabase,
127 path: &ModPath,
128 shadow: BuiltinShadowMode,
129 ) -> PerNs {
121 let (item_map, module) = match self.module() { 130 let (item_map, module) = match self.module() {
122 Some(it) => it, 131 Some(it) => it,
123 None => return PerNs::none(), 132 None => return PerNs::none(),
124 }; 133 };
125 let (module_res, segment_index) = item_map.resolve_path(db, module, path); 134 let (module_res, segment_index) = item_map.resolve_path(db, module, &path, shadow);
126 if segment_index.is_some() { 135 if segment_index.is_some() {
127 return PerNs::none(); 136 return PerNs::none();
128 } 137 }
129 module_res 138 module_res
130 } 139 }
131 140
141 pub fn resolve_module_path_in_items(&self, db: &impl DefDatabase, path: &ModPath) -> PerNs {
142 self.resolve_module_path(db, path, BuiltinShadowMode::Module)
143 }
144
132 pub fn resolve_path_in_type_ns( 145 pub fn resolve_path_in_type_ns(
133 &self, 146 &self,
134 db: &impl DefDatabase, 147 db: &impl DefDatabase,
135 path: &Path, 148 path: &ModPath,
136 ) -> Option<(TypeNs, Option<usize>)> { 149 ) -> Option<(TypeNs, Option<usize>)> {
137 if path.is_type_relative() { 150 let first_name = path.segments.first()?;
138 return None;
139 }
140 let first_name = &path.segments.first()?.name;
141 let skip_to_mod = path.kind != PathKind::Plain; 151 let skip_to_mod = path.kind != PathKind::Plain;
142 for scope in self.scopes.iter().rev() { 152 for scope in self.scopes.iter().rev() {
143 match scope { 153 match scope {
144 Scope::ExprScope(_) => continue, 154 Scope::ExprScope(_) => continue,
145 Scope::GenericParams { .. } | Scope::ImplBlockScope(_) if skip_to_mod => continue, 155 Scope::GenericParams { .. }
156 | Scope::ImplBlockScope(_)
157 | Scope::LocalItemsScope(_)
158 if skip_to_mod =>
159 {
160 continue
161 }
146 162
147 Scope::GenericParams { params, .. } => { 163 Scope::GenericParams { params, def } => {
148 if let Some(param) = params.find_by_name(first_name) { 164 if let Some(local_id) = params.find_by_name(first_name) {
149 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 165 let idx = if path.segments.len() == 1 { None } else { Some(1) };
150 return Some((TypeNs::GenericParam(param.idx), idx)); 166 return Some((
167 TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
168 idx,
169 ));
151 } 170 }
152 } 171 }
153 Scope::ImplBlockScope(impl_) => { 172 Scope::ImplBlockScope(impl_) => {
154 if first_name == &name::SELF_TYPE { 173 if first_name == &name![Self] {
155 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 174 let idx = if path.segments.len() == 1 { None } else { Some(1) };
156 return Some((TypeNs::SelfType(*impl_), idx)); 175 return Some((TypeNs::SelfType(*impl_), idx));
157 } 176 }
158 } 177 }
159 Scope::AdtScope(adt) => { 178 Scope::AdtScope(adt) => {
160 if first_name == &name::SELF_TYPE { 179 if first_name == &name![Self] {
161 let idx = if path.segments.len() == 1 { None } else { Some(1) }; 180 let idx = if path.segments.len() == 1 { None } else { Some(1) };
162 return Some((TypeNs::AdtSelfType(*adt), idx)); 181 return Some((TypeNs::AdtSelfType(*adt), idx));
163 } 182 }
164 } 183 }
165 Scope::ModuleScope(m) => { 184 Scope::ModuleScope(m) => {
166 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 185 let (module_def, idx) = m.crate_def_map.resolve_path(
167 let res = match module_def.take_types()? { 186 db,
168 ModuleDefId::AdtId(it) => TypeNs::AdtId(it), 187 m.module_id,
169 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it), 188 &path,
170 189 BuiltinShadowMode::Other,
171 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it), 190 );
172 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it), 191 let res = to_type_ns(module_def)?;
173
174 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
175
176 ModuleDefId::FunctionId(_)
177 | ModuleDefId::ConstId(_)
178 | ModuleDefId::StaticId(_)
179 | ModuleDefId::ModuleId(_) => return None,
180 };
181 return Some((res, idx)); 192 return Some((res, idx));
182 } 193 }
194 Scope::LocalItemsScope(body) => {
195 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
196 if let Some(res) = to_type_ns(def) {
197 return Some((res, None));
198 }
199 }
183 } 200 }
184 } 201 }
185 None 202 return None;
203 fn to_type_ns(per_ns: PerNs) -> Option<TypeNs> {
204 let res = match per_ns.take_types()? {
205 ModuleDefId::AdtId(it) => TypeNs::AdtId(it),
206 ModuleDefId::EnumVariantId(it) => TypeNs::EnumVariantId(it),
207
208 ModuleDefId::TypeAliasId(it) => TypeNs::TypeAliasId(it),
209 ModuleDefId::BuiltinType(it) => TypeNs::BuiltinType(it),
210
211 ModuleDefId::TraitId(it) => TypeNs::TraitId(it),
212
213 ModuleDefId::FunctionId(_)
214 | ModuleDefId::ConstId(_)
215 | ModuleDefId::StaticId(_)
216 | ModuleDefId::ModuleId(_) => return None,
217 };
218 Some(res)
219 }
186 } 220 }
187 221
188 pub fn resolve_path_in_type_ns_fully( 222 pub fn resolve_path_in_type_ns_fully(
189 &self, 223 &self,
190 db: &impl DefDatabase, 224 db: &impl DefDatabase,
191 path: &Path, 225 path: &ModPath,
192 ) -> Option<TypeNs> { 226 ) -> Option<TypeNs> {
193 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?; 227 let (res, unresolved) = self.resolve_path_in_type_ns(db, path)?;
194 if unresolved.is_some() { 228 if unresolved.is_some() {
@@ -197,17 +231,14 @@ impl Resolver {
197 Some(res) 231 Some(res)
198 } 232 }
199 233
200 pub fn resolve_path_in_value_ns<'p>( 234 pub fn resolve_path_in_value_ns(
201 &self, 235 &self,
202 db: &impl DefDatabase, 236 db: &impl DefDatabase,
203 path: &'p Path, 237 path: &ModPath,
204 ) -> Option<ResolveValueResult> { 238 ) -> Option<ResolveValueResult> {
205 if path.is_type_relative() {
206 return None;
207 }
208 let n_segments = path.segments.len(); 239 let n_segments = path.segments.len();
209 let tmp = name::SELF_PARAM; 240 let tmp = name![self];
210 let first_name = if path.is_self() { &tmp } else { &path.segments.first()?.name }; 241 let first_name = if path.is_self() { &tmp } else { &path.segments.first()? };
211 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self(); 242 let skip_to_mod = path.kind != PathKind::Plain && !path.is_self();
212 for scope in self.scopes.iter().rev() { 243 for scope in self.scopes.iter().rev() {
213 match scope { 244 match scope {
@@ -215,6 +246,7 @@ impl Resolver {
215 | Scope::ExprScope(_) 246 | Scope::ExprScope(_)
216 | Scope::GenericParams { .. } 247 | Scope::GenericParams { .. }
217 | Scope::ImplBlockScope(_) 248 | Scope::ImplBlockScope(_)
249 | Scope::LocalItemsScope(_)
218 if skip_to_mod => 250 if skip_to_mod =>
219 { 251 {
220 continue 252 continue
@@ -233,22 +265,22 @@ impl Resolver {
233 } 265 }
234 Scope::ExprScope(_) => continue, 266 Scope::ExprScope(_) => continue,
235 267
236 Scope::GenericParams { params, .. } if n_segments > 1 => { 268 Scope::GenericParams { params, def } if n_segments > 1 => {
237 if let Some(param) = params.find_by_name(first_name) { 269 if let Some(local_id) = params.find_by_name(first_name) {
238 let ty = TypeNs::GenericParam(param.idx); 270 let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
239 return Some(ResolveValueResult::Partial(ty, 1)); 271 return Some(ResolveValueResult::Partial(ty, 1));
240 } 272 }
241 } 273 }
242 Scope::GenericParams { .. } => continue, 274 Scope::GenericParams { .. } => continue,
243 275
244 Scope::ImplBlockScope(impl_) if n_segments > 1 => { 276 Scope::ImplBlockScope(impl_) if n_segments > 1 => {
245 if first_name == &name::SELF_TYPE { 277 if first_name == &name![Self] {
246 let ty = TypeNs::SelfType(*impl_); 278 let ty = TypeNs::SelfType(*impl_);
247 return Some(ResolveValueResult::Partial(ty, 1)); 279 return Some(ResolveValueResult::Partial(ty, 1));
248 } 280 }
249 } 281 }
250 Scope::AdtScope(adt) if n_segments > 1 => { 282 Scope::AdtScope(adt) if n_segments > 1 => {
251 if first_name == &name::SELF_TYPE { 283 if first_name == &name![Self] {
252 let ty = TypeNs::AdtSelfType(*adt); 284 let ty = TypeNs::AdtSelfType(*adt);
253 return Some(ResolveValueResult::Partial(ty, 1)); 285 return Some(ResolveValueResult::Partial(ty, 1));
254 } 286 }
@@ -256,23 +288,15 @@ impl Resolver {
256 Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue, 288 Scope::ImplBlockScope(_) | Scope::AdtScope(_) => continue,
257 289
258 Scope::ModuleScope(m) => { 290 Scope::ModuleScope(m) => {
259 let (module_def, idx) = m.crate_def_map.resolve_path(db, m.module_id, path); 291 let (module_def, idx) = m.crate_def_map.resolve_path(
292 db,
293 m.module_id,
294 &path,
295 BuiltinShadowMode::Other,
296 );
260 return match idx { 297 return match idx {
261 None => { 298 None => {
262 let value = match module_def.take_values()? { 299 let value = to_value_ns(module_def)?;
263 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
264 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
265 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
266 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
267 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
268
269 ModuleDefId::AdtId(AdtId::EnumId(_))
270 | ModuleDefId::AdtId(AdtId::UnionId(_))
271 | ModuleDefId::TraitId(_)
272 | ModuleDefId::TypeAliasId(_)
273 | ModuleDefId::BuiltinType(_)
274 | ModuleDefId::ModuleId(_) => return None,
275 };
276 Some(ResolveValueResult::ValueNs(value)) 300 Some(ResolveValueResult::ValueNs(value))
277 } 301 }
278 Some(idx) => { 302 Some(idx) => {
@@ -292,15 +316,39 @@ impl Resolver {
292 } 316 }
293 }; 317 };
294 } 318 }
319 Scope::LocalItemsScope(body) => {
320 let def = body.item_scope.get(first_name, BuiltinShadowMode::Other);
321 if let Some(res) = to_value_ns(def) {
322 return Some(ResolveValueResult::ValueNs(res));
323 }
324 }
295 } 325 }
296 } 326 }
297 None 327 return None;
328
329 fn to_value_ns(per_ns: PerNs) -> Option<ValueNs> {
330 let res = match per_ns.take_values()? {
331 ModuleDefId::FunctionId(it) => ValueNs::FunctionId(it),
332 ModuleDefId::AdtId(AdtId::StructId(it)) => ValueNs::StructId(it),
333 ModuleDefId::EnumVariantId(it) => ValueNs::EnumVariantId(it),
334 ModuleDefId::ConstId(it) => ValueNs::ConstId(it),
335 ModuleDefId::StaticId(it) => ValueNs::StaticId(it),
336
337 ModuleDefId::AdtId(AdtId::EnumId(_))
338 | ModuleDefId::AdtId(AdtId::UnionId(_))
339 | ModuleDefId::TraitId(_)
340 | ModuleDefId::TypeAliasId(_)
341 | ModuleDefId::BuiltinType(_)
342 | ModuleDefId::ModuleId(_) => return None,
343 };
344 Some(res)
345 }
298 } 346 }
299 347
300 pub fn resolve_path_in_value_ns_fully( 348 pub fn resolve_path_in_value_ns_fully(
301 &self, 349 &self,
302 db: &impl DefDatabase, 350 db: &impl DefDatabase,
303 path: &Path, 351 path: &ModPath,
304 ) -> Option<ValueNs> { 352 ) -> Option<ValueNs> {
305 match self.resolve_path_in_value_ns(db, path)? { 353 match self.resolve_path_in_value_ns(db, path)? {
306 ResolveValueResult::ValueNs(it) => Some(it), 354 ResolveValueResult::ValueNs(it) => Some(it),
@@ -308,9 +356,13 @@ impl Resolver {
308 } 356 }
309 } 357 }
310 358
311 pub fn resolve_path_as_macro(&self, db: &impl DefDatabase, path: &Path) -> Option<MacroDefId> { 359 pub fn resolve_path_as_macro(
360 &self,
361 db: &impl DefDatabase,
362 path: &ModPath,
363 ) -> Option<MacroDefId> {
312 let (item_map, module) = self.module()?; 364 let (item_map, module) = self.module()?;
313 item_map.resolve_path(db, module, path).0.take_macros() 365 item_map.resolve_path(db, module, &path, BuiltinShadowMode::Other).0.take_macros()
314 } 366 }
315 367
316 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) { 368 pub fn process_all_names(&self, db: &impl DefDatabase, f: &mut dyn FnMut(Name, ScopeDef)) {
@@ -350,6 +402,7 @@ impl Resolver {
350 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a { 402 ) -> impl Iterator<Item = &'a crate::generics::WherePredicate> + 'a {
351 self.scopes 403 self.scopes
352 .iter() 404 .iter()
405 .rev()
353 .filter_map(|scope| match scope { 406 .filter_map(|scope| match scope {
354 Scope::GenericParams { params, .. } => Some(params), 407 Scope::GenericParams { params, .. } => Some(params),
355 _ => None, 408 _ => None,
@@ -358,14 +411,14 @@ impl Resolver {
358 } 411 }
359 412
360 pub fn generic_def(&self) -> Option<GenericDefId> { 413 pub fn generic_def(&self) -> Option<GenericDefId> {
361 self.scopes.iter().find_map(|scope| match scope { 414 self.scopes.iter().rev().find_map(|scope| match scope {
362 Scope::GenericParams { def, .. } => Some(*def), 415 Scope::GenericParams { def, .. } => Some(*def),
363 _ => None, 416 _ => None,
364 }) 417 })
365 } 418 }
366 419
367 pub fn body_owner(&self) -> Option<DefWithBodyId> { 420 pub fn body_owner(&self) -> Option<DefWithBodyId> {
368 self.scopes.iter().find_map(|scope| match scope { 421 self.scopes.iter().rev().find_map(|scope| match scope {
369 Scope::ExprScope(it) => Some(it.owner), 422 Scope::ExprScope(it) => Some(it.owner),
370 _ => None, 423 _ => None,
371 }) 424 })
@@ -376,7 +429,7 @@ pub enum ScopeDef {
376 PerNs(PerNs), 429 PerNs(PerNs),
377 ImplSelfType(ImplId), 430 ImplSelfType(ImplId),
378 AdtSelfType(AdtId), 431 AdtSelfType(AdtId),
379 GenericParam(u32), 432 GenericParam(TypeParamId),
380 Local(PatId), 433 Local(PatId),
381} 434}
382 435
@@ -391,8 +444,8 @@ impl Scope {
391 // def: m.module.into(), 444 // def: m.module.into(),
392 // }), 445 // }),
393 // ); 446 // );
394 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, res)| { 447 m.crate_def_map[m.module_id].scope.entries().for_each(|(name, def)| {
395 f(name.clone(), ScopeDef::PerNs(res.def)); 448 f(name.clone(), ScopeDef::PerNs(def));
396 }); 449 });
397 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| { 450 m.crate_def_map[m.module_id].scope.legacy_macros().for_each(|(name, macro_)| {
398 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_))); 451 f(name.clone(), ScopeDef::PerNs(PerNs::macros(macro_)));
@@ -402,21 +455,29 @@ impl Scope {
402 }); 455 });
403 if let Some(prelude) = m.crate_def_map.prelude { 456 if let Some(prelude) = m.crate_def_map.prelude {
404 let prelude_def_map = db.crate_def_map(prelude.krate); 457 let prelude_def_map = db.crate_def_map(prelude.krate);
405 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, res)| { 458 prelude_def_map[prelude.local_id].scope.entries().for_each(|(name, def)| {
406 f(name.clone(), ScopeDef::PerNs(res.def)); 459 f(name.clone(), ScopeDef::PerNs(def));
407 }); 460 });
408 } 461 }
409 } 462 }
410 Scope::GenericParams { params, .. } => { 463 Scope::LocalItemsScope(body) => {
411 for param in params.params.iter() { 464 body.item_scope.entries_without_primitives().for_each(|(name, def)| {
412 f(param.name.clone(), ScopeDef::GenericParam(param.idx)) 465 f(name.clone(), ScopeDef::PerNs(def));
466 })
467 }
468 Scope::GenericParams { params, def } => {
469 for (local_id, param) in params.types.iter() {
470 f(
471 param.name.clone(),
472 ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
473 )
413 } 474 }
414 } 475 }
415 Scope::ImplBlockScope(i) => { 476 Scope::ImplBlockScope(i) => {
416 f(name::SELF_TYPE, ScopeDef::ImplSelfType((*i).into())); 477 f(name![Self], ScopeDef::ImplSelfType((*i).into()));
417 } 478 }
418 Scope::AdtScope(i) => { 479 Scope::AdtScope(i) => {
419 f(name::SELF_TYPE, ScopeDef::AdtSelfType((*i).into())); 480 f(name![Self], ScopeDef::AdtSelfType((*i).into()));
420 } 481 }
421 Scope::ExprScope(scope) => { 482 Scope::ExprScope(scope) => {
422 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| { 483 scope.expr_scopes.entries(scope.scope_id).iter().for_each(|e| {
@@ -439,6 +500,7 @@ pub fn resolver_for_scope(
439 scope_id: Option<ScopeId>, 500 scope_id: Option<ScopeId>,
440) -> Resolver { 501) -> Resolver {
441 let mut r = owner.resolver(db); 502 let mut r = owner.resolver(db);
503 r = r.push_local_items_scope(db.body(owner));
442 let scopes = db.expr_scopes(owner); 504 let scopes = db.expr_scopes(owner);
443 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>(); 505 let scope_chain = scopes.scope_chain(scope_id).collect::<Vec<_>>();
444 for scope in scope_chain.into_iter().rev() { 506 for scope in scope_chain.into_iter().rev() {
@@ -455,7 +517,7 @@ impl Resolver {
455 517
456 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver { 518 fn push_generic_params_scope(self, db: &impl DefDatabase, def: GenericDefId) -> Resolver {
457 let params = db.generic_params(def); 519 let params = db.generic_params(def);
458 if params.params.is_empty() { 520 if params.types.is_empty() {
459 self 521 self
460 } else { 522 } else {
461 self.push_scope(Scope::GenericParams { def, params }) 523 self.push_scope(Scope::GenericParams { def, params })
@@ -474,6 +536,10 @@ impl Resolver {
474 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id })) 536 self.push_scope(Scope::ModuleScope(ModuleItemMap { crate_def_map, module_id }))
475 } 537 }
476 538
539 fn push_local_items_scope(self, body: Arc<Body>) -> Resolver {
540 self.push_scope(Scope::LocalItemsScope(body))
541 }
542
477 fn push_expr_scope( 543 fn push_expr_scope(
478 self, 544 self,
479 owner: DefWithBodyId, 545 owner: DefWithBodyId,
@@ -498,7 +564,7 @@ impl HasResolver for ModuleId {
498 564
499impl HasResolver for TraitId { 565impl HasResolver for TraitId {
500 fn resolver(self, db: &impl DefDatabase) -> Resolver { 566 fn resolver(self, db: &impl DefDatabase) -> Resolver {
501 self.module(db).resolver(db).push_generic_params_scope(db, self.into()) 567 self.lookup(db).container.resolver(db).push_generic_params_scope(db, self.into())
502 } 568 }
503} 569}
504 570
@@ -518,16 +584,6 @@ impl HasResolver for FunctionId {
518 } 584 }
519} 585}
520 586
521impl HasResolver for DefWithBodyId {
522 fn resolver(self, db: &impl DefDatabase) -> Resolver {
523 match self {
524 DefWithBodyId::ConstId(c) => c.resolver(db),
525 DefWithBodyId::FunctionId(f) => f.resolver(db),
526 DefWithBodyId::StaticId(s) => s.resolver(db),
527 }
528 }
529}
530
531impl HasResolver for ConstId { 587impl HasResolver for ConstId {
532 fn resolver(self, db: &impl DefDatabase) -> Resolver { 588 fn resolver(self, db: &impl DefDatabase) -> Resolver {
533 self.lookup(db).container.resolver(db) 589 self.lookup(db).container.resolver(db)
@@ -546,12 +602,41 @@ impl HasResolver for TypeAliasId {
546 } 602 }
547} 603}
548 604
605impl HasResolver for ImplId {
606 fn resolver(self, db: &impl DefDatabase) -> Resolver {
607 self.lookup(db)
608 .container
609 .resolver(db)
610 .push_generic_params_scope(db, self.into())
611 .push_impl_block_scope(self)
612 }
613}
614
615impl HasResolver for DefWithBodyId {
616 fn resolver(self, db: &impl DefDatabase) -> Resolver {
617 match self {
618 DefWithBodyId::ConstId(c) => c.resolver(db),
619 DefWithBodyId::FunctionId(f) => f.resolver(db),
620 DefWithBodyId::StaticId(s) => s.resolver(db),
621 }
622 }
623}
624
549impl HasResolver for ContainerId { 625impl HasResolver for ContainerId {
550 fn resolver(self, db: &impl DefDatabase) -> Resolver { 626 fn resolver(self, db: &impl DefDatabase) -> Resolver {
551 match self { 627 match self {
552 ContainerId::TraitId(it) => it.resolver(db),
553 ContainerId::ImplId(it) => it.resolver(db),
554 ContainerId::ModuleId(it) => it.resolver(db), 628 ContainerId::ModuleId(it) => it.resolver(db),
629 ContainerId::DefWithBodyId(it) => it.resolver(db),
630 }
631 }
632}
633
634impl HasResolver for AssocContainerId {
635 fn resolver(self, db: &impl DefDatabase) -> Resolver {
636 match self {
637 AssocContainerId::ContainerId(it) => it.resolver(db),
638 AssocContainerId::TraitId(it) => it.resolver(db),
639 AssocContainerId::ImplId(it) => it.resolver(db),
555 } 640 }
556 } 641 }
557} 642}
@@ -570,11 +655,12 @@ impl HasResolver for GenericDefId {
570 } 655 }
571} 656}
572 657
573impl HasResolver for ImplId { 658impl HasResolver for VariantId {
574 fn resolver(self, db: &impl DefDatabase) -> Resolver { 659 fn resolver(self, db: &impl DefDatabase) -> Resolver {
575 self.module(db) 660 match self {
576 .resolver(db) 661 VariantId::EnumVariantId(it) => it.parent.resolver(db),
577 .push_generic_params_scope(db, self.into()) 662 VariantId::StructId(it) => it.resolver(db),
578 .push_impl_block_scope(self) 663 VariantId::UnionId(it) => it.resolver(db),
664 }
579 } 665 }
580} 666}
diff --git a/crates/ra_hir_def/src/src.rs b/crates/ra_hir_def/src/src.rs
new file mode 100644
index 000000000..499375b80
--- /dev/null
+++ b/crates/ra_hir_def/src/src.rs
@@ -0,0 +1,36 @@
1//! Utilities for mapping between hir IDs and the surface syntax.
2
3use hir_expand::InFile;
4use ra_arena::map::ArenaMap;
5use ra_syntax::AstNode;
6
7use crate::{db::DefDatabase, AssocItemLoc, ItemLoc};
8
9pub trait HasSource {
10 type Value;
11 fn source(&self, db: &impl DefDatabase) -> InFile<Self::Value>;
12}
13
14impl<N: AstNode> HasSource for AssocItemLoc<N> {
15 type Value = N;
16
17 fn source(&self, db: &impl DefDatabase) -> InFile<N> {
18 let node = self.ast_id.to_node(db);
19 InFile::new(self.ast_id.file_id, node)
20 }
21}
22
23impl<N: AstNode> HasSource for ItemLoc<N> {
24 type Value = N;
25
26 fn source(&self, db: &impl DefDatabase) -> InFile<N> {
27 let node = self.ast_id.to_node(db);
28 InFile::new(self.ast_id.file_id, node)
29 }
30}
31
32pub trait HasChildSource {
33 type ChildId;
34 type Value;
35 fn child_source(&self, db: &impl DefDatabase) -> InFile<ArenaMap<Self::ChildId, Self::Value>>;
36}
diff --git a/crates/ra_hir_def/src/trace.rs b/crates/ra_hir_def/src/trace.rs
index 2bcd707bc..9769e88df 100644
--- a/crates/ra_hir_def/src/trace.rs
+++ b/crates/ra_hir_def/src/trace.rs
@@ -18,10 +18,6 @@ pub(crate) struct Trace<ID: ArenaId, T, V> {
18} 18}
19 19
20impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> { 20impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> {
21 pub(crate) fn new() -> Trace<ID, T, V> {
22 Trace { arena: Some(Arena::default()), map: Some(ArenaMap::default()), len: 0 }
23 }
24
25 pub(crate) fn new_for_arena() -> Trace<ID, T, V> { 21 pub(crate) fn new_for_arena() -> Trace<ID, T, V> {
26 Trace { arena: Some(Arena::default()), map: None, len: 0 } 22 Trace { arena: Some(Arena::default()), map: None, len: 0 }
27 } 23 }
@@ -52,8 +48,4 @@ impl<ID: ra_arena::ArenaId + Copy, T, V> Trace<ID, T, V> {
52 pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> { 48 pub(crate) fn into_map(mut self) -> ArenaMap<ID, V> {
53 self.map.take().unwrap() 49 self.map.take().unwrap()
54 } 50 }
55
56 pub(crate) fn into_arena_and_map(mut self) -> (Arena<ID, T>, ArenaMap<ID, V>) {
57 (self.arena.take().unwrap(), self.map.take().unwrap())
58 }
59} 51}
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml
index c60152a79..3ae4376dc 100644
--- a/crates/ra_hir_expand/Cargo.toml
+++ b/crates/ra_hir_expand/Cargo.toml
@@ -9,6 +9,7 @@ doctest = false
9 9
10[dependencies] 10[dependencies]
11log = "0.4.5" 11log = "0.4.5"
12either = "1.5"
12 13
13ra_arena = { path = "../ra_arena" } 14ra_arena = { path = "../ra_arena" }
14ra_db = { path = "../ra_db" } 15ra_db = { path = "../ra_db" }
diff --git a/crates/ra_hir_expand/src/ast_id_map.rs b/crates/ra_hir_expand/src/ast_id_map.rs
index cb464c3ff..a764bdf24 100644
--- a/crates/ra_hir_expand/src/ast_id_map.rs
+++ b/crates/ra_hir_expand/src/ast_id_map.rs
@@ -39,6 +39,16 @@ impl<N: AstNode> Hash for FileAstId<N> {
39 } 39 }
40} 40}
41 41
42impl<N: AstNode> FileAstId<N> {
43 // Can't make this a From implementation because of coherence
44 pub fn upcast<M: AstNode>(self) -> FileAstId<M>
45 where
46 M: From<N>,
47 {
48 FileAstId { raw: self.raw, _ty: PhantomData }
49 }
50}
51
42#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] 52#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43struct ErasedFileAstId(RawId); 53struct ErasedFileAstId(RawId);
44impl_arena_id!(ErasedFileAstId); 54impl_arena_id!(ErasedFileAstId);
@@ -53,7 +63,7 @@ impl AstIdMap {
53 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap { 63 pub(crate) fn from_source(node: &SyntaxNode) -> AstIdMap {
54 assert!(node.parent().is_none()); 64 assert!(node.parent().is_none());
55 let mut res = AstIdMap { arena: Arena::default() }; 65 let mut res = AstIdMap { arena: Arena::default() };
56 // By walking the tree in bread-first order we make sure that parents 66 // By walking the tree in breadth-first order we make sure that parents
57 // get lower ids then children. That is, adding a new child does not 67 // get lower ids then children. That is, adding a new child does not
58 // change parent's id. This means that, say, adding a new function to a 68 // change parent's id. This means that, say, adding a new function to a
59 // trait does not change ids of top-level items, which helps caching. 69 // trait does not change ids of top-level items, which helps caching.
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs
new file mode 100644
index 000000000..62c60e336
--- /dev/null
+++ b/crates/ra_hir_expand/src/builtin_derive.rs
@@ -0,0 +1,321 @@
1//! Builtin derives.
2
3use log::debug;
4
5use ra_parser::FragmentKind;
6use ra_syntax::{
7 ast::{self, AstNode, ModuleItemOwner, NameOwner, TypeParamsOwner},
8 match_ast,
9};
10
11use crate::db::AstDatabase;
12use crate::{name, quote, MacroCallId, MacroDefId, MacroDefKind};
13
14macro_rules! register_builtin {
15 ( $($trait:ident => $expand:ident),* ) => {
16 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
17 pub enum BuiltinDeriveExpander {
18 $($trait),*
19 }
20
21 impl BuiltinDeriveExpander {
22 pub fn expand(
23 &self,
24 db: &dyn AstDatabase,
25 id: MacroCallId,
26 tt: &tt::Subtree,
27 ) -> Result<tt::Subtree, mbe::ExpandError> {
28 let expander = match *self {
29 $( BuiltinDeriveExpander::$trait => $expand, )*
30 };
31 expander(db, id, tt)
32 }
33 }
34
35 pub fn find_builtin_derive(ident: &name::Name) -> Option<MacroDefId> {
36 let kind = match ident {
37 $( id if id == &name::name![$trait] => BuiltinDeriveExpander::$trait, )*
38 _ => return None,
39 };
40
41 Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) })
42 }
43 };
44}
45
46register_builtin! {
47 Copy => copy_expand,
48 Clone => clone_expand,
49 Default => default_expand,
50 Debug => debug_expand,
51 Hash => hash_expand,
52 Ord => ord_expand,
53 PartialOrd => partial_ord_expand,
54 Eq => eq_expand,
55 PartialEq => partial_eq_expand
56}
57
58struct BasicAdtInfo {
59 name: tt::Ident,
60 type_params: usize,
61}
62
63fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, mbe::ExpandError> {
64 let (parsed, token_map) = mbe::token_tree_to_syntax_node(tt, FragmentKind::Items)?; // FragmentKind::Items doesn't parse attrs?
65 let macro_items = ast::MacroItems::cast(parsed.syntax_node()).ok_or_else(|| {
66 debug!("derive node didn't parse");
67 mbe::ExpandError::UnexpectedToken
68 })?;
69 let item = macro_items.items().next().ok_or_else(|| {
70 debug!("no module item parsed");
71 mbe::ExpandError::NoMatchingRule
72 })?;
73 let node = item.syntax();
74 let (name, params) = match_ast! {
75 match node {
76 ast::StructDef(it) => { (it.name(), it.type_param_list()) },
77 ast::EnumDef(it) => { (it.name(), it.type_param_list()) },
78 ast::UnionDef(it) => { (it.name(), it.type_param_list()) },
79 _ => {
80 debug!("unexpected node is {:?}", node);
81 return Err(mbe::ExpandError::ConversionError)
82 },
83 }
84 };
85 let name = name.ok_or_else(|| {
86 debug!("parsed item has no name");
87 mbe::ExpandError::NoMatchingRule
88 })?;
89 let name_token_id = token_map.token_by_range(name.syntax().text_range()).ok_or_else(|| {
90 debug!("name token not found");
91 mbe::ExpandError::ConversionError
92 })?;
93 let name_token = tt::Ident { id: name_token_id, text: name.text().clone() };
94 let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
95 Ok(BasicAdtInfo { name: name_token, type_params })
96}
97
98fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
99 let mut result = Vec::<tt::TokenTree>::new();
100 result.push(
101 tt::Leaf::Punct(tt::Punct {
102 char: '<',
103 spacing: tt::Spacing::Alone,
104 id: tt::TokenId::unspecified(),
105 })
106 .into(),
107 );
108 for i in 0..n {
109 if i > 0 {
110 result.push(
111 tt::Leaf::Punct(tt::Punct {
112 char: ',',
113 spacing: tt::Spacing::Alone,
114 id: tt::TokenId::unspecified(),
115 })
116 .into(),
117 );
118 }
119 result.push(
120 tt::Leaf::Ident(tt::Ident {
121 id: tt::TokenId::unspecified(),
122 text: format!("T{}", i).into(),
123 })
124 .into(),
125 );
126 result.extend(bound.iter().cloned());
127 }
128 result.push(
129 tt::Leaf::Punct(tt::Punct {
130 char: '>',
131 spacing: tt::Spacing::Alone,
132 id: tt::TokenId::unspecified(),
133 })
134 .into(),
135 );
136 result
137}
138
139fn expand_simple_derive(
140 tt: &tt::Subtree,
141 trait_path: tt::Subtree,
142) -> Result<tt::Subtree, mbe::ExpandError> {
143 let info = parse_adt(tt)?;
144 let name = info.name;
145 let trait_path_clone = trait_path.token_trees.clone();
146 let bound = (quote! { : ##trait_path_clone }).token_trees;
147 let type_params = make_type_args(info.type_params, bound);
148 let type_args = make_type_args(info.type_params, Vec::new());
149 let trait_path = trait_path.token_trees;
150 let expanded = quote! {
151 impl ##type_params ##trait_path for #name ##type_args {}
152 };
153 Ok(expanded)
154}
155
156fn copy_expand(
157 _db: &dyn AstDatabase,
158 _id: MacroCallId,
159 tt: &tt::Subtree,
160) -> Result<tt::Subtree, mbe::ExpandError> {
161 expand_simple_derive(tt, quote! { std::marker::Copy })
162}
163
164fn clone_expand(
165 _db: &dyn AstDatabase,
166 _id: MacroCallId,
167 tt: &tt::Subtree,
168) -> Result<tt::Subtree, mbe::ExpandError> {
169 expand_simple_derive(tt, quote! { std::clone::Clone })
170}
171
172fn default_expand(
173 _db: &dyn AstDatabase,
174 _id: MacroCallId,
175 tt: &tt::Subtree,
176) -> Result<tt::Subtree, mbe::ExpandError> {
177 expand_simple_derive(tt, quote! { std::default::Default })
178}
179
180fn debug_expand(
181 _db: &dyn AstDatabase,
182 _id: MacroCallId,
183 tt: &tt::Subtree,
184) -> Result<tt::Subtree, mbe::ExpandError> {
185 expand_simple_derive(tt, quote! { std::fmt::Debug })
186}
187
188fn hash_expand(
189 _db: &dyn AstDatabase,
190 _id: MacroCallId,
191 tt: &tt::Subtree,
192) -> Result<tt::Subtree, mbe::ExpandError> {
193 expand_simple_derive(tt, quote! { std::hash::Hash })
194}
195
196fn eq_expand(
197 _db: &dyn AstDatabase,
198 _id: MacroCallId,
199 tt: &tt::Subtree,
200) -> Result<tt::Subtree, mbe::ExpandError> {
201 expand_simple_derive(tt, quote! { std::cmp::Eq })
202}
203
204fn partial_eq_expand(
205 _db: &dyn AstDatabase,
206 _id: MacroCallId,
207 tt: &tt::Subtree,
208) -> Result<tt::Subtree, mbe::ExpandError> {
209 expand_simple_derive(tt, quote! { std::cmp::PartialEq })
210}
211
212fn ord_expand(
213 _db: &dyn AstDatabase,
214 _id: MacroCallId,
215 tt: &tt::Subtree,
216) -> Result<tt::Subtree, mbe::ExpandError> {
217 expand_simple_derive(tt, quote! { std::cmp::Ord })
218}
219
220fn partial_ord_expand(
221 _db: &dyn AstDatabase,
222 _id: MacroCallId,
223 tt: &tt::Subtree,
224) -> Result<tt::Subtree, mbe::ExpandError> {
225 expand_simple_derive(tt, quote! { std::cmp::PartialOrd })
226}
227
228#[cfg(test)]
229mod tests {
230 use super::*;
231 use crate::{test_db::TestDB, AstId, MacroCallKind, MacroCallLoc};
232 use ra_db::{fixture::WithFixture, SourceDatabase};
233
234 fn expand_builtin_derive(s: &str, expander: BuiltinDeriveExpander) -> String {
235 let (db, file_id) = TestDB::with_single_file(&s);
236 let parsed = db.parse(file_id);
237 let items: Vec<_> =
238 parsed.syntax_node().descendants().filter_map(|it| ast::ModuleItem::cast(it)).collect();
239
240 let ast_id_map = db.ast_id_map(file_id.into());
241
242 // the first one should be a macro_rules
243 let def =
244 MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(expander) };
245
246 let loc = MacroCallLoc {
247 def,
248 kind: MacroCallKind::Attr(AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]))),
249 };
250
251 let id = db.intern_macro(loc);
252 let parsed = db.parse_or_expand(id.as_file()).unwrap();
253
254 // FIXME text() for syntax nodes parsed from token tree looks weird
255 // because there's no whitespace, see below
256 parsed.text().to_string()
257 }
258
259 #[test]
260 fn test_copy_expand_simple() {
261 let expanded = expand_builtin_derive(
262 r#"
263 #[derive(Copy)]
264 struct Foo;
265"#,
266 BuiltinDeriveExpander::Copy,
267 );
268
269 assert_eq!(expanded, "impl <>std::marker::CopyforFoo <>{}");
270 }
271
272 #[test]
273 fn test_copy_expand_with_type_params() {
274 let expanded = expand_builtin_derive(
275 r#"
276 #[derive(Copy)]
277 struct Foo<A, B>;
278"#,
279 BuiltinDeriveExpander::Copy,
280 );
281
282 assert_eq!(
283 expanded,
284 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
285 );
286 }
287
288 #[test]
289 fn test_copy_expand_with_lifetimes() {
290 let expanded = expand_builtin_derive(
291 r#"
292 #[derive(Copy)]
293 struct Foo<A, B, 'a, 'b>;
294"#,
295 BuiltinDeriveExpander::Copy,
296 );
297
298 // We currently just ignore lifetimes
299
300 assert_eq!(
301 expanded,
302 "impl<T0:std::marker::Copy,T1:std::marker::Copy>std::marker::CopyforFoo<T0,T1>{}"
303 );
304 }
305
306 #[test]
307 fn test_clone_expand() {
308 let expanded = expand_builtin_derive(
309 r#"
310 #[derive(Clone)]
311 struct Foo<A, B>;
312"#,
313 BuiltinDeriveExpander::Clone,
314 );
315
316 assert_eq!(
317 expanded,
318 "impl<T0:std::clone::Clone,T1:std::clone::Clone>std::clone::CloneforFoo<T0,T1>{}"
319 );
320 }
321}
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs
index d370dfb34..2c119269c 100644
--- a/crates/ra_hir_expand/src/builtin_macro.rs
+++ b/crates/ra_hir_expand/src/builtin_macro.rs
@@ -2,8 +2,7 @@
2use crate::db::AstDatabase; 2use crate::db::AstDatabase;
3use crate::{ 3use crate::{
4 ast::{self, AstNode}, 4 ast::{self, AstNode},
5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, MacroFileKind, 5 name, AstId, CrateId, HirFileId, MacroCallId, MacroDefId, MacroDefKind, TextUnit,
6 TextUnit,
7}; 6};
8 7
9use crate::quote; 8use crate::quote;
@@ -27,6 +26,13 @@ macro_rules! register_builtin {
27 }; 26 };
28 expander(db, id, tt) 27 expander(db, id, tt)
29 } 28 }
29
30 fn by_name(ident: &name::Name) -> Option<BuiltinFnLikeExpander> {
31 match ident {
32 $( id if id == &name::name![$name] => Some(BuiltinFnLikeExpander::$kind), )*
33 _ => return None,
34 }
35 }
30 } 36 }
31 37
32 pub fn find_builtin_macro( 38 pub fn find_builtin_macro(
@@ -34,22 +40,25 @@ macro_rules! register_builtin {
34 krate: CrateId, 40 krate: CrateId,
35 ast_id: AstId<ast::MacroCall>, 41 ast_id: AstId<ast::MacroCall>,
36 ) -> Option<MacroDefId> { 42 ) -> Option<MacroDefId> {
37 let kind = match ident { 43 let kind = BuiltinFnLikeExpander::by_name(ident)?;
38 $( id if id == &name::$name => BuiltinFnLikeExpander::$kind, )*
39 _ => return None,
40 };
41 44
42 Some(MacroDefId { krate, ast_id, kind: MacroDefKind::BuiltIn(kind) }) 45 Some(MacroDefId { krate: Some(krate), ast_id: Some(ast_id), kind: MacroDefKind::BuiltIn(kind) })
43 } 46 }
44 }; 47 };
45} 48}
46 49
47register_builtin! { 50register_builtin! {
48 (COLUMN_MACRO, Column) => column_expand, 51 (column, Column) => column_expand,
49 (COMPILE_ERROR_MACRO, CompileError) => compile_error_expand, 52 (compile_error, CompileError) => compile_error_expand,
50 (FILE_MACRO, File) => file_expand, 53 (file, File) => file_expand,
51 (LINE_MACRO, Line) => line_expand, 54 (line, Line) => line_expand,
52 (STRINGIFY_MACRO, Stringify) => stringify_expand 55 (stringify, Stringify) => stringify_expand,
56 (format_args, FormatArgs) => format_args_expand,
57 (env, Env) => env_expand,
58 (option_env, OptionEnv) => option_env_expand,
59 // format_args_nl only differs in that it adds a newline in the end,
60 // so we use the same stub expansion for now
61 (format_args_nl, FormatArgsNl) => format_args_expand
53} 62}
54 63
55fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 64fn to_line_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
@@ -82,12 +91,11 @@ fn line_expand(
82 _tt: &tt::Subtree, 91 _tt: &tt::Subtree,
83) -> Result<tt::Subtree, mbe::ExpandError> { 92) -> Result<tt::Subtree, mbe::ExpandError> {
84 let loc = db.lookup_intern_macro(id); 93 let loc = db.lookup_intern_macro(id);
85 let macro_call = loc.ast_id.to_node(db);
86 94
87 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 95 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
88 let arg_start = arg.syntax().text_range().start(); 96 let arg_start = arg.text_range().start();
89 97
90 let file = id.as_file(MacroFileKind::Expr); 98 let file = id.as_file();
91 let line_num = to_line_number(db, file, arg_start); 99 let line_num = to_line_number(db, file, arg_start);
92 100
93 let expanded = quote! { 101 let expanded = quote! {
@@ -103,11 +111,10 @@ fn stringify_expand(
103 _tt: &tt::Subtree, 111 _tt: &tt::Subtree,
104) -> Result<tt::Subtree, mbe::ExpandError> { 112) -> Result<tt::Subtree, mbe::ExpandError> {
105 let loc = db.lookup_intern_macro(id); 113 let loc = db.lookup_intern_macro(id);
106 let macro_call = loc.ast_id.to_node(db);
107 114
108 let macro_content = { 115 let macro_content = {
109 let arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 116 let arg = loc.kind.arg(db).ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
110 let macro_args = arg.syntax().clone(); 117 let macro_args = arg;
111 let text = macro_args.text(); 118 let text = macro_args.text();
112 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')'); 119 let without_parens = TextUnit::of_char('(')..text.len() - TextUnit::of_char(')');
113 text.slice(without_parens).to_string() 120 text.slice(without_parens).to_string()
@@ -120,6 +127,28 @@ fn stringify_expand(
120 Ok(expanded) 127 Ok(expanded)
121} 128}
122 129
130fn env_expand(
131 _db: &dyn AstDatabase,
132 _id: MacroCallId,
133 _tt: &tt::Subtree,
134) -> Result<tt::Subtree, mbe::ExpandError> {
135 // dummy implementation for type-checking purposes
136 let expanded = quote! { "" };
137
138 Ok(expanded)
139}
140
141fn option_env_expand(
142 _db: &dyn AstDatabase,
143 _id: MacroCallId,
144 _tt: &tt::Subtree,
145) -> Result<tt::Subtree, mbe::ExpandError> {
146 // dummy implementation for type-checking purposes
147 let expanded = quote! { std::option::Option::None::<&str> };
148
149 Ok(expanded)
150}
151
123fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize { 152fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize {
124 // FIXME: Use expansion info 153 // FIXME: Use expansion info
125 let file_id = file.original_file(db); 154 let file_id = file.original_file(db);
@@ -137,7 +166,7 @@ fn to_col_number(db: &dyn AstDatabase, file: HirFileId, pos: TextUnit) -> usize
137 if c == '\n' { 166 if c == '\n' {
138 break; 167 break;
139 } 168 }
140 col_num = col_num + 1; 169 col_num += 1;
141 } 170 }
142 col_num 171 col_num
143} 172}
@@ -148,12 +177,15 @@ fn column_expand(
148 _tt: &tt::Subtree, 177 _tt: &tt::Subtree,
149) -> Result<tt::Subtree, mbe::ExpandError> { 178) -> Result<tt::Subtree, mbe::ExpandError> {
150 let loc = db.lookup_intern_macro(id); 179 let loc = db.lookup_intern_macro(id);
151 let macro_call = loc.ast_id.to_node(db); 180 let macro_call = match loc.kind {
181 crate::MacroCallKind::FnLike(ast_id) => ast_id.to_node(db),
182 _ => panic!("column macro called as attr"),
183 };
152 184
153 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?; 185 let _arg = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
154 let col_start = macro_call.syntax().text_range().start(); 186 let col_start = macro_call.syntax().text_range().start();
155 187
156 let file = id.as_file(MacroFileKind::Expr); 188 let file = id.as_file();
157 let col_num = to_col_number(db, file, col_start); 189 let col_num = to_col_number(db, file, col_start);
158 190
159 let expanded = quote! { 191 let expanded = quote! {
@@ -164,15 +196,10 @@ fn column_expand(
164} 196}
165 197
166fn file_expand( 198fn file_expand(
167 db: &dyn AstDatabase, 199 _db: &dyn AstDatabase,
168 id: MacroCallId, 200 _id: MacroCallId,
169 _tt: &tt::Subtree, 201 _tt: &tt::Subtree,
170) -> Result<tt::Subtree, mbe::ExpandError> { 202) -> Result<tt::Subtree, mbe::ExpandError> {
171 let loc = db.lookup_intern_macro(id);
172 let macro_call = loc.ast_id.to_node(db);
173
174 let _ = macro_call.token_tree().ok_or_else(|| mbe::ExpandError::UnexpectedToken)?;
175
176 // FIXME: RA purposefully lacks knowledge of absolute file names 203 // FIXME: RA purposefully lacks knowledge of absolute file names
177 // so just return "". 204 // so just return "".
178 let file_name = ""; 205 let file_name = "";
@@ -204,13 +231,56 @@ fn compile_error_expand(
204 Err(mbe::ExpandError::BindingError("Must be a string".into())) 231 Err(mbe::ExpandError::BindingError("Must be a string".into()))
205} 232}
206 233
234fn format_args_expand(
235 _db: &dyn AstDatabase,
236 _id: MacroCallId,
237 tt: &tt::Subtree,
238) -> Result<tt::Subtree, mbe::ExpandError> {
239 // We expand `format_args!("", a1, a2)` to
240 // ```
241 // std::fmt::Arguments::new_v1(&[], &[
242 // std::fmt::ArgumentV1::new(&arg1,std::fmt::Display::fmt),
243 // std::fmt::ArgumentV1::new(&arg2,std::fmt::Display::fmt),
244 // ])
245 // ```,
246 // which is still not really correct, but close enough for now
247 let mut args = Vec::new();
248 let mut current = Vec::new();
249 for tt in tt.token_trees.iter().cloned() {
250 match tt {
251 tt::TokenTree::Leaf(tt::Leaf::Punct(p)) if p.char == ',' => {
252 args.push(current);
253 current = Vec::new();
254 }
255 _ => {
256 current.push(tt);
257 }
258 }
259 }
260 if !current.is_empty() {
261 args.push(current);
262 }
263 if args.is_empty() {
264 return Err(mbe::ExpandError::NoMatchingRule);
265 }
266 let _format_string = args.remove(0);
267 let arg_tts = args.into_iter().flat_map(|arg| {
268 quote! { std::fmt::ArgumentV1::new(&(##arg), std::fmt::Display::fmt), }
269 }.token_trees).collect::<Vec<_>>();
270 let expanded = quote! {
271 std::fmt::Arguments::new_v1(&[], &[##arg_tts])
272 };
273 Ok(expanded)
274}
275
207#[cfg(test)] 276#[cfg(test)]
208mod tests { 277mod tests {
209 use super::*; 278 use super::*;
210 use crate::{test_db::TestDB, MacroCallLoc}; 279 use crate::{name::AsName, test_db::TestDB, MacroCallKind, MacroCallLoc};
211 use ra_db::{fixture::WithFixture, SourceDatabase}; 280 use ra_db::{fixture::WithFixture, SourceDatabase};
281 use ra_syntax::ast::NameOwner;
212 282
213 fn expand_builtin_macro(s: &str, expander: BuiltinFnLikeExpander) -> String { 283 fn expand_builtin_macro(s: &str) -> String {
214 let (db, file_id) = TestDB::with_single_file(&s); 284 let (db, file_id) = TestDB::with_single_file(&s);
215 let parsed = db.parse(file_id); 285 let parsed = db.parse(file_id);
216 let macro_calls: Vec<_> = 286 let macro_calls: Vec<_> =
@@ -218,20 +288,26 @@ mod tests {
218 288
219 let ast_id_map = db.ast_id_map(file_id.into()); 289 let ast_id_map = db.ast_id_map(file_id.into());
220 290
291 let expander =
292 BuiltinFnLikeExpander::by_name(&macro_calls[0].name().unwrap().as_name()).unwrap();
293
221 // the first one should be a macro_rules 294 // the first one should be a macro_rules
222 let def = MacroDefId { 295 let def = MacroDefId {
223 krate: CrateId(0), 296 krate: Some(CrateId(0)),
224 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0])), 297 ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[0]))),
225 kind: MacroDefKind::BuiltIn(expander), 298 kind: MacroDefKind::BuiltIn(expander),
226 }; 299 };
227 300
228 let loc = MacroCallLoc { 301 let loc = MacroCallLoc {
229 def, 302 def,
230 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_calls[1])), 303 kind: MacroCallKind::FnLike(AstId::new(
304 file_id.into(),
305 ast_id_map.ast_id(&macro_calls[1]),
306 )),
231 }; 307 };
232 308
233 let id = db.intern_macro(loc); 309 let id = db.intern_macro(loc);
234 let parsed = db.parse_or_expand(id.as_file(MacroFileKind::Expr)).unwrap(); 310 let parsed = db.parse_or_expand(id.as_file()).unwrap();
235 311
236 parsed.text().to_string() 312 parsed.text().to_string()
237 } 313 }
@@ -240,25 +316,23 @@ mod tests {
240 fn test_column_expand() { 316 fn test_column_expand() {
241 let expanded = expand_builtin_macro( 317 let expanded = expand_builtin_macro(
242 r#" 318 r#"
243 #[rustc_builtin_macro] 319 #[rustc_builtin_macro]
244 macro_rules! column {() => {}} 320 macro_rules! column {() => {}}
245 column!() 321 column!()
246"#, 322 "#,
247 BuiltinFnLikeExpander::Column,
248 ); 323 );
249 324
250 assert_eq!(expanded, "9"); 325 assert_eq!(expanded, "13");
251 } 326 }
252 327
253 #[test] 328 #[test]
254 fn test_line_expand() { 329 fn test_line_expand() {
255 let expanded = expand_builtin_macro( 330 let expanded = expand_builtin_macro(
256 r#" 331 r#"
257 #[rustc_builtin_macro] 332 #[rustc_builtin_macro]
258 macro_rules! line {() => {}} 333 macro_rules! line {() => {}}
259 line!() 334 line!()
260"#, 335 "#,
261 BuiltinFnLikeExpander::Line,
262 ); 336 );
263 337
264 assert_eq!(expanded, "4"); 338 assert_eq!(expanded, "4");
@@ -268,25 +342,49 @@ mod tests {
268 fn test_stringify_expand() { 342 fn test_stringify_expand() {
269 let expanded = expand_builtin_macro( 343 let expanded = expand_builtin_macro(
270 r#" 344 r#"
271 #[rustc_builtin_macro] 345 #[rustc_builtin_macro]
272 macro_rules! stringify {() => {}} 346 macro_rules! stringify {() => {}}
273 stringify!(a b c) 347 stringify!(a b c)
274"#, 348 "#,
275 BuiltinFnLikeExpander::Stringify,
276 ); 349 );
277 350
278 assert_eq!(expanded, "\"a b c\""); 351 assert_eq!(expanded, "\"a b c\"");
279 } 352 }
280 353
281 #[test] 354 #[test]
355 fn test_env_expand() {
356 let expanded = expand_builtin_macro(
357 r#"
358 #[rustc_builtin_macro]
359 macro_rules! env {() => {}}
360 env!("TEST_ENV_VAR")
361 "#,
362 );
363
364 assert_eq!(expanded, "\"\"");
365 }
366
367 #[test]
368 fn test_option_env_expand() {
369 let expanded = expand_builtin_macro(
370 r#"
371 #[rustc_builtin_macro]
372 macro_rules! option_env {() => {}}
373 option_env!("TEST_ENV_VAR")
374 "#,
375 );
376
377 assert_eq!(expanded, "std::option::Option::None:: <&str>");
378 }
379
380 #[test]
282 fn test_file_expand() { 381 fn test_file_expand() {
283 let expanded = expand_builtin_macro( 382 let expanded = expand_builtin_macro(
284 r#" 383 r#"
285 #[rustc_builtin_macro] 384 #[rustc_builtin_macro]
286 macro_rules! file {() => {}} 385 macro_rules! file {() => {}}
287 file!() 386 file!()
288"#, 387 "#,
289 BuiltinFnLikeExpander::File,
290 ); 388 );
291 389
292 assert_eq!(expanded, "\"\""); 390 assert_eq!(expanded, "\"\"");
@@ -296,16 +394,34 @@ mod tests {
296 fn test_compile_error_expand() { 394 fn test_compile_error_expand() {
297 let expanded = expand_builtin_macro( 395 let expanded = expand_builtin_macro(
298 r#" 396 r#"
299 #[rustc_builtin_macro] 397 #[rustc_builtin_macro]
300 macro_rules! compile_error { 398 macro_rules! compile_error {
301 ($msg:expr) => ({ /* compiler built-in */ }); 399 ($msg:expr) => ({ /* compiler built-in */ });
302 ($msg:expr,) => ({ /* compiler built-in */ }) 400 ($msg:expr,) => ({ /* compiler built-in */ })
303 } 401 }
304 compile_error!("error!"); 402 compile_error!("error!");
305"#, 403 "#,
306 BuiltinFnLikeExpander::CompileError,
307 ); 404 );
308 405
309 assert_eq!(expanded, r#"loop{"error!"}"#); 406 assert_eq!(expanded, r#"loop{"error!"}"#);
310 } 407 }
408
409 #[test]
410 fn test_format_args_expand() {
411 let expanded = expand_builtin_macro(
412 r#"
413 #[rustc_builtin_macro]
414 macro_rules! format_args {
415 ($fmt:expr) => ({ /* compiler built-in */ });
416 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
417 }
418 format_args!("{} {:?}", arg1(a, b, c), arg2);
419 "#,
420 );
421
422 assert_eq!(
423 expanded,
424 r#"std::fmt::Arguments::new_v1(&[] ,&[std::fmt::ArgumentV1::new(&(arg1(a,b,c)),std::fmt::Display::fmt),std::fmt::ArgumentV1::new(&(arg2),std::fmt::Display::fmt),])"#
425 );
426 }
311} 427}
diff --git a/crates/ra_hir_expand/src/db.rs b/crates/ra_hir_expand/src/db.rs
index 8e46fa177..2e12e126f 100644
--- a/crates/ra_hir_expand/src/db.rs
+++ b/crates/ra_hir_expand/src/db.rs
@@ -6,17 +6,18 @@ use mbe::MacroRules;
6use ra_db::{salsa, SourceDatabase}; 6use ra_db::{salsa, SourceDatabase};
7use ra_parser::FragmentKind; 7use ra_parser::FragmentKind;
8use ra_prof::profile; 8use ra_prof::profile;
9use ra_syntax::{AstNode, Parse, SyntaxNode}; 9use ra_syntax::{AstNode, Parse, SyntaxKind::*, SyntaxNode};
10 10
11use crate::{ 11use crate::{
12 ast_id_map::AstIdMap, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr, MacroCallId, 12 ast_id_map::AstIdMap, BuiltinDeriveExpander, BuiltinFnLikeExpander, HirFileId, HirFileIdRepr,
13 MacroCallLoc, MacroDefId, MacroDefKind, MacroFile, MacroFileKind, 13 MacroCallId, MacroCallLoc, MacroDefId, MacroDefKind, MacroFile,
14}; 14};
15 15
16#[derive(Debug, Clone, Eq, PartialEq)] 16#[derive(Debug, Clone, Eq, PartialEq)]
17pub enum TokenExpander { 17pub enum TokenExpander {
18 MacroRules(mbe::MacroRules), 18 MacroRules(mbe::MacroRules),
19 Builtin(BuiltinFnLikeExpander), 19 Builtin(BuiltinFnLikeExpander),
20 BuiltinDerive(BuiltinDeriveExpander),
20} 21}
21 22
22impl TokenExpander { 23impl TokenExpander {
@@ -29,6 +30,7 @@ impl TokenExpander {
29 match self { 30 match self {
30 TokenExpander::MacroRules(it) => it.expand(tt), 31 TokenExpander::MacroRules(it) => it.expand(tt),
31 TokenExpander::Builtin(it) => it.expand(db, id, tt), 32 TokenExpander::Builtin(it) => it.expand(db, id, tt),
33 TokenExpander::BuiltinDerive(it) => it.expand(db, id, tt),
32 } 34 }
33 } 35 }
34 36
@@ -36,13 +38,15 @@ impl TokenExpander {
36 match self { 38 match self {
37 TokenExpander::MacroRules(it) => it.map_id_down(id), 39 TokenExpander::MacroRules(it) => it.map_id_down(id),
38 TokenExpander::Builtin(..) => id, 40 TokenExpander::Builtin(..) => id,
41 TokenExpander::BuiltinDerive(..) => id,
39 } 42 }
40 } 43 }
41 44
42 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) { 45 pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, mbe::Origin) {
43 match self { 46 match self {
44 TokenExpander::MacroRules(it) => it.map_id_up(id), 47 TokenExpander::MacroRules(it) => it.map_id_up(id),
45 TokenExpander::Builtin(..) => (id, mbe::Origin::Def), 48 TokenExpander::Builtin(..) => (id, mbe::Origin::Call),
49 TokenExpander::BuiltinDerive(..) => (id, mbe::Origin::Call),
46 } 50 }
47 } 51 }
48} 52}
@@ -76,7 +80,7 @@ pub(crate) fn macro_def(
76) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> { 80) -> Option<Arc<(TokenExpander, mbe::TokenMap)>> {
77 match id.kind { 81 match id.kind {
78 MacroDefKind::Declarative => { 82 MacroDefKind::Declarative => {
79 let macro_call = id.ast_id.to_node(db); 83 let macro_call = id.ast_id?.to_node(db);
80 let arg = macro_call.token_tree()?; 84 let arg = macro_call.token_tree()?;
81 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 85 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| {
82 log::warn!("fail on macro_def to token tree: {:#?}", arg); 86 log::warn!("fail on macro_def to token tree: {:#?}", arg);
@@ -89,7 +93,10 @@ pub(crate) fn macro_def(
89 Some(Arc::new((TokenExpander::MacroRules(rules), tmap))) 93 Some(Arc::new((TokenExpander::MacroRules(rules), tmap)))
90 } 94 }
91 MacroDefKind::BuiltIn(expander) => { 95 MacroDefKind::BuiltIn(expander) => {
92 Some(Arc::new((TokenExpander::Builtin(expander.clone()), mbe::TokenMap::default()))) 96 Some(Arc::new((TokenExpander::Builtin(expander), mbe::TokenMap::default())))
97 }
98 MacroDefKind::BuiltInDerive(expander) => {
99 Some(Arc::new((TokenExpander::BuiltinDerive(expander), mbe::TokenMap::default())))
93 } 100 }
94 } 101 }
95} 102}
@@ -99,9 +106,8 @@ pub(crate) fn macro_arg(
99 id: MacroCallId, 106 id: MacroCallId,
100) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 107) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
101 let loc = db.lookup_intern_macro(id); 108 let loc = db.lookup_intern_macro(id);
102 let macro_call = loc.ast_id.to_node(db); 109 let arg = loc.kind.arg(db)?;
103 let arg = macro_call.token_tree()?; 110 let (tt, tmap) = mbe::syntax_node_to_token_tree(&arg)?;
104 let (tt, tmap) = mbe::ast_to_token_tree(&arg)?;
105 Some(Arc::new((tt, tmap))) 111 Some(Arc::new((tt, tmap)))
106} 112}
107 113
@@ -148,11 +154,43 @@ pub(crate) fn parse_macro(
148 }) 154 })
149 .ok()?; 155 .ok()?;
150 156
151 let fragment_kind = match macro_file.macro_file_kind { 157 let fragment_kind = to_fragment_kind(db, macro_call_id);
152 MacroFileKind::Items => FragmentKind::Items, 158
153 MacroFileKind::Expr => FragmentKind::Expr,
154 MacroFileKind::Statements => FragmentKind::Statements,
155 };
156 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?; 159 let (parse, rev_token_map) = mbe::token_tree_to_syntax_node(&tt, fragment_kind).ok()?;
157 Some((parse, Arc::new(rev_token_map))) 160 Some((parse, Arc::new(rev_token_map)))
158} 161}
162
163/// Given a `MacroCallId`, return what `FragmentKind` it belongs to.
164/// FIXME: Not completed
165fn to_fragment_kind(db: &dyn AstDatabase, macro_call_id: MacroCallId) -> FragmentKind {
166 let syn = db.lookup_intern_macro(macro_call_id).kind.node(db).value;
167
168 let parent = match syn.parent() {
169 Some(it) => it,
170 None => {
171 // FIXME:
172 // If it is root, which means the parent HirFile
173 // MacroKindFile must be non-items
174 // return expr now.
175 return FragmentKind::Expr;
176 }
177 };
178
179 match parent.kind() {
180 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
181 LET_STMT => {
182 // FIXME: Handle Pattern
183 FragmentKind::Expr
184 }
185 // FIXME: Expand to statements in appropriate positions; HIR lowering needs to handle that
186 EXPR_STMT | BLOCK => FragmentKind::Expr,
187 ARG_LIST => FragmentKind::Expr,
188 TRY_EXPR => FragmentKind::Expr,
189 TUPLE_EXPR => FragmentKind::Expr,
190 ITEM_LIST => FragmentKind::Items,
191 _ => {
192 // Unknown , Just guess it is `Items`
193 FragmentKind::Items
194 }
195 }
196}
diff --git a/crates/ra_hir_expand/src/diagnostics.rs b/crates/ra_hir_expand/src/diagnostics.rs
index 3d37e9335..108c1e38c 100644
--- a/crates/ra_hir_expand/src/diagnostics.rs
+++ b/crates/ra_hir_expand/src/diagnostics.rs
@@ -18,11 +18,11 @@ use std::{any::Any, fmt};
18 18
19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange}; 19use ra_syntax::{SyntaxNode, SyntaxNodePtr, TextRange};
20 20
21use crate::{db::AstDatabase, Source}; 21use crate::{db::AstDatabase, InFile};
22 22
23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static { 23pub trait Diagnostic: Any + Send + Sync + fmt::Debug + 'static {
24 fn message(&self) -> String; 24 fn message(&self) -> String;
25 fn source(&self) -> Source<SyntaxNodePtr>; 25 fn source(&self) -> InFile<SyntaxNodePtr>;
26 fn highlight_range(&self) -> TextRange { 26 fn highlight_range(&self) -> TextRange {
27 self.source().value.range() 27 self.source().value.range()
28 } 28 }
diff --git a/crates/ra_hir_expand/src/either.rs b/crates/ra_hir_expand/src/either.rs
deleted file mode 100644
index 83583ef8b..000000000
--- a/crates/ra_hir_expand/src/either.rs
+++ /dev/null
@@ -1,54 +0,0 @@
1//! FIXME: write short doc here
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
4pub enum Either<A, B> {
5 A(A),
6 B(B),
7}
8
9impl<A, B> Either<A, B> {
10 pub fn either<R, F1, F2>(self, f1: F1, f2: F2) -> R
11 where
12 F1: FnOnce(A) -> R,
13 F2: FnOnce(B) -> R,
14 {
15 match self {
16 Either::A(a) => f1(a),
17 Either::B(b) => f2(b),
18 }
19 }
20 pub fn map<U, V, F1, F2>(self, f1: F1, f2: F2) -> Either<U, V>
21 where
22 F1: FnOnce(A) -> U,
23 F2: FnOnce(B) -> V,
24 {
25 match self {
26 Either::A(a) => Either::A(f1(a)),
27 Either::B(b) => Either::B(f2(b)),
28 }
29 }
30 pub fn map_a<U, F>(self, f: F) -> Either<U, B>
31 where
32 F: FnOnce(A) -> U,
33 {
34 self.map(f, |it| it)
35 }
36 pub fn a(self) -> Option<A> {
37 match self {
38 Either::A(it) => Some(it),
39 Either::B(_) => None,
40 }
41 }
42 pub fn b(self) -> Option<B> {
43 match self {
44 Either::A(_) => None,
45 Either::B(it) => Some(it),
46 }
47 }
48 pub fn as_ref(&self) -> Either<&A, &B> {
49 match self {
50 Either::A(it) => Either::A(it),
51 Either::B(it) => Either::B(it),
52 }
53 }
54}
diff --git a/crates/ra_hir_expand/src/hygiene.rs b/crates/ra_hir_expand/src/hygiene.rs
index 379562a2c..2e8a533f7 100644
--- a/crates/ra_hir_expand/src/hygiene.rs
+++ b/crates/ra_hir_expand/src/hygiene.rs
@@ -2,12 +2,12 @@
2//! 2//!
3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at 3//! Specifically, `ast` + `Hygiene` allows you to create a `Name`. Note that, at
4//! this moment, this is horribly incomplete and handles only `$crate`. 4//! this moment, this is horribly incomplete and handles only `$crate`.
5use either::Either;
5use ra_db::CrateId; 6use ra_db::CrateId;
6use ra_syntax::ast; 7use ra_syntax::ast;
7 8
8use crate::{ 9use crate::{
9 db::AstDatabase, 10 db::AstDatabase,
10 either::Either,
11 name::{AsName, Name}, 11 name::{AsName, Name},
12 HirFileId, HirFileIdRepr, MacroDefKind, 12 HirFileId, HirFileIdRepr, MacroDefKind,
13}; 13};
@@ -25,8 +25,9 @@ impl Hygiene {
25 HirFileIdRepr::MacroFile(macro_file) => { 25 HirFileIdRepr::MacroFile(macro_file) => {
26 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 26 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
27 match loc.def.kind { 27 match loc.def.kind {
28 MacroDefKind::Declarative => Some(loc.def.krate), 28 MacroDefKind::Declarative => loc.def.krate,
29 MacroDefKind::BuiltIn(_) => None, 29 MacroDefKind::BuiltIn(_) => None,
30 MacroDefKind::BuiltInDerive(_) => None,
30 } 31 }
31 } 32 }
32 }; 33 };
@@ -41,9 +42,9 @@ impl Hygiene {
41 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> { 42 pub fn name_ref_to_name(&self, name_ref: ast::NameRef) -> Either<Name, CrateId> {
42 if let Some(def_crate) = self.def_crate { 43 if let Some(def_crate) = self.def_crate {
43 if name_ref.text() == "$crate" { 44 if name_ref.text() == "$crate" {
44 return Either::B(def_crate); 45 return Either::Right(def_crate);
45 } 46 }
46 } 47 }
47 Either::A(name_ref.as_name()) 48 Either::Left(name_ref.as_name())
48 } 49 }
49} 50}
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs
index b6a739cda..2fa5d5140 100644
--- a/crates/ra_hir_expand/src/lib.rs
+++ b/crates/ra_hir_expand/src/lib.rs
@@ -6,14 +6,14 @@
6 6
7pub mod db; 7pub mod db;
8pub mod ast_id_map; 8pub mod ast_id_map;
9pub mod either;
10pub mod name; 9pub mod name;
11pub mod hygiene; 10pub mod hygiene;
12pub mod diagnostics; 11pub mod diagnostics;
12pub mod builtin_derive;
13pub mod builtin_macro; 13pub mod builtin_macro;
14pub mod quote; 14pub mod quote;
15 15
16use std::hash::{Hash, Hasher}; 16use std::hash::Hash;
17use std::sync::Arc; 17use std::sync::Arc;
18 18
19use ra_db::{salsa, CrateId, FileId}; 19use ra_db::{salsa, CrateId, FileId};
@@ -24,6 +24,7 @@ use ra_syntax::{
24}; 24};
25 25
26use crate::ast_id_map::FileAstId; 26use crate::ast_id_map::FileAstId;
27use crate::builtin_derive::BuiltinDeriveExpander;
27use crate::builtin_macro::BuiltinFnLikeExpander; 28use crate::builtin_macro::BuiltinFnLikeExpander;
28 29
29#[cfg(test)] 30#[cfg(test)]
@@ -70,7 +71,18 @@ impl HirFileId {
70 HirFileIdRepr::FileId(file_id) => file_id, 71 HirFileIdRepr::FileId(file_id) => file_id,
71 HirFileIdRepr::MacroFile(macro_file) => { 72 HirFileIdRepr::MacroFile(macro_file) => {
72 let loc = db.lookup_intern_macro(macro_file.macro_call_id); 73 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
73 loc.ast_id.file_id().original_file(db) 74 loc.kind.file_id().original_file(db)
75 }
76 }
77 }
78
79 /// If this is a macro call, returns the syntax node of the call.
80 pub fn call_node(self, db: &dyn db::AstDatabase) -> Option<InFile<SyntaxNode>> {
81 match self.0 {
82 HirFileIdRepr::FileId(_) => None,
83 HirFileIdRepr::MacroFile(macro_file) => {
84 let loc = db.lookup_intern_macro(macro_file.macro_call_id);
85 Some(loc.kind.node(db))
74 } 86 }
75 } 87 }
76 } 88 }
@@ -82,17 +94,17 @@ impl HirFileId {
82 HirFileIdRepr::MacroFile(macro_file) => { 94 HirFileIdRepr::MacroFile(macro_file) => {
83 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id); 95 let loc: MacroCallLoc = db.lookup_intern_macro(macro_file.macro_call_id);
84 96
85 let arg_tt = loc.ast_id.to_node(db).token_tree()?; 97 let arg_tt = loc.kind.arg(db)?;
86 let def_tt = loc.def.ast_id.to_node(db).token_tree()?; 98 let def_tt = loc.def.ast_id?.to_node(db).token_tree()?;
87 99
88 let macro_def = db.macro_def(loc.def)?; 100 let macro_def = db.macro_def(loc.def)?;
89 let (parse, exp_map) = db.parse_macro(macro_file)?; 101 let (parse, exp_map) = db.parse_macro(macro_file)?;
90 let macro_arg = db.macro_arg(macro_file.macro_call_id)?; 102 let macro_arg = db.macro_arg(macro_file.macro_call_id)?;
91 103
92 Some(ExpansionInfo { 104 Some(ExpansionInfo {
93 expanded: Source::new(self, parse.syntax_node()), 105 expanded: InFile::new(self, parse.syntax_node()),
94 arg: Source::new(loc.ast_id.file_id, arg_tt), 106 arg: InFile::new(loc.kind.file_id(), arg_tt),
95 def: Source::new(loc.ast_id.file_id, def_tt), 107 def: InFile::new(loc.def.ast_id?.file_id, def_tt),
96 macro_arg, 108 macro_arg,
97 macro_def, 109 macro_def,
98 exp_map, 110 exp_map,
@@ -105,14 +117,6 @@ impl HirFileId {
105#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 117#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
106pub struct MacroFile { 118pub struct MacroFile {
107 macro_call_id: MacroCallId, 119 macro_call_id: MacroCallId,
108 macro_file_kind: MacroFileKind,
109}
110
111#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
112pub enum MacroFileKind {
113 Items,
114 Expr,
115 Statements,
116} 120}
117 121
118/// `MacroCallId` identifies a particular macro invocation, like 122/// `MacroCallId` identifies a particular macro invocation, like
@@ -130,18 +134,20 @@ impl salsa::InternKey for MacroCallId {
130 134
131#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 135#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
132pub struct MacroDefId { 136pub struct MacroDefId {
133 pub krate: CrateId, 137 // FIXME: krate and ast_id are currently optional because we don't have a
134 pub ast_id: AstId<ast::MacroCall>, 138 // definition location for built-in derives. There is one, though: the
139 // standard library defines them. The problem is that it uses the new
140 // `macro` syntax for this, which we don't support yet. As soon as we do
141 // (which will probably require touching this code), we can instead use
142 // that (and also remove the hacks for resolving built-in derives).
143 pub krate: Option<CrateId>,
144 pub ast_id: Option<AstId<ast::MacroCall>>,
135 pub kind: MacroDefKind, 145 pub kind: MacroDefKind,
136} 146}
137 147
138impl MacroDefId { 148impl MacroDefId {
139 pub fn as_call_id( 149 pub fn as_call_id(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> MacroCallId {
140 self, 150 db.intern_macro(MacroCallLoc { def: self, kind })
141 db: &dyn db::AstDatabase,
142 ast_id: AstId<ast::MacroCall>,
143 ) -> MacroCallId {
144 db.intern_macro(MacroCallLoc { def: self, ast_id })
145 } 151 }
146} 152}
147 153
@@ -149,64 +155,103 @@ impl MacroDefId {
149pub enum MacroDefKind { 155pub enum MacroDefKind {
150 Declarative, 156 Declarative,
151 BuiltIn(BuiltinFnLikeExpander), 157 BuiltIn(BuiltinFnLikeExpander),
158 // FIXME: maybe just Builtin and rename BuiltinFnLikeExpander to BuiltinExpander
159 BuiltInDerive(BuiltinDeriveExpander),
152} 160}
153 161
154#[derive(Debug, Clone, PartialEq, Eq, Hash)] 162#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155pub struct MacroCallLoc { 163pub struct MacroCallLoc {
156 pub(crate) def: MacroDefId, 164 pub(crate) def: MacroDefId,
157 pub(crate) ast_id: AstId<ast::MacroCall>, 165 pub(crate) kind: MacroCallKind,
166}
167
168#[derive(Debug, Clone, PartialEq, Eq, Hash)]
169pub enum MacroCallKind {
170 FnLike(AstId<ast::MacroCall>),
171 Attr(AstId<ast::ModuleItem>),
172}
173
174impl MacroCallKind {
175 pub fn file_id(&self) -> HirFileId {
176 match self {
177 MacroCallKind::FnLike(ast_id) => ast_id.file_id,
178 MacroCallKind::Attr(ast_id) => ast_id.file_id,
179 }
180 }
181
182 pub fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
183 match self {
184 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
185 MacroCallKind::Attr(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()),
186 }
187 }
188
189 pub fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
190 match self {
191 MacroCallKind::FnLike(ast_id) => {
192 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
193 }
194 MacroCallKind::Attr(ast_id) => Some(ast_id.to_node(db).syntax().clone()),
195 }
196 }
158} 197}
159 198
160impl MacroCallId { 199impl MacroCallId {
161 pub fn as_file(self, kind: MacroFileKind) -> HirFileId { 200 pub fn as_file(self) -> HirFileId {
162 let macro_file = MacroFile { macro_call_id: self, macro_file_kind: kind }; 201 MacroFile { macro_call_id: self }.into()
163 macro_file.into()
164 } 202 }
165} 203}
166 204
167/// ExpansionInfo mainly describes how to map text range between src and expanded macro 205/// ExpansionInfo mainly describes how to map text range between src and expanded macro
168#[derive(Debug, Clone, PartialEq, Eq)] 206#[derive(Debug, Clone, PartialEq, Eq)]
169pub struct ExpansionInfo { 207pub struct ExpansionInfo {
170 expanded: Source<SyntaxNode>, 208 expanded: InFile<SyntaxNode>,
171 arg: Source<ast::TokenTree>, 209 arg: InFile<SyntaxNode>,
172 def: Source<ast::TokenTree>, 210 def: InFile<ast::TokenTree>,
173 211
174 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>, 212 macro_def: Arc<(db::TokenExpander, mbe::TokenMap)>,
175 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>, 213 macro_arg: Arc<(tt::Subtree, mbe::TokenMap)>,
176 exp_map: Arc<mbe::TokenMap>, 214 exp_map: Arc<mbe::TokenMap>,
177} 215}
178 216
217pub use mbe::Origin;
218
179impl ExpansionInfo { 219impl ExpansionInfo {
180 pub fn map_token_down(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { 220 pub fn call_node(&self) -> Option<InFile<SyntaxNode>> {
221 Some(self.arg.with_value(self.arg.value.parent()?))
222 }
223
224 pub fn map_token_down(&self, token: InFile<&SyntaxToken>) -> Option<InFile<SyntaxToken>> {
181 assert_eq!(token.file_id, self.arg.file_id); 225 assert_eq!(token.file_id, self.arg.file_id);
182 let range = 226 let range = token.value.text_range().checked_sub(self.arg.value.text_range().start())?;
183 token.value.text_range().checked_sub(self.arg.value.syntax().text_range().start())?;
184 let token_id = self.macro_arg.1.token_by_range(range)?; 227 let token_id = self.macro_arg.1.token_by_range(range)?;
185 let token_id = self.macro_def.0.map_id_down(token_id); 228 let token_id = self.macro_def.0.map_id_down(token_id);
186 229
187 let range = self.exp_map.range_by_token(token_id)?; 230 let range = self.exp_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
188 231
189 let token = algo::find_covering_element(&self.expanded.value, range).into_token()?; 232 let token = algo::find_covering_element(&self.expanded.value, range).into_token()?;
190 233
191 Some(self.expanded.with_value(token)) 234 Some(self.expanded.with_value(token))
192 } 235 }
193 236
194 pub fn map_token_up(&self, token: Source<&SyntaxToken>) -> Option<Source<SyntaxToken>> { 237 pub fn map_token_up(
238 &self,
239 token: InFile<&SyntaxToken>,
240 ) -> Option<(InFile<SyntaxToken>, Origin)> {
195 let token_id = self.exp_map.token_by_range(token.value.text_range())?; 241 let token_id = self.exp_map.token_by_range(token.value.text_range())?;
196 242
197 let (token_id, origin) = self.macro_def.0.map_id_up(token_id); 243 let (token_id, origin) = self.macro_def.0.map_id_up(token_id);
198 let (token_map, tt) = match origin { 244 let (token_map, tt) = match origin {
199 mbe::Origin::Call => (&self.macro_arg.1, &self.arg), 245 mbe::Origin::Call => (&self.macro_arg.1, self.arg.clone()),
200 mbe::Origin::Def => (&self.macro_def.1, &self.def), 246 mbe::Origin::Def => {
247 (&self.macro_def.1, self.def.as_ref().map(|tt| tt.syntax().clone()))
248 }
201 }; 249 };
202 250
203 let range = token_map.range_by_token(token_id)?; 251 let range = token_map.range_by_token(token_id)?.by_kind(token.value.kind())?;
204 let token = algo::find_covering_element( 252 let token = algo::find_covering_element(&tt.value, range + tt.value.text_range().start())
205 tt.value.syntax(), 253 .into_token()?;
206 range + tt.value.syntax().text_range().start(), 254 Some((tt.with_value(token), origin))
207 )
208 .into_token()?;
209 Some(tt.with_value(token))
210 } 255 }
211} 256}
212 257
@@ -214,76 +259,66 @@ impl ExpansionInfo {
214/// 259///
215/// It is stable across reparses, and can be used as salsa key/value. 260/// It is stable across reparses, and can be used as salsa key/value.
216// FIXME: isn't this just a `Source<FileAstId<N>>` ? 261// FIXME: isn't this just a `Source<FileAstId<N>>` ?
217#[derive(Debug)] 262pub type AstId<N> = InFile<FileAstId<N>>;
218pub struct AstId<N: AstNode> {
219 file_id: HirFileId,
220 file_ast_id: FileAstId<N>,
221}
222
223impl<N: AstNode> Clone for AstId<N> {
224 fn clone(&self) -> AstId<N> {
225 *self
226 }
227}
228impl<N: AstNode> Copy for AstId<N> {}
229
230impl<N: AstNode> PartialEq for AstId<N> {
231 fn eq(&self, other: &Self) -> bool {
232 (self.file_id, self.file_ast_id) == (other.file_id, other.file_ast_id)
233 }
234}
235impl<N: AstNode> Eq for AstId<N> {}
236impl<N: AstNode> Hash for AstId<N> {
237 fn hash<H: Hasher>(&self, hasher: &mut H) {
238 (self.file_id, self.file_ast_id).hash(hasher);
239 }
240}
241 263
242impl<N: AstNode> AstId<N> { 264impl<N: AstNode> AstId<N> {
243 pub fn new(file_id: HirFileId, file_ast_id: FileAstId<N>) -> AstId<N> {
244 AstId { file_id, file_ast_id }
245 }
246
247 pub fn file_id(&self) -> HirFileId {
248 self.file_id
249 }
250
251 pub fn to_node(&self, db: &dyn db::AstDatabase) -> N { 265 pub fn to_node(&self, db: &dyn db::AstDatabase) -> N {
252 let root = db.parse_or_expand(self.file_id).unwrap(); 266 let root = db.parse_or_expand(self.file_id).unwrap();
253 db.ast_id_map(self.file_id).get(self.file_ast_id).to_node(&root) 267 db.ast_id_map(self.file_id).get(self.value).to_node(&root)
254 } 268 }
255} 269}
256 270
257/// `Source<T>` stores a value of `T` inside a particular file/syntax tree. 271/// `InFile<T>` stores a value of `T` inside a particular file/syntax tree.
258/// 272///
259/// Typical usages are: 273/// Typical usages are:
260/// 274///
261/// * `Source<SyntaxNode>` -- syntax node in a file 275/// * `InFile<SyntaxNode>` -- syntax node in a file
262/// * `Source<ast::FnDef>` -- ast node in a file 276/// * `InFile<ast::FnDef>` -- ast node in a file
263/// * `Source<TextUnit>` -- offset in a file 277/// * `InFile<TextUnit>` -- offset in a file
264#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)] 278#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash)]
265pub struct Source<T> { 279pub struct InFile<T> {
266 pub file_id: HirFileId, 280 pub file_id: HirFileId,
267 pub value: T, 281 pub value: T,
268} 282}
269 283
270impl<T> Source<T> { 284impl<T> InFile<T> {
271 pub fn new(file_id: HirFileId, value: T) -> Source<T> { 285 pub fn new(file_id: HirFileId, value: T) -> InFile<T> {
272 Source { file_id, value } 286 InFile { file_id, value }
273 } 287 }
274 288
275 // Similarly, naming here is stupid... 289 // Similarly, naming here is stupid...
276 pub fn with_value<U>(&self, value: U) -> Source<U> { 290 pub fn with_value<U>(&self, value: U) -> InFile<U> {
277 Source::new(self.file_id, value) 291 InFile::new(self.file_id, value)
278 } 292 }
279 293
280 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> { 294 pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> InFile<U> {
281 Source::new(self.file_id, f(self.value)) 295 InFile::new(self.file_id, f(self.value))
282 } 296 }
283 pub fn as_ref(&self) -> Source<&T> { 297 pub fn as_ref(&self) -> InFile<&T> {
284 self.with_value(&self.value) 298 self.with_value(&self.value)
285 } 299 }
286 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode { 300 pub fn file_syntax(&self, db: &impl db::AstDatabase) -> SyntaxNode {
287 db.parse_or_expand(self.file_id).expect("source created from invalid file") 301 db.parse_or_expand(self.file_id).expect("source created from invalid file")
288 } 302 }
289} 303}
304
305impl<T: Clone> InFile<&T> {
306 pub fn cloned(&self) -> InFile<T> {
307 self.with_value(self.value.clone())
308 }
309}
310
311impl InFile<SyntaxNode> {
312 pub fn ancestors_with_macros<'a>(
313 self,
314 db: &'a impl crate::db::AstDatabase,
315 ) -> impl Iterator<Item = InFile<SyntaxNode>> + 'a {
316 std::iter::successors(Some(self), move |node| match node.value.parent() {
317 Some(parent) => Some(node.with_value(parent)),
318 None => {
319 let parent_node = node.file_id.call_node(db)?;
320 Some(parent_node)
321 }
322 })
323 }
324}
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 7824489d7..e62693b68 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -38,8 +38,8 @@ impl Name {
38 } 38 }
39 39
40 /// Shortcut to create inline plain text name 40 /// Shortcut to create inline plain text name
41 const fn new_inline_ascii(len: usize, text: &[u8]) -> Name { 41 const fn new_inline_ascii(text: &[u8]) -> Name {
42 Name::new_text(SmolStr::new_inline_from_ascii(len, text)) 42 Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text))
43 } 43 }
44 44
45 /// Resolve a name from the text of token. 45 /// Resolve a name from the text of token.
@@ -83,6 +83,12 @@ impl AsName for ast::Name {
83 } 83 }
84} 84}
85 85
86impl AsName for tt::Ident {
87 fn as_name(&self) -> Name {
88 Name::resolve(&self.text)
89 }
90}
91
86impl AsName for ast::FieldKind { 92impl AsName for ast::FieldKind {
87 fn as_name(&self) -> Name { 93 fn as_name(&self) -> Name {
88 match self { 94 match self {
@@ -98,52 +104,102 @@ impl AsName for ra_db::Dependency {
98 } 104 }
99} 105}
100 106
101// Primitives 107pub mod known {
102pub const ISIZE: Name = Name::new_inline_ascii(5, b"isize"); 108 macro_rules! known_names {
103pub const I8: Name = Name::new_inline_ascii(2, b"i8"); 109 ($($ident:ident),* $(,)?) => {
104pub const I16: Name = Name::new_inline_ascii(3, b"i16"); 110 $(
105pub const I32: Name = Name::new_inline_ascii(3, b"i32"); 111 #[allow(bad_style)]
106pub const I64: Name = Name::new_inline_ascii(3, b"i64"); 112 pub const $ident: super::Name =
107pub const I128: Name = Name::new_inline_ascii(4, b"i128"); 113 super::Name::new_inline_ascii(stringify!($ident).as_bytes());
108pub const USIZE: Name = Name::new_inline_ascii(5, b"usize"); 114 )*
109pub const U8: Name = Name::new_inline_ascii(2, b"u8"); 115 };
110pub const U16: Name = Name::new_inline_ascii(3, b"u16"); 116 }
111pub const U32: Name = Name::new_inline_ascii(3, b"u32"); 117
112pub const U64: Name = Name::new_inline_ascii(3, b"u64"); 118 known_names!(
113pub const U128: Name = Name::new_inline_ascii(4, b"u128"); 119 // Primitives
114pub const F32: Name = Name::new_inline_ascii(3, b"f32"); 120 isize,
115pub const F64: Name = Name::new_inline_ascii(3, b"f64"); 121 i8,
116pub const BOOL: Name = Name::new_inline_ascii(4, b"bool"); 122 i16,
117pub const CHAR: Name = Name::new_inline_ascii(4, b"char"); 123 i32,
118pub const STR: Name = Name::new_inline_ascii(3, b"str"); 124 i64,
119 125 i128,
120// Special names 126 usize,
121pub const SELF_PARAM: Name = Name::new_inline_ascii(4, b"self"); 127 u8,
122pub const SELF_TYPE: Name = Name::new_inline_ascii(4, b"Self"); 128 u16,
123pub const MACRO_RULES: Name = Name::new_inline_ascii(11, b"macro_rules"); 129 u32,
124 130 u64,
125// Components of known path (value or mod name) 131 u128,
126pub const STD: Name = Name::new_inline_ascii(3, b"std"); 132 f32,
127pub const ITER: Name = Name::new_inline_ascii(4, b"iter"); 133 f64,
128pub const OPS: Name = Name::new_inline_ascii(3, b"ops"); 134 bool,
129pub const FUTURE: Name = Name::new_inline_ascii(6, b"future"); 135 char,
130pub const RESULT: Name = Name::new_inline_ascii(6, b"result"); 136 str,
131pub const BOXED: Name = Name::new_inline_ascii(5, b"boxed"); 137 // Special names
132 138 macro_rules,
133// Components of known path (type name) 139 // Components of known path (value or mod name)
134pub const INTO_ITERATOR_TYPE: Name = Name::new_inline_ascii(12, b"IntoIterator"); 140 std,
135pub const ITEM_TYPE: Name = Name::new_inline_ascii(4, b"Item"); 141 iter,
136pub const TRY_TYPE: Name = Name::new_inline_ascii(3, b"Try"); 142 ops,
137pub const OK_TYPE: Name = Name::new_inline_ascii(2, b"Ok"); 143 future,
138pub const FUTURE_TYPE: Name = Name::new_inline_ascii(6, b"Future"); 144 result,
139pub const RESULT_TYPE: Name = Name::new_inline_ascii(6, b"Result"); 145 boxed,
140pub const OUTPUT_TYPE: Name = Name::new_inline_ascii(6, b"Output"); 146 // Components of known path (type name)
141pub const TARGET_TYPE: Name = Name::new_inline_ascii(6, b"Target"); 147 IntoIterator,
142pub const BOX_TYPE: Name = Name::new_inline_ascii(3, b"Box"); 148 Item,
143 149 Try,
144// Builtin Macros 150 Ok,
145pub const FILE_MACRO: Name = Name::new_inline_ascii(4, b"file"); 151 Future,
146pub const COLUMN_MACRO: Name = Name::new_inline_ascii(6, b"column"); 152 Result,
147pub const COMPILE_ERROR_MACRO: Name = Name::new_inline_ascii(13, b"compile_error"); 153 Output,
148pub const LINE_MACRO: Name = Name::new_inline_ascii(4, b"line"); 154 Target,
149pub const STRINGIFY_MACRO: Name = Name::new_inline_ascii(9, b"stringify"); 155 Box,
156 RangeFrom,
157 RangeFull,
158 RangeInclusive,
159 RangeToInclusive,
160 RangeTo,
161 Range,
162 Neg,
163 Not,
164 Index,
165 // Builtin macros
166 file,
167 column,
168 compile_error,
169 line,
170 stringify,
171 format_args,
172 format_args_nl,
173 env,
174 option_env,
175 // Builtin derives
176 Copy,
177 Clone,
178 Default,
179 Debug,
180 Hash,
181 Ord,
182 PartialOrd,
183 Eq,
184 PartialEq,
185 );
186
187 // self/Self cannot be used as an identifier
188 pub const SELF_PARAM: super::Name = super::Name::new_inline_ascii(b"self");
189 pub const SELF_TYPE: super::Name = super::Name::new_inline_ascii(b"Self");
190
191 #[macro_export]
192 macro_rules! name {
193 (self) => {
194 $crate::name::known::SELF_PARAM
195 };
196 (Self) => {
197 $crate::name::known::SELF_TYPE
198 };
199 ($ident:ident) => {
200 $crate::name::known::$ident
201 };
202 }
203}
204
205pub use crate::name;
diff --git a/crates/ra_hir_expand/src/quote.rs b/crates/ra_hir_expand/src/quote.rs
index 65a35e52f..4de219ce4 100644
--- a/crates/ra_hir_expand/src/quote.rs
+++ b/crates/ra_hir_expand/src/quote.rs
@@ -16,7 +16,10 @@ macro_rules! __quote {
16 { 16 {
17 let children = $crate::__quote!($($tt)*); 17 let children = $crate::__quote!($($tt)*);
18 let subtree = tt::Subtree { 18 let subtree = tt::Subtree {
19 delimiter: tt::Delimiter::$delim, 19 delimiter: Some(tt::Delimiter {
20 kind: tt::DelimiterKind::$delim,
21 id: tt::TokenId::unspecified(),
22 }),
20 token_trees: $crate::quote::IntoTt::to_tokens(children), 23 token_trees: $crate::quote::IntoTt::to_tokens(children),
21 }; 24 };
22 subtree 25 subtree
@@ -29,6 +32,7 @@ macro_rules! __quote {
29 tt::Leaf::Punct(tt::Punct { 32 tt::Leaf::Punct(tt::Punct {
30 char: $first, 33 char: $first,
31 spacing: tt::Spacing::Alone, 34 spacing: tt::Spacing::Alone,
35 id: tt::TokenId::unspecified(),
32 }).into() 36 }).into()
33 ] 37 ]
34 } 38 }
@@ -40,10 +44,12 @@ macro_rules! __quote {
40 tt::Leaf::Punct(tt::Punct { 44 tt::Leaf::Punct(tt::Punct {
41 char: $first, 45 char: $first,
42 spacing: tt::Spacing::Joint, 46 spacing: tt::Spacing::Joint,
47 id: tt::TokenId::unspecified(),
43 }).into(), 48 }).into(),
44 tt::Leaf::Punct(tt::Punct { 49 tt::Leaf::Punct(tt::Punct {
45 char: $sec, 50 char: $sec,
46 spacing: tt::Spacing::Alone, 51 spacing: tt::Spacing::Alone,
52 id: tt::TokenId::unspecified(),
47 }).into() 53 }).into()
48 ] 54 ]
49 } 55 }
@@ -60,6 +66,15 @@ macro_rules! __quote {
60 } 66 }
61 }; 67 };
62 68
69 ( ## $first:ident $($tail:tt)* ) => {
70 {
71 let mut tokens = $first.into_iter().map($crate::quote::ToTokenTree::to_token).collect::<Vec<tt::TokenTree>>();
72 let mut tail_tokens = $crate::quote::IntoTt::to_tokens($crate::__quote!($($tail)*));
73 tokens.append(&mut tail_tokens);
74 tokens
75 }
76 };
77
63 // Brace 78 // Brace
64 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) }; 79 ( { $($tt:tt)* } ) => { $crate::__quote!(@SUBTREE Brace $($tt)*) };
65 // Bracket 80 // Bracket
@@ -85,7 +100,10 @@ macro_rules! __quote {
85 ( & ) => {$crate::__quote!(@PUNCT '&')}; 100 ( & ) => {$crate::__quote!(@PUNCT '&')};
86 ( , ) => {$crate::__quote!(@PUNCT ',')}; 101 ( , ) => {$crate::__quote!(@PUNCT ',')};
87 ( : ) => {$crate::__quote!(@PUNCT ':')}; 102 ( : ) => {$crate::__quote!(@PUNCT ':')};
103 ( :: ) => {$crate::__quote!(@PUNCT ':', ':')};
88 ( . ) => {$crate::__quote!(@PUNCT '.')}; 104 ( . ) => {$crate::__quote!(@PUNCT '.')};
105 ( < ) => {$crate::__quote!(@PUNCT '<')};
106 ( > ) => {$crate::__quote!(@PUNCT '>')};
89 107
90 ( $first:tt $($tail:tt)+ ) => { 108 ( $first:tt $($tail:tt)+ ) => {
91 { 109 {
@@ -114,7 +132,7 @@ pub(crate) trait IntoTt {
114 132
115impl IntoTt for Vec<tt::TokenTree> { 133impl IntoTt for Vec<tt::TokenTree> {
116 fn to_subtree(self) -> tt::Subtree { 134 fn to_subtree(self) -> tt::Subtree {
117 tt::Subtree { delimiter: tt::Delimiter::None, token_trees: self } 135 tt::Subtree { delimiter: None, token_trees: self }
118 } 136 }
119 137
120 fn to_tokens(self) -> Vec<tt::TokenTree> { 138 fn to_tokens(self) -> Vec<tt::TokenTree> {
@@ -169,15 +187,15 @@ macro_rules! impl_to_to_tokentrees {
169} 187}
170 188
171impl_to_to_tokentrees! { 189impl_to_to_tokentrees! {
172 u32 => self { tt::Literal{text: self.to_string().into()} }; 190 u32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()} };
173 usize => self { tt::Literal{text: self.to_string().into()}}; 191 usize => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
174 i32 => self { tt::Literal{text: self.to_string().into()}}; 192 i32 => self { tt::Literal{text: self.to_string().into(), id: tt::TokenId::unspecified()}};
175 tt::Leaf => self { self }; 193 tt::Leaf => self { self };
176 tt::Literal => self { self }; 194 tt::Literal => self { self };
177 tt::Ident => self { self }; 195 tt::Ident => self { self };
178 tt::Punct => self { self }; 196 tt::Punct => self { self };
179 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}}; 197 &str => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}};
180 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into()}} 198 String => self { tt::Literal{text: format!("{:?}", self.escape_default().to_string()).into(), id: tt::TokenId::unspecified()}}
181} 199}
182 200
183#[cfg(test)] 201#[cfg(test)]
@@ -244,7 +262,13 @@ mod tests {
244 let fields = 262 let fields =
245 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten(); 263 fields.iter().map(|it| quote!(#it: self.#it.clone(), ).token_trees.clone()).flatten();
246 264
247 let list = tt::Subtree { delimiter: tt::Delimiter::Brace, token_trees: fields.collect() }; 265 let list = tt::Subtree {
266 delimiter: Some(tt::Delimiter {
267 kind: tt::DelimiterKind::Brace,
268 id: tt::TokenId::unspecified(),
269 }),
270 token_trees: fields.collect(),
271 };
248 272
249 let quoted = quote! { 273 let quoted = quote! {
250 impl Clone for #struct_name { 274 impl Clone for #struct_name {
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml
index 429242870..60793db44 100644
--- a/crates/ra_hir_ty/Cargo.toml
+++ b/crates/ra_hir_ty/Cargo.toml
@@ -21,10 +21,9 @@ ra_prof = { path = "../ra_prof" }
21ra_syntax = { path = "../ra_syntax" } 21ra_syntax = { path = "../ra_syntax" }
22test_utils = { path = "../test_utils" } 22test_utils = { path = "../test_utils" }
23 23
24# https://github.com/rust-lang/chalk/pull/294 24chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
25chalk-solve = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } 25chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
26chalk-rust-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" } 26chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "ff65b5ac9860f3c36bd892c865ab23d5ff0bbae5" }
27chalk-ir = { git = "https://github.com/jackh726/chalk.git", rev = "095cd38a4f16337913bba487f2055b9ca0179f30" }
28 27
29lalrpop-intern = "0.15.1" 28lalrpop-intern = "0.15.1"
30 29
diff --git a/crates/ra_hir_ty/src/autoderef.rs b/crates/ra_hir_ty/src/autoderef.rs
index 9d1d4e48c..f32d5786a 100644
--- a/crates/ra_hir_ty/src/autoderef.rs
+++ b/crates/ra_hir_ty/src/autoderef.rs
@@ -6,14 +6,14 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9use hir_expand::name; 9use hir_expand::name::name;
10use log::{info, warn}; 10use log::{info, warn};
11use ra_db::CrateId; 11use ra_db::CrateId;
12 12
13use crate::db::HirDatabase; 13use crate::{
14 14 db::HirDatabase,
15use super::{
16 traits::{InEnvironment, Solution}, 15 traits::{InEnvironment, Solution},
16 utils::generics,
17 Canonical, Substs, Ty, TypeWalk, 17 Canonical, Substs, Ty, TypeWalk,
18}; 18};
19 19
@@ -48,14 +48,14 @@ fn deref_by_trait(
48 krate: CrateId, 48 krate: CrateId,
49 ty: InEnvironment<&Canonical<Ty>>, 49 ty: InEnvironment<&Canonical<Ty>>,
50) -> Option<Canonical<Ty>> { 50) -> Option<Canonical<Ty>> {
51 let deref_trait = match db.lang_item(krate.into(), "deref".into())? { 51 let deref_trait = match db.lang_item(krate, "deref".into())? {
52 LangItemTarget::TraitId(it) => it, 52 LangItemTarget::TraitId(it) => it,
53 _ => return None, 53 _ => return None,
54 }; 54 };
55 let target = db.trait_data(deref_trait).associated_type_by_name(&name::TARGET_TYPE)?; 55 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
56 56
57 let generic_params = db.generic_params(target.into()); 57 let generic_params = generics(db, target.into());
58 if generic_params.count_params_including_parent() != 1 { 58 if generic_params.len() != 1 {
59 // the Target type + Deref trait should only have one generic parameter, 59 // the Target type + Deref trait should only have one generic parameter,
60 // namely Deref's Self type 60 // namely Deref's Self type
61 return None; 61 return None;
@@ -78,7 +78,7 @@ fn deref_by_trait(
78 78
79 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env }; 79 let canonical = super::Canonical { num_vars: 1 + ty.value.num_vars, value: in_env };
80 80
81 let solution = db.trait_solve(krate.into(), canonical)?; 81 let solution = db.trait_solve(krate, canonical)?;
82 82
83 match &solution { 83 match &solution {
84 Solution::Unique(vars) => { 84 Solution::Unique(vars) => {
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index 9ce154593..d52f65b83 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -10,8 +10,8 @@ use ra_db::{salsa, CrateId};
10 10
11use crate::{ 11use crate::{
12 method_resolution::CrateImplBlocks, 12 method_resolution::CrateImplBlocks,
13 traits::{AssocTyValue, Impl}, 13 traits::{chalk, AssocTyValue, Impl},
14 CallableDef, FnSig, GenericPredicate, ImplTy, InferenceResult, Substs, Ty, TyDefId, TypeCtor, 14 CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor,
15 ValueTyDefId, 15 ValueTyDefId,
16}; 16};
17 17
@@ -22,13 +22,18 @@ pub trait HirDatabase: DefDatabase {
22 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>; 22 fn infer(&self, def: DefWithBodyId) -> Arc<InferenceResult>;
23 23
24 #[salsa::invoke(crate::lower::ty_query)] 24 #[salsa::invoke(crate::lower::ty_query)]
25 #[salsa::cycle(crate::lower::ty_recover)]
25 fn ty(&self, def: TyDefId) -> Ty; 26 fn ty(&self, def: TyDefId) -> Ty;
26 27
27 #[salsa::invoke(crate::lower::value_ty_query)] 28 #[salsa::invoke(crate::lower::value_ty_query)]
28 fn value_ty(&self, def: ValueTyDefId) -> Ty; 29 fn value_ty(&self, def: ValueTyDefId) -> Ty;
29 30
30 #[salsa::invoke(crate::lower::impl_ty_query)] 31 #[salsa::invoke(crate::lower::impl_self_ty_query)]
31 fn impl_ty(&self, def: ImplId) -> ImplTy; 32 #[salsa::cycle(crate::lower::impl_self_ty_recover)]
33 fn impl_self_ty(&self, def: ImplId) -> Ty;
34
35 #[salsa::invoke(crate::lower::impl_trait_query)]
36 fn impl_trait(&self, def: ImplId) -> Option<TraitRef>;
32 37
33 #[salsa::invoke(crate::lower::field_types_query)] 38 #[salsa::invoke(crate::lower::field_types_query)]
34 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>; 39 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>;
@@ -37,6 +42,7 @@ pub trait HirDatabase: DefDatabase {
37 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 42 fn callable_item_signature(&self, def: CallableDef) -> FnSig;
38 43
39 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] 44 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
45 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
40 fn generic_predicates_for_param( 46 fn generic_predicates_for_param(
41 &self, 47 &self,
42 def: GenericDefId, 48 def: GenericDefId,
@@ -71,39 +77,24 @@ pub trait HirDatabase: DefDatabase {
71 #[salsa::interned] 77 #[salsa::interned]
72 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; 78 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
73 79
74 #[salsa::invoke(crate::traits::chalk::associated_ty_data_query)] 80 #[salsa::invoke(chalk::associated_ty_data_query)]
75 fn associated_ty_data( 81 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>;
76 &self,
77 id: chalk_ir::TypeId,
78 ) -> Arc<chalk_rust_ir::AssociatedTyDatum<chalk_ir::family::ChalkIr>>;
79 82
80 #[salsa::invoke(crate::traits::chalk::trait_datum_query)] 83 #[salsa::invoke(chalk::trait_datum_query)]
81 fn trait_datum( 84 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>;
82 &self,
83 krate: CrateId,
84 trait_id: chalk_ir::TraitId,
85 ) -> Arc<chalk_rust_ir::TraitDatum<chalk_ir::family::ChalkIr>>;
86 85
87 #[salsa::invoke(crate::traits::chalk::struct_datum_query)] 86 #[salsa::invoke(chalk::struct_datum_query)]
88 fn struct_datum( 87 fn struct_datum(&self, krate: CrateId, struct_id: chalk::StructId) -> Arc<chalk::StructDatum>;
89 &self,
90 krate: CrateId,
91 struct_id: chalk_ir::StructId,
92 ) -> Arc<chalk_rust_ir::StructDatum<chalk_ir::family::ChalkIr>>;
93 88
94 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 89 #[salsa::invoke(crate::traits::chalk::impl_datum_query)]
95 fn impl_datum( 90 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>;
96 &self,
97 krate: CrateId,
98 impl_id: chalk_ir::ImplId,
99 ) -> Arc<chalk_rust_ir::ImplDatum<chalk_ir::family::ChalkIr>>;
100 91
101 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 92 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)]
102 fn associated_ty_value( 93 fn associated_ty_value(
103 &self, 94 &self,
104 krate: CrateId, 95 krate: CrateId,
105 id: chalk_rust_ir::AssociatedTyValueId, 96 id: chalk::AssociatedTyValueId,
106 ) -> Arc<chalk_rust_ir::AssociatedTyValue<chalk_ir::family::ChalkIr>>; 97 ) -> Arc<chalk::AssociatedTyValue>;
107 98
108 #[salsa::invoke(crate::traits::trait_solve_query)] 99 #[salsa::invoke(crate::traits::trait_solve_query)]
109 fn trait_solve( 100 fn trait_solve(
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs
index 4a13fac23..5054189cc 100644
--- a/crates/ra_hir_ty/src/diagnostics.rs
+++ b/crates/ra_hir_ty/src/diagnostics.rs
@@ -2,7 +2,7 @@
2 2
3use std::any::Any; 3use std::any::Any;
4 4
5use hir_expand::{db::AstDatabase, name::Name, HirFileId, Source}; 5use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile};
6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; 6use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
7 7
8pub use hir_def::diagnostics::UnresolvedModule; 8pub use hir_def::diagnostics::UnresolvedModule;
@@ -19,8 +19,8 @@ impl Diagnostic for NoSuchField {
19 "no such field".to_string() 19 "no such field".to_string()
20 } 20 }
21 21
22 fn source(&self) -> Source<SyntaxNodePtr> { 22 fn source(&self) -> InFile<SyntaxNodePtr> {
23 Source { file_id: self.file, value: self.field.into() } 23 InFile { file_id: self.file, value: self.field.into() }
24 } 24 }
25 25
26 fn as_any(&self) -> &(dyn Any + Send + 'static) { 26 fn as_any(&self) -> &(dyn Any + Send + 'static) {
@@ -44,8 +44,8 @@ impl Diagnostic for MissingFields {
44 } 44 }
45 message 45 message
46 } 46 }
47 fn source(&self) -> Source<SyntaxNodePtr> { 47 fn source(&self) -> InFile<SyntaxNodePtr> {
48 Source { file_id: self.file, value: self.field_list.into() } 48 InFile { file_id: self.file, value: self.field_list.into() }
49 } 49 }
50 fn as_any(&self) -> &(dyn Any + Send + 'static) { 50 fn as_any(&self) -> &(dyn Any + Send + 'static) {
51 self 51 self
@@ -72,8 +72,8 @@ impl Diagnostic for MissingOkInTailExpr {
72 fn message(&self) -> String { 72 fn message(&self) -> String {
73 "wrap return expression in Ok".to_string() 73 "wrap return expression in Ok".to_string()
74 } 74 }
75 fn source(&self) -> Source<SyntaxNodePtr> { 75 fn source(&self) -> InFile<SyntaxNodePtr> {
76 Source { file_id: self.file, value: self.expr.into() } 76 InFile { file_id: self.file, value: self.expr.into() }
77 } 77 }
78 fn as_any(&self) -> &(dyn Any + Send + 'static) { 78 fn as_any(&self) -> &(dyn Any + Send + 'static) {
79 self 79 self
diff --git a/crates/ra_hir_ty/src/display.rs b/crates/ra_hir_ty/src/display.rs
index 9bb3ece6c..dcca1bace 100644
--- a/crates/ra_hir_ty/src/display.rs
+++ b/crates/ra_hir_ty/src/display.rs
@@ -10,6 +10,7 @@ pub struct HirFormatter<'a, 'b, DB> {
10 buf: String, 10 buf: String,
11 curr_size: usize, 11 curr_size: usize,
12 max_size: Option<usize>, 12 max_size: Option<usize>,
13 should_display_default_types: bool,
13} 14}
14 15
15pub trait HirDisplay { 16pub trait HirDisplay {
@@ -19,7 +20,7 @@ pub trait HirDisplay {
19 where 20 where
20 Self: Sized, 21 Self: Sized,
21 { 22 {
22 HirDisplayWrapper(db, self, None) 23 HirDisplayWrapper(db, self, None, true)
23 } 24 }
24 25
25 fn display_truncated<'a, DB>( 26 fn display_truncated<'a, DB>(
@@ -30,7 +31,7 @@ pub trait HirDisplay {
30 where 31 where
31 Self: Sized, 32 Self: Sized,
32 { 33 {
33 HirDisplayWrapper(db, self, max_size) 34 HirDisplayWrapper(db, self, max_size, false)
34 } 35 }
35} 36}
36 37
@@ -72,9 +73,13 @@ where
72 false 73 false
73 } 74 }
74 } 75 }
76
77 pub fn should_display_default_types(&self) -> bool {
78 self.should_display_default_types
79 }
75} 80}
76 81
77pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<usize>); 82pub struct HirDisplayWrapper<'a, DB, T>(&'a DB, &'a T, Option<usize>, bool);
78 83
79impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T> 84impl<'a, DB, T> fmt::Display for HirDisplayWrapper<'a, DB, T>
80where 85where
@@ -88,6 +93,7 @@ where
88 buf: String::with_capacity(20), 93 buf: String::with_capacity(20),
89 curr_size: 0, 94 curr_size: 0,
90 max_size: self.2, 95 max_size: self.2,
96 should_display_default_types: self.3,
91 }) 97 })
92 } 98 }
93} 99}
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs
index 5c65f9370..f752a9f09 100644
--- a/crates/ra_hir_ty/src/expr.rs
+++ b/crates/ra_hir_ty/src/expr.rs
@@ -3,7 +3,7 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 path::{known, Path}, 6 path::{path, Path},
7 resolver::HasResolver, 7 resolver::HasResolver,
8 AdtId, FunctionId, 8 AdtId, FunctionId,
9}; 9};
@@ -97,7 +97,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
97 let (_, source_map) = db.body_with_source_map(self.func.into()); 97 let (_, source_map) = db.body_with_source_map(self.func.into());
98 98
99 if let Some(source_ptr) = source_map.expr_syntax(id) { 99 if let Some(source_ptr) = source_map.expr_syntax(id) {
100 if let Some(expr) = source_ptr.value.a() { 100 if let Some(expr) = source_ptr.value.left() {
101 let root = source_ptr.file_syntax(db); 101 let root = source_ptr.file_syntax(db);
102 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) { 102 if let ast::Expr::RecordLit(record_lit) = expr.to_node(&root) {
103 if let Some(field_list) = record_lit.record_field_list() { 103 if let Some(field_list) = record_lit.record_field_list() {
@@ -124,7 +124,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
124 None => return, 124 None => return,
125 }; 125 };
126 126
127 let std_result_path = known::std_result_result(); 127 let std_result_path = path![std::result::Result];
128 128
129 let resolver = self.func.resolver(db); 129 let resolver = self.func.resolver(db);
130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) { 130 let std_result_enum = match resolver.resolve_known_enum(db, &std_result_path) {
@@ -142,7 +142,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
142 let (_, source_map) = db.body_with_source_map(self.func.into()); 142 let (_, source_map) = db.body_with_source_map(self.func.into());
143 143
144 if let Some(source_ptr) = source_map.expr_syntax(id) { 144 if let Some(source_ptr) = source_map.expr_syntax(id) {
145 if let Some(expr) = source_ptr.value.a() { 145 if let Some(expr) = source_ptr.value.left() {
146 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr }); 146 self.sink.push(MissingOkInTailExpr { file: source_ptr.file_id, expr });
147 } 147 }
148 } 148 }
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index 1e9f4b208..e97b81473 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -18,19 +18,18 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
22use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
23 22
24use hir_def::{ 23use hir_def::{
25 body::Body, 24 body::Body,
26 data::{ConstData, FunctionData}, 25 data::{ConstData, FunctionData},
27 expr::{BindingAnnotation, ExprId, PatId}, 26 expr::{BindingAnnotation, ExprId, PatId},
28 path::{known, Path}, 27 path::{path, Path},
29 resolver::{HasResolver, Resolver, TypeNs}, 28 resolver::{HasResolver, Resolver, TypeNs},
30 type_ref::{Mutability, TypeRef}, 29 type_ref::{Mutability, TypeRef},
31 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId, 30 AdtId, AssocItemId, DefWithBodyId, FunctionId, StructFieldId, TypeAliasId, VariantId,
32}; 31};
33use hir_expand::{diagnostics::DiagnosticSink, name}; 32use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 33use ra_arena::map::ArenaMap;
35use ra_prof::profile; 34use ra_prof::profile;
36use test_utils::tested_by; 35use test_utils::tested_by;
@@ -43,6 +42,8 @@ use super::{
43}; 42};
44use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; 43use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic};
45 44
45pub(crate) use unify::unify;
46
46macro_rules! ty_app { 47macro_rules! ty_app {
47 ($ctor:pat, $param:pat) => { 48 ($ctor:pat, $param:pat) => {
48 crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param }) 49 crate::Ty::Apply(crate::ApplicationTy { ctor: $ctor, parameters: $param })
@@ -191,11 +192,16 @@ struct InferenceContext<'a, D: HirDatabase> {
191 owner: DefWithBodyId, 192 owner: DefWithBodyId,
192 body: Arc<Body>, 193 body: Arc<Body>,
193 resolver: Resolver, 194 resolver: Resolver,
194 var_unification_table: InPlaceUnificationTable<TypeVarId>, 195 table: unify::InferenceTable,
195 trait_env: Arc<TraitEnvironment>, 196 trait_env: Arc<TraitEnvironment>,
196 obligations: Vec<Obligation>, 197 obligations: Vec<Obligation>,
197 result: InferenceResult, 198 result: InferenceResult,
198 /// The return type of the function being inferred. 199 /// The return type of the function being inferred, or the closure if we're
200 /// currently within one.
201 ///
202 /// We might consider using a nested inference context for checking
203 /// closures, but currently this is the only field that will change there,
204 /// so it doesn't make sense.
199 return_ty: Ty, 205 return_ty: Ty,
200 206
201 /// Impls of `CoerceUnsized` used in coercion. 207 /// Impls of `CoerceUnsized` used in coercion.
@@ -209,7 +215,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
209 fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self { 215 fn new(db: &'a D, owner: DefWithBodyId, resolver: Resolver) -> Self {
210 InferenceContext { 216 InferenceContext {
211 result: InferenceResult::default(), 217 result: InferenceResult::default(),
212 var_unification_table: InPlaceUnificationTable::new(), 218 table: unify::InferenceTable::new(),
213 obligations: Vec::default(), 219 obligations: Vec::default(),
214 return_ty: Ty::Unknown, // set in collect_fn_signature 220 return_ty: Ty::Unknown, // set in collect_fn_signature
215 trait_env: TraitEnvironment::lower(db, &resolver), 221 trait_env: TraitEnvironment::lower(db, &resolver),
@@ -224,13 +230,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
224 fn resolve_all(mut self) -> InferenceResult { 230 fn resolve_all(mut self) -> InferenceResult {
225 // FIXME resolve obligations as well (use Guidance if necessary) 231 // FIXME resolve obligations as well (use Guidance if necessary)
226 let mut result = mem::replace(&mut self.result, InferenceResult::default()); 232 let mut result = mem::replace(&mut self.result, InferenceResult::default());
227 let mut tv_stack = Vec::new();
228 for ty in result.type_of_expr.values_mut() { 233 for ty in result.type_of_expr.values_mut() {
229 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); 234 let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
230 *ty = resolved; 235 *ty = resolved;
231 } 236 }
232 for ty in result.type_of_pat.values_mut() { 237 for ty in result.type_of_pat.values_mut() {
233 let resolved = self.resolve_ty_completely(&mut tv_stack, mem::replace(ty, Ty::Unknown)); 238 let resolved = self.table.resolve_ty_completely(mem::replace(ty, Ty::Unknown));
234 *ty = resolved; 239 *ty = resolved;
235 } 240 }
236 result 241 result
@@ -275,96 +280,38 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
275 self.normalize_associated_types_in(ty) 280 self.normalize_associated_types_in(ty)
276 } 281 }
277 282
278 fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool { 283 /// Replaces `impl Trait` in `ty` by type variables and obligations for
279 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) 284 /// those variables. This is done for function arguments when calling a
280 } 285 /// function, and for return types when inside the function body, i.e. in
281 286 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
282 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 287 /// Trait` is represented by `Ty::Opaque`.
283 self.unify_inner(ty1, ty2, 0) 288 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
284 } 289 ty.fold(&mut |ty| match ty {
285 290 Ty::Opaque(preds) => {
286 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 291 tested_by!(insert_vars_for_impl_trait);
287 if depth > 1000 { 292 let var = self.table.new_type_var();
288 // prevent stackoverflows 293 let var_subst = Substs::builder(1).push(var.clone()).build();
289 panic!("infinite recursion in unification"); 294 self.obligations.extend(
290 } 295 preds
291 if ty1 == ty2 { 296 .iter()
292 return true; 297 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
293 } 298 .filter_map(Obligation::from_predicate),
294 // try to resolve type vars first 299 );
295 let ty1 = self.resolve_ty_shallow(ty1); 300 var
296 let ty2 = self.resolve_ty_shallow(ty2);
297 match (&*ty1, &*ty2) {
298 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
299 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
300 }
301 _ => self.unify_inner_trivial(&ty1, &ty2),
302 }
303 }
304
305 fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
306 match (ty1, ty2) {
307 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
308
309 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
310 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
311 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
312 | (
313 Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)),
314 Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)),
315 ) => {
316 // both type vars are unknown since we tried to resolve them
317 self.var_unification_table.union(*tv1, *tv2);
318 true
319 }
320
321 // The order of MaybeNeverTypeVar matters here.
322 // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar.
323 // Unifying MaybeNeverTypeVar and other concrete type will let the former become it.
324 (Ty::Infer(InferTy::TypeVar(tv)), other)
325 | (other, Ty::Infer(InferTy::TypeVar(tv)))
326 | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other)
327 | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv)))
328 | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_)))
329 | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv)))
330 | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_)))
331 | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => {
332 // the type var is unknown since we tried to resolve it
333 self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
334 true
335 } 301 }
336 302 _ => ty,
337 _ => false, 303 })
338 }
339 }
340
341 fn new_type_var(&mut self) -> Ty {
342 Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
343 }
344
345 fn new_integer_var(&mut self) -> Ty {
346 Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
347 }
348
349 fn new_float_var(&mut self) -> Ty {
350 Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
351 }
352
353 fn new_maybe_never_type_var(&mut self) -> Ty {
354 Ty::Infer(InferTy::MaybeNeverTypeVar(
355 self.var_unification_table.new_key(TypeVarValue::Unknown),
356 ))
357 } 304 }
358 305
359 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 306 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
360 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 307 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
361 match ty { 308 match ty {
362 Ty::Unknown => self.new_type_var(), 309 Ty::Unknown => self.table.new_type_var(),
363 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => { 310 Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(Uncertain::Unknown), .. }) => {
364 self.new_integer_var() 311 self.table.new_integer_var()
365 } 312 }
366 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => { 313 Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(Uncertain::Unknown), .. }) => {
367 self.new_float_var() 314 self.table.new_float_var()
368 } 315 }
369 _ => ty, 316 _ => ty,
370 } 317 }
@@ -402,64 +349,52 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
402 } 349 }
403 } 350 }
404 351
352 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
353 self.table.unify(ty1, ty2)
354 }
355
405 /// Resolves the type as far as currently possible, replacing type variables 356 /// Resolves the type as far as currently possible, replacing type variables
406 /// by their known types. All types returned by the infer_* functions should 357 /// by their known types. All types returned by the infer_* functions should
407 /// be resolved as far as possible, i.e. contain no type variables with 358 /// be resolved as far as possible, i.e. contain no type variables with
408 /// known type. 359 /// known type.
409 fn resolve_ty_as_possible(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 360 fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
410 self.resolve_obligations_as_possible(); 361 self.resolve_obligations_as_possible();
411 362
412 ty.fold(&mut |ty| match ty { 363 self.table.resolve_ty_as_possible(ty)
413 Ty::Infer(tv) => {
414 let inner = tv.to_inner();
415 if tv_stack.contains(&inner) {
416 tested_by!(type_var_cycles_resolve_as_possible);
417 // recursive type
418 return tv.fallback_value();
419 }
420 if let Some(known_ty) =
421 self.var_unification_table.inlined_probe_value(inner).known()
422 {
423 // known_ty may contain other variables that are known by now
424 tv_stack.push(inner);
425 let result = self.resolve_ty_as_possible(tv_stack, known_ty.clone());
426 tv_stack.pop();
427 result
428 } else {
429 ty
430 }
431 }
432 _ => ty,
433 })
434 } 364 }
435 365
436 /// If `ty` is a type variable with known type, returns that type;
437 /// otherwise, return ty.
438 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> { 366 fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
439 let mut ty = Cow::Borrowed(ty); 367 self.table.resolve_ty_shallow(ty)
440 // The type variable could resolve to a int/float variable. Hence try 368 }
441 // resolving up to three times; each type of variable shouldn't occur 369
442 // more than once 370 fn resolve_associated_type(&mut self, inner_ty: Ty, assoc_ty: Option<TypeAliasId>) -> Ty {
443 for i in 0..3 { 371 self.resolve_associated_type_with_params(inner_ty, assoc_ty, &[])
444 if i > 0 { 372 }
445 tested_by!(type_var_resolves_to_int_var); 373
446 } 374 fn resolve_associated_type_with_params(
447 match &*ty { 375 &mut self,
448 Ty::Infer(tv) => { 376 inner_ty: Ty,
449 let inner = tv.to_inner(); 377 assoc_ty: Option<TypeAliasId>,
450 match self.var_unification_table.inlined_probe_value(inner).known() { 378 params: &[Ty],
451 Some(known_ty) => { 379 ) -> Ty {
452 // The known_ty can't be a type var itself 380 match assoc_ty {
453 ty = Cow::Owned(known_ty.clone()); 381 Some(res_assoc_ty) => {
454 } 382 let ty = self.table.new_type_var();
455 _ => return ty, 383 let builder = Substs::build_for_def(self.db, res_assoc_ty)
456 } 384 .push(inner_ty)
457 } 385 .fill(params.iter().cloned());
458 _ => return ty, 386 let projection = ProjectionPredicate {
387 ty: ty.clone(),
388 projection_ty: ProjectionTy {
389 associated_ty: res_assoc_ty,
390 parameters: builder.build(),
391 },
392 };
393 self.obligations.push(Obligation::Projection(projection));
394 self.resolve_ty_as_possible(ty)
459 } 395 }
396 None => Ty::Unknown,
460 } 397 }
461 log::error!("Inference variable still not resolved: {:?}", ty);
462 ty
463 } 398 }
464 399
465 /// Recurses through the given type, normalizing associated types mentioned 400 /// Recurses through the given type, normalizing associated types mentioned
@@ -469,7 +404,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
469 /// call). `make_ty` handles this already, but e.g. for field types we need 404 /// call). `make_ty` handles this already, but e.g. for field types we need
470 /// to do it as well. 405 /// to do it as well.
471 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 406 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
472 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 407 let ty = self.resolve_ty_as_possible(ty);
473 ty.fold(&mut |ty| match ty { 408 ty.fold(&mut |ty| match ty {
474 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty), 409 Ty::Projection(proj_ty) => self.normalize_projection_ty(proj_ty),
475 _ => ty, 410 _ => ty,
@@ -477,40 +412,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
477 } 412 }
478 413
479 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 414 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
480 let var = self.new_type_var(); 415 let var = self.table.new_type_var();
481 let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() }; 416 let predicate = ProjectionPredicate { projection_ty: proj_ty, ty: var.clone() };
482 let obligation = Obligation::Projection(predicate); 417 let obligation = Obligation::Projection(predicate);
483 self.obligations.push(obligation); 418 self.obligations.push(obligation);
484 var 419 var
485 } 420 }
486 421
487 /// Resolves the type completely; type variables without known type are
488 /// replaced by Ty::Unknown.
489 fn resolve_ty_completely(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
490 ty.fold(&mut |ty| match ty {
491 Ty::Infer(tv) => {
492 let inner = tv.to_inner();
493 if tv_stack.contains(&inner) {
494 tested_by!(type_var_cycles_resolve_completely);
495 // recursive type
496 return tv.fallback_value();
497 }
498 if let Some(known_ty) =
499 self.var_unification_table.inlined_probe_value(inner).known()
500 {
501 // known_ty may contain other variables that are known by now
502 tv_stack.push(inner);
503 let result = self.resolve_ty_completely(tv_stack, known_ty.clone());
504 tv_stack.pop();
505 result
506 } else {
507 tv.fallback_value()
508 }
509 }
510 _ => ty,
511 })
512 }
513
514 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) { 422 fn resolve_variant(&mut self, path: Option<&Path>) -> (Ty, Option<VariantId>) {
515 let path = match path { 423 let path = match path {
516 Some(path) => path, 424 Some(path) => path,
@@ -519,7 +427,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
519 let resolver = &self.resolver; 427 let resolver = &self.resolver;
520 // FIXME: this should resolve assoc items as well, see this example: 428 // FIXME: this should resolve assoc items as well, see this example:
521 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 429 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
522 match resolver.resolve_path_in_type_ns_fully(self.db, &path) { 430 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
523 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 431 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
524 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); 432 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into());
525 let ty = self.db.ty(strukt.into()); 433 let ty = self.db.ty(strukt.into());
@@ -547,93 +455,90 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
547 455
548 self.infer_pat(*pat, &ty, BindingMode::default()); 456 self.infer_pat(*pat, &ty, BindingMode::default());
549 } 457 }
550 self.return_ty = self.make_ty(&data.ret_type); 458 let return_ty = self.make_ty(&data.ret_type);
459 self.return_ty = self.insert_vars_for_impl_trait(return_ty);
551 } 460 }
552 461
553 fn infer_body(&mut self) { 462 fn infer_body(&mut self) {
554 self.infer_expr(self.body.body_expr, &Expectation::has_type(self.return_ty.clone())); 463 self.infer_expr_coerce(self.body.body_expr, &Expectation::has_type(self.return_ty.clone()));
555 } 464 }
556 465
557 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { 466 fn resolve_into_iter_item(&self) -> Option<TypeAliasId> {
558 let path = known::std_iter_into_iterator(); 467 let path = path![std::iter::IntoIterator];
559 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 468 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
560 self.db.trait_data(trait_).associated_type_by_name(&name::ITEM_TYPE) 469 self.db.trait_data(trait_).associated_type_by_name(&name![Item])
561 } 470 }
562 471
563 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { 472 fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> {
564 let path = known::std_ops_try(); 473 let path = path![std::ops::Try];
474 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
475 self.db.trait_data(trait_).associated_type_by_name(&name![Ok])
476 }
477
478 fn resolve_ops_neg_output(&self) -> Option<TypeAliasId> {
479 let path = path![std::ops::Neg];
480 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
481 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
482 }
483
484 fn resolve_ops_not_output(&self) -> Option<TypeAliasId> {
485 let path = path![std::ops::Not];
565 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 486 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
566 self.db.trait_data(trait_).associated_type_by_name(&name::OK_TYPE) 487 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
567 } 488 }
568 489
569 fn resolve_future_future_output(&self) -> Option<TypeAliasId> { 490 fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
570 let path = known::std_future_future(); 491 let path = path![std::future::Future];
571 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?; 492 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
572 self.db.trait_data(trait_).associated_type_by_name(&name::OUTPUT_TYPE) 493 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
573 } 494 }
574 495
575 fn resolve_boxed_box(&self) -> Option<AdtId> { 496 fn resolve_boxed_box(&self) -> Option<AdtId> {
576 let path = known::std_boxed_box(); 497 let path = path![std::boxed::Box];
577 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?; 498 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
578 Some(struct_.into()) 499 Some(struct_.into())
579 } 500 }
580}
581
582/// The ID of a type variable.
583#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
584pub struct TypeVarId(pub(super) u32);
585
586impl UnifyKey for TypeVarId {
587 type Value = TypeVarValue;
588 501
589 fn index(&self) -> u32 { 502 fn resolve_range_full(&self) -> Option<AdtId> {
590 self.0 503 let path = path![std::ops::RangeFull];
504 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
505 Some(struct_.into())
591 } 506 }
592 507
593 fn from_index(i: u32) -> Self { 508 fn resolve_range(&self) -> Option<AdtId> {
594 TypeVarId(i) 509 let path = path![std::ops::Range];
510 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
511 Some(struct_.into())
595 } 512 }
596 513
597 fn tag() -> &'static str { 514 fn resolve_range_inclusive(&self) -> Option<AdtId> {
598 "TypeVarId" 515 let path = path![std::ops::RangeInclusive];
516 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
517 Some(struct_.into())
599 } 518 }
600}
601
602/// The value of a type variable: either we already know the type, or we don't
603/// know it yet.
604#[derive(Clone, PartialEq, Eq, Debug)]
605pub enum TypeVarValue {
606 Known(Ty),
607 Unknown,
608}
609 519
610impl TypeVarValue { 520 fn resolve_range_from(&self) -> Option<AdtId> {
611 fn known(&self) -> Option<&Ty> { 521 let path = path![std::ops::RangeFrom];
612 match self { 522 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
613 TypeVarValue::Known(ty) => Some(ty), 523 Some(struct_.into())
614 TypeVarValue::Unknown => None,
615 }
616 } 524 }
617}
618 525
619impl UnifyValue for TypeVarValue { 526 fn resolve_range_to(&self) -> Option<AdtId> {
620 type Error = NoError; 527 let path = path![std::ops::RangeTo];
621 528 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
622 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> { 529 Some(struct_.into())
623 match (value1, value2) { 530 }
624 // We should never equate two type variables, both of which have
625 // known types. Instead, we recursively equate those types.
626 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
627 "equating two type variables, both of which have known types: {:?} and {:?}",
628 t1, t2
629 ),
630 531
631 // If one side is known, prefer that one. 532 fn resolve_range_to_inclusive(&self) -> Option<AdtId> {
632 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()), 533 let path = path![std::ops::RangeToInclusive];
633 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()), 534 let struct_ = self.resolver.resolve_known_struct(self.db, &path)?;
535 Some(struct_.into())
536 }
634 537
635 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown), 538 fn resolve_ops_index_output(&self) -> Option<TypeAliasId> {
636 } 539 let path = path![std::ops::Index];
540 let trait_ = self.resolver.resolve_known_trait(self.db, &path)?;
541 self.db.trait_data(trait_).associated_type_by_name(&name![Output])
637 } 542 }
638} 543}
639 544
@@ -643,14 +548,14 @@ impl UnifyValue for TypeVarValue {
643/// several integer types). 548/// several integer types).
644#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)] 549#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
645pub enum InferTy { 550pub enum InferTy {
646 TypeVar(TypeVarId), 551 TypeVar(unify::TypeVarId),
647 IntVar(TypeVarId), 552 IntVar(unify::TypeVarId),
648 FloatVar(TypeVarId), 553 FloatVar(unify::TypeVarId),
649 MaybeNeverTypeVar(TypeVarId), 554 MaybeNeverTypeVar(unify::TypeVarId),
650} 555}
651 556
652impl InferTy { 557impl InferTy {
653 fn to_inner(self) -> TypeVarId { 558 fn to_inner(self) -> unify::TypeVarId {
654 match self { 559 match self {
655 InferTy::TypeVar(ty) 560 InferTy::TypeVar(ty)
656 | InferTy::IntVar(ty) 561 | InferTy::IntVar(ty)
@@ -693,7 +598,7 @@ impl Expectation {
693} 598}
694 599
695mod diagnostics { 600mod diagnostics {
696 use hir_def::{expr::ExprId, FunctionId, HasSource, Lookup}; 601 use hir_def::{expr::ExprId, src::HasSource, FunctionId, Lookup};
697 use hir_expand::diagnostics::DiagnosticSink; 602 use hir_expand::diagnostics::DiagnosticSink;
698 603
699 use crate::{db::HirDatabase, diagnostics::NoSuchField}; 604 use crate::{db::HirDatabase, diagnostics::NoSuchField};
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 719a0f395..83c0c2c3f 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -8,9 +8,9 @@ use hir_def::{lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutabilit
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use test_utils::tested_by; 9use test_utils::tested_by;
10 10
11use crate::{autoderef, db::HirDatabase, ImplTy, Substs, Ty, TypeCtor, TypeWalk}; 11use crate::{autoderef, db::HirDatabase, Substs, Ty, TypeCtor, TypeWalk};
12 12
13use super::{InEnvironment, InferTy, InferenceContext, TypeVarValue}; 13use super::{unify::TypeVarValue, InEnvironment, InferTy, InferenceContext};
14 14
15impl<'a, D: HirDatabase> InferenceContext<'a, D> { 15impl<'a, D: HirDatabase> InferenceContext<'a, D> {
16 /// Unify two types, but may coerce the first one to the second one 16 /// Unify two types, but may coerce the first one to the second one
@@ -54,10 +54,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
54 impls 54 impls
55 .iter() 55 .iter()
56 .filter_map(|&impl_id| { 56 .filter_map(|&impl_id| {
57 let trait_ref = match db.impl_ty(impl_id) { 57 let trait_ref = db.impl_trait(impl_id)?;
58 ImplTy::TraitRef(it) => it,
59 ImplTy::Inherent(_) => return None,
60 };
61 58
62 // `CoerseUnsized` has one generic parameter for the target type. 59 // `CoerseUnsized` has one generic parameter for the target type.
63 let cur_from_ty = trait_ref.substs.0.get(0)?; 60 let cur_from_ty = trait_ref.substs.0.get(0)?;
@@ -88,8 +85,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
88 match (&from_ty, to_ty) { 85 match (&from_ty, to_ty) {
89 // Never type will make type variable to fallback to Never Type instead of Unknown. 86 // Never type will make type variable to fallback to Never Type instead of Unknown.
90 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => { 87 (ty_app!(TypeCtor::Never), Ty::Infer(InferTy::TypeVar(tv))) => {
91 let var = self.new_maybe_never_type_var(); 88 let var = self.table.new_maybe_never_type_var();
92 self.var_unification_table.union_value(*tv, TypeVarValue::Known(var)); 89 self.table.var_unification_table.union_value(*tv, TypeVarValue::Known(var));
93 return true; 90 return true;
94 } 91 }
95 (ty_app!(TypeCtor::Never), _) => return true, 92 (ty_app!(TypeCtor::Never), _) => return true,
@@ -97,7 +94,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
97 // Trivial cases, this should go after `never` check to 94 // Trivial cases, this should go after `never` check to
98 // avoid infer result type to be never 95 // avoid infer result type to be never
99 _ => { 96 _ => {
100 if self.unify_inner_trivial(&from_ty, &to_ty) { 97 if self.table.unify_inner_trivial(&from_ty, &to_ty) {
101 return true; 98 return true;
102 } 99 }
103 } 100 }
@@ -137,6 +134,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
137 } 134 }
138 } 135 }
139 136
137 (ty_app!(TypeCtor::Closure { .. }, params), ty_app!(TypeCtor::FnPtr { .. })) => {
138 from_ty = params[0].clone();
139 }
140
140 _ => {} 141 _ => {}
141 } 142 }
142 143
@@ -333,9 +334,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
333 // Stop when constructor matches. 334 // Stop when constructor matches.
334 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => { 335 (ty_app!(from_ctor, st1), ty_app!(to_ctor, st2)) if from_ctor == to_ctor => {
335 // It will not recurse to `coerce`. 336 // It will not recurse to `coerce`.
336 return self.unify_substs(st1, st2, 0); 337 return self.table.unify_substs(st1, st2, 0);
338 }
339 _ => {
340 if self.table.unify_inner_trivial(&derefed_ty, &to_ty) {
341 return true;
342 }
337 } 343 }
338 _ => {}
339 } 344 }
340 } 345 }
341 346
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 2f9ca4bbb..3af05394c 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -6,17 +6,21 @@ use std::sync::Arc;
6use hir_def::{ 6use hir_def::{
7 builtin_type::Signedness, 7 builtin_type::Signedness,
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 generics::GenericParams,
10 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
11 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
12 AdtId, ContainerId, Lookup, StructFieldId, 11 AdtId, AssocContainerId, Lookup, StructFieldId,
13}; 12};
14use hir_expand::name::{self, Name}; 13use hir_expand::name::{name, Name};
14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
17 autoderef, db::HirDatabase, method_resolution, op, traits::InEnvironment, utils::variant_data, 17 autoderef,
18 CallableDef, InferTy, IntTy, Mutability, Obligation, ProjectionPredicate, ProjectionTy, Substs, 18 db::HirDatabase,
19 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 19 method_resolution, op,
20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics},
22 ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty,
23 TypeCtor, TypeWalk, Uncertain,
20}; 24};
21 25
22use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -31,13 +35,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
31 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() }, 35 TypeMismatch { expected: expected.ty.clone(), actual: ty.clone() },
32 ); 36 );
33 } 37 }
34 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 38 let ty = self.resolve_ty_as_possible(ty);
35 ty 39 ty
36 } 40 }
37 41
38 /// Infer type of expression with possibly implicit coerce to the expected type. 42 /// Infer type of expression with possibly implicit coerce to the expected type.
39 /// Return the type after possible coercion. 43 /// Return the type after possible coercion.
40 fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty { 44 pub(super) fn infer_expr_coerce(&mut self, expr: ExprId, expected: &Expectation) -> Ty {
41 let ty = self.infer_expr_inner(expr, &expected); 45 let ty = self.infer_expr_inner(expr, &expected);
42 let ty = if !self.coerce(&ty, &expected.ty) { 46 let ty = if !self.coerce(&ty, &expected.ty) {
43 self.result 47 self.result
@@ -52,7 +56,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
52 expected.ty.clone() 56 expected.ty.clone()
53 }; 57 };
54 58
55 self.resolve_ty_as_possible(&mut vec![], ty) 59 self.resolve_ty_as_possible(ty)
56 } 60 }
57 61
58 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 62 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
@@ -91,27 +95,14 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
91 Expr::For { iterable, body, pat } => { 95 Expr::For { iterable, body, pat } => {
92 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 96 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
93 97
94 let pat_ty = match self.resolve_into_iter_item() { 98 let pat_ty =
95 Some(into_iter_item_alias) => { 99 self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item());
96 let pat_ty = self.new_type_var();
97 let projection = ProjectionPredicate {
98 ty: pat_ty.clone(),
99 projection_ty: ProjectionTy {
100 associated_ty: into_iter_item_alias,
101 parameters: Substs::single(iterable_ty),
102 },
103 };
104 self.obligations.push(Obligation::Projection(projection));
105 self.resolve_ty_as_possible(&mut vec![], pat_ty)
106 }
107 None => Ty::Unknown,
108 };
109 100
110 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 101 self.infer_pat(*pat, &pat_ty, BindingMode::default());
111 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 102 self.infer_expr(*body, &Expectation::has_type(Ty::unit()));
112 Ty::unit() 103 Ty::unit()
113 } 104 }
114 Expr::Lambda { body, args, arg_types } => { 105 Expr::Lambda { body, args, ret_type, arg_types } => {
115 assert_eq!(args.len(), arg_types.len()); 106 assert_eq!(args.len(), arg_types.len());
116 107
117 let mut sig_tys = Vec::new(); 108 let mut sig_tys = Vec::new();
@@ -127,7 +118,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
127 } 118 }
128 119
129 // add return type 120 // add return type
130 let ret_ty = self.new_type_var(); 121 let ret_ty = match ret_type {
122 Some(type_ref) => self.make_ty(type_ref),
123 None => self.table.new_type_var(),
124 };
131 sig_tys.push(ret_ty.clone()); 125 sig_tys.push(ret_ty.clone());
132 let sig_ty = Ty::apply( 126 let sig_ty = Ty::apply(
133 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, 127 TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 },
@@ -143,7 +137,12 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
143 // infer the body. 137 // infer the body.
144 self.coerce(&closure_ty, &expected.ty); 138 self.coerce(&closure_ty, &expected.ty);
145 139
146 self.infer_expr(*body, &Expectation::has_type(ret_ty)); 140 let prev_ret_ty = std::mem::replace(&mut self.return_ty, ret_ty.clone());
141
142 self.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
143
144 self.return_ty = prev_ret_ty;
145
147 closure_ty 146 closure_ty
148 } 147 }
149 Expr::Call { callee, args } => { 148 Expr::Call { callee, args } => {
@@ -166,7 +165,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
166 Expr::Match { expr, arms } => { 165 Expr::Match { expr, arms } => {
167 let input_ty = self.infer_expr(*expr, &Expectation::none()); 166 let input_ty = self.infer_expr(*expr, &Expectation::none());
168 167
169 let mut result_ty = self.new_maybe_never_type_var(); 168 let mut result_ty = self.table.new_maybe_never_type_var();
170 169
171 for arm in arms { 170 for arm in arms {
172 for &pat in &arm.pats { 171 for &pat in &arm.pats {
@@ -200,7 +199,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
200 } 199 }
201 Expr::Return { expr } => { 200 Expr::Return { expr } => {
202 if let Some(expr) = expr { 201 if let Some(expr) = expr {
203 self.infer_expr(*expr, &Expectation::has_type(self.return_ty.clone())); 202 self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
203 } else {
204 let unit = Ty::unit();
205 self.coerce(&unit, &self.return_ty.clone());
204 } 206 }
205 Ty::simple(TypeCtor::Never) 207 Ty::simple(TypeCtor::Never)
206 } 208 }
@@ -244,7 +246,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
244 ty 246 ty
245 } 247 }
246 Expr::Field { expr, name } => { 248 Expr::Field { expr, name } => {
247 let receiver_ty = self.infer_expr(*expr, &Expectation::none()); 249 let receiver_ty = self.infer_expr_inner(*expr, &Expectation::none());
248 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty); 250 let canonicalized = self.canonicalizer().canonicalize_ty(receiver_ty);
249 let ty = autoderef::autoderef( 251 let ty = autoderef::autoderef(
250 self.db, 252 self.db,
@@ -279,45 +281,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
279 self.normalize_associated_types_in(ty) 281 self.normalize_associated_types_in(ty)
280 } 282 }
281 Expr::Await { expr } => { 283 Expr::Await { expr } => {
282 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 284 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
283 let ty = match self.resolve_future_future_output() { 285 let ty =
284 Some(future_future_output_alias) => { 286 self.resolve_associated_type(inner_ty, self.resolve_future_future_output());
285 let ty = self.new_type_var();
286 let projection = ProjectionPredicate {
287 ty: ty.clone(),
288 projection_ty: ProjectionTy {
289 associated_ty: future_future_output_alias,
290 parameters: Substs::single(inner_ty),
291 },
292 };
293 self.obligations.push(Obligation::Projection(projection));
294 self.resolve_ty_as_possible(&mut vec![], ty)
295 }
296 None => Ty::Unknown,
297 };
298 ty 287 ty
299 } 288 }
300 Expr::Try { expr } => { 289 Expr::Try { expr } => {
301 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 290 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
302 let ty = match self.resolve_ops_try_ok() { 291 let ty = self.resolve_associated_type(inner_ty, self.resolve_ops_try_ok());
303 Some(ops_try_ok_alias) => {
304 let ty = self.new_type_var();
305 let projection = ProjectionPredicate {
306 ty: ty.clone(),
307 projection_ty: ProjectionTy {
308 associated_ty: ops_try_ok_alias,
309 parameters: Substs::single(inner_ty),
310 },
311 };
312 self.obligations.push(Obligation::Projection(projection));
313 self.resolve_ty_as_possible(&mut vec![], ty)
314 }
315 None => Ty::Unknown,
316 };
317 ty 292 ty
318 } 293 }
319 Expr::Cast { expr, type_ref } => { 294 Expr::Cast { expr, type_ref } => {
320 let _inner_ty = self.infer_expr(*expr, &Expectation::none()); 295 let _inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
321 let cast_ty = self.make_ty(type_ref); 296 let cast_ty = self.make_ty(type_ref);
322 // FIXME check the cast... 297 // FIXME check the cast...
323 cast_ty 298 cast_ty
@@ -333,12 +308,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
333 } else { 308 } else {
334 Expectation::none() 309 Expectation::none()
335 }; 310 };
336 // FIXME reference coercions etc. 311 let inner_ty = self.infer_expr_inner(*expr, &expectation);
337 let inner_ty = self.infer_expr(*expr, &expectation);
338 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) 312 Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty)
339 } 313 }
340 Expr::Box { expr } => { 314 Expr::Box { expr } => {
341 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 315 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
342 if let Some(box_) = self.resolve_boxed_box() { 316 if let Some(box_) = self.resolve_boxed_box() {
343 Ty::apply_one(TypeCtor::Adt(box_), inner_ty) 317 Ty::apply_one(TypeCtor::Adt(box_), inner_ty)
344 } else { 318 } else {
@@ -346,7 +320,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
346 } 320 }
347 } 321 }
348 Expr::UnaryOp { expr, op } => { 322 Expr::UnaryOp { expr, op } => {
349 let inner_ty = self.infer_expr(*expr, &Expectation::none()); 323 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
350 match op { 324 match op {
351 UnaryOp::Deref => match self.resolver.krate() { 325 UnaryOp::Deref => match self.resolver.krate() {
352 Some(krate) => { 326 Some(krate) => {
@@ -369,31 +343,36 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
369 }, 343 },
370 UnaryOp::Neg => { 344 UnaryOp::Neg => {
371 match &inner_ty { 345 match &inner_ty {
372 Ty::Apply(a_ty) => match a_ty.ctor { 346 // Fast path for builtins
373 TypeCtor::Int(Uncertain::Unknown) 347 Ty::Apply(ApplicationTy {
374 | TypeCtor::Int(Uncertain::Known(IntTy { 348 ctor:
375 signedness: Signedness::Signed, 349 TypeCtor::Int(Uncertain::Known(IntTy {
376 .. 350 signedness: Signedness::Signed,
377 })) 351 ..
378 | TypeCtor::Float(..) => inner_ty, 352 })),
379 _ => Ty::Unknown, 353 ..
380 }, 354 })
381 Ty::Infer(InferTy::IntVar(..)) | Ty::Infer(InferTy::FloatVar(..)) => { 355 | Ty::Apply(ApplicationTy {
382 inner_ty 356 ctor: TypeCtor::Int(Uncertain::Unknown),
383 } 357 ..
384 // FIXME: resolve ops::Neg trait 358 })
385 _ => Ty::Unknown, 359 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Float(_), .. })
360 | Ty::Infer(InferTy::IntVar(..))
361 | Ty::Infer(InferTy::FloatVar(..)) => inner_ty,
362 // Otherwise we resolve via the std::ops::Neg trait
363 _ => self
364 .resolve_associated_type(inner_ty, self.resolve_ops_neg_output()),
386 } 365 }
387 } 366 }
388 UnaryOp::Not => { 367 UnaryOp::Not => {
389 match &inner_ty { 368 match &inner_ty {
390 Ty::Apply(a_ty) => match a_ty.ctor { 369 // Fast path for builtins
391 TypeCtor::Bool | TypeCtor::Int(_) => inner_ty, 370 Ty::Apply(ApplicationTy { ctor: TypeCtor::Bool, .. })
392 _ => Ty::Unknown, 371 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Int(_), .. })
393 }, 372 | Ty::Infer(InferTy::IntVar(..)) => inner_ty,
394 Ty::Infer(InferTy::IntVar(..)) => inner_ty, 373 // Otherwise we resolve via the std::ops::Not trait
395 // FIXME: resolve ops::Not trait for inner_ty 374 _ => self
396 _ => Ty::Unknown, 375 .resolve_associated_type(inner_ty, self.resolve_ops_not_output()),
397 } 376 }
398 } 377 }
399 } 378 }
@@ -415,21 +394,63 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
415 } 394 }
416 _ => Ty::Unknown, 395 _ => Ty::Unknown,
417 }, 396 },
397 Expr::Range { lhs, rhs, range_type } => {
398 let lhs_ty = lhs.map(|e| self.infer_expr_inner(e, &Expectation::none()));
399 let rhs_expect = lhs_ty
400 .as_ref()
401 .map_or_else(Expectation::none, |ty| Expectation::has_type(ty.clone()));
402 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
403 match (range_type, lhs_ty, rhs_ty) {
404 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
405 Some(adt) => Ty::simple(TypeCtor::Adt(adt)),
406 None => Ty::Unknown,
407 },
408 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
409 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
410 None => Ty::Unknown,
411 },
412 (RangeOp::Inclusive, None, Some(ty)) => {
413 match self.resolve_range_to_inclusive() {
414 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
415 None => Ty::Unknown,
416 }
417 }
418 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
419 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
420 None => Ty::Unknown,
421 },
422 (RangeOp::Inclusive, Some(_), Some(ty)) => {
423 match self.resolve_range_inclusive() {
424 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
425 None => Ty::Unknown,
426 }
427 }
428 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
429 Some(adt) => Ty::apply_one(TypeCtor::Adt(adt), ty),
430 None => Ty::Unknown,
431 },
432 (RangeOp::Inclusive, _, None) => Ty::Unknown,
433 }
434 }
418 Expr::Index { base, index } => { 435 Expr::Index { base, index } => {
419 let _base_ty = self.infer_expr(*base, &Expectation::none()); 436 let base_ty = self.infer_expr_inner(*base, &Expectation::none());
420 let _index_ty = self.infer_expr(*index, &Expectation::none()); 437 let index_ty = self.infer_expr(*index, &Expectation::none());
421 // FIXME: use `std::ops::Index::Output` to figure out the real return type 438
422 Ty::Unknown 439 self.resolve_associated_type_with_params(
440 base_ty,
441 self.resolve_ops_index_output(),
442 &[index_ty],
443 )
423 } 444 }
424 Expr::Tuple { exprs } => { 445 Expr::Tuple { exprs } => {
425 let mut tys = match &expected.ty { 446 let mut tys = match &expected.ty {
426 ty_app!(TypeCtor::Tuple { .. }, st) => st 447 ty_app!(TypeCtor::Tuple { .. }, st) => st
427 .iter() 448 .iter()
428 .cloned() 449 .cloned()
429 .chain(repeat_with(|| self.new_type_var())) 450 .chain(repeat_with(|| self.table.new_type_var()))
430 .take(exprs.len()) 451 .take(exprs.len())
431 .collect::<Vec<_>>(), 452 .collect::<Vec<_>>(),
432 _ => (0..exprs.len()).map(|_| self.new_type_var()).collect(), 453 _ => (0..exprs.len()).map(|_| self.table.new_type_var()).collect(),
433 }; 454 };
434 455
435 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) { 456 for (expr, ty) in exprs.iter().zip(tys.iter_mut()) {
@@ -443,7 +464,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
443 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => { 464 ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
444 st.as_single().clone() 465 st.as_single().clone()
445 } 466 }
446 _ => self.new_type_var(), 467 _ => self.table.new_type_var(),
447 }; 468 };
448 469
449 match array { 470 match array {
@@ -485,7 +506,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
485 }; 506 };
486 // use a new type variable if we got Ty::Unknown here 507 // use a new type variable if we got Ty::Unknown here
487 let ty = self.insert_type_vars_shallow(ty); 508 let ty = self.insert_type_vars_shallow(ty);
488 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 509 let ty = self.resolve_ty_as_possible(ty);
489 self.write_expr_ty(tgt_expr, ty.clone()); 510 self.write_expr_ty(tgt_expr, ty.clone());
490 ty 511 ty
491 } 512 }
@@ -514,7 +535,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
514 } 535 }
515 } 536 }
516 537
517 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 538 let ty = self.resolve_ty_as_possible(ty);
518 self.infer_pat(*pat, &ty, BindingMode::default()); 539 self.infer_pat(*pat, &ty, BindingMode::default());
519 } 540 }
520 Statement::Expr(expr) => { 541 Statement::Expr(expr) => {
@@ -558,7 +579,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
558 Some((ty, func)) => { 579 Some((ty, func)) => {
559 let ty = canonicalized_receiver.decanonicalize_ty(ty); 580 let ty = canonicalized_receiver.decanonicalize_ty(ty);
560 self.write_method_resolution(tgt_expr, func); 581 self.write_method_resolution(tgt_expr, func);
561 (ty, self.db.value_ty(func.into()), Some(self.db.generic_params(func.into()))) 582 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into())))
562 } 583 }
563 None => (receiver_ty, Ty::Unknown, None), 584 None => (receiver_ty, Ty::Unknown, None),
564 }; 585 };
@@ -607,6 +628,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
607 continue; 628 continue;
608 } 629 }
609 630
631 let param_ty = self.insert_vars_for_impl_trait(param_ty);
610 let param_ty = self.normalize_associated_types_in(param_ty); 632 let param_ty = self.normalize_associated_types_in(param_ty);
611 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 633 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
612 } 634 }
@@ -615,17 +637,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
615 637
616 fn substs_for_method_call( 638 fn substs_for_method_call(
617 &mut self, 639 &mut self,
618 def_generics: Option<Arc<GenericParams>>, 640 def_generics: Option<Generics>,
619 generic_args: Option<&GenericArgs>, 641 generic_args: Option<&GenericArgs>,
620 receiver_ty: &Ty, 642 receiver_ty: &Ty,
621 ) -> Substs { 643 ) -> Substs {
622 let (parent_param_count, param_count) = 644 let (total_len, _parent_len, child_len) =
623 def_generics.as_ref().map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 645 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split());
624 let mut substs = Vec::with_capacity(parent_param_count + param_count); 646 let mut substs = Vec::with_capacity(total_len);
625 // Parent arguments are unknown, except for the receiver type 647 // Parent arguments are unknown, except for the receiver type
626 if let Some(parent_generics) = def_generics.and_then(|p| p.parent_params.clone()) { 648 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
627 for param in &parent_generics.params { 649 for (_id, param) in parent_generics {
628 if param.name == name::SELF_TYPE { 650 if param.name == name![Self] {
629 substs.push(receiver_ty.clone()); 651 substs.push(receiver_ty.clone());
630 } else { 652 } else {
631 substs.push(Ty::Unknown); 653 substs.push(Ty::Unknown);
@@ -635,7 +657,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
635 // handle provided type arguments 657 // handle provided type arguments
636 if let Some(generic_args) = generic_args { 658 if let Some(generic_args) = generic_args {
637 // if args are provided, it should be all of them, but we can't rely on that 659 // if args are provided, it should be all of them, but we can't rely on that
638 for arg in generic_args.args.iter().take(param_count) { 660 for arg in generic_args.args.iter().take(child_len) {
639 match arg { 661 match arg {
640 GenericArg::Type(type_ref) => { 662 GenericArg::Type(type_ref) => {
641 let ty = self.make_ty(type_ref); 663 let ty = self.make_ty(type_ref);
@@ -645,10 +667,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
645 } 667 }
646 }; 668 };
647 let supplied_params = substs.len(); 669 let supplied_params = substs.len();
648 for _ in supplied_params..parent_param_count + param_count { 670 for _ in supplied_params..total_len {
649 substs.push(Ty::Unknown); 671 substs.push(Ty::Unknown);
650 } 672 }
651 assert_eq!(substs.len(), parent_param_count + param_count); 673 assert_eq!(substs.len(), total_len);
652 Substs(substs.into()) 674 Substs(substs.into())
653 } 675 }
654 676
@@ -665,13 +687,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
665 // add obligation for trait implementation, if this is a trait method 687 // add obligation for trait implementation, if this is a trait method
666 match def { 688 match def {
667 CallableDef::FunctionId(f) => { 689 CallableDef::FunctionId(f) => {
668 if let ContainerId::TraitId(trait_) = f.lookup(self.db).container { 690 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db).container {
669 // construct a TraitDef 691 // construct a TraitDef
670 let substs = a_ty.parameters.prefix( 692 let substs =
671 self.db 693 a_ty.parameters.prefix(generics(self.db, trait_.into()).len());
672 .generic_params(trait_.into())
673 .count_params_including_parent(),
674 );
675 self.obligations.push(Obligation::Trait(TraitRef { 694 self.obligations.push(Obligation::Trait(TraitRef {
676 trait_: trait_.into(), 695 trait_: trait_.into(),
677 substs, 696 substs,
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index 1ebb36239..a14662884 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -170,7 +170,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
170 } 170 }
171 BindingMode::Move => inner_ty.clone(), 171 BindingMode::Move => inner_ty.clone(),
172 }; 172 };
173 let bound_ty = self.resolve_ty_as_possible(&mut vec![], bound_ty); 173 let bound_ty = self.resolve_ty_as_possible(bound_ty);
174 self.write_pat_ty(pat, bound_ty); 174 self.write_pat_ty(pat, bound_ty);
175 return inner_ty; 175 return inner_ty;
176 } 176 }
@@ -179,7 +179,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
179 // use a new type variable if we got Ty::Unknown here 179 // use a new type variable if we got Ty::Unknown here
180 let ty = self.insert_type_vars_shallow(ty); 180 let ty = self.insert_type_vars_shallow(ty);
181 self.unify(&ty, expected); 181 self.unify(&ty, expected);
182 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 182 let ty = self.resolve_ty_as_possible(ty);
183 self.write_pat_ty(pat, ty.clone()); 183 self.write_pat_ty(pat, ty.clone());
184 ty 184 ty
185 } 185 }
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 14be66836..ffd358367 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -1,9 +1,11 @@
1//! Path expression resolution. 1//! Path expression resolution.
2 2
3use std::iter;
4
3use hir_def::{ 5use hir_def::{
4 path::{Path, PathKind, PathSegment}, 6 path::{Path, PathSegment},
5 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs}, 7 resolver::{ResolveValueResult, Resolver, TypeNs, ValueNs},
6 AssocItemId, ContainerId, Lookup, 8 AssocContainerId, AssocItemId, Lookup,
7}; 9};
8use hir_expand::name::Name; 10use hir_expand::name::Name;
9 11
@@ -30,21 +32,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
30 path: &Path, 32 path: &Path,
31 id: ExprOrPatId, 33 id: ExprOrPatId,
32 ) -> Option<Ty> { 34 ) -> Option<Ty> {
33 let (value, self_subst) = if let PathKind::Type(type_ref) = &path.kind { 35 let (value, self_subst) = if let Some(type_ref) = path.type_anchor() {
34 if path.segments.is_empty() { 36 if path.segments().is_empty() {
35 // This can't actually happen syntax-wise 37 // This can't actually happen syntax-wise
36 return None; 38 return None;
37 } 39 }
38 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
39 let remaining_segments_for_ty = &path.segments[..path.segments.len() - 1]; 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
40 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty);
41 self.resolve_ty_assoc_item( 43 self.resolve_ty_assoc_item(
42 ty, 44 ty,
43 &path.segments.last().expect("path had at least one segment").name, 45 &path.segments().last().expect("path had at least one segment").name,
44 id, 46 id,
45 )? 47 )?
46 } else { 48 } else {
47 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, &path)?; 49 let value_or_partial = resolver.resolve_path_in_value_ns(self.db, path.mod_path())?;
48 50
49 match value_or_partial { 51 match value_or_partial {
50 ResolveValueResult::ValueNs(it) => (it, None), 52 ResolveValueResult::ValueNs(it) => (it, None),
@@ -57,7 +59,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
57 let typable: ValueTyDefId = match value { 59 let typable: ValueTyDefId = match value {
58 ValueNs::LocalBinding(pat) => { 60 ValueNs::LocalBinding(pat) => {
59 let ty = self.result.type_of_pat.get(pat)?.clone(); 61 let ty = self.result.type_of_pat.get(pat)?.clone();
60 let ty = self.resolve_ty_as_possible(&mut vec![], ty); 62 let ty = self.resolve_ty_as_possible(ty);
61 return Some(ty); 63 return Some(ty);
62 } 64 }
63 ValueNs::FunctionId(it) => it.into(), 65 ValueNs::FunctionId(it) => it.into(),
@@ -83,13 +85,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
83 remaining_index: usize, 85 remaining_index: usize,
84 id: ExprOrPatId, 86 id: ExprOrPatId,
85 ) -> Option<(ValueNs, Option<Substs>)> { 87 ) -> Option<(ValueNs, Option<Substs>)> {
86 assert!(remaining_index < path.segments.len()); 88 assert!(remaining_index < path.segments().len());
87 // there may be more intermediate segments between the resolved one and 89 // there may be more intermediate segments between the resolved one and
88 // the end. Only the last segment needs to be resolved to a value; from 90 // the end. Only the last segment needs to be resolved to a value; from
89 // the segments before that, we need to get either a type or a trait ref. 91 // the segments before that, we need to get either a type or a trait ref.
90 92
91 let resolved_segment = &path.segments[remaining_index - 1]; 93 let resolved_segment = path.segments().get(remaining_index - 1).unwrap();
92 let remaining_segments = &path.segments[remaining_index..]; 94 let remaining_segments = path.segments().skip(remaining_index);
93 let is_before_last = remaining_segments.len() == 1; 95 let is_before_last = remaining_segments.len() == 1;
94 96
95 match (def, is_before_last) { 97 match (def, is_before_last) {
@@ -110,7 +112,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
110 // trait but it's not the last segment, so the next segment 112 // trait but it's not the last segment, so the next segment
111 // should resolve to an associated type of that trait (e.g. `<T 113 // should resolve to an associated type of that trait (e.g. `<T
112 // as Iterator>::Item::default`) 114 // as Iterator>::Item::default`)
113 let remaining_segments_for_ty = &remaining_segments[..remaining_segments.len() - 1]; 115 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1);
114 let ty = Ty::from_partly_resolved_hir_path( 117 let ty = Ty::from_partly_resolved_hir_path(
115 self.db, 118 self.db,
116 &self.resolver, 119 &self.resolver,
@@ -136,7 +139,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
136 fn resolve_trait_assoc_item( 139 fn resolve_trait_assoc_item(
137 &mut self, 140 &mut self,
138 trait_ref: TraitRef, 141 trait_ref: TraitRef,
139 segment: &PathSegment, 142 segment: PathSegment<'_>,
140 id: ExprOrPatId, 143 id: ExprOrPatId,
141 ) -> Option<(ValueNs, Option<Substs>)> { 144 ) -> Option<(ValueNs, Option<Substs>)> {
142 let trait_ = trait_ref.trait_; 145 let trait_ = trait_ref.trait_;
@@ -148,7 +151,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
148 .map(|(_name, id)| (*id).into()) 151 .map(|(_name, id)| (*id).into())
149 .find_map(|item| match item { 152 .find_map(|item| match item {
150 AssocItemId::FunctionId(func) => { 153 AssocItemId::FunctionId(func) => {
151 if segment.name == self.db.function_data(func).name { 154 if segment.name == &self.db.function_data(func).name {
152 Some(AssocItemId::FunctionId(func)) 155 Some(AssocItemId::FunctionId(func))
153 } else { 156 } else {
154 None 157 None
@@ -156,7 +159,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
156 } 159 }
157 160
158 AssocItemId::ConstId(konst) => { 161 AssocItemId::ConstId(konst) => {
159 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == &segment.name) 162 if self.db.const_data(konst).name.as_ref().map_or(false, |n| n == segment.name)
160 { 163 {
161 Some(AssocItemId::ConstId(konst)) 164 Some(AssocItemId::ConstId(konst))
162 } else { 165 } else {
@@ -206,12 +209,23 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
206 AssocItemId::TypeAliasId(_) => unreachable!(), 209 AssocItemId::TypeAliasId(_) => unreachable!(),
207 }; 210 };
208 let substs = match container { 211 let substs = match container {
209 ContainerId::ImplId(_) => self.find_self_types(&def, ty.clone()), 212 AssocContainerId::ImplId(impl_id) => {
210 ContainerId::TraitId(trait_) => { 213 let impl_substs = Substs::build_for_def(self.db, impl_id)
214 .fill(iter::repeat_with(|| self.table.new_type_var()))
215 .build();
216 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs);
217 let substs = Substs::build_for_def(self.db, item)
218 .use_parent_substs(&impl_substs)
219 .fill_with_params()
220 .build();
221 self.unify(&impl_self_ty, &ty);
222 Some(substs)
223 }
224 AssocContainerId::TraitId(trait_) => {
211 // we're picking this method 225 // we're picking this method
212 let trait_substs = Substs::build_for_def(self.db, trait_) 226 let trait_substs = Substs::build_for_def(self.db, trait_)
213 .push(ty.clone()) 227 .push(ty.clone())
214 .fill(std::iter::repeat_with(|| self.new_type_var())) 228 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
215 .build(); 229 .build();
216 let substs = Substs::build_for_def(self.db, item) 230 let substs = Substs::build_for_def(self.db, item)
217 .use_parent_substs(&trait_substs) 231 .use_parent_substs(&trait_substs)
@@ -223,7 +237,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
223 })); 237 }));
224 Some(substs) 238 Some(substs)
225 } 239 }
226 ContainerId::ModuleId(_) => None, 240 AssocContainerId::ContainerId(_) => None,
227 }; 241 };
228 242
229 self.write_assoc_resolution(id, item.into()); 243 self.write_assoc_resolution(id, item.into());
@@ -231,38 +245,4 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
231 }, 245 },
232 ) 246 )
233 } 247 }
234
235 fn find_self_types(&self, def: &ValueNs, actual_def_ty: Ty) -> Option<Substs> {
236 if let ValueNs::FunctionId(func) = *def {
237 // We only do the infer if parent has generic params
238 let gen = self.db.generic_params(func.into());
239 if gen.count_parent_params() == 0 {
240 return None;
241 }
242
243 let impl_id = match func.lookup(self.db).container {
244 ContainerId::ImplId(it) => it,
245 _ => return None,
246 };
247 let self_ty = self.db.impl_ty(impl_id).self_type().clone();
248 let self_ty_substs = self_ty.substs()?;
249 let actual_substs = actual_def_ty.substs()?;
250
251 let mut new_substs = vec![Ty::Unknown; gen.count_parent_params()];
252
253 // The following code *link up* the function actual parma type
254 // and impl_block type param index
255 self_ty_substs.iter().zip(actual_substs.iter()).for_each(|(param, pty)| {
256 if let Ty::Param { idx, .. } = param {
257 if let Some(s) = new_substs.get_mut(*idx as usize) {
258 *s = pty.clone();
259 }
260 }
261 });
262
263 Some(Substs(new_substs.into()))
264 } else {
265 None
266 }
267 }
268} 248}
diff --git a/crates/ra_hir_ty/src/infer/unify.rs b/crates/ra_hir_ty/src/infer/unify.rs
index f3a875678..fe05642ae 100644
--- a/crates/ra_hir_ty/src/infer/unify.rs
+++ b/crates/ra_hir_ty/src/infer/unify.rs
@@ -1,9 +1,15 @@
1//! Unification and canonicalization logic. 1//! Unification and canonicalization logic.
2 2
3use std::borrow::Cow;
4
5use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
6
7use test_utils::tested_by;
8
3use super::{InferenceContext, Obligation}; 9use super::{InferenceContext, Obligation};
4use crate::{ 10use crate::{
5 db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate, 11 db::HirDatabase, utils::make_mut_slice, Canonical, InEnvironment, InferTy, ProjectionPredicate,
6 ProjectionTy, Substs, TraitRef, Ty, TypeWalk, 12 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
7}; 13};
8 14
9impl<'a, D: HirDatabase> InferenceContext<'a, D> { 15impl<'a, D: HirDatabase> InferenceContext<'a, D> {
@@ -24,7 +30,7 @@ where
24 /// A stack of type variables that is used to detect recursive types (which 30 /// A stack of type variables that is used to detect recursive types (which
25 /// are an error, but we need to protect against them to avoid stack 31 /// are an error, but we need to protect against them to avoid stack
26 /// overflows). 32 /// overflows).
27 var_stack: Vec<super::TypeVarId>, 33 var_stack: Vec<TypeVarId>,
28} 34}
29 35
30pub(super) struct Canonicalized<T> { 36pub(super) struct Canonicalized<T> {
@@ -53,14 +59,14 @@ where
53 return tv.fallback_value(); 59 return tv.fallback_value();
54 } 60 }
55 if let Some(known_ty) = 61 if let Some(known_ty) =
56 self.ctx.var_unification_table.inlined_probe_value(inner).known() 62 self.ctx.table.var_unification_table.inlined_probe_value(inner).known()
57 { 63 {
58 self.var_stack.push(inner); 64 self.var_stack.push(inner);
59 let result = self.do_canonicalize_ty(known_ty.clone()); 65 let result = self.do_canonicalize_ty(known_ty.clone());
60 self.var_stack.pop(); 66 self.var_stack.pop();
61 result 67 result
62 } else { 68 } else {
63 let root = self.ctx.var_unification_table.find(inner); 69 let root = self.ctx.table.var_unification_table.find(inner);
64 let free_var = match tv { 70 let free_var = match tv {
65 InferTy::TypeVar(_) => InferTy::TypeVar(root), 71 InferTy::TypeVar(_) => InferTy::TypeVar(root),
66 InferTy::IntVar(_) => InferTy::IntVar(root), 72 InferTy::IntVar(_) => InferTy::IntVar(root),
@@ -153,10 +159,268 @@ impl<T> Canonicalized<T> {
153 solution: Canonical<Vec<Ty>>, 159 solution: Canonical<Vec<Ty>>,
154 ) { 160 ) {
155 // the solution may contain new variables, which we need to convert to new inference vars 161 // the solution may contain new variables, which we need to convert to new inference vars
156 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.new_type_var()).collect()); 162 let new_vars = Substs((0..solution.num_vars).map(|_| ctx.table.new_type_var()).collect());
157 for (i, ty) in solution.value.into_iter().enumerate() { 163 for (i, ty) in solution.value.into_iter().enumerate() {
158 let var = self.free_vars[i]; 164 let var = self.free_vars[i];
159 ctx.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars)); 165 ctx.table.unify(&Ty::Infer(var), &ty.subst_bound_vars(&new_vars));
166 }
167 }
168}
169
170pub fn unify(ty1: &Canonical<Ty>, ty2: &Canonical<Ty>) -> Option<Substs> {
171 let mut table = InferenceTable::new();
172 let vars =
173 Substs::builder(ty1.num_vars).fill(std::iter::repeat_with(|| table.new_type_var())).build();
174 let ty_with_vars = ty1.value.clone().subst_bound_vars(&vars);
175 if !table.unify(&ty_with_vars, &ty2.value) {
176 return None;
177 }
178 Some(
179 Substs::builder(ty1.num_vars)
180 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone())))
181 .build(),
182 )
183}
184
185#[derive(Clone, Debug)]
186pub(crate) struct InferenceTable {
187 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
188}
189
190impl InferenceTable {
191 pub fn new() -> Self {
192 InferenceTable { var_unification_table: InPlaceUnificationTable::new() }
193 }
194
195 pub fn new_type_var(&mut self) -> Ty {
196 Ty::Infer(InferTy::TypeVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
197 }
198
199 pub fn new_integer_var(&mut self) -> Ty {
200 Ty::Infer(InferTy::IntVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
201 }
202
203 pub fn new_float_var(&mut self) -> Ty {
204 Ty::Infer(InferTy::FloatVar(self.var_unification_table.new_key(TypeVarValue::Unknown)))
205 }
206
207 pub fn new_maybe_never_type_var(&mut self) -> Ty {
208 Ty::Infer(InferTy::MaybeNeverTypeVar(
209 self.var_unification_table.new_key(TypeVarValue::Unknown),
210 ))
211 }
212
213 pub fn resolve_ty_completely(&mut self, ty: Ty) -> Ty {
214 self.resolve_ty_completely_inner(&mut Vec::new(), ty)
215 }
216
217 pub fn resolve_ty_as_possible(&mut self, ty: Ty) -> Ty {
218 self.resolve_ty_as_possible_inner(&mut Vec::new(), ty)
219 }
220
221 pub fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
222 self.unify_inner(ty1, ty2, 0)
223 }
224
225 pub fn unify_substs(&mut self, substs1: &Substs, substs2: &Substs, depth: usize) -> bool {
226 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth))
227 }
228
229 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
230 if depth > 1000 {
231 // prevent stackoverflows
232 panic!("infinite recursion in unification");
233 }
234 if ty1 == ty2 {
235 return true;
236 }
237 // try to resolve type vars first
238 let ty1 = self.resolve_ty_shallow(ty1);
239 let ty2 = self.resolve_ty_shallow(ty2);
240 match (&*ty1, &*ty2) {
241 (Ty::Apply(a_ty1), Ty::Apply(a_ty2)) if a_ty1.ctor == a_ty2.ctor => {
242 self.unify_substs(&a_ty1.parameters, &a_ty2.parameters, depth + 1)
243 }
244 _ => self.unify_inner_trivial(&ty1, &ty2),
245 }
246 }
247
248 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
249 match (ty1, ty2) {
250 (Ty::Unknown, _) | (_, Ty::Unknown) => true,
251
252 (Ty::Infer(InferTy::TypeVar(tv1)), Ty::Infer(InferTy::TypeVar(tv2)))
253 | (Ty::Infer(InferTy::IntVar(tv1)), Ty::Infer(InferTy::IntVar(tv2)))
254 | (Ty::Infer(InferTy::FloatVar(tv1)), Ty::Infer(InferTy::FloatVar(tv2)))
255 | (
256 Ty::Infer(InferTy::MaybeNeverTypeVar(tv1)),
257 Ty::Infer(InferTy::MaybeNeverTypeVar(tv2)),
258 ) => {
259 // both type vars are unknown since we tried to resolve them
260 self.var_unification_table.union(*tv1, *tv2);
261 true
262 }
263
264 // The order of MaybeNeverTypeVar matters here.
265 // Unifying MaybeNeverTypeVar and TypeVar will let the latter become MaybeNeverTypeVar.
266 // Unifying MaybeNeverTypeVar and other concrete type will let the former become it.
267 (Ty::Infer(InferTy::TypeVar(tv)), other)
268 | (other, Ty::Infer(InferTy::TypeVar(tv)))
269 | (Ty::Infer(InferTy::MaybeNeverTypeVar(tv)), other)
270 | (other, Ty::Infer(InferTy::MaybeNeverTypeVar(tv)))
271 | (Ty::Infer(InferTy::IntVar(tv)), other @ ty_app!(TypeCtor::Int(_)))
272 | (other @ ty_app!(TypeCtor::Int(_)), Ty::Infer(InferTy::IntVar(tv)))
273 | (Ty::Infer(InferTy::FloatVar(tv)), other @ ty_app!(TypeCtor::Float(_)))
274 | (other @ ty_app!(TypeCtor::Float(_)), Ty::Infer(InferTy::FloatVar(tv))) => {
275 // the type var is unknown since we tried to resolve it
276 self.var_unification_table.union_value(*tv, TypeVarValue::Known(other.clone()));
277 true
278 }
279
280 _ => false,
281 }
282 }
283
284 /// If `ty` is a type variable with known type, returns that type;
285 /// otherwise, return ty.
286 pub fn resolve_ty_shallow<'b>(&mut self, ty: &'b Ty) -> Cow<'b, Ty> {
287 let mut ty = Cow::Borrowed(ty);
288 // The type variable could resolve to a int/float variable. Hence try
289 // resolving up to three times; each type of variable shouldn't occur
290 // more than once
291 for i in 0..3 {
292 if i > 0 {
293 tested_by!(type_var_resolves_to_int_var);
294 }
295 match &*ty {
296 Ty::Infer(tv) => {
297 let inner = tv.to_inner();
298 match self.var_unification_table.inlined_probe_value(inner).known() {
299 Some(known_ty) => {
300 // The known_ty can't be a type var itself
301 ty = Cow::Owned(known_ty.clone());
302 }
303 _ => return ty,
304 }
305 }
306 _ => return ty,
307 }
308 }
309 log::error!("Inference variable still not resolved: {:?}", ty);
310 ty
311 }
312
313 /// Resolves the type as far as currently possible, replacing type variables
314 /// by their known types. All types returned by the infer_* functions should
315 /// be resolved as far as possible, i.e. contain no type variables with
316 /// known type.
317 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
318 ty.fold(&mut |ty| match ty {
319 Ty::Infer(tv) => {
320 let inner = tv.to_inner();
321 if tv_stack.contains(&inner) {
322 tested_by!(type_var_cycles_resolve_as_possible);
323 // recursive type
324 return tv.fallback_value();
325 }
326 if let Some(known_ty) =
327 self.var_unification_table.inlined_probe_value(inner).known()
328 {
329 // known_ty may contain other variables that are known by now
330 tv_stack.push(inner);
331 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
332 tv_stack.pop();
333 result
334 } else {
335 ty
336 }
337 }
338 _ => ty,
339 })
340 }
341
342 /// Resolves the type completely; type variables without known type are
343 /// replaced by Ty::Unknown.
344 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
345 ty.fold(&mut |ty| match ty {
346 Ty::Infer(tv) => {
347 let inner = tv.to_inner();
348 if tv_stack.contains(&inner) {
349 tested_by!(type_var_cycles_resolve_completely);
350 // recursive type
351 return tv.fallback_value();
352 }
353 if let Some(known_ty) =
354 self.var_unification_table.inlined_probe_value(inner).known()
355 {
356 // known_ty may contain other variables that are known by now
357 tv_stack.push(inner);
358 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
359 tv_stack.pop();
360 result
361 } else {
362 tv.fallback_value()
363 }
364 }
365 _ => ty,
366 })
367 }
368}
369
370/// The ID of a type variable.
371#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
372pub struct TypeVarId(pub(super) u32);
373
374impl UnifyKey for TypeVarId {
375 type Value = TypeVarValue;
376
377 fn index(&self) -> u32 {
378 self.0
379 }
380
381 fn from_index(i: u32) -> Self {
382 TypeVarId(i)
383 }
384
385 fn tag() -> &'static str {
386 "TypeVarId"
387 }
388}
389
390/// The value of a type variable: either we already know the type, or we don't
391/// know it yet.
392#[derive(Clone, PartialEq, Eq, Debug)]
393pub enum TypeVarValue {
394 Known(Ty),
395 Unknown,
396}
397
398impl TypeVarValue {
399 fn known(&self) -> Option<&Ty> {
400 match self {
401 TypeVarValue::Known(ty) => Some(ty),
402 TypeVarValue::Unknown => None,
403 }
404 }
405}
406
407impl UnifyValue for TypeVarValue {
408 type Error = NoError;
409
410 fn unify_values(value1: &Self, value2: &Self) -> Result<Self, NoError> {
411 match (value1, value2) {
412 // We should never equate two type variables, both of which have
413 // known types. Instead, we recursively equate those types.
414 (TypeVarValue::Known(t1), TypeVarValue::Known(t2)) => panic!(
415 "equating two type variables, both of which have known types: {:?} and {:?}",
416 t1, t2
417 ),
418
419 // If one side is known, prefer that one.
420 (TypeVarValue::Known(..), TypeVarValue::Unknown) => Ok(value1.clone()),
421 (TypeVarValue::Unknown, TypeVarValue::Known(..)) => Ok(value2.clone()),
422
423 (TypeVarValue::Unknown, TypeVarValue::Unknown) => Ok(TypeVarValue::Unknown),
160 } 424 }
161 } 425 }
162} 426}
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index b45c8f82f..48abf97c9 100644
--- a/crates/ra_hir_ty/src/lib.rs
+++ b/crates/ra_hir_ty/src/lib.rs
@@ -44,8 +44,8 @@ use std::sync::Arc;
44use std::{fmt, iter, mem}; 44use std::{fmt, iter, mem};
45 45
46use hir_def::{ 46use hir_def::{
47 expr::ExprId, generics::GenericParams, type_ref::Mutability, AdtId, ContainerId, DefWithBodyId, 47 expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId,
48 GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, 48 HasModule, Lookup, TraitId, TypeAliasId,
49}; 49};
50use hir_expand::name::Name; 50use hir_expand::name::Name;
51use ra_db::{impl_intern_key, salsa, CrateId}; 51use ra_db::{impl_intern_key, salsa, CrateId};
@@ -53,7 +53,7 @@ use ra_db::{impl_intern_key, salsa, CrateId};
53use crate::{ 53use crate::{
54 db::HirDatabase, 54 db::HirDatabase,
55 primitive::{FloatTy, IntTy, Uncertain}, 55 primitive::{FloatTy, IntTy, Uncertain},
56 utils::make_mut_slice, 56 utils::{generics, make_mut_slice, Generics},
57}; 57};
58use display::{HirDisplay, HirFormatter}; 58use display::{HirDisplay, HirFormatter};
59 59
@@ -166,16 +166,16 @@ impl TypeCtor {
166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure 166 | TypeCtor::Closure { .. } // 1 param representing the signature of the closure
167 => 1, 167 => 1,
168 TypeCtor::Adt(adt) => { 168 TypeCtor::Adt(adt) => {
169 let generic_params = db.generic_params(AdtId::from(adt).into()); 169 let generic_params = generics(db, AdtId::from(adt).into());
170 generic_params.count_params_including_parent() 170 generic_params.len()
171 } 171 }
172 TypeCtor::FnDef(callable) => { 172 TypeCtor::FnDef(callable) => {
173 let generic_params = db.generic_params(callable.into()); 173 let generic_params = generics(db, callable.into());
174 generic_params.count_params_including_parent() 174 generic_params.len()
175 } 175 }
176 TypeCtor::AssociatedType(type_alias) => { 176 TypeCtor::AssociatedType(type_alias) => {
177 let generic_params = db.generic_params(type_alias.into()); 177 let generic_params = generics(db, type_alias.into());
178 generic_params.count_params_including_parent() 178 generic_params.len()
179 } 179 }
180 TypeCtor::FnPtr { num_args } => num_args as usize + 1, 180 TypeCtor::FnPtr { num_args } => num_args as usize + 1,
181 TypeCtor::Tuple { cardinality } => cardinality as usize, 181 TypeCtor::Tuple { cardinality } => cardinality as usize,
@@ -251,7 +251,7 @@ impl ProjectionTy {
251 251
252 fn trait_(&self, db: &impl HirDatabase) -> TraitId { 252 fn trait_(&self, db: &impl HirDatabase) -> TraitId {
253 match self.associated_ty.lookup(db).container { 253 match self.associated_ty.lookup(db).container {
254 ContainerId::TraitId(it) => it, 254 AssocContainerId::TraitId(it) => it,
255 _ => panic!("projection ty without parent trait"), 255 _ => panic!("projection ty without parent trait"),
256 } 256 }
257 } 257 }
@@ -364,36 +364,26 @@ impl Substs {
364 } 364 }
365 365
366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`). 366 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
367 pub fn identity(generic_params: &GenericParams) -> Substs { 367 pub(crate) fn identity(generic_params: &Generics) -> Substs {
368 Substs( 368 Substs(
369 generic_params 369 generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(),
370 .params_including_parent()
371 .into_iter()
372 .map(|p| Ty::Param { idx: p.idx, name: p.name.clone() })
373 .collect(),
374 ) 370 )
375 } 371 }
376 372
377 /// Return Substs that replace each parameter by a bound variable. 373 /// Return Substs that replace each parameter by a bound variable.
378 pub fn bound_vars(generic_params: &GenericParams) -> Substs { 374 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
379 Substs( 375 Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect())
380 generic_params
381 .params_including_parent()
382 .into_iter()
383 .map(|p| Ty::Bound(p.idx))
384 .collect(),
385 )
386 } 376 }
387 377
388 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { 378 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
389 let def = def.into(); 379 let def = def.into();
390 let params = db.generic_params(def); 380 let params = generics(db, def);
391 let param_count = params.count_params_including_parent(); 381 let param_count = params.len();
392 Substs::builder(param_count) 382 Substs::builder(param_count)
393 } 383 }
394 384
395 pub fn build_for_generics(generic_params: &GenericParams) -> SubstsBuilder { 385 pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder {
396 Substs::builder(generic_params.count_params_including_parent()) 386 Substs::builder(generic_params.len())
397 } 387 }
398 388
399 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder { 389 pub fn build_for_type_ctor(db: &impl HirDatabase, type_ctor: TypeCtor) -> SubstsBuilder {
@@ -486,21 +476,6 @@ impl TypeWalk for TraitRef {
486 } 476 }
487} 477}
488 478
489#[derive(Clone, PartialEq, Eq, Debug)]
490pub enum ImplTy {
491 Inherent(Ty),
492 TraitRef(TraitRef),
493}
494
495impl ImplTy {
496 pub(crate) fn self_type(&self) -> &Ty {
497 match self {
498 ImplTy::Inherent(it) => it,
499 ImplTy::TraitRef(tr) => &tr.substs[0],
500 }
501 }
502}
503
504/// Like `generics::WherePredicate`, but with resolved types: A condition on the 479/// Like `generics::WherePredicate`, but with resolved types: A condition on the
505/// parameters of a generic item. 480/// parameters of a generic item.
506#[derive(Debug, Clone, PartialEq, Eq, Hash)] 481#[derive(Debug, Clone, PartialEq, Eq, Hash)]
@@ -931,13 +906,44 @@ impl HirDisplay for ApplicationTy {
931 write!(f, "{}", name)?; 906 write!(f, "{}", name)?;
932 if self.parameters.len() > 0 { 907 if self.parameters.len() > 0 {
933 write!(f, "<")?; 908 write!(f, "<")?;
934 f.write_joined(&*self.parameters.0, ", ")?; 909
910 let mut non_default_parameters = Vec::with_capacity(self.parameters.len());
911 let parameters_to_write = if f.should_display_default_types() {
912 self.parameters.0.as_ref()
913 } else {
914 match self
915 .ctor
916 .as_generic_def()
917 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
918 .filter(|defaults| !defaults.is_empty())
919 {
920 Option::None => self.parameters.0.as_ref(),
921 Option::Some(default_parameters) => {
922 for (i, parameter) in self.parameters.iter().enumerate() {
923 match (parameter, default_parameters.get(i)) {
924 (&Ty::Unknown, _) | (_, None) => {
925 non_default_parameters.push(parameter.clone())
926 }
927 (_, Some(default_parameter))
928 if parameter != default_parameter =>
929 {
930 non_default_parameters.push(parameter.clone())
931 }
932 _ => (),
933 }
934 }
935 &non_default_parameters
936 }
937 }
938 };
939
940 f.write_joined(parameters_to_write, ", ")?;
935 write!(f, ">")?; 941 write!(f, ">")?;
936 } 942 }
937 } 943 }
938 TypeCtor::AssociatedType(type_alias) => { 944 TypeCtor::AssociatedType(type_alias) => {
939 let trait_ = match type_alias.lookup(f.db).container { 945 let trait_ = match type_alias.lookup(f.db).container {
940 ContainerId::TraitId(it) => it, 946 AssocContainerId::TraitId(it) => it,
941 _ => panic!("not an associated type"), 947 _ => panic!("not an associated type"),
942 }; 948 };
943 let trait_name = f.db.trait_data(trait_).name.clone(); 949 let trait_name = f.db.trait_data(trait_).name.clone();
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 091c60f4f..af3db2e1d 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -11,10 +11,10 @@ use std::sync::Arc;
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::WherePredicate,
14 path::{GenericArg, Path, PathKind, PathSegment}, 14 path::{GenericArg, Path, PathSegment, PathSegments},
15 resolver::{HasResolver, Resolver, TypeNs}, 15 resolver::{HasResolver, Resolver, TypeNs},
16 type_ref::{TypeBound, TypeRef}, 16 type_ref::{TypeBound, TypeRef},
17 AdtId, AstItemDef, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, 17 AdtId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId,
18 LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId, 18 LocalStructFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, UnionId, VariantId,
19}; 19};
20use ra_arena::map::ArenaMap; 20use ra_arena::map::ArenaMap;
@@ -24,11 +24,11 @@ use crate::{
24 db::HirDatabase, 24 db::HirDatabase,
25 primitive::{FloatTy, IntTy}, 25 primitive::{FloatTy, IntTy},
26 utils::{ 26 utils::{
27 all_super_traits, associated_type_by_name_including_super_traits, make_mut_slice, 27 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
28 variant_data, 28 variant_data,
29 }, 29 },
30 FnSig, GenericPredicate, ImplTy, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, 30 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef,
31 TraitRef, Ty, TypeCtor, TypeWalk, 31 Ty, TypeCtor, TypeWalk,
32}; 32};
33 33
34impl Ty { 34impl Ty {
@@ -101,17 +101,19 @@ impl Ty {
101 TypeRef::Path(path) => path, 101 TypeRef::Path(path) => path,
102 _ => return None, 102 _ => return None,
103 }; 103 };
104 if let PathKind::Type(_) = &path.kind { 104 if path.type_anchor().is_some() {
105 return None; 105 return None;
106 } 106 }
107 if path.segments.len() > 1 { 107 if path.segments().len() > 1 {
108 return None; 108 return None;
109 } 109 }
110 let resolution = match resolver.resolve_path_in_type_ns(db, path) { 110 let resolution = match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
111 Some((it, None)) => it, 111 Some((it, None)) => it,
112 _ => return None, 112 _ => return None,
113 }; 113 };
114 if let TypeNs::GenericParam(idx) = resolution { 114 if let TypeNs::GenericParam(param_id) = resolution {
115 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
116 let idx = generics.param_idx(param_id);
115 Some(idx) 117 Some(idx)
116 } else { 118 } else {
117 None 119 None
@@ -122,11 +124,11 @@ impl Ty {
122 db: &impl HirDatabase, 124 db: &impl HirDatabase,
123 resolver: &Resolver, 125 resolver: &Resolver,
124 ty: Ty, 126 ty: Ty,
125 remaining_segments: &[PathSegment], 127 remaining_segments: PathSegments<'_>,
126 ) -> Ty { 128 ) -> Ty {
127 if remaining_segments.len() == 1 { 129 if remaining_segments.len() == 1 {
128 // resolve unselected assoc types 130 // resolve unselected assoc types
129 let segment = &remaining_segments[0]; 131 let segment = remaining_segments.first().unwrap();
130 Ty::select_associated_type(db, resolver, ty, segment) 132 Ty::select_associated_type(db, resolver, ty, segment)
131 } else if remaining_segments.len() > 1 { 133 } else if remaining_segments.len() > 1 {
132 // FIXME report error (ambiguous associated type) 134 // FIXME report error (ambiguous associated type)
@@ -140,15 +142,15 @@ impl Ty {
140 db: &impl HirDatabase, 142 db: &impl HirDatabase,
141 resolver: &Resolver, 143 resolver: &Resolver,
142 resolution: TypeNs, 144 resolution: TypeNs,
143 resolved_segment: &PathSegment, 145 resolved_segment: PathSegment<'_>,
144 remaining_segments: &[PathSegment], 146 remaining_segments: PathSegments<'_>,
145 ) -> Ty { 147 ) -> Ty {
146 let ty = match resolution { 148 let ty = match resolution {
147 TypeNs::TraitId(trait_) => { 149 TypeNs::TraitId(trait_) => {
148 let trait_ref = 150 let trait_ref =
149 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); 151 TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None);
150 return if remaining_segments.len() == 1 { 152 return if remaining_segments.len() == 1 {
151 let segment = &remaining_segments[0]; 153 let segment = remaining_segments.first().unwrap();
152 let associated_ty = associated_type_by_name_including_super_traits( 154 let associated_ty = associated_type_by_name_including_super_traits(
153 db, 155 db,
154 trait_ref.trait_, 156 trait_ref.trait_,
@@ -174,12 +176,14 @@ impl Ty {
174 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) 176 Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)]))
175 }; 177 };
176 } 178 }
177 TypeNs::GenericParam(idx) => { 179 TypeNs::GenericParam(param_id) => {
180 let generics = generics(db, resolver.generic_def().expect("generics in scope"));
181 let idx = generics.param_idx(param_id);
178 // FIXME: maybe return name in resolution? 182 // FIXME: maybe return name in resolution?
179 let name = resolved_segment.name.clone(); 183 let name = generics.param_name(param_id);
180 Ty::Param { idx, name } 184 Ty::Param { idx, name }
181 } 185 }
182 TypeNs::SelfType(impl_id) => db.impl_ty(impl_id).self_type().clone(), 186 TypeNs::SelfType(impl_id) => db.impl_self_ty(impl_id).clone(),
183 TypeNs::AdtSelfType(adt) => db.ty(adt.into()), 187 TypeNs::AdtSelfType(adt) => db.ty(adt.into()),
184 188
185 TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), 189 TypeNs::AdtId(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()),
@@ -198,21 +202,21 @@ impl Ty {
198 202
199 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { 203 pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty {
200 // Resolve the path (in type namespace) 204 // Resolve the path (in type namespace)
201 if let PathKind::Type(type_ref) = &path.kind { 205 if let Some(type_ref) = path.type_anchor() {
202 let ty = Ty::from_hir(db, resolver, &type_ref); 206 let ty = Ty::from_hir(db, resolver, &type_ref);
203 let remaining_segments = &path.segments[..]; 207 return Ty::from_type_relative_path(db, resolver, ty, path.segments());
204 return Ty::from_type_relative_path(db, resolver, ty, remaining_segments);
205 } 208 }
206 let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { 209 let (resolution, remaining_index) =
207 Some(it) => it, 210 match resolver.resolve_path_in_type_ns(db, path.mod_path()) {
208 None => return Ty::Unknown, 211 Some(it) => it,
209 }; 212 None => return Ty::Unknown,
213 };
210 let (resolved_segment, remaining_segments) = match remaining_index { 214 let (resolved_segment, remaining_segments) = match remaining_index {
211 None => ( 215 None => (
212 path.segments.last().expect("resolved path has at least one element"), 216 path.segments().last().expect("resolved path has at least one element"),
213 &[] as &[PathSegment], 217 PathSegments::EMPTY,
214 ), 218 ),
215 Some(i) => (&path.segments[i - 1], &path.segments[i..]), 219 Some(i) => (path.segments().get(i - 1).unwrap(), path.segments().skip(i)),
216 }; 220 };
217 Ty::from_partly_resolved_hir_path( 221 Ty::from_partly_resolved_hir_path(
218 db, 222 db,
@@ -227,7 +231,7 @@ impl Ty {
227 db: &impl HirDatabase, 231 db: &impl HirDatabase,
228 resolver: &Resolver, 232 resolver: &Resolver,
229 self_ty: Ty, 233 self_ty: Ty,
230 segment: &PathSegment, 234 segment: PathSegment<'_>,
231 ) -> Ty { 235 ) -> Ty {
232 let param_idx = match self_ty { 236 let param_idx = match self_ty {
233 Ty::Param { idx, .. } => idx, 237 Ty::Param { idx, .. } => idx,
@@ -257,7 +261,7 @@ impl Ty {
257 fn from_hir_path_inner( 261 fn from_hir_path_inner(
258 db: &impl HirDatabase, 262 db: &impl HirDatabase,
259 resolver: &Resolver, 263 resolver: &Resolver,
260 segment: &PathSegment, 264 segment: PathSegment<'_>,
261 typable: TyDefId, 265 typable: TyDefId,
262 ) -> Ty { 266 ) -> Ty {
263 let generic_def = match typable { 267 let generic_def = match typable {
@@ -280,7 +284,7 @@ impl Ty {
280 // special-case enum variants 284 // special-case enum variants
281 resolved: ValueTyDefId, 285 resolved: ValueTyDefId,
282 ) -> Substs { 286 ) -> Substs {
283 let last = path.segments.last().expect("path should have at least one segment"); 287 let last = path.segments().last().expect("path should have at least one segment");
284 let (segment, generic_def) = match resolved { 288 let (segment, generic_def) = match resolved {
285 ValueTyDefId::FunctionId(it) => (last, Some(it.into())), 289 ValueTyDefId::FunctionId(it) => (last, Some(it.into())),
286 ValueTyDefId::StructId(it) => (last, Some(it.into())), 290 ValueTyDefId::StructId(it) => (last, Some(it.into())),
@@ -292,13 +296,11 @@ impl Ty {
292 // referring to the variant. So `Option::<T>::None` and 296 // referring to the variant. So `Option::<T>::None` and
293 // `Option::None::<T>` are both allowed (though the former is 297 // `Option::None::<T>` are both allowed (though the former is
294 // preferred). See also `def_ids_for_path_segments` in rustc. 298 // preferred). See also `def_ids_for_path_segments` in rustc.
295 let len = path.segments.len(); 299 let len = path.segments().len();
296 let segment = if len >= 2 && path.segments[len - 2].args_and_bindings.is_some() { 300 let penultimate = if len >= 2 { path.segments().get(len - 2) } else { None };
297 // Option::<T>::None 301 let segment = match penultimate {
298 &path.segments[len - 2] 302 Some(segment) if segment.args_and_bindings.is_some() => segment,
299 } else { 303 _ => last,
300 // Option::None::<T>
301 last
302 }; 304 };
303 (segment, Some(var.parent.into())) 305 (segment, Some(var.parent.into()))
304 } 306 }
@@ -310,16 +312,15 @@ impl Ty {
310pub(super) fn substs_from_path_segment( 312pub(super) fn substs_from_path_segment(
311 db: &impl HirDatabase, 313 db: &impl HirDatabase,
312 resolver: &Resolver, 314 resolver: &Resolver,
313 segment: &PathSegment, 315 segment: PathSegment<'_>,
314 def_generic: Option<GenericDefId>, 316 def_generic: Option<GenericDefId>,
315 add_self_param: bool, 317 add_self_param: bool,
316) -> Substs { 318) -> Substs {
317 let mut substs = Vec::new(); 319 let mut substs = Vec::new();
318 let def_generics = def_generic.map(|def| db.generic_params(def.into())); 320 let def_generics = def_generic.map(|def| generics(db, def.into()));
319 321
320 let (parent_param_count, param_count) = 322 let (total_len, parent_len, child_len) = def_generics.map_or((0, 0, 0), |g| g.len_split());
321 def_generics.map_or((0, 0), |g| (g.count_parent_params(), g.params.len())); 323 substs.extend(iter::repeat(Ty::Unknown).take(parent_len));
322 substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count));
323 if add_self_param { 324 if add_self_param {
324 // FIXME this add_self_param argument is kind of a hack: Traits have the 325 // FIXME this add_self_param argument is kind of a hack: Traits have the
325 // Self type as an implicit first type parameter, but it can't be 326 // Self type as an implicit first type parameter, but it can't be
@@ -330,8 +331,8 @@ pub(super) fn substs_from_path_segment(
330 if let Some(generic_args) = &segment.args_and_bindings { 331 if let Some(generic_args) = &segment.args_and_bindings {
331 // if args are provided, it should be all of them, but we can't rely on that 332 // if args are provided, it should be all of them, but we can't rely on that
332 let self_param_correction = if add_self_param { 1 } else { 0 }; 333 let self_param_correction = if add_self_param { 1 } else { 0 };
333 let param_count = param_count - self_param_correction; 334 let child_len = child_len + self_param_correction;
334 for arg in generic_args.args.iter().take(param_count) { 335 for arg in generic_args.args.iter().take(child_len) {
335 match arg { 336 match arg {
336 GenericArg::Type(type_ref) => { 337 GenericArg::Type(type_ref) => {
337 let ty = Ty::from_hir(db, resolver, type_ref); 338 let ty = Ty::from_hir(db, resolver, type_ref);
@@ -342,10 +343,10 @@ pub(super) fn substs_from_path_segment(
342 } 343 }
343 // add placeholders for args that were not provided 344 // add placeholders for args that were not provided
344 let supplied_params = substs.len(); 345 let supplied_params = substs.len();
345 for _ in supplied_params..parent_param_count + param_count { 346 for _ in supplied_params..total_len {
346 substs.push(Ty::Unknown); 347 substs.push(Ty::Unknown);
347 } 348 }
348 assert_eq!(substs.len(), parent_param_count + param_count); 349 assert_eq!(substs.len(), total_len);
349 350
350 // handle defaults 351 // handle defaults
351 if let Some(def_generic) = def_generic { 352 if let Some(def_generic) = def_generic {
@@ -369,11 +370,11 @@ impl TraitRef {
369 path: &Path, 370 path: &Path,
370 explicit_self_ty: Option<Ty>, 371 explicit_self_ty: Option<Ty>,
371 ) -> Option<Self> { 372 ) -> Option<Self> {
372 let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { 373 let resolved = match resolver.resolve_path_in_type_ns_fully(db, path.mod_path())? {
373 TypeNs::TraitId(tr) => tr, 374 TypeNs::TraitId(tr) => tr,
374 _ => return None, 375 _ => return None,
375 }; 376 };
376 let segment = path.segments.last().expect("path should have at least one segment"); 377 let segment = path.segments().last().expect("path should have at least one segment");
377 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty)) 378 Some(TraitRef::from_resolved_path(db, resolver, resolved.into(), segment, explicit_self_ty))
378 } 379 }
379 380
@@ -381,7 +382,7 @@ impl TraitRef {
381 db: &impl HirDatabase, 382 db: &impl HirDatabase,
382 resolver: &Resolver, 383 resolver: &Resolver,
383 resolved: TraitId, 384 resolved: TraitId,
384 segment: &PathSegment, 385 segment: PathSegment<'_>,
385 explicit_self_ty: Option<Ty>, 386 explicit_self_ty: Option<Ty>,
386 ) -> Self { 387 ) -> Self {
387 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved); 388 let mut substs = TraitRef::substs_from_path(db, resolver, segment, resolved);
@@ -407,7 +408,7 @@ impl TraitRef {
407 fn substs_from_path( 408 fn substs_from_path(
408 db: &impl HirDatabase, 409 db: &impl HirDatabase,
409 resolver: &Resolver, 410 resolver: &Resolver,
410 segment: &PathSegment, 411 segment: PathSegment<'_>,
411 resolved: TraitId, 412 resolved: TraitId,
412 ) -> Substs { 413 ) -> Substs {
413 let has_self_param = 414 let has_self_param =
@@ -461,12 +462,12 @@ fn assoc_type_bindings_from_type_bound<'a>(
461 trait_ref: TraitRef, 462 trait_ref: TraitRef,
462) -> impl Iterator<Item = GenericPredicate> + 'a { 463) -> impl Iterator<Item = GenericPredicate> + 'a {
463 let last_segment = match bound { 464 let last_segment = match bound {
464 TypeBound::Path(path) => path.segments.last(), 465 TypeBound::Path(path) => path.segments().last(),
465 TypeBound::Error => None, 466 TypeBound::Error => None,
466 }; 467 };
467 last_segment 468 last_segment
468 .into_iter() 469 .into_iter()
469 .flat_map(|segment| segment.args_and_bindings.iter()) 470 .flat_map(|segment| segment.args_and_bindings.into_iter())
470 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) 471 .flat_map(|args_and_bindings| args_and_bindings.bindings.iter())
471 .map(move |(name, type_ref)| { 472 .map(move |(name, type_ref)| {
472 let associated_ty = 473 let associated_ty =
@@ -532,6 +533,15 @@ pub(crate) fn generic_predicates_for_param_query(
532 .collect() 533 .collect()
533} 534}
534 535
536pub(crate) fn generic_predicates_for_param_recover(
537 _db: &impl HirDatabase,
538 _cycle: &[String],
539 _def: &GenericDefId,
540 _param_idx: &u32,
541) -> Arc<[GenericPredicate]> {
542 Arc::new([])
543}
544
535impl TraitEnvironment { 545impl TraitEnvironment {
536 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> { 546 pub fn lower(db: &impl HirDatabase, resolver: &Resolver) -> Arc<TraitEnvironment> {
537 let predicates = resolver 547 let predicates = resolver
@@ -558,12 +568,11 @@ pub(crate) fn generic_predicates_query(
558/// Resolve the default type params from generics 568/// Resolve the default type params from generics
559pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs { 569pub(crate) fn generic_defaults_query(db: &impl HirDatabase, def: GenericDefId) -> Substs {
560 let resolver = def.resolver(db); 570 let resolver = def.resolver(db);
561 let generic_params = db.generic_params(def.into()); 571 let generic_params = generics(db, def.into());
562 572
563 let defaults = generic_params 573 let defaults = generic_params
564 .params_including_parent() 574 .iter()
565 .into_iter() 575 .map(|(_idx, p)| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
566 .map(|p| p.default.as_ref().map_or(Ty::Unknown, |t| Ty::from_hir(db, &resolver, t)))
567 .collect(); 576 .collect();
568 577
569 Substs(defaults) 578 Substs(defaults)
@@ -580,7 +589,7 @@ fn fn_sig_for_fn(db: &impl HirDatabase, def: FunctionId) -> FnSig {
580/// Build the declared type of a function. This should not need to look at the 589/// Build the declared type of a function. This should not need to look at the
581/// function body. 590/// function body.
582fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty { 591fn type_for_fn(db: &impl HirDatabase, def: FunctionId) -> Ty {
583 let generics = db.generic_params(def.into()); 592 let generics = generics(db, def.into());
584 let substs = Substs::identity(&generics); 593 let substs = Substs::identity(&generics);
585 Ty::apply(TypeCtor::FnDef(def.into()), substs) 594 Ty::apply(TypeCtor::FnDef(def.into()), substs)
586} 595}
@@ -630,7 +639,7 @@ fn type_for_struct_constructor(db: &impl HirDatabase, def: StructId) -> Ty {
630 if struct_data.variant_data.is_unit() { 639 if struct_data.variant_data.is_unit() {
631 return type_for_adt(db, def.into()); // Unit struct 640 return type_for_adt(db, def.into()); // Unit struct
632 } 641 }
633 let generics = db.generic_params(def.into()); 642 let generics = generics(db, def.into());
634 let substs = Substs::identity(&generics); 643 let substs = Substs::identity(&generics);
635 Ty::apply(TypeCtor::FnDef(def.into()), substs) 644 Ty::apply(TypeCtor::FnDef(def.into()), substs)
636} 645}
@@ -644,7 +653,7 @@ fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId
644 .iter() 653 .iter()
645 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) 654 .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
646 .collect::<Vec<_>>(); 655 .collect::<Vec<_>>();
647 let generics = db.generic_params(def.parent.into()); 656 let generics = generics(db, def.parent.into());
648 let substs = Substs::identity(&generics); 657 let substs = Substs::identity(&generics);
649 let ret = type_for_adt(db, def.parent.into()).subst(&substs); 658 let ret = type_for_adt(db, def.parent.into()).subst(&substs);
650 FnSig::from_params_and_return(params, ret) 659 FnSig::from_params_and_return(params, ret)
@@ -657,18 +666,18 @@ fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariantId)
657 if var_data.is_unit() { 666 if var_data.is_unit() {
658 return type_for_adt(db, def.parent.into()); // Unit variant 667 return type_for_adt(db, def.parent.into()); // Unit variant
659 } 668 }
660 let generics = db.generic_params(def.parent.into()); 669 let generics = generics(db, def.parent.into());
661 let substs = Substs::identity(&generics); 670 let substs = Substs::identity(&generics);
662 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs) 671 Ty::apply(TypeCtor::FnDef(EnumVariantId::from(def).into()), substs)
663} 672}
664 673
665fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty { 674fn type_for_adt(db: &impl HirDatabase, adt: AdtId) -> Ty {
666 let generics = db.generic_params(adt.into()); 675 let generics = generics(db, adt.into());
667 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics)) 676 Ty::apply(TypeCtor::Adt(adt), Substs::identity(&generics))
668} 677}
669 678
670fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty { 679fn type_for_type_alias(db: &impl HirDatabase, t: TypeAliasId) -> Ty {
671 let generics = db.generic_params(t.into()); 680 let generics = generics(db, t.into());
672 let resolver = t.resolver(db); 681 let resolver = t.resolver(db);
673 let type_ref = &db.type_alias_data(t).type_ref; 682 let type_ref = &db.type_alias_data(t).type_ref;
674 let substs = Substs::identity(&generics); 683 let substs = Substs::identity(&generics);
@@ -687,10 +696,11 @@ impl_froms!(CallableDef: FunctionId, StructId, EnumVariantId);
687impl CallableDef { 696impl CallableDef {
688 pub fn krate(self, db: &impl HirDatabase) -> CrateId { 697 pub fn krate(self, db: &impl HirDatabase) -> CrateId {
689 match self { 698 match self {
690 CallableDef::FunctionId(f) => f.lookup(db).module(db).krate, 699 CallableDef::FunctionId(f) => f.lookup(db).module(db),
691 CallableDef::StructId(s) => s.module(db).krate, 700 CallableDef::StructId(s) => s.lookup(db).container.module(db),
692 CallableDef::EnumVariantId(e) => e.parent.module(db).krate, 701 CallableDef::EnumVariantId(e) => e.parent.lookup(db).container.module(db),
693 } 702 }
703 .krate
694 } 704 }
695} 705}
696 706
@@ -733,6 +743,11 @@ pub(crate) fn ty_query(db: &impl HirDatabase, def: TyDefId) -> Ty {
733 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), 743 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
734 } 744 }
735} 745}
746
747pub(crate) fn ty_recover(_db: &impl HirDatabase, _cycle: &[String], _def: &TyDefId) -> Ty {
748 Ty::Unknown
749}
750
736pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty { 751pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
737 match def { 752 match def {
738 ValueTyDefId::FunctionId(it) => type_for_fn(db, it), 753 ValueTyDefId::FunctionId(it) => type_for_fn(db, it),
@@ -743,17 +758,24 @@ pub(crate) fn value_ty_query(db: &impl HirDatabase, def: ValueTyDefId) -> Ty {
743 } 758 }
744} 759}
745 760
746pub(crate) fn impl_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> ImplTy { 761pub(crate) fn impl_self_ty_query(db: &impl HirDatabase, impl_id: ImplId) -> Ty {
747 let impl_data = db.impl_data(impl_id); 762 let impl_data = db.impl_data(impl_id);
748 let resolver = impl_id.resolver(db); 763 let resolver = impl_id.resolver(db);
749 let self_ty = Ty::from_hir(db, &resolver, &impl_data.target_type); 764 Ty::from_hir(db, &resolver, &impl_data.target_type)
750 match impl_data.target_trait.as_ref() { 765}
751 Some(trait_ref) => { 766
752 match TraitRef::from_hir(db, &resolver, trait_ref, Some(self_ty.clone())) { 767pub(crate) fn impl_self_ty_recover(
753 Some(it) => ImplTy::TraitRef(it), 768 _db: &impl HirDatabase,
754 None => ImplTy::Inherent(self_ty), 769 _cycle: &[String],
755 } 770 _impl_id: &ImplId,
756 } 771) -> Ty {
757 None => ImplTy::Inherent(self_ty), 772 Ty::Unknown
758 } 773}
774
775pub(crate) fn impl_trait_query(db: &impl HirDatabase, impl_id: ImplId) -> Option<TraitRef> {
776 let impl_data = db.impl_data(impl_id);
777 let resolver = impl_id.resolver(db);
778 let self_ty = db.impl_self_ty(impl_id);
779 let target_trait = impl_data.target_trait.as_ref()?;
780 TraitRef::from_hir(db, &resolver, target_trait, Some(self_ty.clone()))
759} 781}
diff --git a/crates/ra_hir_ty/src/marks.rs b/crates/ra_hir_ty/src/marks.rs
index 0f754eb9c..fe74acf11 100644
--- a/crates/ra_hir_ty/src/marks.rs
+++ b/crates/ra_hir_ty/src/marks.rs
@@ -6,4 +6,5 @@ test_utils::marks!(
6 type_var_resolves_to_int_var 6 type_var_resolves_to_int_var
7 match_ergonomics_ref 7 match_ergonomics_ref
8 coerce_merge_fail_fallback 8 coerce_merge_fail_fallback
9 insert_vars_for_impl_trait
9); 10);
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs
index ee1936b0e..888dc3116 100644
--- a/crates/ra_hir_ty/src/method_resolution.rs
+++ b/crates/ra_hir_ty/src/method_resolution.rs
@@ -6,20 +6,21 @@ use std::sync::Arc;
6 6
7use arrayvec::ArrayVec; 7use arrayvec::ArrayVec;
8use hir_def::{ 8use hir_def::{
9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocItemId, AstItemDef, 9 lang_item::LangItemTarget, resolver::Resolver, type_ref::Mutability, AssocContainerId,
10 FunctionId, HasModule, ImplId, TraitId, 10 AssocItemId, FunctionId, HasModule, ImplId, Lookup, TraitId,
11}; 11};
12use hir_expand::name::Name; 12use hir_expand::name::Name;
13use ra_db::CrateId; 13use ra_db::CrateId;
14use ra_prof::profile; 14use ra_prof::profile;
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16 16
17use super::Substs;
17use crate::{ 18use crate::{
18 autoderef, 19 autoderef,
19 db::HirDatabase, 20 db::HirDatabase,
20 primitive::{FloatBitness, Uncertain}, 21 primitive::{FloatBitness, Uncertain},
21 utils::all_super_traits, 22 utils::all_super_traits,
22 Canonical, ImplTy, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, 23 Canonical, InEnvironment, TraitEnvironment, TraitRef, Ty, TypeCtor, TypeWalk,
23}; 24};
24 25
25/// This is used as a key for indexing impls. 26/// This is used as a key for indexing impls.
@@ -57,12 +58,13 @@ impl CrateImplBlocks {
57 58
58 let crate_def_map = db.crate_def_map(krate); 59 let crate_def_map = db.crate_def_map(krate);
59 for (_module_id, module_data) in crate_def_map.modules.iter() { 60 for (_module_id, module_data) in crate_def_map.modules.iter() {
60 for &impl_id in module_data.impls.iter() { 61 for impl_id in module_data.scope.impls() {
61 match db.impl_ty(impl_id) { 62 match db.impl_trait(impl_id) {
62 ImplTy::TraitRef(tr) => { 63 Some(tr) => {
63 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id); 64 res.impls_by_trait.entry(tr.trait_).or_default().push(impl_id);
64 } 65 }
65 ImplTy::Inherent(self_ty) => { 66 None => {
67 let self_ty = db.impl_self_ty(impl_id);
66 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) { 68 if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty) {
67 res.impls.entry(self_ty_fp).or_default().push(impl_id); 69 res.impls.entry(self_ty_fp).or_default().push(impl_id);
68 } 70 }
@@ -132,7 +134,7 @@ impl Ty {
132 LangItemTarget::ImplBlockId(it) => Some(it), 134 LangItemTarget::ImplBlockId(it) => Some(it),
133 _ => None, 135 _ => None,
134 }) 136 })
135 .map(|it| it.module(db).krate) 137 .map(|it| it.lookup(db).container.module(db).krate)
136 .collect(); 138 .collect();
137 Some(res) 139 Some(res)
138 } 140 }
@@ -175,7 +177,6 @@ pub fn iterate_method_candidates<T>(
175 mode: LookupMode, 177 mode: LookupMode,
176 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 178 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
177) -> Option<T> { 179) -> Option<T> {
178 let krate = resolver.krate()?;
179 match mode { 180 match mode {
180 LookupMode::MethodCall => { 181 LookupMode::MethodCall => {
181 // For method calls, rust first does any number of autoderef, and then one 182 // For method calls, rust first does any number of autoderef, and then one
@@ -188,57 +189,159 @@ pub fn iterate_method_candidates<T>(
188 // rustc does an autoderef and then autoref again). 189 // rustc does an autoderef and then autoref again).
189 let environment = TraitEnvironment::lower(db, resolver); 190 let environment = TraitEnvironment::lower(db, resolver);
190 let ty = InEnvironment { value: ty.clone(), environment }; 191 let ty = InEnvironment { value: ty.clone(), environment };
191 for derefed_ty in autoderef::autoderef(db, resolver.krate(), ty) { 192 let krate = resolver.krate()?;
192 if let Some(result) = 193
193 iterate_inherent_methods(&derefed_ty, db, name, mode, krate, &mut callback) 194 // We have to be careful about the order we're looking at candidates
194 { 195 // in here. Consider the case where we're resolving `x.clone()`
195 return Some(result); 196 // where `x: &Vec<_>`. This resolves to the clone method with self
196 } 197 // type `Vec<_>`, *not* `&_`. I.e. we need to consider methods where
197 if let Some(result) = iterate_trait_method_candidates( 198 // the receiver type exactly matches before cases where we have to
198 &derefed_ty, 199 // do autoref. But in the autoderef steps, the `&_` self type comes
200 // up *before* the `Vec<_>` self type.
201 //
202 // On the other hand, we don't want to just pick any by-value method
203 // before any by-autoref method; it's just that we need to consider
204 // the methods by autoderef order of *receiver types*, not *self
205 // types*.
206
207 let deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty.clone()).collect();
208 for i in 0..deref_chain.len() {
209 if let Some(result) = iterate_method_candidates_with_autoref(
210 &deref_chain[i..],
199 db, 211 db,
200 resolver, 212 resolver,
201 name, 213 name,
202 mode,
203 &mut callback, 214 &mut callback,
204 ) { 215 ) {
205 return Some(result); 216 return Some(result);
206 } 217 }
207 } 218 }
219 None
208 } 220 }
209 LookupMode::Path => { 221 LookupMode::Path => {
210 // No autoderef for path lookups 222 // No autoderef for path lookups
211 if let Some(result) = 223 iterate_method_candidates_for_self_ty(&ty, db, resolver, name, &mut callback)
212 iterate_inherent_methods(&ty, db, name, mode, krate.into(), &mut callback) 224 }
213 { 225 }
214 return Some(result); 226}
215 } 227
216 if let Some(result) = 228fn iterate_method_candidates_with_autoref<T>(
217 iterate_trait_method_candidates(&ty, db, resolver, name, mode, &mut callback) 229 deref_chain: &[Canonical<Ty>],
218 { 230 db: &impl HirDatabase,
219 return Some(result); 231 resolver: &Resolver,
220 } 232 name: Option<&Name>,
233 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
234) -> Option<T> {
235 if let Some(result) = iterate_method_candidates_by_receiver(
236 &deref_chain[0],
237 &deref_chain[1..],
238 db,
239 resolver,
240 name,
241 &mut callback,
242 ) {
243 return Some(result);
244 }
245 let refed = Canonical {
246 num_vars: deref_chain[0].num_vars,
247 value: Ty::apply_one(TypeCtor::Ref(Mutability::Shared), deref_chain[0].value.clone()),
248 };
249 if let Some(result) = iterate_method_candidates_by_receiver(
250 &refed,
251 deref_chain,
252 db,
253 resolver,
254 name,
255 &mut callback,
256 ) {
257 return Some(result);
258 }
259 let ref_muted = Canonical {
260 num_vars: deref_chain[0].num_vars,
261 value: Ty::apply_one(TypeCtor::Ref(Mutability::Mut), deref_chain[0].value.clone()),
262 };
263 if let Some(result) = iterate_method_candidates_by_receiver(
264 &ref_muted,
265 deref_chain,
266 db,
267 resolver,
268 name,
269 &mut callback,
270 ) {
271 return Some(result);
272 }
273 None
274}
275
276fn iterate_method_candidates_by_receiver<T>(
277 receiver_ty: &Canonical<Ty>,
278 rest_of_deref_chain: &[Canonical<Ty>],
279 db: &impl HirDatabase,
280 resolver: &Resolver,
281 name: Option<&Name>,
282 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
283) -> Option<T> {
284 // We're looking for methods with *receiver* type receiver_ty. These could
285 // be found in any of the derefs of receiver_ty, so we have to go through
286 // that.
287 let krate = resolver.krate()?;
288 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
289 if let Some(result) =
290 iterate_inherent_methods(self_ty, db, name, Some(receiver_ty), krate, &mut callback)
291 {
292 return Some(result);
293 }
294 }
295 for self_ty in std::iter::once(receiver_ty).chain(rest_of_deref_chain) {
296 if let Some(result) = iterate_trait_method_candidates(
297 self_ty,
298 db,
299 resolver,
300 name,
301 Some(receiver_ty),
302 &mut callback,
303 ) {
304 return Some(result);
221 } 305 }
222 } 306 }
223 None 307 None
224} 308}
225 309
310fn iterate_method_candidates_for_self_ty<T>(
311 self_ty: &Canonical<Ty>,
312 db: &impl HirDatabase,
313 resolver: &Resolver,
314 name: Option<&Name>,
315 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
316) -> Option<T> {
317 let krate = resolver.krate()?;
318 if let Some(result) = iterate_inherent_methods(self_ty, db, name, None, krate, &mut callback) {
319 return Some(result);
320 }
321 if let Some(result) =
322 iterate_trait_method_candidates(self_ty, db, resolver, name, None, &mut callback)
323 {
324 return Some(result);
325 }
326 None
327}
328
226fn iterate_trait_method_candidates<T>( 329fn iterate_trait_method_candidates<T>(
227 ty: &Canonical<Ty>, 330 self_ty: &Canonical<Ty>,
228 db: &impl HirDatabase, 331 db: &impl HirDatabase,
229 resolver: &Resolver, 332 resolver: &Resolver,
230 name: Option<&Name>, 333 name: Option<&Name>,
231 mode: LookupMode, 334 receiver_ty: Option<&Canonical<Ty>>,
232 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 335 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
233) -> Option<T> { 336) -> Option<T> {
234 let krate = resolver.krate()?; 337 let krate = resolver.krate()?;
235 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that) 338 // FIXME: maybe put the trait_env behind a query (need to figure out good input parameters for that)
236 let env = TraitEnvironment::lower(db, resolver); 339 let env = TraitEnvironment::lower(db, resolver);
237 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope 340 // if ty is `impl Trait` or `dyn Trait`, the trait doesn't need to be in scope
238 let inherent_trait = ty.value.inherent_trait().into_iter(); 341 let inherent_trait = self_ty.value.inherent_trait().into_iter();
239 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 342 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
240 let traits_from_env = env 343 let traits_from_env = env
241 .trait_predicates_for_self_ty(&ty.value) 344 .trait_predicates_for_self_ty(&self_ty.value)
242 .map(|tr| tr.trait_) 345 .map(|tr| tr.trait_)
243 .flat_map(|t| all_super_traits(db, t)); 346 .flat_map(|t| all_super_traits(db, t));
244 let traits = 347 let traits =
@@ -251,17 +354,17 @@ fn iterate_trait_method_candidates<T>(
251 // iteration 354 // iteration
252 let mut known_implemented = false; 355 let mut known_implemented = false;
253 for (_name, item) in data.items.iter() { 356 for (_name, item) in data.items.iter() {
254 if !is_valid_candidate(db, name, mode, (*item).into()) { 357 if !is_valid_candidate(db, name, receiver_ty, (*item).into(), self_ty) {
255 continue; 358 continue;
256 } 359 }
257 if !known_implemented { 360 if !known_implemented {
258 let goal = generic_implements_goal(db, env.clone(), t, ty.clone()); 361 let goal = generic_implements_goal(db, env.clone(), t, self_ty.clone());
259 if db.trait_solve(krate.into(), goal).is_none() { 362 if db.trait_solve(krate.into(), goal).is_none() {
260 continue 'traits; 363 continue 'traits;
261 } 364 }
262 } 365 }
263 known_implemented = true; 366 known_implemented = true;
264 if let Some(result) = callback(&ty.value, (*item).into()) { 367 if let Some(result) = callback(&self_ty.value, (*item).into()) {
265 return Some(result); 368 return Some(result);
266 } 369 }
267 } 370 }
@@ -270,22 +373,22 @@ fn iterate_trait_method_candidates<T>(
270} 373}
271 374
272fn iterate_inherent_methods<T>( 375fn iterate_inherent_methods<T>(
273 ty: &Canonical<Ty>, 376 self_ty: &Canonical<Ty>,
274 db: &impl HirDatabase, 377 db: &impl HirDatabase,
275 name: Option<&Name>, 378 name: Option<&Name>,
276 mode: LookupMode, 379 receiver_ty: Option<&Canonical<Ty>>,
277 krate: CrateId, 380 krate: CrateId,
278 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>, 381 mut callback: impl FnMut(&Ty, AssocItemId) -> Option<T>,
279) -> Option<T> { 382) -> Option<T> {
280 for krate in ty.value.def_crates(db, krate)? { 383 for krate in self_ty.value.def_crates(db, krate)? {
281 let impls = db.impls_in_crate(krate); 384 let impls = db.impls_in_crate(krate);
282 385
283 for impl_block in impls.lookup_impl_blocks(&ty.value) { 386 for impl_block in impls.lookup_impl_blocks(&self_ty.value) {
284 for &item in db.impl_data(impl_block).items.iter() { 387 for &item in db.impl_data(impl_block).items.iter() {
285 if !is_valid_candidate(db, name, mode, item) { 388 if !is_valid_candidate(db, name, receiver_ty, item, self_ty) {
286 continue; 389 continue;
287 } 390 }
288 if let Some(result) = callback(&ty.value, item.into()) { 391 if let Some(result) = callback(&self_ty.value, item) {
289 return Some(result); 392 return Some(result);
290 } 393 }
291 } 394 }
@@ -297,23 +400,68 @@ fn iterate_inherent_methods<T>(
297fn is_valid_candidate( 400fn is_valid_candidate(
298 db: &impl HirDatabase, 401 db: &impl HirDatabase,
299 name: Option<&Name>, 402 name: Option<&Name>,
300 mode: LookupMode, 403 receiver_ty: Option<&Canonical<Ty>>,
301 item: AssocItemId, 404 item: AssocItemId,
405 self_ty: &Canonical<Ty>,
302) -> bool { 406) -> bool {
303 match item { 407 match item {
304 AssocItemId::FunctionId(m) => { 408 AssocItemId::FunctionId(m) => {
305 let data = db.function_data(m); 409 let data = db.function_data(m);
306 name.map_or(true, |name| &data.name == name) 410 if let Some(name) = name {
307 && (data.has_self_param || mode == LookupMode::Path) 411 if &data.name != name {
412 return false;
413 }
414 }
415 if let Some(receiver_ty) = receiver_ty {
416 if !data.has_self_param {
417 return false;
418 }
419 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
420 Some(ty) => ty,
421 None => return false,
422 };
423 if transformed_receiver_ty != receiver_ty.value {
424 return false;
425 }
426 }
427 true
308 } 428 }
309 AssocItemId::ConstId(c) => { 429 AssocItemId::ConstId(c) => {
310 let data = db.const_data(c); 430 let data = db.const_data(c);
311 name.map_or(true, |name| data.name.as_ref() == Some(name)) && (mode == LookupMode::Path) 431 name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
312 } 432 }
313 _ => false, 433 _ => false,
314 } 434 }
315} 435}
316 436
437pub(crate) fn inherent_impl_substs(
438 db: &impl HirDatabase,
439 impl_id: ImplId,
440 self_ty: &Canonical<Ty>,
441) -> Option<Substs> {
442 let vars = Substs::build_for_def(db, impl_id).fill_with_bound_vars(0).build();
443 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars);
444 let self_ty_with_vars = Canonical { num_vars: vars.len(), value: self_ty_with_vars };
445 super::infer::unify(&self_ty_with_vars, self_ty)
446}
447
448fn transform_receiver_ty(
449 db: &impl HirDatabase,
450 function_id: FunctionId,
451 self_ty: &Canonical<Ty>,
452) -> Option<Ty> {
453 let substs = match function_id.lookup(db).container {
454 AssocContainerId::TraitId(_) => Substs::build_for_def(db, function_id)
455 .push(self_ty.value.clone())
456 .fill_with_unknown()
457 .build(),
458 AssocContainerId::ImplId(impl_id) => inherent_impl_substs(db, impl_id, &self_ty)?,
459 AssocContainerId::ContainerId(_) => unreachable!(),
460 };
461 let sig = db.callable_item_signature(function_id.into());
462 Some(sig.params()[0].clone().subst(&substs))
463}
464
317pub fn implements_trait( 465pub fn implements_trait(
318 ty: &Canonical<Ty>, 466 ty: &Canonical<Ty>,
319 db: &impl HirDatabase, 467 db: &impl HirDatabase,
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs
index 1dc9793f9..1a31b587b 100644
--- a/crates/ra_hir_ty/src/test_db.rs
+++ b/crates/ra_hir_ty/src/test_db.rs
@@ -74,7 +74,7 @@ impl TestDB {
74 for &krate in self.relevant_crates(file_id).iter() { 74 for &krate in self.relevant_crates(file_id).iter() {
75 let crate_def_map = self.crate_def_map(krate); 75 let crate_def_map = self.crate_def_map(krate);
76 for (local_id, data) in crate_def_map.modules.iter() { 76 for (local_id, data) in crate_def_map.modules.iter() {
77 if data.definition == Some(file_id) { 77 if data.origin.file_id() == Some(file_id) {
78 return ModuleId { krate, local_id }; 78 return ModuleId { krate, local_id };
79 } 79 }
80 } 80 }
@@ -98,7 +98,7 @@ impl TestDB {
98 } 98 }
99 } 99 }
100 100
101 for &impl_id in crate_def_map[module_id].impls.iter() { 101 for impl_id in crate_def_map[module_id].scope.impls() {
102 let impl_data = self.impl_data(impl_id); 102 let impl_data = self.impl_data(impl_id);
103 for item in impl_data.items.iter() { 103 for item in impl_data.items.iter() {
104 if let AssocItemId::FunctionId(f) = item { 104 if let AssocItemId::FunctionId(f) = item {
diff --git a/crates/ra_hir_ty/src/tests.rs b/crates/ra_hir_ty/src/tests.rs
index c8461b447..d447b4571 100644
--- a/crates/ra_hir_ty/src/tests.rs
+++ b/crates/ra_hir_ty/src/tests.rs
@@ -1,21 +1,26 @@
1mod never_type; 1mod never_type;
2mod coercion; 2mod coercion;
3mod regression;
4mod simple;
5mod patterns;
6mod traits;
7mod method_resolution;
8mod macros;
3 9
4use std::fmt::Write; 10use std::fmt::Write;
5use std::sync::Arc; 11use std::sync::Arc;
6 12
7use hir_def::{ 13use hir_def::{
8 body::BodySourceMap, db::DefDatabase, nameres::CrateDefMap, AssocItemId, DefWithBodyId, 14 body::BodySourceMap, child_by_source::ChildBySource, db::DefDatabase, keys,
9 LocalModuleId, Lookup, ModuleDefId, 15 nameres::CrateDefMap, AssocItemId, DefWithBodyId, LocalModuleId, Lookup, ModuleDefId,
10}; 16};
11use hir_expand::Source; 17use hir_expand::InFile;
12use insta::assert_snapshot; 18use insta::assert_snapshot;
13use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase}; 19use ra_db::{fixture::WithFixture, salsa::Database, FilePosition, SourceDatabase};
14use ra_syntax::{ 20use ra_syntax::{
15 algo, 21 algo,
16 ast::{self, AstNode}, 22 ast::{self, AstNode},
17}; 23};
18use test_utils::covers;
19 24
20use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult}; 25use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResult};
21 26
@@ -23,4669 +28,20 @@ use crate::{db::HirDatabase, display::HirDisplay, test_db::TestDB, InferenceResu
23// against snapshots of the expected results using insta. Use cargo-insta to 28// against snapshots of the expected results using insta. Use cargo-insta to
24// update the snapshots. 29// update the snapshots.
25 30
26#[test]
27fn cfg_impl_block() {
28 let (db, pos) = TestDB::with_position(
29 r#"
30//- /main.rs crate:main deps:foo cfg:test
31use foo::S as T;
32struct S;
33
34#[cfg(test)]
35impl S {
36 fn foo1(&self) -> i32 { 0 }
37}
38
39#[cfg(not(test))]
40impl S {
41 fn foo2(&self) -> i32 { 0 }
42}
43
44fn test() {
45 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
46 t<|>;
47}
48
49//- /foo.rs crate:foo
50struct S;
51
52#[cfg(not(test))]
53impl S {
54 fn foo3(&self) -> i32 { 0 }
55}
56
57#[cfg(test)]
58impl S {
59 fn foo4(&self) -> i32 { 0 }
60}
61"#,
62 );
63 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
64}
65
66#[test]
67fn infer_await() {
68 let (db, pos) = TestDB::with_position(
69 r#"
70//- /main.rs crate:main deps:std
71
72struct IntFuture;
73
74impl Future for IntFuture {
75 type Output = u64;
76}
77
78fn test() {
79 let r = IntFuture;
80 let v = r.await;
81 v<|>;
82}
83
84//- /std.rs crate:std
85#[prelude_import] use future::*;
86mod future {
87 trait Future {
88 type Output;
89 }
90}
91
92"#,
93 );
94 assert_eq!("u64", type_at_pos(&db, pos));
95}
96
97#[test]
98fn infer_box() {
99 let (db, pos) = TestDB::with_position(
100 r#"
101//- /main.rs crate:main deps:std
102
103fn test() {
104 let x = box 1;
105 let t = (x, box x, box &1, box [1]);
106 t<|>;
107}
108
109//- /std.rs crate:std
110#[prelude_import] use prelude::*;
111mod prelude {}
112
113mod boxed {
114 pub struct Box<T: ?Sized> {
115 inner: *mut T,
116 }
117}
118
119"#,
120 );
121 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
122}
123
124#[test]
125fn infer_adt_self() {
126 let (db, pos) = TestDB::with_position(
127 r#"
128//- /main.rs
129enum Nat { Succ(Self), Demo(Nat), Zero }
130
131fn test() {
132 let foo: Nat = Nat::Zero;
133 if let Nat::Succ(x) = foo {
134 x<|>
135 }
136}
137
138"#,
139 );
140 assert_eq!("Nat", type_at_pos(&db, pos));
141}
142
143#[test]
144fn infer_try() {
145 let (db, pos) = TestDB::with_position(
146 r#"
147//- /main.rs crate:main deps:std
148
149fn test() {
150 let r: Result<i32, u64> = Result::Ok(1);
151 let v = r?;
152 v<|>;
153}
154
155//- /std.rs crate:std
156
157#[prelude_import] use ops::*;
158mod ops {
159 trait Try {
160 type Ok;
161 type Error;
162 }
163}
164
165#[prelude_import] use result::*;
166mod result {
167 enum Result<O, E> {
168 Ok(O),
169 Err(E)
170 }
171
172 impl<O, E> crate::ops::Try for Result<O, E> {
173 type Ok = O;
174 type Error = E;
175 }
176}
177
178"#,
179 );
180 assert_eq!("i32", type_at_pos(&db, pos));
181}
182
183#[test]
184fn infer_for_loop() {
185 let (db, pos) = TestDB::with_position(
186 r#"
187//- /main.rs crate:main deps:std
188
189use std::collections::Vec;
190
191fn test() {
192 let v = Vec::new();
193 v.push("foo");
194 for x in v {
195 x<|>;
196 }
197}
198
199//- /std.rs crate:std
200
201#[prelude_import] use iter::*;
202mod iter {
203 trait IntoIterator {
204 type Item;
205 }
206}
207
208mod collections {
209 struct Vec<T> {}
210 impl<T> Vec<T> {
211 fn new() -> Self { Vec {} }
212 fn push(&mut self, t: T) { }
213 }
214
215 impl<T> crate::iter::IntoIterator for Vec<T> {
216 type Item=T;
217 }
218}
219"#,
220 );
221 assert_eq!("&str", type_at_pos(&db, pos));
222}
223
224#[test]
225fn infer_while_let() {
226 let (db, pos) = TestDB::with_position(
227 r#"
228//- /main.rs
229enum Option<T> { Some(T), None }
230
231fn test() {
232 let foo: Option<f32> = None;
233 while let Option::Some(x) = foo {
234 <|>x
235 }
236}
237
238"#,
239 );
240 assert_eq!("f32", type_at_pos(&db, pos));
241}
242
243#[test]
244fn infer_basics() {
245 assert_snapshot!(
246 infer(r#"
247fn test(a: u32, b: isize, c: !, d: &str) {
248 a;
249 b;
250 c;
251 d;
252 1usize;
253 1isize;
254 "test";
255 1.0f32;
256}"#),
257 @r###"
258 [9; 10) 'a': u32
259 [17; 18) 'b': isize
260 [27; 28) 'c': !
261 [33; 34) 'd': &str
262 [42; 121) '{ ...f32; }': !
263 [48; 49) 'a': u32
264 [55; 56) 'b': isize
265 [62; 63) 'c': !
266 [69; 70) 'd': &str
267 [76; 82) '1usize': usize
268 [88; 94) '1isize': isize
269 [100; 106) '"test"': &str
270 [112; 118) '1.0f32': f32
271 "###
272 );
273}
274
275#[test]
276fn infer_let() {
277 assert_snapshot!(
278 infer(r#"
279fn test() {
280 let a = 1isize;
281 let b: usize = 1;
282 let c = b;
283 let d: u32;
284 let e;
285 let f: i32 = e;
286}
287"#),
288 @r###"
289 [11; 118) '{ ...= e; }': ()
290 [21; 22) 'a': isize
291 [25; 31) '1isize': isize
292 [41; 42) 'b': usize
293 [52; 53) '1': usize
294 [63; 64) 'c': usize
295 [67; 68) 'b': usize
296 [78; 79) 'd': u32
297 [94; 95) 'e': i32
298 [105; 106) 'f': i32
299 [114; 115) 'e': i32
300 "###
301 );
302}
303
304#[test]
305fn infer_paths() {
306 assert_snapshot!(
307 infer(r#"
308fn a() -> u32 { 1 }
309
310mod b {
311 fn c() -> u32 { 1 }
312}
313
314fn test() {
315 a();
316 b::c();
317}
318"#),
319 @r###"
320 [15; 20) '{ 1 }': u32
321 [17; 18) '1': u32
322 [48; 53) '{ 1 }': u32
323 [50; 51) '1': u32
324 [67; 91) '{ ...c(); }': ()
325 [73; 74) 'a': fn a() -> u32
326 [73; 76) 'a()': u32
327 [82; 86) 'b::c': fn c() -> u32
328 [82; 88) 'b::c()': u32
329 "###
330 );
331}
332
333#[test]
334fn infer_path_type() {
335 assert_snapshot!(
336 infer(r#"
337struct S;
338
339impl S {
340 fn foo() -> i32 { 1 }
341}
342
343fn test() {
344 S::foo();
345 <S>::foo();
346}
347"#),
348 @r###"
349 [41; 46) '{ 1 }': i32
350 [43; 44) '1': i32
351 [60; 93) '{ ...o(); }': ()
352 [66; 72) 'S::foo': fn foo() -> i32
353 [66; 74) 'S::foo()': i32
354 [80; 88) '<S>::foo': fn foo() -> i32
355 [80; 90) '<S>::foo()': i32
356 "###
357 );
358}
359
360#[test]
361fn infer_slice_method() {
362 assert_snapshot!(
363 infer(r#"
364#[lang = "slice"]
365impl<T> [T] {
366 fn foo(&self) -> T {
367 loop {}
368 }
369}
370
371#[lang = "slice_alloc"]
372impl<T> [T] {}
373
374fn test() {
375 <[_]>::foo(b"foo");
376}
377"#),
378 @r###"
379 [45; 49) 'self': &[T]
380 [56; 79) '{ ... }': T
381 [66; 73) 'loop {}': !
382 [71; 73) '{}': ()
383 [133; 160) '{ ...o"); }': ()
384 [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T
385 [139; 157) '<[_]>:..."foo")': u8
386 [150; 156) 'b"foo"': &[u8]
387 "###
388 );
389}
390
391#[test]
392fn infer_struct() {
393 assert_snapshot!(
394 infer(r#"
395struct A {
396 b: B,
397 c: C,
398}
399struct B;
400struct C(usize);
401
402fn test() {
403 let c = C(1);
404 B;
405 let a: A = A { b: B, c: C(1) };
406 a.b;
407 a.c;
408}
409"#),
410 @r###"
411 [72; 154) '{ ...a.c; }': ()
412 [82; 83) 'c': C
413 [86; 87) 'C': C(usize) -> C
414 [86; 90) 'C(1)': C
415 [88; 89) '1': usize
416 [96; 97) 'B': B
417 [107; 108) 'a': A
418 [114; 133) 'A { b:...C(1) }': A
419 [121; 122) 'B': B
420 [127; 128) 'C': C(usize) -> C
421 [127; 131) 'C(1)': C
422 [129; 130) '1': usize
423 [139; 140) 'a': A
424 [139; 142) 'a.b': B
425 [148; 149) 'a': A
426 [148; 151) 'a.c': C
427 "###
428 );
429}
430
431#[test]
432fn infer_enum() {
433 assert_snapshot!(
434 infer(r#"
435enum E {
436 V1 { field: u32 },
437 V2
438}
439fn test() {
440 E::V1 { field: 1 };
441 E::V2;
442}"#),
443 @r###"
444 [48; 82) '{ E:...:V2; }': ()
445 [52; 70) 'E::V1 ...d: 1 }': E
446 [67; 68) '1': u32
447 [74; 79) 'E::V2': E
448 "###
449 );
450}
451
452#[test]
453fn infer_refs() {
454 assert_snapshot!(
455 infer(r#"
456fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
457 a;
458 *a;
459 &a;
460 &mut a;
461 b;
462 *b;
463 &b;
464 c;
465 *c;
466 d;
467 *d;
468}
469"#),
470 @r###"
471 [9; 10) 'a': &u32
472 [18; 19) 'b': &mut u32
473 [31; 32) 'c': *const u32
474 [46; 47) 'd': *mut u32
475 [59; 150) '{ ... *d; }': ()
476 [65; 66) 'a': &u32
477 [72; 74) '*a': u32
478 [73; 74) 'a': &u32
479 [80; 82) '&a': &&u32
480 [81; 82) 'a': &u32
481 [88; 94) '&mut a': &mut &u32
482 [93; 94) 'a': &u32
483 [100; 101) 'b': &mut u32
484 [107; 109) '*b': u32
485 [108; 109) 'b': &mut u32
486 [115; 117) '&b': &&mut u32
487 [116; 117) 'b': &mut u32
488 [123; 124) 'c': *const u32
489 [130; 132) '*c': u32
490 [131; 132) 'c': *const u32
491 [138; 139) 'd': *mut u32
492 [145; 147) '*d': u32
493 [146; 147) 'd': *mut u32
494 "###
495 );
496}
497
498#[test]
499fn infer_literals() {
500 assert_snapshot!(
501 infer(r##"
502fn test() {
503 5i32;
504 5f32;
505 5f64;
506 "hello";
507 b"bytes";
508 'c';
509 b'b';
510 3.14;
511 5000;
512 false;
513 true;
514 r#"
515 //! doc
516 // non-doc
517 mod foo {}
518 "#;
519 br#"yolo"#;
520}
521"##),
522 @r###"
523 [11; 221) '{ ...o"#; }': ()
524 [17; 21) '5i32': i32
525 [27; 31) '5f32': f32
526 [37; 41) '5f64': f64
527 [47; 54) '"hello"': &str
528 [60; 68) 'b"bytes"': &[u8]
529 [74; 77) ''c'': char
530 [83; 87) 'b'b'': u8
531 [93; 97) '3.14': f64
532 [103; 107) '5000': i32
533 [113; 118) 'false': bool
534 [124; 128) 'true': bool
535 [134; 202) 'r#" ... "#': &str
536 [208; 218) 'br#"yolo"#': &[u8]
537 "###
538 );
539}
540
541#[test]
542fn infer_unary_op() {
543 assert_snapshot!(
544 infer(r#"
545enum SomeType {}
546
547fn test(x: SomeType) {
548 let b = false;
549 let c = !b;
550 let a = 100;
551 let d: i128 = -a;
552 let e = -100;
553 let f = !!!true;
554 let g = !42;
555 let h = !10u32;
556 let j = !a;
557 -3.14;
558 !3;
559 -x;
560 !x;
561 -"hello";
562 !"hello";
563}
564"#),
565 @r###"
566 [27; 28) 'x': SomeType
567 [40; 272) '{ ...lo"; }': ()
568 [50; 51) 'b': bool
569 [54; 59) 'false': bool
570 [69; 70) 'c': bool
571 [73; 75) '!b': bool
572 [74; 75) 'b': bool
573 [85; 86) 'a': i128
574 [89; 92) '100': i128
575 [102; 103) 'd': i128
576 [112; 114) '-a': i128
577 [113; 114) 'a': i128
578 [124; 125) 'e': i32
579 [128; 132) '-100': i32
580 [129; 132) '100': i32
581 [142; 143) 'f': bool
582 [146; 153) '!!!true': bool
583 [147; 153) '!!true': bool
584 [148; 153) '!true': bool
585 [149; 153) 'true': bool
586 [163; 164) 'g': i32
587 [167; 170) '!42': i32
588 [168; 170) '42': i32
589 [180; 181) 'h': u32
590 [184; 190) '!10u32': u32
591 [185; 190) '10u32': u32
592 [200; 201) 'j': i128
593 [204; 206) '!a': i128
594 [205; 206) 'a': i128
595 [212; 217) '-3.14': f64
596 [213; 217) '3.14': f64
597 [223; 225) '!3': i32
598 [224; 225) '3': i32
599 [231; 233) '-x': {unknown}
600 [232; 233) 'x': SomeType
601 [239; 241) '!x': {unknown}
602 [240; 241) 'x': SomeType
603 [247; 255) '-"hello"': {unknown}
604 [248; 255) '"hello"': &str
605 [261; 269) '!"hello"': {unknown}
606 [262; 269) '"hello"': &str
607 "###
608 );
609}
610
611#[test]
612fn infer_backwards() {
613 assert_snapshot!(
614 infer(r#"
615fn takes_u32(x: u32) {}
616
617struct S { i32_field: i32 }
618
619fn test() -> &mut &f64 {
620 let a = unknown_function();
621 takes_u32(a);
622 let b = unknown_function();
623 S { i32_field: b };
624 let c = unknown_function();
625 &mut &c
626}
627"#),
628 @r###"
629 [14; 15) 'x': u32
630 [22; 24) '{}': ()
631 [78; 231) '{ ...t &c }': &mut &f64
632 [88; 89) 'a': u32
633 [92; 108) 'unknow...nction': {unknown}
634 [92; 110) 'unknow...tion()': u32
635 [116; 125) 'takes_u32': fn takes_u32(u32) -> ()
636 [116; 128) 'takes_u32(a)': ()
637 [126; 127) 'a': u32
638 [138; 139) 'b': i32
639 [142; 158) 'unknow...nction': {unknown}
640 [142; 160) 'unknow...tion()': i32
641 [166; 184) 'S { i3...d: b }': S
642 [181; 182) 'b': i32
643 [194; 195) 'c': f64
644 [198; 214) 'unknow...nction': {unknown}
645 [198; 216) 'unknow...tion()': f64
646 [222; 229) '&mut &c': &mut &f64
647 [227; 229) '&c': &f64
648 [228; 229) 'c': f64
649 "###
650 );
651}
652
653#[test]
654fn infer_self() {
655 assert_snapshot!(
656 infer(r#"
657struct S;
658
659impl S {
660 fn test(&self) {
661 self;
662 }
663 fn test2(self: &Self) {
664 self;
665 }
666 fn test3() -> Self {
667 S {}
668 }
669 fn test4() -> Self {
670 Self {}
671 }
672}
673"#),
674 @r###"
675 [34; 38) 'self': &S
676 [40; 61) '{ ... }': ()
677 [50; 54) 'self': &S
678 [75; 79) 'self': &S
679 [88; 109) '{ ... }': ()
680 [98; 102) 'self': &S
681 [133; 153) '{ ... }': S
682 [143; 147) 'S {}': S
683 [177; 200) '{ ... }': S
684 [187; 194) 'Self {}': S
685 "###
686 );
687}
688
689#[test]
690fn infer_binary_op() {
691 assert_snapshot!(
692 infer(r#"
693fn f(x: bool) -> i32 {
694 0i32
695}
696
697fn test() -> bool {
698 let x = a && b;
699 let y = true || false;
700 let z = x == y;
701 let t = x != y;
702 let minus_forty: isize = -40isize;
703 let h = minus_forty <= CONST_2;
704 let c = f(z || y) + 5;
705 let d = b;
706 let g = minus_forty ^= i;
707 let ten: usize = 10;
708 let ten_is_eleven = ten == some_num;
709
710 ten < 3
711}
712"#),
713 @r###"
714 [6; 7) 'x': bool
715 [22; 34) '{ 0i32 }': i32
716 [28; 32) '0i32': i32
717 [54; 370) '{ ... < 3 }': bool
718 [64; 65) 'x': bool
719 [68; 69) 'a': bool
720 [68; 74) 'a && b': bool
721 [73; 74) 'b': bool
722 [84; 85) 'y': bool
723 [88; 92) 'true': bool
724 [88; 101) 'true || false': bool
725 [96; 101) 'false': bool
726 [111; 112) 'z': bool
727 [115; 116) 'x': bool
728 [115; 121) 'x == y': bool
729 [120; 121) 'y': bool
730 [131; 132) 't': bool
731 [135; 136) 'x': bool
732 [135; 141) 'x != y': bool
733 [140; 141) 'y': bool
734 [151; 162) 'minus_forty': isize
735 [172; 180) '-40isize': isize
736 [173; 180) '40isize': isize
737 [190; 191) 'h': bool
738 [194; 205) 'minus_forty': isize
739 [194; 216) 'minus_...ONST_2': bool
740 [209; 216) 'CONST_2': isize
741 [226; 227) 'c': i32
742 [230; 231) 'f': fn f(bool) -> i32
743 [230; 239) 'f(z || y)': i32
744 [230; 243) 'f(z || y) + 5': i32
745 [232; 233) 'z': bool
746 [232; 238) 'z || y': bool
747 [237; 238) 'y': bool
748 [242; 243) '5': i32
749 [253; 254) 'd': {unknown}
750 [257; 258) 'b': {unknown}
751 [268; 269) 'g': ()
752 [272; 283) 'minus_forty': isize
753 [272; 288) 'minus_...y ^= i': ()
754 [287; 288) 'i': isize
755 [298; 301) 'ten': usize
756 [311; 313) '10': usize
757 [323; 336) 'ten_is_eleven': bool
758 [339; 342) 'ten': usize
759 [339; 354) 'ten == some_num': bool
760 [346; 354) 'some_num': usize
761 [361; 364) 'ten': usize
762 [361; 368) 'ten < 3': bool
763 [367; 368) '3': usize
764 "###
765 );
766}
767
768#[test]
769fn infer_field_autoderef() {
770 assert_snapshot!(
771 infer(r#"
772struct A {
773 b: B,
774}
775struct B;
776
777fn test1(a: A) {
778 let a1 = a;
779 a1.b;
780 let a2 = &a;
781 a2.b;
782 let a3 = &mut a;
783 a3.b;
784 let a4 = &&&&&&&a;
785 a4.b;
786 let a5 = &mut &&mut &&mut a;
787 a5.b;
788}
789
790fn test2(a1: *const A, a2: *mut A) {
791 a1.b;
792 a2.b;
793}
794"#),
795 @r###"
796 [44; 45) 'a': A
797 [50; 213) '{ ...5.b; }': ()
798 [60; 62) 'a1': A
799 [65; 66) 'a': A
800 [72; 74) 'a1': A
801 [72; 76) 'a1.b': B
802 [86; 88) 'a2': &A
803 [91; 93) '&a': &A
804 [92; 93) 'a': A
805 [99; 101) 'a2': &A
806 [99; 103) 'a2.b': B
807 [113; 115) 'a3': &mut A
808 [118; 124) '&mut a': &mut A
809 [123; 124) 'a': A
810 [130; 132) 'a3': &mut A
811 [130; 134) 'a3.b': B
812 [144; 146) 'a4': &&&&&&&A
813 [149; 157) '&&&&&&&a': &&&&&&&A
814 [150; 157) '&&&&&&a': &&&&&&A
815 [151; 157) '&&&&&a': &&&&&A
816 [152; 157) '&&&&a': &&&&A
817 [153; 157) '&&&a': &&&A
818 [154; 157) '&&a': &&A
819 [155; 157) '&a': &A
820 [156; 157) 'a': A
821 [163; 165) 'a4': &&&&&&&A
822 [163; 167) 'a4.b': B
823 [177; 179) 'a5': &mut &&mut &&mut A
824 [182; 200) '&mut &...&mut a': &mut &&mut &&mut A
825 [187; 200) '&&mut &&mut a': &&mut &&mut A
826 [188; 200) '&mut &&mut a': &mut &&mut A
827 [193; 200) '&&mut a': &&mut A
828 [194; 200) '&mut a': &mut A
829 [199; 200) 'a': A
830 [206; 208) 'a5': &mut &&mut &&mut A
831 [206; 210) 'a5.b': B
832 [224; 226) 'a1': *const A
833 [238; 240) 'a2': *mut A
834 [250; 273) '{ ...2.b; }': ()
835 [256; 258) 'a1': *const A
836 [256; 260) 'a1.b': B
837 [266; 268) 'a2': *mut A
838 [266; 270) 'a2.b': B
839 "###
840 );
841}
842
843#[test]
844fn infer_argument_autoderef() {
845 assert_snapshot!(
846 infer(r#"
847#[lang = "deref"]
848pub trait Deref {
849 type Target;
850 fn deref(&self) -> &Self::Target;
851}
852
853struct A<T>(T);
854
855impl<T> A<T> {
856 fn foo(&self) -> &T {
857 &self.0
858 }
859}
860
861struct B<T>(T);
862
863impl<T> Deref for B<T> {
864 type Target = T;
865 fn deref(&self) -> &Self::Target {
866 &self.0
867 }
868}
869
870fn test() {
871 let t = A::foo(&&B(B(A(42))));
872}
873"#),
874 @r###"
875 [68; 72) 'self': &Self
876 [139; 143) 'self': &A<T>
877 [151; 174) '{ ... }': &T
878 [161; 168) '&self.0': &T
879 [162; 166) 'self': &A<T>
880 [162; 168) 'self.0': T
881 [255; 259) 'self': &B<T>
882 [278; 301) '{ ... }': &T
883 [288; 295) '&self.0': &T
884 [289; 293) 'self': &B<T>
885 [289; 295) 'self.0': T
886 [315; 353) '{ ...))); }': ()
887 [325; 326) 't': &i32
888 [329; 335) 'A::foo': fn foo<i32>(&A<T>) -> &T
889 [329; 350) 'A::foo...42))))': &i32
890 [336; 349) '&&B(B(A(42)))': &&B<B<A<i32>>>
891 [337; 349) '&B(B(A(42)))': &B<B<A<i32>>>
892 [338; 339) 'B': B<B<A<i32>>>(T) -> B<T>
893 [338; 349) 'B(B(A(42)))': B<B<A<i32>>>
894 [340; 341) 'B': B<A<i32>>(T) -> B<T>
895 [340; 348) 'B(A(42))': B<A<i32>>
896 [342; 343) 'A': A<i32>(T) -> A<T>
897 [342; 347) 'A(42)': A<i32>
898 [344; 346) '42': i32
899 "###
900 );
901}
902
903#[test]
904fn infer_method_argument_autoderef() {
905 assert_snapshot!(
906 infer(r#"
907#[lang = "deref"]
908pub trait Deref {
909 type Target;
910 fn deref(&self) -> &Self::Target;
911}
912
913struct A<T>(*mut T);
914
915impl<T> A<T> {
916 fn foo(&self, x: &A<T>) -> &T {
917 &*x.0
918 }
919}
920
921struct B<T>(T);
922
923impl<T> Deref for B<T> {
924 type Target = T;
925 fn deref(&self) -> &Self::Target {
926 &self.0
927 }
928}
929
930fn test(a: A<i32>) {
931 let t = A(0 as *mut _).foo(&&B(B(a)));
932}
933"#),
934 @r###"
935 [68; 72) 'self': &Self
936 [144; 148) 'self': &A<T>
937 [150; 151) 'x': &A<T>
938 [166; 187) '{ ... }': &T
939 [176; 181) '&*x.0': &T
940 [177; 181) '*x.0': T
941 [178; 179) 'x': &A<T>
942 [178; 181) 'x.0': *mut T
943 [268; 272) 'self': &B<T>
944 [291; 314) '{ ... }': &T
945 [301; 308) '&self.0': &T
946 [302; 306) 'self': &B<T>
947 [302; 308) 'self.0': T
948 [326; 327) 'a': A<i32>
949 [337; 383) '{ ...))); }': ()
950 [347; 348) 't': &i32
951 [351; 352) 'A': A<i32>(*mut T) -> A<T>
952 [351; 365) 'A(0 as *mut _)': A<i32>
953 [351; 380) 'A(0 as...B(a)))': &i32
954 [353; 354) '0': i32
955 [353; 364) '0 as *mut _': *mut i32
956 [370; 379) '&&B(B(a))': &&B<B<A<i32>>>
957 [371; 379) '&B(B(a))': &B<B<A<i32>>>
958 [372; 373) 'B': B<B<A<i32>>>(T) -> B<T>
959 [372; 379) 'B(B(a))': B<B<A<i32>>>
960 [374; 375) 'B': B<A<i32>>(T) -> B<T>
961 [374; 378) 'B(a)': B<A<i32>>
962 [376; 377) 'a': A<i32>
963 "###
964 );
965}
966
967#[test]
968fn bug_484() {
969 assert_snapshot!(
970 infer(r#"
971fn test() {
972 let x = if true {};
973}
974"#),
975 @r###"
976 [11; 37) '{ l... {}; }': ()
977 [20; 21) 'x': ()
978 [24; 34) 'if true {}': ()
979 [27; 31) 'true': bool
980 [32; 34) '{}': ()
981 "###
982 );
983}
984
985#[test]
986fn infer_in_elseif() {
987 assert_snapshot!(
988 infer(r#"
989struct Foo { field: i32 }
990fn main(foo: Foo) {
991 if true {
992
993 } else if false {
994 foo.field
995 }
996}
997"#),
998 @r###"
999 [35; 38) 'foo': Foo
1000 [45; 109) '{ ... } }': ()
1001 [51; 107) 'if tru... }': ()
1002 [54; 58) 'true': bool
1003 [59; 67) '{ }': ()
1004 [73; 107) 'if fal... }': ()
1005 [76; 81) 'false': bool
1006 [82; 107) '{ ... }': i32
1007 [92; 95) 'foo': Foo
1008 [92; 101) 'foo.field': i32
1009 "###
1010 )
1011}
1012
1013#[test]
1014fn infer_if_match_with_return() {
1015 assert_snapshot!(
1016 infer(r#"
1017fn foo() {
1018 let _x1 = if true {
1019 1
1020 } else {
1021 return;
1022 };
1023 let _x2 = if true {
1024 2
1025 } else {
1026 return
1027 };
1028 let _x3 = match true {
1029 true => 3,
1030 _ => {
1031 return;
1032 }
1033 };
1034 let _x4 = match true {
1035 true => 4,
1036 _ => return
1037 };
1038}"#),
1039 @r###"
1040 [10; 323) '{ ... }; }': ()
1041 [20; 23) '_x1': i32
1042 [26; 80) 'if tru... }': i32
1043 [29; 33) 'true': bool
1044 [34; 51) '{ ... }': i32
1045 [44; 45) '1': i32
1046 [57; 80) '{ ... }': !
1047 [67; 73) 'return': !
1048 [90; 93) '_x2': i32
1049 [96; 149) 'if tru... }': i32
1050 [99; 103) 'true': bool
1051 [104; 121) '{ ... }': i32
1052 [114; 115) '2': i32
1053 [127; 149) '{ ... }': !
1054 [137; 143) 'return': !
1055 [159; 162) '_x3': i32
1056 [165; 247) 'match ... }': i32
1057 [171; 175) 'true': bool
1058 [186; 190) 'true': bool
1059 [194; 195) '3': i32
1060 [205; 206) '_': bool
1061 [210; 241) '{ ... }': !
1062 [224; 230) 'return': !
1063 [257; 260) '_x4': i32
1064 [263; 320) 'match ... }': i32
1065 [269; 273) 'true': bool
1066 [284; 288) 'true': bool
1067 [292; 293) '4': i32
1068 [303; 304) '_': bool
1069 [308; 314) 'return': !
1070 "###
1071 )
1072}
1073
1074#[test]
1075fn infer_inherent_method() {
1076 assert_snapshot!(
1077 infer(r#"
1078struct A;
1079
1080impl A {
1081 fn foo(self, x: u32) -> i32 {}
1082}
1083
1084mod b {
1085 impl super::A {
1086 fn bar(&self, x: u64) -> i64 {}
1087 }
1088}
1089
1090fn test(a: A) {
1091 a.foo(1);
1092 (&a).bar(1);
1093 a.bar(1);
1094}
1095"#),
1096 @r###"
1097 [32; 36) 'self': A
1098 [38; 39) 'x': u32
1099 [53; 55) '{}': ()
1100 [103; 107) 'self': &A
1101 [109; 110) 'x': u64
1102 [124; 126) '{}': ()
1103 [144; 145) 'a': A
1104 [150; 198) '{ ...(1); }': ()
1105 [156; 157) 'a': A
1106 [156; 164) 'a.foo(1)': i32
1107 [162; 163) '1': u32
1108 [170; 181) '(&a).bar(1)': i64
1109 [171; 173) '&a': &A
1110 [172; 173) 'a': A
1111 [179; 180) '1': u64
1112 [187; 188) 'a': A
1113 [187; 195) 'a.bar(1)': i64
1114 [193; 194) '1': u64
1115 "###
1116 );
1117}
1118
1119#[test]
1120fn infer_inherent_method_str() {
1121 assert_snapshot!(
1122 infer(r#"
1123#[lang = "str"]
1124impl str {
1125 fn foo(&self) -> i32 {}
1126}
1127
1128fn test() {
1129 "foo".foo();
1130}
1131"#),
1132 @r###"
1133 [40; 44) 'self': &str
1134 [53; 55) '{}': ()
1135 [69; 89) '{ ...o(); }': ()
1136 [75; 80) '"foo"': &str
1137 [75; 86) '"foo".foo()': i32
1138 "###
1139 );
1140}
1141
1142#[test]
1143fn infer_tuple() {
1144 assert_snapshot!(
1145 infer(r#"
1146fn test(x: &str, y: isize) {
1147 let a: (u32, &str) = (1, "a");
1148 let b = (a, x);
1149 let c = (y, x);
1150 let d = (c, x);
1151 let e = (1, "e");
1152 let f = (e, "d");
1153}
1154"#),
1155 @r###"
1156 [9; 10) 'x': &str
1157 [18; 19) 'y': isize
1158 [28; 170) '{ ...d"); }': ()
1159 [38; 39) 'a': (u32, &str)
1160 [55; 63) '(1, "a")': (u32, &str)
1161 [56; 57) '1': u32
1162 [59; 62) '"a"': &str
1163 [73; 74) 'b': ((u32, &str), &str)
1164 [77; 83) '(a, x)': ((u32, &str), &str)
1165 [78; 79) 'a': (u32, &str)
1166 [81; 82) 'x': &str
1167 [93; 94) 'c': (isize, &str)
1168 [97; 103) '(y, x)': (isize, &str)
1169 [98; 99) 'y': isize
1170 [101; 102) 'x': &str
1171 [113; 114) 'd': ((isize, &str), &str)
1172 [117; 123) '(c, x)': ((isize, &str), &str)
1173 [118; 119) 'c': (isize, &str)
1174 [121; 122) 'x': &str
1175 [133; 134) 'e': (i32, &str)
1176 [137; 145) '(1, "e")': (i32, &str)
1177 [138; 139) '1': i32
1178 [141; 144) '"e"': &str
1179 [155; 156) 'f': ((i32, &str), &str)
1180 [159; 167) '(e, "d")': ((i32, &str), &str)
1181 [160; 161) 'e': (i32, &str)
1182 [163; 166) '"d"': &str
1183 "###
1184 );
1185}
1186
1187#[test]
1188fn infer_array() {
1189 assert_snapshot!(
1190 infer(r#"
1191fn test(x: &str, y: isize) {
1192 let a = [x];
1193 let b = [a, a];
1194 let c = [b, b];
1195
1196 let d = [y, 1, 2, 3];
1197 let d = [1, y, 2, 3];
1198 let e = [y];
1199 let f = [d, d];
1200 let g = [e, e];
1201
1202 let h = [1, 2];
1203 let i = ["a", "b"];
1204
1205 let b = [a, ["b"]];
1206 let x: [u8; 0] = [];
1207}
1208"#),
1209 @r###"
1210 [9; 10) 'x': &str
1211 [18; 19) 'y': isize
1212 [28; 293) '{ ... []; }': ()
1213 [38; 39) 'a': [&str;_]
1214 [42; 45) '[x]': [&str;_]
1215 [43; 44) 'x': &str
1216 [55; 56) 'b': [[&str;_];_]
1217 [59; 65) '[a, a]': [[&str;_];_]
1218 [60; 61) 'a': [&str;_]
1219 [63; 64) 'a': [&str;_]
1220 [75; 76) 'c': [[[&str;_];_];_]
1221 [79; 85) '[b, b]': [[[&str;_];_];_]
1222 [80; 81) 'b': [[&str;_];_]
1223 [83; 84) 'b': [[&str;_];_]
1224 [96; 97) 'd': [isize;_]
1225 [100; 112) '[y, 1, 2, 3]': [isize;_]
1226 [101; 102) 'y': isize
1227 [104; 105) '1': isize
1228 [107; 108) '2': isize
1229 [110; 111) '3': isize
1230 [122; 123) 'd': [isize;_]
1231 [126; 138) '[1, y, 2, 3]': [isize;_]
1232 [127; 128) '1': isize
1233 [130; 131) 'y': isize
1234 [133; 134) '2': isize
1235 [136; 137) '3': isize
1236 [148; 149) 'e': [isize;_]
1237 [152; 155) '[y]': [isize;_]
1238 [153; 154) 'y': isize
1239 [165; 166) 'f': [[isize;_];_]
1240 [169; 175) '[d, d]': [[isize;_];_]
1241 [170; 171) 'd': [isize;_]
1242 [173; 174) 'd': [isize;_]
1243 [185; 186) 'g': [[isize;_];_]
1244 [189; 195) '[e, e]': [[isize;_];_]
1245 [190; 191) 'e': [isize;_]
1246 [193; 194) 'e': [isize;_]
1247 [206; 207) 'h': [i32;_]
1248 [210; 216) '[1, 2]': [i32;_]
1249 [211; 212) '1': i32
1250 [214; 215) '2': i32
1251 [226; 227) 'i': [&str;_]
1252 [230; 240) '["a", "b"]': [&str;_]
1253 [231; 234) '"a"': &str
1254 [236; 239) '"b"': &str
1255 [251; 252) 'b': [[&str;_];_]
1256 [255; 265) '[a, ["b"]]': [[&str;_];_]
1257 [256; 257) 'a': [&str;_]
1258 [259; 264) '["b"]': [&str;_]
1259 [260; 263) '"b"': &str
1260 [275; 276) 'x': [u8;_]
1261 [288; 290) '[]': [u8;_]
1262 "###
1263 );
1264}
1265
1266#[test]
1267fn infer_pattern() {
1268 assert_snapshot!(
1269 infer(r#"
1270fn test(x: &i32) {
1271 let y = x;
1272 let &z = x;
1273 let a = z;
1274 let (c, d) = (1, "hello");
1275
1276 for (e, f) in some_iter {
1277 let g = e;
1278 }
1279
1280 if let [val] = opt {
1281 let h = val;
1282 }
1283
1284 let lambda = |a: u64, b, c: i32| { a + b; c };
1285
1286 let ref ref_to_x = x;
1287 let mut mut_x = x;
1288 let ref mut mut_ref_to_x = x;
1289 let k = mut_ref_to_x;
1290}
1291"#),
1292 @r###"
1293 [9; 10) 'x': &i32
1294 [18; 369) '{ ...o_x; }': ()
1295 [28; 29) 'y': &i32
1296 [32; 33) 'x': &i32
1297 [43; 45) '&z': &i32
1298 [44; 45) 'z': i32
1299 [48; 49) 'x': &i32
1300 [59; 60) 'a': i32
1301 [63; 64) 'z': i32
1302 [74; 80) '(c, d)': (i32, &str)
1303 [75; 76) 'c': i32
1304 [78; 79) 'd': &str
1305 [83; 95) '(1, "hello")': (i32, &str)
1306 [84; 85) '1': i32
1307 [87; 94) '"hello"': &str
1308 [102; 152) 'for (e... }': ()
1309 [106; 112) '(e, f)': ({unknown}, {unknown})
1310 [107; 108) 'e': {unknown}
1311 [110; 111) 'f': {unknown}
1312 [116; 125) 'some_iter': {unknown}
1313 [126; 152) '{ ... }': ()
1314 [140; 141) 'g': {unknown}
1315 [144; 145) 'e': {unknown}
1316 [158; 205) 'if let... }': ()
1317 [165; 170) '[val]': {unknown}
1318 [173; 176) 'opt': {unknown}
1319 [177; 205) '{ ... }': ()
1320 [191; 192) 'h': {unknown}
1321 [195; 198) 'val': {unknown}
1322 [215; 221) 'lambda': |u64, u64, i32| -> i32
1323 [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
1324 [225; 226) 'a': u64
1325 [233; 234) 'b': u64
1326 [236; 237) 'c': i32
1327 [244; 256) '{ a + b; c }': i32
1328 [246; 247) 'a': u64
1329 [246; 251) 'a + b': u64
1330 [250; 251) 'b': u64
1331 [253; 254) 'c': i32
1332 [267; 279) 'ref ref_to_x': &&i32
1333 [282; 283) 'x': &i32
1334 [293; 302) 'mut mut_x': &i32
1335 [305; 306) 'x': &i32
1336 [316; 336) 'ref mu...f_to_x': &mut &i32
1337 [339; 340) 'x': &i32
1338 [350; 351) 'k': &mut &i32
1339 [354; 366) 'mut_ref_to_x': &mut &i32
1340 "###
1341 );
1342}
1343
1344#[test]
1345fn infer_pattern_match_ergonomics() {
1346 assert_snapshot!(
1347 infer(r#"
1348struct A<T>(T);
1349
1350fn test() {
1351 let A(n) = &A(1);
1352 let A(n) = &mut A(1);
1353}
1354"#),
1355 @r###"
1356 [28; 79) '{ ...(1); }': ()
1357 [38; 42) 'A(n)': A<i32>
1358 [40; 41) 'n': &i32
1359 [45; 50) '&A(1)': &A<i32>
1360 [46; 47) 'A': A<i32>(T) -> A<T>
1361 [46; 50) 'A(1)': A<i32>
1362 [48; 49) '1': i32
1363 [60; 64) 'A(n)': A<i32>
1364 [62; 63) 'n': &mut i32
1365 [67; 76) '&mut A(1)': &mut A<i32>
1366 [72; 73) 'A': A<i32>(T) -> A<T>
1367 [72; 76) 'A(1)': A<i32>
1368 [74; 75) '1': i32
1369 "###
1370 );
1371}
1372
1373#[test]
1374fn infer_pattern_match_ergonomics_ref() {
1375 covers!(match_ergonomics_ref);
1376 assert_snapshot!(
1377 infer(r#"
1378fn test() {
1379 let v = &(1, &2);
1380 let (_, &w) = v;
1381}
1382"#),
1383 @r###"
1384 [11; 57) '{ ...= v; }': ()
1385 [21; 22) 'v': &(i32, &i32)
1386 [25; 33) '&(1, &2)': &(i32, &i32)
1387 [26; 33) '(1, &2)': (i32, &i32)
1388 [27; 28) '1': i32
1389 [30; 32) '&2': &i32
1390 [31; 32) '2': i32
1391 [43; 50) '(_, &w)': (i32, &i32)
1392 [44; 45) '_': i32
1393 [47; 49) '&w': &i32
1394 [48; 49) 'w': i32
1395 [53; 54) 'v': &(i32, &i32)
1396 "###
1397 );
1398}
1399
1400#[test]
1401fn infer_adt_pattern() {
1402 assert_snapshot!(
1403 infer(r#"
1404enum E {
1405 A { x: usize },
1406 B
1407}
1408
1409struct S(u32, E);
1410
1411fn test() {
1412 let e = E::A { x: 3 };
1413
1414 let S(y, z) = foo;
1415 let E::A { x: new_var } = e;
1416
1417 match e {
1418 E::A { x } => x,
1419 E::B if foo => 1,
1420 E::B => 10,
1421 };
1422
1423 let ref d @ E::A { .. } = e;
1424 d;
1425}
1426"#),
1427 @r###"
1428 [68; 289) '{ ... d; }': ()
1429 [78; 79) 'e': E
1430 [82; 95) 'E::A { x: 3 }': E
1431 [92; 93) '3': usize
1432 [106; 113) 'S(y, z)': S
1433 [108; 109) 'y': u32
1434 [111; 112) 'z': E
1435 [116; 119) 'foo': S
1436 [129; 148) 'E::A {..._var }': E
1437 [139; 146) 'new_var': usize
1438 [151; 152) 'e': E
1439 [159; 245) 'match ... }': usize
1440 [165; 166) 'e': E
1441 [177; 187) 'E::A { x }': E
1442 [184; 185) 'x': usize
1443 [191; 192) 'x': usize
1444 [202; 206) 'E::B': E
1445 [210; 213) 'foo': bool
1446 [217; 218) '1': usize
1447 [228; 232) 'E::B': E
1448 [236; 238) '10': usize
1449 [256; 275) 'ref d ...{ .. }': &E
1450 [264; 275) 'E::A { .. }': E
1451 [278; 279) 'e': E
1452 [285; 286) 'd': &E
1453 "###
1454 );
1455}
1456
1457#[test]
1458fn infer_struct_generics() {
1459 assert_snapshot!(
1460 infer(r#"
1461struct A<T> {
1462 x: T,
1463}
1464
1465fn test(a1: A<u32>, i: i32) {
1466 a1.x;
1467 let a2 = A { x: i };
1468 a2.x;
1469 let a3 = A::<i128> { x: 1 };
1470 a3.x;
1471}
1472"#),
1473 @r###"
1474 [36; 38) 'a1': A<u32>
1475 [48; 49) 'i': i32
1476 [56; 147) '{ ...3.x; }': ()
1477 [62; 64) 'a1': A<u32>
1478 [62; 66) 'a1.x': u32
1479 [76; 78) 'a2': A<i32>
1480 [81; 91) 'A { x: i }': A<i32>
1481 [88; 89) 'i': i32
1482 [97; 99) 'a2': A<i32>
1483 [97; 101) 'a2.x': i32
1484 [111; 113) 'a3': A<i128>
1485 [116; 134) 'A::<i1...x: 1 }': A<i128>
1486 [131; 132) '1': i128
1487 [140; 142) 'a3': A<i128>
1488 [140; 144) 'a3.x': i128
1489 "###
1490 );
1491}
1492
1493#[test]
1494fn infer_tuple_struct_generics() {
1495 assert_snapshot!(
1496 infer(r#"
1497struct A<T>(T);
1498enum Option<T> { Some(T), None }
1499use Option::*;
1500
1501fn test() {
1502 A(42);
1503 A(42u128);
1504 Some("x");
1505 Option::Some("x");
1506 None;
1507 let x: Option<i64> = None;
1508}
1509"#),
1510 @r###"
1511 [76; 184) '{ ...one; }': ()
1512 [82; 83) 'A': A<i32>(T) -> A<T>
1513 [82; 87) 'A(42)': A<i32>
1514 [84; 86) '42': i32
1515 [93; 94) 'A': A<u128>(T) -> A<T>
1516 [93; 102) 'A(42u128)': A<u128>
1517 [95; 101) '42u128': u128
1518 [108; 112) 'Some': Some<&str>(T) -> Option<T>
1519 [108; 117) 'Some("x")': Option<&str>
1520 [113; 116) '"x"': &str
1521 [123; 135) 'Option::Some': Some<&str>(T) -> Option<T>
1522 [123; 140) 'Option...e("x")': Option<&str>
1523 [136; 139) '"x"': &str
1524 [146; 150) 'None': Option<{unknown}>
1525 [160; 161) 'x': Option<i64>
1526 [177; 181) 'None': Option<i64>
1527 "###
1528 );
1529}
1530
1531#[test]
1532fn infer_generics_in_patterns() {
1533 assert_snapshot!(
1534 infer(r#"
1535struct A<T> {
1536 x: T,
1537}
1538
1539enum Option<T> {
1540 Some(T),
1541 None,
1542}
1543
1544fn test(a1: A<u32>, o: Option<u64>) {
1545 let A { x: x2 } = a1;
1546 let A::<i64> { x: x3 } = A { x: 1 };
1547 match o {
1548 Option::Some(t) => t,
1549 _ => 1,
1550 };
1551}
1552"#),
1553 @r###"
1554 [79; 81) 'a1': A<u32>
1555 [91; 92) 'o': Option<u64>
1556 [107; 244) '{ ... }; }': ()
1557 [117; 128) 'A { x: x2 }': A<u32>
1558 [124; 126) 'x2': u32
1559 [131; 133) 'a1': A<u32>
1560 [143; 161) 'A::<i6...: x3 }': A<i64>
1561 [157; 159) 'x3': i64
1562 [164; 174) 'A { x: 1 }': A<i64>
1563 [171; 172) '1': i64
1564 [180; 241) 'match ... }': u64
1565 [186; 187) 'o': Option<u64>
1566 [198; 213) 'Option::Some(t)': Option<u64>
1567 [211; 212) 't': u64
1568 [217; 218) 't': u64
1569 [228; 229) '_': Option<u64>
1570 [233; 234) '1': u64
1571 "###
1572 );
1573}
1574
1575#[test]
1576fn infer_function_generics() {
1577 assert_snapshot!(
1578 infer(r#"
1579fn id<T>(t: T) -> T { t }
1580
1581fn test() {
1582 id(1u32);
1583 id::<i128>(1);
1584 let x: u64 = id(1);
1585}
1586"#),
1587 @r###"
1588 [10; 11) 't': T
1589 [21; 26) '{ t }': T
1590 [23; 24) 't': T
1591 [38; 98) '{ ...(1); }': ()
1592 [44; 46) 'id': fn id<u32>(T) -> T
1593 [44; 52) 'id(1u32)': u32
1594 [47; 51) '1u32': u32
1595 [58; 68) 'id::<i128>': fn id<i128>(T) -> T
1596 [58; 71) 'id::<i128>(1)': i128
1597 [69; 70) '1': i128
1598 [81; 82) 'x': u64
1599 [90; 92) 'id': fn id<u64>(T) -> T
1600 [90; 95) 'id(1)': u64
1601 [93; 94) '1': u64
1602 "###
1603 );
1604}
1605
1606#[test]
1607fn infer_impl_generics() {
1608 assert_snapshot!(
1609 infer(r#"
1610struct A<T1, T2> {
1611 x: T1,
1612 y: T2,
1613}
1614impl<Y, X> A<X, Y> {
1615 fn x(self) -> X {
1616 self.x
1617 }
1618 fn y(self) -> Y {
1619 self.y
1620 }
1621 fn z<T>(self, t: T) -> (X, Y, T) {
1622 (self.x, self.y, t)
1623 }
1624}
1625
1626fn test() -> i128 {
1627 let a = A { x: 1u64, y: 1i64 };
1628 a.x();
1629 a.y();
1630 a.z(1i128);
1631 a.z::<u128>(1);
1632}
1633"#),
1634 @r###"
1635 [74; 78) 'self': A<X, Y>
1636 [85; 107) '{ ... }': X
1637 [95; 99) 'self': A<X, Y>
1638 [95; 101) 'self.x': X
1639 [117; 121) 'self': A<X, Y>
1640 [128; 150) '{ ... }': Y
1641 [138; 142) 'self': A<X, Y>
1642 [138; 144) 'self.y': Y
1643 [163; 167) 'self': A<X, Y>
1644 [169; 170) 't': T
1645 [188; 223) '{ ... }': (X, Y, T)
1646 [198; 217) '(self.....y, t)': (X, Y, T)
1647 [199; 203) 'self': A<X, Y>
1648 [199; 205) 'self.x': X
1649 [207; 211) 'self': A<X, Y>
1650 [207; 213) 'self.y': Y
1651 [215; 216) 't': T
1652 [245; 342) '{ ...(1); }': ()
1653 [255; 256) 'a': A<u64, i64>
1654 [259; 281) 'A { x:...1i64 }': A<u64, i64>
1655 [266; 270) '1u64': u64
1656 [275; 279) '1i64': i64
1657 [287; 288) 'a': A<u64, i64>
1658 [287; 292) 'a.x()': u64
1659 [298; 299) 'a': A<u64, i64>
1660 [298; 303) 'a.y()': i64
1661 [309; 310) 'a': A<u64, i64>
1662 [309; 319) 'a.z(1i128)': (u64, i64, i128)
1663 [313; 318) '1i128': i128
1664 [325; 326) 'a': A<u64, i64>
1665 [325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
1666 [337; 338) '1': u128
1667 "###
1668 );
1669}
1670
1671#[test]
1672fn infer_impl_generics_with_autoderef() {
1673 assert_snapshot!(
1674 infer(r#"
1675enum Option<T> {
1676 Some(T),
1677 None,
1678}
1679impl<T> Option<T> {
1680 fn as_ref(&self) -> Option<&T> {}
1681}
1682fn test(o: Option<u32>) {
1683 (&o).as_ref();
1684 o.as_ref();
1685}
1686"#),
1687 @r###"
1688 [78; 82) 'self': &Option<T>
1689 [98; 100) '{}': ()
1690 [111; 112) 'o': Option<u32>
1691 [127; 165) '{ ...f(); }': ()
1692 [133; 146) '(&o).as_ref()': Option<&u32>
1693 [134; 136) '&o': &Option<u32>
1694 [135; 136) 'o': Option<u32>
1695 [152; 153) 'o': Option<u32>
1696 [152; 162) 'o.as_ref()': Option<&u32>
1697 "###
1698 );
1699}
1700
1701#[test]
1702fn infer_generic_chain() {
1703 assert_snapshot!(
1704 infer(r#"
1705struct A<T> {
1706 x: T,
1707}
1708impl<T2> A<T2> {
1709 fn x(self) -> T2 {
1710 self.x
1711 }
1712}
1713fn id<T>(t: T) -> T { t }
1714
1715fn test() -> i128 {
1716 let x = 1;
1717 let y = id(x);
1718 let a = A { x: id(y) };
1719 let z = id(a.x);
1720 let b = A { x: z };
1721 b.x()
1722}
1723"#),
1724 @r###"
1725 [53; 57) 'self': A<T2>
1726 [65; 87) '{ ... }': T2
1727 [75; 79) 'self': A<T2>
1728 [75; 81) 'self.x': T2
1729 [99; 100) 't': T
1730 [110; 115) '{ t }': T
1731 [112; 113) 't': T
1732 [135; 261) '{ ....x() }': i128
1733 [146; 147) 'x': i128
1734 [150; 151) '1': i128
1735 [162; 163) 'y': i128
1736 [166; 168) 'id': fn id<i128>(T) -> T
1737 [166; 171) 'id(x)': i128
1738 [169; 170) 'x': i128
1739 [182; 183) 'a': A<i128>
1740 [186; 200) 'A { x: id(y) }': A<i128>
1741 [193; 195) 'id': fn id<i128>(T) -> T
1742 [193; 198) 'id(y)': i128
1743 [196; 197) 'y': i128
1744 [211; 212) 'z': i128
1745 [215; 217) 'id': fn id<i128>(T) -> T
1746 [215; 222) 'id(a.x)': i128
1747 [218; 219) 'a': A<i128>
1748 [218; 221) 'a.x': i128
1749 [233; 234) 'b': A<i128>
1750 [237; 247) 'A { x: z }': A<i128>
1751 [244; 245) 'z': i128
1752 [254; 255) 'b': A<i128>
1753 [254; 259) 'b.x()': i128
1754 "###
1755 );
1756}
1757
1758#[test]
1759fn infer_associated_const() {
1760 assert_snapshot!(
1761 infer(r#"
1762struct Struct;
1763
1764impl Struct {
1765 const FOO: u32 = 1;
1766}
1767
1768enum Enum {}
1769
1770impl Enum {
1771 const BAR: u32 = 2;
1772}
1773
1774trait Trait {
1775 const ID: u32;
1776}
1777
1778struct TraitTest;
1779
1780impl Trait for TraitTest {
1781 const ID: u32 = 5;
1782}
1783
1784fn test() {
1785 let x = Struct::FOO;
1786 let y = Enum::BAR;
1787 let z = TraitTest::ID;
1788}
1789"#),
1790 @r###"
1791 [52; 53) '1': u32
1792 [105; 106) '2': u32
1793 [213; 214) '5': u32
1794 [229; 307) '{ ...:ID; }': ()
1795 [239; 240) 'x': u32
1796 [243; 254) 'Struct::FOO': u32
1797 [264; 265) 'y': u32
1798 [268; 277) 'Enum::BAR': u32
1799 [287; 288) 'z': u32
1800 [291; 304) 'TraitTest::ID': u32
1801 "###
1802 );
1803}
1804
1805#[test]
1806fn infer_associated_method_struct() {
1807 assert_snapshot!(
1808 infer(r#"
1809struct A { x: u32 }
1810
1811impl A {
1812 fn new() -> A {
1813 A { x: 0 }
1814 }
1815}
1816fn test() {
1817 let a = A::new();
1818 a.x;
1819}
1820"#),
1821 @r###"
1822 [49; 75) '{ ... }': A
1823 [59; 69) 'A { x: 0 }': A
1824 [66; 67) '0': u32
1825 [88; 122) '{ ...a.x; }': ()
1826 [98; 99) 'a': A
1827 [102; 108) 'A::new': fn new() -> A
1828 [102; 110) 'A::new()': A
1829 [116; 117) 'a': A
1830 [116; 119) 'a.x': u32
1831 "###
1832 );
1833}
1834
1835#[test]
1836fn infer_associated_method_enum() {
1837 assert_snapshot!(
1838 infer(r#"
1839enum A { B, C }
1840
1841impl A {
1842 pub fn b() -> A {
1843 A::B
1844 }
1845 pub fn c() -> A {
1846 A::C
1847 }
1848}
1849fn test() {
1850 let a = A::b();
1851 a;
1852 let c = A::c();
1853 c;
1854}
1855"#),
1856 @r###"
1857 [47; 67) '{ ... }': A
1858 [57; 61) 'A::B': A
1859 [88; 108) '{ ... }': A
1860 [98; 102) 'A::C': A
1861 [121; 178) '{ ... c; }': ()
1862 [131; 132) 'a': A
1863 [135; 139) 'A::b': fn b() -> A
1864 [135; 141) 'A::b()': A
1865 [147; 148) 'a': A
1866 [158; 159) 'c': A
1867 [162; 166) 'A::c': fn c() -> A
1868 [162; 168) 'A::c()': A
1869 [174; 175) 'c': A
1870 "###
1871 );
1872}
1873
1874#[test]
1875fn infer_associated_method_with_modules() {
1876 assert_snapshot!(
1877 infer(r#"
1878mod a {
1879 struct A;
1880 impl A { pub fn thing() -> A { A {} }}
1881}
1882
1883mod b {
1884 struct B;
1885 impl B { pub fn thing() -> u32 { 99 }}
1886
1887 mod c {
1888 struct C;
1889 impl C { pub fn thing() -> C { C {} }}
1890 }
1891}
1892use b::c;
1893
1894fn test() {
1895 let x = a::A::thing();
1896 let y = b::B::thing();
1897 let z = c::C::thing();
1898}
1899"#),
1900 @r###"
1901 [56; 64) '{ A {} }': A
1902 [58; 62) 'A {}': A
1903 [126; 132) '{ 99 }': u32
1904 [128; 130) '99': u32
1905 [202; 210) '{ C {} }': C
1906 [204; 208) 'C {}': C
1907 [241; 325) '{ ...g(); }': ()
1908 [251; 252) 'x': A
1909 [255; 266) 'a::A::thing': fn thing() -> A
1910 [255; 268) 'a::A::thing()': A
1911 [278; 279) 'y': u32
1912 [282; 293) 'b::B::thing': fn thing() -> u32
1913 [282; 295) 'b::B::thing()': u32
1914 [305; 306) 'z': C
1915 [309; 320) 'c::C::thing': fn thing() -> C
1916 [309; 322) 'c::C::thing()': C
1917 "###
1918 );
1919}
1920
1921#[test]
1922fn infer_associated_method_generics() {
1923 assert_snapshot!(
1924 infer(r#"
1925struct Gen<T> {
1926 val: T
1927}
1928
1929impl<T> Gen<T> {
1930 pub fn make(val: T) -> Gen<T> {
1931 Gen { val }
1932 }
1933}
1934
1935fn test() {
1936 let a = Gen::make(0u32);
1937}
1938"#),
1939 @r###"
1940 [64; 67) 'val': T
1941 [82; 109) '{ ... }': Gen<T>
1942 [92; 103) 'Gen { val }': Gen<T>
1943 [98; 101) 'val': T
1944 [123; 155) '{ ...32); }': ()
1945 [133; 134) 'a': Gen<u32>
1946 [137; 146) 'Gen::make': fn make<u32>(T) -> Gen<T>
1947 [137; 152) 'Gen::make(0u32)': Gen<u32>
1948 [147; 151) '0u32': u32
1949 "###
1950 );
1951}
1952
1953#[test]
1954fn infer_associated_method_generics_with_default_param() {
1955 assert_snapshot!(
1956 infer(r#"
1957struct Gen<T=u32> {
1958 val: T
1959}
1960
1961impl<T> Gen<T> {
1962 pub fn make() -> Gen<T> {
1963 loop { }
1964 }
1965}
1966
1967fn test() {
1968 let a = Gen::make();
1969}
1970"#),
1971 @r###"
1972 [80; 104) '{ ... }': Gen<T>
1973 [90; 98) 'loop { }': !
1974 [95; 98) '{ }': ()
1975 [118; 146) '{ ...e(); }': ()
1976 [128; 129) 'a': Gen<u32>
1977 [132; 141) 'Gen::make': fn make<u32>() -> Gen<T>
1978 [132; 143) 'Gen::make()': Gen<u32>
1979 "###
1980 );
1981}
1982
1983#[test]
1984fn infer_associated_method_generics_with_default_tuple_param() {
1985 let t = type_at(
1986 r#"
1987//- /main.rs
1988struct Gen<T=()> {
1989 val: T
1990}
1991
1992impl<T> Gen<T> {
1993 pub fn make() -> Gen<T> {
1994 loop { }
1995 }
1996}
1997
1998fn test() {
1999 let a = Gen::make();
2000 a.val<|>;
2001}
2002"#,
2003 );
2004 assert_eq!(t, "()");
2005}
2006
2007#[test]
2008fn infer_associated_method_generics_without_args() {
2009 assert_snapshot!(
2010 infer(r#"
2011struct Gen<T> {
2012 val: T
2013}
2014
2015impl<T> Gen<T> {
2016 pub fn make() -> Gen<T> {
2017 loop { }
2018 }
2019}
2020
2021fn test() {
2022 let a = Gen::<u32>::make();
2023}
2024"#),
2025 @r###"
2026 [76; 100) '{ ... }': Gen<T>
2027 [86; 94) 'loop { }': !
2028 [91; 94) '{ }': ()
2029 [114; 149) '{ ...e(); }': ()
2030 [124; 125) 'a': Gen<u32>
2031 [128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T>
2032 [128; 146) 'Gen::<...make()': Gen<u32>
2033 "###
2034 );
2035}
2036
2037#[test]
2038fn infer_associated_method_generics_2_type_params_without_args() {
2039 assert_snapshot!(
2040 infer(r#"
2041struct Gen<T, U> {
2042 val: T,
2043 val2: U,
2044}
2045
2046impl<T> Gen<u32, T> {
2047 pub fn make() -> Gen<u32,T> {
2048 loop { }
2049 }
2050}
2051
2052fn test() {
2053 let a = Gen::<u32, u64>::make();
2054}
2055"#),
2056 @r###"
2057 [102; 126) '{ ... }': Gen<u32, T>
2058 [112; 120) 'loop { }': !
2059 [117; 120) '{ }': ()
2060 [140; 180) '{ ...e(); }': ()
2061 [150; 151) 'a': Gen<u32, u64>
2062 [154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T>
2063 [154; 177) 'Gen::<...make()': Gen<u32, u64>
2064 "###
2065 );
2066}
2067
2068#[test]
2069fn infer_type_alias() {
2070 assert_snapshot!(
2071 infer(r#"
2072struct A<X, Y> { x: X, y: Y }
2073type Foo = A<u32, i128>;
2074type Bar<T> = A<T, u128>;
2075type Baz<U, V> = A<V, U>;
2076fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
2077 x.x;
2078 x.y;
2079 y.x;
2080 y.y;
2081 z.x;
2082 z.y;
2083}
2084"#),
2085 @r###"
2086 [116; 117) 'x': A<u32, i128>
2087 [124; 125) 'y': A<&str, u128>
2088 [138; 139) 'z': A<u8, i8>
2089 [154; 211) '{ ...z.y; }': ()
2090 [160; 161) 'x': A<u32, i128>
2091 [160; 163) 'x.x': u32
2092 [169; 170) 'x': A<u32, i128>
2093 [169; 172) 'x.y': i128
2094 [178; 179) 'y': A<&str, u128>
2095 [178; 181) 'y.x': &str
2096 [187; 188) 'y': A<&str, u128>
2097 [187; 190) 'y.y': u128
2098 [196; 197) 'z': A<u8, i8>
2099 [196; 199) 'z.x': u8
2100 [205; 206) 'z': A<u8, i8>
2101 [205; 208) 'z.y': i8
2102 "###
2103 )
2104}
2105
2106#[test]
2107#[should_panic] // we currently can't handle this
2108fn recursive_type_alias() {
2109 assert_snapshot!(
2110 infer(r#"
2111struct A<X> {}
2112type Foo = Foo;
2113type Bar = A<Bar>;
2114fn test(x: Foo) {}
2115"#),
2116 @""
2117 )
2118}
2119
2120#[test]
2121fn no_panic_on_field_of_enum() {
2122 assert_snapshot!(
2123 infer(r#"
2124enum X {}
2125
2126fn test(x: X) {
2127 x.some_field;
2128}
2129"#),
2130 @r###"
2131 [20; 21) 'x': X
2132 [26; 47) '{ ...eld; }': ()
2133 [32; 33) 'x': X
2134 [32; 44) 'x.some_field': {unknown}
2135 "###
2136 );
2137}
2138
2139#[test]
2140fn bug_585() {
2141 assert_snapshot!(
2142 infer(r#"
2143fn test() {
2144 X {};
2145 match x {
2146 A::B {} => (),
2147 A::Y() => (),
2148 }
2149}
2150"#),
2151 @r###"
2152 [11; 89) '{ ... } }': ()
2153 [17; 21) 'X {}': {unknown}
2154 [27; 87) 'match ... }': ()
2155 [33; 34) 'x': {unknown}
2156 [45; 52) 'A::B {}': {unknown}
2157 [56; 58) '()': ()
2158 [68; 74) 'A::Y()': {unknown}
2159 [78; 80) '()': ()
2160 "###
2161 );
2162}
2163
2164#[test]
2165fn bug_651() {
2166 assert_snapshot!(
2167 infer(r#"
2168fn quux() {
2169 let y = 92;
2170 1 + y;
2171}
2172"#),
2173 @r###"
2174 [11; 41) '{ ...+ y; }': ()
2175 [21; 22) 'y': i32
2176 [25; 27) '92': i32
2177 [33; 34) '1': i32
2178 [33; 38) '1 + y': i32
2179 [37; 38) 'y': i32
2180 "###
2181 );
2182}
2183
2184#[test]
2185fn recursive_vars() {
2186 covers!(type_var_cycles_resolve_completely);
2187 covers!(type_var_cycles_resolve_as_possible);
2188 assert_snapshot!(
2189 infer(r#"
2190fn test() {
2191 let y = unknown;
2192 [y, &y];
2193}
2194"#),
2195 @r###"
2196 [11; 48) '{ ...&y]; }': ()
2197 [21; 22) 'y': &{unknown}
2198 [25; 32) 'unknown': &{unknown}
2199 [38; 45) '[y, &y]': [&&{unknown};_]
2200 [39; 40) 'y': &{unknown}
2201 [42; 44) '&y': &&{unknown}
2202 [43; 44) 'y': &{unknown}
2203 "###
2204 );
2205}
2206
2207#[test]
2208fn recursive_vars_2() {
2209 covers!(type_var_cycles_resolve_completely);
2210 covers!(type_var_cycles_resolve_as_possible);
2211 assert_snapshot!(
2212 infer(r#"
2213fn test() {
2214 let x = unknown;
2215 let y = unknown;
2216 [(x, y), (&y, &x)];
2217}
2218"#),
2219 @r###"
2220 [11; 80) '{ ...x)]; }': ()
2221 [21; 22) 'x': &&{unknown}
2222 [25; 32) 'unknown': &&{unknown}
2223 [42; 43) 'y': &&{unknown}
2224 [46; 53) 'unknown': &&{unknown}
2225 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_]
2226 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown})
2227 [61; 62) 'x': &&{unknown}
2228 [64; 65) 'y': &&{unknown}
2229 [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown})
2230 [69; 71) '&y': &&&{unknown}
2231 [70; 71) 'y': &&{unknown}
2232 [73; 75) '&x': &&&{unknown}
2233 [74; 75) 'x': &&{unknown}
2234 "###
2235 );
2236}
2237
2238#[test]
2239fn infer_type_param() {
2240 assert_snapshot!(
2241 infer(r#"
2242fn id<T>(x: T) -> T {
2243 x
2244}
2245
2246fn clone<T>(x: &T) -> T {
2247 *x
2248}
2249
2250fn test() {
2251 let y = 10u32;
2252 id(y);
2253 let x: bool = clone(z);
2254 id::<i128>(1);
2255}
2256"#),
2257 @r###"
2258 [10; 11) 'x': T
2259 [21; 30) '{ x }': T
2260 [27; 28) 'x': T
2261 [44; 45) 'x': &T
2262 [56; 66) '{ *x }': T
2263 [62; 64) '*x': T
2264 [63; 64) 'x': &T
2265 [78; 158) '{ ...(1); }': ()
2266 [88; 89) 'y': u32
2267 [92; 97) '10u32': u32
2268 [103; 105) 'id': fn id<u32>(T) -> T
2269 [103; 108) 'id(y)': u32
2270 [106; 107) 'y': u32
2271 [118; 119) 'x': bool
2272 [128; 133) 'clone': fn clone<bool>(&T) -> T
2273 [128; 136) 'clone(z)': bool
2274 [134; 135) 'z': &bool
2275 [142; 152) 'id::<i128>': fn id<i128>(T) -> T
2276 [142; 155) 'id::<i128>(1)': i128
2277 [153; 154) '1': i128
2278 "###
2279 );
2280}
2281
2282#[test]
2283fn infer_std_crash_1() {
2284 // caused stack overflow, taken from std
2285 assert_snapshot!(
2286 infer(r#"
2287enum Maybe<T> {
2288 Real(T),
2289 Fake,
2290}
2291
2292fn write() {
2293 match something_unknown {
2294 Maybe::Real(ref mut something) => (),
2295 }
2296}
2297"#),
2298 @r###"
2299 [54; 139) '{ ... } }': ()
2300 [60; 137) 'match ... }': ()
2301 [66; 83) 'someth...nknown': Maybe<{unknown}>
2302 [94; 124) 'Maybe:...thing)': Maybe<{unknown}>
2303 [106; 123) 'ref mu...ething': &mut {unknown}
2304 [128; 130) '()': ()
2305 "###
2306 );
2307}
2308
2309#[test]
2310fn infer_std_crash_2() {
2311 covers!(type_var_resolves_to_int_var);
2312 // caused "equating two type variables, ...", taken from std
2313 assert_snapshot!(
2314 infer(r#"
2315fn test_line_buffer() {
2316 &[0, b'\n', 1, b'\n'];
2317}
2318"#),
2319 @r###"
2320 [23; 53) '{ ...n']; }': ()
2321 [29; 50) '&[0, b...b'\n']': &[u8;_]
2322 [30; 50) '[0, b'...b'\n']': [u8;_]
2323 [31; 32) '0': u8
2324 [34; 39) 'b'\n'': u8
2325 [41; 42) '1': u8
2326 [44; 49) 'b'\n'': u8
2327 "###
2328 );
2329}
2330
2331#[test]
2332fn infer_std_crash_3() {
2333 // taken from rustc
2334 assert_snapshot!(
2335 infer(r#"
2336pub fn compute() {
2337 match nope!() {
2338 SizeSkeleton::Pointer { non_zero: true, tail } => {}
2339 }
2340}
2341"#),
2342 @r###"
2343 [18; 108) '{ ... } }': ()
2344 [24; 106) 'match ... }': ()
2345 [30; 37) 'nope!()': {unknown}
2346 [48; 94) 'SizeSk...tail }': {unknown}
2347 [82; 86) 'true': {unknown}
2348 [88; 92) 'tail': {unknown}
2349 [98; 100) '{}': ()
2350 "###
2351 );
2352}
2353
2354#[test]
2355fn infer_std_crash_4() {
2356 // taken from rustc
2357 assert_snapshot!(
2358 infer(r#"
2359pub fn primitive_type() {
2360 match *self {
2361 BorrowedRef { type_: Primitive(p), ..} => {},
2362 }
2363}
2364"#),
2365 @r###"
2366 [25; 106) '{ ... } }': ()
2367 [31; 104) 'match ... }': ()
2368 [37; 42) '*self': {unknown}
2369 [38; 42) 'self': {unknown}
2370 [53; 91) 'Borrow...), ..}': {unknown}
2371 [74; 86) 'Primitive(p)': {unknown}
2372 [84; 85) 'p': {unknown}
2373 [95; 97) '{}': ()
2374 "###
2375 );
2376}
2377
2378#[test]
2379fn infer_std_crash_5() {
2380 // taken from rustc
2381 assert_snapshot!(
2382 infer(r#"
2383fn extra_compiler_flags() {
2384 for content in doesnt_matter {
2385 let name = if doesnt_matter {
2386 first
2387 } else {
2388 &content
2389 };
2390
2391 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
2392 name
2393 } else {
2394 content
2395 };
2396 }
2397}
2398"#),
2399 @r###"
2400 [27; 323) '{ ... } }': ()
2401 [33; 321) 'for co... }': ()
2402 [37; 44) 'content': &{unknown}
2403 [48; 61) 'doesnt_matter': {unknown}
2404 [62; 321) '{ ... }': ()
2405 [76; 80) 'name': &&{unknown}
2406 [83; 167) 'if doe... }': &&{unknown}
2407 [86; 99) 'doesnt_matter': bool
2408 [100; 129) '{ ... }': &&{unknown}
2409 [114; 119) 'first': &&{unknown}
2410 [135; 167) '{ ... }': &&{unknown}
2411 [149; 157) '&content': &&{unknown}
2412 [150; 157) 'content': &{unknown}
2413 [182; 189) 'content': &{unknown}
2414 [192; 314) 'if ICE... }': &{unknown}
2415 [195; 232) 'ICE_RE..._VALUE': {unknown}
2416 [195; 248) 'ICE_RE...&name)': bool
2417 [242; 247) '&name': &&&{unknown}
2418 [243; 247) 'name': &&{unknown}
2419 [249; 277) '{ ... }': &&{unknown}
2420 [263; 267) 'name': &&{unknown}
2421 [283; 314) '{ ... }': &{unknown}
2422 [297; 304) 'content': &{unknown}
2423 "###
2424 );
2425}
2426
2427#[test]
2428fn infer_nested_generics_crash() {
2429 // another crash found typechecking rustc
2430 assert_snapshot!(
2431 infer(r#"
2432struct Canonical<V> {
2433 value: V,
2434}
2435struct QueryResponse<V> {
2436 value: V,
2437}
2438fn test<R>(query_response: Canonical<QueryResponse<R>>) {
2439 &query_response.value;
2440}
2441"#),
2442 @r###"
2443 [92; 106) 'query_response': Canonical<QueryResponse<R>>
2444 [137; 167) '{ ...lue; }': ()
2445 [143; 164) '&query....value': &QueryResponse<R>
2446 [144; 158) 'query_response': Canonical<QueryResponse<R>>
2447 [144; 164) 'query_....value': QueryResponse<R>
2448 "###
2449 );
2450}
2451
2452#[test]
2453fn bug_1030() {
2454 assert_snapshot!(infer(r#"
2455struct HashSet<T, H>;
2456struct FxHasher;
2457type FxHashSet<T> = HashSet<T, FxHasher>;
2458
2459impl<T, H> HashSet<T, H> {
2460 fn default() -> HashSet<T, H> {}
2461}
2462
2463pub fn main_loop() {
2464 FxHashSet::default();
2465}
2466"#),
2467 @r###"
2468 [144; 146) '{}': ()
2469 [169; 198) '{ ...t(); }': ()
2470 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
2471 [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>
2472 "###
2473 );
2474}
2475
2476#[test]
2477fn cross_crate_associated_method_call() {
2478 let (db, pos) = TestDB::with_position(
2479 r#"
2480//- /main.rs crate:main deps:other_crate
2481fn test() {
2482 let x = other_crate::foo::S::thing();
2483 x<|>;
2484}
2485
2486//- /lib.rs crate:other_crate
2487mod foo {
2488 struct S;
2489 impl S {
2490 fn thing() -> i128 {}
2491 }
2492}
2493"#,
2494 );
2495 assert_eq!("i128", type_at_pos(&db, pos));
2496}
2497
2498#[test]
2499fn infer_const() {
2500 assert_snapshot!(
2501 infer(r#"
2502struct Foo;
2503impl Foo { const ASSOC_CONST: u32 = 0; }
2504const GLOBAL_CONST: u32 = 101;
2505fn test() {
2506 const LOCAL_CONST: u32 = 99;
2507 let x = LOCAL_CONST;
2508 let z = GLOBAL_CONST;
2509 let id = Foo::ASSOC_CONST;
2510}
2511"#),
2512 @r###"
2513 [49; 50) '0': u32
2514 [80; 83) '101': u32
2515 [95; 213) '{ ...NST; }': ()
2516 [138; 139) 'x': {unknown}
2517 [142; 153) 'LOCAL_CONST': {unknown}
2518 [163; 164) 'z': u32
2519 [167; 179) 'GLOBAL_CONST': u32
2520 [189; 191) 'id': u32
2521 [194; 210) 'Foo::A..._CONST': u32
2522 "###
2523 );
2524}
2525
2526#[test]
2527fn infer_static() {
2528 assert_snapshot!(
2529 infer(r#"
2530static GLOBAL_STATIC: u32 = 101;
2531static mut GLOBAL_STATIC_MUT: u32 = 101;
2532fn test() {
2533 static LOCAL_STATIC: u32 = 99;
2534 static mut LOCAL_STATIC_MUT: u32 = 99;
2535 let x = LOCAL_STATIC;
2536 let y = LOCAL_STATIC_MUT;
2537 let z = GLOBAL_STATIC;
2538 let w = GLOBAL_STATIC_MUT;
2539}
2540"#),
2541 @r###"
2542 [29; 32) '101': u32
2543 [70; 73) '101': u32
2544 [85; 280) '{ ...MUT; }': ()
2545 [173; 174) 'x': {unknown}
2546 [177; 189) 'LOCAL_STATIC': {unknown}
2547 [199; 200) 'y': {unknown}
2548 [203; 219) 'LOCAL_...IC_MUT': {unknown}
2549 [229; 230) 'z': u32
2550 [233; 246) 'GLOBAL_STATIC': u32
2551 [256; 257) 'w': u32
2552 [260; 277) 'GLOBAL...IC_MUT': u32
2553 "###
2554 );
2555}
2556
2557#[test]
2558fn infer_trait_method_simple() {
2559 // the trait implementation is intentionally incomplete -- it shouldn't matter
2560 assert_snapshot!(
2561 infer(r#"
2562trait Trait1 {
2563 fn method(&self) -> u32;
2564}
2565struct S1;
2566impl Trait1 for S1 {}
2567trait Trait2 {
2568 fn method(&self) -> i128;
2569}
2570struct S2;
2571impl Trait2 for S2 {}
2572fn test() {
2573 S1.method(); // -> u32
2574 S2.method(); // -> i128
2575}
2576"#),
2577 @r###"
2578 [31; 35) 'self': &Self
2579 [110; 114) 'self': &Self
2580 [170; 228) '{ ...i128 }': ()
2581 [176; 178) 'S1': S1
2582 [176; 187) 'S1.method()': u32
2583 [203; 205) 'S2': S2
2584 [203; 214) 'S2.method()': i128
2585 "###
2586 );
2587}
2588
2589#[test]
2590fn infer_trait_method_scoped() {
2591 // the trait implementation is intentionally incomplete -- it shouldn't matter
2592 assert_snapshot!(
2593 infer(r#"
2594struct S;
2595mod foo {
2596 pub trait Trait1 {
2597 fn method(&self) -> u32;
2598 }
2599 impl Trait1 for super::S {}
2600}
2601mod bar {
2602 pub trait Trait2 {
2603 fn method(&self) -> i128;
2604 }
2605 impl Trait2 for super::S {}
2606}
2607
2608mod foo_test {
2609 use super::S;
2610 use super::foo::Trait1;
2611 fn test() {
2612 S.method(); // -> u32
2613 }
2614}
2615
2616mod bar_test {
2617 use super::S;
2618 use super::bar::Trait2;
2619 fn test() {
2620 S.method(); // -> i128
2621 }
2622}
2623"#),
2624 @r###"
2625 [63; 67) 'self': &Self
2626 [169; 173) 'self': &Self
2627 [300; 337) '{ ... }': ()
2628 [310; 311) 'S': S
2629 [310; 320) 'S.method()': u32
2630 [416; 454) '{ ... }': ()
2631 [426; 427) 'S': S
2632 [426; 436) 'S.method()': i128
2633 "###
2634 );
2635}
2636
2637#[test]
2638fn infer_trait_method_generic_1() {
2639 // the trait implementation is intentionally incomplete -- it shouldn't matter
2640 assert_snapshot!(
2641 infer(r#"
2642trait Trait<T> {
2643 fn method(&self) -> T;
2644}
2645struct S;
2646impl Trait<u32> for S {}
2647fn test() {
2648 S.method();
2649}
2650"#),
2651 @r###"
2652 [33; 37) 'self': &Self
2653 [92; 111) '{ ...d(); }': ()
2654 [98; 99) 'S': S
2655 [98; 108) 'S.method()': u32
2656 "###
2657 );
2658}
2659
2660#[test]
2661fn infer_trait_method_generic_more_params() {
2662 // the trait implementation is intentionally incomplete -- it shouldn't matter
2663 assert_snapshot!(
2664 infer(r#"
2665trait Trait<T1, T2, T3> {
2666 fn method1(&self) -> (T1, T2, T3);
2667 fn method2(&self) -> (T3, T2, T1);
2668}
2669struct S1;
2670impl Trait<u8, u16, u32> for S1 {}
2671struct S2;
2672impl<T> Trait<i8, i16, T> for S2 {}
2673fn test() {
2674 S1.method1(); // u8, u16, u32
2675 S1.method2(); // u32, u16, u8
2676 S2.method1(); // i8, i16, {unknown}
2677 S2.method2(); // {unknown}, i16, i8
2678}
2679"#),
2680 @r###"
2681 [43; 47) 'self': &Self
2682 [82; 86) 'self': &Self
2683 [210; 361) '{ ..., i8 }': ()
2684 [216; 218) 'S1': S1
2685 [216; 228) 'S1.method1()': (u8, u16, u32)
2686 [250; 252) 'S1': S1
2687 [250; 262) 'S1.method2()': (u32, u16, u8)
2688 [284; 286) 'S2': S2
2689 [284; 296) 'S2.method1()': (i8, i16, {unknown})
2690 [324; 326) 'S2': S2
2691 [324; 336) 'S2.method2()': ({unknown}, i16, i8)
2692 "###
2693 );
2694}
2695
2696#[test]
2697fn infer_trait_method_generic_2() {
2698 // the trait implementation is intentionally incomplete -- it shouldn't matter
2699 assert_snapshot!(
2700 infer(r#"
2701trait Trait<T> {
2702 fn method(&self) -> T;
2703}
2704struct S<T>(T);
2705impl<U> Trait<U> for S<U> {}
2706fn test() {
2707 S(1u32).method();
2708}
2709"#),
2710 @r###"
2711 [33; 37) 'self': &Self
2712 [102; 127) '{ ...d(); }': ()
2713 [108; 109) 'S': S<u32>(T) -> S<T>
2714 [108; 115) 'S(1u32)': S<u32>
2715 [108; 124) 'S(1u32...thod()': u32
2716 [110; 114) '1u32': u32
2717 "###
2718 );
2719}
2720
2721#[test]
2722fn infer_trait_assoc_method() {
2723 assert_snapshot!(
2724 infer(r#"
2725trait Default {
2726 fn default() -> Self;
2727}
2728struct S;
2729impl Default for S {}
2730fn test() {
2731 let s1: S = Default::default();
2732 let s2 = S::default();
2733 let s3 = <S as Default>::default();
2734}
2735"#),
2736 @r###"
2737 [87; 193) '{ ...t(); }': ()
2738 [97; 99) 's1': S
2739 [105; 121) 'Defaul...efault': fn default<S>() -> Self
2740 [105; 123) 'Defaul...ault()': S
2741 [133; 135) 's2': S
2742 [138; 148) 'S::default': fn default<S>() -> Self
2743 [138; 150) 'S::default()': S
2744 [160; 162) 's3': S
2745 [165; 188) '<S as ...efault': fn default<S>() -> Self
2746 [165; 190) '<S as ...ault()': S
2747 "###
2748 );
2749}
2750
2751#[test]
2752fn infer_trait_assoc_method_generics_1() {
2753 assert_snapshot!(
2754 infer(r#"
2755trait Trait<T> {
2756 fn make() -> T;
2757}
2758struct S;
2759impl Trait<u32> for S {}
2760struct G<T>;
2761impl<T> Trait<T> for G<T> {}
2762fn test() {
2763 let a = S::make();
2764 let b = G::<u64>::make();
2765 let c: f64 = G::make();
2766}
2767"#),
2768 @r###"
2769 [127; 211) '{ ...e(); }': ()
2770 [137; 138) 'a': u32
2771 [141; 148) 'S::make': fn make<S, u32>() -> T
2772 [141; 150) 'S::make()': u32
2773 [160; 161) 'b': u64
2774 [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
2775 [164; 180) 'G::<u6...make()': u64
2776 [190; 191) 'c': f64
2777 [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
2778 [199; 208) 'G::make()': f64
2779 "###
2780 );
2781}
2782
2783#[test]
2784fn infer_trait_assoc_method_generics_2() {
2785 assert_snapshot!(
2786 infer(r#"
2787trait Trait<T> {
2788 fn make<U>() -> (T, U);
2789}
2790struct S;
2791impl Trait<u32> for S {}
2792struct G<T>;
2793impl<T> Trait<T> for G<T> {}
2794fn test() {
2795 let a = S::make::<i64>();
2796 let b: (_, i64) = S::make();
2797 let c = G::<u32>::make::<i64>();
2798 let d: (u32, _) = G::make::<i64>();
2799 let e: (u32, i64) = G::make();
2800}
2801"#),
2802 @r###"
2803 [135; 313) '{ ...e(); }': ()
2804 [145; 146) 'a': (u32, i64)
2805 [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
2806 [149; 165) 'S::mak...i64>()': (u32, i64)
2807 [175; 176) 'b': (u32, i64)
2808 [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
2809 [189; 198) 'S::make()': (u32, i64)
2810 [208; 209) 'c': (u32, i64)
2811 [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2812 [212; 235) 'G::<u3...i64>()': (u32, i64)
2813 [245; 246) 'd': (u32, i64)
2814 [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
2815 [259; 275) 'G::mak...i64>()': (u32, i64)
2816 [285; 286) 'e': (u32, i64)
2817 [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
2818 [301; 310) 'G::make()': (u32, i64)
2819 "###
2820 );
2821}
2822
2823#[test]
2824fn infer_trait_assoc_method_generics_3() {
2825 assert_snapshot!(
2826 infer(r#"
2827trait Trait<T> {
2828 fn make() -> (Self, T);
2829}
2830struct S<T>;
2831impl Trait<i64> for S<i32> {}
2832fn test() {
2833 let a = S::make();
2834}
2835"#),
2836 @r###"
2837 [101; 127) '{ ...e(); }': ()
2838 [111; 112) 'a': (S<i32>, i64)
2839 [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T)
2840 [115; 124) 'S::make()': (S<i32>, i64)
2841 "###
2842 );
2843}
2844
2845#[test]
2846fn infer_trait_assoc_method_generics_4() {
2847 assert_snapshot!(
2848 infer(r#"
2849trait Trait<T> {
2850 fn make() -> (Self, T);
2851}
2852struct S<T>;
2853impl Trait<i64> for S<u64> {}
2854impl Trait<i32> for S<u32> {}
2855fn test() {
2856 let a: (S<u64>, _) = S::make();
2857 let b: (_, i32) = S::make();
2858}
2859"#),
2860 @r###"
2861 [131; 203) '{ ...e(); }': ()
2862 [141; 142) 'a': (S<u64>, i64)
2863 [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T)
2864 [158; 167) 'S::make()': (S<u64>, i64)
2865 [177; 178) 'b': (S<u32>, i32)
2866 [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T)
2867 [191; 200) 'S::make()': (S<u32>, i32)
2868 "###
2869 );
2870}
2871
2872#[test]
2873fn infer_trait_assoc_method_generics_5() {
2874 assert_snapshot!(
2875 infer(r#"
2876trait Trait<T> {
2877 fn make<U>() -> (Self, T, U);
2878}
2879struct S<T>;
2880impl Trait<i64> for S<u64> {}
2881fn test() {
2882 let a = <S as Trait<i64>>::make::<u8>();
2883 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
2884}
2885"#),
2886 @r###"
2887 [107; 211) '{ ...>(); }': ()
2888 [117; 118) 'a': (S<u64>, i64, u8)
2889 [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2890 [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
2891 [162; 163) 'b': (S<u64>, i64, u8)
2892 [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
2893 [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
2894 "###
2895 );
2896}
2897
2898#[test]
2899fn infer_from_bound_1() {
2900 assert_snapshot!(
2901 infer(r#"
2902trait Trait<T> {}
2903struct S<T>(T);
2904impl<U> Trait<U> for S<U> {}
2905fn foo<T: Trait<u32>>(t: T) {}
2906fn test() {
2907 let s = S(unknown);
2908 foo(s);
2909}
2910"#),
2911 @r###"
2912 [86; 87) 't': T
2913 [92; 94) '{}': ()
2914 [105; 144) '{ ...(s); }': ()
2915 [115; 116) 's': S<u32>
2916 [119; 120) 'S': S<u32>(T) -> S<T>
2917 [119; 129) 'S(unknown)': S<u32>
2918 [121; 128) 'unknown': u32
2919 [135; 138) 'foo': fn foo<S<u32>>(T) -> ()
2920 [135; 141) 'foo(s)': ()
2921 [139; 140) 's': S<u32>
2922 "###
2923 );
2924}
2925
2926#[test]
2927fn infer_from_bound_2() {
2928 assert_snapshot!(
2929 infer(r#"
2930trait Trait<T> {}
2931struct S<T>(T);
2932impl<U> Trait<U> for S<U> {}
2933fn foo<U, T: Trait<U>>(t: T) -> U {}
2934fn test() {
2935 let s = S(unknown);
2936 let x: u32 = foo(s);
2937}
2938"#),
2939 @r###"
2940 [87; 88) 't': T
2941 [98; 100) '{}': ()
2942 [111; 163) '{ ...(s); }': ()
2943 [121; 122) 's': S<u32>
2944 [125; 126) 'S': S<u32>(T) -> S<T>
2945 [125; 135) 'S(unknown)': S<u32>
2946 [127; 134) 'unknown': u32
2947 [145; 146) 'x': u32
2948 [154; 157) 'foo': fn foo<u32, S<u32>>(T) -> U
2949 [154; 160) 'foo(s)': u32
2950 [158; 159) 's': S<u32>
2951 "###
2952 );
2953}
2954
2955#[test]
2956fn infer_call_trait_method_on_generic_param_1() {
2957 assert_snapshot!(
2958 infer(r#"
2959trait Trait {
2960 fn method(&self) -> u32;
2961}
2962fn test<T: Trait>(t: T) {
2963 t.method();
2964}
2965"#),
2966 @r###"
2967 [30; 34) 'self': &Self
2968 [64; 65) 't': T
2969 [70; 89) '{ ...d(); }': ()
2970 [76; 77) 't': T
2971 [76; 86) 't.method()': u32
2972 "###
2973 );
2974}
2975
2976#[test]
2977fn infer_call_trait_method_on_generic_param_2() {
2978 assert_snapshot!(
2979 infer(r#"
2980trait Trait<T> {
2981 fn method(&self) -> T;
2982}
2983fn test<U, T: Trait<U>>(t: T) {
2984 t.method();
2985}
2986"#),
2987 @r###"
2988 [33; 37) 'self': &Self
2989 [71; 72) 't': T
2990 [77; 96) '{ ...d(); }': ()
2991 [83; 84) 't': T
2992 [83; 93) 't.method()': [missing name]
2993 "###
2994 );
2995}
2996
2997#[test]
2998fn infer_with_multiple_trait_impls() {
2999 assert_snapshot!(
3000 infer(r#"
3001trait Into<T> {
3002 fn into(self) -> T;
3003}
3004struct S;
3005impl Into<u32> for S {}
3006impl Into<u64> for S {}
3007fn test() {
3008 let x: u32 = S.into();
3009 let y: u64 = S.into();
3010 let z = Into::<u64>::into(S);
3011}
3012"#),
3013 @r###"
3014 [29; 33) 'self': Self
3015 [111; 202) '{ ...(S); }': ()
3016 [121; 122) 'x': u32
3017 [130; 131) 'S': S
3018 [130; 138) 'S.into()': u32
3019 [148; 149) 'y': u64
3020 [157; 158) 'S': S
3021 [157; 165) 'S.into()': u64
3022 [175; 176) 'z': u64
3023 [179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
3024 [179; 199) 'Into::...nto(S)': u64
3025 [197; 198) 'S': S
3026 "###
3027 );
3028}
3029
3030#[test]
3031fn infer_project_associated_type() {
3032 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
3033 assert_snapshot!(
3034 infer(r#"
3035trait Iterable {
3036 type Item;
3037}
3038struct S;
3039impl Iterable for S { type Item = u32; }
3040fn test<T: Iterable>() {
3041 let x: <S as Iterable>::Item = 1;
3042 let y: <T as Iterable>::Item = no_matter;
3043 let z: T::Item = no_matter;
3044 let a: <T>::Item = no_matter;
3045}
3046"#),
3047 @r###"
3048 [108; 261) '{ ...ter; }': ()
3049 [118; 119) 'x': u32
3050 [145; 146) '1': u32
3051 [156; 157) 'y': {unknown}
3052 [183; 192) 'no_matter': {unknown}
3053 [202; 203) 'z': {unknown}
3054 [215; 224) 'no_matter': {unknown}
3055 [234; 235) 'a': {unknown}
3056 [249; 258) 'no_matter': {unknown}
3057 "###
3058 );
3059}
3060
3061#[test]
3062fn infer_return_associated_type() {
3063 assert_snapshot!(
3064 infer(r#"
3065trait Iterable {
3066 type Item;
3067}
3068struct S;
3069impl Iterable for S { type Item = u32; }
3070fn foo1<T: Iterable>(t: T) -> T::Item {}
3071fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
3072fn foo3<T: Iterable>(t: T) -> <T>::Item {}
3073fn test() {
3074 let x = foo1(S);
3075 let y = foo2(S);
3076 let z = foo3(S);
3077}
3078"#),
3079 @r###"
3080 [106; 107) 't': T
3081 [123; 125) '{}': ()
3082 [147; 148) 't': T
3083 [178; 180) '{}': ()
3084 [202; 203) 't': T
3085 [221; 223) '{}': ()
3086 [234; 300) '{ ...(S); }': ()
3087 [244; 245) 'x': u32
3088 [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item
3089 [248; 255) 'foo1(S)': u32
3090 [253; 254) 'S': S
3091 [265; 266) 'y': u32
3092 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
3093 [269; 276) 'foo2(S)': u32
3094 [274; 275) 'S': S
3095 [286; 287) 'z': u32
3096 [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item
3097 [290; 297) 'foo3(S)': u32
3098 [295; 296) 'S': S
3099 "###
3100 );
3101}
3102
3103#[test]
3104fn infer_associated_type_bound() {
3105 assert_snapshot!(
3106 infer(r#"
3107trait Iterable {
3108 type Item;
3109}
3110fn test<T: Iterable<Item=u32>>() {
3111 let y: T::Item = unknown;
3112}
3113"#),
3114 @r###"
3115 [67; 100) '{ ...own; }': ()
3116 [77; 78) 'y': {unknown}
3117 [90; 97) 'unknown': {unknown}
3118 "###
3119 );
3120}
3121
3122#[test]
3123fn infer_const_body() {
3124 assert_snapshot!(
3125 infer(r#"
3126const A: u32 = 1 + 1;
3127static B: u64 = { let x = 1; x };
3128"#),
3129 @r###"
3130 [16; 17) '1': u32
3131 [16; 21) '1 + 1': u32
3132 [20; 21) '1': u32
3133 [39; 55) '{ let ...1; x }': u64
3134 [45; 46) 'x': u64
3135 [49; 50) '1': u64
3136 [52; 53) 'x': u64
3137 "###
3138 );
3139}
3140
3141#[test]
3142fn tuple_struct_fields() {
3143 assert_snapshot!(
3144 infer(r#"
3145struct S(i32, u64);
3146fn test() -> u64 {
3147 let a = S(4, 6);
3148 let b = a.0;
3149 a.1
3150}
3151"#),
3152 @r###"
3153 [38; 87) '{ ... a.1 }': u64
3154 [48; 49) 'a': S
3155 [52; 53) 'S': S(i32, u64) -> S
3156 [52; 59) 'S(4, 6)': S
3157 [54; 55) '4': i32
3158 [57; 58) '6': u64
3159 [69; 70) 'b': i32
3160 [73; 74) 'a': S
3161 [73; 76) 'a.0': i32
3162 [82; 83) 'a': S
3163 [82; 85) 'a.1': u64
3164 "###
3165 );
3166}
3167
3168#[test]
3169fn tuple_struct_with_fn() {
3170 assert_snapshot!(
3171 infer(r#"
3172struct S(fn(u32) -> u64);
3173fn test() -> u64 {
3174 let a = S(|i| 2*i);
3175 let b = a.0(4);
3176 a.0(2)
3177}
3178"#),
3179 @r###"
3180 [44; 102) '{ ...0(2) }': u64
3181 [54; 55) 'a': S
3182 [58; 59) 'S': S(fn(u32) -> u64) -> S
3183 [58; 68) 'S(|i| 2*i)': S
3184 [60; 67) '|i| 2*i': |i32| -> i32
3185 [61; 62) 'i': i32
3186 [64; 65) '2': i32
3187 [64; 67) '2*i': i32
3188 [66; 67) 'i': i32
3189 [78; 79) 'b': u64
3190 [82; 83) 'a': S
3191 [82; 85) 'a.0': fn(u32) -> u64
3192 [82; 88) 'a.0(4)': u64
3193 [86; 87) '4': u32
3194 [94; 95) 'a': S
3195 [94; 97) 'a.0': fn(u32) -> u64
3196 [94; 100) 'a.0(2)': u64
3197 [98; 99) '2': u32
3198 "###
3199 );
3200}
3201
3202#[test]
3203fn indexing_arrays() {
3204 assert_snapshot!(
3205 infer("fn main() { &mut [9][2]; }"),
3206 @r###"
3207 [10; 26) '{ &mut...[2]; }': ()
3208 [12; 23) '&mut [9][2]': &mut {unknown}
3209 [17; 20) '[9]': [i32;_]
3210 [17; 23) '[9][2]': {unknown}
3211 [18; 19) '9': i32
3212 [21; 22) '2': i32
3213 "###
3214 )
3215}
3216
3217#[test]
3218fn infer_macros_expanded() {
3219 assert_snapshot!(
3220 infer(r#"
3221struct Foo(Vec<i32>);
3222
3223macro_rules! foo {
3224 ($($item:expr),*) => {
3225 {
3226 Foo(vec![$($item,)*])
3227 }
3228 };
3229}
3230
3231fn main() {
3232 let x = foo!(1,2);
3233}
3234"#),
3235 @r###"
3236 ![0; 17) '{Foo(v...,2,])}': Foo
3237 ![1; 4) 'Foo': Foo({unknown}) -> Foo
3238 ![1; 16) 'Foo(vec![1,2,])': Foo
3239 ![5; 15) 'vec![1,2,]': {unknown}
3240 [156; 182) '{ ...,2); }': ()
3241 [166; 167) 'x': Foo
3242 "###
3243 );
3244}
3245
3246#[test]
3247fn infer_legacy_textual_scoped_macros_expanded() {
3248 assert_snapshot!(
3249 infer(r#"
3250struct Foo(Vec<i32>);
3251
3252#[macro_use]
3253mod m {
3254 macro_rules! foo {
3255 ($($item:expr),*) => {
3256 {
3257 Foo(vec![$($item,)*])
3258 }
3259 };
3260 }
3261}
3262
3263fn main() {
3264 let x = foo!(1,2);
3265 let y = crate::foo!(1,2);
3266}
3267"#),
3268 @r###"
3269 ![0; 17) '{Foo(v...,2,])}': Foo
3270 ![1; 4) 'Foo': Foo({unknown}) -> Foo
3271 ![1; 16) 'Foo(vec![1,2,])': Foo
3272 ![5; 15) 'vec![1,2,]': {unknown}
3273 [195; 251) '{ ...,2); }': ()
3274 [205; 206) 'x': Foo
3275 [228; 229) 'y': {unknown}
3276 [232; 248) 'crate:...!(1,2)': {unknown}
3277 "###
3278 );
3279}
3280
3281#[test]
3282fn infer_path_qualified_macros_expanded() {
3283 assert_snapshot!(
3284 infer(r#"
3285#[macro_export]
3286macro_rules! foo {
3287 () => { 42i32 }
3288}
3289
3290mod m {
3291 pub use super::foo as bar;
3292}
3293
3294fn main() {
3295 let x = crate::foo!();
3296 let y = m::bar!();
3297}
3298"#),
3299 @r###"
3300 ![0; 5) '42i32': i32
3301 ![0; 5) '42i32': i32
3302 [111; 164) '{ ...!(); }': ()
3303 [121; 122) 'x': i32
3304 [148; 149) 'y': i32
3305 "###
3306 );
3307}
3308
3309#[test]
3310fn infer_type_value_macro_having_same_name() {
3311 assert_snapshot!(
3312 infer(r#"
3313#[macro_export]
3314macro_rules! foo {
3315 () => {
3316 mod foo {
3317 pub use super::foo;
3318 }
3319 };
3320 ($x:tt) => {
3321 $x
3322 };
3323}
3324
3325foo!();
3326
3327fn foo() {
3328 let foo = foo::foo!(42i32);
3329}
3330"#),
3331 @r###"
3332 ![0; 5) '42i32': i32
3333 [171; 206) '{ ...32); }': ()
3334 [181; 184) 'foo': i32
3335 "###
3336 );
3337}
3338
3339#[test]
3340fn processes_impls_generated_by_macros() {
3341 let t = type_at(
3342 r#"
3343//- /main.rs
3344macro_rules! m {
3345 ($ident:ident) => (impl Trait for $ident {})
3346}
3347trait Trait { fn foo(self) -> u128 {} }
3348struct S;
3349m!(S);
3350fn test() { S.foo()<|>; }
3351"#,
3352 );
3353 assert_eq!(t, "u128");
3354}
3355
3356#[test]
3357fn infer_macro_with_dollar_crate_is_correct_in_expr() {
3358 let (db, pos) = TestDB::with_position(
3359 r#"
3360//- /main.rs crate:main deps:foo
3361fn test() {
3362 let x = (foo::foo!(1), foo::foo!(2));
3363 x<|>;
3364}
3365
3366//- /lib.rs crate:foo
3367#[macro_export]
3368macro_rules! foo {
3369 (1) => { $crate::bar!() };
3370 (2) => { 1 + $crate::baz() };
3371}
3372
3373#[macro_export]
3374macro_rules! bar {
3375 () => { 42 }
3376}
3377
3378pub fn baz() -> usize { 31usize }
3379"#,
3380 );
3381 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
3382}
3383
3384#[ignore]
3385#[test]
3386fn method_resolution_trait_before_autoref() {
3387 let t = type_at(
3388 r#"
3389//- /main.rs
3390trait Trait { fn foo(self) -> u128; }
3391struct S;
3392impl S { fn foo(&self) -> i8 { 0 } }
3393impl Trait for S { fn foo(self) -> u128 { 0 } }
3394fn test() { S.foo()<|>; }
3395"#,
3396 );
3397 assert_eq!(t, "u128");
3398}
3399
3400#[ignore]
3401#[test]
3402fn method_resolution_by_value_before_autoref() {
3403 let t = type_at(
3404 r#"
3405//- /main.rs
3406trait Clone { fn clone(&self) -> Self; }
3407struct S;
3408impl Clone for S {}
3409impl Clone for &S {}
3410fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
3411"#,
3412 );
3413 assert_eq!(t, "(S, S, &S)");
3414}
3415
3416#[test]
3417fn method_resolution_trait_before_autoderef() {
3418 let t = type_at(
3419 r#"
3420//- /main.rs
3421trait Trait { fn foo(self) -> u128; }
3422struct S;
3423impl S { fn foo(self) -> i8 { 0 } }
3424impl Trait for &S { fn foo(self) -> u128 { 0 } }
3425fn test() { (&S).foo()<|>; }
3426"#,
3427 );
3428 assert_eq!(t, "u128");
3429}
3430
3431#[test]
3432fn method_resolution_impl_before_trait() {
3433 let t = type_at(
3434 r#"
3435//- /main.rs
3436trait Trait { fn foo(self) -> u128; }
3437struct S;
3438impl S { fn foo(self) -> i8 { 0 } }
3439impl Trait for S { fn foo(self) -> u128 { 0 } }
3440fn test() { S.foo()<|>; }
3441"#,
3442 );
3443 assert_eq!(t, "i8");
3444}
3445
3446#[test]
3447fn method_resolution_trait_autoderef() {
3448 let t = type_at(
3449 r#"
3450//- /main.rs
3451trait Trait { fn foo(self) -> u128; }
3452struct S;
3453impl Trait for S { fn foo(self) -> u128 { 0 } }
3454fn test() { (&S).foo()<|>; }
3455"#,
3456 );
3457 assert_eq!(t, "u128");
3458}
3459
3460#[test]
3461fn method_resolution_trait_from_prelude() {
3462 let (db, pos) = TestDB::with_position(
3463 r#"
3464//- /main.rs crate:main deps:other_crate
3465struct S;
3466impl Clone for S {}
3467
3468fn test() {
3469 S.clone()<|>;
3470}
3471
3472//- /lib.rs crate:other_crate
3473#[prelude_import] use foo::*;
3474
3475mod foo {
3476 trait Clone {
3477 fn clone(&self) -> Self;
3478 }
3479}
3480"#,
3481 );
3482 assert_eq!("S", type_at_pos(&db, pos));
3483}
3484
3485#[test]
3486fn method_resolution_where_clause_for_unknown_trait() {
3487 // The blanket impl shouldn't apply because we can't even resolve UnknownTrait
3488 let t = type_at(
3489 r#"
3490//- /main.rs
3491trait Trait { fn foo(self) -> u128; }
3492struct S;
3493impl<T> Trait for T where T: UnknownTrait {}
3494fn test() { (&S).foo()<|>; }
3495"#,
3496 );
3497 assert_eq!(t, "{unknown}");
3498}
3499
3500#[test]
3501fn method_resolution_where_clause_not_met() {
3502 // The blanket impl shouldn't apply because we can't prove S: Clone
3503 let t = type_at(
3504 r#"
3505//- /main.rs
3506trait Clone {}
3507trait Trait { fn foo(self) -> u128; }
3508struct S;
3509impl<T> Trait for T where T: Clone {}
3510fn test() { (&S).foo()<|>; }
3511"#,
3512 );
3513 // This is also to make sure that we don't resolve to the foo method just
3514 // because that's the only method named foo we can find, which would make
3515 // the below tests not work
3516 assert_eq!(t, "{unknown}");
3517}
3518
3519#[test]
3520fn method_resolution_where_clause_inline_not_met() {
3521 // The blanket impl shouldn't apply because we can't prove S: Clone
3522 let t = type_at(
3523 r#"
3524//- /main.rs
3525trait Clone {}
3526trait Trait { fn foo(self) -> u128; }
3527struct S;
3528impl<T: Clone> Trait for T {}
3529fn test() { (&S).foo()<|>; }
3530"#,
3531 );
3532 assert_eq!(t, "{unknown}");
3533}
3534
3535#[test]
3536fn method_resolution_where_clause_1() {
3537 let t = type_at(
3538 r#"
3539//- /main.rs
3540trait Clone {}
3541trait Trait { fn foo(self) -> u128; }
3542struct S;
3543impl Clone for S {}
3544impl<T> Trait for T where T: Clone {}
3545fn test() { S.foo()<|>; }
3546"#,
3547 );
3548 assert_eq!(t, "u128");
3549}
3550
3551#[test]
3552fn method_resolution_where_clause_2() {
3553 let t = type_at(
3554 r#"
3555//- /main.rs
3556trait Into<T> { fn into(self) -> T; }
3557trait From<T> { fn from(other: T) -> Self; }
3558struct S1;
3559struct S2;
3560impl From<S2> for S1 {}
3561impl<T, U> Into<U> for T where U: From<T> {}
3562fn test() { S2.into()<|>; }
3563"#,
3564 );
3565 assert_eq!(t, "{unknown}");
3566}
3567
3568#[test]
3569fn method_resolution_where_clause_inline() {
3570 let t = type_at(
3571 r#"
3572//- /main.rs
3573trait Into<T> { fn into(self) -> T; }
3574trait From<T> { fn from(other: T) -> Self; }
3575struct S1;
3576struct S2;
3577impl From<S2> for S1 {}
3578impl<T, U: From<T>> Into<U> for T {}
3579fn test() { S2.into()<|>; }
3580"#,
3581 );
3582 assert_eq!(t, "{unknown}");
3583}
3584
3585#[test]
3586fn method_resolution_encountering_fn_type() {
3587 type_at(
3588 r#"
3589//- /main.rs
3590fn foo() {}
3591trait FnOnce { fn call(self); }
3592fn test() { foo.call()<|>; }
3593"#,
3594 );
3595}
3596
3597#[test]
3598fn method_resolution_slow() {
3599 // this can get quite slow if we set the solver size limit too high
3600 let t = type_at(
3601 r#"
3602//- /main.rs
3603trait SendX {}
3604
3605struct S1; impl SendX for S1 {}
3606struct S2; impl SendX for S2 {}
3607struct U1;
3608
3609trait Trait { fn method(self); }
3610
3611struct X1<A, B> {}
3612impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
3613
3614struct S<B, C> {}
3615
3616trait FnX {}
3617
3618impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
3619
3620fn test() { (S {}).method()<|>; }
3621"#,
3622 );
3623 assert_eq!(t, "()");
3624}
3625
3626#[test]
3627fn shadowing_primitive() {
3628 let t = type_at(
3629 r#"
3630//- /main.rs
3631struct i32;
3632struct Foo;
3633
3634impl i32 { fn foo(&self) -> Foo { Foo } }
3635
3636fn main() {
3637 let x: i32 = i32;
3638 x.foo()<|>;
3639}"#,
3640 );
3641 assert_eq!(t, "Foo");
3642}
3643
3644#[test]
3645fn deref_trait() {
3646 let t = type_at(
3647 r#"
3648//- /main.rs
3649#[lang = "deref"]
3650trait Deref {
3651 type Target;
3652 fn deref(&self) -> &Self::Target;
3653}
3654
3655struct Arc<T>;
3656impl<T> Deref for Arc<T> {
3657 type Target = T;
3658}
3659
3660struct S;
3661impl S {
3662 fn foo(&self) -> u128 {}
3663}
3664
3665fn test(s: Arc<S>) {
3666 (*s, s.foo())<|>;
3667}
3668"#,
3669 );
3670 assert_eq!(t, "(S, u128)");
3671}
3672
3673#[test]
3674fn deref_trait_with_inference_var() {
3675 let t = type_at(
3676 r#"
3677//- /main.rs
3678#[lang = "deref"]
3679trait Deref {
3680 type Target;
3681 fn deref(&self) -> &Self::Target;
3682}
3683
3684struct Arc<T>;
3685fn new_arc<T>() -> Arc<T> {}
3686impl<T> Deref for Arc<T> {
3687 type Target = T;
3688}
3689
3690struct S;
3691fn foo(a: Arc<S>) {}
3692
3693fn test() {
3694 let a = new_arc();
3695 let b = (*a)<|>;
3696 foo(a);
3697}
3698"#,
3699 );
3700 assert_eq!(t, "S");
3701}
3702
3703#[test]
3704fn deref_trait_infinite_recursion() {
3705 let t = type_at(
3706 r#"
3707//- /main.rs
3708#[lang = "deref"]
3709trait Deref {
3710 type Target;
3711 fn deref(&self) -> &Self::Target;
3712}
3713
3714struct S;
3715
3716impl Deref for S {
3717 type Target = S;
3718}
3719
3720fn test(s: S) {
3721 s.foo()<|>;
3722}
3723"#,
3724 );
3725 assert_eq!(t, "{unknown}");
3726}
3727
3728#[test]
3729fn deref_trait_with_question_mark_size() {
3730 let t = type_at(
3731 r#"
3732//- /main.rs
3733#[lang = "deref"]
3734trait Deref {
3735 type Target;
3736 fn deref(&self) -> &Self::Target;
3737}
3738
3739struct Arc<T>;
3740impl<T> Deref for Arc<T> {
3741 type Target = T;
3742}
3743
3744struct S;
3745impl S {
3746 fn foo(&self) -> u128 {}
3747}
3748
3749fn test(s: Arc<S>) {
3750 (*s, s.foo())<|>;
3751}
3752"#,
3753 );
3754 assert_eq!(t, "(S, u128)");
3755}
3756
3757#[test]
3758fn obligation_from_function_clause() {
3759 let t = type_at(
3760 r#"
3761//- /main.rs
3762struct S;
3763
3764trait Trait<T> {}
3765impl Trait<u32> for S {}
3766
3767fn foo<T: Trait<U>, U>(t: T) -> U {}
3768
3769fn test(s: S) {
3770 foo(s)<|>;
3771}
3772"#,
3773 );
3774 assert_eq!(t, "u32");
3775}
3776
3777#[test]
3778fn obligation_from_method_clause() {
3779 let t = type_at(
3780 r#"
3781//- /main.rs
3782struct S;
3783
3784trait Trait<T> {}
3785impl Trait<isize> for S {}
3786
3787struct O;
3788impl O {
3789 fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
3790}
3791
3792fn test() {
3793 O.foo(S)<|>;
3794}
3795"#,
3796 );
3797 assert_eq!(t, "isize");
3798}
3799
3800#[test]
3801fn obligation_from_self_method_clause() {
3802 let t = type_at(
3803 r#"
3804//- /main.rs
3805struct S;
3806
3807trait Trait<T> {}
3808impl Trait<i64> for S {}
3809
3810impl S {
3811 fn foo<U>(&self) -> U where Self: Trait<U> {}
3812}
3813
3814fn test() {
3815 S.foo()<|>;
3816}
3817"#,
3818 );
3819 assert_eq!(t, "i64");
3820}
3821
3822#[test]
3823fn obligation_from_impl_clause() {
3824 let t = type_at(
3825 r#"
3826//- /main.rs
3827struct S;
3828
3829trait Trait<T> {}
3830impl Trait<&str> for S {}
3831
3832struct O<T>;
3833impl<U, T: Trait<U>> O<T> {
3834 fn foo(&self) -> U {}
3835}
3836
3837fn test(o: O<S>) {
3838 o.foo()<|>;
3839}
3840"#,
3841 );
3842 assert_eq!(t, "&str");
3843}
3844
3845#[test]
3846fn generic_param_env_1() {
3847 let t = type_at(
3848 r#"
3849//- /main.rs
3850trait Clone {}
3851trait Trait { fn foo(self) -> u128; }
3852struct S;
3853impl Clone for S {}
3854impl<T> Trait for T where T: Clone {}
3855fn test<T: Clone>(t: T) { t.foo()<|>; }
3856"#,
3857 );
3858 assert_eq!(t, "u128");
3859}
3860
3861#[test]
3862fn generic_param_env_1_not_met() {
3863 let t = type_at(
3864 r#"
3865//- /main.rs
3866trait Clone {}
3867trait Trait { fn foo(self) -> u128; }
3868struct S;
3869impl Clone for S {}
3870impl<T> Trait for T where T: Clone {}
3871fn test<T>(t: T) { t.foo()<|>; }
3872"#,
3873 );
3874 assert_eq!(t, "{unknown}");
3875}
3876
3877#[test]
3878fn generic_param_env_2() {
3879 let t = type_at(
3880 r#"
3881//- /main.rs
3882trait Trait { fn foo(self) -> u128; }
3883struct S;
3884impl Trait for S {}
3885fn test<T: Trait>(t: T) { t.foo()<|>; }
3886"#,
3887 );
3888 assert_eq!(t, "u128");
3889}
3890
3891#[test]
3892fn generic_param_env_2_not_met() {
3893 let t = type_at(
3894 r#"
3895//- /main.rs
3896trait Trait { fn foo(self) -> u128; }
3897struct S;
3898impl Trait for S {}
3899fn test<T>(t: T) { t.foo()<|>; }
3900"#,
3901 );
3902 assert_eq!(t, "{unknown}");
3903}
3904
3905#[test]
3906fn generic_param_env_deref() {
3907 let t = type_at(
3908 r#"
3909//- /main.rs
3910#[lang = "deref"]
3911trait Deref {
3912 type Target;
3913}
3914trait Trait {}
3915impl<T> Deref for T where T: Trait {
3916 type Target = i128;
3917}
3918fn test<T: Trait>(t: T) { (*t)<|>; }
3919"#,
3920 );
3921 assert_eq!(t, "i128");
3922}
3923
3924#[test]
3925fn associated_type_placeholder() {
3926 let t = type_at(
3927 r#"
3928//- /main.rs
3929pub trait ApplyL {
3930 type Out;
3931}
3932
3933pub struct RefMutL<T>;
3934
3935impl<T> ApplyL for RefMutL<T> {
3936 type Out = <T as ApplyL>::Out;
3937}
3938
3939fn test<T: ApplyL>() {
3940 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
3941 y<|>;
3942}
3943"#,
3944 );
3945 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
3946 // FIXME: fix type parameter names going missing when going through Chalk
3947 assert_eq!(t, "ApplyL::Out<[missing name]>");
3948}
3949
3950#[test]
3951fn associated_type_placeholder_2() {
3952 let t = type_at(
3953 r#"
3954//- /main.rs
3955pub trait ApplyL {
3956 type Out;
3957}
3958fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
3959
3960fn test<T: ApplyL>(t: T) {
3961 let y = foo(t);
3962 y<|>;
3963}
3964"#,
3965 );
3966 // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
3967 // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
3968 // to the trait env ourselves here; probably Chalk can't do this by itself.
3969 // assert_eq!(t, "ApplyL::Out<[missing name]>");
3970 assert_eq!(t, "{unknown}");
3971}
3972
3973#[test]
3974fn impl_trait() {
3975 assert_snapshot!(
3976 infer(r#"
3977trait Trait<T> {
3978 fn foo(&self) -> T;
3979 fn foo2(&self) -> i64;
3980}
3981fn bar() -> impl Trait<u64> {}
3982
3983fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
3984 x;
3985 y;
3986 let z = bar();
3987 x.foo();
3988 y.foo();
3989 z.foo();
3990 x.foo2();
3991 y.foo2();
3992 z.foo2();
3993}
3994"#),
3995 @r###"
3996 [30; 34) 'self': &Self
3997 [55; 59) 'self': &Self
3998 [99; 101) '{}': ()
3999 [111; 112) 'x': impl Trait<u64>
4000 [131; 132) 'y': &impl Trait<u64>
4001 [152; 269) '{ ...2(); }': ()
4002 [158; 159) 'x': impl Trait<u64>
4003 [165; 166) 'y': &impl Trait<u64>
4004 [176; 177) 'z': impl Trait<u64>
4005 [180; 183) 'bar': fn bar() -> impl Trait<u64>
4006 [180; 185) 'bar()': impl Trait<u64>
4007 [191; 192) 'x': impl Trait<u64>
4008 [191; 198) 'x.foo()': u64
4009 [204; 205) 'y': &impl Trait<u64>
4010 [204; 211) 'y.foo()': u64
4011 [217; 218) 'z': impl Trait<u64>
4012 [217; 224) 'z.foo()': u64
4013 [230; 231) 'x': impl Trait<u64>
4014 [230; 238) 'x.foo2()': i64
4015 [244; 245) 'y': &impl Trait<u64>
4016 [244; 252) 'y.foo2()': i64
4017 [258; 259) 'z': impl Trait<u64>
4018 [258; 266) 'z.foo2()': i64
4019 "###
4020 );
4021}
4022
4023#[test]
4024fn dyn_trait() {
4025 assert_snapshot!(
4026 infer(r#"
4027trait Trait<T> {
4028 fn foo(&self) -> T;
4029 fn foo2(&self) -> i64;
4030}
4031fn bar() -> dyn Trait<u64> {}
4032
4033fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
4034 x;
4035 y;
4036 let z = bar();
4037 x.foo();
4038 y.foo();
4039 z.foo();
4040 x.foo2();
4041 y.foo2();
4042 z.foo2();
4043}
4044"#),
4045 @r###"
4046 [30; 34) 'self': &Self
4047 [55; 59) 'self': &Self
4048 [98; 100) '{}': ()
4049 [110; 111) 'x': dyn Trait<u64>
4050 [129; 130) 'y': &dyn Trait<u64>
4051 [149; 266) '{ ...2(); }': ()
4052 [155; 156) 'x': dyn Trait<u64>
4053 [162; 163) 'y': &dyn Trait<u64>
4054 [173; 174) 'z': dyn Trait<u64>
4055 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
4056 [177; 182) 'bar()': dyn Trait<u64>
4057 [188; 189) 'x': dyn Trait<u64>
4058 [188; 195) 'x.foo()': u64
4059 [201; 202) 'y': &dyn Trait<u64>
4060 [201; 208) 'y.foo()': u64
4061 [214; 215) 'z': dyn Trait<u64>
4062 [214; 221) 'z.foo()': u64
4063 [227; 228) 'x': dyn Trait<u64>
4064 [227; 235) 'x.foo2()': i64
4065 [241; 242) 'y': &dyn Trait<u64>
4066 [241; 249) 'y.foo2()': i64
4067 [255; 256) 'z': dyn Trait<u64>
4068 [255; 263) 'z.foo2()': i64
4069 "###
4070 );
4071}
4072
4073#[test]
4074fn dyn_trait_bare() {
4075 assert_snapshot!(
4076 infer(r#"
4077trait Trait {
4078 fn foo(&self) -> u64;
4079}
4080fn bar() -> Trait {}
4081
4082fn test(x: Trait, y: &Trait) -> u64 {
4083 x;
4084 y;
4085 let z = bar();
4086 x.foo();
4087 y.foo();
4088 z.foo();
4089}
4090"#),
4091 @r###"
4092 [27; 31) 'self': &Self
4093 [61; 63) '{}': ()
4094 [73; 74) 'x': dyn Trait
4095 [83; 84) 'y': &dyn Trait
4096 [101; 176) '{ ...o(); }': ()
4097 [107; 108) 'x': dyn Trait
4098 [114; 115) 'y': &dyn Trait
4099 [125; 126) 'z': dyn Trait
4100 [129; 132) 'bar': fn bar() -> dyn Trait
4101 [129; 134) 'bar()': dyn Trait
4102 [140; 141) 'x': dyn Trait
4103 [140; 147) 'x.foo()': u64
4104 [153; 154) 'y': &dyn Trait
4105 [153; 160) 'y.foo()': u64
4106 [166; 167) 'z': dyn Trait
4107 [166; 173) 'z.foo()': u64
4108 "###
4109 );
4110}
4111
4112#[test]
4113fn weird_bounds() {
4114 assert_snapshot!(
4115 infer(r#"
4116trait Trait {}
4117fn test() {
4118 let a: impl Trait + 'lifetime = foo;
4119 let b: impl 'lifetime = foo;
4120 let b: impl (Trait) = foo;
4121 let b: impl ('lifetime) = foo;
4122 let d: impl ?Sized = foo;
4123 let e: impl Trait + ?Sized = foo;
4124}
4125"#),
4126 @r###"
4127 [26; 237) '{ ...foo; }': ()
4128 [36; 37) 'a': impl Trait + {error}
4129 [64; 67) 'foo': impl Trait + {error}
4130 [77; 78) 'b': impl {error}
4131 [97; 100) 'foo': impl {error}
4132 [110; 111) 'b': impl Trait
4133 [128; 131) 'foo': impl Trait
4134 [141; 142) 'b': impl {error}
4135 [163; 166) 'foo': impl {error}
4136 [176; 177) 'd': impl {error}
4137 [193; 196) 'foo': impl {error}
4138 [206; 207) 'e': impl Trait + {error}
4139 [231; 234) 'foo': impl Trait + {error}
4140 "###
4141 );
4142}
4143
4144#[test]
4145fn assoc_type_bindings() {
4146 assert_snapshot!(
4147 infer(r#"
4148trait Trait {
4149 type Type;
4150}
4151
4152fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
4153fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
4154fn set<T: Trait<Type = u64>>(t: T) -> T {t}
4155
4156struct S<T>;
4157impl<T> Trait for S<T> { type Type = T; }
4158
4159fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
4160 get(x);
4161 get2(x);
4162 get(y);
4163 get2(y);
4164 get(set(S));
4165 get2(set(S));
4166 get2(S::<str>);
4167}
4168"#),
4169 @r###"
4170 [50; 51) 't': T
4171 [78; 80) '{}': ()
4172 [112; 113) 't': T
4173 [123; 125) '{}': ()
4174 [155; 156) 't': T
4175 [166; 169) '{t}': T
4176 [167; 168) 't': T
4177 [257; 258) 'x': T
4178 [263; 264) 'y': impl Trait<Type = i64>
4179 [290; 398) '{ ...r>); }': ()
4180 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
4181 [296; 302) 'get(x)': {unknown}
4182 [300; 301) 'x': T
4183 [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
4184 [308; 315) 'get2(x)': {unknown}
4185 [313; 314) 'x': T
4186 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
4187 [321; 327) 'get(y)': {unknown}
4188 [325; 326) 'y': impl Trait<Type = i64>
4189 [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
4190 [333; 340) 'get2(y)': {unknown}
4191 [338; 339) 'y': impl Trait<Type = i64>
4192 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
4193 [346; 357) 'get(set(S))': u64
4194 [350; 353) 'set': fn set<S<u64>>(T) -> T
4195 [350; 356) 'set(S)': S<u64>
4196 [354; 355) 'S': S<u64>
4197 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
4198 [363; 375) 'get2(set(S))': u64
4199 [368; 371) 'set': fn set<S<u64>>(T) -> T
4200 [368; 374) 'set(S)': S<u64>
4201 [372; 373) 'S': S<u64>
4202 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
4203 [381; 395) 'get2(S::<str>)': str
4204 [386; 394) 'S::<str>': S<str>
4205 "###
4206 );
4207}
4208
4209#[test]
4210fn impl_trait_assoc_binding_projection_bug() {
4211 let (db, pos) = TestDB::with_position(
4212 r#"
4213//- /main.rs crate:main deps:std
4214pub trait Language {
4215 type Kind;
4216}
4217pub enum RustLanguage {}
4218impl Language for RustLanguage {
4219 type Kind = SyntaxKind;
4220}
4221struct SyntaxNode<L> {}
4222fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
4223
4224trait Clone {
4225 fn clone(&self) -> Self;
4226}
4227
4228fn api_walkthrough() {
4229 for node in foo() {
4230 node.clone()<|>;
4231 }
4232}
4233
4234//- /std.rs crate:std
4235#[prelude_import] use iter::*;
4236mod iter {
4237 trait IntoIterator {
4238 type Item;
4239 }
4240 trait Iterator {
4241 type Item;
4242 }
4243 impl<T: Iterator> IntoIterator for T {
4244 type Item = <T as Iterator>::Item;
4245 }
4246}
4247"#,
4248 );
4249 assert_eq!("{unknown}", type_at_pos(&db, pos));
4250}
4251
4252#[test]
4253fn projection_eq_within_chalk() {
4254 // std::env::set_var("CHALK_DEBUG", "1");
4255 assert_snapshot!(
4256 infer(r#"
4257trait Trait1 {
4258 type Type;
4259}
4260trait Trait2<T> {
4261 fn foo(self) -> T;
4262}
4263impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
4264
4265fn test<T: Trait1<Type = u32>>(x: T) {
4266 x.foo();
4267}
4268"#),
4269 @r###"
4270 [62; 66) 'self': Self
4271 [164; 165) 'x': T
4272 [170; 186) '{ ...o(); }': ()
4273 [176; 177) 'x': T
4274 [176; 183) 'x.foo()': {unknown}
4275 "###
4276 );
4277}
4278
4279#[test]
4280fn where_clause_trait_in_scope_for_method_resolution() {
4281 let t = type_at(
4282 r#"
4283//- /main.rs
4284mod foo {
4285 trait Trait {
4286 fn foo(&self) -> u32 {}
4287 }
4288}
4289
4290fn test<T: foo::Trait>(x: T) {
4291 x.foo()<|>;
4292}
4293"#,
4294 );
4295 assert_eq!(t, "u32");
4296}
4297
4298#[test]
4299fn super_trait_method_resolution() {
4300 assert_snapshot!(
4301 infer(r#"
4302mod foo {
4303 trait SuperTrait {
4304 fn foo(&self) -> u32 {}
4305 }
4306}
4307trait Trait1: foo::SuperTrait {}
4308trait Trait2 where Self: foo::SuperTrait {}
4309
4310fn test<T: Trait1, U: Trait2>(x: T, y: U) {
4311 x.foo();
4312 y.foo();
4313}
4314"#),
4315 @r###"
4316 [50; 54) 'self': &Self
4317 [63; 65) '{}': ()
4318 [182; 183) 'x': T
4319 [188; 189) 'y': U
4320 [194; 223) '{ ...o(); }': ()
4321 [200; 201) 'x': T
4322 [200; 207) 'x.foo()': u32
4323 [213; 214) 'y': U
4324 [213; 220) 'y.foo()': u32
4325 "###
4326 );
4327}
4328
4329#[test]
4330fn super_trait_cycle() {
4331 // This just needs to not crash
4332 assert_snapshot!(
4333 infer(r#"
4334trait A: B {}
4335trait B: A {}
4336
4337fn test<T: A>(x: T) {
4338 x.foo();
4339}
4340"#),
4341 @r###"
4342 [44; 45) 'x': T
4343 [50; 66) '{ ...o(); }': ()
4344 [56; 57) 'x': T
4345 [56; 63) 'x.foo()': {unknown}
4346 "###
4347 );
4348}
4349
4350#[test]
4351fn super_trait_assoc_type_bounds() {
4352 assert_snapshot!(
4353 infer(r#"
4354trait SuperTrait { type Type; }
4355trait Trait where Self: SuperTrait {}
4356
4357fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
4358fn set<T: Trait<Type = u64>>(t: T) -> T {t}
4359
4360struct S<T>;
4361impl<T> SuperTrait for S<T> { type Type = T; }
4362impl<T> Trait for S<T> {}
4363
4364fn test() {
4365 get2(set(S));
4366}
4367"#),
4368 @r###"
4369 [103; 104) 't': T
4370 [114; 116) '{}': ()
4371 [146; 147) 't': T
4372 [157; 160) '{t}': T
4373 [158; 159) 't': T
4374 [259; 280) '{ ...S)); }': ()
4375 [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
4376 [265; 277) 'get2(set(S))': u64
4377 [270; 273) 'set': fn set<S<u64>>(T) -> T
4378 [270; 276) 'set(S)': S<u64>
4379 [274; 275) 'S': S<u64>
4380 "###
4381 );
4382}
4383
4384#[test]
4385fn fn_trait() {
4386 assert_snapshot!(
4387 infer(r#"
4388trait FnOnce<Args> {
4389 type Output;
4390
4391 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
4392}
4393
4394fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
4395 f.call_once((1, 2));
4396}
4397"#),
4398 @r###"
4399 [57; 61) 'self': Self
4400 [63; 67) 'args': Args
4401 [150; 151) 'f': F
4402 [156; 184) '{ ...2)); }': ()
4403 [162; 163) 'f': F
4404 [162; 181) 'f.call...1, 2))': {unknown}
4405 [174; 180) '(1, 2)': (u32, u64)
4406 [175; 176) '1': u32
4407 [178; 179) '2': u64
4408 "###
4409 );
4410}
4411
4412#[test]
4413fn closure_1() {
4414 assert_snapshot!(
4415 infer(r#"
4416#[lang = "fn_once"]
4417trait FnOnce<Args> {
4418 type Output;
4419}
4420
4421enum Option<T> { Some(T), None }
4422impl<T> Option<T> {
4423 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
4424}
4425
4426fn test() {
4427 let x = Option::Some(1u32);
4428 x.map(|v| v + 1);
4429 x.map(|_v| 1u64);
4430 let y: Option<i64> = x.map(|_v| 1);
4431}
4432"#),
4433 @r###"
4434 [148; 152) 'self': Option<T>
4435 [154; 155) 'f': F
4436 [173; 175) '{}': ()
4437 [189; 308) '{ ... 1); }': ()
4438 [199; 200) 'x': Option<u32>
4439 [203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
4440 [203; 221) 'Option...(1u32)': Option<u32>
4441 [216; 220) '1u32': u32
4442 [227; 228) 'x': Option<u32>
4443 [227; 243) 'x.map(...v + 1)': Option<u32>
4444 [233; 242) '|v| v + 1': |u32| -> u32
4445 [234; 235) 'v': u32
4446 [237; 238) 'v': u32
4447 [237; 242) 'v + 1': u32
4448 [241; 242) '1': u32
4449 [249; 250) 'x': Option<u32>
4450 [249; 265) 'x.map(... 1u64)': Option<u64>
4451 [255; 264) '|_v| 1u64': |u32| -> u64
4452 [256; 258) '_v': u32
4453 [260; 264) '1u64': u64
4454 [275; 276) 'y': Option<i64>
4455 [292; 293) 'x': Option<u32>
4456 [292; 305) 'x.map(|_v| 1)': Option<i64>
4457 [298; 304) '|_v| 1': |u32| -> i64
4458 [299; 301) '_v': u32
4459 [303; 304) '1': i64
4460 "###
4461 );
4462}
4463
4464#[test]
4465fn closure_2() {
4466 assert_snapshot!(
4467 infer(r#"
4468trait FnOnce<Args> {
4469 type Output;
4470}
4471
4472fn test<F: FnOnce(u32) -> u64>(f: F) {
4473 f(1);
4474 let g = |v| v + 1;
4475 g(1u64);
4476 let h = |v| 1u128 + v;
4477}
4478"#),
4479 @r###"
4480 [73; 74) 'f': F
4481 [79; 155) '{ ...+ v; }': ()
4482 [85; 86) 'f': F
4483 [85; 89) 'f(1)': {unknown}
4484 [87; 88) '1': i32
4485 [99; 100) 'g': |u64| -> i32
4486 [103; 112) '|v| v + 1': |u64| -> i32
4487 [104; 105) 'v': u64
4488 [107; 108) 'v': u64
4489 [107; 112) 'v + 1': i32
4490 [111; 112) '1': i32
4491 [118; 119) 'g': |u64| -> i32
4492 [118; 125) 'g(1u64)': i32
4493 [120; 124) '1u64': u64
4494 [135; 136) 'h': |u128| -> u128
4495 [139; 152) '|v| 1u128 + v': |u128| -> u128
4496 [140; 141) 'v': u128
4497 [143; 148) '1u128': u128
4498 [143; 152) '1u128 + v': u128
4499 [151; 152) 'v': u128
4500 "###
4501 );
4502}
4503
4504#[test]
4505fn closure_as_argument_inference_order() {
4506 assert_snapshot!(
4507 infer(r#"
4508#[lang = "fn_once"]
4509trait FnOnce<Args> {
4510 type Output;
4511}
4512
4513fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
4514fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
4515
4516struct S;
4517impl S {
4518 fn method(self) -> u64;
4519
4520 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
4521 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
4522}
4523
4524fn test() {
4525 let x1 = foo1(S, |s| s.method());
4526 let x2 = foo2(|s| s.method(), S);
4527 let x3 = S.foo1(S, |s| s.method());
4528 let x4 = S.foo2(|s| s.method(), S);
4529}
4530"#),
4531 @r###"
4532 [95; 96) 'x': T
4533 [101; 102) 'f': F
4534 [112; 114) '{}': ()
4535 [148; 149) 'f': F
4536 [154; 155) 'x': T
4537 [165; 167) '{}': ()
4538 [202; 206) 'self': S
4539 [254; 258) 'self': S
4540 [260; 261) 'x': T
4541 [266; 267) 'f': F
4542 [277; 279) '{}': ()
4543 [317; 321) 'self': S
4544 [323; 324) 'f': F
4545 [329; 330) 'x': T
4546 [340; 342) '{}': ()
4547 [356; 515) '{ ... S); }': ()
4548 [366; 368) 'x1': u64
4549 [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
4550 [371; 394) 'foo1(S...hod())': u64
4551 [376; 377) 'S': S
4552 [379; 393) '|s| s.method()': |S| -> u64
4553 [380; 381) 's': S
4554 [383; 384) 's': S
4555 [383; 393) 's.method()': u64
4556 [404; 406) 'x2': u64
4557 [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
4558 [409; 432) 'foo2(|...(), S)': u64
4559 [414; 428) '|s| s.method()': |S| -> u64
4560 [415; 416) 's': S
4561 [418; 419) 's': S
4562 [418; 428) 's.method()': u64
4563 [430; 431) 'S': S
4564 [442; 444) 'x3': u64
4565 [447; 448) 'S': S
4566 [447; 472) 'S.foo1...hod())': u64
4567 [454; 455) 'S': S
4568 [457; 471) '|s| s.method()': |S| -> u64
4569 [458; 459) 's': S
4570 [461; 462) 's': S
4571 [461; 471) 's.method()': u64
4572 [482; 484) 'x4': u64
4573 [487; 488) 'S': S
4574 [487; 512) 'S.foo2...(), S)': u64
4575 [494; 508) '|s| s.method()': |S| -> u64
4576 [495; 496) 's': S
4577 [498; 499) 's': S
4578 [498; 508) 's.method()': u64
4579 [510; 511) 'S': S
4580 "###
4581 );
4582}
4583
4584#[test]
4585fn unselected_projection_in_trait_env_1() {
4586 let t = type_at(
4587 r#"
4588//- /main.rs
4589trait Trait {
4590 type Item;
4591}
4592
4593trait Trait2 {
4594 fn foo(&self) -> u32;
4595}
4596
4597fn test<T: Trait>() where T::Item: Trait2 {
4598 let x: T::Item = no_matter;
4599 x.foo()<|>;
4600}
4601"#,
4602 );
4603 assert_eq!(t, "u32");
4604}
4605
4606#[test]
4607fn unselected_projection_in_trait_env_2() {
4608 let t = type_at(
4609 r#"
4610//- /main.rs
4611trait Trait<T> {
4612 type Item;
4613}
4614
4615trait Trait2 {
4616 fn foo(&self) -> u32;
4617}
4618
4619fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
4620 let x: T::Item = no_matter;
4621 x.foo()<|>;
4622}
4623"#,
4624 );
4625 assert_eq!(t, "u32");
4626}
4627
4628#[test]
4629// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4630// in Unknown, and we should be able to do that once Salsa allows us to handle
4631// the cycle. But at least it doesn't overflow for now.
4632#[should_panic]
4633fn unselected_projection_in_trait_env_cycle_1() {
4634 let t = type_at(
4635 r#"
4636//- /main.rs
4637trait Trait {
4638 type Item;
4639}
4640
4641trait Trait2<T> {}
4642
4643fn test<T: Trait>() where T: Trait2<T::Item> {
4644 let x: T::Item = no_matter<|>;
4645}
4646"#,
4647 );
4648 // this is a legitimate cycle
4649 assert_eq!(t, "{unknown}");
4650}
4651
4652#[test]
4653// FIXME this is currently a Salsa panic; it would be nicer if it just returned
4654// in Unknown, and we should be able to do that once Salsa allows us to handle
4655// the cycle. But at least it doesn't overflow for now.
4656#[should_panic]
4657fn unselected_projection_in_trait_env_cycle_2() {
4658 let t = type_at(
4659 r#"
4660//- /main.rs
4661trait Trait<T> {
4662 type Item;
4663}
4664
4665fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
4666 let x: T::Item = no_matter<|>;
4667}
4668"#,
4669 );
4670 // this is a legitimate cycle
4671 assert_eq!(t, "{unknown}");
4672}
4673
4674fn type_at_pos(db: &TestDB, pos: FilePosition) -> String { 31fn type_at_pos(db: &TestDB, pos: FilePosition) -> String {
4675 let file = db.parse(pos.file_id).ok().unwrap(); 32 let file = db.parse(pos.file_id).ok().unwrap();
4676 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap(); 33 let expr = algo::find_node_at_offset::<ast::Expr>(file.syntax(), pos.offset).unwrap();
4677 34 let fn_def = expr.syntax().ancestors().find_map(ast::FnDef::cast).unwrap();
4678 let module = db.module_for_file(pos.file_id); 35 let module = db.module_for_file(pos.file_id);
4679 let crate_def_map = db.crate_def_map(module.krate); 36 let func = *module.child_by_source(db)[keys::FUNCTION]
4680 for decl in crate_def_map[module.local_id].scope.declarations() { 37 .get(&InFile::new(pos.file_id.into(), fn_def))
4681 if let ModuleDefId::FunctionId(func) = decl { 38 .unwrap();
4682 let (_body, source_map) = db.body_with_source_map(func.into()); 39
4683 if let Some(expr_id) = source_map.node_expr(Source::new(pos.file_id.into(), &expr)) { 40 let (_body, source_map) = db.body_with_source_map(func.into());
4684 let infer = db.infer(func.into()); 41 if let Some(expr_id) = source_map.node_expr(InFile::new(pos.file_id.into(), &expr)) {
4685 let ty = &infer[expr_id]; 42 let infer = db.infer(func.into());
4686 return ty.display(db).to_string(); 43 let ty = &infer[expr_id];
4687 } 44 return ty.display(db).to_string();
4688 }
4689 } 45 }
4690 panic!("Can't find expression") 46 panic!("Can't find expression")
4691} 47}
@@ -4696,6 +52,10 @@ fn type_at(content: &str) -> String {
4696} 52}
4697 53
4698fn infer(content: &str) -> String { 54fn infer(content: &str) -> String {
55 infer_with_mismatches(content, false)
56}
57
58fn infer_with_mismatches(content: &str, include_mismatches: bool) -> String {
4699 let (db, file_id) = TestDB::with_single_file(content); 59 let (db, file_id) = TestDB::with_single_file(content);
4700 60
4701 let mut acc = String::new(); 61 let mut acc = String::new();
@@ -4703,6 +63,7 @@ fn infer(content: &str) -> String {
4703 let mut infer_def = |inference_result: Arc<InferenceResult>, 63 let mut infer_def = |inference_result: Arc<InferenceResult>,
4704 body_source_map: Arc<BodySourceMap>| { 64 body_source_map: Arc<BodySourceMap>| {
4705 let mut types = Vec::new(); 65 let mut types = Vec::new();
66 let mut mismatches = Vec::new();
4706 67
4707 for (pat, ty) in inference_result.type_of_pat.iter() { 68 for (pat, ty) in inference_result.type_of_pat.iter() {
4708 let syntax_ptr = match body_source_map.pat_syntax(pat) { 69 let syntax_ptr = match body_source_map.pat_syntax(pat) {
@@ -4722,6 +83,9 @@ fn infer(content: &str) -> String {
4722 None => continue, 83 None => continue,
4723 }; 84 };
4724 types.push((syntax_ptr, ty)); 85 types.push((syntax_ptr, ty));
86 if let Some(mismatch) = inference_result.type_mismatch_for_expr(expr) {
87 mismatches.push((syntax_ptr, mismatch));
88 }
4725 } 89 }
4726 90
4727 // sort ranges for consistency 91 // sort ranges for consistency
@@ -4747,6 +111,24 @@ fn infer(content: &str) -> String {
4747 ) 111 )
4748 .unwrap(); 112 .unwrap();
4749 } 113 }
114 if include_mismatches {
115 mismatches.sort_by_key(|(src_ptr, _)| {
116 (src_ptr.value.range().start(), src_ptr.value.range().end())
117 });
118 for (src_ptr, mismatch) in &mismatches {
119 let range = src_ptr.value.range();
120 let macro_prefix = if src_ptr.file_id != file_id.into() { "!" } else { "" };
121 write!(
122 acc,
123 "{}{}: expected {}, got {}\n",
124 macro_prefix,
125 range,
126 mismatch.expected.display(&db),
127 mismatch.actual.display(&db),
128 )
129 .unwrap();
130 }
131 }
4750 }; 132 };
4751 133
4752 let module = db.module_for_file(file_id); 134 let module = db.module_for_file(file_id);
@@ -4800,7 +182,7 @@ fn visit_module(
4800 _ => (), 182 _ => (),
4801 } 183 }
4802 } 184 }
4803 for &impl_id in crate_def_map[module_id].impls.iter() { 185 for impl_id in crate_def_map[module_id].scope.impls() {
4804 let impl_data = db.impl_data(impl_id); 186 let impl_data = db.impl_data(impl_id);
4805 for &item in impl_data.items.iter() { 187 for &item in impl_data.items.iter() {
4806 match item { 188 match item {
@@ -4899,60 +281,3 @@ fn no_such_field_diagnostics() {
4899 "### 281 "###
4900 ); 282 );
4901} 283}
4902
4903#[test]
4904fn infer_builtin_macros_line() {
4905 assert_snapshot!(
4906 infer(r#"
4907#[rustc_builtin_macro]
4908macro_rules! line {() => {}}
4909
4910fn main() {
4911 let x = line!();
4912}
4913"#),
4914 @r###"
4915 ![0; 1) '6': i32
4916 [64; 88) '{ ...!(); }': ()
4917 [74; 75) 'x': i32
4918 "###
4919 );
4920}
4921
4922#[test]
4923fn infer_builtin_macros_file() {
4924 assert_snapshot!(
4925 infer(r#"
4926#[rustc_builtin_macro]
4927macro_rules! file {() => {}}
4928
4929fn main() {
4930 let x = file!();
4931}
4932"#),
4933 @r###"
4934 ![0; 2) '""': &str
4935 [64; 88) '{ ...!(); }': ()
4936 [74; 75) 'x': &str
4937 "###
4938 );
4939}
4940
4941#[test]
4942fn infer_builtin_macros_column() {
4943 assert_snapshot!(
4944 infer(r#"
4945#[rustc_builtin_macro]
4946macro_rules! column {() => {}}
4947
4948fn main() {
4949 let x = column!();
4950}
4951"#),
4952 @r###"
4953 ![0; 2) '13': i32
4954 [66; 92) '{ ...!(); }': ()
4955 [76; 77) 'x': i32
4956 "###
4957 );
4958}
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs
index 1530fcc63..7e99a42ed 100644
--- a/crates/ra_hir_ty/src/tests/coercion.rs
+++ b/crates/ra_hir_ty/src/tests/coercion.rs
@@ -1,3 +1,4 @@
1use super::infer_with_mismatches;
1use insta::assert_snapshot; 2use insta::assert_snapshot;
2use test_utils::covers; 3use test_utils::covers;
3 4
@@ -367,3 +368,161 @@ fn test() {
367 "### 368 "###
368 ); 369 );
369} 370}
371
372#[test]
373fn return_coerce_unknown() {
374 assert_snapshot!(
375 infer_with_mismatches(r#"
376fn foo() -> u32 {
377 return unknown;
378}
379"#, true),
380 @r###"
381 [17; 40) '{ ...own; }': !
382 [23; 37) 'return unknown': !
383 [30; 37) 'unknown': u32
384 "###
385 );
386}
387
388#[test]
389fn coerce_autoderef() {
390 assert_snapshot!(
391 infer_with_mismatches(r#"
392struct Foo;
393fn takes_ref_foo(x: &Foo) {}
394fn test() {
395 takes_ref_foo(&Foo);
396 takes_ref_foo(&&Foo);
397 takes_ref_foo(&&&Foo);
398}
399"#, true),
400 @r###"
401 [30; 31) 'x': &Foo
402 [39; 41) '{}': ()
403 [52; 133) '{ ...oo); }': ()
404 [58; 71) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
405 [58; 77) 'takes_...(&Foo)': ()
406 [72; 76) '&Foo': &Foo
407 [73; 76) 'Foo': Foo
408 [83; 96) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
409 [83; 103) 'takes_...&&Foo)': ()
410 [97; 102) '&&Foo': &&Foo
411 [98; 102) '&Foo': &Foo
412 [99; 102) 'Foo': Foo
413 [109; 122) 'takes_ref_foo': fn takes_ref_foo(&Foo) -> ()
414 [109; 130) 'takes_...&&Foo)': ()
415 [123; 129) '&&&Foo': &&&Foo
416 [124; 129) '&&Foo': &&Foo
417 [125; 129) '&Foo': &Foo
418 [126; 129) 'Foo': Foo
419 "###
420 );
421}
422
423#[test]
424fn coerce_autoderef_generic() {
425 assert_snapshot!(
426 infer_with_mismatches(r#"
427struct Foo;
428fn takes_ref<T>(x: &T) -> T { *x }
429fn test() {
430 takes_ref(&Foo);
431 takes_ref(&&Foo);
432 takes_ref(&&&Foo);
433}
434"#, true),
435 @r###"
436 [29; 30) 'x': &T
437 [41; 47) '{ *x }': T
438 [43; 45) '*x': T
439 [44; 45) 'x': &T
440 [58; 127) '{ ...oo); }': ()
441 [64; 73) 'takes_ref': fn takes_ref<Foo>(&T) -> T
442 [64; 79) 'takes_ref(&Foo)': Foo
443 [74; 78) '&Foo': &Foo
444 [75; 78) 'Foo': Foo
445 [85; 94) 'takes_ref': fn takes_ref<&Foo>(&T) -> T
446 [85; 101) 'takes_...&&Foo)': &Foo
447 [95; 100) '&&Foo': &&Foo
448 [96; 100) '&Foo': &Foo
449 [97; 100) 'Foo': Foo
450 [107; 116) 'takes_ref': fn takes_ref<&&Foo>(&T) -> T
451 [107; 124) 'takes_...&&Foo)': &&Foo
452 [117; 123) '&&&Foo': &&&Foo
453 [118; 123) '&&Foo': &&Foo
454 [119; 123) '&Foo': &Foo
455 [120; 123) 'Foo': Foo
456 "###
457 );
458}
459
460#[test]
461fn closure_return_coerce() {
462 assert_snapshot!(
463 infer_with_mismatches(r#"
464fn foo() {
465 let x = || {
466 if true {
467 return &1u32;
468 }
469 &&1u32
470 };
471}
472"#, true),
473 @r###"
474 [10; 106) '{ ... }; }': ()
475 [20; 21) 'x': || -> &u32
476 [24; 103) '|| { ... }': || -> &u32
477 [27; 103) '{ ... }': &u32
478 [37; 82) 'if tru... }': ()
479 [40; 44) 'true': bool
480 [45; 82) '{ ... }': !
481 [59; 71) 'return &1u32': !
482 [66; 71) '&1u32': &u32
483 [67; 71) '1u32': u32
484 [91; 97) '&&1u32': &&u32
485 [92; 97) '&1u32': &u32
486 [93; 97) '1u32': u32
487 "###
488 );
489}
490
491#[test]
492fn coerce_fn_item_to_fn_ptr() {
493 assert_snapshot!(
494 infer_with_mismatches(r#"
495fn foo(x: u32) -> isize { 1 }
496fn test() {
497 let f: fn(u32) -> isize = foo;
498}
499"#, true),
500 @r###"
501 [8; 9) 'x': u32
502 [25; 30) '{ 1 }': isize
503 [27; 28) '1': isize
504 [41; 79) '{ ...foo; }': ()
505 [51; 52) 'f': fn(u32) -> isize
506 [73; 76) 'foo': fn foo(u32) -> isize
507 "###
508 );
509}
510
511#[test]
512fn coerce_closure_to_fn_ptr() {
513 assert_snapshot!(
514 infer_with_mismatches(r#"
515fn test() {
516 let f: fn(u32) -> isize = |x| { 1 };
517}
518"#, true),
519 @r###"
520 [11; 55) '{ ...1 }; }': ()
521 [21; 22) 'f': fn(u32) -> isize
522 [43; 52) '|x| { 1 }': |u32| -> isize
523 [44; 45) 'x': u32
524 [47; 52) '{ 1 }': isize
525 [49; 50) '1': isize
526 "###
527 );
528}
diff --git a/crates/ra_hir_ty/src/tests/macros.rs b/crates/ra_hir_ty/src/tests/macros.rs
new file mode 100644
index 000000000..69c695cc8
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/macros.rs
@@ -0,0 +1,390 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn cfg_impl_block() {
8 let (db, pos) = TestDB::with_position(
9 r#"
10//- /main.rs crate:main deps:foo cfg:test
11use foo::S as T;
12struct S;
13
14#[cfg(test)]
15impl S {
16 fn foo1(&self) -> i32 { 0 }
17}
18
19#[cfg(not(test))]
20impl S {
21 fn foo2(&self) -> i32 { 0 }
22}
23
24fn test() {
25 let t = (S.foo1(), S.foo2(), T.foo3(), T.foo4());
26 t<|>;
27}
28
29//- /foo.rs crate:foo
30struct S;
31
32#[cfg(not(test))]
33impl S {
34 fn foo3(&self) -> i32 { 0 }
35}
36
37#[cfg(test)]
38impl S {
39 fn foo4(&self) -> i32 { 0 }
40}
41"#,
42 );
43 assert_eq!("(i32, {unknown}, i32, {unknown})", type_at_pos(&db, pos));
44}
45
46#[test]
47fn infer_macros_expanded() {
48 assert_snapshot!(
49 infer(r#"
50struct Foo(Vec<i32>);
51
52macro_rules! foo {
53 ($($item:expr),*) => {
54 {
55 Foo(vec![$($item,)*])
56 }
57 };
58}
59
60fn main() {
61 let x = foo!(1,2);
62}
63"#),
64 @r###"
65 ![0; 17) '{Foo(v...,2,])}': Foo
66 ![1; 4) 'Foo': Foo({unknown}) -> Foo
67 ![1; 16) 'Foo(vec![1,2,])': Foo
68 ![5; 15) 'vec![1,2,]': {unknown}
69 [156; 182) '{ ...,2); }': ()
70 [166; 167) 'x': Foo
71 "###
72 );
73}
74
75#[test]
76fn infer_legacy_textual_scoped_macros_expanded() {
77 assert_snapshot!(
78 infer(r#"
79struct Foo(Vec<i32>);
80
81#[macro_use]
82mod m {
83 macro_rules! foo {
84 ($($item:expr),*) => {
85 {
86 Foo(vec![$($item,)*])
87 }
88 };
89 }
90}
91
92fn main() {
93 let x = foo!(1,2);
94 let y = crate::foo!(1,2);
95}
96"#),
97 @r###"
98 ![0; 17) '{Foo(v...,2,])}': Foo
99 ![1; 4) 'Foo': Foo({unknown}) -> Foo
100 ![1; 16) 'Foo(vec![1,2,])': Foo
101 ![5; 15) 'vec![1,2,]': {unknown}
102 [195; 251) '{ ...,2); }': ()
103 [205; 206) 'x': Foo
104 [228; 229) 'y': {unknown}
105 [232; 248) 'crate:...!(1,2)': {unknown}
106 "###
107 );
108}
109
110#[test]
111fn infer_path_qualified_macros_expanded() {
112 assert_snapshot!(
113 infer(r#"
114#[macro_export]
115macro_rules! foo {
116 () => { 42i32 }
117}
118
119mod m {
120 pub use super::foo as bar;
121}
122
123fn main() {
124 let x = crate::foo!();
125 let y = m::bar!();
126}
127"#),
128 @r###"
129 ![0; 5) '42i32': i32
130 ![0; 5) '42i32': i32
131 [111; 164) '{ ...!(); }': ()
132 [121; 122) 'x': i32
133 [148; 149) 'y': i32
134 "###
135 );
136}
137
138#[test]
139fn infer_type_value_macro_having_same_name() {
140 assert_snapshot!(
141 infer(r#"
142#[macro_export]
143macro_rules! foo {
144 () => {
145 mod foo {
146 pub use super::foo;
147 }
148 };
149 ($x:tt) => {
150 $x
151 };
152}
153
154foo!();
155
156fn foo() {
157 let foo = foo::foo!(42i32);
158}
159"#),
160 @r###"
161 ![0; 5) '42i32': i32
162 [171; 206) '{ ...32); }': ()
163 [181; 184) 'foo': i32
164 "###
165 );
166}
167
168#[test]
169fn processes_impls_generated_by_macros() {
170 let t = type_at(
171 r#"
172//- /main.rs
173macro_rules! m {
174 ($ident:ident) => (impl Trait for $ident {})
175}
176trait Trait { fn foo(self) -> u128 {} }
177struct S;
178m!(S);
179fn test() { S.foo()<|>; }
180"#,
181 );
182 assert_eq!(t, "u128");
183}
184
185#[test]
186fn infer_impl_items_generated_by_macros() {
187 let t = type_at(
188 r#"
189//- /main.rs
190macro_rules! m {
191 () => (fn foo(&self) -> u128 {0})
192}
193struct S;
194impl S {
195 m!();
196}
197
198fn test() { S.foo()<|>; }
199"#,
200 );
201 assert_eq!(t, "u128");
202}
203
204#[test]
205fn infer_impl_items_generated_by_macros_chain() {
206 let t = type_at(
207 r#"
208//- /main.rs
209macro_rules! m_inner {
210 () => {fn foo(&self) -> u128 {0}}
211}
212macro_rules! m {
213 () => {m_inner!();}
214}
215
216struct S;
217impl S {
218 m!();
219}
220
221fn test() { S.foo()<|>; }
222"#,
223 );
224 assert_eq!(t, "u128");
225}
226
227#[test]
228fn infer_macro_with_dollar_crate_is_correct_in_expr() {
229 let (db, pos) = TestDB::with_position(
230 r#"
231//- /main.rs crate:main deps:foo
232fn test() {
233 let x = (foo::foo!(1), foo::foo!(2));
234 x<|>;
235}
236
237//- /lib.rs crate:foo
238#[macro_export]
239macro_rules! foo {
240 (1) => { $crate::bar!() };
241 (2) => { 1 + $crate::baz() };
242}
243
244#[macro_export]
245macro_rules! bar {
246 () => { 42 }
247}
248
249pub fn baz() -> usize { 31usize }
250"#,
251 );
252 assert_eq!("(i32, usize)", type_at_pos(&db, pos));
253}
254
255#[test]
256fn infer_type_value_non_legacy_macro_use_as() {
257 assert_snapshot!(
258 infer(r#"
259mod m {
260 macro_rules! _foo {
261 ($x:ident) => { type $x = u64; }
262 }
263 pub(crate) use _foo as foo;
264}
265
266m::foo!(foo);
267use foo as bar;
268fn f() -> bar { 0 }
269fn main() {
270 let _a = f();
271}
272"#),
273 @r###"
274 [159; 164) '{ 0 }': u64
275 [161; 162) '0': u64
276 [175; 199) '{ ...f(); }': ()
277 [187; 189) '_a': u64
278 [193; 194) 'f': fn f() -> u64
279 [193; 196) 'f()': u64
280 "###
281 );
282}
283
284#[test]
285fn infer_builtin_macros_line() {
286 assert_snapshot!(
287 infer(r#"
288#[rustc_builtin_macro]
289macro_rules! line {() => {}}
290
291fn main() {
292 let x = line!();
293}
294"#),
295 @r###"
296 ![0; 1) '6': i32
297 [64; 88) '{ ...!(); }': ()
298 [74; 75) 'x': i32
299 "###
300 );
301}
302
303#[test]
304fn infer_builtin_macros_file() {
305 assert_snapshot!(
306 infer(r#"
307#[rustc_builtin_macro]
308macro_rules! file {() => {}}
309
310fn main() {
311 let x = file!();
312}
313"#),
314 @r###"
315 ![0; 2) '""': &str
316 [64; 88) '{ ...!(); }': ()
317 [74; 75) 'x': &str
318 "###
319 );
320}
321
322#[test]
323fn infer_builtin_macros_column() {
324 assert_snapshot!(
325 infer(r#"
326#[rustc_builtin_macro]
327macro_rules! column {() => {}}
328
329fn main() {
330 let x = column!();
331}
332"#),
333 @r###"
334 ![0; 2) '13': i32
335 [66; 92) '{ ...!(); }': ()
336 [76; 77) 'x': i32
337 "###
338 );
339}
340
341#[test]
342fn infer_derive_clone_simple() {
343 let (db, pos) = TestDB::with_position(
344 r#"
345//- /main.rs crate:main deps:std
346#[derive(Clone)]
347struct S;
348fn test() {
349 S.clone()<|>;
350}
351
352//- /lib.rs crate:std
353#[prelude_import]
354use clone::*;
355mod clone {
356 trait Clone {
357 fn clone(&self) -> Self;
358 }
359}
360"#,
361 );
362 assert_eq!("S", type_at_pos(&db, pos));
363}
364
365#[test]
366fn infer_derive_clone_with_params() {
367 let (db, pos) = TestDB::with_position(
368 r#"
369//- /main.rs crate:main deps:std
370#[derive(Clone)]
371struct S;
372#[derive(Clone)]
373struct Wrapper<T>(T);
374struct NonClone;
375fn test() {
376 (Wrapper(S).clone(), Wrapper(NonClone).clone())<|>;
377}
378
379//- /lib.rs crate:std
380#[prelude_import]
381use clone::*;
382mod clone {
383 trait Clone {
384 fn clone(&self) -> Self;
385 }
386}
387"#,
388 );
389 assert_eq!("(Wrapper<S>, {unknown})", type_at_pos(&db, pos));
390}
diff --git a/crates/ra_hir_ty/src/tests/method_resolution.rs b/crates/ra_hir_ty/src/tests/method_resolution.rs
new file mode 100644
index 000000000..ce9a06fde
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/method_resolution.rs
@@ -0,0 +1,1005 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn infer_slice_method() {
8 assert_snapshot!(
9 infer(r#"
10#[lang = "slice"]
11impl<T> [T] {
12 fn foo(&self) -> T {
13 loop {}
14 }
15}
16
17#[lang = "slice_alloc"]
18impl<T> [T] {}
19
20fn test() {
21 <[_]>::foo(b"foo");
22}
23"#),
24 @r###"
25 [45; 49) 'self': &[T]
26 [56; 79) '{ ... }': T
27 [66; 73) 'loop {}': !
28 [71; 73) '{}': ()
29 [133; 160) '{ ...o"); }': ()
30 [139; 149) '<[_]>::foo': fn foo<u8>(&[T]) -> T
31 [139; 157) '<[_]>:..."foo")': u8
32 [150; 156) 'b"foo"': &[u8]
33 "###
34 );
35}
36
37#[test]
38fn infer_associated_method_struct() {
39 assert_snapshot!(
40 infer(r#"
41struct A { x: u32 }
42
43impl A {
44 fn new() -> A {
45 A { x: 0 }
46 }
47}
48fn test() {
49 let a = A::new();
50 a.x;
51}
52"#),
53 @r###"
54 [49; 75) '{ ... }': A
55 [59; 69) 'A { x: 0 }': A
56 [66; 67) '0': u32
57 [88; 122) '{ ...a.x; }': ()
58 [98; 99) 'a': A
59 [102; 108) 'A::new': fn new() -> A
60 [102; 110) 'A::new()': A
61 [116; 117) 'a': A
62 [116; 119) 'a.x': u32
63 "###
64 );
65}
66
67#[test]
68fn infer_associated_method_enum() {
69 assert_snapshot!(
70 infer(r#"
71enum A { B, C }
72
73impl A {
74 pub fn b() -> A {
75 A::B
76 }
77 pub fn c() -> A {
78 A::C
79 }
80}
81fn test() {
82 let a = A::b();
83 a;
84 let c = A::c();
85 c;
86}
87"#),
88 @r###"
89 [47; 67) '{ ... }': A
90 [57; 61) 'A::B': A
91 [88; 108) '{ ... }': A
92 [98; 102) 'A::C': A
93 [121; 178) '{ ... c; }': ()
94 [131; 132) 'a': A
95 [135; 139) 'A::b': fn b() -> A
96 [135; 141) 'A::b()': A
97 [147; 148) 'a': A
98 [158; 159) 'c': A
99 [162; 166) 'A::c': fn c() -> A
100 [162; 168) 'A::c()': A
101 [174; 175) 'c': A
102 "###
103 );
104}
105
106#[test]
107fn infer_associated_method_with_modules() {
108 assert_snapshot!(
109 infer(r#"
110mod a {
111 struct A;
112 impl A { pub fn thing() -> A { A {} }}
113}
114
115mod b {
116 struct B;
117 impl B { pub fn thing() -> u32 { 99 }}
118
119 mod c {
120 struct C;
121 impl C { pub fn thing() -> C { C {} }}
122 }
123}
124use b::c;
125
126fn test() {
127 let x = a::A::thing();
128 let y = b::B::thing();
129 let z = c::C::thing();
130}
131"#),
132 @r###"
133 [56; 64) '{ A {} }': A
134 [58; 62) 'A {}': A
135 [126; 132) '{ 99 }': u32
136 [128; 130) '99': u32
137 [202; 210) '{ C {} }': C
138 [204; 208) 'C {}': C
139 [241; 325) '{ ...g(); }': ()
140 [251; 252) 'x': A
141 [255; 266) 'a::A::thing': fn thing() -> A
142 [255; 268) 'a::A::thing()': A
143 [278; 279) 'y': u32
144 [282; 293) 'b::B::thing': fn thing() -> u32
145 [282; 295) 'b::B::thing()': u32
146 [305; 306) 'z': C
147 [309; 320) 'c::C::thing': fn thing() -> C
148 [309; 322) 'c::C::thing()': C
149 "###
150 );
151}
152
153#[test]
154fn infer_associated_method_generics() {
155 assert_snapshot!(
156 infer(r#"
157struct Gen<T> {
158 val: T
159}
160
161impl<T> Gen<T> {
162 pub fn make(val: T) -> Gen<T> {
163 Gen { val }
164 }
165}
166
167fn test() {
168 let a = Gen::make(0u32);
169}
170"#),
171 @r###"
172 [64; 67) 'val': T
173 [82; 109) '{ ... }': Gen<T>
174 [92; 103) 'Gen { val }': Gen<T>
175 [98; 101) 'val': T
176 [123; 155) '{ ...32); }': ()
177 [133; 134) 'a': Gen<u32>
178 [137; 146) 'Gen::make': fn make<u32>(T) -> Gen<T>
179 [137; 152) 'Gen::make(0u32)': Gen<u32>
180 [147; 151) '0u32': u32
181 "###
182 );
183}
184
185#[test]
186fn infer_associated_method_generics_with_default_param() {
187 assert_snapshot!(
188 infer(r#"
189struct Gen<T=u32> {
190 val: T
191}
192
193impl<T> Gen<T> {
194 pub fn make() -> Gen<T> {
195 loop { }
196 }
197}
198
199fn test() {
200 let a = Gen::make();
201}
202"#),
203 @r###"
204 [80; 104) '{ ... }': Gen<T>
205 [90; 98) 'loop { }': !
206 [95; 98) '{ }': ()
207 [118; 146) '{ ...e(); }': ()
208 [128; 129) 'a': Gen<u32>
209 [132; 141) 'Gen::make': fn make<u32>() -> Gen<T>
210 [132; 143) 'Gen::make()': Gen<u32>
211 "###
212 );
213}
214
215#[test]
216fn infer_associated_method_generics_with_default_tuple_param() {
217 let t = type_at(
218 r#"
219//- /main.rs
220struct Gen<T=()> {
221 val: T
222}
223
224impl<T> Gen<T> {
225 pub fn make() -> Gen<T> {
226 loop { }
227 }
228}
229
230fn test() {
231 let a = Gen::make();
232 a.val<|>;
233}
234"#,
235 );
236 assert_eq!(t, "()");
237}
238
239#[test]
240fn infer_associated_method_generics_without_args() {
241 assert_snapshot!(
242 infer(r#"
243struct Gen<T> {
244 val: T
245}
246
247impl<T> Gen<T> {
248 pub fn make() -> Gen<T> {
249 loop { }
250 }
251}
252
253fn test() {
254 let a = Gen::<u32>::make();
255}
256"#),
257 @r###"
258 [76; 100) '{ ... }': Gen<T>
259 [86; 94) 'loop { }': !
260 [91; 94) '{ }': ()
261 [114; 149) '{ ...e(); }': ()
262 [124; 125) 'a': Gen<u32>
263 [128; 144) 'Gen::<...::make': fn make<u32>() -> Gen<T>
264 [128; 146) 'Gen::<...make()': Gen<u32>
265 "###
266 );
267}
268
269#[test]
270fn infer_associated_method_generics_2_type_params_without_args() {
271 assert_snapshot!(
272 infer(r#"
273struct Gen<T, U> {
274 val: T,
275 val2: U,
276}
277
278impl<T> Gen<u32, T> {
279 pub fn make() -> Gen<u32,T> {
280 loop { }
281 }
282}
283
284fn test() {
285 let a = Gen::<u32, u64>::make();
286}
287"#),
288 @r###"
289 [102; 126) '{ ... }': Gen<u32, T>
290 [112; 120) 'loop { }': !
291 [117; 120) '{ }': ()
292 [140; 180) '{ ...e(); }': ()
293 [150; 151) 'a': Gen<u32, u64>
294 [154; 175) 'Gen::<...::make': fn make<u64>() -> Gen<u32, T>
295 [154; 177) 'Gen::<...make()': Gen<u32, u64>
296 "###
297 );
298}
299
300#[test]
301fn cross_crate_associated_method_call() {
302 let (db, pos) = TestDB::with_position(
303 r#"
304//- /main.rs crate:main deps:other_crate
305fn test() {
306 let x = other_crate::foo::S::thing();
307 x<|>;
308}
309
310//- /lib.rs crate:other_crate
311mod foo {
312 struct S;
313 impl S {
314 fn thing() -> i128 {}
315 }
316}
317"#,
318 );
319 assert_eq!("i128", type_at_pos(&db, pos));
320}
321
322#[test]
323fn infer_trait_method_simple() {
324 // the trait implementation is intentionally incomplete -- it shouldn't matter
325 assert_snapshot!(
326 infer(r#"
327trait Trait1 {
328 fn method(&self) -> u32;
329}
330struct S1;
331impl Trait1 for S1 {}
332trait Trait2 {
333 fn method(&self) -> i128;
334}
335struct S2;
336impl Trait2 for S2 {}
337fn test() {
338 S1.method(); // -> u32
339 S2.method(); // -> i128
340}
341"#),
342 @r###"
343 [31; 35) 'self': &Self
344 [110; 114) 'self': &Self
345 [170; 228) '{ ...i128 }': ()
346 [176; 178) 'S1': S1
347 [176; 187) 'S1.method()': u32
348 [203; 205) 'S2': S2
349 [203; 214) 'S2.method()': i128
350 "###
351 );
352}
353
354#[test]
355fn infer_trait_method_scoped() {
356 // the trait implementation is intentionally incomplete -- it shouldn't matter
357 assert_snapshot!(
358 infer(r#"
359struct S;
360mod foo {
361 pub trait Trait1 {
362 fn method(&self) -> u32;
363 }
364 impl Trait1 for super::S {}
365}
366mod bar {
367 pub trait Trait2 {
368 fn method(&self) -> i128;
369 }
370 impl Trait2 for super::S {}
371}
372
373mod foo_test {
374 use super::S;
375 use super::foo::Trait1;
376 fn test() {
377 S.method(); // -> u32
378 }
379}
380
381mod bar_test {
382 use super::S;
383 use super::bar::Trait2;
384 fn test() {
385 S.method(); // -> i128
386 }
387}
388"#),
389 @r###"
390 [63; 67) 'self': &Self
391 [169; 173) 'self': &Self
392 [300; 337) '{ ... }': ()
393 [310; 311) 'S': S
394 [310; 320) 'S.method()': u32
395 [416; 454) '{ ... }': ()
396 [426; 427) 'S': S
397 [426; 436) 'S.method()': i128
398 "###
399 );
400}
401
402#[test]
403fn infer_trait_method_generic_1() {
404 // the trait implementation is intentionally incomplete -- it shouldn't matter
405 assert_snapshot!(
406 infer(r#"
407trait Trait<T> {
408 fn method(&self) -> T;
409}
410struct S;
411impl Trait<u32> for S {}
412fn test() {
413 S.method();
414}
415"#),
416 @r###"
417 [33; 37) 'self': &Self
418 [92; 111) '{ ...d(); }': ()
419 [98; 99) 'S': S
420 [98; 108) 'S.method()': u32
421 "###
422 );
423}
424
425#[test]
426fn infer_trait_method_generic_more_params() {
427 // the trait implementation is intentionally incomplete -- it shouldn't matter
428 assert_snapshot!(
429 infer(r#"
430trait Trait<T1, T2, T3> {
431 fn method1(&self) -> (T1, T2, T3);
432 fn method2(&self) -> (T3, T2, T1);
433}
434struct S1;
435impl Trait<u8, u16, u32> for S1 {}
436struct S2;
437impl<T> Trait<i8, i16, T> for S2 {}
438fn test() {
439 S1.method1(); // u8, u16, u32
440 S1.method2(); // u32, u16, u8
441 S2.method1(); // i8, i16, {unknown}
442 S2.method2(); // {unknown}, i16, i8
443}
444"#),
445 @r###"
446 [43; 47) 'self': &Self
447 [82; 86) 'self': &Self
448 [210; 361) '{ ..., i8 }': ()
449 [216; 218) 'S1': S1
450 [216; 228) 'S1.method1()': (u8, u16, u32)
451 [250; 252) 'S1': S1
452 [250; 262) 'S1.method2()': (u32, u16, u8)
453 [284; 286) 'S2': S2
454 [284; 296) 'S2.method1()': (i8, i16, {unknown})
455 [324; 326) 'S2': S2
456 [324; 336) 'S2.method2()': ({unknown}, i16, i8)
457 "###
458 );
459}
460
461#[test]
462fn infer_trait_method_generic_2() {
463 // the trait implementation is intentionally incomplete -- it shouldn't matter
464 assert_snapshot!(
465 infer(r#"
466trait Trait<T> {
467 fn method(&self) -> T;
468}
469struct S<T>(T);
470impl<U> Trait<U> for S<U> {}
471fn test() {
472 S(1u32).method();
473}
474"#),
475 @r###"
476 [33; 37) 'self': &Self
477 [102; 127) '{ ...d(); }': ()
478 [108; 109) 'S': S<u32>(T) -> S<T>
479 [108; 115) 'S(1u32)': S<u32>
480 [108; 124) 'S(1u32...thod()': u32
481 [110; 114) '1u32': u32
482 "###
483 );
484}
485
486#[test]
487fn infer_trait_assoc_method() {
488 assert_snapshot!(
489 infer(r#"
490trait Default {
491 fn default() -> Self;
492}
493struct S;
494impl Default for S {}
495fn test() {
496 let s1: S = Default::default();
497 let s2 = S::default();
498 let s3 = <S as Default>::default();
499}
500"#),
501 @r###"
502 [87; 193) '{ ...t(); }': ()
503 [97; 99) 's1': S
504 [105; 121) 'Defaul...efault': fn default<S>() -> Self
505 [105; 123) 'Defaul...ault()': S
506 [133; 135) 's2': S
507 [138; 148) 'S::default': fn default<S>() -> Self
508 [138; 150) 'S::default()': S
509 [160; 162) 's3': S
510 [165; 188) '<S as ...efault': fn default<S>() -> Self
511 [165; 190) '<S as ...ault()': S
512 "###
513 );
514}
515
516#[test]
517fn infer_trait_assoc_method_generics_1() {
518 assert_snapshot!(
519 infer(r#"
520trait Trait<T> {
521 fn make() -> T;
522}
523struct S;
524impl Trait<u32> for S {}
525struct G<T>;
526impl<T> Trait<T> for G<T> {}
527fn test() {
528 let a = S::make();
529 let b = G::<u64>::make();
530 let c: f64 = G::make();
531}
532"#),
533 @r###"
534 [127; 211) '{ ...e(); }': ()
535 [137; 138) 'a': u32
536 [141; 148) 'S::make': fn make<S, u32>() -> T
537 [141; 150) 'S::make()': u32
538 [160; 161) 'b': u64
539 [164; 178) 'G::<u64>::make': fn make<G<u64>, u64>() -> T
540 [164; 180) 'G::<u6...make()': u64
541 [190; 191) 'c': f64
542 [199; 206) 'G::make': fn make<G<f64>, f64>() -> T
543 [199; 208) 'G::make()': f64
544 "###
545 );
546}
547
548#[test]
549fn infer_trait_assoc_method_generics_2() {
550 assert_snapshot!(
551 infer(r#"
552trait Trait<T> {
553 fn make<U>() -> (T, U);
554}
555struct S;
556impl Trait<u32> for S {}
557struct G<T>;
558impl<T> Trait<T> for G<T> {}
559fn test() {
560 let a = S::make::<i64>();
561 let b: (_, i64) = S::make();
562 let c = G::<u32>::make::<i64>();
563 let d: (u32, _) = G::make::<i64>();
564 let e: (u32, i64) = G::make();
565}
566"#),
567 @r###"
568 [135; 313) '{ ...e(); }': ()
569 [145; 146) 'a': (u32, i64)
570 [149; 163) 'S::make::<i64>': fn make<S, u32, i64>() -> (T, U)
571 [149; 165) 'S::mak...i64>()': (u32, i64)
572 [175; 176) 'b': (u32, i64)
573 [189; 196) 'S::make': fn make<S, u32, i64>() -> (T, U)
574 [189; 198) 'S::make()': (u32, i64)
575 [208; 209) 'c': (u32, i64)
576 [212; 233) 'G::<u3...:<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
577 [212; 235) 'G::<u3...i64>()': (u32, i64)
578 [245; 246) 'd': (u32, i64)
579 [259; 273) 'G::make::<i64>': fn make<G<u32>, u32, i64>() -> (T, U)
580 [259; 275) 'G::mak...i64>()': (u32, i64)
581 [285; 286) 'e': (u32, i64)
582 [301; 308) 'G::make': fn make<G<u32>, u32, i64>() -> (T, U)
583 [301; 310) 'G::make()': (u32, i64)
584 "###
585 );
586}
587
588#[test]
589fn infer_trait_assoc_method_generics_3() {
590 assert_snapshot!(
591 infer(r#"
592trait Trait<T> {
593 fn make() -> (Self, T);
594}
595struct S<T>;
596impl Trait<i64> for S<i32> {}
597fn test() {
598 let a = S::make();
599}
600"#),
601 @r###"
602 [101; 127) '{ ...e(); }': ()
603 [111; 112) 'a': (S<i32>, i64)
604 [115; 122) 'S::make': fn make<S<i32>, i64>() -> (Self, T)
605 [115; 124) 'S::make()': (S<i32>, i64)
606 "###
607 );
608}
609
610#[test]
611fn infer_trait_assoc_method_generics_4() {
612 assert_snapshot!(
613 infer(r#"
614trait Trait<T> {
615 fn make() -> (Self, T);
616}
617struct S<T>;
618impl Trait<i64> for S<u64> {}
619impl Trait<i32> for S<u32> {}
620fn test() {
621 let a: (S<u64>, _) = S::make();
622 let b: (_, i32) = S::make();
623}
624"#),
625 @r###"
626 [131; 203) '{ ...e(); }': ()
627 [141; 142) 'a': (S<u64>, i64)
628 [158; 165) 'S::make': fn make<S<u64>, i64>() -> (Self, T)
629 [158; 167) 'S::make()': (S<u64>, i64)
630 [177; 178) 'b': (S<u32>, i32)
631 [191; 198) 'S::make': fn make<S<u32>, i32>() -> (Self, T)
632 [191; 200) 'S::make()': (S<u32>, i32)
633 "###
634 );
635}
636
637#[test]
638fn infer_trait_assoc_method_generics_5() {
639 assert_snapshot!(
640 infer(r#"
641trait Trait<T> {
642 fn make<U>() -> (Self, T, U);
643}
644struct S<T>;
645impl Trait<i64> for S<u64> {}
646fn test() {
647 let a = <S as Trait<i64>>::make::<u8>();
648 let b: (S<u64>, _, _) = Trait::<i64>::make::<u8>();
649}
650"#),
651 @r###"
652 [107; 211) '{ ...>(); }': ()
653 [117; 118) 'a': (S<u64>, i64, u8)
654 [121; 150) '<S as ...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
655 [121; 152) '<S as ...<u8>()': (S<u64>, i64, u8)
656 [162; 163) 'b': (S<u64>, i64, u8)
657 [182; 206) 'Trait:...::<u8>': fn make<S<u64>, i64, u8>() -> (Self, T, U)
658 [182; 208) 'Trait:...<u8>()': (S<u64>, i64, u8)
659 "###
660 );
661}
662
663#[test]
664fn infer_call_trait_method_on_generic_param_1() {
665 assert_snapshot!(
666 infer(r#"
667trait Trait {
668 fn method(&self) -> u32;
669}
670fn test<T: Trait>(t: T) {
671 t.method();
672}
673"#),
674 @r###"
675 [30; 34) 'self': &Self
676 [64; 65) 't': T
677 [70; 89) '{ ...d(); }': ()
678 [76; 77) 't': T
679 [76; 86) 't.method()': u32
680 "###
681 );
682}
683
684#[test]
685fn infer_call_trait_method_on_generic_param_2() {
686 assert_snapshot!(
687 infer(r#"
688trait Trait<T> {
689 fn method(&self) -> T;
690}
691fn test<U, T: Trait<U>>(t: T) {
692 t.method();
693}
694"#),
695 @r###"
696 [33; 37) 'self': &Self
697 [71; 72) 't': T
698 [77; 96) '{ ...d(); }': ()
699 [83; 84) 't': T
700 [83; 93) 't.method()': [missing name]
701 "###
702 );
703}
704
705#[test]
706fn infer_with_multiple_trait_impls() {
707 assert_snapshot!(
708 infer(r#"
709trait Into<T> {
710 fn into(self) -> T;
711}
712struct S;
713impl Into<u32> for S {}
714impl Into<u64> for S {}
715fn test() {
716 let x: u32 = S.into();
717 let y: u64 = S.into();
718 let z = Into::<u64>::into(S);
719}
720"#),
721 @r###"
722 [29; 33) 'self': Self
723 [111; 202) '{ ...(S); }': ()
724 [121; 122) 'x': u32
725 [130; 131) 'S': S
726 [130; 138) 'S.into()': u32
727 [148; 149) 'y': u64
728 [157; 158) 'S': S
729 [157; 165) 'S.into()': u64
730 [175; 176) 'z': u64
731 [179; 196) 'Into::...::into': fn into<S, u64>(Self) -> T
732 [179; 199) 'Into::...nto(S)': u64
733 [197; 198) 'S': S
734 "###
735 );
736}
737
738#[test]
739fn method_resolution_unify_impl_self_type() {
740 let t = type_at(
741 r#"
742//- /main.rs
743struct S<T>;
744impl S<u32> { fn foo(&self) -> u8 {} }
745impl S<i32> { fn foo(&self) -> i8 {} }
746fn test() { (S::<u32>.foo(), S::<i32>.foo())<|>; }
747"#,
748 );
749 assert_eq!(t, "(u8, i8)");
750}
751
752#[test]
753fn method_resolution_trait_before_autoref() {
754 let t = type_at(
755 r#"
756//- /main.rs
757trait Trait { fn foo(self) -> u128; }
758struct S;
759impl S { fn foo(&self) -> i8 { 0 } }
760impl Trait for S { fn foo(self) -> u128 { 0 } }
761fn test() { S.foo()<|>; }
762"#,
763 );
764 assert_eq!(t, "u128");
765}
766
767#[test]
768fn method_resolution_by_value_before_autoref() {
769 let t = type_at(
770 r#"
771//- /main.rs
772trait Clone { fn clone(&self) -> Self; }
773struct S;
774impl Clone for S {}
775impl Clone for &S {}
776fn test() { (S.clone(), (&S).clone(), (&&S).clone())<|>; }
777"#,
778 );
779 assert_eq!(t, "(S, S, &S)");
780}
781
782#[test]
783fn method_resolution_trait_before_autoderef() {
784 let t = type_at(
785 r#"
786//- /main.rs
787trait Trait { fn foo(self) -> u128; }
788struct S;
789impl S { fn foo(self) -> i8 { 0 } }
790impl Trait for &S { fn foo(self) -> u128 { 0 } }
791fn test() { (&S).foo()<|>; }
792"#,
793 );
794 assert_eq!(t, "u128");
795}
796
797#[test]
798fn method_resolution_impl_before_trait() {
799 let t = type_at(
800 r#"
801//- /main.rs
802trait Trait { fn foo(self) -> u128; }
803struct S;
804impl S { fn foo(self) -> i8 { 0 } }
805impl Trait for S { fn foo(self) -> u128 { 0 } }
806fn test() { S.foo()<|>; }
807"#,
808 );
809 assert_eq!(t, "i8");
810}
811
812#[test]
813fn method_resolution_impl_ref_before_trait() {
814 let t = type_at(
815 r#"
816//- /main.rs
817trait Trait { fn foo(self) -> u128; }
818struct S;
819impl S { fn foo(&self) -> i8 { 0 } }
820impl Trait for &S { fn foo(self) -> u128 { 0 } }
821fn test() { S.foo()<|>; }
822"#,
823 );
824 assert_eq!(t, "i8");
825}
826
827#[test]
828fn method_resolution_trait_autoderef() {
829 let t = type_at(
830 r#"
831//- /main.rs
832trait Trait { fn foo(self) -> u128; }
833struct S;
834impl Trait for S { fn foo(self) -> u128 { 0 } }
835fn test() { (&S).foo()<|>; }
836"#,
837 );
838 assert_eq!(t, "u128");
839}
840
841#[test]
842fn method_resolution_trait_from_prelude() {
843 let (db, pos) = TestDB::with_position(
844 r#"
845//- /main.rs crate:main deps:other_crate
846struct S;
847impl Clone for S {}
848
849fn test() {
850 S.clone()<|>;
851}
852
853//- /lib.rs crate:other_crate
854#[prelude_import] use foo::*;
855
856mod foo {
857 trait Clone {
858 fn clone(&self) -> Self;
859 }
860}
861"#,
862 );
863 assert_eq!("S", type_at_pos(&db, pos));
864}
865
866#[test]
867fn method_resolution_where_clause_for_unknown_trait() {
868 // The blanket impl currently applies because we ignore the unresolved where clause
869 let t = type_at(
870 r#"
871//- /main.rs
872trait Trait { fn foo(self) -> u128; }
873struct S;
874impl<T> Trait for T where T: UnknownTrait {}
875fn test() { (&S).foo()<|>; }
876"#,
877 );
878 assert_eq!(t, "u128");
879}
880
881#[test]
882fn method_resolution_where_clause_not_met() {
883 // The blanket impl shouldn't apply because we can't prove S: Clone
884 let t = type_at(
885 r#"
886//- /main.rs
887trait Clone {}
888trait Trait { fn foo(self) -> u128; }
889struct S;
890impl<T> Trait for T where T: Clone {}
891fn test() { (&S).foo()<|>; }
892"#,
893 );
894 // This is also to make sure that we don't resolve to the foo method just
895 // because that's the only method named foo we can find, which would make
896 // the below tests not work
897 assert_eq!(t, "{unknown}");
898}
899
900#[test]
901fn method_resolution_where_clause_inline_not_met() {
902 // The blanket impl shouldn't apply because we can't prove S: Clone
903 let t = type_at(
904 r#"
905//- /main.rs
906trait Clone {}
907trait Trait { fn foo(self) -> u128; }
908struct S;
909impl<T: Clone> Trait for T {}
910fn test() { (&S).foo()<|>; }
911"#,
912 );
913 assert_eq!(t, "{unknown}");
914}
915
916#[test]
917fn method_resolution_where_clause_1() {
918 let t = type_at(
919 r#"
920//- /main.rs
921trait Clone {}
922trait Trait { fn foo(self) -> u128; }
923struct S;
924impl Clone for S {}
925impl<T> Trait for T where T: Clone {}
926fn test() { S.foo()<|>; }
927"#,
928 );
929 assert_eq!(t, "u128");
930}
931
932#[test]
933fn method_resolution_where_clause_2() {
934 let t = type_at(
935 r#"
936//- /main.rs
937trait Into<T> { fn into(self) -> T; }
938trait From<T> { fn from(other: T) -> Self; }
939struct S1;
940struct S2;
941impl From<S2> for S1 {}
942impl<T, U> Into<U> for T where U: From<T> {}
943fn test() { S2.into()<|>; }
944"#,
945 );
946 assert_eq!(t, "{unknown}");
947}
948
949#[test]
950fn method_resolution_where_clause_inline() {
951 let t = type_at(
952 r#"
953//- /main.rs
954trait Into<T> { fn into(self) -> T; }
955trait From<T> { fn from(other: T) -> Self; }
956struct S1;
957struct S2;
958impl From<S2> for S1 {}
959impl<T, U: From<T>> Into<U> for T {}
960fn test() { S2.into()<|>; }
961"#,
962 );
963 assert_eq!(t, "{unknown}");
964}
965
966#[test]
967fn method_resolution_encountering_fn_type() {
968 type_at(
969 r#"
970//- /main.rs
971fn foo() {}
972trait FnOnce { fn call(self); }
973fn test() { foo.call()<|>; }
974"#,
975 );
976}
977
978#[test]
979fn method_resolution_slow() {
980 // this can get quite slow if we set the solver size limit too high
981 let t = type_at(
982 r#"
983//- /main.rs
984trait SendX {}
985
986struct S1; impl SendX for S1 {}
987struct S2; impl SendX for S2 {}
988struct U1;
989
990trait Trait { fn method(self); }
991
992struct X1<A, B> {}
993impl<A, B> SendX for X1<A, B> where A: SendX, B: SendX {}
994
995struct S<B, C> {}
996
997trait FnX {}
998
999impl<B, C> Trait for S<B, C> where C: FnX, B: SendX {}
1000
1001fn test() { (S {}).method()<|>; }
1002"#,
1003 );
1004 assert_eq!(t, "()");
1005}
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs
new file mode 100644
index 000000000..cb3890b42
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/patterns.rs
@@ -0,0 +1,238 @@
1use super::infer;
2use insta::assert_snapshot;
3use test_utils::covers;
4
5#[test]
6fn infer_pattern() {
7 assert_snapshot!(
8 infer(r#"
9fn test(x: &i32) {
10 let y = x;
11 let &z = x;
12 let a = z;
13 let (c, d) = (1, "hello");
14
15 for (e, f) in some_iter {
16 let g = e;
17 }
18
19 if let [val] = opt {
20 let h = val;
21 }
22
23 let lambda = |a: u64, b, c: i32| { a + b; c };
24
25 let ref ref_to_x = x;
26 let mut mut_x = x;
27 let ref mut mut_ref_to_x = x;
28 let k = mut_ref_to_x;
29}
30"#),
31 @r###"
32 [9; 10) 'x': &i32
33 [18; 369) '{ ...o_x; }': ()
34 [28; 29) 'y': &i32
35 [32; 33) 'x': &i32
36 [43; 45) '&z': &i32
37 [44; 45) 'z': i32
38 [48; 49) 'x': &i32
39 [59; 60) 'a': i32
40 [63; 64) 'z': i32
41 [74; 80) '(c, d)': (i32, &str)
42 [75; 76) 'c': i32
43 [78; 79) 'd': &str
44 [83; 95) '(1, "hello")': (i32, &str)
45 [84; 85) '1': i32
46 [87; 94) '"hello"': &str
47 [102; 152) 'for (e... }': ()
48 [106; 112) '(e, f)': ({unknown}, {unknown})
49 [107; 108) 'e': {unknown}
50 [110; 111) 'f': {unknown}
51 [116; 125) 'some_iter': {unknown}
52 [126; 152) '{ ... }': ()
53 [140; 141) 'g': {unknown}
54 [144; 145) 'e': {unknown}
55 [158; 205) 'if let... }': ()
56 [165; 170) '[val]': {unknown}
57 [173; 176) 'opt': {unknown}
58 [177; 205) '{ ... }': ()
59 [191; 192) 'h': {unknown}
60 [195; 198) 'val': {unknown}
61 [215; 221) 'lambda': |u64, u64, i32| -> i32
62 [224; 256) '|a: u6...b; c }': |u64, u64, i32| -> i32
63 [225; 226) 'a': u64
64 [233; 234) 'b': u64
65 [236; 237) 'c': i32
66 [244; 256) '{ a + b; c }': i32
67 [246; 247) 'a': u64
68 [246; 251) 'a + b': u64
69 [250; 251) 'b': u64
70 [253; 254) 'c': i32
71 [267; 279) 'ref ref_to_x': &&i32
72 [282; 283) 'x': &i32
73 [293; 302) 'mut mut_x': &i32
74 [305; 306) 'x': &i32
75 [316; 336) 'ref mu...f_to_x': &mut &i32
76 [339; 340) 'x': &i32
77 [350; 351) 'k': &mut &i32
78 [354; 366) 'mut_ref_to_x': &mut &i32
79 "###
80 );
81}
82
83#[test]
84fn infer_pattern_match_ergonomics() {
85 assert_snapshot!(
86 infer(r#"
87struct A<T>(T);
88
89fn test() {
90 let A(n) = &A(1);
91 let A(n) = &mut A(1);
92}
93"#),
94 @r###"
95 [28; 79) '{ ...(1); }': ()
96 [38; 42) 'A(n)': A<i32>
97 [40; 41) 'n': &i32
98 [45; 50) '&A(1)': &A<i32>
99 [46; 47) 'A': A<i32>(T) -> A<T>
100 [46; 50) 'A(1)': A<i32>
101 [48; 49) '1': i32
102 [60; 64) 'A(n)': A<i32>
103 [62; 63) 'n': &mut i32
104 [67; 76) '&mut A(1)': &mut A<i32>
105 [72; 73) 'A': A<i32>(T) -> A<T>
106 [72; 76) 'A(1)': A<i32>
107 [74; 75) '1': i32
108 "###
109 );
110}
111
112#[test]
113fn infer_pattern_match_ergonomics_ref() {
114 covers!(match_ergonomics_ref);
115 assert_snapshot!(
116 infer(r#"
117fn test() {
118 let v = &(1, &2);
119 let (_, &w) = v;
120}
121"#),
122 @r###"
123 [11; 57) '{ ...= v; }': ()
124 [21; 22) 'v': &(i32, &i32)
125 [25; 33) '&(1, &2)': &(i32, &i32)
126 [26; 33) '(1, &2)': (i32, &i32)
127 [27; 28) '1': i32
128 [30; 32) '&2': &i32
129 [31; 32) '2': i32
130 [43; 50) '(_, &w)': (i32, &i32)
131 [44; 45) '_': i32
132 [47; 49) '&w': &i32
133 [48; 49) 'w': i32
134 [53; 54) 'v': &(i32, &i32)
135 "###
136 );
137}
138
139#[test]
140fn infer_adt_pattern() {
141 assert_snapshot!(
142 infer(r#"
143enum E {
144 A { x: usize },
145 B
146}
147
148struct S(u32, E);
149
150fn test() {
151 let e = E::A { x: 3 };
152
153 let S(y, z) = foo;
154 let E::A { x: new_var } = e;
155
156 match e {
157 E::A { x } => x,
158 E::B if foo => 1,
159 E::B => 10,
160 };
161
162 let ref d @ E::A { .. } = e;
163 d;
164}
165"#),
166 @r###"
167 [68; 289) '{ ... d; }': ()
168 [78; 79) 'e': E
169 [82; 95) 'E::A { x: 3 }': E
170 [92; 93) '3': usize
171 [106; 113) 'S(y, z)': S
172 [108; 109) 'y': u32
173 [111; 112) 'z': E
174 [116; 119) 'foo': S
175 [129; 148) 'E::A {..._var }': E
176 [139; 146) 'new_var': usize
177 [151; 152) 'e': E
178 [159; 245) 'match ... }': usize
179 [165; 166) 'e': E
180 [177; 187) 'E::A { x }': E
181 [184; 185) 'x': usize
182 [191; 192) 'x': usize
183 [202; 206) 'E::B': E
184 [210; 213) 'foo': bool
185 [217; 218) '1': usize
186 [228; 232) 'E::B': E
187 [236; 238) '10': usize
188 [256; 275) 'ref d ...{ .. }': &E
189 [264; 275) 'E::A { .. }': E
190 [278; 279) 'e': E
191 [285; 286) 'd': &E
192 "###
193 );
194}
195
196#[test]
197fn infer_generics_in_patterns() {
198 assert_snapshot!(
199 infer(r#"
200struct A<T> {
201 x: T,
202}
203
204enum Option<T> {
205 Some(T),
206 None,
207}
208
209fn test(a1: A<u32>, o: Option<u64>) {
210 let A { x: x2 } = a1;
211 let A::<i64> { x: x3 } = A { x: 1 };
212 match o {
213 Option::Some(t) => t,
214 _ => 1,
215 };
216}
217"#),
218 @r###"
219 [79; 81) 'a1': A<u32>
220 [91; 92) 'o': Option<u64>
221 [107; 244) '{ ... }; }': ()
222 [117; 128) 'A { x: x2 }': A<u32>
223 [124; 126) 'x2': u32
224 [131; 133) 'a1': A<u32>
225 [143; 161) 'A::<i6...: x3 }': A<i64>
226 [157; 159) 'x3': i64
227 [164; 174) 'A { x: 1 }': A<i64>
228 [171; 172) '1': i64
229 [180; 241) 'match ... }': u64
230 [186; 187) 'o': Option<u64>
231 [198; 213) 'Option::Some(t)': Option<u64>
232 [211; 212) 't': u64
233 [217; 218) 't': u64
234 [228; 229) '_': Option<u64>
235 [233; 234) '1': u64
236 "###
237 );
238}
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs
new file mode 100644
index 000000000..09d684ac2
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/regression.rs
@@ -0,0 +1,333 @@
1use super::infer;
2use insta::assert_snapshot;
3use test_utils::covers;
4
5#[test]
6fn bug_484() {
7 assert_snapshot!(
8 infer(r#"
9fn test() {
10 let x = if true {};
11}
12"#),
13 @r###"
14 [11; 37) '{ l... {}; }': ()
15 [20; 21) 'x': ()
16 [24; 34) 'if true {}': ()
17 [27; 31) 'true': bool
18 [32; 34) '{}': ()
19 "###
20 );
21}
22
23#[test]
24fn no_panic_on_field_of_enum() {
25 assert_snapshot!(
26 infer(r#"
27enum X {}
28
29fn test(x: X) {
30 x.some_field;
31}
32"#),
33 @r###"
34 [20; 21) 'x': X
35 [26; 47) '{ ...eld; }': ()
36 [32; 33) 'x': X
37 [32; 44) 'x.some_field': {unknown}
38 "###
39 );
40}
41
42#[test]
43fn bug_585() {
44 assert_snapshot!(
45 infer(r#"
46fn test() {
47 X {};
48 match x {
49 A::B {} => (),
50 A::Y() => (),
51 }
52}
53"#),
54 @r###"
55 [11; 89) '{ ... } }': ()
56 [17; 21) 'X {}': {unknown}
57 [27; 87) 'match ... }': ()
58 [33; 34) 'x': {unknown}
59 [45; 52) 'A::B {}': {unknown}
60 [56; 58) '()': ()
61 [68; 74) 'A::Y()': {unknown}
62 [78; 80) '()': ()
63 "###
64 );
65}
66
67#[test]
68fn bug_651() {
69 assert_snapshot!(
70 infer(r#"
71fn quux() {
72 let y = 92;
73 1 + y;
74}
75"#),
76 @r###"
77 [11; 41) '{ ...+ y; }': ()
78 [21; 22) 'y': i32
79 [25; 27) '92': i32
80 [33; 34) '1': i32
81 [33; 38) '1 + y': i32
82 [37; 38) 'y': i32
83 "###
84 );
85}
86
87#[test]
88fn recursive_vars() {
89 covers!(type_var_cycles_resolve_completely);
90 covers!(type_var_cycles_resolve_as_possible);
91 assert_snapshot!(
92 infer(r#"
93fn test() {
94 let y = unknown;
95 [y, &y];
96}
97"#),
98 @r###"
99 [11; 48) '{ ...&y]; }': ()
100 [21; 22) 'y': &{unknown}
101 [25; 32) 'unknown': &{unknown}
102 [38; 45) '[y, &y]': [&&{unknown};_]
103 [39; 40) 'y': &{unknown}
104 [42; 44) '&y': &&{unknown}
105 [43; 44) 'y': &{unknown}
106 "###
107 );
108}
109
110#[test]
111fn recursive_vars_2() {
112 covers!(type_var_cycles_resolve_completely);
113 covers!(type_var_cycles_resolve_as_possible);
114 assert_snapshot!(
115 infer(r#"
116fn test() {
117 let x = unknown;
118 let y = unknown;
119 [(x, y), (&y, &x)];
120}
121"#),
122 @r###"
123 [11; 80) '{ ...x)]; }': ()
124 [21; 22) 'x': &&{unknown}
125 [25; 32) 'unknown': &&{unknown}
126 [42; 43) 'y': &&{unknown}
127 [46; 53) 'unknown': &&{unknown}
128 [59; 77) '[(x, y..., &x)]': [(&&&{unknown}, &&&{unknown});_]
129 [60; 66) '(x, y)': (&&&{unknown}, &&&{unknown})
130 [61; 62) 'x': &&{unknown}
131 [64; 65) 'y': &&{unknown}
132 [68; 76) '(&y, &x)': (&&&{unknown}, &&&{unknown})
133 [69; 71) '&y': &&&{unknown}
134 [70; 71) 'y': &&{unknown}
135 [73; 75) '&x': &&&{unknown}
136 [74; 75) 'x': &&{unknown}
137 "###
138 );
139}
140
141#[test]
142fn infer_std_crash_1() {
143 // caused stack overflow, taken from std
144 assert_snapshot!(
145 infer(r#"
146enum Maybe<T> {
147 Real(T),
148 Fake,
149}
150
151fn write() {
152 match something_unknown {
153 Maybe::Real(ref mut something) => (),
154 }
155}
156"#),
157 @r###"
158 [54; 139) '{ ... } }': ()
159 [60; 137) 'match ... }': ()
160 [66; 83) 'someth...nknown': Maybe<{unknown}>
161 [94; 124) 'Maybe:...thing)': Maybe<{unknown}>
162 [106; 123) 'ref mu...ething': &mut {unknown}
163 [128; 130) '()': ()
164 "###
165 );
166}
167
168#[test]
169fn infer_std_crash_2() {
170 covers!(type_var_resolves_to_int_var);
171 // caused "equating two type variables, ...", taken from std
172 assert_snapshot!(
173 infer(r#"
174fn test_line_buffer() {
175 &[0, b'\n', 1, b'\n'];
176}
177"#),
178 @r###"
179 [23; 53) '{ ...n']; }': ()
180 [29; 50) '&[0, b...b'\n']': &[u8;_]
181 [30; 50) '[0, b'...b'\n']': [u8;_]
182 [31; 32) '0': u8
183 [34; 39) 'b'\n'': u8
184 [41; 42) '1': u8
185 [44; 49) 'b'\n'': u8
186 "###
187 );
188}
189
190#[test]
191fn infer_std_crash_3() {
192 // taken from rustc
193 assert_snapshot!(
194 infer(r#"
195pub fn compute() {
196 match nope!() {
197 SizeSkeleton::Pointer { non_zero: true, tail } => {}
198 }
199}
200"#),
201 @r###"
202 [18; 108) '{ ... } }': ()
203 [24; 106) 'match ... }': ()
204 [30; 37) 'nope!()': {unknown}
205 [48; 94) 'SizeSk...tail }': {unknown}
206 [82; 86) 'true': {unknown}
207 [88; 92) 'tail': {unknown}
208 [98; 100) '{}': ()
209 "###
210 );
211}
212
213#[test]
214fn infer_std_crash_4() {
215 // taken from rustc
216 assert_snapshot!(
217 infer(r#"
218pub fn primitive_type() {
219 match *self {
220 BorrowedRef { type_: Primitive(p), ..} => {},
221 }
222}
223"#),
224 @r###"
225 [25; 106) '{ ... } }': ()
226 [31; 104) 'match ... }': ()
227 [37; 42) '*self': {unknown}
228 [38; 42) 'self': {unknown}
229 [53; 91) 'Borrow...), ..}': {unknown}
230 [74; 86) 'Primitive(p)': {unknown}
231 [84; 85) 'p': {unknown}
232 [95; 97) '{}': ()
233 "###
234 );
235}
236
237#[test]
238fn infer_std_crash_5() {
239 // taken from rustc
240 assert_snapshot!(
241 infer(r#"
242fn extra_compiler_flags() {
243 for content in doesnt_matter {
244 let name = if doesnt_matter {
245 first
246 } else {
247 &content
248 };
249
250 let content = if ICE_REPORT_COMPILER_FLAGS_STRIP_VALUE.contains(&name) {
251 name
252 } else {
253 content
254 };
255 }
256}
257"#),
258 @r###"
259 [27; 323) '{ ... } }': ()
260 [33; 321) 'for co... }': ()
261 [37; 44) 'content': &{unknown}
262 [48; 61) 'doesnt_matter': {unknown}
263 [62; 321) '{ ... }': ()
264 [76; 80) 'name': &&{unknown}
265 [83; 167) 'if doe... }': &&{unknown}
266 [86; 99) 'doesnt_matter': bool
267 [100; 129) '{ ... }': &&{unknown}
268 [114; 119) 'first': &&{unknown}
269 [135; 167) '{ ... }': &&{unknown}
270 [149; 157) '&content': &&{unknown}
271 [150; 157) 'content': &{unknown}
272 [182; 189) 'content': &{unknown}
273 [192; 314) 'if ICE... }': &{unknown}
274 [195; 232) 'ICE_RE..._VALUE': {unknown}
275 [195; 248) 'ICE_RE...&name)': bool
276 [242; 247) '&name': &&&{unknown}
277 [243; 247) 'name': &&{unknown}
278 [249; 277) '{ ... }': &&{unknown}
279 [263; 267) 'name': &&{unknown}
280 [283; 314) '{ ... }': &{unknown}
281 [297; 304) 'content': &{unknown}
282 "###
283 );
284}
285
286#[test]
287fn infer_nested_generics_crash() {
288 // another crash found typechecking rustc
289 assert_snapshot!(
290 infer(r#"
291struct Canonical<V> {
292 value: V,
293}
294struct QueryResponse<V> {
295 value: V,
296}
297fn test<R>(query_response: Canonical<QueryResponse<R>>) {
298 &query_response.value;
299}
300"#),
301 @r###"
302 [92; 106) 'query_response': Canonical<QueryResponse<R>>
303 [137; 167) '{ ...lue; }': ()
304 [143; 164) '&query....value': &QueryResponse<R>
305 [144; 158) 'query_response': Canonical<QueryResponse<R>>
306 [144; 164) 'query_....value': QueryResponse<R>
307 "###
308 );
309}
310
311#[test]
312fn bug_1030() {
313 assert_snapshot!(infer(r#"
314struct HashSet<T, H>;
315struct FxHasher;
316type FxHashSet<T> = HashSet<T, FxHasher>;
317
318impl<T, H> HashSet<T, H> {
319 fn default() -> HashSet<T, H> {}
320}
321
322pub fn main_loop() {
323 FxHashSet::default();
324}
325"#),
326 @r###"
327 [144; 146) '{}': ()
328 [169; 198) '{ ...t(); }': ()
329 [175; 193) 'FxHash...efault': fn default<{unknown}, FxHasher>() -> HashSet<T, H>
330 [175; 195) 'FxHash...ault()': HashSet<{unknown}, FxHasher>
331 "###
332 );
333}
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs
new file mode 100644
index 000000000..3e5e163e3
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/simple.rs
@@ -0,0 +1,1663 @@
1use super::{infer, type_at, type_at_pos};
2use crate::test_db::TestDB;
3use insta::assert_snapshot;
4use ra_db::fixture::WithFixture;
5
6#[test]
7fn infer_box() {
8 let (db, pos) = TestDB::with_position(
9 r#"
10//- /main.rs crate:main deps:std
11
12fn test() {
13 let x = box 1;
14 let t = (x, box x, box &1, box [1]);
15 t<|>;
16}
17
18//- /std.rs crate:std
19#[prelude_import] use prelude::*;
20mod prelude {}
21
22mod boxed {
23 pub struct Box<T: ?Sized> {
24 inner: *mut T,
25 }
26}
27
28"#,
29 );
30 assert_eq!("(Box<i32>, Box<Box<i32>>, Box<&i32>, Box<[i32;_]>)", type_at_pos(&db, pos));
31}
32
33#[test]
34fn infer_adt_self() {
35 let (db, pos) = TestDB::with_position(
36 r#"
37//- /main.rs
38enum Nat { Succ(Self), Demo(Nat), Zero }
39
40fn test() {
41 let foo: Nat = Nat::Zero;
42 if let Nat::Succ(x) = foo {
43 x<|>
44 }
45}
46
47"#,
48 );
49 assert_eq!("Nat", type_at_pos(&db, pos));
50}
51
52#[test]
53fn infer_ranges() {
54 let (db, pos) = TestDB::with_position(
55 r#"
56//- /main.rs crate:main deps:std
57fn test() {
58 let a = ..;
59 let b = 1..;
60 let c = ..2u32;
61 let d = 1..2usize;
62 let e = ..=10;
63 let f = 'a'..='z';
64
65 let t = (a, b, c, d, e, f);
66 t<|>;
67}
68
69//- /std.rs crate:std
70#[prelude_import] use prelude::*;
71mod prelude {}
72
73pub mod ops {
74 pub struct Range<Idx> {
75 pub start: Idx,
76 pub end: Idx,
77 }
78 pub struct RangeFrom<Idx> {
79 pub start: Idx,
80 }
81 struct RangeFull;
82 pub struct RangeInclusive<Idx> {
83 start: Idx,
84 end: Idx,
85 is_empty: u8,
86 }
87 pub struct RangeTo<Idx> {
88 pub end: Idx,
89 }
90 pub struct RangeToInclusive<Idx> {
91 pub end: Idx,
92 }
93}
94"#,
95 );
96 assert_eq!(
97 "(RangeFull, RangeFrom<i32>, RangeTo<u32>, Range<usize>, RangeToInclusive<i32>, RangeInclusive<char>)",
98 type_at_pos(&db, pos),
99 );
100}
101
102#[test]
103fn infer_while_let() {
104 let (db, pos) = TestDB::with_position(
105 r#"
106//- /main.rs
107enum Option<T> { Some(T), None }
108
109fn test() {
110 let foo: Option<f32> = None;
111 while let Option::Some(x) = foo {
112 <|>x
113 }
114}
115
116"#,
117 );
118 assert_eq!("f32", type_at_pos(&db, pos));
119}
120
121#[test]
122fn infer_basics() {
123 assert_snapshot!(
124 infer(r#"
125fn test(a: u32, b: isize, c: !, d: &str) {
126 a;
127 b;
128 c;
129 d;
130 1usize;
131 1isize;
132 "test";
133 1.0f32;
134}"#),
135 @r###"
136 [9; 10) 'a': u32
137 [17; 18) 'b': isize
138 [27; 28) 'c': !
139 [33; 34) 'd': &str
140 [42; 121) '{ ...f32; }': !
141 [48; 49) 'a': u32
142 [55; 56) 'b': isize
143 [62; 63) 'c': !
144 [69; 70) 'd': &str
145 [76; 82) '1usize': usize
146 [88; 94) '1isize': isize
147 [100; 106) '"test"': &str
148 [112; 118) '1.0f32': f32
149 "###
150 );
151}
152
153#[test]
154fn infer_let() {
155 assert_snapshot!(
156 infer(r#"
157fn test() {
158 let a = 1isize;
159 let b: usize = 1;
160 let c = b;
161 let d: u32;
162 let e;
163 let f: i32 = e;
164}
165"#),
166 @r###"
167 [11; 118) '{ ...= e; }': ()
168 [21; 22) 'a': isize
169 [25; 31) '1isize': isize
170 [41; 42) 'b': usize
171 [52; 53) '1': usize
172 [63; 64) 'c': usize
173 [67; 68) 'b': usize
174 [78; 79) 'd': u32
175 [94; 95) 'e': i32
176 [105; 106) 'f': i32
177 [114; 115) 'e': i32
178 "###
179 );
180}
181
182#[test]
183fn infer_paths() {
184 assert_snapshot!(
185 infer(r#"
186fn a() -> u32 { 1 }
187
188mod b {
189 fn c() -> u32 { 1 }
190}
191
192fn test() {
193 a();
194 b::c();
195}
196"#),
197 @r###"
198 [15; 20) '{ 1 }': u32
199 [17; 18) '1': u32
200 [48; 53) '{ 1 }': u32
201 [50; 51) '1': u32
202 [67; 91) '{ ...c(); }': ()
203 [73; 74) 'a': fn a() -> u32
204 [73; 76) 'a()': u32
205 [82; 86) 'b::c': fn c() -> u32
206 [82; 88) 'b::c()': u32
207 "###
208 );
209}
210
211#[test]
212fn infer_path_type() {
213 assert_snapshot!(
214 infer(r#"
215struct S;
216
217impl S {
218 fn foo() -> i32 { 1 }
219}
220
221fn test() {
222 S::foo();
223 <S>::foo();
224}
225"#),
226 @r###"
227 [41; 46) '{ 1 }': i32
228 [43; 44) '1': i32
229 [60; 93) '{ ...o(); }': ()
230 [66; 72) 'S::foo': fn foo() -> i32
231 [66; 74) 'S::foo()': i32
232 [80; 88) '<S>::foo': fn foo() -> i32
233 [80; 90) '<S>::foo()': i32
234 "###
235 );
236}
237
238#[test]
239fn infer_struct() {
240 assert_snapshot!(
241 infer(r#"
242struct A {
243 b: B,
244 c: C,
245}
246struct B;
247struct C(usize);
248
249fn test() {
250 let c = C(1);
251 B;
252 let a: A = A { b: B, c: C(1) };
253 a.b;
254 a.c;
255}
256"#),
257 @r###"
258 [72; 154) '{ ...a.c; }': ()
259 [82; 83) 'c': C
260 [86; 87) 'C': C(usize) -> C
261 [86; 90) 'C(1)': C
262 [88; 89) '1': usize
263 [96; 97) 'B': B
264 [107; 108) 'a': A
265 [114; 133) 'A { b:...C(1) }': A
266 [121; 122) 'B': B
267 [127; 128) 'C': C(usize) -> C
268 [127; 131) 'C(1)': C
269 [129; 130) '1': usize
270 [139; 140) 'a': A
271 [139; 142) 'a.b': B
272 [148; 149) 'a': A
273 [148; 151) 'a.c': C
274 "###
275 );
276}
277
278#[test]
279fn infer_enum() {
280 assert_snapshot!(
281 infer(r#"
282enum E {
283 V1 { field: u32 },
284 V2
285}
286fn test() {
287 E::V1 { field: 1 };
288 E::V2;
289}"#),
290 @r###"
291 [48; 82) '{ E:...:V2; }': ()
292 [52; 70) 'E::V1 ...d: 1 }': E
293 [67; 68) '1': u32
294 [74; 79) 'E::V2': E
295 "###
296 );
297}
298
299#[test]
300fn infer_refs() {
301 assert_snapshot!(
302 infer(r#"
303fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) {
304 a;
305 *a;
306 &a;
307 &mut a;
308 b;
309 *b;
310 &b;
311 c;
312 *c;
313 d;
314 *d;
315}
316"#),
317 @r###"
318 [9; 10) 'a': &u32
319 [18; 19) 'b': &mut u32
320 [31; 32) 'c': *const u32
321 [46; 47) 'd': *mut u32
322 [59; 150) '{ ... *d; }': ()
323 [65; 66) 'a': &u32
324 [72; 74) '*a': u32
325 [73; 74) 'a': &u32
326 [80; 82) '&a': &&u32
327 [81; 82) 'a': &u32
328 [88; 94) '&mut a': &mut &u32
329 [93; 94) 'a': &u32
330 [100; 101) 'b': &mut u32
331 [107; 109) '*b': u32
332 [108; 109) 'b': &mut u32
333 [115; 117) '&b': &&mut u32
334 [116; 117) 'b': &mut u32
335 [123; 124) 'c': *const u32
336 [130; 132) '*c': u32
337 [131; 132) 'c': *const u32
338 [138; 139) 'd': *mut u32
339 [145; 147) '*d': u32
340 [146; 147) 'd': *mut u32
341 "###
342 );
343}
344
345#[test]
346fn infer_literals() {
347 assert_snapshot!(
348 infer(r##"
349fn test() {
350 5i32;
351 5f32;
352 5f64;
353 "hello";
354 b"bytes";
355 'c';
356 b'b';
357 3.14;
358 5000;
359 false;
360 true;
361 r#"
362 //! doc
363 // non-doc
364 mod foo {}
365 "#;
366 br#"yolo"#;
367}
368"##),
369 @r###"
370 [11; 221) '{ ...o"#; }': ()
371 [17; 21) '5i32': i32
372 [27; 31) '5f32': f32
373 [37; 41) '5f64': f64
374 [47; 54) '"hello"': &str
375 [60; 68) 'b"bytes"': &[u8]
376 [74; 77) ''c'': char
377 [83; 87) 'b'b'': u8
378 [93; 97) '3.14': f64
379 [103; 107) '5000': i32
380 [113; 118) 'false': bool
381 [124; 128) 'true': bool
382 [134; 202) 'r#" ... "#': &str
383 [208; 218) 'br#"yolo"#': &[u8]
384 "###
385 );
386}
387
388#[test]
389fn infer_unary_op() {
390 assert_snapshot!(
391 infer(r#"
392enum SomeType {}
393
394fn test(x: SomeType) {
395 let b = false;
396 let c = !b;
397 let a = 100;
398 let d: i128 = -a;
399 let e = -100;
400 let f = !!!true;
401 let g = !42;
402 let h = !10u32;
403 let j = !a;
404 -3.14;
405 !3;
406 -x;
407 !x;
408 -"hello";
409 !"hello";
410}
411"#),
412 @r###"
413 [27; 28) 'x': SomeType
414 [40; 272) '{ ...lo"; }': ()
415 [50; 51) 'b': bool
416 [54; 59) 'false': bool
417 [69; 70) 'c': bool
418 [73; 75) '!b': bool
419 [74; 75) 'b': bool
420 [85; 86) 'a': i128
421 [89; 92) '100': i128
422 [102; 103) 'd': i128
423 [112; 114) '-a': i128
424 [113; 114) 'a': i128
425 [124; 125) 'e': i32
426 [128; 132) '-100': i32
427 [129; 132) '100': i32
428 [142; 143) 'f': bool
429 [146; 153) '!!!true': bool
430 [147; 153) '!!true': bool
431 [148; 153) '!true': bool
432 [149; 153) 'true': bool
433 [163; 164) 'g': i32
434 [167; 170) '!42': i32
435 [168; 170) '42': i32
436 [180; 181) 'h': u32
437 [184; 190) '!10u32': u32
438 [185; 190) '10u32': u32
439 [200; 201) 'j': i128
440 [204; 206) '!a': i128
441 [205; 206) 'a': i128
442 [212; 217) '-3.14': f64
443 [213; 217) '3.14': f64
444 [223; 225) '!3': i32
445 [224; 225) '3': i32
446 [231; 233) '-x': {unknown}
447 [232; 233) 'x': SomeType
448 [239; 241) '!x': {unknown}
449 [240; 241) 'x': SomeType
450 [247; 255) '-"hello"': {unknown}
451 [248; 255) '"hello"': &str
452 [261; 269) '!"hello"': {unknown}
453 [262; 269) '"hello"': &str
454 "###
455 );
456}
457
458#[test]
459fn infer_backwards() {
460 assert_snapshot!(
461 infer(r#"
462fn takes_u32(x: u32) {}
463
464struct S { i32_field: i32 }
465
466fn test() -> &mut &f64 {
467 let a = unknown_function();
468 takes_u32(a);
469 let b = unknown_function();
470 S { i32_field: b };
471 let c = unknown_function();
472 &mut &c
473}
474"#),
475 @r###"
476 [14; 15) 'x': u32
477 [22; 24) '{}': ()
478 [78; 231) '{ ...t &c }': &mut &f64
479 [88; 89) 'a': u32
480 [92; 108) 'unknow...nction': {unknown}
481 [92; 110) 'unknow...tion()': u32
482 [116; 125) 'takes_u32': fn takes_u32(u32) -> ()
483 [116; 128) 'takes_u32(a)': ()
484 [126; 127) 'a': u32
485 [138; 139) 'b': i32
486 [142; 158) 'unknow...nction': {unknown}
487 [142; 160) 'unknow...tion()': i32
488 [166; 184) 'S { i3...d: b }': S
489 [181; 182) 'b': i32
490 [194; 195) 'c': f64
491 [198; 214) 'unknow...nction': {unknown}
492 [198; 216) 'unknow...tion()': f64
493 [222; 229) '&mut &c': &mut &f64
494 [227; 229) '&c': &f64
495 [228; 229) 'c': f64
496 "###
497 );
498}
499
500#[test]
501fn infer_self() {
502 assert_snapshot!(
503 infer(r#"
504struct S;
505
506impl S {
507 fn test(&self) {
508 self;
509 }
510 fn test2(self: &Self) {
511 self;
512 }
513 fn test3() -> Self {
514 S {}
515 }
516 fn test4() -> Self {
517 Self {}
518 }
519}
520"#),
521 @r###"
522 [34; 38) 'self': &S
523 [40; 61) '{ ... }': ()
524 [50; 54) 'self': &S
525 [75; 79) 'self': &S
526 [88; 109) '{ ... }': ()
527 [98; 102) 'self': &S
528 [133; 153) '{ ... }': S
529 [143; 147) 'S {}': S
530 [177; 200) '{ ... }': S
531 [187; 194) 'Self {}': S
532 "###
533 );
534}
535
536#[test]
537fn infer_binary_op() {
538 assert_snapshot!(
539 infer(r#"
540fn f(x: bool) -> i32 {
541 0i32
542}
543
544fn test() -> bool {
545 let x = a && b;
546 let y = true || false;
547 let z = x == y;
548 let t = x != y;
549 let minus_forty: isize = -40isize;
550 let h = minus_forty <= CONST_2;
551 let c = f(z || y) + 5;
552 let d = b;
553 let g = minus_forty ^= i;
554 let ten: usize = 10;
555 let ten_is_eleven = ten == some_num;
556
557 ten < 3
558}
559"#),
560 @r###"
561 [6; 7) 'x': bool
562 [22; 34) '{ 0i32 }': i32
563 [28; 32) '0i32': i32
564 [54; 370) '{ ... < 3 }': bool
565 [64; 65) 'x': bool
566 [68; 69) 'a': bool
567 [68; 74) 'a && b': bool
568 [73; 74) 'b': bool
569 [84; 85) 'y': bool
570 [88; 92) 'true': bool
571 [88; 101) 'true || false': bool
572 [96; 101) 'false': bool
573 [111; 112) 'z': bool
574 [115; 116) 'x': bool
575 [115; 121) 'x == y': bool
576 [120; 121) 'y': bool
577 [131; 132) 't': bool
578 [135; 136) 'x': bool
579 [135; 141) 'x != y': bool
580 [140; 141) 'y': bool
581 [151; 162) 'minus_forty': isize
582 [172; 180) '-40isize': isize
583 [173; 180) '40isize': isize
584 [190; 191) 'h': bool
585 [194; 205) 'minus_forty': isize
586 [194; 216) 'minus_...ONST_2': bool
587 [209; 216) 'CONST_2': isize
588 [226; 227) 'c': i32
589 [230; 231) 'f': fn f(bool) -> i32
590 [230; 239) 'f(z || y)': i32
591 [230; 243) 'f(z || y) + 5': i32
592 [232; 233) 'z': bool
593 [232; 238) 'z || y': bool
594 [237; 238) 'y': bool
595 [242; 243) '5': i32
596 [253; 254) 'd': {unknown}
597 [257; 258) 'b': {unknown}
598 [268; 269) 'g': ()
599 [272; 283) 'minus_forty': isize
600 [272; 288) 'minus_...y ^= i': ()
601 [287; 288) 'i': isize
602 [298; 301) 'ten': usize
603 [311; 313) '10': usize
604 [323; 336) 'ten_is_eleven': bool
605 [339; 342) 'ten': usize
606 [339; 354) 'ten == some_num': bool
607 [346; 354) 'some_num': usize
608 [361; 364) 'ten': usize
609 [361; 368) 'ten < 3': bool
610 [367; 368) '3': usize
611 "###
612 );
613}
614
615#[test]
616fn infer_field_autoderef() {
617 assert_snapshot!(
618 infer(r#"
619struct A {
620 b: B,
621}
622struct B;
623
624fn test1(a: A) {
625 let a1 = a;
626 a1.b;
627 let a2 = &a;
628 a2.b;
629 let a3 = &mut a;
630 a3.b;
631 let a4 = &&&&&&&a;
632 a4.b;
633 let a5 = &mut &&mut &&mut a;
634 a5.b;
635}
636
637fn test2(a1: *const A, a2: *mut A) {
638 a1.b;
639 a2.b;
640}
641"#),
642 @r###"
643 [44; 45) 'a': A
644 [50; 213) '{ ...5.b; }': ()
645 [60; 62) 'a1': A
646 [65; 66) 'a': A
647 [72; 74) 'a1': A
648 [72; 76) 'a1.b': B
649 [86; 88) 'a2': &A
650 [91; 93) '&a': &A
651 [92; 93) 'a': A
652 [99; 101) 'a2': &A
653 [99; 103) 'a2.b': B
654 [113; 115) 'a3': &mut A
655 [118; 124) '&mut a': &mut A
656 [123; 124) 'a': A
657 [130; 132) 'a3': &mut A
658 [130; 134) 'a3.b': B
659 [144; 146) 'a4': &&&&&&&A
660 [149; 157) '&&&&&&&a': &&&&&&&A
661 [150; 157) '&&&&&&a': &&&&&&A
662 [151; 157) '&&&&&a': &&&&&A
663 [152; 157) '&&&&a': &&&&A
664 [153; 157) '&&&a': &&&A
665 [154; 157) '&&a': &&A
666 [155; 157) '&a': &A
667 [156; 157) 'a': A
668 [163; 165) 'a4': &&&&&&&A
669 [163; 167) 'a4.b': B
670 [177; 179) 'a5': &mut &&mut &&mut A
671 [182; 200) '&mut &...&mut a': &mut &&mut &&mut A
672 [187; 200) '&&mut &&mut a': &&mut &&mut A
673 [188; 200) '&mut &&mut a': &mut &&mut A
674 [193; 200) '&&mut a': &&mut A
675 [194; 200) '&mut a': &mut A
676 [199; 200) 'a': A
677 [206; 208) 'a5': &mut &&mut &&mut A
678 [206; 210) 'a5.b': B
679 [224; 226) 'a1': *const A
680 [238; 240) 'a2': *mut A
681 [250; 273) '{ ...2.b; }': ()
682 [256; 258) 'a1': *const A
683 [256; 260) 'a1.b': B
684 [266; 268) 'a2': *mut A
685 [266; 270) 'a2.b': B
686 "###
687 );
688}
689
690#[test]
691fn infer_argument_autoderef() {
692 assert_snapshot!(
693 infer(r#"
694#[lang = "deref"]
695pub trait Deref {
696 type Target;
697 fn deref(&self) -> &Self::Target;
698}
699
700struct A<T>(T);
701
702impl<T> A<T> {
703 fn foo(&self) -> &T {
704 &self.0
705 }
706}
707
708struct B<T>(T);
709
710impl<T> Deref for B<T> {
711 type Target = T;
712 fn deref(&self) -> &Self::Target {
713 &self.0
714 }
715}
716
717fn test() {
718 let t = A::foo(&&B(B(A(42))));
719}
720"#),
721 @r###"
722 [68; 72) 'self': &Self
723 [139; 143) 'self': &A<T>
724 [151; 174) '{ ... }': &T
725 [161; 168) '&self.0': &T
726 [162; 166) 'self': &A<T>
727 [162; 168) 'self.0': T
728 [255; 259) 'self': &B<T>
729 [278; 301) '{ ... }': &T
730 [288; 295) '&self.0': &T
731 [289; 293) 'self': &B<T>
732 [289; 295) 'self.0': T
733 [315; 353) '{ ...))); }': ()
734 [325; 326) 't': &i32
735 [329; 335) 'A::foo': fn foo<i32>(&A<T>) -> &T
736 [329; 350) 'A::foo...42))))': &i32
737 [336; 349) '&&B(B(A(42)))': &&B<B<A<i32>>>
738 [337; 349) '&B(B(A(42)))': &B<B<A<i32>>>
739 [338; 339) 'B': B<B<A<i32>>>(T) -> B<T>
740 [338; 349) 'B(B(A(42)))': B<B<A<i32>>>
741 [340; 341) 'B': B<A<i32>>(T) -> B<T>
742 [340; 348) 'B(A(42))': B<A<i32>>
743 [342; 343) 'A': A<i32>(T) -> A<T>
744 [342; 347) 'A(42)': A<i32>
745 [344; 346) '42': i32
746 "###
747 );
748}
749
750#[test]
751fn infer_method_argument_autoderef() {
752 assert_snapshot!(
753 infer(r#"
754#[lang = "deref"]
755pub trait Deref {
756 type Target;
757 fn deref(&self) -> &Self::Target;
758}
759
760struct A<T>(*mut T);
761
762impl<T> A<T> {
763 fn foo(&self, x: &A<T>) -> &T {
764 &*x.0
765 }
766}
767
768struct B<T>(T);
769
770impl<T> Deref for B<T> {
771 type Target = T;
772 fn deref(&self) -> &Self::Target {
773 &self.0
774 }
775}
776
777fn test(a: A<i32>) {
778 let t = A(0 as *mut _).foo(&&B(B(a)));
779}
780"#),
781 @r###"
782 [68; 72) 'self': &Self
783 [144; 148) 'self': &A<T>
784 [150; 151) 'x': &A<T>
785 [166; 187) '{ ... }': &T
786 [176; 181) '&*x.0': &T
787 [177; 181) '*x.0': T
788 [178; 179) 'x': &A<T>
789 [178; 181) 'x.0': *mut T
790 [268; 272) 'self': &B<T>
791 [291; 314) '{ ... }': &T
792 [301; 308) '&self.0': &T
793 [302; 306) 'self': &B<T>
794 [302; 308) 'self.0': T
795 [326; 327) 'a': A<i32>
796 [337; 383) '{ ...))); }': ()
797 [347; 348) 't': &i32
798 [351; 352) 'A': A<i32>(*mut T) -> A<T>
799 [351; 365) 'A(0 as *mut _)': A<i32>
800 [351; 380) 'A(0 as...B(a)))': &i32
801 [353; 354) '0': i32
802 [353; 364) '0 as *mut _': *mut i32
803 [370; 379) '&&B(B(a))': &&B<B<A<i32>>>
804 [371; 379) '&B(B(a))': &B<B<A<i32>>>
805 [372; 373) 'B': B<B<A<i32>>>(T) -> B<T>
806 [372; 379) 'B(B(a))': B<B<A<i32>>>
807 [374; 375) 'B': B<A<i32>>(T) -> B<T>
808 [374; 378) 'B(a)': B<A<i32>>
809 [376; 377) 'a': A<i32>
810 "###
811 );
812}
813
814#[test]
815fn infer_in_elseif() {
816 assert_snapshot!(
817 infer(r#"
818struct Foo { field: i32 }
819fn main(foo: Foo) {
820 if true {
821
822 } else if false {
823 foo.field
824 }
825}
826"#),
827 @r###"
828 [35; 38) 'foo': Foo
829 [45; 109) '{ ... } }': ()
830 [51; 107) 'if tru... }': ()
831 [54; 58) 'true': bool
832 [59; 67) '{ }': ()
833 [73; 107) 'if fal... }': ()
834 [76; 81) 'false': bool
835 [82; 107) '{ ... }': i32
836 [92; 95) 'foo': Foo
837 [92; 101) 'foo.field': i32
838 "###
839 )
840}
841
842#[test]
843fn infer_if_match_with_return() {
844 assert_snapshot!(
845 infer(r#"
846fn foo() {
847 let _x1 = if true {
848 1
849 } else {
850 return;
851 };
852 let _x2 = if true {
853 2
854 } else {
855 return
856 };
857 let _x3 = match true {
858 true => 3,
859 _ => {
860 return;
861 }
862 };
863 let _x4 = match true {
864 true => 4,
865 _ => return
866 };
867}"#),
868 @r###"
869 [10; 323) '{ ... }; }': ()
870 [20; 23) '_x1': i32
871 [26; 80) 'if tru... }': i32
872 [29; 33) 'true': bool
873 [34; 51) '{ ... }': i32
874 [44; 45) '1': i32
875 [57; 80) '{ ... }': !
876 [67; 73) 'return': !
877 [90; 93) '_x2': i32
878 [96; 149) 'if tru... }': i32
879 [99; 103) 'true': bool
880 [104; 121) '{ ... }': i32
881 [114; 115) '2': i32
882 [127; 149) '{ ... }': !
883 [137; 143) 'return': !
884 [159; 162) '_x3': i32
885 [165; 247) 'match ... }': i32
886 [171; 175) 'true': bool
887 [186; 190) 'true': bool
888 [194; 195) '3': i32
889 [205; 206) '_': bool
890 [210; 241) '{ ... }': !
891 [224; 230) 'return': !
892 [257; 260) '_x4': i32
893 [263; 320) 'match ... }': i32
894 [269; 273) 'true': bool
895 [284; 288) 'true': bool
896 [292; 293) '4': i32
897 [303; 304) '_': bool
898 [308; 314) 'return': !
899 "###
900 )
901}
902
903#[test]
904fn infer_inherent_method() {
905 assert_snapshot!(
906 infer(r#"
907struct A;
908
909impl A {
910 fn foo(self, x: u32) -> i32 {}
911}
912
913mod b {
914 impl super::A {
915 fn bar(&self, x: u64) -> i64 {}
916 }
917}
918
919fn test(a: A) {
920 a.foo(1);
921 (&a).bar(1);
922 a.bar(1);
923}
924"#),
925 @r###"
926 [32; 36) 'self': A
927 [38; 39) 'x': u32
928 [53; 55) '{}': ()
929 [103; 107) 'self': &A
930 [109; 110) 'x': u64
931 [124; 126) '{}': ()
932 [144; 145) 'a': A
933 [150; 198) '{ ...(1); }': ()
934 [156; 157) 'a': A
935 [156; 164) 'a.foo(1)': i32
936 [162; 163) '1': u32
937 [170; 181) '(&a).bar(1)': i64
938 [171; 173) '&a': &A
939 [172; 173) 'a': A
940 [179; 180) '1': u64
941 [187; 188) 'a': A
942 [187; 195) 'a.bar(1)': i64
943 [193; 194) '1': u64
944 "###
945 );
946}
947
948#[test]
949fn infer_inherent_method_str() {
950 assert_snapshot!(
951 infer(r#"
952#[lang = "str"]
953impl str {
954 fn foo(&self) -> i32 {}
955}
956
957fn test() {
958 "foo".foo();
959}
960"#),
961 @r###"
962 [40; 44) 'self': &str
963 [53; 55) '{}': ()
964 [69; 89) '{ ...o(); }': ()
965 [75; 80) '"foo"': &str
966 [75; 86) '"foo".foo()': i32
967 "###
968 );
969}
970
971#[test]
972fn infer_tuple() {
973 assert_snapshot!(
974 infer(r#"
975fn test(x: &str, y: isize) {
976 let a: (u32, &str) = (1, "a");
977 let b = (a, x);
978 let c = (y, x);
979 let d = (c, x);
980 let e = (1, "e");
981 let f = (e, "d");
982}
983"#),
984 @r###"
985 [9; 10) 'x': &str
986 [18; 19) 'y': isize
987 [28; 170) '{ ...d"); }': ()
988 [38; 39) 'a': (u32, &str)
989 [55; 63) '(1, "a")': (u32, &str)
990 [56; 57) '1': u32
991 [59; 62) '"a"': &str
992 [73; 74) 'b': ((u32, &str), &str)
993 [77; 83) '(a, x)': ((u32, &str), &str)
994 [78; 79) 'a': (u32, &str)
995 [81; 82) 'x': &str
996 [93; 94) 'c': (isize, &str)
997 [97; 103) '(y, x)': (isize, &str)
998 [98; 99) 'y': isize
999 [101; 102) 'x': &str
1000 [113; 114) 'd': ((isize, &str), &str)
1001 [117; 123) '(c, x)': ((isize, &str), &str)
1002 [118; 119) 'c': (isize, &str)
1003 [121; 122) 'x': &str
1004 [133; 134) 'e': (i32, &str)
1005 [137; 145) '(1, "e")': (i32, &str)
1006 [138; 139) '1': i32
1007 [141; 144) '"e"': &str
1008 [155; 156) 'f': ((i32, &str), &str)
1009 [159; 167) '(e, "d")': ((i32, &str), &str)
1010 [160; 161) 'e': (i32, &str)
1011 [163; 166) '"d"': &str
1012 "###
1013 );
1014}
1015
1016#[test]
1017fn infer_array() {
1018 assert_snapshot!(
1019 infer(r#"
1020fn test(x: &str, y: isize) {
1021 let a = [x];
1022 let b = [a, a];
1023 let c = [b, b];
1024
1025 let d = [y, 1, 2, 3];
1026 let d = [1, y, 2, 3];
1027 let e = [y];
1028 let f = [d, d];
1029 let g = [e, e];
1030
1031 let h = [1, 2];
1032 let i = ["a", "b"];
1033
1034 let b = [a, ["b"]];
1035 let x: [u8; 0] = [];
1036}
1037"#),
1038 @r###"
1039 [9; 10) 'x': &str
1040 [18; 19) 'y': isize
1041 [28; 293) '{ ... []; }': ()
1042 [38; 39) 'a': [&str;_]
1043 [42; 45) '[x]': [&str;_]
1044 [43; 44) 'x': &str
1045 [55; 56) 'b': [[&str;_];_]
1046 [59; 65) '[a, a]': [[&str;_];_]
1047 [60; 61) 'a': [&str;_]
1048 [63; 64) 'a': [&str;_]
1049 [75; 76) 'c': [[[&str;_];_];_]
1050 [79; 85) '[b, b]': [[[&str;_];_];_]
1051 [80; 81) 'b': [[&str;_];_]
1052 [83; 84) 'b': [[&str;_];_]
1053 [96; 97) 'd': [isize;_]
1054 [100; 112) '[y, 1, 2, 3]': [isize;_]
1055 [101; 102) 'y': isize
1056 [104; 105) '1': isize
1057 [107; 108) '2': isize
1058 [110; 111) '3': isize
1059 [122; 123) 'd': [isize;_]
1060 [126; 138) '[1, y, 2, 3]': [isize;_]
1061 [127; 128) '1': isize
1062 [130; 131) 'y': isize
1063 [133; 134) '2': isize
1064 [136; 137) '3': isize
1065 [148; 149) 'e': [isize;_]
1066 [152; 155) '[y]': [isize;_]
1067 [153; 154) 'y': isize
1068 [165; 166) 'f': [[isize;_];_]
1069 [169; 175) '[d, d]': [[isize;_];_]
1070 [170; 171) 'd': [isize;_]
1071 [173; 174) 'd': [isize;_]
1072 [185; 186) 'g': [[isize;_];_]
1073 [189; 195) '[e, e]': [[isize;_];_]
1074 [190; 191) 'e': [isize;_]
1075 [193; 194) 'e': [isize;_]
1076 [206; 207) 'h': [i32;_]
1077 [210; 216) '[1, 2]': [i32;_]
1078 [211; 212) '1': i32
1079 [214; 215) '2': i32
1080 [226; 227) 'i': [&str;_]
1081 [230; 240) '["a", "b"]': [&str;_]
1082 [231; 234) '"a"': &str
1083 [236; 239) '"b"': &str
1084 [251; 252) 'b': [[&str;_];_]
1085 [255; 265) '[a, ["b"]]': [[&str;_];_]
1086 [256; 257) 'a': [&str;_]
1087 [259; 264) '["b"]': [&str;_]
1088 [260; 263) '"b"': &str
1089 [275; 276) 'x': [u8;_]
1090 [288; 290) '[]': [u8;_]
1091 "###
1092 );
1093}
1094
1095#[test]
1096fn infer_struct_generics() {
1097 assert_snapshot!(
1098 infer(r#"
1099struct A<T> {
1100 x: T,
1101}
1102
1103fn test(a1: A<u32>, i: i32) {
1104 a1.x;
1105 let a2 = A { x: i };
1106 a2.x;
1107 let a3 = A::<i128> { x: 1 };
1108 a3.x;
1109}
1110"#),
1111 @r###"
1112 [36; 38) 'a1': A<u32>
1113 [48; 49) 'i': i32
1114 [56; 147) '{ ...3.x; }': ()
1115 [62; 64) 'a1': A<u32>
1116 [62; 66) 'a1.x': u32
1117 [76; 78) 'a2': A<i32>
1118 [81; 91) 'A { x: i }': A<i32>
1119 [88; 89) 'i': i32
1120 [97; 99) 'a2': A<i32>
1121 [97; 101) 'a2.x': i32
1122 [111; 113) 'a3': A<i128>
1123 [116; 134) 'A::<i1...x: 1 }': A<i128>
1124 [131; 132) '1': i128
1125 [140; 142) 'a3': A<i128>
1126 [140; 144) 'a3.x': i128
1127 "###
1128 );
1129}
1130
1131#[test]
1132fn infer_tuple_struct_generics() {
1133 assert_snapshot!(
1134 infer(r#"
1135struct A<T>(T);
1136enum Option<T> { Some(T), None }
1137use Option::*;
1138
1139fn test() {
1140 A(42);
1141 A(42u128);
1142 Some("x");
1143 Option::Some("x");
1144 None;
1145 let x: Option<i64> = None;
1146}
1147"#),
1148 @r###"
1149 [76; 184) '{ ...one; }': ()
1150 [82; 83) 'A': A<i32>(T) -> A<T>
1151 [82; 87) 'A(42)': A<i32>
1152 [84; 86) '42': i32
1153 [93; 94) 'A': A<u128>(T) -> A<T>
1154 [93; 102) 'A(42u128)': A<u128>
1155 [95; 101) '42u128': u128
1156 [108; 112) 'Some': Some<&str>(T) -> Option<T>
1157 [108; 117) 'Some("x")': Option<&str>
1158 [113; 116) '"x"': &str
1159 [123; 135) 'Option::Some': Some<&str>(T) -> Option<T>
1160 [123; 140) 'Option...e("x")': Option<&str>
1161 [136; 139) '"x"': &str
1162 [146; 150) 'None': Option<{unknown}>
1163 [160; 161) 'x': Option<i64>
1164 [177; 181) 'None': Option<i64>
1165 "###
1166 );
1167}
1168
1169#[test]
1170fn infer_function_generics() {
1171 assert_snapshot!(
1172 infer(r#"
1173fn id<T>(t: T) -> T { t }
1174
1175fn test() {
1176 id(1u32);
1177 id::<i128>(1);
1178 let x: u64 = id(1);
1179}
1180"#),
1181 @r###"
1182 [10; 11) 't': T
1183 [21; 26) '{ t }': T
1184 [23; 24) 't': T
1185 [38; 98) '{ ...(1); }': ()
1186 [44; 46) 'id': fn id<u32>(T) -> T
1187 [44; 52) 'id(1u32)': u32
1188 [47; 51) '1u32': u32
1189 [58; 68) 'id::<i128>': fn id<i128>(T) -> T
1190 [58; 71) 'id::<i128>(1)': i128
1191 [69; 70) '1': i128
1192 [81; 82) 'x': u64
1193 [90; 92) 'id': fn id<u64>(T) -> T
1194 [90; 95) 'id(1)': u64
1195 [93; 94) '1': u64
1196 "###
1197 );
1198}
1199
1200#[test]
1201fn infer_impl_generics() {
1202 assert_snapshot!(
1203 infer(r#"
1204struct A<T1, T2> {
1205 x: T1,
1206 y: T2,
1207}
1208impl<Y, X> A<X, Y> {
1209 fn x(self) -> X {
1210 self.x
1211 }
1212 fn y(self) -> Y {
1213 self.y
1214 }
1215 fn z<T>(self, t: T) -> (X, Y, T) {
1216 (self.x, self.y, t)
1217 }
1218}
1219
1220fn test() -> i128 {
1221 let a = A { x: 1u64, y: 1i64 };
1222 a.x();
1223 a.y();
1224 a.z(1i128);
1225 a.z::<u128>(1);
1226}
1227"#),
1228 @r###"
1229 [74; 78) 'self': A<X, Y>
1230 [85; 107) '{ ... }': X
1231 [95; 99) 'self': A<X, Y>
1232 [95; 101) 'self.x': X
1233 [117; 121) 'self': A<X, Y>
1234 [128; 150) '{ ... }': Y
1235 [138; 142) 'self': A<X, Y>
1236 [138; 144) 'self.y': Y
1237 [163; 167) 'self': A<X, Y>
1238 [169; 170) 't': T
1239 [188; 223) '{ ... }': (X, Y, T)
1240 [198; 217) '(self.....y, t)': (X, Y, T)
1241 [199; 203) 'self': A<X, Y>
1242 [199; 205) 'self.x': X
1243 [207; 211) 'self': A<X, Y>
1244 [207; 213) 'self.y': Y
1245 [215; 216) 't': T
1246 [245; 342) '{ ...(1); }': ()
1247 [255; 256) 'a': A<u64, i64>
1248 [259; 281) 'A { x:...1i64 }': A<u64, i64>
1249 [266; 270) '1u64': u64
1250 [275; 279) '1i64': i64
1251 [287; 288) 'a': A<u64, i64>
1252 [287; 292) 'a.x()': u64
1253 [298; 299) 'a': A<u64, i64>
1254 [298; 303) 'a.y()': i64
1255 [309; 310) 'a': A<u64, i64>
1256 [309; 319) 'a.z(1i128)': (u64, i64, i128)
1257 [313; 318) '1i128': i128
1258 [325; 326) 'a': A<u64, i64>
1259 [325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
1260 [337; 338) '1': u128
1261 "###
1262 );
1263}
1264
1265#[test]
1266fn infer_impl_generics_with_autoderef() {
1267 assert_snapshot!(
1268 infer(r#"
1269enum Option<T> {
1270 Some(T),
1271 None,
1272}
1273impl<T> Option<T> {
1274 fn as_ref(&self) -> Option<&T> {}
1275}
1276fn test(o: Option<u32>) {
1277 (&o).as_ref();
1278 o.as_ref();
1279}
1280"#),
1281 @r###"
1282 [78; 82) 'self': &Option<T>
1283 [98; 100) '{}': ()
1284 [111; 112) 'o': Option<u32>
1285 [127; 165) '{ ...f(); }': ()
1286 [133; 146) '(&o).as_ref()': Option<&u32>
1287 [134; 136) '&o': &Option<u32>
1288 [135; 136) 'o': Option<u32>
1289 [152; 153) 'o': Option<u32>
1290 [152; 162) 'o.as_ref()': Option<&u32>
1291 "###
1292 );
1293}
1294
1295#[test]
1296fn infer_generic_chain() {
1297 assert_snapshot!(
1298 infer(r#"
1299struct A<T> {
1300 x: T,
1301}
1302impl<T2> A<T2> {
1303 fn x(self) -> T2 {
1304 self.x
1305 }
1306}
1307fn id<T>(t: T) -> T { t }
1308
1309fn test() -> i128 {
1310 let x = 1;
1311 let y = id(x);
1312 let a = A { x: id(y) };
1313 let z = id(a.x);
1314 let b = A { x: z };
1315 b.x()
1316}
1317"#),
1318 @r###"
1319 [53; 57) 'self': A<T2>
1320 [65; 87) '{ ... }': T2
1321 [75; 79) 'self': A<T2>
1322 [75; 81) 'self.x': T2
1323 [99; 100) 't': T
1324 [110; 115) '{ t }': T
1325 [112; 113) 't': T
1326 [135; 261) '{ ....x() }': i128
1327 [146; 147) 'x': i128
1328 [150; 151) '1': i128
1329 [162; 163) 'y': i128
1330 [166; 168) 'id': fn id<i128>(T) -> T
1331 [166; 171) 'id(x)': i128
1332 [169; 170) 'x': i128
1333 [182; 183) 'a': A<i128>
1334 [186; 200) 'A { x: id(y) }': A<i128>
1335 [193; 195) 'id': fn id<i128>(T) -> T
1336 [193; 198) 'id(y)': i128
1337 [196; 197) 'y': i128
1338 [211; 212) 'z': i128
1339 [215; 217) 'id': fn id<i128>(T) -> T
1340 [215; 222) 'id(a.x)': i128
1341 [218; 219) 'a': A<i128>
1342 [218; 221) 'a.x': i128
1343 [233; 234) 'b': A<i128>
1344 [237; 247) 'A { x: z }': A<i128>
1345 [244; 245) 'z': i128
1346 [254; 255) 'b': A<i128>
1347 [254; 259) 'b.x()': i128
1348 "###
1349 );
1350}
1351
1352#[test]
1353fn infer_associated_const() {
1354 assert_snapshot!(
1355 infer(r#"
1356struct Struct;
1357
1358impl Struct {
1359 const FOO: u32 = 1;
1360}
1361
1362enum Enum {}
1363
1364impl Enum {
1365 const BAR: u32 = 2;
1366}
1367
1368trait Trait {
1369 const ID: u32;
1370}
1371
1372struct TraitTest;
1373
1374impl Trait for TraitTest {
1375 const ID: u32 = 5;
1376}
1377
1378fn test() {
1379 let x = Struct::FOO;
1380 let y = Enum::BAR;
1381 let z = TraitTest::ID;
1382}
1383"#),
1384 @r###"
1385 [52; 53) '1': u32
1386 [105; 106) '2': u32
1387 [213; 214) '5': u32
1388 [229; 307) '{ ...:ID; }': ()
1389 [239; 240) 'x': u32
1390 [243; 254) 'Struct::FOO': u32
1391 [264; 265) 'y': u32
1392 [268; 277) 'Enum::BAR': u32
1393 [287; 288) 'z': u32
1394 [291; 304) 'TraitTest::ID': u32
1395 "###
1396 );
1397}
1398
1399#[test]
1400fn infer_type_alias() {
1401 assert_snapshot!(
1402 infer(r#"
1403struct A<X, Y> { x: X, y: Y }
1404type Foo = A<u32, i128>;
1405type Bar<T> = A<T, u128>;
1406type Baz<U, V> = A<V, U>;
1407fn test(x: Foo, y: Bar<&str>, z: Baz<i8, u8>) {
1408 x.x;
1409 x.y;
1410 y.x;
1411 y.y;
1412 z.x;
1413 z.y;
1414}
1415"#),
1416 @r###"
1417 [116; 117) 'x': A<u32, i128>
1418 [124; 125) 'y': A<&str, u128>
1419 [138; 139) 'z': A<u8, i8>
1420 [154; 211) '{ ...z.y; }': ()
1421 [160; 161) 'x': A<u32, i128>
1422 [160; 163) 'x.x': u32
1423 [169; 170) 'x': A<u32, i128>
1424 [169; 172) 'x.y': i128
1425 [178; 179) 'y': A<&str, u128>
1426 [178; 181) 'y.x': &str
1427 [187; 188) 'y': A<&str, u128>
1428 [187; 190) 'y.y': u128
1429 [196; 197) 'z': A<u8, i8>
1430 [196; 199) 'z.x': u8
1431 [205; 206) 'z': A<u8, i8>
1432 [205; 208) 'z.y': i8
1433 "###
1434 )
1435}
1436
1437#[test]
1438fn recursive_type_alias() {
1439 assert_snapshot!(
1440 infer(r#"
1441struct A<X> {}
1442type Foo = Foo;
1443type Bar = A<Bar>;
1444fn test(x: Foo) {}
1445"#),
1446 @r###"
1447 [59; 60) 'x': {unknown}
1448 [67; 69) '{}': ()
1449 "###
1450 )
1451}
1452
1453#[test]
1454fn infer_type_param() {
1455 assert_snapshot!(
1456 infer(r#"
1457fn id<T>(x: T) -> T {
1458 x
1459}
1460
1461fn clone<T>(x: &T) -> T {
1462 *x
1463}
1464
1465fn test() {
1466 let y = 10u32;
1467 id(y);
1468 let x: bool = clone(z);
1469 id::<i128>(1);
1470}
1471"#),
1472 @r###"
1473 [10; 11) 'x': T
1474 [21; 30) '{ x }': T
1475 [27; 28) 'x': T
1476 [44; 45) 'x': &T
1477 [56; 66) '{ *x }': T
1478 [62; 64) '*x': T
1479 [63; 64) 'x': &T
1480 [78; 158) '{ ...(1); }': ()
1481 [88; 89) 'y': u32
1482 [92; 97) '10u32': u32
1483 [103; 105) 'id': fn id<u32>(T) -> T
1484 [103; 108) 'id(y)': u32
1485 [106; 107) 'y': u32
1486 [118; 119) 'x': bool
1487 [128; 133) 'clone': fn clone<bool>(&T) -> T
1488 [128; 136) 'clone(z)': bool
1489 [134; 135) 'z': &bool
1490 [142; 152) 'id::<i128>': fn id<i128>(T) -> T
1491 [142; 155) 'id::<i128>(1)': i128
1492 [153; 154) '1': i128
1493 "###
1494 );
1495}
1496
1497#[test]
1498fn infer_const() {
1499 assert_snapshot!(
1500 infer(r#"
1501struct Foo;
1502impl Foo { const ASSOC_CONST: u32 = 0; }
1503const GLOBAL_CONST: u32 = 101;
1504fn test() {
1505 const LOCAL_CONST: u32 = 99;
1506 let x = LOCAL_CONST;
1507 let z = GLOBAL_CONST;
1508 let id = Foo::ASSOC_CONST;
1509}
1510"#),
1511 @r###"
1512 [49; 50) '0': u32
1513 [80; 83) '101': u32
1514 [95; 213) '{ ...NST; }': ()
1515 [138; 139) 'x': u32
1516 [142; 153) 'LOCAL_CONST': u32
1517 [163; 164) 'z': u32
1518 [167; 179) 'GLOBAL_CONST': u32
1519 [189; 191) 'id': u32
1520 [194; 210) 'Foo::A..._CONST': u32
1521 "###
1522 );
1523}
1524
1525#[test]
1526fn infer_static() {
1527 assert_snapshot!(
1528 infer(r#"
1529static GLOBAL_STATIC: u32 = 101;
1530static mut GLOBAL_STATIC_MUT: u32 = 101;
1531fn test() {
1532 static LOCAL_STATIC: u32 = 99;
1533 static mut LOCAL_STATIC_MUT: u32 = 99;
1534 let x = LOCAL_STATIC;
1535 let y = LOCAL_STATIC_MUT;
1536 let z = GLOBAL_STATIC;
1537 let w = GLOBAL_STATIC_MUT;
1538}
1539"#),
1540 @r###"
1541 [29; 32) '101': u32
1542 [70; 73) '101': u32
1543 [85; 280) '{ ...MUT; }': ()
1544 [173; 174) 'x': u32
1545 [177; 189) 'LOCAL_STATIC': u32
1546 [199; 200) 'y': u32
1547 [203; 219) 'LOCAL_...IC_MUT': u32
1548 [229; 230) 'z': u32
1549 [233; 246) 'GLOBAL_STATIC': u32
1550 [256; 257) 'w': u32
1551 [260; 277) 'GLOBAL...IC_MUT': u32
1552 "###
1553 );
1554}
1555
1556#[test]
1557fn shadowing_primitive() {
1558 let t = type_at(
1559 r#"
1560//- /main.rs
1561struct i32;
1562struct Foo;
1563
1564impl i32 { fn foo(&self) -> Foo { Foo } }
1565
1566fn main() {
1567 let x: i32 = i32;
1568 x.foo()<|>;
1569}"#,
1570 );
1571 assert_eq!(t, "Foo");
1572}
1573
1574#[test]
1575fn not_shadowing_primitive_by_module() {
1576 let t = type_at(
1577 r#"
1578//- /str.rs
1579fn foo() {}
1580
1581//- /main.rs
1582mod str;
1583fn foo() -> &'static str { "" }
1584
1585fn main() {
1586 foo()<|>;
1587}"#,
1588 );
1589 assert_eq!(t, "&str");
1590}
1591
1592#[test]
1593fn not_shadowing_module_by_primitive() {
1594 let t = type_at(
1595 r#"
1596//- /str.rs
1597fn foo() -> u32 {0}
1598
1599//- /main.rs
1600mod str;
1601fn foo() -> &'static str { "" }
1602
1603fn main() {
1604 str::foo()<|>;
1605}"#,
1606 );
1607 assert_eq!(t, "u32");
1608}
1609
1610#[test]
1611fn closure_return() {
1612 assert_snapshot!(
1613 infer(r#"
1614fn foo() -> u32 {
1615 let x = || -> usize { return 1; };
1616}
1617"#),
1618 @r###"
1619 [17; 59) '{ ...; }; }': ()
1620 [27; 28) 'x': || -> usize
1621 [31; 56) '|| -> ...n 1; }': || -> usize
1622 [43; 56) '{ return 1; }': !
1623 [45; 53) 'return 1': !
1624 [52; 53) '1': usize
1625 "###
1626 );
1627}
1628
1629#[test]
1630fn closure_return_unit() {
1631 assert_snapshot!(
1632 infer(r#"
1633fn foo() -> u32 {
1634 let x = || { return; };
1635}
1636"#),
1637 @r###"
1638 [17; 48) '{ ...; }; }': ()
1639 [27; 28) 'x': || -> ()
1640 [31; 45) '|| { return; }': || -> ()
1641 [34; 45) '{ return; }': !
1642 [36; 42) 'return': !
1643 "###
1644 );
1645}
1646
1647#[test]
1648fn closure_return_inferred() {
1649 assert_snapshot!(
1650 infer(r#"
1651fn foo() -> u32 {
1652 let x = || { "test" };
1653}
1654"#),
1655 @r###"
1656 [17; 47) '{ ..." }; }': ()
1657 [27; 28) 'x': || -> &str
1658 [31; 44) '|| { "test" }': || -> &str
1659 [34; 44) '{ "test" }': &str
1660 [36; 42) '"test"': &str
1661 "###
1662 );
1663}
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs
new file mode 100644
index 000000000..ae316922b
--- /dev/null
+++ b/crates/ra_hir_ty/src/tests/traits.rs
@@ -0,0 +1,1598 @@
1use insta::assert_snapshot;
2
3use ra_db::fixture::WithFixture;
4use test_utils::covers;
5
6use super::{infer, infer_with_mismatches, type_at, type_at_pos};
7use crate::test_db::TestDB;
8
9#[test]
10fn infer_await() {
11 let (db, pos) = TestDB::with_position(
12 r#"
13//- /main.rs crate:main deps:std
14
15struct IntFuture;
16
17impl Future for IntFuture {
18 type Output = u64;
19}
20
21fn test() {
22 let r = IntFuture;
23 let v = r.await;
24 v<|>;
25}
26
27//- /std.rs crate:std
28#[prelude_import] use future::*;
29mod future {
30 trait Future {
31 type Output;
32 }
33}
34
35"#,
36 );
37 assert_eq!("u64", type_at_pos(&db, pos));
38}
39
40#[test]
41fn infer_try() {
42 let (db, pos) = TestDB::with_position(
43 r#"
44//- /main.rs crate:main deps:std
45
46fn test() {
47 let r: Result<i32, u64> = Result::Ok(1);
48 let v = r?;
49 v<|>;
50}
51
52//- /std.rs crate:std
53
54#[prelude_import] use ops::*;
55mod ops {
56 trait Try {
57 type Ok;
58 type Error;
59 }
60}
61
62#[prelude_import] use result::*;
63mod result {
64 enum Result<O, E> {
65 Ok(O),
66 Err(E)
67 }
68
69 impl<O, E> crate::ops::Try for Result<O, E> {
70 type Ok = O;
71 type Error = E;
72 }
73}
74
75"#,
76 );
77 assert_eq!("i32", type_at_pos(&db, pos));
78}
79
80#[test]
81fn infer_for_loop() {
82 let (db, pos) = TestDB::with_position(
83 r#"
84//- /main.rs crate:main deps:std
85
86use std::collections::Vec;
87
88fn test() {
89 let v = Vec::new();
90 v.push("foo");
91 for x in v {
92 x<|>;
93 }
94}
95
96//- /std.rs crate:std
97
98#[prelude_import] use iter::*;
99mod iter {
100 trait IntoIterator {
101 type Item;
102 }
103}
104
105mod collections {
106 struct Vec<T> {}
107 impl<T> Vec<T> {
108 fn new() -> Self { Vec {} }
109 fn push(&mut self, t: T) { }
110 }
111
112 impl<T> crate::iter::IntoIterator for Vec<T> {
113 type Item=T;
114 }
115}
116"#,
117 );
118 assert_eq!("&str", type_at_pos(&db, pos));
119}
120
121#[test]
122fn infer_ops_neg() {
123 let (db, pos) = TestDB::with_position(
124 r#"
125//- /main.rs crate:main deps:std
126
127struct Bar;
128struct Foo;
129
130impl std::ops::Neg for Bar {
131 type Output = Foo;
132}
133
134fn test() {
135 let a = Bar;
136 let b = -a;
137 b<|>;
138}
139
140//- /std.rs crate:std
141
142#[prelude_import] use ops::*;
143mod ops {
144 pub trait Neg {
145 type Output;
146 }
147}
148"#,
149 );
150 assert_eq!("Foo", type_at_pos(&db, pos));
151}
152
153#[test]
154fn infer_ops_not() {
155 let (db, pos) = TestDB::with_position(
156 r#"
157//- /main.rs crate:main deps:std
158
159struct Bar;
160struct Foo;
161
162impl std::ops::Not for Bar {
163 type Output = Foo;
164}
165
166fn test() {
167 let a = Bar;
168 let b = !a;
169 b<|>;
170}
171
172//- /std.rs crate:std
173
174#[prelude_import] use ops::*;
175mod ops {
176 pub trait Not {
177 type Output;
178 }
179}
180"#,
181 );
182 assert_eq!("Foo", type_at_pos(&db, pos));
183}
184
185#[test]
186fn infer_from_bound_1() {
187 assert_snapshot!(
188 infer(r#"
189trait Trait<T> {}
190struct S<T>(T);
191impl<U> Trait<U> for S<U> {}
192fn foo<T: Trait<u32>>(t: T) {}
193fn test() {
194 let s = S(unknown);
195 foo(s);
196}
197"#),
198 @r###"
199 [86; 87) 't': T
200 [92; 94) '{}': ()
201 [105; 144) '{ ...(s); }': ()
202 [115; 116) 's': S<u32>
203 [119; 120) 'S': S<u32>(T) -> S<T>
204 [119; 129) 'S(unknown)': S<u32>
205 [121; 128) 'unknown': u32
206 [135; 138) 'foo': fn foo<S<u32>>(T) -> ()
207 [135; 141) 'foo(s)': ()
208 [139; 140) 's': S<u32>
209 "###
210 );
211}
212
213#[test]
214fn infer_from_bound_2() {
215 assert_snapshot!(
216 infer(r#"
217trait Trait<T> {}
218struct S<T>(T);
219impl<U> Trait<U> for S<U> {}
220fn foo<U, T: Trait<U>>(t: T) -> U {}
221fn test() {
222 let s = S(unknown);
223 let x: u32 = foo(s);
224}
225"#),
226 @r###"
227 [87; 88) 't': T
228 [98; 100) '{}': ()
229 [111; 163) '{ ...(s); }': ()
230 [121; 122) 's': S<u32>
231 [125; 126) 'S': S<u32>(T) -> S<T>
232 [125; 135) 'S(unknown)': S<u32>
233 [127; 134) 'unknown': u32
234 [145; 146) 'x': u32
235 [154; 157) 'foo': fn foo<u32, S<u32>>(T) -> U
236 [154; 160) 'foo(s)': u32
237 [158; 159) 's': S<u32>
238 "###
239 );
240}
241
242#[test]
243fn infer_project_associated_type() {
244 // y, z, a don't yet work because of https://github.com/rust-lang/chalk/issues/234
245 assert_snapshot!(
246 infer(r#"
247trait Iterable {
248 type Item;
249}
250struct S;
251impl Iterable for S { type Item = u32; }
252fn test<T: Iterable>() {
253 let x: <S as Iterable>::Item = 1;
254 let y: <T as Iterable>::Item = no_matter;
255 let z: T::Item = no_matter;
256 let a: <T>::Item = no_matter;
257}
258"#),
259 @r###"
260 [108; 261) '{ ...ter; }': ()
261 [118; 119) 'x': u32
262 [145; 146) '1': u32
263 [156; 157) 'y': {unknown}
264 [183; 192) 'no_matter': {unknown}
265 [202; 203) 'z': {unknown}
266 [215; 224) 'no_matter': {unknown}
267 [234; 235) 'a': {unknown}
268 [249; 258) 'no_matter': {unknown}
269 "###
270 );
271}
272
273#[test]
274fn infer_return_associated_type() {
275 assert_snapshot!(
276 infer(r#"
277trait Iterable {
278 type Item;
279}
280struct S;
281impl Iterable for S { type Item = u32; }
282fn foo1<T: Iterable>(t: T) -> T::Item {}
283fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
284fn foo3<T: Iterable>(t: T) -> <T>::Item {}
285fn test() {
286 let x = foo1(S);
287 let y = foo2(S);
288 let z = foo3(S);
289}
290"#),
291 @r###"
292 [106; 107) 't': T
293 [123; 125) '{}': ()
294 [147; 148) 't': T
295 [178; 180) '{}': ()
296 [202; 203) 't': T
297 [221; 223) '{}': ()
298 [234; 300) '{ ...(S); }': ()
299 [244; 245) 'x': u32
300 [248; 252) 'foo1': fn foo1<S>(T) -> <T as Iterable>::Item
301 [248; 255) 'foo1(S)': u32
302 [253; 254) 'S': S
303 [265; 266) 'y': u32
304 [269; 273) 'foo2': fn foo2<S>(T) -> <T as Iterable>::Item
305 [269; 276) 'foo2(S)': u32
306 [274; 275) 'S': S
307 [286; 287) 'z': u32
308 [290; 294) 'foo3': fn foo3<S>(T) -> <T as Iterable>::Item
309 [290; 297) 'foo3(S)': u32
310 [295; 296) 'S': S
311 "###
312 );
313}
314
315#[test]
316fn infer_associated_type_bound() {
317 assert_snapshot!(
318 infer(r#"
319trait Iterable {
320 type Item;
321}
322fn test<T: Iterable<Item=u32>>() {
323 let y: T::Item = unknown;
324}
325"#),
326 @r###"
327 [67; 100) '{ ...own; }': ()
328 [77; 78) 'y': {unknown}
329 [90; 97) 'unknown': {unknown}
330 "###
331 );
332}
333
334#[test]
335fn infer_const_body() {
336 assert_snapshot!(
337 infer(r#"
338const A: u32 = 1 + 1;
339static B: u64 = { let x = 1; x };
340"#),
341 @r###"
342 [16; 17) '1': u32
343 [16; 21) '1 + 1': u32
344 [20; 21) '1': u32
345 [39; 55) '{ let ...1; x }': u64
346 [45; 46) 'x': u64
347 [49; 50) '1': u64
348 [52; 53) 'x': u64
349 "###
350 );
351}
352
353#[test]
354fn tuple_struct_fields() {
355 assert_snapshot!(
356 infer(r#"
357struct S(i32, u64);
358fn test() -> u64 {
359 let a = S(4, 6);
360 let b = a.0;
361 a.1
362}
363"#),
364 @r###"
365 [38; 87) '{ ... a.1 }': u64
366 [48; 49) 'a': S
367 [52; 53) 'S': S(i32, u64) -> S
368 [52; 59) 'S(4, 6)': S
369 [54; 55) '4': i32
370 [57; 58) '6': u64
371 [69; 70) 'b': i32
372 [73; 74) 'a': S
373 [73; 76) 'a.0': i32
374 [82; 83) 'a': S
375 [82; 85) 'a.1': u64
376 "###
377 );
378}
379
380#[test]
381fn tuple_struct_with_fn() {
382 assert_snapshot!(
383 infer(r#"
384struct S(fn(u32) -> u64);
385fn test() -> u64 {
386 let a = S(|i| 2*i);
387 let b = a.0(4);
388 a.0(2)
389}
390"#),
391 @r###"
392 [44; 102) '{ ...0(2) }': u64
393 [54; 55) 'a': S
394 [58; 59) 'S': S(fn(u32) -> u64) -> S
395 [58; 68) 'S(|i| 2*i)': S
396 [60; 67) '|i| 2*i': |u32| -> u64
397 [61; 62) 'i': u32
398 [64; 65) '2': u32
399 [64; 67) '2*i': u32
400 [66; 67) 'i': u32
401 [78; 79) 'b': u64
402 [82; 83) 'a': S
403 [82; 85) 'a.0': fn(u32) -> u64
404 [82; 88) 'a.0(4)': u64
405 [86; 87) '4': u32
406 [94; 95) 'a': S
407 [94; 97) 'a.0': fn(u32) -> u64
408 [94; 100) 'a.0(2)': u64
409 [98; 99) '2': u32
410 "###
411 );
412}
413
414#[test]
415fn indexing_arrays() {
416 assert_snapshot!(
417 infer("fn main() { &mut [9][2]; }"),
418 @r###"
419 [10; 26) '{ &mut...[2]; }': ()
420 [12; 23) '&mut [9][2]': &mut {unknown}
421 [17; 20) '[9]': [i32;_]
422 [17; 23) '[9][2]': {unknown}
423 [18; 19) '9': i32
424 [21; 22) '2': i32
425 "###
426 )
427}
428
429#[test]
430fn infer_ops_index() {
431 let (db, pos) = TestDB::with_position(
432 r#"
433//- /main.rs crate:main deps:std
434
435struct Bar;
436struct Foo;
437
438impl std::ops::Index<u32> for Bar {
439 type Output = Foo;
440}
441
442fn test() {
443 let a = Bar;
444 let b = a[1];
445 b<|>;
446}
447
448//- /std.rs crate:std
449
450#[prelude_import] use ops::*;
451mod ops {
452 pub trait Index<Idx> {
453 type Output;
454 }
455}
456"#,
457 );
458 assert_eq!("Foo", type_at_pos(&db, pos));
459}
460
461#[test]
462fn deref_trait() {
463 let t = type_at(
464 r#"
465//- /main.rs
466#[lang = "deref"]
467trait Deref {
468 type Target;
469 fn deref(&self) -> &Self::Target;
470}
471
472struct Arc<T>;
473impl<T> Deref for Arc<T> {
474 type Target = T;
475}
476
477struct S;
478impl S {
479 fn foo(&self) -> u128 {}
480}
481
482fn test(s: Arc<S>) {
483 (*s, s.foo())<|>;
484}
485"#,
486 );
487 assert_eq!(t, "(S, u128)");
488}
489
490#[test]
491fn deref_trait_with_inference_var() {
492 let t = type_at(
493 r#"
494//- /main.rs
495#[lang = "deref"]
496trait Deref {
497 type Target;
498 fn deref(&self) -> &Self::Target;
499}
500
501struct Arc<T>;
502fn new_arc<T>() -> Arc<T> {}
503impl<T> Deref for Arc<T> {
504 type Target = T;
505}
506
507struct S;
508fn foo(a: Arc<S>) {}
509
510fn test() {
511 let a = new_arc();
512 let b = (*a)<|>;
513 foo(a);
514}
515"#,
516 );
517 assert_eq!(t, "S");
518}
519
520#[test]
521fn deref_trait_infinite_recursion() {
522 let t = type_at(
523 r#"
524//- /main.rs
525#[lang = "deref"]
526trait Deref {
527 type Target;
528 fn deref(&self) -> &Self::Target;
529}
530
531struct S;
532
533impl Deref for S {
534 type Target = S;
535}
536
537fn test(s: S) {
538 s.foo()<|>;
539}
540"#,
541 );
542 assert_eq!(t, "{unknown}");
543}
544
545#[test]
546fn deref_trait_with_question_mark_size() {
547 let t = type_at(
548 r#"
549//- /main.rs
550#[lang = "deref"]
551trait Deref {
552 type Target;
553 fn deref(&self) -> &Self::Target;
554}
555
556struct Arc<T>;
557impl<T> Deref for Arc<T> {
558 type Target = T;
559}
560
561struct S;
562impl S {
563 fn foo(&self) -> u128 {}
564}
565
566fn test(s: Arc<S>) {
567 (*s, s.foo())<|>;
568}
569"#,
570 );
571 assert_eq!(t, "(S, u128)");
572}
573
574#[test]
575fn obligation_from_function_clause() {
576 let t = type_at(
577 r#"
578//- /main.rs
579struct S;
580
581trait Trait<T> {}
582impl Trait<u32> for S {}
583
584fn foo<T: Trait<U>, U>(t: T) -> U {}
585
586fn test(s: S) {
587 foo(s)<|>;
588}
589"#,
590 );
591 assert_eq!(t, "u32");
592}
593
594#[test]
595fn obligation_from_method_clause() {
596 let t = type_at(
597 r#"
598//- /main.rs
599struct S;
600
601trait Trait<T> {}
602impl Trait<isize> for S {}
603
604struct O;
605impl O {
606 fn foo<T: Trait<U>, U>(&self, t: T) -> U {}
607}
608
609fn test() {
610 O.foo(S)<|>;
611}
612"#,
613 );
614 assert_eq!(t, "isize");
615}
616
617#[test]
618fn obligation_from_self_method_clause() {
619 let t = type_at(
620 r#"
621//- /main.rs
622struct S;
623
624trait Trait<T> {}
625impl Trait<i64> for S {}
626
627impl S {
628 fn foo<U>(&self) -> U where Self: Trait<U> {}
629}
630
631fn test() {
632 S.foo()<|>;
633}
634"#,
635 );
636 assert_eq!(t, "i64");
637}
638
639#[test]
640fn obligation_from_impl_clause() {
641 let t = type_at(
642 r#"
643//- /main.rs
644struct S;
645
646trait Trait<T> {}
647impl Trait<&str> for S {}
648
649struct O<T>;
650impl<U, T: Trait<U>> O<T> {
651 fn foo(&self) -> U {}
652}
653
654fn test(o: O<S>) {
655 o.foo()<|>;
656}
657"#,
658 );
659 assert_eq!(t, "&str");
660}
661
662#[test]
663fn generic_param_env_1() {
664 let t = type_at(
665 r#"
666//- /main.rs
667trait Clone {}
668trait Trait { fn foo(self) -> u128; }
669struct S;
670impl Clone for S {}
671impl<T> Trait for T where T: Clone {}
672fn test<T: Clone>(t: T) { t.foo()<|>; }
673"#,
674 );
675 assert_eq!(t, "u128");
676}
677
678#[test]
679fn generic_param_env_1_not_met() {
680 let t = type_at(
681 r#"
682//- /main.rs
683trait Clone {}
684trait Trait { fn foo(self) -> u128; }
685struct S;
686impl Clone for S {}
687impl<T> Trait for T where T: Clone {}
688fn test<T>(t: T) { t.foo()<|>; }
689"#,
690 );
691 assert_eq!(t, "{unknown}");
692}
693
694#[test]
695fn generic_param_env_2() {
696 let t = type_at(
697 r#"
698//- /main.rs
699trait Trait { fn foo(self) -> u128; }
700struct S;
701impl Trait for S {}
702fn test<T: Trait>(t: T) { t.foo()<|>; }
703"#,
704 );
705 assert_eq!(t, "u128");
706}
707
708#[test]
709fn generic_param_env_2_not_met() {
710 let t = type_at(
711 r#"
712//- /main.rs
713trait Trait { fn foo(self) -> u128; }
714struct S;
715impl Trait for S {}
716fn test<T>(t: T) { t.foo()<|>; }
717"#,
718 );
719 assert_eq!(t, "{unknown}");
720}
721
722#[test]
723fn generic_param_env_deref() {
724 let t = type_at(
725 r#"
726//- /main.rs
727#[lang = "deref"]
728trait Deref {
729 type Target;
730}
731trait Trait {}
732impl<T> Deref for T where T: Trait {
733 type Target = i128;
734}
735fn test<T: Trait>(t: T) { (*t)<|>; }
736"#,
737 );
738 assert_eq!(t, "i128");
739}
740
741#[test]
742fn associated_type_placeholder() {
743 let t = type_at(
744 r#"
745//- /main.rs
746pub trait ApplyL {
747 type Out;
748}
749
750pub struct RefMutL<T>;
751
752impl<T> ApplyL for RefMutL<T> {
753 type Out = <T as ApplyL>::Out;
754}
755
756fn test<T: ApplyL>() {
757 let y: <RefMutL<T> as ApplyL>::Out = no_matter;
758 y<|>;
759}
760"#,
761 );
762 // inside the generic function, the associated type gets normalized to a placeholder `ApplL::Out<T>` [https://rust-lang.github.io/rustc-guide/traits/associated-types.html#placeholder-associated-types].
763 // FIXME: fix type parameter names going missing when going through Chalk
764 assert_eq!(t, "ApplyL::Out<[missing name]>");
765}
766
767#[test]
768fn associated_type_placeholder_2() {
769 let t = type_at(
770 r#"
771//- /main.rs
772pub trait ApplyL {
773 type Out;
774}
775fn foo<T: ApplyL>(t: T) -> <T as ApplyL>::Out;
776
777fn test<T: ApplyL>(t: T) {
778 let y = foo(t);
779 y<|>;
780}
781"#,
782 );
783 // FIXME here Chalk doesn't normalize the type to a placeholder. I think we
784 // need to add a rule like Normalize(<T as ApplyL>::Out -> ApplyL::Out<T>)
785 // to the trait env ourselves here; probably Chalk can't do this by itself.
786 // assert_eq!(t, "ApplyL::Out<[missing name]>");
787 assert_eq!(t, "{unknown}");
788}
789
790#[test]
791fn impl_trait() {
792 assert_snapshot!(
793 infer(r#"
794trait Trait<T> {
795 fn foo(&self) -> T;
796 fn foo2(&self) -> i64;
797}
798fn bar() -> impl Trait<u64> {}
799
800fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
801 x;
802 y;
803 let z = bar();
804 x.foo();
805 y.foo();
806 z.foo();
807 x.foo2();
808 y.foo2();
809 z.foo2();
810}
811"#),
812 @r###"
813 [30; 34) 'self': &Self
814 [55; 59) 'self': &Self
815 [99; 101) '{}': ()
816 [111; 112) 'x': impl Trait<u64>
817 [131; 132) 'y': &impl Trait<u64>
818 [152; 269) '{ ...2(); }': ()
819 [158; 159) 'x': impl Trait<u64>
820 [165; 166) 'y': &impl Trait<u64>
821 [176; 177) 'z': impl Trait<u64>
822 [180; 183) 'bar': fn bar() -> impl Trait<u64>
823 [180; 185) 'bar()': impl Trait<u64>
824 [191; 192) 'x': impl Trait<u64>
825 [191; 198) 'x.foo()': u64
826 [204; 205) 'y': &impl Trait<u64>
827 [204; 211) 'y.foo()': u64
828 [217; 218) 'z': impl Trait<u64>
829 [217; 224) 'z.foo()': u64
830 [230; 231) 'x': impl Trait<u64>
831 [230; 238) 'x.foo2()': i64
832 [244; 245) 'y': &impl Trait<u64>
833 [244; 252) 'y.foo2()': i64
834 [258; 259) 'z': impl Trait<u64>
835 [258; 266) 'z.foo2()': i64
836 "###
837 );
838}
839
840#[test]
841fn dyn_trait() {
842 assert_snapshot!(
843 infer(r#"
844trait Trait<T> {
845 fn foo(&self) -> T;
846 fn foo2(&self) -> i64;
847}
848fn bar() -> dyn Trait<u64> {}
849
850fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
851 x;
852 y;
853 let z = bar();
854 x.foo();
855 y.foo();
856 z.foo();
857 x.foo2();
858 y.foo2();
859 z.foo2();
860}
861"#),
862 @r###"
863 [30; 34) 'self': &Self
864 [55; 59) 'self': &Self
865 [98; 100) '{}': ()
866 [110; 111) 'x': dyn Trait<u64>
867 [129; 130) 'y': &dyn Trait<u64>
868 [149; 266) '{ ...2(); }': ()
869 [155; 156) 'x': dyn Trait<u64>
870 [162; 163) 'y': &dyn Trait<u64>
871 [173; 174) 'z': dyn Trait<u64>
872 [177; 180) 'bar': fn bar() -> dyn Trait<u64>
873 [177; 182) 'bar()': dyn Trait<u64>
874 [188; 189) 'x': dyn Trait<u64>
875 [188; 195) 'x.foo()': u64
876 [201; 202) 'y': &dyn Trait<u64>
877 [201; 208) 'y.foo()': u64
878 [214; 215) 'z': dyn Trait<u64>
879 [214; 221) 'z.foo()': u64
880 [227; 228) 'x': dyn Trait<u64>
881 [227; 235) 'x.foo2()': i64
882 [241; 242) 'y': &dyn Trait<u64>
883 [241; 249) 'y.foo2()': i64
884 [255; 256) 'z': dyn Trait<u64>
885 [255; 263) 'z.foo2()': i64
886 "###
887 );
888}
889
890#[test]
891fn dyn_trait_bare() {
892 assert_snapshot!(
893 infer(r#"
894trait Trait {
895 fn foo(&self) -> u64;
896}
897fn bar() -> Trait {}
898
899fn test(x: Trait, y: &Trait) -> u64 {
900 x;
901 y;
902 let z = bar();
903 x.foo();
904 y.foo();
905 z.foo();
906}
907"#),
908 @r###"
909 [27; 31) 'self': &Self
910 [61; 63) '{}': ()
911 [73; 74) 'x': dyn Trait
912 [83; 84) 'y': &dyn Trait
913 [101; 176) '{ ...o(); }': ()
914 [107; 108) 'x': dyn Trait
915 [114; 115) 'y': &dyn Trait
916 [125; 126) 'z': dyn Trait
917 [129; 132) 'bar': fn bar() -> dyn Trait
918 [129; 134) 'bar()': dyn Trait
919 [140; 141) 'x': dyn Trait
920 [140; 147) 'x.foo()': u64
921 [153; 154) 'y': &dyn Trait
922 [153; 160) 'y.foo()': u64
923 [166; 167) 'z': dyn Trait
924 [166; 173) 'z.foo()': u64
925 "###
926 );
927}
928
929#[test]
930fn weird_bounds() {
931 assert_snapshot!(
932 infer(r#"
933trait Trait {}
934fn test() {
935 let a: impl Trait + 'lifetime = foo;
936 let b: impl 'lifetime = foo;
937 let b: impl (Trait) = foo;
938 let b: impl ('lifetime) = foo;
939 let d: impl ?Sized = foo;
940 let e: impl Trait + ?Sized = foo;
941}
942"#),
943 @r###"
944 [26; 237) '{ ...foo; }': ()
945 [36; 37) 'a': impl Trait + {error}
946 [64; 67) 'foo': impl Trait + {error}
947 [77; 78) 'b': impl {error}
948 [97; 100) 'foo': impl {error}
949 [110; 111) 'b': impl Trait
950 [128; 131) 'foo': impl Trait
951 [141; 142) 'b': impl {error}
952 [163; 166) 'foo': impl {error}
953 [176; 177) 'd': impl {error}
954 [193; 196) 'foo': impl {error}
955 [206; 207) 'e': impl Trait + {error}
956 [231; 234) 'foo': impl Trait + {error}
957 "###
958 );
959}
960
961#[test]
962fn error_bound_chalk() {
963 let t = type_at(
964 r#"
965//- /main.rs
966trait Trait {
967 fn foo(&self) -> u32 {}
968}
969
970fn test(x: (impl Trait + UnknownTrait)) {
971 x.foo()<|>;
972}
973"#,
974 );
975 assert_eq!(t, "u32");
976}
977
978#[test]
979fn assoc_type_bindings() {
980 assert_snapshot!(
981 infer(r#"
982trait Trait {
983 type Type;
984}
985
986fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
987fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
988fn set<T: Trait<Type = u64>>(t: T) -> T {t}
989
990struct S<T>;
991impl<T> Trait for S<T> { type Type = T; }
992
993fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
994 get(x);
995 get2(x);
996 get(y);
997 get2(y);
998 get(set(S));
999 get2(set(S));
1000 get2(S::<str>);
1001}
1002"#),
1003 @r###"
1004 [50; 51) 't': T
1005 [78; 80) '{}': ()
1006 [112; 113) 't': T
1007 [123; 125) '{}': ()
1008 [155; 156) 't': T
1009 [166; 169) '{t}': T
1010 [167; 168) 't': T
1011 [257; 258) 'x': T
1012 [263; 264) 'y': impl Trait<Type = i64>
1013 [290; 398) '{ ...r>); }': ()
1014 [296; 299) 'get': fn get<T>(T) -> <T as Trait>::Type
1015 [296; 302) 'get(x)': {unknown}
1016 [300; 301) 'x': T
1017 [308; 312) 'get2': fn get2<{unknown}, T>(T) -> U
1018 [308; 315) 'get2(x)': {unknown}
1019 [313; 314) 'x': T
1020 [321; 324) 'get': fn get<impl Trait<Type = i64>>(T) -> <T as Trait>::Type
1021 [321; 327) 'get(y)': {unknown}
1022 [325; 326) 'y': impl Trait<Type = i64>
1023 [333; 337) 'get2': fn get2<{unknown}, impl Trait<Type = i64>>(T) -> U
1024 [333; 340) 'get2(y)': {unknown}
1025 [338; 339) 'y': impl Trait<Type = i64>
1026 [346; 349) 'get': fn get<S<u64>>(T) -> <T as Trait>::Type
1027 [346; 357) 'get(set(S))': u64
1028 [350; 353) 'set': fn set<S<u64>>(T) -> T
1029 [350; 356) 'set(S)': S<u64>
1030 [354; 355) 'S': S<u64>
1031 [363; 367) 'get2': fn get2<u64, S<u64>>(T) -> U
1032 [363; 375) 'get2(set(S))': u64
1033 [368; 371) 'set': fn set<S<u64>>(T) -> T
1034 [368; 374) 'set(S)': S<u64>
1035 [372; 373) 'S': S<u64>
1036 [381; 385) 'get2': fn get2<str, S<str>>(T) -> U
1037 [381; 395) 'get2(S::<str>)': str
1038 [386; 394) 'S::<str>': S<str>
1039 "###
1040 );
1041}
1042
1043#[test]
1044fn impl_trait_assoc_binding_projection_bug() {
1045 let (db, pos) = TestDB::with_position(
1046 r#"
1047//- /main.rs crate:main deps:std
1048pub trait Language {
1049 type Kind;
1050}
1051pub enum RustLanguage {}
1052impl Language for RustLanguage {
1053 type Kind = SyntaxKind;
1054}
1055struct SyntaxNode<L> {}
1056fn foo() -> impl Iterator<Item = SyntaxNode<RustLanguage>> {}
1057
1058trait Clone {
1059 fn clone(&self) -> Self;
1060}
1061
1062fn api_walkthrough() {
1063 for node in foo() {
1064 node.clone()<|>;
1065 }
1066}
1067
1068//- /std.rs crate:std
1069#[prelude_import] use iter::*;
1070mod iter {
1071 trait IntoIterator {
1072 type Item;
1073 }
1074 trait Iterator {
1075 type Item;
1076 }
1077 impl<T: Iterator> IntoIterator for T {
1078 type Item = <T as Iterator>::Item;
1079 }
1080}
1081"#,
1082 );
1083 assert_eq!("{unknown}", type_at_pos(&db, pos));
1084}
1085
1086#[test]
1087fn projection_eq_within_chalk() {
1088 // std::env::set_var("CHALK_DEBUG", "1");
1089 assert_snapshot!(
1090 infer(r#"
1091trait Trait1 {
1092 type Type;
1093}
1094trait Trait2<T> {
1095 fn foo(self) -> T;
1096}
1097impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
1098
1099fn test<T: Trait1<Type = u32>>(x: T) {
1100 x.foo();
1101}
1102"#),
1103 @r###"
1104 [62; 66) 'self': Self
1105 [164; 165) 'x': T
1106 [170; 186) '{ ...o(); }': ()
1107 [176; 177) 'x': T
1108 [176; 183) 'x.foo()': {unknown}
1109 "###
1110 );
1111}
1112
1113#[test]
1114fn where_clause_trait_in_scope_for_method_resolution() {
1115 let t = type_at(
1116 r#"
1117//- /main.rs
1118mod foo {
1119 trait Trait {
1120 fn foo(&self) -> u32 {}
1121 }
1122}
1123
1124fn test<T: foo::Trait>(x: T) {
1125 x.foo()<|>;
1126}
1127"#,
1128 );
1129 assert_eq!(t, "u32");
1130}
1131
1132#[test]
1133fn super_trait_method_resolution() {
1134 assert_snapshot!(
1135 infer(r#"
1136mod foo {
1137 trait SuperTrait {
1138 fn foo(&self) -> u32 {}
1139 }
1140}
1141trait Trait1: foo::SuperTrait {}
1142trait Trait2 where Self: foo::SuperTrait {}
1143
1144fn test<T: Trait1, U: Trait2>(x: T, y: U) {
1145 x.foo();
1146 y.foo();
1147}
1148"#),
1149 @r###"
1150 [50; 54) 'self': &Self
1151 [63; 65) '{}': ()
1152 [182; 183) 'x': T
1153 [188; 189) 'y': U
1154 [194; 223) '{ ...o(); }': ()
1155 [200; 201) 'x': T
1156 [200; 207) 'x.foo()': u32
1157 [213; 214) 'y': U
1158 [213; 220) 'y.foo()': u32
1159 "###
1160 );
1161}
1162
1163#[test]
1164fn super_trait_cycle() {
1165 // This just needs to not crash
1166 assert_snapshot!(
1167 infer(r#"
1168trait A: B {}
1169trait B: A {}
1170
1171fn test<T: A>(x: T) {
1172 x.foo();
1173}
1174"#),
1175 @r###"
1176 [44; 45) 'x': T
1177 [50; 66) '{ ...o(); }': ()
1178 [56; 57) 'x': T
1179 [56; 63) 'x.foo()': {unknown}
1180 "###
1181 );
1182}
1183
1184#[test]
1185fn super_trait_assoc_type_bounds() {
1186 assert_snapshot!(
1187 infer(r#"
1188trait SuperTrait { type Type; }
1189trait Trait where Self: SuperTrait {}
1190
1191fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1192fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1193
1194struct S<T>;
1195impl<T> SuperTrait for S<T> { type Type = T; }
1196impl<T> Trait for S<T> {}
1197
1198fn test() {
1199 get2(set(S));
1200}
1201"#),
1202 @r###"
1203 [103; 104) 't': T
1204 [114; 116) '{}': ()
1205 [146; 147) 't': T
1206 [157; 160) '{t}': T
1207 [158; 159) 't': T
1208 [259; 280) '{ ...S)); }': ()
1209 [265; 269) 'get2': fn get2<u64, S<u64>>(T) -> U
1210 [265; 277) 'get2(set(S))': u64
1211 [270; 273) 'set': fn set<S<u64>>(T) -> T
1212 [270; 276) 'set(S)': S<u64>
1213 [274; 275) 'S': S<u64>
1214 "###
1215 );
1216}
1217
1218#[test]
1219fn fn_trait() {
1220 assert_snapshot!(
1221 infer(r#"
1222trait FnOnce<Args> {
1223 type Output;
1224
1225 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
1226}
1227
1228fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1229 f.call_once((1, 2));
1230}
1231"#),
1232 @r###"
1233 [57; 61) 'self': Self
1234 [63; 67) 'args': Args
1235 [150; 151) 'f': F
1236 [156; 184) '{ ...2)); }': ()
1237 [162; 163) 'f': F
1238 [162; 181) 'f.call...1, 2))': {unknown}
1239 [174; 180) '(1, 2)': (u32, u64)
1240 [175; 176) '1': u32
1241 [178; 179) '2': u64
1242 "###
1243 );
1244}
1245
1246#[test]
1247fn closure_1() {
1248 assert_snapshot!(
1249 infer(r#"
1250#[lang = "fn_once"]
1251trait FnOnce<Args> {
1252 type Output;
1253}
1254
1255enum Option<T> { Some(T), None }
1256impl<T> Option<T> {
1257 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> {}
1258}
1259
1260fn test() {
1261 let x = Option::Some(1u32);
1262 x.map(|v| v + 1);
1263 x.map(|_v| 1u64);
1264 let y: Option<i64> = x.map(|_v| 1);
1265}
1266"#),
1267 @r###"
1268 [148; 152) 'self': Option<T>
1269 [154; 155) 'f': F
1270 [173; 175) '{}': ()
1271 [189; 308) '{ ... 1); }': ()
1272 [199; 200) 'x': Option<u32>
1273 [203; 215) 'Option::Some': Some<u32>(T) -> Option<T>
1274 [203; 221) 'Option...(1u32)': Option<u32>
1275 [216; 220) '1u32': u32
1276 [227; 228) 'x': Option<u32>
1277 [227; 243) 'x.map(...v + 1)': Option<u32>
1278 [233; 242) '|v| v + 1': |u32| -> u32
1279 [234; 235) 'v': u32
1280 [237; 238) 'v': u32
1281 [237; 242) 'v + 1': u32
1282 [241; 242) '1': u32
1283 [249; 250) 'x': Option<u32>
1284 [249; 265) 'x.map(... 1u64)': Option<u64>
1285 [255; 264) '|_v| 1u64': |u32| -> u64
1286 [256; 258) '_v': u32
1287 [260; 264) '1u64': u64
1288 [275; 276) 'y': Option<i64>
1289 [292; 293) 'x': Option<u32>
1290 [292; 305) 'x.map(|_v| 1)': Option<i64>
1291 [298; 304) '|_v| 1': |u32| -> i64
1292 [299; 301) '_v': u32
1293 [303; 304) '1': i64
1294 "###
1295 );
1296}
1297
1298#[test]
1299fn closure_2() {
1300 assert_snapshot!(
1301 infer(r#"
1302trait FnOnce<Args> {
1303 type Output;
1304}
1305
1306fn test<F: FnOnce(u32) -> u64>(f: F) {
1307 f(1);
1308 let g = |v| v + 1;
1309 g(1u64);
1310 let h = |v| 1u128 + v;
1311}
1312"#),
1313 @r###"
1314 [73; 74) 'f': F
1315 [79; 155) '{ ...+ v; }': ()
1316 [85; 86) 'f': F
1317 [85; 89) 'f(1)': {unknown}
1318 [87; 88) '1': i32
1319 [99; 100) 'g': |u64| -> i32
1320 [103; 112) '|v| v + 1': |u64| -> i32
1321 [104; 105) 'v': u64
1322 [107; 108) 'v': u64
1323 [107; 112) 'v + 1': i32
1324 [111; 112) '1': i32
1325 [118; 119) 'g': |u64| -> i32
1326 [118; 125) 'g(1u64)': i32
1327 [120; 124) '1u64': u64
1328 [135; 136) 'h': |u128| -> u128
1329 [139; 152) '|v| 1u128 + v': |u128| -> u128
1330 [140; 141) 'v': u128
1331 [143; 148) '1u128': u128
1332 [143; 152) '1u128 + v': u128
1333 [151; 152) 'v': u128
1334 "###
1335 );
1336}
1337
1338#[test]
1339fn closure_as_argument_inference_order() {
1340 assert_snapshot!(
1341 infer(r#"
1342#[lang = "fn_once"]
1343trait FnOnce<Args> {
1344 type Output;
1345}
1346
1347fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U {}
1348fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U {}
1349
1350struct S;
1351impl S {
1352 fn method(self) -> u64;
1353
1354 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U {}
1355 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U {}
1356}
1357
1358fn test() {
1359 let x1 = foo1(S, |s| s.method());
1360 let x2 = foo2(|s| s.method(), S);
1361 let x3 = S.foo1(S, |s| s.method());
1362 let x4 = S.foo2(|s| s.method(), S);
1363}
1364"#),
1365 @r###"
1366 [95; 96) 'x': T
1367 [101; 102) 'f': F
1368 [112; 114) '{}': ()
1369 [148; 149) 'f': F
1370 [154; 155) 'x': T
1371 [165; 167) '{}': ()
1372 [202; 206) 'self': S
1373 [254; 258) 'self': S
1374 [260; 261) 'x': T
1375 [266; 267) 'f': F
1376 [277; 279) '{}': ()
1377 [317; 321) 'self': S
1378 [323; 324) 'f': F
1379 [329; 330) 'x': T
1380 [340; 342) '{}': ()
1381 [356; 515) '{ ... S); }': ()
1382 [366; 368) 'x1': u64
1383 [371; 375) 'foo1': fn foo1<S, u64, |S| -> u64>(T, F) -> U
1384 [371; 394) 'foo1(S...hod())': u64
1385 [376; 377) 'S': S
1386 [379; 393) '|s| s.method()': |S| -> u64
1387 [380; 381) 's': S
1388 [383; 384) 's': S
1389 [383; 393) 's.method()': u64
1390 [404; 406) 'x2': u64
1391 [409; 413) 'foo2': fn foo2<S, u64, |S| -> u64>(F, T) -> U
1392 [409; 432) 'foo2(|...(), S)': u64
1393 [414; 428) '|s| s.method()': |S| -> u64
1394 [415; 416) 's': S
1395 [418; 419) 's': S
1396 [418; 428) 's.method()': u64
1397 [430; 431) 'S': S
1398 [442; 444) 'x3': u64
1399 [447; 448) 'S': S
1400 [447; 472) 'S.foo1...hod())': u64
1401 [454; 455) 'S': S
1402 [457; 471) '|s| s.method()': |S| -> u64
1403 [458; 459) 's': S
1404 [461; 462) 's': S
1405 [461; 471) 's.method()': u64
1406 [482; 484) 'x4': u64
1407 [487; 488) 'S': S
1408 [487; 512) 'S.foo2...(), S)': u64
1409 [494; 508) '|s| s.method()': |S| -> u64
1410 [495; 496) 's': S
1411 [498; 499) 's': S
1412 [498; 508) 's.method()': u64
1413 [510; 511) 'S': S
1414 "###
1415 );
1416}
1417
1418#[test]
1419fn unselected_projection_in_trait_env_1() {
1420 let t = type_at(
1421 r#"
1422//- /main.rs
1423trait Trait {
1424 type Item;
1425}
1426
1427trait Trait2 {
1428 fn foo(&self) -> u32;
1429}
1430
1431fn test<T: Trait>() where T::Item: Trait2 {
1432 let x: T::Item = no_matter;
1433 x.foo()<|>;
1434}
1435"#,
1436 );
1437 assert_eq!(t, "u32");
1438}
1439
1440#[test]
1441fn unselected_projection_in_trait_env_2() {
1442 let t = type_at(
1443 r#"
1444//- /main.rs
1445trait Trait<T> {
1446 type Item;
1447}
1448
1449trait Trait2 {
1450 fn foo(&self) -> u32;
1451}
1452
1453fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
1454 let x: T::Item = no_matter;
1455 x.foo()<|>;
1456}
1457"#,
1458 );
1459 assert_eq!(t, "u32");
1460}
1461
1462#[test]
1463fn trait_impl_self_ty() {
1464 let t = type_at(
1465 r#"
1466//- /main.rs
1467trait Trait<T> {
1468 fn foo(&self);
1469}
1470
1471struct S;
1472
1473impl Trait<Self> for S {}
1474
1475fn test() {
1476 S.foo()<|>;
1477}
1478"#,
1479 );
1480 assert_eq!(t, "()");
1481}
1482
1483#[test]
1484fn trait_impl_self_ty_cycle() {
1485 let t = type_at(
1486 r#"
1487//- /main.rs
1488trait Trait {
1489 fn foo(&self);
1490}
1491
1492struct S<T>;
1493
1494impl Trait for S<Self> {}
1495
1496fn test() {
1497 S.foo()<|>;
1498}
1499"#,
1500 );
1501 assert_eq!(t, "{unknown}");
1502}
1503
1504#[test]
1505fn unselected_projection_in_trait_env_cycle_1() {
1506 let t = type_at(
1507 r#"
1508//- /main.rs
1509trait Trait {
1510 type Item;
1511}
1512
1513trait Trait2<T> {}
1514
1515fn test<T: Trait>() where T: Trait2<T::Item> {
1516 let x: T::Item = no_matter<|>;
1517}
1518"#,
1519 );
1520 // this is a legitimate cycle
1521 assert_eq!(t, "{unknown}");
1522}
1523
1524#[test]
1525fn unselected_projection_in_trait_env_cycle_2() {
1526 let t = type_at(
1527 r#"
1528//- /main.rs
1529trait Trait<T> {
1530 type Item;
1531}
1532
1533fn test<T, U>() where T: Trait<U::Item>, U: Trait<T::Item> {
1534 let x: T::Item = no_matter<|>;
1535}
1536"#,
1537 );
1538 // this is a legitimate cycle
1539 assert_eq!(t, "{unknown}");
1540}
1541
1542#[test]
1543fn unify_impl_trait() {
1544 covers!(insert_vars_for_impl_trait);
1545 assert_snapshot!(
1546 infer_with_mismatches(r#"
1547trait Trait<T> {}
1548
1549fn foo(x: impl Trait<u32>) { loop {} }
1550fn bar<T>(x: impl Trait<T>) -> T { loop {} }
1551
1552struct S<T>(T);
1553impl<T> Trait<T> for S<T> {}
1554
1555fn default<T>() -> T { loop {} }
1556
1557fn test() -> impl Trait<i32> {
1558 let s1 = S(default());
1559 foo(s1);
1560 let x: i32 = bar(S(default()));
1561 S(default())
1562}
1563"#, true),
1564 @r###"
1565 [27; 28) 'x': impl Trait<u32>
1566 [47; 58) '{ loop {} }': ()
1567 [49; 56) 'loop {}': !
1568 [54; 56) '{}': ()
1569 [69; 70) 'x': impl Trait<T>
1570 [92; 103) '{ loop {} }': T
1571 [94; 101) 'loop {}': !
1572 [99; 101) '{}': ()
1573 [172; 183) '{ loop {} }': T
1574 [174; 181) 'loop {}': !
1575 [179; 181) '{}': ()
1576 [214; 310) '{ ...t()) }': S<i32>
1577 [224; 226) 's1': S<u32>
1578 [229; 230) 'S': S<u32>(T) -> S<T>
1579 [229; 241) 'S(default())': S<u32>
1580 [231; 238) 'default': fn default<u32>() -> T
1581 [231; 240) 'default()': u32
1582 [247; 250) 'foo': fn foo(impl Trait<u32>) -> ()
1583 [247; 254) 'foo(s1)': ()
1584 [251; 253) 's1': S<u32>
1585 [264; 265) 'x': i32
1586 [273; 276) 'bar': fn bar<i32>(impl Trait<T>) -> T
1587 [273; 290) 'bar(S(...lt()))': i32
1588 [277; 278) 'S': S<i32>(T) -> S<T>
1589 [277; 289) 'S(default())': S<i32>
1590 [279; 286) 'default': fn default<i32>() -> T
1591 [279; 288) 'default()': i32
1592 [296; 297) 'S': S<i32>(T) -> S<T>
1593 [296; 308) 'S(default())': S<i32>
1594 [298; 305) 'default': fn default<i32>() -> T
1595 [298; 307) 'default()': i32
1596 "###
1597 );
1598}
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs
index 76189a60b..c4dc857bc 100644
--- a/crates/ra_hir_ty/src/traits.rs
+++ b/crates/ra_hir_ty/src/traits.rs
@@ -1,7 +1,7 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2use std::sync::{Arc, Mutex}; 2use std::sync::{Arc, Mutex};
3 3
4use chalk_ir::{cast::Cast, family::ChalkIr}; 4use chalk_ir::cast::Cast;
5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; 5use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId};
6use log::debug; 6use log::debug;
7use ra_db::{impl_intern_key, salsa, CrateId}; 7use ra_db::{impl_intern_key, salsa, CrateId};
@@ -12,14 +12,15 @@ use crate::db::HirDatabase;
12 12
13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; 13use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk};
14 14
15use self::chalk::{from_chalk, ToChalk}; 15use self::chalk::{from_chalk, ToChalk, TypeFamily};
16 16
17pub(crate) mod chalk; 17pub(crate) mod chalk;
18mod builtin;
18 19
19#[derive(Debug, Clone)] 20#[derive(Debug, Clone)]
20pub struct TraitSolver { 21pub struct TraitSolver {
21 krate: CrateId, 22 krate: CrateId,
22 inner: Arc<Mutex<chalk_solve::Solver<ChalkIr>>>, 23 inner: Arc<Mutex<chalk_solve::Solver<TypeFamily>>>,
23} 24}
24 25
25/// We need eq for salsa 26/// We need eq for salsa
@@ -35,8 +36,8 @@ impl TraitSolver {
35 fn solve( 36 fn solve(
36 &self, 37 &self,
37 db: &impl HirDatabase, 38 db: &impl HirDatabase,
38 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<ChalkIr>>>, 39 goal: &chalk_ir::UCanonical<chalk_ir::InEnvironment<chalk_ir::Goal<TypeFamily>>>,
39 ) -> Option<chalk_solve::Solution<ChalkIr>> { 40 ) -> Option<chalk_solve::Solution<TypeFamily>> {
40 let context = ChalkContext { db, krate: self.krate }; 41 let context = ChalkContext { db, krate: self.krate };
41 debug!("solve goal: {:?}", goal); 42 debug!("solve goal: {:?}", goal);
42 let mut solver = match self.inner.lock() { 43 let mut solver = match self.inner.lock() {
@@ -200,17 +201,17 @@ pub(crate) fn trait_solve_query(
200 201
201fn solution_from_chalk( 202fn solution_from_chalk(
202 db: &impl HirDatabase, 203 db: &impl HirDatabase,
203 solution: chalk_solve::Solution<ChalkIr>, 204 solution: chalk_solve::Solution<TypeFamily>,
204) -> Solution { 205) -> Solution {
205 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<ChalkIr>>| { 206 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<TypeFamily>>| {
206 let value = subst 207 let value = subst
207 .value 208 .value
208 .parameters 209 .parameters
209 .into_iter() 210 .into_iter()
210 .map(|p| { 211 .map(|p| {
211 let ty = match p { 212 let ty = match p.ty() {
212 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 213 Some(ty) => from_chalk(db, ty.clone()),
213 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 214 None => unimplemented!(),
214 }; 215 };
215 ty 216 ty
216 }) 217 })
@@ -290,7 +291,7 @@ impl FnTrait {
290 } 291 }
291} 292}
292 293
293#[derive(Debug, Clone, PartialEq, Eq, Hash)] 294#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
294pub struct ClosureFnTraitImplData { 295pub struct ClosureFnTraitImplData {
295 def: DefWithBodyId, 296 def: DefWithBodyId,
296 expr: ExprId, 297 expr: ExprId,
@@ -299,7 +300,7 @@ pub struct ClosureFnTraitImplData {
299 300
300/// An impl. Usually this comes from an impl block, but some built-in types get 301/// An impl. Usually this comes from an impl block, but some built-in types get
301/// synthetic impls. 302/// synthetic impls.
302#[derive(Debug, Clone, PartialEq, Eq, Hash)] 303#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
303pub enum Impl { 304pub enum Impl {
304 /// A normal impl from an impl block. 305 /// A normal impl from an impl block.
305 ImplBlock(ImplId), 306 ImplBlock(ImplId),
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs
new file mode 100644
index 000000000..dd41176f0
--- /dev/null
+++ b/crates/ra_hir_ty/src/traits/builtin.rs
@@ -0,0 +1,178 @@
1//! This module provides the built-in trait implementations, e.g. to make
2//! closures implement `Fn`.
3use hir_def::{expr::Expr, lang_item::LangItemTarget, TraitId, TypeAliasId};
4use hir_expand::name::name;
5use ra_db::CrateId;
6
7use super::{AssocTyValue, Impl};
8use crate::{db::HirDatabase, ApplicationTy, Substs, TraitRef, Ty, TypeCtor};
9
10pub(super) struct BuiltinImplData {
11 pub num_vars: usize,
12 pub trait_ref: TraitRef,
13 pub where_clauses: Vec<super::GenericPredicate>,
14 pub assoc_ty_values: Vec<AssocTyValue>,
15}
16
17pub(super) struct BuiltinImplAssocTyValueData {
18 pub impl_: Impl,
19 pub assoc_ty_id: TypeAliasId,
20 pub num_vars: usize,
21 pub value: Ty,
22}
23
24pub(super) fn get_builtin_impls(
25 db: &impl HirDatabase,
26 krate: CrateId,
27 ty: &Ty,
28 trait_: TraitId,
29 mut callback: impl FnMut(Impl),
30) {
31 // Note: since impl_datum needs to be infallible, we need to make sure here
32 // that we have all prerequisites to build the respective impls.
33 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty {
34 for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter()
35 {
36 if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) {
37 if trait_ == actual_trait {
38 let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait };
39 if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) {
40 callback(Impl::ClosureFnTraitImpl(impl_));
41 }
42 }
43 }
44 }
45 }
46}
47
48pub(super) fn impl_datum(db: &impl HirDatabase, krate: CrateId, impl_: Impl) -> BuiltinImplData {
49 match impl_ {
50 Impl::ImplBlock(_) => unreachable!(),
51 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data),
52 }
53}
54
55pub(super) fn associated_ty_value(
56 db: &impl HirDatabase,
57 krate: CrateId,
58 data: AssocTyValue,
59) -> BuiltinImplAssocTyValueData {
60 match data {
61 AssocTyValue::TypeAlias(_) => unreachable!(),
62 AssocTyValue::ClosureFnTraitImplOutput(data) => {
63 closure_fn_trait_output_assoc_ty_value(db, krate, data)
64 }
65 }
66}
67
68fn check_closure_fn_trait_impl_prerequisites(
69 db: &impl HirDatabase,
70 krate: CrateId,
71 data: super::ClosureFnTraitImplData,
72) -> bool {
73 // the respective Fn/FnOnce/FnMut trait needs to exist
74 if get_fn_trait(db, krate, data.fn_trait).is_none() {
75 return false;
76 }
77
78 // FIXME: there are more assumptions that we should probably check here:
79 // the traits having no type params, FnOnce being a supertrait
80
81 // the FnOnce trait needs to exist and have an assoc type named Output
82 let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) {
83 Some(t) => t,
84 None => return false,
85 };
86 db.trait_data(fn_once_trait).associated_type_by_name(&name![Output]).is_some()
87}
88
89fn closure_fn_trait_impl_datum(
90 db: &impl HirDatabase,
91 krate: CrateId,
92 data: super::ClosureFnTraitImplData,
93) -> BuiltinImplData {
94 // for some closure |X, Y| -> Z:
95 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
96
97 let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait
98 // the existence of the Fn trait has been checked before
99 .expect("fn trait for closure impl missing");
100
101 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
102 Expr::Lambda { args, .. } => args.len() as u16,
103 _ => {
104 log::warn!("closure for closure type {:?} not found", data);
105 0
106 }
107 };
108
109 let arg_ty = Ty::apply(
110 TypeCtor::Tuple { cardinality: num_args },
111 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
112 );
113 let sig_ty = Ty::apply(
114 TypeCtor::FnPtr { num_args },
115 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
116 );
117
118 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
119
120 let trait_ref = TraitRef {
121 trait_: trait_.into(),
122 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
123 };
124
125 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone());
126
127 BuiltinImplData {
128 num_vars: num_args as usize + 1,
129 trait_ref,
130 where_clauses: Vec::new(),
131 assoc_ty_values: vec![output_ty_id],
132 }
133}
134
135fn closure_fn_trait_output_assoc_ty_value(
136 db: &impl HirDatabase,
137 krate: CrateId,
138 data: super::ClosureFnTraitImplData,
139) -> BuiltinImplAssocTyValueData {
140 let impl_ = Impl::ClosureFnTraitImpl(data.clone());
141
142 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
143 Expr::Lambda { args, .. } => args.len() as u16,
144 _ => {
145 log::warn!("closure for closure type {:?} not found", data);
146 0
147 }
148 };
149
150 let output_ty = Ty::Bound(num_args.into());
151
152 let fn_once_trait =
153 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
154
155 let output_ty_id = db
156 .trait_data(fn_once_trait)
157 .associated_type_by_name(&name![Output])
158 .expect("assoc ty value should not exist");
159
160 BuiltinImplAssocTyValueData {
161 impl_,
162 assoc_ty_id: output_ty_id,
163 num_vars: num_args as usize + 1,
164 value: output_ty,
165 }
166}
167
168fn get_fn_trait(
169 db: &impl HirDatabase,
170 krate: CrateId,
171 fn_trait: super::FnTrait,
172) -> Option<TraitId> {
173 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
174 match target {
175 LangItemTarget::TraitId(t) => Some(t),
176 _ => None,
177 }
178}
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs
index 35de37e6b..555930c9b 100644
--- a/crates/ra_hir_ty/src/traits/chalk.rs
+++ b/crates/ra_hir_ty/src/traits/chalk.rs
@@ -1,32 +1,99 @@
1//! Conversion code from/to Chalk. 1//! Conversion code from/to Chalk.
2use std::sync::Arc; 2use std::{fmt, sync::Arc};
3 3
4use log::debug; 4use log::debug;
5 5
6use chalk_ir::{ 6use chalk_ir::{cast::Cast, Parameter, PlaceholderIndex, TypeName, UniverseIndex};
7 cast::Cast, family::ChalkIr, Identifier, Parameter, PlaceholderIndex, TypeId, TypeKindId,
8 TypeName, UniverseIndex,
9};
10use chalk_rust_ir::{AssociatedTyDatum, AssociatedTyValue, ImplDatum, StructDatum, TraitDatum};
11use ra_db::CrateId;
12 7
13use hir_def::{ 8use hir_def::{AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId};
14 expr::Expr, lang_item::LangItemTarget, AssocItemId, AstItemDef, ContainerId, GenericDefId, 9use ra_db::{
15 ImplId, Lookup, TraitId, TypeAliasId, 10 salsa::{InternId, InternKey},
11 CrateId,
16}; 12};
17use hir_expand::name;
18
19use ra_db::salsa::{InternId, InternKey};
20 13
21use super::{AssocTyValue, Canonical, ChalkContext, Impl, Obligation}; 14use super::{builtin, AssocTyValue, Canonical, ChalkContext, Impl, Obligation};
22use crate::{ 15use crate::{
23 db::HirDatabase, display::HirDisplay, ApplicationTy, GenericPredicate, ImplTy, ProjectionTy, 16 db::HirDatabase, display::HirDisplay, utils::generics, ApplicationTy, GenericPredicate,
24 Substs, TraitRef, Ty, TypeCtor, TypeWalk, 17 ProjectionTy, Substs, TraitRef, Ty, TypeCtor, TypeWalk,
25}; 18};
26 19
27/// This represents a trait whose name we could not resolve. 20#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
28const UNKNOWN_TRAIT: chalk_ir::TraitId = 21pub struct TypeFamily {}
29 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); 22
23impl chalk_ir::family::TypeFamily for TypeFamily {
24 type InternedType = Box<chalk_ir::TyData<Self>>;
25 type InternedLifetime = chalk_ir::LifetimeData<Self>;
26 type InternedParameter = chalk_ir::ParameterData<Self>;
27 type DefId = InternId;
28
29 // FIXME: implement these
30 fn debug_struct_id(
31 _type_kind_id: chalk_ir::StructId<Self>,
32 _fmt: &mut fmt::Formatter<'_>,
33 ) -> Option<fmt::Result> {
34 None
35 }
36
37 fn debug_trait_id(
38 _type_kind_id: chalk_ir::TraitId<Self>,
39 _fmt: &mut fmt::Formatter<'_>,
40 ) -> Option<fmt::Result> {
41 None
42 }
43
44 fn debug_assoc_type_id(
45 _id: chalk_ir::AssocTypeId<Self>,
46 _fmt: &mut fmt::Formatter<'_>,
47 ) -> Option<fmt::Result> {
48 None
49 }
50
51 fn debug_projection(
52 _projection: &chalk_ir::ProjectionTy<Self>,
53 _fmt: &mut fmt::Formatter<'_>,
54 ) -> Option<fmt::Result> {
55 None
56 }
57
58 fn intern_ty(ty: chalk_ir::TyData<Self>) -> Box<chalk_ir::TyData<Self>> {
59 Box::new(ty)
60 }
61
62 fn ty_data(ty: &Box<chalk_ir::TyData<Self>>) -> &chalk_ir::TyData<Self> {
63 ty
64 }
65
66 fn intern_lifetime(lifetime: chalk_ir::LifetimeData<Self>) -> chalk_ir::LifetimeData<Self> {
67 lifetime
68 }
69
70 fn lifetime_data(lifetime: &chalk_ir::LifetimeData<Self>) -> &chalk_ir::LifetimeData<Self> {
71 lifetime
72 }
73
74 fn intern_parameter(parameter: chalk_ir::ParameterData<Self>) -> chalk_ir::ParameterData<Self> {
75 parameter
76 }
77
78 fn parameter_data(parameter: &chalk_ir::ParameterData<Self>) -> &chalk_ir::ParameterData<Self> {
79 parameter
80 }
81}
82
83impl chalk_ir::family::HasTypeFamily for TypeFamily {
84 type TypeFamily = Self;
85}
86
87pub type AssocTypeId = chalk_ir::AssocTypeId<TypeFamily>;
88pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<TypeFamily>;
89pub type TraitId = chalk_ir::TraitId<TypeFamily>;
90pub type TraitDatum = chalk_rust_ir::TraitDatum<TypeFamily>;
91pub type StructId = chalk_ir::StructId<TypeFamily>;
92pub type StructDatum = chalk_rust_ir::StructDatum<TypeFamily>;
93pub type ImplId = chalk_ir::ImplId<TypeFamily>;
94pub type ImplDatum = chalk_rust_ir::ImplDatum<TypeFamily>;
95pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId;
96pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<TypeFamily>;
30 97
31pub(super) trait ToChalk { 98pub(super) trait ToChalk {
32 type Chalk; 99 type Chalk;
@@ -42,21 +109,11 @@ where
42} 109}
43 110
44impl ToChalk for Ty { 111impl ToChalk for Ty {
45 type Chalk = chalk_ir::Ty<ChalkIr>; 112 type Chalk = chalk_ir::Ty<TypeFamily>;
46 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<ChalkIr> { 113 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Ty<TypeFamily> {
47 match self { 114 match self {
48 Ty::Apply(apply_ty) => { 115 Ty::Apply(apply_ty) => {
49 let name = match apply_ty.ctor { 116 let name = apply_ty.ctor.to_chalk(db);
50 TypeCtor::AssociatedType(type_alias) => {
51 let type_id = type_alias.to_chalk(db);
52 TypeName::AssociatedType(type_id)
53 }
54 _ => {
55 // other TypeCtors get interned and turned into a chalk StructId
56 let struct_id = apply_ty.ctor.to_chalk(db);
57 TypeName::TypeKindId(struct_id.into())
58 }
59 };
60 let parameters = apply_ty.parameters.to_chalk(db); 117 let parameters = apply_ty.parameters.to_chalk(db);
61 chalk_ir::ApplicationTy { name, parameters }.cast().intern() 118 chalk_ir::ApplicationTy { name, parameters }.cast().intern()
62 } 119 }
@@ -66,17 +123,30 @@ impl ToChalk for Ty {
66 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern() 123 chalk_ir::ProjectionTy { associated_ty_id, parameters }.cast().intern()
67 } 124 }
68 Ty::Param { idx, .. } => { 125 Ty::Param { idx, .. } => {
69 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }.to_ty::<ChalkIr>() 126 PlaceholderIndex { ui: UniverseIndex::ROOT, idx: idx as usize }
127 .to_ty::<TypeFamily>()
70 } 128 }
71 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(), 129 Ty::Bound(idx) => chalk_ir::TyData::BoundVar(idx as usize).intern(),
72 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), 130 Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"),
73 Ty::Dyn(predicates) => { 131 Ty::Dyn(predicates) => {
74 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); 132 let where_clauses = predicates
75 chalk_ir::TyData::Dyn(make_binders(where_clauses, 1)).intern() 133 .iter()
134 .filter(|p| !p.is_error())
135 .cloned()
136 .map(|p| p.to_chalk(db))
137 .collect();
138 let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) };
139 chalk_ir::TyData::Dyn(bounded_ty).intern()
76 } 140 }
77 Ty::Opaque(predicates) => { 141 Ty::Opaque(predicates) => {
78 let where_clauses = predicates.iter().cloned().map(|p| p.to_chalk(db)).collect(); 142 let where_clauses = predicates
79 chalk_ir::TyData::Opaque(make_binders(where_clauses, 1)).intern() 143 .iter()
144 .filter(|p| !p.is_error())
145 .cloned()
146 .map(|p| p.to_chalk(db))
147 .collect();
148 let bounded_ty = chalk_ir::BoundedTy { bounds: make_binders(where_clauses, 1) };
149 chalk_ir::TyData::Opaque(bounded_ty).intern()
80 } 150 }
81 Ty::Unknown => { 151 Ty::Unknown => {
82 let parameters = Vec::new(); 152 let parameters = Vec::new();
@@ -85,30 +155,19 @@ impl ToChalk for Ty {
85 } 155 }
86 } 156 }
87 } 157 }
88 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<ChalkIr>) -> Self { 158 fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty<TypeFamily>) -> Self {
89 match chalk.data().clone() { 159 match chalk.data().clone() {
90 chalk_ir::TyData::Apply(apply_ty) => { 160 chalk_ir::TyData::Apply(apply_ty) => match apply_ty.name {
91 // FIXME this is kind of hacky due to the fact that 161 TypeName::Error => Ty::Unknown,
92 // TypeName::Placeholder is a Ty::Param on our side 162 _ => {
93 match apply_ty.name { 163 let ctor = from_chalk(db, apply_ty.name);
94 TypeName::TypeKindId(TypeKindId::StructId(struct_id)) => { 164 let parameters = from_chalk(db, apply_ty.parameters);
95 let ctor = from_chalk(db, struct_id); 165 Ty::Apply(ApplicationTy { ctor, parameters })
96 let parameters = from_chalk(db, apply_ty.parameters);
97 Ty::Apply(ApplicationTy { ctor, parameters })
98 }
99 TypeName::AssociatedType(type_id) => {
100 let ctor = TypeCtor::AssociatedType(from_chalk(db, type_id));
101 let parameters = from_chalk(db, apply_ty.parameters);
102 Ty::Apply(ApplicationTy { ctor, parameters })
103 }
104 TypeName::Error => Ty::Unknown,
105 // FIXME handle TypeKindId::Trait/Type here
106 TypeName::TypeKindId(_) => unimplemented!(),
107 TypeName::Placeholder(idx) => {
108 assert_eq!(idx.ui, UniverseIndex::ROOT);
109 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
110 }
111 } 166 }
167 },
168 chalk_ir::TyData::Placeholder(idx) => {
169 assert_eq!(idx.ui, UniverseIndex::ROOT);
170 Ty::Param { idx: idx.idx as u32, name: crate::Name::missing() }
112 } 171 }
113 chalk_ir::TyData::Projection(proj) => { 172 chalk_ir::TyData::Projection(proj) => {
114 let associated_ty = from_chalk(db, proj.associated_ty_id); 173 let associated_ty = from_chalk(db, proj.associated_ty_id);
@@ -119,15 +178,15 @@ impl ToChalk for Ty {
119 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32), 178 chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx as u32),
120 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, 179 chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown,
121 chalk_ir::TyData::Dyn(where_clauses) => { 180 chalk_ir::TyData::Dyn(where_clauses) => {
122 assert_eq!(where_clauses.binders.len(), 1); 181 assert_eq!(where_clauses.bounds.binders.len(), 1);
123 let predicates = 182 let predicates =
124 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 183 where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect();
125 Ty::Dyn(predicates) 184 Ty::Dyn(predicates)
126 } 185 }
127 chalk_ir::TyData::Opaque(where_clauses) => { 186 chalk_ir::TyData::Opaque(where_clauses) => {
128 assert_eq!(where_clauses.binders.len(), 1); 187 assert_eq!(where_clauses.bounds.binders.len(), 1);
129 let predicates = 188 let predicates =
130 where_clauses.value.into_iter().map(|c| from_chalk(db, c)).collect(); 189 where_clauses.bounds.value.into_iter().map(|c| from_chalk(db, c)).collect();
131 Ty::Opaque(predicates) 190 Ty::Opaque(predicates)
132 } 191 }
133 } 192 }
@@ -135,18 +194,21 @@ impl ToChalk for Ty {
135} 194}
136 195
137impl ToChalk for Substs { 196impl ToChalk for Substs {
138 type Chalk = Vec<chalk_ir::Parameter<ChalkIr>>; 197 type Chalk = Vec<chalk_ir::Parameter<TypeFamily>>;
139 198
140 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<ChalkIr>> { 199 fn to_chalk(self, db: &impl HirDatabase) -> Vec<Parameter<TypeFamily>> {
141 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect() 200 self.iter().map(|ty| ty.clone().to_chalk(db).cast()).collect()
142 } 201 }
143 202
144 fn from_chalk(db: &impl HirDatabase, parameters: Vec<chalk_ir::Parameter<ChalkIr>>) -> Substs { 203 fn from_chalk(
204 db: &impl HirDatabase,
205 parameters: Vec<chalk_ir::Parameter<TypeFamily>>,
206 ) -> Substs {
145 let tys = parameters 207 let tys = parameters
146 .into_iter() 208 .into_iter()
147 .map(|p| match p { 209 .map(|p| match p.ty() {
148 chalk_ir::Parameter(chalk_ir::ParameterKind::Ty(ty)) => from_chalk(db, ty), 210 Some(ty) => from_chalk(db, ty.clone()),
149 chalk_ir::Parameter(chalk_ir::ParameterKind::Lifetime(_)) => unimplemented!(), 211 None => unimplemented!(),
150 }) 212 })
151 .collect(); 213 .collect();
152 Substs(tys) 214 Substs(tys)
@@ -154,88 +216,102 @@ impl ToChalk for Substs {
154} 216}
155 217
156impl ToChalk for TraitRef { 218impl ToChalk for TraitRef {
157 type Chalk = chalk_ir::TraitRef<ChalkIr>; 219 type Chalk = chalk_ir::TraitRef<TypeFamily>;
158 220
159 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<ChalkIr> { 221 fn to_chalk(self: TraitRef, db: &impl HirDatabase) -> chalk_ir::TraitRef<TypeFamily> {
160 let trait_id = self.trait_.to_chalk(db); 222 let trait_id = self.trait_.to_chalk(db);
161 let parameters = self.substs.to_chalk(db); 223 let parameters = self.substs.to_chalk(db);
162 chalk_ir::TraitRef { trait_id, parameters } 224 chalk_ir::TraitRef { trait_id, parameters }
163 } 225 }
164 226
165 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<ChalkIr>) -> Self { 227 fn from_chalk(db: &impl HirDatabase, trait_ref: chalk_ir::TraitRef<TypeFamily>) -> Self {
166 let trait_ = from_chalk(db, trait_ref.trait_id); 228 let trait_ = from_chalk(db, trait_ref.trait_id);
167 let substs = from_chalk(db, trait_ref.parameters); 229 let substs = from_chalk(db, trait_ref.parameters);
168 TraitRef { trait_, substs } 230 TraitRef { trait_, substs }
169 } 231 }
170} 232}
171 233
172impl ToChalk for TraitId { 234impl ToChalk for hir_def::TraitId {
173 type Chalk = chalk_ir::TraitId; 235 type Chalk = TraitId;
174 236
175 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TraitId { 237 fn to_chalk(self, _db: &impl HirDatabase) -> TraitId {
176 chalk_ir::TraitId(id_to_chalk(self)) 238 chalk_ir::TraitId(self.as_intern_id())
177 } 239 }
178 240
179 fn from_chalk(_db: &impl HirDatabase, trait_id: chalk_ir::TraitId) -> TraitId { 241 fn from_chalk(_db: &impl HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
180 id_from_chalk(trait_id.0) 242 InternKey::from_intern_id(trait_id.0)
181 } 243 }
182} 244}
183 245
184impl ToChalk for TypeCtor { 246impl ToChalk for TypeCtor {
185 type Chalk = chalk_ir::StructId; 247 type Chalk = TypeName<TypeFamily>;
186 248
187 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::StructId { 249 fn to_chalk(self, db: &impl HirDatabase) -> TypeName<TypeFamily> {
188 db.intern_type_ctor(self).into() 250 match self {
251 TypeCtor::AssociatedType(type_alias) => {
252 let type_id = type_alias.to_chalk(db);
253 TypeName::AssociatedType(type_id)
254 }
255 _ => {
256 // other TypeCtors get interned and turned into a chalk StructId
257 let struct_id = db.intern_type_ctor(self).into();
258 TypeName::Struct(struct_id)
259 }
260 }
189 } 261 }
190 262
191 fn from_chalk(db: &impl HirDatabase, struct_id: chalk_ir::StructId) -> TypeCtor { 263 fn from_chalk(db: &impl HirDatabase, type_name: TypeName<TypeFamily>) -> TypeCtor {
192 db.lookup_intern_type_ctor(struct_id.into()) 264 match type_name {
265 TypeName::Struct(struct_id) => db.lookup_intern_type_ctor(struct_id.into()),
266 TypeName::AssociatedType(type_id) => TypeCtor::AssociatedType(from_chalk(db, type_id)),
267 TypeName::Error => {
268 // this should not be reached, since we don't represent TypeName::Error with TypeCtor
269 unreachable!()
270 }
271 }
193 } 272 }
194} 273}
195 274
196impl ToChalk for Impl { 275impl ToChalk for Impl {
197 type Chalk = chalk_ir::ImplId; 276 type Chalk = ImplId;
198 277
199 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ImplId { 278 fn to_chalk(self, db: &impl HirDatabase) -> ImplId {
200 db.intern_chalk_impl(self).into() 279 db.intern_chalk_impl(self).into()
201 } 280 }
202 281
203 fn from_chalk(db: &impl HirDatabase, impl_id: chalk_ir::ImplId) -> Impl { 282 fn from_chalk(db: &impl HirDatabase, impl_id: ImplId) -> Impl {
204 db.lookup_intern_chalk_impl(impl_id.into()) 283 db.lookup_intern_chalk_impl(impl_id.into())
205 } 284 }
206} 285}
207 286
208impl ToChalk for TypeAliasId { 287impl ToChalk for TypeAliasId {
209 type Chalk = chalk_ir::TypeId; 288 type Chalk = AssocTypeId;
210 289
211 fn to_chalk(self, _db: &impl HirDatabase) -> chalk_ir::TypeId { 290 fn to_chalk(self, _db: &impl HirDatabase) -> AssocTypeId {
212 chalk_ir::TypeId(id_to_chalk(self)) 291 chalk_ir::AssocTypeId(self.as_intern_id())
213 } 292 }
214 293
215 fn from_chalk(_db: &impl HirDatabase, type_alias_id: chalk_ir::TypeId) -> TypeAliasId { 294 fn from_chalk(_db: &impl HirDatabase, type_alias_id: AssocTypeId) -> TypeAliasId {
216 id_from_chalk(type_alias_id.0) 295 InternKey::from_intern_id(type_alias_id.0)
217 } 296 }
218} 297}
219 298
220impl ToChalk for AssocTyValue { 299impl ToChalk for AssocTyValue {
221 type Chalk = chalk_rust_ir::AssociatedTyValueId; 300 type Chalk = AssociatedTyValueId;
222 301
223 fn to_chalk(self, db: &impl HirDatabase) -> chalk_rust_ir::AssociatedTyValueId { 302 fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValueId {
224 db.intern_assoc_ty_value(self).into() 303 db.intern_assoc_ty_value(self).into()
225 } 304 }
226 305
227 fn from_chalk( 306 fn from_chalk(db: &impl HirDatabase, assoc_ty_value_id: AssociatedTyValueId) -> AssocTyValue {
228 db: &impl HirDatabase,
229 assoc_ty_value_id: chalk_rust_ir::AssociatedTyValueId,
230 ) -> AssocTyValue {
231 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into()) 307 db.lookup_intern_assoc_ty_value(assoc_ty_value_id.into())
232 } 308 }
233} 309}
234 310
235impl ToChalk for GenericPredicate { 311impl ToChalk for GenericPredicate {
236 type Chalk = chalk_ir::QuantifiedWhereClause<ChalkIr>; 312 type Chalk = chalk_ir::QuantifiedWhereClause<TypeFamily>;
237 313
238 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<ChalkIr> { 314 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause<TypeFamily> {
239 match self { 315 match self {
240 GenericPredicate::Implemented(trait_ref) => { 316 GenericPredicate::Implemented(trait_ref) => {
241 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) 317 make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0)
@@ -247,26 +323,16 @@ impl ToChalk for GenericPredicate {
247 }), 323 }),
248 0, 324 0,
249 ), 325 ),
250 GenericPredicate::Error => { 326 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"),
251 let impossible_trait_ref = chalk_ir::TraitRef {
252 trait_id: UNKNOWN_TRAIT,
253 parameters: vec![Ty::Unknown.to_chalk(db).cast()],
254 };
255 make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0)
256 }
257 } 327 }
258 } 328 }
259 329
260 fn from_chalk( 330 fn from_chalk(
261 db: &impl HirDatabase, 331 db: &impl HirDatabase,
262 where_clause: chalk_ir::QuantifiedWhereClause<ChalkIr>, 332 where_clause: chalk_ir::QuantifiedWhereClause<TypeFamily>,
263 ) -> GenericPredicate { 333 ) -> GenericPredicate {
264 match where_clause.value { 334 match where_clause.value {
265 chalk_ir::WhereClause::Implemented(tr) => { 335 chalk_ir::WhereClause::Implemented(tr) => {
266 if tr.trait_id == UNKNOWN_TRAIT {
267 // FIXME we need an Error enum on the Chalk side to avoid this
268 return GenericPredicate::Error;
269 }
270 GenericPredicate::Implemented(from_chalk(db, tr)) 336 GenericPredicate::Implemented(from_chalk(db, tr))
271 } 337 }
272 chalk_ir::WhereClause::ProjectionEq(projection_eq) => { 338 chalk_ir::WhereClause::ProjectionEq(projection_eq) => {
@@ -279,9 +345,9 @@ impl ToChalk for GenericPredicate {
279} 345}
280 346
281impl ToChalk for ProjectionTy { 347impl ToChalk for ProjectionTy {
282 type Chalk = chalk_ir::ProjectionTy<ChalkIr>; 348 type Chalk = chalk_ir::ProjectionTy<TypeFamily>;
283 349
284 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<ChalkIr> { 350 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::ProjectionTy<TypeFamily> {
285 chalk_ir::ProjectionTy { 351 chalk_ir::ProjectionTy {
286 associated_ty_id: self.associated_ty.to_chalk(db), 352 associated_ty_id: self.associated_ty.to_chalk(db),
287 parameters: self.parameters.to_chalk(db), 353 parameters: self.parameters.to_chalk(db),
@@ -290,7 +356,7 @@ impl ToChalk for ProjectionTy {
290 356
291 fn from_chalk( 357 fn from_chalk(
292 db: &impl HirDatabase, 358 db: &impl HirDatabase,
293 projection_ty: chalk_ir::ProjectionTy<ChalkIr>, 359 projection_ty: chalk_ir::ProjectionTy<TypeFamily>,
294 ) -> ProjectionTy { 360 ) -> ProjectionTy {
295 ProjectionTy { 361 ProjectionTy {
296 associated_ty: from_chalk(db, projection_ty.associated_ty_id), 362 associated_ty: from_chalk(db, projection_ty.associated_ty_id),
@@ -300,31 +366,31 @@ impl ToChalk for ProjectionTy {
300} 366}
301 367
302impl ToChalk for super::ProjectionPredicate { 368impl ToChalk for super::ProjectionPredicate {
303 type Chalk = chalk_ir::Normalize<ChalkIr>; 369 type Chalk = chalk_ir::Normalize<TypeFamily>;
304 370
305 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<ChalkIr> { 371 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Normalize<TypeFamily> {
306 chalk_ir::Normalize { 372 chalk_ir::Normalize {
307 projection: self.projection_ty.to_chalk(db), 373 projection: self.projection_ty.to_chalk(db),
308 ty: self.ty.to_chalk(db), 374 ty: self.ty.to_chalk(db),
309 } 375 }
310 } 376 }
311 377
312 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<ChalkIr>) -> Self { 378 fn from_chalk(_db: &impl HirDatabase, _normalize: chalk_ir::Normalize<TypeFamily>) -> Self {
313 unimplemented!() 379 unimplemented!()
314 } 380 }
315} 381}
316 382
317impl ToChalk for Obligation { 383impl ToChalk for Obligation {
318 type Chalk = chalk_ir::DomainGoal<ChalkIr>; 384 type Chalk = chalk_ir::DomainGoal<TypeFamily>;
319 385
320 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<ChalkIr> { 386 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::DomainGoal<TypeFamily> {
321 match self { 387 match self {
322 Obligation::Trait(tr) => tr.to_chalk(db).cast(), 388 Obligation::Trait(tr) => tr.to_chalk(db).cast(),
323 Obligation::Projection(pr) => pr.to_chalk(db).cast(), 389 Obligation::Projection(pr) => pr.to_chalk(db).cast(),
324 } 390 }
325 } 391 }
326 392
327 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<ChalkIr>) -> Self { 393 fn from_chalk(_db: &impl HirDatabase, _goal: chalk_ir::DomainGoal<TypeFamily>) -> Self {
328 unimplemented!() 394 unimplemented!()
329 } 395 }
330} 396}
@@ -348,16 +414,17 @@ where
348} 414}
349 415
350impl ToChalk for Arc<super::TraitEnvironment> { 416impl ToChalk for Arc<super::TraitEnvironment> {
351 type Chalk = chalk_ir::Environment<ChalkIr>; 417 type Chalk = chalk_ir::Environment<TypeFamily>;
352 418
353 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<ChalkIr> { 419 fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::Environment<TypeFamily> {
354 let mut clauses = Vec::new(); 420 let mut clauses = Vec::new();
355 for pred in &self.predicates { 421 for pred in &self.predicates {
356 if pred.is_error() { 422 if pred.is_error() {
357 // for env, we just ignore errors 423 // for env, we just ignore errors
358 continue; 424 continue;
359 } 425 }
360 let program_clause: chalk_ir::ProgramClause<ChalkIr> = pred.clone().to_chalk(db).cast(); 426 let program_clause: chalk_ir::ProgramClause<TypeFamily> =
427 pred.clone().to_chalk(db).cast();
361 clauses.push(program_clause.into_from_env_clause()); 428 clauses.push(program_clause.into_from_env_clause());
362 } 429 }
363 chalk_ir::Environment::new().add_clauses(clauses) 430 chalk_ir::Environment::new().add_clauses(clauses)
@@ -365,7 +432,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
365 432
366 fn from_chalk( 433 fn from_chalk(
367 _db: &impl HirDatabase, 434 _db: &impl HirDatabase,
368 _env: chalk_ir::Environment<ChalkIr>, 435 _env: chalk_ir::Environment<TypeFamily>,
369 ) -> Arc<super::TraitEnvironment> { 436 ) -> Arc<super::TraitEnvironment> {
370 unimplemented!() 437 unimplemented!()
371 } 438 }
@@ -373,7 +440,7 @@ impl ToChalk for Arc<super::TraitEnvironment> {
373 440
374impl<T: ToChalk> ToChalk for super::InEnvironment<T> 441impl<T: ToChalk> ToChalk for super::InEnvironment<T>
375where 442where
376 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = ChalkIr>, 443 T::Chalk: chalk_ir::family::HasTypeFamily<TypeFamily = TypeFamily>,
377{ 444{
378 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 445 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
379 446
@@ -395,6 +462,51 @@ where
395 } 462 }
396} 463}
397 464
465impl ToChalk for builtin::BuiltinImplData {
466 type Chalk = ImplDatum;
467
468 fn to_chalk(self, db: &impl HirDatabase) -> ImplDatum {
469 let impl_type = chalk_rust_ir::ImplType::External;
470 let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect();
471
472 let impl_datum_bound =
473 chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses };
474 let associated_ty_value_ids =
475 self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect();
476 chalk_rust_ir::ImplDatum {
477 binders: make_binders(impl_datum_bound, self.num_vars),
478 impl_type,
479 polarity: chalk_rust_ir::Polarity::Positive,
480 associated_ty_value_ids,
481 }
482 }
483
484 fn from_chalk(_db: &impl HirDatabase, _data: ImplDatum) -> Self {
485 unimplemented!()
486 }
487}
488
489impl ToChalk for builtin::BuiltinImplAssocTyValueData {
490 type Chalk = AssociatedTyValue;
491
492 fn to_chalk(self, db: &impl HirDatabase) -> AssociatedTyValue {
493 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: self.value.to_chalk(db) };
494
495 chalk_rust_ir::AssociatedTyValue {
496 associated_ty_id: self.assoc_ty_id.to_chalk(db),
497 impl_id: self.impl_.to_chalk(db),
498 value: make_binders(value_bound, self.num_vars),
499 }
500 }
501
502 fn from_chalk(
503 _db: &impl HirDatabase,
504 _data: AssociatedTyValue,
505 ) -> builtin::BuiltinImplAssocTyValueData {
506 unimplemented!()
507 }
508}
509
398fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 510fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> {
399 chalk_ir::Binders { 511 chalk_ir::Binders {
400 value, 512 value,
@@ -406,46 +518,46 @@ fn convert_where_clauses(
406 db: &impl HirDatabase, 518 db: &impl HirDatabase,
407 def: GenericDefId, 519 def: GenericDefId,
408 substs: &Substs, 520 substs: &Substs,
409) -> Vec<chalk_ir::QuantifiedWhereClause<ChalkIr>> { 521) -> Vec<chalk_ir::QuantifiedWhereClause<TypeFamily>> {
410 let generic_predicates = db.generic_predicates(def); 522 let generic_predicates = db.generic_predicates(def);
411 let mut result = Vec::with_capacity(generic_predicates.len()); 523 let mut result = Vec::with_capacity(generic_predicates.len());
412 for pred in generic_predicates.iter() { 524 for pred in generic_predicates.iter() {
413 if pred.is_error() { 525 if pred.is_error() {
414 // HACK: Return just the single predicate (which is always false 526 // skip errored predicates completely
415 // anyway), otherwise Chalk can easily get into slow situations 527 continue;
416 return vec![pred.clone().subst(substs).to_chalk(db)];
417 } 528 }
418 result.push(pred.clone().subst(substs).to_chalk(db)); 529 result.push(pred.clone().subst(substs).to_chalk(db));
419 } 530 }
420 result 531 result
421} 532}
422 533
423impl<'a, DB> chalk_solve::RustIrDatabase<ChalkIr> for ChalkContext<'a, DB> 534impl<'a, DB> chalk_solve::RustIrDatabase<TypeFamily> for ChalkContext<'a, DB>
424where 535where
425 DB: HirDatabase, 536 DB: HirDatabase,
426{ 537{
427 fn associated_ty_data(&self, id: TypeId) -> Arc<AssociatedTyDatum<ChalkIr>> { 538 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
428 self.db.associated_ty_data(id) 539 self.db.associated_ty_data(id)
429 } 540 }
430 fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum<ChalkIr>> { 541 fn trait_datum(&self, trait_id: TraitId) -> Arc<TraitDatum> {
431 self.db.trait_datum(self.krate, trait_id) 542 self.db.trait_datum(self.krate, trait_id)
432 } 543 }
433 fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum<ChalkIr>> { 544 fn struct_datum(&self, struct_id: StructId) -> Arc<StructDatum> {
434 self.db.struct_datum(self.krate, struct_id) 545 self.db.struct_datum(self.krate, struct_id)
435 } 546 }
436 fn impl_datum(&self, impl_id: chalk_ir::ImplId) -> Arc<ImplDatum<ChalkIr>> { 547 fn impl_datum(&self, impl_id: ImplId) -> Arc<ImplDatum> {
437 self.db.impl_datum(self.krate, impl_id) 548 self.db.impl_datum(self.krate, impl_id)
438 } 549 }
439 fn impls_for_trait( 550 fn impls_for_trait(
440 &self, 551 &self,
441 trait_id: chalk_ir::TraitId, 552 trait_id: TraitId,
442 parameters: &[Parameter<ChalkIr>], 553 parameters: &[Parameter<TypeFamily>],
443 ) -> Vec<chalk_ir::ImplId> { 554 ) -> Vec<ImplId> {
444 debug!("impls_for_trait {:?}", trait_id); 555 debug!("impls_for_trait {:?}", trait_id);
445 if trait_id == UNKNOWN_TRAIT { 556 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id);
446 return Vec::new(); 557
447 } 558 // Note: Since we're using impls_for_trait, only impls where the trait
448 let trait_: TraitId = from_chalk(self.db, trait_id); 559 // can be resolved should ever reach Chalk. `impl_datum` relies on that
560 // and will panic if the trait can't be resolved.
449 let mut result: Vec<_> = self 561 let mut result: Vec<_> = self
450 .db 562 .db
451 .impls_for_trait(self.krate, trait_.into()) 563 .impls_for_trait(self.krate, trait_.into())
@@ -456,62 +568,47 @@ where
456 .collect(); 568 .collect();
457 569
458 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone()); 570 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref().clone());
459 if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { 571
460 for &fn_trait in 572 builtin::get_builtin_impls(self.db, self.krate, &ty, trait_, |i| {
461 [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() 573 result.push(i.to_chalk(self.db))
462 { 574 });
463 if let Some(actual_trait) = get_fn_trait(self.db, self.krate, fn_trait) {
464 if trait_ == actual_trait {
465 let impl_ = super::ClosureFnTraitImplData { def, expr, fn_trait };
466 result.push(Impl::ClosureFnTraitImpl(impl_).to_chalk(self.db));
467 }
468 }
469 }
470 }
471 575
472 debug!("impls_for_trait returned {} impls", result.len()); 576 debug!("impls_for_trait returned {} impls", result.len());
473 result 577 result
474 } 578 }
475 fn impl_provided_for( 579 fn impl_provided_for(&self, auto_trait_id: TraitId, struct_id: StructId) -> bool {
476 &self,
477 auto_trait_id: chalk_ir::TraitId,
478 struct_id: chalk_ir::StructId,
479 ) -> bool {
480 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id); 580 debug!("impl_provided_for {:?}, {:?}", auto_trait_id, struct_id);
481 false // FIXME 581 false // FIXME
482 } 582 }
483 fn type_name(&self, _id: TypeKindId) -> Identifier { 583 fn associated_ty_value(&self, id: AssociatedTyValueId) -> Arc<AssociatedTyValue> {
484 unimplemented!()
485 }
486 fn associated_ty_value(
487 &self,
488 id: chalk_rust_ir::AssociatedTyValueId,
489 ) -> Arc<AssociatedTyValue<ChalkIr>> {
490 self.db.associated_ty_value(self.krate.into(), id) 584 self.db.associated_ty_value(self.krate.into(), id)
491 } 585 }
492 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<ChalkIr>> { 586 fn custom_clauses(&self) -> Vec<chalk_ir::ProgramClause<TypeFamily>> {
493 vec![] 587 vec![]
494 } 588 }
495 fn local_impls_to_coherence_check( 589 fn local_impls_to_coherence_check(&self, _trait_id: TraitId) -> Vec<ImplId> {
496 &self,
497 _trait_id: chalk_ir::TraitId,
498 ) -> Vec<chalk_ir::ImplId> {
499 // We don't do coherence checking (yet) 590 // We don't do coherence checking (yet)
500 unimplemented!() 591 unimplemented!()
501 } 592 }
593 fn as_struct_id(&self, id: &TypeName<TypeFamily>) -> Option<StructId> {
594 match id {
595 TypeName::Struct(struct_id) => Some(*struct_id),
596 _ => None,
597 }
598 }
502} 599}
503 600
504pub(crate) fn associated_ty_data_query( 601pub(crate) fn associated_ty_data_query(
505 db: &impl HirDatabase, 602 db: &impl HirDatabase,
506 id: TypeId, 603 id: AssocTypeId,
507) -> Arc<AssociatedTyDatum<ChalkIr>> { 604) -> Arc<AssociatedTyDatum> {
508 debug!("associated_ty_data {:?}", id); 605 debug!("associated_ty_data {:?}", id);
509 let type_alias: TypeAliasId = from_chalk(db, id); 606 let type_alias: TypeAliasId = from_chalk(db, id);
510 let trait_ = match type_alias.lookup(db).container { 607 let trait_ = match type_alias.lookup(db).container {
511 ContainerId::TraitId(t) => t, 608 AssocContainerId::TraitId(t) => t,
512 _ => panic!("associated type not in trait"), 609 _ => panic!("associated type not in trait"),
513 }; 610 };
514 let generic_params = db.generic_params(type_alias.into()); 611 let generic_params = generics(db, type_alias.into());
515 let bound_data = chalk_rust_ir::AssociatedTyDatumBound { 612 let bound_data = chalk_rust_ir::AssociatedTyDatumBound {
516 // FIXME add bounds and where clauses 613 // FIXME add bounds and where clauses
517 bounds: vec![], 614 bounds: vec![],
@@ -521,7 +618,7 @@ pub(crate) fn associated_ty_data_query(
521 trait_id: trait_.to_chalk(db), 618 trait_id: trait_.to_chalk(db),
522 id, 619 id,
523 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()), 620 name: lalrpop_intern::intern(&db.type_alias_data(type_alias).name.to_string()),
524 binders: make_binders(bound_data, generic_params.count_params_including_parent()), 621 binders: make_binders(bound_data, generic_params.len()),
525 }; 622 };
526 Arc::new(datum) 623 Arc::new(datum)
527} 624}
@@ -529,35 +626,17 @@ pub(crate) fn associated_ty_data_query(
529pub(crate) fn trait_datum_query( 626pub(crate) fn trait_datum_query(
530 db: &impl HirDatabase, 627 db: &impl HirDatabase,
531 krate: CrateId, 628 krate: CrateId,
532 trait_id: chalk_ir::TraitId, 629 trait_id: TraitId,
533) -> Arc<TraitDatum<ChalkIr>> { 630) -> Arc<TraitDatum> {
534 debug!("trait_datum {:?}", trait_id); 631 debug!("trait_datum {:?}", trait_id);
535 if trait_id == UNKNOWN_TRAIT { 632 let trait_: hir_def::TraitId = from_chalk(db, trait_id);
536 let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses: Vec::new() };
537
538 let flags = chalk_rust_ir::TraitFlags {
539 auto: false,
540 marker: false,
541 upstream: true,
542 fundamental: false,
543 non_enumerable: true,
544 coinductive: false,
545 };
546 return Arc::new(TraitDatum {
547 id: trait_id,
548 binders: make_binders(trait_datum_bound, 1),
549 flags,
550 associated_ty_ids: vec![],
551 });
552 }
553 let trait_: TraitId = from_chalk(db, trait_id);
554 let trait_data = db.trait_data(trait_); 633 let trait_data = db.trait_data(trait_);
555 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 634 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
556 let generic_params = db.generic_params(trait_.into()); 635 let generic_params = generics(db, trait_.into());
557 let bound_vars = Substs::bound_vars(&generic_params); 636 let bound_vars = Substs::bound_vars(&generic_params);
558 let flags = chalk_rust_ir::TraitFlags { 637 let flags = chalk_rust_ir::TraitFlags {
559 auto: trait_data.auto, 638 auto: trait_data.auto,
560 upstream: trait_.module(db).krate != krate, 639 upstream: trait_.lookup(db).container.module(db).krate != krate,
561 non_enumerable: true, 640 non_enumerable: true,
562 coinductive: false, // only relevant for Chalk testing 641 coinductive: false, // only relevant for Chalk testing
563 // FIXME set these flags correctly 642 // FIXME set these flags correctly
@@ -580,17 +659,17 @@ pub(crate) fn trait_datum_query(
580pub(crate) fn struct_datum_query( 659pub(crate) fn struct_datum_query(
581 db: &impl HirDatabase, 660 db: &impl HirDatabase,
582 krate: CrateId, 661 krate: CrateId,
583 struct_id: chalk_ir::StructId, 662 struct_id: StructId,
584) -> Arc<StructDatum<ChalkIr>> { 663) -> Arc<StructDatum> {
585 debug!("struct_datum {:?}", struct_id); 664 debug!("struct_datum {:?}", struct_id);
586 let type_ctor: TypeCtor = from_chalk(db, struct_id); 665 let type_ctor: TypeCtor = from_chalk(db, TypeName::Struct(struct_id));
587 debug!("struct {:?} = {:?}", struct_id, type_ctor); 666 debug!("struct {:?} = {:?}", struct_id, type_ctor);
588 let num_params = type_ctor.num_ty_params(db); 667 let num_params = type_ctor.num_ty_params(db);
589 let upstream = type_ctor.krate(db) != Some(krate); 668 let upstream = type_ctor.krate(db) != Some(krate);
590 let where_clauses = type_ctor 669 let where_clauses = type_ctor
591 .as_generic_def() 670 .as_generic_def()
592 .map(|generic_def| { 671 .map(|generic_def| {
593 let generic_params = db.generic_params(generic_def.into()); 672 let generic_params = generics(db, generic_def.into());
594 let bound_vars = Substs::bound_vars(&generic_params); 673 let bound_vars = Substs::bound_vars(&generic_params);
595 convert_where_clauses(db, generic_def, &bound_vars) 674 convert_where_clauses(db, generic_def, &bound_vars)
596 }) 675 })
@@ -612,35 +691,34 @@ pub(crate) fn struct_datum_query(
612pub(crate) fn impl_datum_query( 691pub(crate) fn impl_datum_query(
613 db: &impl HirDatabase, 692 db: &impl HirDatabase,
614 krate: CrateId, 693 krate: CrateId,
615 impl_id: chalk_ir::ImplId, 694 impl_id: ImplId,
616) -> Arc<ImplDatum<ChalkIr>> { 695) -> Arc<ImplDatum> {
617 let _p = ra_prof::profile("impl_datum"); 696 let _p = ra_prof::profile("impl_datum");
618 debug!("impl_datum {:?}", impl_id); 697 debug!("impl_datum {:?}", impl_id);
619 let impl_: Impl = from_chalk(db, impl_id); 698 let impl_: Impl = from_chalk(db, impl_id);
620 match impl_ { 699 match impl_ {
621 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block), 700 Impl::ImplBlock(impl_block) => impl_block_datum(db, krate, impl_id, impl_block),
622 Impl::ClosureFnTraitImpl(data) => closure_fn_trait_impl_datum(db, krate, data), 701 _ => Arc::new(builtin::impl_datum(db, krate, impl_).to_chalk(db)),
623 } 702 }
624 .unwrap_or_else(invalid_impl_datum)
625} 703}
626 704
627fn impl_block_datum( 705fn impl_block_datum(
628 db: &impl HirDatabase, 706 db: &impl HirDatabase,
629 krate: CrateId, 707 krate: CrateId,
630 chalk_id: chalk_ir::ImplId, 708 chalk_id: ImplId,
631 impl_id: ImplId, 709 impl_id: hir_def::ImplId,
632) -> Option<Arc<ImplDatum<ChalkIr>>> { 710) -> Arc<ImplDatum> {
633 let trait_ref = match db.impl_ty(impl_id) { 711 let trait_ref = db
634 ImplTy::TraitRef(it) => it, 712 .impl_trait(impl_id)
635 ImplTy::Inherent(_) => return None, 713 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
636 }; 714 .expect("invalid impl passed to Chalk");
637 let impl_data = db.impl_data(impl_id); 715 let impl_data = db.impl_data(impl_id);
638 716
639 let generic_params = db.generic_params(impl_id.into()); 717 let generic_params = generics(db, impl_id.into());
640 let bound_vars = Substs::bound_vars(&generic_params); 718 let bound_vars = Substs::bound_vars(&generic_params);
641 let trait_ref = trait_ref.subst(&bound_vars); 719 let trait_ref = trait_ref.subst(&bound_vars);
642 let trait_ = trait_ref.trait_; 720 let trait_ = trait_ref.trait_;
643 let impl_type = if impl_id.module(db).krate == krate { 721 let impl_type = if impl_id.lookup(db).container.module(db).krate == krate {
644 chalk_rust_ir::ImplType::Local 722 chalk_rust_ir::ImplType::Local
645 } else { 723 } else {
646 chalk_rust_ir::ImplType::External 724 chalk_rust_ir::ImplType::External
@@ -685,94 +763,20 @@ fn impl_block_datum(
685 polarity, 763 polarity,
686 associated_ty_value_ids, 764 associated_ty_value_ids,
687 }; 765 };
688 Some(Arc::new(impl_datum))
689}
690
691fn invalid_impl_datum() -> Arc<ImplDatum<ChalkIr>> {
692 let trait_ref = chalk_ir::TraitRef {
693 trait_id: UNKNOWN_TRAIT,
694 parameters: vec![chalk_ir::TyData::BoundVar(0).cast().intern().cast()],
695 };
696 let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses: Vec::new() };
697 let impl_datum = ImplDatum {
698 binders: make_binders(impl_datum_bound, 1),
699 impl_type: chalk_rust_ir::ImplType::External,
700 polarity: chalk_rust_ir::Polarity::Positive,
701 associated_ty_value_ids: Vec::new(),
702 };
703 Arc::new(impl_datum) 766 Arc::new(impl_datum)
704} 767}
705 768
706fn closure_fn_trait_impl_datum(
707 db: &impl HirDatabase,
708 krate: CrateId,
709 data: super::ClosureFnTraitImplData,
710) -> Option<Arc<ImplDatum<ChalkIr>>> {
711 // for some closure |X, Y| -> Z:
712 // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V }
713
714 let trait_ = get_fn_trait(db, krate, data.fn_trait)?; // get corresponding fn trait
715
716 // validate FnOnce trait, since we need it in the assoc ty value definition
717 // and don't want to return a valid value only to find out later that FnOnce
718 // is broken
719 let fn_once_trait = get_fn_trait(db, krate, super::FnTrait::FnOnce)?;
720 let _output = db.trait_data(fn_once_trait).associated_type_by_name(&name::OUTPUT_TYPE)?;
721
722 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
723 Expr::Lambda { args, .. } => args.len() as u16,
724 _ => {
725 log::warn!("closure for closure type {:?} not found", data);
726 0
727 }
728 };
729
730 let arg_ty = Ty::apply(
731 TypeCtor::Tuple { cardinality: num_args },
732 Substs::builder(num_args as usize).fill_with_bound_vars(0).build(),
733 );
734 let sig_ty = Ty::apply(
735 TypeCtor::FnPtr { num_args },
736 Substs::builder(num_args as usize + 1).fill_with_bound_vars(0).build(),
737 );
738
739 let self_ty = Ty::apply_one(TypeCtor::Closure { def: data.def, expr: data.expr }, sig_ty);
740
741 let trait_ref = TraitRef {
742 trait_: trait_.into(),
743 substs: Substs::build_for_def(db, trait_).push(self_ty).push(arg_ty).build(),
744 };
745
746 let output_ty_id = AssocTyValue::ClosureFnTraitImplOutput(data.clone()).to_chalk(db);
747
748 let impl_type = chalk_rust_ir::ImplType::External;
749
750 let impl_datum_bound = chalk_rust_ir::ImplDatumBound {
751 trait_ref: trait_ref.to_chalk(db),
752 where_clauses: Vec::new(),
753 };
754 let impl_datum = ImplDatum {
755 binders: make_binders(impl_datum_bound, num_args as usize + 1),
756 impl_type,
757 polarity: chalk_rust_ir::Polarity::Positive,
758 associated_ty_value_ids: vec![output_ty_id],
759 };
760 Some(Arc::new(impl_datum))
761}
762
763pub(crate) fn associated_ty_value_query( 769pub(crate) fn associated_ty_value_query(
764 db: &impl HirDatabase, 770 db: &impl HirDatabase,
765 krate: CrateId, 771 krate: CrateId,
766 id: chalk_rust_ir::AssociatedTyValueId, 772 id: AssociatedTyValueId,
767) -> Arc<chalk_rust_ir::AssociatedTyValue<ChalkIr>> { 773) -> Arc<AssociatedTyValue> {
768 let data: AssocTyValue = from_chalk(db, id); 774 let data: AssocTyValue = from_chalk(db, id);
769 match data { 775 match data {
770 AssocTyValue::TypeAlias(type_alias) => { 776 AssocTyValue::TypeAlias(type_alias) => {
771 type_alias_associated_ty_value(db, krate, type_alias) 777 type_alias_associated_ty_value(db, krate, type_alias)
772 } 778 }
773 AssocTyValue::ClosureFnTraitImplOutput(data) => { 779 _ => Arc::new(builtin::associated_ty_value(db, krate, data).to_chalk(db)),
774 closure_fn_trait_output_assoc_ty_value(db, krate, data)
775 }
776 } 780 }
777} 781}
778 782
@@ -780,24 +784,20 @@ fn type_alias_associated_ty_value(
780 db: &impl HirDatabase, 784 db: &impl HirDatabase,
781 _krate: CrateId, 785 _krate: CrateId,
782 type_alias: TypeAliasId, 786 type_alias: TypeAliasId,
783) -> Arc<AssociatedTyValue<ChalkIr>> { 787) -> Arc<AssociatedTyValue> {
784 let type_alias_data = db.type_alias_data(type_alias); 788 let type_alias_data = db.type_alias_data(type_alias);
785 let impl_id = match type_alias.lookup(db).container { 789 let impl_id = match type_alias.lookup(db).container {
786 ContainerId::ImplId(it) => it, 790 AssocContainerId::ImplId(it) => it,
787 _ => panic!("assoc ty value should be in impl"), 791 _ => panic!("assoc ty value should be in impl"),
788 }; 792 };
789 793
790 let trait_ref = match db.impl_ty(impl_id) { 794 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist"); // we don't return any assoc ty values if the impl'd trait can't be resolved
791 ImplTy::TraitRef(it) => it,
792 // we don't return any assoc ty values if the impl'd trait can't be resolved
793 ImplTy::Inherent(_) => panic!("assoc ty value should not exist"),
794 };
795 795
796 let assoc_ty = db 796 let assoc_ty = db
797 .trait_data(trait_ref.trait_) 797 .trait_data(trait_ref.trait_)
798 .associated_type_by_name(&type_alias_data.name) 798 .associated_type_by_name(&type_alias_data.name)
799 .expect("assoc ty value should not exist"); // validated when building the impl data as well 799 .expect("assoc ty value should not exist"); // validated when building the impl data as well
800 let generic_params = db.generic_params(impl_id.into()); 800 let generic_params = generics(db, impl_id.into());
801 let bound_vars = Substs::bound_vars(&generic_params); 801 let bound_vars = Substs::bound_vars(&generic_params);
802 let ty = db.ty(type_alias.into()).subst(&bound_vars); 802 let ty = db.ty(type_alias.into()).subst(&bound_vars);
803 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) }; 803 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.to_chalk(db) };
@@ -809,53 +809,6 @@ fn type_alias_associated_ty_value(
809 Arc::new(value) 809 Arc::new(value)
810} 810}
811 811
812fn closure_fn_trait_output_assoc_ty_value(
813 db: &impl HirDatabase,
814 krate: CrateId,
815 data: super::ClosureFnTraitImplData,
816) -> Arc<AssociatedTyValue<ChalkIr>> {
817 let impl_id = Impl::ClosureFnTraitImpl(data.clone()).to_chalk(db);
818
819 let num_args: u16 = match &db.body(data.def.into())[data.expr] {
820 Expr::Lambda { args, .. } => args.len() as u16,
821 _ => {
822 log::warn!("closure for closure type {:?} not found", data);
823 0
824 }
825 };
826
827 let output_ty = Ty::Bound(num_args.into());
828
829 let fn_once_trait =
830 get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist");
831
832 let output_ty_id = db
833 .trait_data(fn_once_trait)
834 .associated_type_by_name(&name::OUTPUT_TYPE)
835 .expect("assoc ty value should not exist");
836
837 let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: output_ty.to_chalk(db) };
838
839 let value = chalk_rust_ir::AssociatedTyValue {
840 associated_ty_id: output_ty_id.to_chalk(db),
841 impl_id,
842 value: make_binders(value_bound, num_args as usize + 1),
843 };
844 Arc::new(value)
845}
846
847fn get_fn_trait(
848 db: &impl HirDatabase,
849 krate: CrateId,
850 fn_trait: super::FnTrait,
851) -> Option<TraitId> {
852 let target = db.lang_item(krate, fn_trait.lang_item_name().into())?;
853 match target {
854 LangItemTarget::TraitId(t) => Some(t),
855 _ => None,
856 }
857}
858
859fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T { 812fn id_from_chalk<T: InternKey>(chalk_id: chalk_ir::RawId) -> T {
860 T::from_intern_id(InternId::from(chalk_id.index)) 813 T::from_intern_id(InternId::from(chalk_id.index))
861} 814}
@@ -863,27 +816,27 @@ fn id_to_chalk<T: InternKey>(salsa_id: T) -> chalk_ir::RawId {
863 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() } 816 chalk_ir::RawId { index: salsa_id.as_intern_id().as_u32() }
864} 817}
865 818
866impl From<chalk_ir::StructId> for crate::TypeCtorId { 819impl From<StructId> for crate::TypeCtorId {
867 fn from(struct_id: chalk_ir::StructId) -> Self { 820 fn from(struct_id: StructId) -> Self {
868 id_from_chalk(struct_id.0) 821 InternKey::from_intern_id(struct_id.0)
869 } 822 }
870} 823}
871 824
872impl From<crate::TypeCtorId> for chalk_ir::StructId { 825impl From<crate::TypeCtorId> for StructId {
873 fn from(type_ctor_id: crate::TypeCtorId) -> Self { 826 fn from(type_ctor_id: crate::TypeCtorId) -> Self {
874 chalk_ir::StructId(id_to_chalk(type_ctor_id)) 827 chalk_ir::StructId(type_ctor_id.as_intern_id())
875 } 828 }
876} 829}
877 830
878impl From<chalk_ir::ImplId> for crate::traits::GlobalImplId { 831impl From<ImplId> for crate::traits::GlobalImplId {
879 fn from(impl_id: chalk_ir::ImplId) -> Self { 832 fn from(impl_id: ImplId) -> Self {
880 id_from_chalk(impl_id.0) 833 InternKey::from_intern_id(impl_id.0)
881 } 834 }
882} 835}
883 836
884impl From<crate::traits::GlobalImplId> for chalk_ir::ImplId { 837impl From<crate::traits::GlobalImplId> for ImplId {
885 fn from(impl_id: crate::traits::GlobalImplId) -> Self { 838 fn from(impl_id: crate::traits::GlobalImplId) -> Self {
886 chalk_ir::ImplId(id_to_chalk(impl_id)) 839 chalk_ir::ImplId(impl_id.as_intern_id())
887 } 840 }
888} 841}
889 842
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index e4ba890ef..0b1806a84 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -5,14 +5,14 @@ use std::sync::Arc;
5use hir_def::{ 5use hir_def::{
6 adt::VariantData, 6 adt::VariantData,
7 db::DefDatabase, 7 db::DefDatabase,
8 generics::{GenericParams, TypeParamData},
9 path::Path,
8 resolver::{HasResolver, TypeNs}, 10 resolver::{HasResolver, TypeNs},
9 type_ref::TypeRef, 11 type_ref::TypeRef,
10 TraitId, TypeAliasId, VariantId, 12 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId,
11}; 13};
12use hir_expand::name::{self, Name}; 14use hir_expand::name::{name, Name};
13 15
14// FIXME: this is wrong, b/c it can't express `trait T: PartialEq<()>`.
15// We should return a `TraitREf` here.
16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> { 16fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
17 let resolver = trait_.resolver(db); 17 let resolver = trait_.resolver(db);
18 // returning the iterator directly doesn't easily work because of 18 // returning the iterator directly doesn't easily work because of
@@ -23,10 +23,10 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
23 .where_predicates 23 .where_predicates
24 .iter() 24 .iter()
25 .filter_map(|pred| match &pred.type_ref { 25 .filter_map(|pred| match &pred.type_ref {
26 TypeRef::Path(p) if p.as_ident() == Some(&name::SELF_TYPE) => pred.bound.as_path(), 26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(),
27 _ => None, 27 _ => None,
28 }) 28 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path) { 29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
30 Some(TypeNs::TraitId(t)) => Some(t), 30 Some(TypeNs::TraitId(t)) => Some(t),
31 _ => None, 31 _ => None,
32 }) 32 })
@@ -82,3 +82,81 @@ pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
82 } 82 }
83 Arc::get_mut(a).unwrap() 83 Arc::get_mut(a).unwrap()
84} 84}
85
86pub(crate) fn generics(db: &impl DefDatabase, def: GenericDefId) -> Generics {
87 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
88 Generics { def, params: db.generic_params(def), parent_generics }
89}
90
91pub(crate) struct Generics {
92 def: GenericDefId,
93 pub(crate) params: Arc<GenericParams>,
94 parent_generics: Option<Box<Generics>>,
95}
96
97impl Generics {
98 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
99 self.parent_generics
100 .as_ref()
101 .into_iter()
102 .flat_map(|it| it.params.types.iter())
103 .chain(self.params.types.iter())
104 .enumerate()
105 .map(|(i, (_local_id, p))| (i as u32, p))
106 }
107
108 pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a {
109 self.parent_generics
110 .as_ref()
111 .into_iter()
112 .flat_map(|it| it.params.types.iter())
113 .enumerate()
114 .map(|(i, (_local_id, p))| (i as u32, p))
115 }
116
117 pub(crate) fn len(&self) -> usize {
118 self.len_split().0
119 }
120 /// (total, parents, child)
121 pub(crate) fn len_split(&self) -> (usize, usize, usize) {
122 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
123 let child = self.params.types.len();
124 (parent + child, parent, child)
125 }
126 pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 {
127 self.find_param(param).0
128 }
129 pub(crate) fn param_name(&self, param: TypeParamId) -> Name {
130 self.find_param(param).1.name.clone()
131 }
132 fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) {
133 if param.parent == self.def {
134 let (idx, (_local_id, data)) = self
135 .params
136 .types
137 .iter()
138 .enumerate()
139 .find(|(_, (idx, _))| *idx == param.local_id)
140 .unwrap();
141 let (_total, parent_len, _child) = self.len_split();
142 return ((parent_len + idx) as u32, data);
143 }
144 self.parent_generics.as_ref().unwrap().find_param(param)
145 }
146}
147
148fn parent_generic_def(db: &impl DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
149 let container = match def {
150 GenericDefId::FunctionId(it) => it.lookup(db).container,
151 GenericDefId::TypeAliasId(it) => it.lookup(db).container,
152 GenericDefId::ConstId(it) => it.lookup(db).container,
153 GenericDefId::EnumVariantId(it) => return Some(it.parent.into()),
154 GenericDefId::AdtId(_) | GenericDefId::TraitId(_) | GenericDefId::ImplId(_) => return None,
155 };
156
157 match container {
158 AssocContainerId::ImplId(it) => Some(it.into()),
159 AssocContainerId::TraitId(it) => Some(it.into()),
160 AssocContainerId::ContainerId(_) => None,
161 }
162}
diff --git a/crates/ra_ide/Cargo.toml b/crates/ra_ide/Cargo.toml
index e6383dd35..e3439ae31 100644
--- a/crates/ra_ide/Cargo.toml
+++ b/crates/ra_ide/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
11wasm = [] 11wasm = []
12 12
13[dependencies] 13[dependencies]
14either = "1.5"
14format-buf = "1.0.0" 15format-buf = "1.0.0"
15itertools = "0.8.0" 16itertools = "0.8.0"
16join_to_string = "0.1.3" 17join_to_string = "0.1.3"
diff --git a/crates/ra_ide/src/call_info.rs b/crates/ra_ide/src/call_info.rs
index d559dc4d0..2c2b6fa48 100644
--- a/crates/ra_ide/src/call_info.rs
+++ b/crates/ra_ide/src/call_info.rs
@@ -1,24 +1,26 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::SourceDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ 4use ra_syntax::{
5 algo::ancestors_at_offset,
6 ast::{self, ArgListOwner}, 5 ast::{self, ArgListOwner},
7 match_ast, AstNode, SyntaxNode, TextUnit, 6 match_ast, AstNode, SyntaxNode,
8}; 7};
9use test_utils::tested_by; 8use test_utils::tested_by;
10 9
11use crate::{db::RootDatabase, CallInfo, FilePosition, FunctionSignature}; 10use crate::{
11 db::RootDatabase, expand::descend_into_macros, CallInfo, FilePosition, FunctionSignature,
12};
12 13
13/// Computes parameter information for the given call expression. 14/// Computes parameter information for the given call expression.
14pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> { 15pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
15 let parse = db.parse(position.file_id); 16 let file = db.parse_or_expand(position.file_id.into())?;
16 let syntax = parse.tree().syntax().clone(); 17 let token = file.token_at_offset(position.offset).next()?;
18 let token = descend_into_macros(db, position.file_id, token);
17 19
18 // Find the calling expression and it's NameRef 20 // Find the calling expression and it's NameRef
19 let calling_node = FnCallNode::with_node(&syntax, position.offset)?; 21 let calling_node = FnCallNode::with_node(&token.value.parent())?;
20 let name_ref = calling_node.name_ref()?; 22 let name_ref = calling_node.name_ref()?;
21 let name_ref = hir::Source::new(position.file_id.into(), name_ref.syntax()); 23 let name_ref = token.with_value(name_ref.syntax());
22 24
23 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None); 25 let analyzer = hir::SourceAnalyzer::new(db, name_ref, None);
24 let (mut call_info, has_self) = match &calling_node { 26 let (mut call_info, has_self) = match &calling_node {
@@ -93,8 +95,8 @@ enum FnCallNode {
93} 95}
94 96
95impl FnCallNode { 97impl FnCallNode {
96 fn with_node(syntax: &SyntaxNode, offset: TextUnit) -> Option<FnCallNode> { 98 fn with_node(syntax: &SyntaxNode) -> Option<FnCallNode> {
97 ancestors_at_offset(syntax, offset).find_map(|node| { 99 syntax.ancestors().find_map(|node| {
98 match_ast! { 100 match_ast! {
99 match node { 101 match node {
100 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) }, 102 ast::CallExpr(it) => { Some(FnCallNode::CallExpr(it)) },
@@ -589,4 +591,25 @@ fn f() {
589 assert_eq!(info.label(), "foo!()"); 591 assert_eq!(info.label(), "foo!()");
590 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string())); 592 assert_eq!(info.doc().map(|it| it.into()), Some("empty macro".to_string()));
591 } 593 }
594
595 #[test]
596 fn fn_signature_for_call_in_macro() {
597 let info = call_info(
598 r#"
599 macro_rules! id {
600 ($($tt:tt)*) => { $($tt)* }
601 }
602 fn foo() {
603
604 }
605 id! {
606 fn bar() {
607 foo(<|>);
608 }
609 }
610 "#,
611 );
612
613 assert_eq!(info.label(), "fn foo()");
614 }
592} 615}
diff --git a/crates/ra_ide/src/change.rs b/crates/ra_ide/src/change.rs
index 4a76d1dd8..387a9cafb 100644
--- a/crates/ra_ide/src/change.rs
+++ b/crates/ra_ide/src/change.rs
@@ -270,7 +270,6 @@ impl RootDatabase {
270 270
271 self.query(hir::db::AstIdMapQuery).sweep(sweep); 271 self.query(hir::db::AstIdMapQuery).sweep(sweep);
272 272
273 self.query(hir::db::RawItemsWithSourceMapQuery).sweep(sweep);
274 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep); 273 self.query(hir::db::BodyWithSourceMapQuery).sweep(sweep);
275 274
276 self.query(hir::db::ExprScopesQuery).sweep(sweep); 275 self.query(hir::db::ExprScopesQuery).sweep(sweep);
@@ -309,7 +308,6 @@ impl RootDatabase {
309 hir::db::StructDataQuery 308 hir::db::StructDataQuery
310 hir::db::EnumDataQuery 309 hir::db::EnumDataQuery
311 hir::db::TraitDataQuery 310 hir::db::TraitDataQuery
312 hir::db::RawItemsWithSourceMapQuery
313 hir::db::RawItemsQuery 311 hir::db::RawItemsQuery
314 hir::db::CrateDefMapQuery 312 hir::db::CrateDefMapQuery
315 hir::db::GenericParamsQuery 313 hir::db::GenericParamsQuery
diff --git a/crates/ra_ide/src/completion/complete_dot.rs b/crates/ra_ide/src/completion/complete_dot.rs
index b6fe48627..294964887 100644
--- a/crates/ra_ide/src/completion/complete_dot.rs
+++ b/crates/ra_ide/src/completion/complete_dot.rs
@@ -27,7 +27,7 @@ pub(super) fn complete_dot(acc: &mut Completions, ctx: &CompletionContext) {
27 complete_methods(acc, ctx, &receiver_ty); 27 complete_methods(acc, ctx, &receiver_ty);
28 28
29 // Suggest .await syntax for types that implement Future trait 29 // Suggest .await syntax for types that implement Future trait
30 if ctx.analyzer.impls_future(ctx.db, receiver_ty.into_ty()) { 30 if ctx.analyzer.impls_future(ctx.db, receiver_ty) {
31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await") 31 CompletionItem::new(CompletionKind::Keyword, ctx.source_range(), "await")
32 .detail("expr.await") 32 .detail("expr.await")
33 .insert_text("await") 33 .insert_text("await")
@@ -217,6 +217,39 @@ mod tests {
217 } 217 }
218 218
219 #[test] 219 #[test]
220 fn test_method_completion_only_fitting_impls() {
221 assert_debug_snapshot!(
222 do_ref_completion(
223 r"
224 struct A<T> {}
225 impl A<u32> {
226 fn the_method(&self) {}
227 }
228 impl A<i32> {
229 fn the_other_method(&self) {}
230 }
231 fn foo(a: A<u32>) {
232 a.<|>
233 }
234 ",
235 ),
236 @r###"
237 [
238 CompletionItem {
239 label: "the_method()",
240 source_range: [243; 243),
241 delete: [243; 243),
242 insert: "the_method()$0",
243 kind: Method,
244 lookup: "the_method",
245 detail: "fn the_method(&self)",
246 },
247 ]
248 "###
249 );
250 }
251
252 #[test]
220 fn test_trait_method_completion() { 253 fn test_trait_method_completion() {
221 assert_debug_snapshot!( 254 assert_debug_snapshot!(
222 do_ref_completion( 255 do_ref_completion(
diff --git a/crates/ra_ide/src/completion/complete_path.rs b/crates/ra_ide/src/completion/complete_path.rs
index 89e0009a1..cc1f7c830 100644
--- a/crates/ra_ide/src/completion/complete_path.rs
+++ b/crates/ra_ide/src/completion/complete_path.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{Adt, Either, HasSource, PathResolution}; 3use hir::{Adt, PathResolution, ScopeDef};
4use ra_syntax::AstNode; 4use ra_syntax::AstNode;
5use test_utils::tested_by; 5use test_utils::tested_by;
6 6
@@ -18,17 +18,15 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
18 match def { 18 match def {
19 hir::ModuleDef::Module(module) => { 19 hir::ModuleDef::Module(module) => {
20 let module_scope = module.scope(ctx.db); 20 let module_scope = module.scope(ctx.db);
21 for (name, def, import) in module_scope { 21 for (name, def) in module_scope {
22 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def { 22 if ctx.use_item_syntax.is_some() {
23 if ctx.use_item_syntax.is_some() { 23 if let hir::ScopeDef::ModuleDef(hir::ModuleDef::BuiltinType(..)) = def {
24 tested_by!(dont_complete_primitive_in_use); 24 tested_by!(dont_complete_primitive_in_use);
25 continue; 25 continue;
26 } 26 }
27 } 27 if let ScopeDef::Unknown = def {
28 if Some(module) == ctx.module { 28 if let Some(name_ref) = ctx.name_ref_syntax.as_ref() {
29 if let Some(import) = import { 29 if &name_ref.syntax().text() == name.to_string().as_str() {
30 if let Either::A(use_tree) = import.source(ctx.db).value {
31 if use_tree.syntax().text_range().contains_inclusive(ctx.offset) {
32 // for `use self::foo<|>`, don't suggest `foo` as a completion 30 // for `use self::foo<|>`, don't suggest `foo` as a completion
33 tested_by!(dont_complete_current_use); 31 tested_by!(dont_complete_current_use);
34 continue; 32 continue;
@@ -36,6 +34,7 @@ pub(super) fn complete_path(acc: &mut Completions, ctx: &CompletionContext) {
36 } 34 }
37 } 35 }
38 } 36 }
37
39 acc.add_resolution(ctx, name.to_string(), &def); 38 acc.add_resolution(ctx, name.to_string(), &def);
40 } 39 }
41 } 40 }
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs
index 646a30c76..5470dc291 100644
--- a/crates/ra_ide/src/completion/complete_postfix.rs
+++ b/crates/ra_ide/src/completion/complete_postfix.rs
@@ -12,7 +12,7 @@ use crate::{
12}; 12};
13 13
14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { 14pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) {
15 if ctx.db.feature_flags.get("completion.enable-postfix") == false { 15 if !ctx.db.feature_flags.get("completion.enable-postfix") {
16 return; 16 return;
17 } 17 }
18 18
diff --git a/crates/ra_ide/src/completion/complete_scope.rs b/crates/ra_ide/src/completion/complete_scope.rs
index d5739b58a..458d7525e 100644
--- a/crates/ra_ide/src/completion/complete_scope.rs
+++ b/crates/ra_ide/src/completion/complete_scope.rs
@@ -873,4 +873,41 @@ mod tests {
873 "### 873 "###
874 ); 874 );
875 } 875 }
876
877 #[test]
878 fn completes_local_item() {
879 assert_debug_snapshot!(
880 do_reference_completion(
881 "
882 //- /main.rs
883 fn main() {
884 return f<|>;
885 fn frobnicate() {}
886 }
887 "
888 ),
889 @r###"
890 [
891 CompletionItem {
892 label: "frobnicate()",
893 source_range: [23; 24),
894 delete: [23; 24),
895 insert: "frobnicate()$0",
896 kind: Function,
897 lookup: "frobnicate",
898 detail: "fn frobnicate()",
899 },
900 CompletionItem {
901 label: "main()",
902 source_range: [23; 24),
903 delete: [23; 24),
904 insert: "main()$0",
905 kind: Function,
906 lookup: "main",
907 detail: "fn main()",
908 },
909 ]
910 "###
911 )
912 }
876} 913}
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs
index b8345c91d..48d69f7e5 100644
--- a/crates/ra_ide/src/completion/completion_context.rs
+++ b/crates/ra_ide/src/completion/completion_context.rs
@@ -19,6 +19,7 @@ pub(crate) struct CompletionContext<'a> {
19 pub(super) offset: TextUnit, 19 pub(super) offset: TextUnit,
20 pub(super) token: SyntaxToken, 20 pub(super) token: SyntaxToken,
21 pub(super) module: Option<hir::Module>, 21 pub(super) module: Option<hir::Module>,
22 pub(super) name_ref_syntax: Option<ast::NameRef>,
22 pub(super) function_syntax: Option<ast::FnDef>, 23 pub(super) function_syntax: Option<ast::FnDef>,
23 pub(super) use_item_syntax: Option<ast::UseItem>, 24 pub(super) use_item_syntax: Option<ast::UseItem>,
24 pub(super) record_lit_syntax: Option<ast::RecordLit>, 25 pub(super) record_lit_syntax: Option<ast::RecordLit>,
@@ -54,13 +55,13 @@ impl<'a> CompletionContext<'a> {
54 let src = hir::ModuleSource::from_position(db, position); 55 let src = hir::ModuleSource::from_position(db, position);
55 let module = hir::Module::from_definition( 56 let module = hir::Module::from_definition(
56 db, 57 db,
57 hir::Source { file_id: position.file_id.into(), value: src }, 58 hir::InFile { file_id: position.file_id.into(), value: src },
58 ); 59 );
59 let token = 60 let token =
60 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?; 61 original_parse.tree().syntax().token_at_offset(position.offset).left_biased()?;
61 let analyzer = hir::SourceAnalyzer::new( 62 let analyzer = hir::SourceAnalyzer::new(
62 db, 63 db,
63 hir::Source::new(position.file_id.into(), &token.parent()), 64 hir::InFile::new(position.file_id.into(), &token.parent()),
64 Some(position.offset), 65 Some(position.offset),
65 ); 66 );
66 let mut ctx = CompletionContext { 67 let mut ctx = CompletionContext {
@@ -69,6 +70,7 @@ impl<'a> CompletionContext<'a> {
69 token, 70 token,
70 offset: position.offset, 71 offset: position.offset,
71 module, 72 module,
73 name_ref_syntax: None,
72 function_syntax: None, 74 function_syntax: None,
73 use_item_syntax: None, 75 use_item_syntax: None,
74 record_lit_syntax: None, 76 record_lit_syntax: None,
@@ -142,6 +144,8 @@ impl<'a> CompletionContext<'a> {
142 } 144 }
143 145
144 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) { 146 fn classify_name_ref(&mut self, original_file: SourceFile, name_ref: ast::NameRef) {
147 self.name_ref_syntax =
148 find_node_at_offset(original_file.syntax(), name_ref.syntax().text_range().start());
145 let name_range = name_ref.syntax().text_range(); 149 let name_range = name_ref.syntax().text_range();
146 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() { 150 if name_ref.syntax().parent().and_then(ast::RecordField::cast).is_some() {
147 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset); 151 self.record_lit_syntax = find_node_at_offset(original_file.syntax(), self.offset);
@@ -188,10 +192,9 @@ impl<'a> CompletionContext<'a> {
188 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some(); 192 self.is_path_type = path.syntax().parent().and_then(ast::PathType::cast).is_some();
189 self.has_type_args = segment.type_arg_list().is_some(); 193 self.has_type_args = segment.type_arg_list().is_some();
190 194
191 if let Some(mut path) = hir::Path::from_ast(path.clone()) { 195 if let Some(path) = hir::Path::from_ast(path.clone()) {
192 if !path.is_ident() { 196 if let Some(path_prefix) = path.qualifier() {
193 path.segments.pop().unwrap(); 197 self.path_prefix = Some(path_prefix);
194 self.path_prefix = Some(path);
195 return; 198 return;
196 } 199 }
197 } 200 }
@@ -240,16 +243,15 @@ impl<'a> CompletionContext<'a> {
240 .expr() 243 .expr()
241 .map(|e| e.syntax().text_range()) 244 .map(|e| e.syntax().text_range())
242 .and_then(|r| find_node_with_range(original_file.syntax(), r)); 245 .and_then(|r| find_node_with_range(original_file.syntax(), r));
243 self.dot_receiver_is_ambiguous_float_literal = if let Some(ast::Expr::Literal(l)) = 246 self.dot_receiver_is_ambiguous_float_literal =
244 &self.dot_receiver 247 if let Some(ast::Expr::Literal(l)) = &self.dot_receiver {
245 { 248 match l.kind() {
246 match l.kind() { 249 ast::LiteralKind::FloatNumber { .. } => l.token().text().ends_with('.'),
247 ast::LiteralKind::FloatNumber { suffix: _ } => l.token().text().ends_with('.'), 250 _ => false,
248 _ => false, 251 }
252 } else {
253 false
249 } 254 }
250 } else {
251 false
252 }
253 } 255 }
254 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) { 256 if let Some(method_call_expr) = ast::MethodCallExpr::cast(parent) {
255 // As above 257 // As above
diff --git a/crates/ra_ide/src/db.rs b/crates/ra_ide/src/db.rs
index f739ebecd..47d0aed6f 100644
--- a/crates/ra_ide/src/db.rs
+++ b/crates/ra_ide/src/db.rs
@@ -5,7 +5,7 @@ use std::sync::Arc;
5use ra_db::{ 5use ra_db::{
6 salsa::{self, Database, Durability}, 6 salsa::{self, Database, Durability},
7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath, 7 Canceled, CheckCanceled, CrateId, FileId, FileLoader, FileLoaderDelegate, RelativePath,
8 SourceDatabase, SourceDatabaseExt, SourceRootId, 8 SourceDatabase, SourceRootId,
9}; 9};
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
@@ -49,18 +49,6 @@ impl FileLoader for RootDatabase {
49 } 49 }
50} 50}
51 51
52impl hir::debug::HirDebugHelper for RootDatabase {
53 fn crate_name(&self, krate: CrateId) -> Option<String> {
54 self.debug_data.crate_names.get(&krate).cloned()
55 }
56 fn file_path(&self, file_id: FileId) -> Option<String> {
57 let source_root_id = self.file_source_root(file_id);
58 let source_root_path = self.debug_data.root_paths.get(&source_root_id)?;
59 let file_path = self.file_relative_path(file_id);
60 Some(format!("{}/{}", source_root_path, file_path))
61 }
62}
63
64impl salsa::Database for RootDatabase { 52impl salsa::Database for RootDatabase {
65 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> { 53 fn salsa_runtime(&self) -> &salsa::Runtime<RootDatabase> {
66 &self.runtime 54 &self.runtime
diff --git a/crates/ra_ide/src/diagnostics.rs b/crates/ra_ide/src/diagnostics.rs
index cc1ccab4b..c50a70d99 100644
--- a/crates/ra_ide/src/diagnostics.rs
+++ b/crates/ra_ide/src/diagnostics.rs
@@ -96,7 +96,7 @@ pub(crate) fn diagnostics(db: &RootDatabase, file_id: FileId) -> Vec<Diagnostic>
96 }); 96 });
97 let source_file = db.parse(file_id).tree(); 97 let source_file = db.parse(file_id).tree();
98 let src = 98 let src =
99 hir::Source { file_id: file_id.into(), value: hir::ModuleSource::SourceFile(source_file) }; 99 hir::InFile { file_id: file_id.into(), value: hir::ModuleSource::SourceFile(source_file) };
100 if let Some(m) = hir::Module::from_definition(db, src) { 100 if let Some(m) = hir::Module::from_definition(db, src) {
101 m.diagnostics(db, &mut sink); 101 m.diagnostics(db, &mut sink);
102 }; 102 };
diff --git a/crates/ra_ide/src/display.rs b/crates/ra_ide/src/display.rs
index 30617412a..fbe89841b 100644
--- a/crates/ra_ide/src/display.rs
+++ b/crates/ra_ide/src/display.rs
@@ -15,7 +15,7 @@ pub use function_signature::FunctionSignature;
15pub use navigation_target::NavigationTarget; 15pub use navigation_target::NavigationTarget;
16pub use structure::{file_structure, StructureNode}; 16pub use structure::{file_structure, StructureNode};
17 17
18pub(crate) use navigation_target::{description_from_symbol, docs_from_symbol, ToNav}; 18pub(crate) use navigation_target::ToNav;
19pub(crate) use short_label::ShortLabel; 19pub(crate) use short_label::ShortLabel;
20 20
21pub(crate) fn function_label(node: &ast::FnDef) -> String { 21pub(crate) fn function_label(node: &ast::FnDef) -> String {
diff --git a/crates/ra_ide/src/display/navigation_target.rs b/crates/ra_ide/src/display/navigation_target.rs
index 6ac60722b..b9ae67828 100644
--- a/crates/ra_ide/src/display/navigation_target.rs
+++ b/crates/ra_ide/src/display/navigation_target.rs
@@ -1,11 +1,12 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{AssocItem, Either, FieldSource, HasSource, ModuleSource, Source}; 3use either::Either;
4use hir::{AssocItem, FieldSource, HasSource, InFile, ModuleSource};
4use ra_db::{FileId, SourceDatabase}; 5use ra_db::{FileId, SourceDatabase};
5use ra_syntax::{ 6use ra_syntax::{
6 ast::{self, DocCommentsOwner, NameOwner}, 7 ast::{self, DocCommentsOwner, NameOwner},
7 match_ast, AstNode, SmolStr, 8 match_ast, AstNode, SmolStr,
8 SyntaxKind::{self, BIND_PAT}, 9 SyntaxKind::{self, BIND_PAT, TYPE_PARAM},
9 TextRange, 10 TextRange,
10}; 11};
11 12
@@ -141,7 +142,7 @@ impl NavigationTarget {
141 /// Allows `NavigationTarget` to be created from a `NameOwner` 142 /// Allows `NavigationTarget` to be created from a `NameOwner`
142 pub(crate) fn from_named( 143 pub(crate) fn from_named(
143 db: &RootDatabase, 144 db: &RootDatabase,
144 node: Source<&dyn ast::NameOwner>, 145 node: InFile<&dyn ast::NameOwner>,
145 docs: Option<String>, 146 docs: Option<String>,
146 description: Option<String>, 147 description: Option<String>,
147 ) -> NavigationTarget { 148 ) -> NavigationTarget {
@@ -230,34 +231,20 @@ impl ToNav for hir::Module {
230 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 231 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
231 let src = self.definition_source(db); 232 let src = self.definition_source(db);
232 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default(); 233 let name = self.name(db).map(|it| it.to_string().into()).unwrap_or_default();
233 match &src.value { 234 let syntax = match &src.value {
234 ModuleSource::SourceFile(node) => { 235 ModuleSource::SourceFile(node) => node.syntax(),
235 let frange = original_range(db, src.with_value(node.syntax())); 236 ModuleSource::Module(node) => node.syntax(),
236 237 };
237 NavigationTarget::from_syntax( 238 let frange = original_range(db, src.with_value(syntax));
238 frange.file_id, 239 NavigationTarget::from_syntax(
239 name, 240 frange.file_id,
240 None, 241 name,
241 frange.range, 242 None,
242 node.syntax().kind(), 243 frange.range,
243 None, 244 syntax.kind(),
244 None, 245 None,
245 ) 246 None,
246 } 247 )
247 ModuleSource::Module(node) => {
248 let frange = original_range(db, src.with_value(node.syntax()));
249
250 NavigationTarget::from_syntax(
251 frange.file_id,
252 name,
253 None,
254 frange.range,
255 node.syntax().kind(),
256 node.doc_comment_text(),
257 node.short_label(),
258 )
259 }
260 }
261 } 248 }
262} 249}
263 250
@@ -341,22 +328,43 @@ impl ToNav for hir::AssocItem {
341impl ToNav for hir::Local { 328impl ToNav for hir::Local {
342 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget { 329 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
343 let src = self.source(db); 330 let src = self.source(db);
344 let (full_range, focus_range) = match src.value { 331 let node = match &src.value {
345 Either::A(it) => { 332 Either::Left(bind_pat) => {
346 (it.syntax().text_range(), it.name().map(|it| it.syntax().text_range())) 333 bind_pat.name().map_or_else(|| bind_pat.syntax().clone(), |it| it.syntax().clone())
347 } 334 }
348 Either::B(it) => (it.syntax().text_range(), Some(it.self_kw_token().text_range())), 335 Either::Right(it) => it.syntax().clone(),
349 }; 336 };
337 let full_range = original_range(db, src.with_value(&node));
350 let name = match self.name(db) { 338 let name = match self.name(db) {
351 Some(it) => it.to_string().into(), 339 Some(it) => it.to_string().into(),
352 None => "".into(), 340 None => "".into(),
353 }; 341 };
354 NavigationTarget { 342 NavigationTarget {
355 file_id: src.file_id.original_file(db), 343 file_id: full_range.file_id,
356 name, 344 name,
357 kind: BIND_PAT, 345 kind: BIND_PAT,
358 full_range, 346 full_range: full_range.range,
359 focus_range, 347 focus_range: None,
348 container_name: None,
349 description: None,
350 docs: None,
351 }
352 }
353}
354
355impl ToNav for hir::TypeParam {
356 fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
357 let src = self.source(db);
358 let range = match src.value {
359 Either::Left(it) => it.syntax().text_range(),
360 Either::Right(it) => it.syntax().text_range(),
361 };
362 NavigationTarget {
363 file_id: src.file_id.original_file(db),
364 name: self.name(db).to_string().into(),
365 kind: TYPE_PARAM,
366 full_range: range,
367 focus_range: None,
360 container_name: None, 368 container_name: None,
361 description: None, 369 description: None,
362 docs: None, 370 docs: None,
diff --git a/crates/ra_ide/src/expand.rs b/crates/ra_ide/src/expand.rs
index 2f1abf509..7a22bb0a4 100644
--- a/crates/ra_ide/src/expand.rs
+++ b/crates/ra_ide/src/expand.rs
@@ -1,42 +1,71 @@
1//! Utilities to work with files, produced by macros. 1//! Utilities to work with files, produced by macros.
2use std::iter::successors; 2use std::iter::successors;
3 3
4use hir::Source; 4use hir::{InFile, Origin};
5use ra_db::FileId; 5use ra_db::FileId;
6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken}; 6use ra_syntax::{ast, AstNode, SyntaxNode, SyntaxToken, TextRange};
7 7
8use crate::{db::RootDatabase, FileRange}; 8use crate::{db::RootDatabase, FileRange};
9 9
10pub(crate) fn original_range(db: &RootDatabase, node: Source<&SyntaxNode>) -> FileRange { 10pub(crate) fn original_range(db: &RootDatabase, node: InFile<&SyntaxNode>) -> FileRange {
11 let expansion = match node.file_id.expansion_info(db) { 11 if let Some((range, Origin::Call)) = original_range_and_origin(db, node) {
12 None => { 12 return range;
13 }
14
15 if let Some(expansion) = node.file_id.expansion_info(db) {
16 if let Some(call_node) = expansion.call_node() {
13 return FileRange { 17 return FileRange {
14 file_id: node.file_id.original_file(db), 18 file_id: call_node.file_id.original_file(db),
15 range: node.value.text_range(), 19 range: call_node.value.text_range(),
16 } 20 };
17 } 21 }
18 Some(it) => it, 22 }
19 }; 23
20 // FIXME: the following completely wrong. 24 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() }
21 // 25}
22 // *First*, we should try to map first and last tokens of node, and, if that 26
23 // fails, return the range of the overall macro expansions. 27fn original_range_and_origin(
24 // 28 db: &RootDatabase,
25 // *Second*, we should handle recurside macro expansions 29 node: InFile<&SyntaxNode>,
26 30) -> Option<(FileRange, Origin)> {
27 let token = node 31 let expansion = node.file_id.expansion_info(db)?;
28 .value 32
29 .descendants_with_tokens() 33 // the input node has only one token ?
30 .filter_map(|it| it.into_token()) 34 let single = node.value.first_token()? == node.value.last_token()?;
31 .find_map(|it| expansion.map_token_up(node.with_value(&it))); 35
32 36 // FIXME: We should handle recurside macro expansions
33 match token { 37 let (range, origin) = node.value.descendants().find_map(|it| {
34 Some(it) => { 38 let first = it.first_token()?;
35 FileRange { file_id: it.file_id.original_file(db), range: it.value.text_range() } 39 let last = it.last_token()?;
40
41 if !single && first == last {
42 return None;
36 } 43 }
37 None => { 44
38 FileRange { file_id: node.file_id.original_file(db), range: node.value.text_range() } 45 // Try to map first and last tokens of node, and, if success, return the union range of mapped tokens
46 let (first, first_origin) = expansion.map_token_up(node.with_value(&first))?;
47 let (last, last_origin) = expansion.map_token_up(node.with_value(&last))?;
48
49 if first.file_id != last.file_id || first_origin != last_origin {
50 return None;
39 } 51 }
52
53 // FIXME: Add union method in TextRange
54 Some((
55 first.with_value(union_range(first.value.text_range(), last.value.text_range())),
56 first_origin,
57 ))
58 })?;
59
60 return Some((
61 FileRange { file_id: range.file_id.original_file(db), range: range.value },
62 origin,
63 ));
64
65 fn union_range(a: TextRange, b: TextRange) -> TextRange {
66 let start = a.start().min(b.start());
67 let end = a.end().max(b.end());
68 TextRange::from_to(start, end)
40 } 69 }
41} 70}
42 71
@@ -44,8 +73,8 @@ pub(crate) fn descend_into_macros(
44 db: &RootDatabase, 73 db: &RootDatabase,
45 file_id: FileId, 74 file_id: FileId,
46 token: SyntaxToken, 75 token: SyntaxToken,
47) -> Source<SyntaxToken> { 76) -> InFile<SyntaxToken> {
48 let src = Source::new(file_id.into(), token); 77 let src = InFile::new(file_id.into(), token);
49 78
50 successors(Some(src), |token| { 79 successors(Some(src), |token| {
51 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?; 80 let macro_call = token.value.ancestors().find_map(ast::MacroCall::cast)?;
diff --git a/crates/ra_ide/src/expand_macro.rs b/crates/ra_ide/src/expand_macro.rs
index abc602244..bdbc31704 100644
--- a/crates/ra_ide/src/expand_macro.rs
+++ b/crates/ra_ide/src/expand_macro.rs
@@ -22,7 +22,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
22 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?; 22 let name_ref = find_node_at_offset::<ast::NameRef>(file.syntax(), position.offset)?;
23 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?; 23 let mac = name_ref.syntax().ancestors().find_map(ast::MacroCall::cast)?;
24 24
25 let source = hir::Source::new(position.file_id.into(), mac.syntax()); 25 let source = hir::InFile::new(position.file_id.into(), mac.syntax());
26 let expanded = expand_macro_recur(db, source, source.with_value(&mac))?; 26 let expanded = expand_macro_recur(db, source, source.with_value(&mac))?;
27 27
28 // FIXME: 28 // FIXME:
@@ -34,8 +34,8 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
34 34
35fn expand_macro_recur( 35fn expand_macro_recur(
36 db: &RootDatabase, 36 db: &RootDatabase,
37 source: hir::Source<&SyntaxNode>, 37 source: hir::InFile<&SyntaxNode>,
38 macro_call: hir::Source<&ast::MacroCall>, 38 macro_call: hir::InFile<&ast::MacroCall>,
39) -> Option<SyntaxNode> { 39) -> Option<SyntaxNode> {
40 let analyzer = hir::SourceAnalyzer::new(db, source, None); 40 let analyzer = hir::SourceAnalyzer::new(db, source, None);
41 let expansion = analyzer.expand(db, macro_call)?; 41 let expansion = analyzer.expand(db, macro_call)?;
@@ -46,7 +46,7 @@ fn expand_macro_recur(
46 let mut replaces = FxHashMap::default(); 46 let mut replaces = FxHashMap::default();
47 47
48 for child in children.into_iter() { 48 for child in children.into_iter() {
49 let node = hir::Source::new(macro_file_id, &child); 49 let node = hir::InFile::new(macro_file_id, &child);
50 if let Some(new_node) = expand_macro_recur(db, source, node) { 50 if let Some(new_node) = expand_macro_recur(db, source, node) {
51 // Replace the whole node if it is root 51 // Replace the whole node if it is root
52 // `replace_descendants` will not replace the parent node 52 // `replace_descendants` will not replace the parent node
@@ -86,21 +86,18 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool { 86 let mut is_next = |f: fn(SyntaxKind) -> bool, default| -> bool {
87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default) 87 token_iter.peek().map(|it| f(it.kind())).unwrap_or(default)
88 }; 88 };
89 let is_last = |f: fn(SyntaxKind) -> bool, default| -> bool { 89 let is_last =
90 last.map(|it| f(it)).unwrap_or(default) 90 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
91 };
92 91
93 res += &match token.kind() { 92 res += &match token.kind() {
94 k @ _ if is_text(k) && is_next(|it| !it.is_punct(), true) => { 93 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ",
95 token.text().to_string() + " "
96 }
97 L_CURLY if is_next(|it| it != R_CURLY, true) => { 94 L_CURLY if is_next(|it| it != R_CURLY, true) => {
98 indent += 1; 95 indent += 1;
99 let leading_space = if is_last(|it| is_text(it), false) { " " } else { "" }; 96 let leading_space = if is_last(is_text, false) { " " } else { "" };
100 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 97 format!("{}{{\n{}", leading_space, " ".repeat(indent))
101 } 98 }
102 R_CURLY if is_last(|it| it != L_CURLY, true) => { 99 R_CURLY if is_last(|it| it != L_CURLY, true) => {
103 indent = indent.checked_sub(1).unwrap_or(0); 100 indent = indent.saturating_sub(1);
104 format!("\n{}}}", " ".repeat(indent)) 101 format!("\n{}}}", " ".repeat(indent))
105 } 102 }
106 R_CURLY => format!("}}\n{}", " ".repeat(indent)), 103 R_CURLY => format!("}}\n{}", " ".repeat(indent)),
diff --git a/crates/ra_ide/src/extend_selection.rs b/crates/ra_ide/src/extend_selection.rs
index 4b7bfc0b1..1ec41a117 100644
--- a/crates/ra_ide/src/extend_selection.rs
+++ b/crates/ra_ide/src/extend_selection.rs
@@ -34,6 +34,7 @@ fn try_extend_selection(root: &SyntaxNode, range: TextRange) -> Option<TextRange
34 ARG_LIST, 34 ARG_LIST,
35 ARRAY_EXPR, 35 ARRAY_EXPR,
36 TUPLE_EXPR, 36 TUPLE_EXPR,
37 TUPLE_TYPE,
37 WHERE_CLAUSE, 38 WHERE_CLAUSE,
38 ]; 39 ];
39 40
@@ -137,7 +138,7 @@ fn extend_ws(root: &SyntaxNode, ws: SyntaxToken, offset: TextUnit) -> TextRange
137 ws.text_range() 138 ws.text_range()
138} 139}
139 140
140fn pick_best<'a>(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken { 141fn pick_best(l: SyntaxToken, r: SyntaxToken) -> SyntaxToken {
141 return if priority(&r) > priority(&l) { r } else { l }; 142 return if priority(&r) > priority(&l) { r } else { l };
142 fn priority(n: &SyntaxToken) -> usize { 143 fn priority(n: &SyntaxToken) -> usize {
143 match n.kind() { 144 match n.kind() {
@@ -174,12 +175,7 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
174 TYPE_BOUND => T![+], 175 TYPE_BOUND => T![+],
175 _ => T![,], 176 _ => T![,],
176 }; 177 };
177 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) { 178
178 return Some(TextRange::from_to(
179 delimiter_node.text_range().start(),
180 node.text_range().end(),
181 ));
182 }
183 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) { 179 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Next) {
184 // Include any following whitespace when delimiter is after list item. 180 // Include any following whitespace when delimiter is after list item.
185 let final_node = delimiter_node 181 let final_node = delimiter_node
@@ -190,6 +186,12 @@ fn extend_list_item(node: &SyntaxNode) -> Option<TextRange> {
190 186
191 return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end())); 187 return Some(TextRange::from_to(node.text_range().start(), final_node.text_range().end()));
192 } 188 }
189 if let Some(delimiter_node) = nearby_delimiter(delimiter, node, Direction::Prev) {
190 return Some(TextRange::from_to(
191 delimiter_node.text_range().start(),
192 node.text_range().end(),
193 ));
194 }
193 195
194 None 196 None
195} 197}
@@ -250,14 +252,14 @@ mod tests {
250 fn test_extend_selection_list() { 252 fn test_extend_selection_list() {
251 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]); 253 do_check(r#"fn foo(<|>x: i32) {}"#, &["x", "x: i32"]);
252 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]); 254 do_check(r#"fn foo(<|>x: i32, y: i32) {}"#, &["x", "x: i32", "x: i32, "]);
253 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,"]); 255 do_check(r#"fn foo(<|>x: i32,y: i32) {}"#, &["x", "x: i32", "x: i32,", "(x: i32,y: i32)"]);
254 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]); 256 do_check(r#"fn foo(x: i32, <|>y: i32) {}"#, &["y", "y: i32", ", y: i32"]);
255 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", ", y: i32"]); 257 do_check(r#"fn foo(x: i32, <|>y: i32, ) {}"#, &["y", "y: i32", "y: i32, "]);
256 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]); 258 do_check(r#"fn foo(x: i32,<|>y: i32) {}"#, &["y", "y: i32", ",y: i32"]);
257 259
258 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]); 260 do_check(r#"const FOO: [usize; 2] = [ 22<|> , 33];"#, &["22", "22 , "]);
259 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]); 261 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|>];"#, &["33", ", 33"]);
260 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", ", 33"]); 262 do_check(r#"const FOO: [usize; 2] = [ 22 , 33<|> ,];"#, &["33", "33 ,", "[ 22 , 33 ,]"]);
261 263
262 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]); 264 do_check(r#"fn main() { (1, 2<|>) }"#, &["2", ", 2", "(1, 2)"]);
263 265
@@ -276,7 +278,7 @@ const FOO: [usize; 2] = [
276 22 278 22
277 , 33<|>, 279 , 33<|>,
278]"#, 280]"#,
279 &["33", ", 33"], 281 &["33", "33,"],
280 ); 282 );
281 } 283 }
282 284
@@ -424,7 +426,7 @@ fn foo<R>()
424 do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]); 426 do_check(r#"fn foo<T>() where T: <|>Copy +Display"#, &["Copy", "Copy +"]);
425 do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]); 427 do_check(r#"fn foo<T>() where T: <|>Copy+Display"#, &["Copy", "Copy+"]);
426 do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]); 428 do_check(r#"fn foo<T>() where T: Copy + <|>Display"#, &["Display", "+ Display"]);
427 do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "+ Display"]); 429 do_check(r#"fn foo<T>() where T: Copy + <|>Display + Sync"#, &["Display", "Display + "]);
428 do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]); 430 do_check(r#"fn foo<T>() where T: Copy +<|>Display"#, &["Display", "+Display"]);
429 } 431 }
430 432
@@ -435,7 +437,7 @@ fn foo<R>()
435 do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]); 437 do_check(r#"fn foo<T: <|>Copy +Display>() {}"#, &["Copy", "Copy +"]);
436 do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]); 438 do_check(r#"fn foo<T: <|>Copy+Display>() {}"#, &["Copy", "Copy+"]);
437 do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]); 439 do_check(r#"fn foo<T: Copy + <|>Display>() {}"#, &["Display", "+ Display"]);
438 do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "+ Display"]); 440 do_check(r#"fn foo<T: Copy + <|>Display + Sync>() {}"#, &["Display", "Display + "]);
439 do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]); 441 do_check(r#"fn foo<T: Copy +<|>Display>() {}"#, &["Display", "+Display"]);
440 do_check( 442 do_check(
441 r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#, 443 r#"fn foo<T: Copy<|> + Display, U: Copy>() {}"#,
@@ -449,4 +451,56 @@ fn foo<R>()
449 ], 451 ],
450 ); 452 );
451 } 453 }
454
455 #[test]
456 fn test_extend_selection_on_tuple_in_type() {
457 do_check(
458 r#"fn main() { let _: (krate, <|>_crate_def_map, module_id) = (); }"#,
459 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
460 );
461 // white space variations
462 do_check(
463 r#"fn main() { let _: (krate,<|>_crate_def_map,module_id) = (); }"#,
464 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
465 );
466 do_check(
467 r#"
468fn main() { let _: (
469 krate,
470 _crate<|>_def_map,
471 module_id
472) = (); }"#,
473 &[
474 "_crate_def_map",
475 "_crate_def_map,",
476 "(\n krate,\n _crate_def_map,\n module_id\n)",
477 ],
478 );
479 }
480
481 #[test]
482 fn test_extend_selection_on_tuple_in_rvalue() {
483 do_check(
484 r#"fn main() { let var = (krate, _crate_def_map<|>, module_id); }"#,
485 &["_crate_def_map", "_crate_def_map, ", "(krate, _crate_def_map, module_id)"],
486 );
487 // white space variations
488 do_check(
489 r#"fn main() { let var = (krate,_crate<|>_def_map,module_id); }"#,
490 &["_crate_def_map", "_crate_def_map,", "(krate,_crate_def_map,module_id)"],
491 );
492 do_check(
493 r#"
494fn main() { let var = (
495 krate,
496 _crate_def_map<|>,
497 module_id
498); }"#,
499 &[
500 "_crate_def_map",
501 "_crate_def_map,",
502 "(\n krate,\n _crate_def_map,\n module_id\n)",
503 ],
504 );
505 }
452} 506}
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index c10a6c844..79d332e8c 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -1,9 +1,11 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::{db::AstDatabase, Source}; 3use hir::{db::AstDatabase, InFile};
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{self, DocCommentsOwner}, 5 ast::{self, DocCommentsOwner},
6 match_ast, AstNode, SyntaxNode, 6 match_ast, AstNode,
7 SyntaxKind::*,
8 SyntaxNode, SyntaxToken, TokenAtOffset,
7}; 9};
8 10
9use crate::{ 11use crate::{
@@ -19,25 +21,33 @@ pub(crate) fn goto_definition(
19 position: FilePosition, 21 position: FilePosition,
20) -> Option<RangeInfo<Vec<NavigationTarget>>> { 22) -> Option<RangeInfo<Vec<NavigationTarget>>> {
21 let file = db.parse_or_expand(position.file_id.into())?; 23 let file = db.parse_or_expand(position.file_id.into())?;
22 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 24 let original_token = pick_best(file.token_at_offset(position.offset))?;
23 let token = descend_into_macros(db, position.file_id, token); 25 let token = descend_into_macros(db, position.file_id, original_token.clone());
24 26
25 let res = match_ast! { 27 let nav_targets = match_ast! {
26 match (token.value.parent()) { 28 match (token.value.parent()) {
27 ast::NameRef(name_ref) => { 29 ast::NameRef(name_ref) => {
28 let navs = reference_definition(db, token.with_value(&name_ref)).to_vec(); 30 reference_definition(db, token.with_value(&name_ref)).to_vec()
29 RangeInfo::new(name_ref.syntax().text_range(), navs.to_vec())
30 }, 31 },
31 ast::Name(name) => { 32 ast::Name(name) => {
32 let navs = name_definition(db, token.with_value(&name))?; 33 name_definition(db, token.with_value(&name))?
33 RangeInfo::new(name.syntax().text_range(), navs)
34
35 }, 34 },
36 _ => return None, 35 _ => return None,
37 } 36 }
38 }; 37 };
39 38
40 Some(res) 39 Some(RangeInfo::new(original_token.text_range(), nav_targets))
40}
41
42fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
43 return tokens.max_by_key(priority);
44 fn priority(n: &SyntaxToken) -> usize {
45 match n.kind() {
46 IDENT | INT_NUMBER => 2,
47 kind if kind.is_trivia() => 0,
48 _ => 1,
49 }
50 }
41} 51}
42 52
43#[derive(Debug)] 53#[derive(Debug)]
@@ -58,15 +68,17 @@ impl ReferenceResult {
58 68
59pub(crate) fn reference_definition( 69pub(crate) fn reference_definition(
60 db: &RootDatabase, 70 db: &RootDatabase,
61 name_ref: Source<&ast::NameRef>, 71 name_ref: InFile<&ast::NameRef>,
62) -> ReferenceResult { 72) -> ReferenceResult {
63 use self::ReferenceResult::*; 73 use self::ReferenceResult::*;
64 74
65 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind); 75 let name_kind = classify_name_ref(db, name_ref).map(|d| d.kind);
66 match name_kind { 76 match name_kind {
67 Some(Macro(mac)) => return Exact(mac.to_nav(db)), 77 Some(Macro(it)) => return Exact(it.to_nav(db)),
68 Some(Field(field)) => return Exact(field.to_nav(db)), 78 Some(Field(it)) => return Exact(it.to_nav(db)),
69 Some(AssocItem(assoc)) => return Exact(assoc.to_nav(db)), 79 Some(TypeParam(it)) => return Exact(it.to_nav(db)),
80 Some(AssocItem(it)) => return Exact(it.to_nav(db)),
81 Some(Local(it)) => return Exact(it.to_nav(db)),
70 Some(Def(def)) => match NavigationTarget::from_def(db, def) { 82 Some(Def(def)) => match NavigationTarget::from_def(db, def) {
71 Some(nav) => return Exact(nav), 83 Some(nav) => return Exact(nav),
72 None => return Approximate(vec![]), 84 None => return Approximate(vec![]),
@@ -77,10 +89,6 @@ pub(crate) fn reference_definition(
77 // us to the actual type 89 // us to the actual type
78 return Exact(imp.to_nav(db)); 90 return Exact(imp.to_nav(db));
79 } 91 }
80 Some(Local(local)) => return Exact(local.to_nav(db)),
81 Some(GenericParam(_)) => {
82 // FIXME: go to the generic param def
83 }
84 None => {} 92 None => {}
85 }; 93 };
86 94
@@ -94,7 +102,7 @@ pub(crate) fn reference_definition(
94 102
95pub(crate) fn name_definition( 103pub(crate) fn name_definition(
96 db: &RootDatabase, 104 db: &RootDatabase,
97 name: Source<&ast::Name>, 105 name: InFile<&ast::Name>,
98) -> Option<Vec<NavigationTarget>> { 106) -> Option<Vec<NavigationTarget>> {
99 let parent = name.value.syntax().parent()?; 107 let parent = name.value.syntax().parent()?;
100 108
@@ -115,7 +123,7 @@ pub(crate) fn name_definition(
115 None 123 None
116} 124}
117 125
118fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<NavigationTarget> { 126fn named_target(db: &RootDatabase, node: InFile<&SyntaxNode>) -> Option<NavigationTarget> {
119 match_ast! { 127 match_ast! {
120 match (node.value) { 128 match (node.value) {
121 ast::StructDef(it) => { 129 ast::StructDef(it) => {
@@ -213,21 +221,44 @@ fn named_target(db: &RootDatabase, node: Source<&SyntaxNode>) -> Option<Navigati
213 221
214#[cfg(test)] 222#[cfg(test)]
215mod tests { 223mod tests {
216 use test_utils::covers; 224 use test_utils::{assert_eq_text, covers};
217 225
218 use crate::mock_analysis::analysis_and_position; 226 use crate::mock_analysis::analysis_and_position;
219 227
220 fn check_goto(fixture: &str, expected: &str) { 228 fn check_goto(fixture: &str, expected: &str, expected_range: &str) {
221 let (analysis, pos) = analysis_and_position(fixture); 229 let (analysis, pos) = analysis_and_position(fixture);
222 230
223 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info; 231 let mut navs = analysis.goto_definition(pos).unwrap().unwrap().info;
224 assert_eq!(navs.len(), 1); 232 assert_eq!(navs.len(), 1);
233
225 let nav = navs.pop().unwrap(); 234 let nav = navs.pop().unwrap();
235 let file_text = analysis.file_text(nav.file_id()).unwrap();
236
237 let mut actual = file_text[nav.full_range()].to_string();
238 if let Some(focus) = nav.focus_range() {
239 actual += "|";
240 actual += &file_text[focus];
241 }
242
243 if !expected_range.contains("...") {
244 test_utils::assert_eq_text!(&actual, expected_range);
245 } else {
246 let mut parts = expected_range.split("...");
247 let prefix = parts.next().unwrap();
248 let suffix = parts.next().unwrap();
249 assert!(
250 actual.starts_with(prefix) && actual.ends_with(suffix),
251 "\nExpected: {}\n Actual: {}\n",
252 expected_range,
253 actual
254 );
255 }
256
226 nav.assert_match(expected); 257 nav.assert_match(expected);
227 } 258 }
228 259
229 #[test] 260 #[test]
230 fn goto_definition_works_in_items() { 261 fn goto_def_in_items() {
231 check_goto( 262 check_goto(
232 " 263 "
233 //- /lib.rs 264 //- /lib.rs
@@ -235,6 +266,20 @@ mod tests {
235 enum E { X(Foo<|>) } 266 enum E { X(Foo<|>) }
236 ", 267 ",
237 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)", 268 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
269 "struct Foo;|Foo",
270 );
271 }
272
273 #[test]
274 fn goto_def_at_start_of_item() {
275 check_goto(
276 "
277 //- /lib.rs
278 struct Foo;
279 enum E { X(<|>Foo) }
280 ",
281 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
282 "struct Foo;|Foo",
238 ); 283 );
239 } 284 }
240 285
@@ -247,61 +292,65 @@ mod tests {
247 mod a; 292 mod a;
248 mod b; 293 mod b;
249 enum E { X(Foo<|>) } 294 enum E { X(Foo<|>) }
295
250 //- /a.rs 296 //- /a.rs
251 struct Foo; 297 struct Foo;
298
252 //- /b.rs 299 //- /b.rs
253 struct Foo; 300 struct Foo;
254 ", 301 ",
255 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)", 302 "Foo STRUCT_DEF FileId(2) [0; 11) [7; 10)",
303 "struct Foo;|Foo",
256 ); 304 );
257 } 305 }
258 306
259 #[test] 307 #[test]
260 fn goto_definition_works_for_module_declaration() { 308 fn goto_def_for_module_declaration() {
261 check_goto( 309 check_goto(
262 " 310 "
263 //- /lib.rs 311 //- /lib.rs
264 mod <|>foo; 312 mod <|>foo;
313
265 //- /foo.rs 314 //- /foo.rs
266 // empty 315 // empty
267 ", 316 ",
268 "foo SOURCE_FILE FileId(2) [0; 10)", 317 "foo SOURCE_FILE FileId(2) [0; 10)",
318 "// empty\n\n",
269 ); 319 );
270 320
271 check_goto( 321 check_goto(
272 " 322 "
273 //- /lib.rs 323 //- /lib.rs
274 mod <|>foo; 324 mod <|>foo;
325
275 //- /foo/mod.rs 326 //- /foo/mod.rs
276 // empty 327 // empty
277 ", 328 ",
278 "foo SOURCE_FILE FileId(2) [0; 10)", 329 "foo SOURCE_FILE FileId(2) [0; 10)",
330 "// empty\n\n",
279 ); 331 );
280 } 332 }
281 333
282 #[test] 334 #[test]
283 fn goto_definition_works_for_macros() { 335 fn goto_def_for_macros() {
284 covers!(goto_definition_works_for_macros); 336 covers!(goto_def_for_macros);
285 check_goto( 337 check_goto(
286 " 338 "
287 //- /lib.rs 339 //- /lib.rs
288 macro_rules! foo { 340 macro_rules! foo { () => { () } }
289 () => {
290 {}
291 };
292 }
293 341
294 fn bar() { 342 fn bar() {
295 <|>foo!(); 343 <|>foo!();
296 } 344 }
297 ", 345 ",
298 "foo MACRO_CALL FileId(1) [0; 50) [13; 16)", 346 "foo MACRO_CALL FileId(1) [0; 33) [13; 16)",
347 "macro_rules! foo { () => { () } }|foo",
299 ); 348 );
300 } 349 }
301 350
302 #[test] 351 #[test]
303 fn goto_definition_works_for_macros_from_other_crates() { 352 fn goto_def_for_macros_from_other_crates() {
304 covers!(goto_definition_works_for_macros); 353 covers!(goto_def_for_macros);
305 check_goto( 354 check_goto(
306 " 355 "
307 //- /lib.rs 356 //- /lib.rs
@@ -312,18 +361,15 @@ mod tests {
312 361
313 //- /foo/lib.rs 362 //- /foo/lib.rs
314 #[macro_export] 363 #[macro_export]
315 macro_rules! foo { 364 macro_rules! foo { () => { () } }
316 () => {
317 {}
318 };
319 }
320 ", 365 ",
321 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 366 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
367 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
322 ); 368 );
323 } 369 }
324 370
325 #[test] 371 #[test]
326 fn goto_definition_works_for_macros_in_use_tree() { 372 fn goto_def_for_macros_in_use_tree() {
327 check_goto( 373 check_goto(
328 " 374 "
329 //- /lib.rs 375 //- /lib.rs
@@ -331,18 +377,15 @@ mod tests {
331 377
332 //- /foo/lib.rs 378 //- /foo/lib.rs
333 #[macro_export] 379 #[macro_export]
334 macro_rules! foo { 380 macro_rules! foo { () => { () } }
335 () => {
336 {}
337 };
338 }
339 ", 381 ",
340 "foo MACRO_CALL FileId(2) [0; 66) [29; 32)", 382 "foo MACRO_CALL FileId(2) [0; 49) [29; 32)",
383 "#[macro_export]\nmacro_rules! foo { () => { () } }|foo",
341 ); 384 );
342 } 385 }
343 386
344 #[test] 387 #[test]
345 fn goto_definition_works_for_macro_defined_fn_with_arg() { 388 fn goto_def_for_macro_defined_fn_with_arg() {
346 check_goto( 389 check_goto(
347 " 390 "
348 //- /lib.rs 391 //- /lib.rs
@@ -350,20 +393,19 @@ mod tests {
350 ($name:ident) => (fn $name() {}) 393 ($name:ident) => (fn $name() {})
351 } 394 }
352 395
353 define_fn!( 396 define_fn!(foo);
354 foo
355 )
356 397
357 fn bar() { 398 fn bar() {
358 <|>foo(); 399 <|>foo();
359 } 400 }
360 ", 401 ",
361 "foo FN_DEF FileId(1) [80; 83) [80; 83)", 402 "foo FN_DEF FileId(1) [64; 80) [75; 78)",
403 "define_fn!(foo);|foo",
362 ); 404 );
363 } 405 }
364 406
365 #[test] 407 #[test]
366 fn goto_definition_works_for_macro_defined_fn_no_arg() { 408 fn goto_def_for_macro_defined_fn_no_arg() {
367 check_goto( 409 check_goto(
368 " 410 "
369 //- /lib.rs 411 //- /lib.rs
@@ -377,32 +419,70 @@ mod tests {
377 <|>foo(); 419 <|>foo();
378 } 420 }
379 ", 421 ",
380 "foo FN_DEF FileId(1) [39; 42) [39; 42)", 422 "foo FN_DEF FileId(1) [51; 64) [51; 64)",
423 "define_fn!();|define_fn!();",
381 ); 424 );
382 } 425 }
383 426
384 #[test] 427 #[test]
385 fn goto_definition_works_for_methods() { 428 fn goto_definition_works_for_macro_inside_pattern() {
386 covers!(goto_definition_works_for_methods); 429 check_goto(
430 "
431 //- /lib.rs
432 macro_rules! foo {() => {0}}
433
434 fn bar() {
435 match (0,1) {
436 (<|>foo!(), _) => {}
437 }
438 }
439 ",
440 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
441 "macro_rules! foo {() => {0}}|foo",
442 );
443 }
444
445 #[test]
446 fn goto_definition_works_for_macro_inside_match_arm_lhs() {
447 check_goto(
448 "
449 //- /lib.rs
450 macro_rules! foo {() => {0}}
451
452 fn bar() {
453 match 0 {
454 <|>foo!() => {}
455 }
456 }
457 ",
458 "foo MACRO_CALL FileId(1) [0; 28) [13; 16)",
459 "macro_rules! foo {() => {0}}|foo",
460 );
461 }
462
463 #[test]
464 fn goto_def_for_methods() {
465 covers!(goto_def_for_methods);
387 check_goto( 466 check_goto(
388 " 467 "
389 //- /lib.rs 468 //- /lib.rs
390 struct Foo; 469 struct Foo;
391 impl Foo { 470 impl Foo {
392 fn frobnicate(&self) { } 471 fn frobnicate(&self) { }
393 } 472 }
394 473
395 fn bar(foo: &Foo) { 474 fn bar(foo: &Foo) {
396 foo.frobnicate<|>(); 475 foo.frobnicate<|>();
397 } 476 }
398 ", 477 ",
399 "frobnicate FN_DEF FileId(1) [27; 52) [30; 40)", 478 "frobnicate FN_DEF FileId(1) [27; 51) [30; 40)",
479 "fn frobnicate(&self) { }|frobnicate",
400 ); 480 );
401 } 481 }
402 482
403 #[test] 483 #[test]
404 fn goto_definition_works_for_fields() { 484 fn goto_def_for_fields() {
405 covers!(goto_definition_works_for_fields); 485 covers!(goto_def_for_fields);
406 check_goto( 486 check_goto(
407 " 487 "
408 //- /lib.rs 488 //- /lib.rs
@@ -415,12 +495,13 @@ mod tests {
415 } 495 }
416 ", 496 ",
417 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 497 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
498 "spam: u32|spam",
418 ); 499 );
419 } 500 }
420 501
421 #[test] 502 #[test]
422 fn goto_definition_works_for_record_fields() { 503 fn goto_def_for_record_fields() {
423 covers!(goto_definition_works_for_record_fields); 504 covers!(goto_def_for_record_fields);
424 check_goto( 505 check_goto(
425 " 506 "
426 //- /lib.rs 507 //- /lib.rs
@@ -435,29 +516,48 @@ mod tests {
435 } 516 }
436 ", 517 ",
437 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)", 518 "spam RECORD_FIELD_DEF FileId(1) [17; 26) [17; 21)",
519 "spam: u32|spam",
520 );
521 }
522
523 #[test]
524 fn goto_for_tuple_fields() {
525 check_goto(
526 "
527 //- /lib.rs
528 struct Foo(u32);
529
530 fn bar() {
531 let foo = Foo(0);
532 foo.<|>0;
533 }
534 ",
535 "TUPLE_FIELD_DEF FileId(1) [11; 14)",
536 "u32",
438 ); 537 );
439 } 538 }
440 539
441 #[test] 540 #[test]
442 fn goto_definition_works_for_ufcs_inherent_methods() { 541 fn goto_def_for_ufcs_inherent_methods() {
443 check_goto( 542 check_goto(
444 " 543 "
445 //- /lib.rs 544 //- /lib.rs
446 struct Foo; 545 struct Foo;
447 impl Foo { 546 impl Foo {
448 fn frobnicate() { } 547 fn frobnicate() { }
449 } 548 }
450 549
451 fn bar(foo: &Foo) { 550 fn bar(foo: &Foo) {
452 Foo::frobnicate<|>(); 551 Foo::frobnicate<|>();
453 } 552 }
454 ", 553 ",
455 "frobnicate FN_DEF FileId(1) [27; 47) [30; 40)", 554 "frobnicate FN_DEF FileId(1) [27; 46) [30; 40)",
555 "fn frobnicate() { }|frobnicate",
456 ); 556 );
457 } 557 }
458 558
459 #[test] 559 #[test]
460 fn goto_definition_works_for_ufcs_trait_methods_through_traits() { 560 fn goto_def_for_ufcs_trait_methods_through_traits() {
461 check_goto( 561 check_goto(
462 " 562 "
463 //- /lib.rs 563 //- /lib.rs
@@ -470,11 +570,12 @@ mod tests {
470 } 570 }
471 ", 571 ",
472 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)", 572 "frobnicate FN_DEF FileId(1) [16; 32) [19; 29)",
573 "fn frobnicate();|frobnicate",
473 ); 574 );
474 } 575 }
475 576
476 #[test] 577 #[test]
477 fn goto_definition_works_for_ufcs_trait_methods_through_self() { 578 fn goto_def_for_ufcs_trait_methods_through_self() {
478 check_goto( 579 check_goto(
479 " 580 "
480 //- /lib.rs 581 //- /lib.rs
@@ -489,6 +590,7 @@ mod tests {
489 } 590 }
490 ", 591 ",
491 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)", 592 "frobnicate FN_DEF FileId(1) [30; 46) [33; 43)",
593 "fn frobnicate();|frobnicate",
492 ); 594 );
493 } 595 }
494 596
@@ -505,6 +607,7 @@ mod tests {
505 } 607 }
506 ", 608 ",
507 "impl IMPL_BLOCK FileId(1) [12; 73)", 609 "impl IMPL_BLOCK FileId(1) [12; 73)",
610 "impl Foo {...}",
508 ); 611 );
509 612
510 check_goto( 613 check_goto(
@@ -518,6 +621,7 @@ mod tests {
518 } 621 }
519 ", 622 ",
520 "impl IMPL_BLOCK FileId(1) [12; 73)", 623 "impl IMPL_BLOCK FileId(1) [12; 73)",
624 "impl Foo {...}",
521 ); 625 );
522 626
523 check_goto( 627 check_goto(
@@ -531,6 +635,7 @@ mod tests {
531 } 635 }
532 ", 636 ",
533 "impl IMPL_BLOCK FileId(1) [15; 75)", 637 "impl IMPL_BLOCK FileId(1) [15; 75)",
638 "impl Foo {...}",
534 ); 639 );
535 640
536 check_goto( 641 check_goto(
@@ -543,6 +648,7 @@ mod tests {
543 } 648 }
544 ", 649 ",
545 "impl IMPL_BLOCK FileId(1) [15; 62)", 650 "impl IMPL_BLOCK FileId(1) [15; 62)",
651 "impl Foo {...}",
546 ); 652 );
547 } 653 }
548 654
@@ -562,6 +668,7 @@ mod tests {
562 } 668 }
563 ", 669 ",
564 "impl IMPL_BLOCK FileId(1) [49; 115)", 670 "impl IMPL_BLOCK FileId(1) [49; 115)",
671 "impl Make for Foo {...}",
565 ); 672 );
566 673
567 check_goto( 674 check_goto(
@@ -578,17 +685,19 @@ mod tests {
578 } 685 }
579 ", 686 ",
580 "impl IMPL_BLOCK FileId(1) [49; 115)", 687 "impl IMPL_BLOCK FileId(1) [49; 115)",
688 "impl Make for Foo {...}",
581 ); 689 );
582 } 690 }
583 691
584 #[test] 692 #[test]
585 fn goto_definition_works_when_used_on_definition_name_itself() { 693 fn goto_def_when_used_on_definition_name_itself() {
586 check_goto( 694 check_goto(
587 " 695 "
588 //- /lib.rs 696 //- /lib.rs
589 struct Foo<|> { value: u32 } 697 struct Foo<|> { value: u32 }
590 ", 698 ",
591 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)", 699 "Foo STRUCT_DEF FileId(1) [0; 25) [7; 10)",
700 "struct Foo { value: u32 }|Foo",
592 ); 701 );
593 702
594 check_goto( 703 check_goto(
@@ -599,15 +708,16 @@ mod tests {
599 } 708 }
600 "#, 709 "#,
601 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)", 710 "field RECORD_FIELD_DEF FileId(1) [17; 30) [17; 22)",
711 "field: string|field",
602 ); 712 );
603 713
604 check_goto( 714 check_goto(
605 " 715 "
606 //- /lib.rs 716 //- /lib.rs
607 fn foo_test<|>() { 717 fn foo_test<|>() { }
608 }
609 ", 718 ",
610 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)", 719 "foo_test FN_DEF FileId(1) [0; 17) [3; 11)",
720 "fn foo_test() { }|foo_test",
611 ); 721 );
612 722
613 check_goto( 723 check_goto(
@@ -618,6 +728,7 @@ mod tests {
618 } 728 }
619 ", 729 ",
620 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)", 730 "Foo ENUM_DEF FileId(1) [0; 25) [5; 8)",
731 "enum Foo {...}|Foo",
621 ); 732 );
622 733
623 check_goto( 734 check_goto(
@@ -630,22 +741,25 @@ mod tests {
630 } 741 }
631 ", 742 ",
632 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)", 743 "Variant2 ENUM_VARIANT FileId(1) [29; 37) [29; 37)",
744 "Variant2|Variant2",
633 ); 745 );
634 746
635 check_goto( 747 check_goto(
636 r#" 748 r#"
637 //- /lib.rs 749 //- /lib.rs
638 static inner<|>: &str = ""; 750 static INNER<|>: &str = "";
639 "#, 751 "#,
640 "inner STATIC_DEF FileId(1) [0; 24) [7; 12)", 752 "INNER STATIC_DEF FileId(1) [0; 24) [7; 12)",
753 "static INNER: &str = \"\";|INNER",
641 ); 754 );
642 755
643 check_goto( 756 check_goto(
644 r#" 757 r#"
645 //- /lib.rs 758 //- /lib.rs
646 const inner<|>: &str = ""; 759 const INNER<|>: &str = "";
647 "#, 760 "#,
648 "inner CONST_DEF FileId(1) [0; 23) [6; 11)", 761 "INNER CONST_DEF FileId(1) [0; 23) [6; 11)",
762 "const INNER: &str = \"\";|INNER",
649 ); 763 );
650 764
651 check_goto( 765 check_goto(
@@ -654,24 +768,25 @@ mod tests {
654 type Thing<|> = Option<()>; 768 type Thing<|> = Option<()>;
655 "#, 769 "#,
656 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)", 770 "Thing TYPE_ALIAS_DEF FileId(1) [0; 24) [5; 10)",
771 "type Thing = Option<()>;|Thing",
657 ); 772 );
658 773
659 check_goto( 774 check_goto(
660 r#" 775 r#"
661 //- /lib.rs 776 //- /lib.rs
662 trait Foo<|> { 777 trait Foo<|> { }
663 }
664 "#, 778 "#,
665 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)", 779 "Foo TRAIT_DEF FileId(1) [0; 13) [6; 9)",
780 "trait Foo { }|Foo",
666 ); 781 );
667 782
668 check_goto( 783 check_goto(
669 r#" 784 r#"
670 //- /lib.rs 785 //- /lib.rs
671 mod bar<|> { 786 mod bar<|> { }
672 }
673 "#, 787 "#,
674 "bar MODULE FileId(1) [0; 11) [4; 7)", 788 "bar MODULE FileId(1) [0; 11) [4; 7)",
789 "mod bar { }|bar",
675 ); 790 );
676 } 791 }
677 792
@@ -689,8 +804,128 @@ mod tests {
689 fo<|>o(); 804 fo<|>o();
690 } 805 }
691 } 806 }
807 mod confuse_index { fn foo(); }
692 ", 808 ",
693 "foo FN_DEF FileId(1) [52; 63) [55; 58)", 809 "foo FN_DEF FileId(1) [52; 63) [55; 58)",
810 "fn foo() {}|foo",
694 ); 811 );
695 } 812 }
813
814 #[test]
815 fn goto_through_format() {
816 check_goto(
817 "
818 //- /lib.rs
819 #[macro_export]
820 macro_rules! format {
821 ($($arg:tt)*) => ($crate::fmt::format($crate::__export::format_args!($($arg)*)))
822 }
823 #[rustc_builtin_macro]
824 #[macro_export]
825 macro_rules! format_args {
826 ($fmt:expr) => ({ /* compiler built-in */ });
827 ($fmt:expr, $($args:tt)*) => ({ /* compiler built-in */ })
828 }
829 pub mod __export {
830 pub use crate::format_args;
831 fn foo() {} // for index confusion
832 }
833 fn foo() -> i8 {}
834 fn test() {
835 format!(\"{}\", fo<|>o())
836 }
837 ",
838 "foo FN_DEF FileId(1) [398; 415) [401; 404)",
839 "fn foo() -> i8 {}|foo",
840 );
841 }
842
843 #[test]
844 fn goto_for_type_param() {
845 check_goto(
846 "
847 //- /lib.rs
848 struct Foo<T> {
849 t: <|>T,
850 }
851 ",
852 "T TYPE_PARAM FileId(1) [11; 12)",
853 "T",
854 );
855 }
856
857 #[test]
858 fn goto_within_macro() {
859 check_goto(
860 "
861 //- /lib.rs
862 macro_rules! id {
863 ($($tt:tt)*) => ($($tt)*)
864 }
865
866 fn foo() {
867 let x = 1;
868 id!({
869 let y = <|>x;
870 let z = y;
871 });
872 }
873 ",
874 "x BIND_PAT FileId(1) [69; 70)",
875 "x",
876 );
877
878 check_goto(
879 "
880 //- /lib.rs
881 macro_rules! id {
882 ($($tt:tt)*) => ($($tt)*)
883 }
884
885 fn foo() {
886 let x = 1;
887 id!({
888 let y = x;
889 let z = <|>y;
890 });
891 }
892 ",
893 "y BIND_PAT FileId(1) [98; 99)",
894 "y",
895 );
896 }
897
898 #[test]
899 fn goto_def_in_local_fn() {
900 check_goto(
901 "
902 //- /lib.rs
903 fn main() {
904 fn foo() {
905 let x = 92;
906 <|>x;
907 }
908 }
909 ",
910 "x BIND_PAT FileId(1) [39; 40)",
911 "x",
912 );
913 }
914
915 #[test]
916 fn goto_def_for_field_init_shorthand() {
917 covers!(goto_def_for_field_init_shorthand);
918 check_goto(
919 "
920 //- /lib.rs
921 struct Foo { x: i32 }
922 fn main() {
923 let x = 92;
924 Foo { x<|> };
925 }
926 ",
927 "x RECORD_FIELD_DEF FileId(1) [13; 19) [13; 14)",
928 "x: i32|x",
929 )
930 }
696} 931}
diff --git a/crates/ra_ide/src/goto_type_definition.rs b/crates/ra_ide/src/goto_type_definition.rs
index 992a08809..ce8b6c72a 100644
--- a/crates/ra_ide/src/goto_type_definition.rs
+++ b/crates/ra_ide/src/goto_type_definition.rs
@@ -1,7 +1,7 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::db::AstDatabase; 3use hir::db::AstDatabase;
4use ra_syntax::{ast, AstNode}; 4use ra_syntax::{ast, AstNode, SyntaxKind::*, SyntaxToken, TokenAtOffset};
5 5
6use crate::{ 6use crate::{
7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget, 7 db::RootDatabase, display::ToNav, expand::descend_into_macros, FilePosition, NavigationTarget,
@@ -13,7 +13,7 @@ pub(crate) fn goto_type_definition(
13 position: FilePosition, 13 position: FilePosition,
14) -> Option<RangeInfo<Vec<NavigationTarget>>> { 14) -> Option<RangeInfo<Vec<NavigationTarget>>> {
15 let file = db.parse_or_expand(position.file_id.into())?; 15 let file = db.parse_or_expand(position.file_id.into())?;
16 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 16 let token = pick_best(file.token_at_offset(position.offset))?;
17 let token = descend_into_macros(db, position.file_id, token); 17 let token = descend_into_macros(db, position.file_id, token);
18 18
19 let node = token.value.ancestors().find_map(|token| { 19 let node = token.value.ancestors().find_map(|token| {
@@ -41,6 +41,17 @@ pub(crate) fn goto_type_definition(
41 Some(RangeInfo::new(node.text_range(), vec![nav])) 41 Some(RangeInfo::new(node.text_range(), vec![nav]))
42} 42}
43 43
44fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
45 return tokens.max_by_key(priority);
46 fn priority(n: &SyntaxToken) -> usize {
47 match n.kind() {
48 IDENT | INT_NUMBER => 2,
49 kind if kind.is_trivia() => 0,
50 _ => 1,
51 }
52 }
53}
54
44#[cfg(test)] 55#[cfg(test)]
45mod tests { 56mod tests {
46 use crate::mock_analysis::analysis_and_position; 57 use crate::mock_analysis::analysis_and_position;
@@ -102,4 +113,32 @@ mod tests {
102 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)", 113 "Foo STRUCT_DEF FileId(1) [52; 65) [59; 62)",
103 ); 114 );
104 } 115 }
116
117 #[test]
118 fn goto_type_definition_for_param() {
119 check_goto(
120 "
121 //- /lib.rs
122 struct Foo;
123 fn foo(<|>f: Foo) {}
124 ",
125 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
126 );
127 }
128
129 #[test]
130 fn goto_type_definition_for_tuple_field() {
131 check_goto(
132 "
133 //- /lib.rs
134 struct Foo;
135 struct Bar(Foo);
136 fn foo() {
137 let bar = Bar(Foo);
138 bar.<|>0;
139 }
140 ",
141 "Foo STRUCT_DEF FileId(1) [0; 11) [7; 10)",
142 );
143 }
105} 144}
diff --git a/crates/ra_ide/src/hover.rs b/crates/ra_ide/src/hover.rs
index 260a7b869..35e39f965 100644
--- a/crates/ra_ide/src/hover.rs
+++ b/crates/ra_ide/src/hover.rs
@@ -6,14 +6,13 @@ use ra_syntax::{
6 algo::find_covering_element, 6 algo::find_covering_element,
7 ast::{self, DocCommentsOwner}, 7 ast::{self, DocCommentsOwner},
8 match_ast, AstNode, 8 match_ast, AstNode,
9 SyntaxKind::*,
10 SyntaxToken, TokenAtOffset,
9}; 11};
10 12
11use crate::{ 13use crate::{
12 db::RootDatabase, 14 db::RootDatabase,
13 display::{ 15 display::{macro_label, rust_code_markup, rust_code_markup_with_doc, ShortLabel},
14 description_from_symbol, docs_from_symbol, macro_label, rust_code_markup,
15 rust_code_markup_with_doc, ShortLabel,
16 },
17 expand::descend_into_macros, 16 expand::descend_into_macros,
18 references::{classify_name, classify_name_ref, NameKind, NameKind::*}, 17 references::{classify_name, classify_name_ref, NameKind, NameKind::*},
19 FilePosition, FileRange, RangeInfo, 18 FilePosition, FileRange, RangeInfo,
@@ -93,11 +92,7 @@ fn hover_text(docs: Option<String>, desc: Option<String>) -> Option<String> {
93 } 92 }
94} 93}
95 94
96fn hover_text_from_name_kind( 95fn hover_text_from_name_kind(db: &RootDatabase, name_kind: NameKind) -> Option<String> {
97 db: &RootDatabase,
98 name_kind: NameKind,
99 no_fallback: &mut bool,
100) -> Option<String> {
101 return match name_kind { 96 return match name_kind {
102 Macro(it) => { 97 Macro(it) => {
103 let src = it.source(db); 98 let src = it.source(db);
@@ -133,12 +128,8 @@ fn hover_text_from_name_kind(
133 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it), 128 hir::ModuleDef::TypeAlias(it) => from_def_source(db, it),
134 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()), 129 hir::ModuleDef::BuiltinType(it) => Some(it.to_string()),
135 }, 130 },
136 Local(_) => { 131 Local(_) => None,
137 // Hover for these shows type names 132 TypeParam(_) | SelfType(_) => {
138 *no_fallback = true;
139 None
140 }
141 GenericParam(_) | SelfType(_) => {
142 // FIXME: Hover for generic param 133 // FIXME: Hover for generic param
143 None 134 None
144 } 135 }
@@ -156,68 +147,55 @@ fn hover_text_from_name_kind(
156 147
157pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> { 148pub(crate) fn hover(db: &RootDatabase, position: FilePosition) -> Option<RangeInfo<HoverResult>> {
158 let file = db.parse_or_expand(position.file_id.into())?; 149 let file = db.parse_or_expand(position.file_id.into())?;
159 let token = file.token_at_offset(position.offset).filter(|it| !it.kind().is_trivia()).next()?; 150 let token = pick_best(file.token_at_offset(position.offset))?;
160 let token = descend_into_macros(db, position.file_id, token); 151 let token = descend_into_macros(db, position.file_id, token);
161 152
162 let mut res = HoverResult::new(); 153 let mut res = HoverResult::new();
163 154
164 let mut range = match_ast! { 155 if let Some((range, name_kind)) = match_ast! {
165 match (token.value.parent()) { 156 match (token.value.parent()) {
166 ast::NameRef(name_ref) => { 157 ast::NameRef(name_ref) => {
167 let mut no_fallback = false; 158 classify_name_ref(db, token.with_value(&name_ref)).map(|d| (name_ref.syntax().text_range(), d.kind))
168 if let Some(name_kind) =
169 classify_name_ref(db, token.with_value(&name_ref)).map(|d| d.kind)
170 {
171 res.extend(hover_text_from_name_kind(db, name_kind, &mut no_fallback))
172 }
173
174 if res.is_empty() && !no_fallback {
175 // Fallback index based approach:
176 let symbols = crate::symbol_index::index_resolve(db, &name_ref);
177 for sym in symbols {
178 let docs = docs_from_symbol(db, &sym);
179 let desc = description_from_symbol(db, &sym);
180 res.extend(hover_text(docs, desc));
181 }
182 }
183
184 if !res.is_empty() {
185 Some(name_ref.syntax().text_range())
186 } else {
187 None
188 }
189 }, 159 },
190 ast::Name(name) => { 160 ast::Name(name) => {
191 if let Some(name_kind) = classify_name(db, token.with_value(&name)).map(|d| d.kind) { 161 classify_name(db, token.with_value(&name)).map(|d| (name.syntax().text_range(), d.kind))
192 res.extend(hover_text_from_name_kind(db, name_kind, &mut true));
193 }
194
195 if !res.is_empty() {
196 Some(name.syntax().text_range())
197 } else {
198 None
199 }
200 }, 162 },
201 _ => None, 163 _ => None,
202 } 164 }
203 }; 165 } {
166 res.extend(hover_text_from_name_kind(db, name_kind));
204 167
205 if range.is_none() { 168 if !res.is_empty() {
206 let node = token.value.ancestors().find(|n| { 169 return Some(RangeInfo::new(range, res));
207 ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some() 170 }
208 })?; 171 }
209 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
210 res.extend(type_of(db, frange).map(rust_code_markup));
211 range = Some(node.text_range());
212 };
213 172
214 let range = range?; 173 let node = token
174 .value
175 .ancestors()
176 .find(|n| ast::Expr::cast(n.clone()).is_some() || ast::Pat::cast(n.clone()).is_some())?;
177 let frange = FileRange { file_id: position.file_id, range: node.text_range() };
178 res.extend(type_of(db, frange).map(rust_code_markup));
215 if res.is_empty() { 179 if res.is_empty() {
216 return None; 180 return None;
217 } 181 }
182 let range = node.text_range();
183
218 Some(RangeInfo::new(range, res)) 184 Some(RangeInfo::new(range, res))
219} 185}
220 186
187fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
188 return tokens.max_by_key(priority);
189 fn priority(n: &SyntaxToken) -> usize {
190 match n.kind() {
191 IDENT | INT_NUMBER => 3,
192 L_PAREN | R_PAREN => 2,
193 kind if kind.is_trivia() => 0,
194 _ => 1,
195 }
196 }
197}
198
221pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> { 199pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
222 let parse = db.parse(frange.file_id); 200 let parse = db.parse(frange.file_id);
223 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range); 201 let leaf_node = find_covering_element(parse.tree().syntax(), frange.range);
@@ -227,7 +205,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
227 .take_while(|it| it.text_range() == leaf_node.text_range()) 205 .take_while(|it| it.text_range() == leaf_node.text_range())
228 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?; 206 .find(|it| ast::Expr::cast(it.clone()).is_some() || ast::Pat::cast(it.clone()).is_some())?;
229 let analyzer = 207 let analyzer =
230 hir::SourceAnalyzer::new(db, hir::Source::new(frange.file_id.into(), &node), None); 208 hir::SourceAnalyzer::new(db, hir::InFile::new(frange.file_id.into(), &node), None);
231 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e)) 209 let ty = if let Some(ty) = ast::Expr::cast(node.clone()).and_then(|e| analyzer.type_of(db, &e))
232 { 210 {
233 ty 211 ty
@@ -236,7 +214,7 @@ pub(crate) fn type_of(db: &RootDatabase, frange: FileRange) -> Option<String> {
236 } else { 214 } else {
237 return None; 215 return None;
238 }; 216 };
239 Some(ty.display(db).to_string()) 217 Some(ty.display_truncated(db, None).to_string())
240} 218}
241 219
242#[cfg(test)] 220#[cfg(test)]
@@ -300,7 +278,7 @@ mod tests {
300 &["pub fn foo() -> u32"], 278 &["pub fn foo() -> u32"],
301 ); 279 );
302 280
303 // Multiple results 281 // Multiple candidates but results are ambiguous.
304 check_hover_result( 282 check_hover_result(
305 r#" 283 r#"
306 //- /a.rs 284 //- /a.rs
@@ -321,7 +299,7 @@ mod tests {
321 let foo_test = fo<|>o(); 299 let foo_test = fo<|>o();
322 } 300 }
323 "#, 301 "#,
324 &["pub fn foo() -> &str", "pub fn foo() -> u32", "pub fn foo(a: u32, b: u32)"], 302 &["{unknown}"],
325 ); 303 );
326 } 304 }
327 305
@@ -411,6 +389,23 @@ mod tests {
411 } 389 }
412 390
413 #[test] 391 #[test]
392 fn hover_omits_default_generic_types() {
393 check_hover_result(
394 r#"
395//- /main.rs
396struct Test<K, T = u8> {
397 k: K,
398 t: T,
399}
400
401fn main() {
402 let zz<|> = Test { t: 23, k: 33 };
403}"#,
404 &["Test<i32>"],
405 );
406 }
407
408 #[test]
414 fn hover_some() { 409 fn hover_some() {
415 let (analysis, position) = single_file_with_position( 410 let (analysis, position) = single_file_with_position(
416 " 411 "
@@ -505,6 +500,13 @@ fn func(foo: i32) { if true { <|>foo; }; }
505 } 500 }
506 501
507 #[test] 502 #[test]
503 fn hover_for_param_edge() {
504 let (analysis, position) = single_file_with_position("fn func(<|>foo: i32) {}");
505 let hover = analysis.hover(position).unwrap().unwrap();
506 assert_eq!(trim_markup_opt(hover.info.first()), Some("i32"));
507 }
508
509 #[test]
508 fn test_type_of_for_function() { 510 fn test_type_of_for_function() {
509 let (analysis, range) = single_file_with_range( 511 let (analysis, range) = single_file_with_range(
510 " 512 "
diff --git a/crates/ra_ide/src/impls.rs b/crates/ra_ide/src/impls.rs
index aa480e399..9b165ee2a 100644
--- a/crates/ra_ide/src/impls.rs
+++ b/crates/ra_ide/src/impls.rs
@@ -16,7 +16,7 @@ pub(crate) fn goto_implementation(
16 let src = hir::ModuleSource::from_position(db, position); 16 let src = hir::ModuleSource::from_position(db, position);
17 let module = hir::Module::from_definition( 17 let module = hir::Module::from_definition(
18 db, 18 db,
19 hir::Source { file_id: position.file_id.into(), value: src }, 19 hir::InFile { file_id: position.file_id.into(), value: src },
20 )?; 20 )?;
21 21
22 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) { 22 if let Some(nominal_def) = find_node_at_offset::<ast::NominalDef>(&syntax, position.offset) {
@@ -42,15 +42,15 @@ fn impls_for_def(
42) -> Option<Vec<NavigationTarget>> { 42) -> Option<Vec<NavigationTarget>> {
43 let ty = match node { 43 let ty = match node {
44 ast::NominalDef::StructDef(def) => { 44 ast::NominalDef::StructDef(def) => {
45 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 45 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
46 hir::Struct::from_source(db, src)?.ty(db) 46 hir::Struct::from_source(db, src)?.ty(db)
47 } 47 }
48 ast::NominalDef::EnumDef(def) => { 48 ast::NominalDef::EnumDef(def) => {
49 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 49 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
50 hir::Enum::from_source(db, src)?.ty(db) 50 hir::Enum::from_source(db, src)?.ty(db)
51 } 51 }
52 ast::NominalDef::UnionDef(def) => { 52 ast::NominalDef::UnionDef(def) => {
53 let src = hir::Source { file_id: position.file_id.into(), value: def.clone() }; 53 let src = hir::InFile { file_id: position.file_id.into(), value: def.clone() };
54 hir::Union::from_source(db, src)?.ty(db) 54 hir::Union::from_source(db, src)?.ty(db)
55 } 55 }
56 }; 56 };
@@ -73,7 +73,7 @@ fn impls_for_trait(
73 node: &ast::TraitDef, 73 node: &ast::TraitDef,
74 module: hir::Module, 74 module: hir::Module,
75) -> Option<Vec<NavigationTarget>> { 75) -> Option<Vec<NavigationTarget>> {
76 let src = hir::Source { file_id: position.file_id.into(), value: node.clone() }; 76 let src = hir::InFile { file_id: position.file_id.into(), value: node.clone() };
77 let tr = hir::Trait::from_source(db, src)?; 77 let tr = hir::Trait::from_source(db, src)?;
78 78
79 let krate = module.krate(); 79 let krate = module.krate();
diff --git a/crates/ra_ide/src/inlay_hints.rs b/crates/ra_ide/src/inlay_hints.rs
index 45149bf0c..c5e406977 100644
--- a/crates/ra_ide/src/inlay_hints.rs
+++ b/crates/ra_ide/src/inlay_hints.rs
@@ -1,12 +1,15 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use crate::{db::RootDatabase, FileId};
4use hir::{HirDisplay, SourceAnalyzer}; 3use hir::{HirDisplay, SourceAnalyzer};
4use once_cell::unsync::Lazy;
5use ra_prof::profile;
5use ra_syntax::{ 6use ra_syntax::{
6 ast::{self, AstNode, TypeAscriptionOwner}, 7 ast::{self, AstNode, TypeAscriptionOwner},
7 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange, 8 match_ast, SmolStr, SourceFile, SyntaxKind, SyntaxNode, TextRange,
8}; 9};
9 10
11use crate::{db::RootDatabase, FileId};
12
10#[derive(Debug, PartialEq, Eq)] 13#[derive(Debug, PartialEq, Eq)]
11pub enum InlayKind { 14pub enum InlayKind {
12 TypeHint, 15 TypeHint,
@@ -27,7 +30,7 @@ pub(crate) fn inlay_hints(
27) -> Vec<InlayHint> { 30) -> Vec<InlayHint> {
28 file.syntax() 31 file.syntax()
29 .descendants() 32 .descendants()
30 .map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length).unwrap_or_default()) 33 .flat_map(|node| get_inlay_hints(db, file_id, &node, max_inlay_hint_length))
31 .flatten() 34 .flatten()
32 .collect() 35 .collect()
33} 36}
@@ -38,7 +41,9 @@ fn get_inlay_hints(
38 node: &SyntaxNode, 41 node: &SyntaxNode,
39 max_inlay_hint_length: Option<usize>, 42 max_inlay_hint_length: Option<usize>,
40) -> Option<Vec<InlayHint>> { 43) -> Option<Vec<InlayHint>> {
41 let analyzer = SourceAnalyzer::new(db, hir::Source::new(file_id.into(), node), None); 44 let _p = profile("get_inlay_hints");
45 let analyzer =
46 Lazy::new(|| SourceAnalyzer::new(db, hir::InFile::new(file_id.into(), node), None));
42 match_ast! { 47 match_ast! {
43 match node { 48 match node {
44 ast::LetStmt(it) => { 49 ast::LetStmt(it) => {
@@ -122,18 +127,11 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
122 127
123 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() { 128 while let Some(maybe_leaf_pat) = pats_to_process.pop_front() {
124 match &maybe_leaf_pat { 129 match &maybe_leaf_pat {
125 ast::Pat::BindPat(bind_pat) => { 130 ast::Pat::BindPat(bind_pat) => match bind_pat.pat() {
126 if let Some(pat) = bind_pat.pat() { 131 Some(pat) => pats_to_process.push_back(pat),
127 pats_to_process.push_back(pat); 132 _ => leaf_pats.push(maybe_leaf_pat),
128 } else { 133 },
129 leaf_pats.push(maybe_leaf_pat); 134 ast::Pat::TuplePat(tuple_pat) => pats_to_process.extend(tuple_pat.args()),
130 }
131 }
132 ast::Pat::TuplePat(tuple_pat) => {
133 for arg_pat in tuple_pat.args() {
134 pats_to_process.push_back(arg_pat);
135 }
136 }
137 ast::Pat::RecordPat(record_pat) => { 135 ast::Pat::RecordPat(record_pat) => {
138 if let Some(pat_list) = record_pat.record_field_pat_list() { 136 if let Some(pat_list) = record_pat.record_field_pat_list() {
139 pats_to_process.extend( 137 pats_to_process.extend(
@@ -151,10 +149,9 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
151 } 149 }
152 } 150 }
153 ast::Pat::TupleStructPat(tuple_struct_pat) => { 151 ast::Pat::TupleStructPat(tuple_struct_pat) => {
154 for arg_pat in tuple_struct_pat.args() { 152 pats_to_process.extend(tuple_struct_pat.args())
155 pats_to_process.push_back(arg_pat);
156 }
157 } 153 }
154 ast::Pat::RefPat(ref_pat) => pats_to_process.extend(ref_pat.pat()),
158 _ => (), 155 _ => (),
159 } 156 }
160 } 157 }
@@ -163,9 +160,36 @@ fn get_leaf_pats(root_pat: ast::Pat) -> Vec<ast::Pat> {
163 160
164#[cfg(test)] 161#[cfg(test)]
165mod tests { 162mod tests {
166 use crate::mock_analysis::single_file;
167 use insta::assert_debug_snapshot; 163 use insta::assert_debug_snapshot;
168 164
165 use crate::mock_analysis::single_file;
166
167 #[test]
168 fn default_generic_types_should_not_be_displayed() {
169 let (analysis, file_id) = single_file(
170 r#"
171struct Test<K, T = u8> {
172 k: K,
173 t: T,
174}
175
176fn main() {
177 let zz = Test { t: 23, k: 33 };
178}"#,
179 );
180
181 assert_debug_snapshot!(analysis.inlay_hints(file_id, None).unwrap(), @r###"
182 [
183 InlayHint {
184 range: [69; 71),
185 kind: TypeHint,
186 label: "Test<i32>",
187 },
188 ]
189 "###
190 );
191 }
192
169 #[test] 193 #[test]
170 fn let_statement() { 194 fn let_statement() {
171 let (analysis, file_id) = single_file( 195 let (analysis, file_id) = single_file(
@@ -202,6 +226,7 @@ fn main() {
202 226
203 let test = (42, 'a'); 227 let test = (42, 'a');
204 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5)); 228 let (a, (b, c, (d, e), f)) = (2, (3, 4, (6.6, 7.7), 5));
229 let &x = &92;
205}"#, 230}"#,
206 ); 231 );
207 232
@@ -257,6 +282,11 @@ fn main() {
257 kind: TypeHint, 282 kind: TypeHint,
258 label: "f64", 283 label: "f64",
259 }, 284 },
285 InlayHint {
286 range: [627; 628),
287 kind: TypeHint,
288 label: "i32",
289 },
260 ] 290 ]
261 "### 291 "###
262 ); 292 );
diff --git a/crates/ra_ide/src/lib.rs b/crates/ra_ide/src/lib.rs
index d1bff4a76..779a81b2c 100644
--- a/crates/ra_ide/src/lib.rs
+++ b/crates/ra_ide/src/lib.rs
@@ -422,6 +422,11 @@ impl Analysis {
422 self.with_db(|db| parent_module::crate_for(db, file_id)) 422 self.with_db(|db| parent_module::crate_for(db, file_id))
423 } 423 }
424 424
425 /// Returns the edition of the given crate.
426 pub fn crate_edition(&self, crate_id: CrateId) -> Cancelable<Edition> {
427 self.with_db(|db| db.crate_graph().edition(crate_id))
428 }
429
425 /// Returns the root file of the given crate. 430 /// Returns the root file of the given crate.
426 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> { 431 pub fn crate_root(&self, crate_id: CrateId) -> Cancelable<FileId> {
427 self.with_db(|db| db.crate_graph().crate_root(crate_id)) 432 self.with_db(|db| db.crate_graph().crate_root(crate_id))
diff --git a/crates/ra_ide/src/marks.rs b/crates/ra_ide/src/marks.rs
index 848ae4dc7..077a44473 100644
--- a/crates/ra_ide/src/marks.rs
+++ b/crates/ra_ide/src/marks.rs
@@ -3,10 +3,11 @@
3test_utils::marks!( 3test_utils::marks!(
4 inserts_angle_brackets_for_generics 4 inserts_angle_brackets_for_generics
5 inserts_parens_for_function_calls 5 inserts_parens_for_function_calls
6 goto_definition_works_for_macros 6 goto_def_for_macros
7 goto_definition_works_for_methods 7 goto_def_for_methods
8 goto_definition_works_for_fields 8 goto_def_for_fields
9 goto_definition_works_for_record_fields 9 goto_def_for_record_fields
10 goto_def_for_field_init_shorthand
10 call_info_bad_offset 11 call_info_bad_offset
11 dont_complete_current_use 12 dont_complete_current_use
12 dont_complete_primitive_in_use 13 dont_complete_primitive_in_use
diff --git a/crates/ra_ide/src/parent_module.rs b/crates/ra_ide/src/parent_module.rs
index 6027e7d54..f5a788c07 100644
--- a/crates/ra_ide/src/parent_module.rs
+++ b/crates/ra_ide/src/parent_module.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use ra_db::{CrateId, FileId, FilePosition}; 3use ra_db::{CrateId, FileId, FilePosition, SourceDatabase};
4 4
5use crate::{db::RootDatabase, NavigationTarget}; 5use crate::{db::RootDatabase, NavigationTarget};
6 6
@@ -10,7 +10,7 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
10 let src = hir::ModuleSource::from_position(db, position); 10 let src = hir::ModuleSource::from_position(db, position);
11 let module = match hir::Module::from_definition( 11 let module = match hir::Module::from_definition(
12 db, 12 db,
13 hir::Source { file_id: position.file_id.into(), value: src }, 13 hir::InFile { file_id: position.file_id.into(), value: src },
14 ) { 14 ) {
15 None => return Vec::new(), 15 None => return Vec::new(),
16 Some(it) => it, 16 Some(it) => it,
@@ -21,15 +21,16 @@ pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<Na
21 21
22/// Returns `Vec` for the same reason as `parent_module` 22/// Returns `Vec` for the same reason as `parent_module`
23pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> { 23pub(crate) fn crate_for(db: &RootDatabase, file_id: FileId) -> Vec<CrateId> {
24 let src = hir::ModuleSource::from_file_id(db, file_id); 24 let source_file = db.parse(file_id).tree();
25 let src = hir::ModuleSource::SourceFile(source_file);
25 let module = 26 let module =
26 match hir::Module::from_definition(db, hir::Source { file_id: file_id.into(), value: src }) 27 match hir::Module::from_definition(db, hir::InFile { file_id: file_id.into(), value: src })
27 { 28 {
28 Some(it) => it, 29 Some(it) => it,
29 None => return Vec::new(), 30 None => return Vec::new(),
30 }; 31 };
31 let krate = module.krate(); 32 let krate = module.krate();
32 vec![krate.crate_id()] 33 vec![krate.into()]
33} 34}
34 35
35#[cfg(test)] 36#[cfg(test)]
diff --git a/crates/ra_ide/src/references.rs b/crates/ra_ide/src/references.rs
index 21a1ea69e..e3ecde50d 100644
--- a/crates/ra_ide/src/references.rs
+++ b/crates/ra_ide/src/references.rs
@@ -14,7 +14,7 @@ mod name_definition;
14mod rename; 14mod rename;
15mod search_scope; 15mod search_scope;
16 16
17use hir::Source; 17use hir::InFile;
18use once_cell::unsync::Lazy; 18use once_cell::unsync::Lazy;
19use ra_db::{SourceDatabase, SourceDatabaseExt}; 19use ra_db::{SourceDatabase, SourceDatabaseExt};
20use ra_prof::profile; 20use ra_prof::profile;
@@ -85,7 +85,7 @@ pub(crate) fn find_all_refs(
85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?, 85 NameKind::Def(def) => NavigationTarget::from_def(db, def)?,
86 NameKind::SelfType(imp) => imp.to_nav(db), 86 NameKind::SelfType(imp) => imp.to_nav(db),
87 NameKind::Local(local) => local.to_nav(db), 87 NameKind::Local(local) => local.to_nav(db),
88 NameKind::GenericParam(_) => return None, 88 NameKind::TypeParam(_) => return None,
89 }; 89 };
90 90
91 let search_scope = { 91 let search_scope = {
@@ -107,12 +107,12 @@ fn find_name<'a>(
107 position: FilePosition, 107 position: FilePosition,
108) -> Option<RangeInfo<(String, NameDefinition)>> { 108) -> Option<RangeInfo<(String, NameDefinition)>> {
109 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) { 109 if let Some(name) = find_node_at_offset::<ast::Name>(&syntax, position.offset) {
110 let def = classify_name(db, Source::new(position.file_id.into(), &name))?; 110 let def = classify_name(db, InFile::new(position.file_id.into(), &name))?;
111 let range = name.syntax().text_range(); 111 let range = name.syntax().text_range();
112 return Some(RangeInfo::new(range, (name.text().to_string(), def))); 112 return Some(RangeInfo::new(range, (name.text().to_string(), def)));
113 } 113 }
114 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?; 114 let name_ref = find_node_at_offset::<ast::NameRef>(&syntax, position.offset)?;
115 let def = classify_name_ref(db, Source::new(position.file_id.into(), &name_ref))?; 115 let def = classify_name_ref(db, InFile::new(position.file_id.into(), &name_ref))?;
116 let range = name_ref.syntax().text_range(); 116 let range = name_ref.syntax().text_range();
117 Some(RangeInfo::new(range, (name_ref.text().to_string(), def))) 117 Some(RangeInfo::new(range, (name_ref.text().to_string(), def)))
118} 118}
@@ -144,7 +144,7 @@ fn process_definition(
144 continue; 144 continue;
145 } 145 }
146 } 146 }
147 if let Some(d) = classify_name_ref(db, Source::new(file_id.into(), &name_ref)) { 147 if let Some(d) = classify_name_ref(db, InFile::new(file_id.into(), &name_ref)) {
148 if d == def { 148 if d == def {
149 refs.push(FileRange { file_id, range }); 149 refs.push(FileRange { file_id, range });
150 } 150 }
diff --git a/crates/ra_ide/src/references/classify.rs b/crates/ra_ide/src/references/classify.rs
index 5cea805ec..3483a7176 100644
--- a/crates/ra_ide/src/references/classify.rs
+++ b/crates/ra_ide/src/references/classify.rs
@@ -1,6 +1,6 @@
1//! Functions that are used to classify an element from its definition or reference. 1//! Functions that are used to classify an element from its definition or reference.
2 2
3use hir::{FromSource, Module, ModuleSource, PathResolution, Source, SourceAnalyzer}; 3use hir::{FromSource, InFile, Module, ModuleSource, PathResolution, SourceAnalyzer};
4use ra_prof::profile; 4use ra_prof::profile;
5use ra_syntax::{ast, match_ast, AstNode}; 5use ra_syntax::{ast, match_ast, AstNode};
6use test_utils::tested_by; 6use test_utils::tested_by;
@@ -11,7 +11,7 @@ use super::{
11}; 11};
12use crate::db::RootDatabase; 12use crate::db::RootDatabase;
13 13
14pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Option<NameDefinition> { 14pub(crate) fn classify_name(db: &RootDatabase, name: InFile<&ast::Name>) -> Option<NameDefinition> {
15 let _p = profile("classify_name"); 15 let _p = profile("classify_name");
16 let parent = name.value.syntax().parent()?; 16 let parent = name.value.syntax().parent()?;
17 17
@@ -110,6 +110,15 @@ pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Opti
110 kind: NameKind::Macro(def), 110 kind: NameKind::Macro(def),
111 }) 111 })
112 }, 112 },
113 ast::TypeParam(it) => {
114 let src = name.with_value(it);
115 let def = hir::TypeParam::from_source(db, src)?;
116 Some(NameDefinition {
117 visibility: None,
118 container: def.module(db),
119 kind: NameKind::TypeParam(def),
120 })
121 },
113 _ => None, 122 _ => None,
114 } 123 }
115 } 124 }
@@ -117,7 +126,7 @@ pub(crate) fn classify_name(db: &RootDatabase, name: Source<&ast::Name>) -> Opti
117 126
118pub(crate) fn classify_name_ref( 127pub(crate) fn classify_name_ref(
119 db: &RootDatabase, 128 db: &RootDatabase,
120 name_ref: Source<&ast::NameRef>, 129 name_ref: InFile<&ast::NameRef>,
121) -> Option<NameDefinition> { 130) -> Option<NameDefinition> {
122 let _p = profile("classify_name_ref"); 131 let _p = profile("classify_name_ref");
123 132
@@ -125,21 +134,22 @@ pub(crate) fn classify_name_ref(
125 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None); 134 let analyzer = SourceAnalyzer::new(db, name_ref.map(|it| it.syntax()), None);
126 135
127 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) { 136 if let Some(method_call) = ast::MethodCallExpr::cast(parent.clone()) {
128 tested_by!(goto_definition_works_for_methods); 137 tested_by!(goto_def_for_methods);
129 if let Some(func) = analyzer.resolve_method_call(&method_call) { 138 if let Some(func) = analyzer.resolve_method_call(&method_call) {
130 return Some(from_assoc_item(db, func.into())); 139 return Some(from_assoc_item(db, func.into()));
131 } 140 }
132 } 141 }
133 142
134 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) { 143 if let Some(field_expr) = ast::FieldExpr::cast(parent.clone()) {
135 tested_by!(goto_definition_works_for_fields); 144 tested_by!(goto_def_for_fields);
136 if let Some(field) = analyzer.resolve_field(&field_expr) { 145 if let Some(field) = analyzer.resolve_field(&field_expr) {
137 return Some(from_struct_field(db, field)); 146 return Some(from_struct_field(db, field));
138 } 147 }
139 } 148 }
140 149
141 if let Some(record_field) = ast::RecordField::cast(parent.clone()) { 150 if let Some(record_field) = ast::RecordField::cast(parent.clone()) {
142 tested_by!(goto_definition_works_for_record_fields); 151 tested_by!(goto_def_for_record_fields);
152 tested_by!(goto_def_for_field_init_shorthand);
143 if let Some(field_def) = analyzer.resolve_record_field(&record_field) { 153 if let Some(field_def) = analyzer.resolve_record_field(&record_field) {
144 return Some(from_struct_field(db, field_def)); 154 return Some(from_struct_field(db, field_def));
145 } 155 }
@@ -151,7 +161,7 @@ pub(crate) fn classify_name_ref(
151 let visibility = None; 161 let visibility = None;
152 162
153 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) { 163 if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
154 tested_by!(goto_definition_works_for_macros); 164 tested_by!(goto_def_for_macros);
155 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) { 165 if let Some(macro_def) = analyzer.resolve_macro_call(db, name_ref.with_value(&macro_call)) {
156 let kind = NameKind::Macro(macro_def); 166 let kind = NameKind::Macro(macro_def);
157 return Some(NameDefinition { kind, container, visibility }); 167 return Some(NameDefinition { kind, container, visibility });
@@ -168,9 +178,8 @@ pub(crate) fn classify_name_ref(
168 let kind = NameKind::Local(local); 178 let kind = NameKind::Local(local);
169 Some(NameDefinition { kind, container, visibility: None }) 179 Some(NameDefinition { kind, container, visibility: None })
170 } 180 }
171 PathResolution::GenericParam(par) => { 181 PathResolution::TypeParam(par) => {
172 // FIXME: get generic param def 182 let kind = NameKind::TypeParam(par);
173 let kind = NameKind::GenericParam(par);
174 Some(NameDefinition { kind, container, visibility }) 183 Some(NameDefinition { kind, container, visibility })
175 } 184 }
176 PathResolution::Macro(def) => { 185 PathResolution::Macro(def) => {
diff --git a/crates/ra_ide/src/references/name_definition.rs b/crates/ra_ide/src/references/name_definition.rs
index 10d3a2364..8c67c8863 100644
--- a/crates/ra_ide/src/references/name_definition.rs
+++ b/crates/ra_ide/src/references/name_definition.rs
@@ -4,8 +4,8 @@
4//! Note that the reference search is possible for not all of the classified items. 4//! Note that the reference search is possible for not all of the classified items.
5 5
6use hir::{ 6use hir::{
7 Adt, AssocItem, GenericParam, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, 7 Adt, AssocItem, HasSource, ImplBlock, Local, MacroDef, Module, ModuleDef, StructField,
8 StructField, VariantDef, 8 TypeParam, VariantDef,
9}; 9};
10use ra_syntax::{ast, ast::VisibilityOwner}; 10use ra_syntax::{ast, ast::VisibilityOwner};
11 11
@@ -19,7 +19,7 @@ pub enum NameKind {
19 Def(ModuleDef), 19 Def(ModuleDef),
20 SelfType(ImplBlock), 20 SelfType(ImplBlock),
21 Local(Local), 21 Local(Local),
22 GenericParam(GenericParam), 22 TypeParam(TypeParam),
23} 23}
24 24
25#[derive(PartialEq, Eq)] 25#[derive(PartialEq, Eq)]
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs
index d58496049..b804d5f6d 100644
--- a/crates/ra_ide/src/references/rename.rs
+++ b/crates/ra_ide/src/references/rename.rs
@@ -2,7 +2,7 @@
2 2
3use hir::ModuleSource; 3use hir::ModuleSource;
4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt}; 4use ra_db::{RelativePath, RelativePathBuf, SourceDatabase, SourceDatabaseExt};
5use ra_syntax::{algo::find_node_at_offset, ast, AstNode, SyntaxNode}; 5use ra_syntax::{algo::find_node_at_offset, ast, tokenize, AstNode, SyntaxKind, SyntaxNode};
6use ra_text_edit::TextEdit; 6use ra_text_edit::TextEdit;
7 7
8use crate::{ 8use crate::{
@@ -17,6 +17,13 @@ pub(crate) fn rename(
17 position: FilePosition, 17 position: FilePosition,
18 new_name: &str, 18 new_name: &str,
19) -> Option<RangeInfo<SourceChange>> { 19) -> Option<RangeInfo<SourceChange>> {
20 let tokens = tokenize(new_name);
21 if tokens.len() != 1
22 || (tokens[0].kind != SyntaxKind::IDENT && tokens[0].kind != SyntaxKind::UNDERSCORE)
23 {
24 return None;
25 }
26
20 let parse = db.parse(position.file_id); 27 let parse = db.parse(position.file_id);
21 if let Some((ast_name, ast_module)) = 28 if let Some((ast_name, ast_module)) =
22 find_name_and_module_at_offset(parse.tree().syntax(), position) 29 find_name_and_module_at_offset(parse.tree().syntax(), position)
@@ -55,7 +62,7 @@ fn rename_mod(
55) -> Option<SourceChange> { 62) -> Option<SourceChange> {
56 let mut source_file_edits = Vec::new(); 63 let mut source_file_edits = Vec::new();
57 let mut file_system_edits = Vec::new(); 64 let mut file_system_edits = Vec::new();
58 let module_src = hir::Source { file_id: position.file_id.into(), value: ast_module.clone() }; 65 let module_src = hir::InFile { file_id: position.file_id.into(), value: ast_module.clone() };
59 if let Some(module) = hir::Module::from_declaration(db, module_src) { 66 if let Some(module) = hir::Module::from_declaration(db, module_src) {
60 let src = module.definition_source(db); 67 let src = module.definition_source(db);
61 let file_id = src.file_id.original_file(db); 68 let file_id = src.file_id.original_file(db);
@@ -124,6 +131,49 @@ mod tests {
124 }; 131 };
125 132
126 #[test] 133 #[test]
134 fn test_rename_to_underscore() {
135 test_rename(
136 r#"
137 fn main() {
138 let i<|> = 1;
139 }"#,
140 "_",
141 r#"
142 fn main() {
143 let _ = 1;
144 }"#,
145 );
146 }
147
148 #[test]
149 fn test_rename_to_raw_identifier() {
150 test_rename(
151 r#"
152 fn main() {
153 let i<|> = 1;
154 }"#,
155 "r#fn",
156 r#"
157 fn main() {
158 let r#fn = 1;
159 }"#,
160 );
161 }
162
163 #[test]
164 fn test_rename_to_invalid_identifier() {
165 let (analysis, position) = single_file_with_position(
166 "
167 fn main() {
168 let i<|> = 1;
169 }",
170 );
171 let new_name = "invalid!";
172 let source_change = analysis.rename(position, new_name).unwrap();
173 assert!(source_change.is_none());
174 }
175
176 #[test]
127 fn test_rename_for_local() { 177 fn test_rename_for_local() {
128 test_rename( 178 test_rename(
129 r#" 179 r#"
diff --git a/crates/ra_ide/src/references/search_scope.rs b/crates/ra_ide/src/references/search_scope.rs
index f5c9589f4..241dd358f 100644
--- a/crates/ra_ide/src/references/search_scope.rs
+++ b/crates/ra_ide/src/references/search_scope.rs
@@ -5,7 +5,7 @@
5use std::mem; 5use std::mem;
6 6
7use hir::{DefWithBody, HasSource, ModuleSource}; 7use hir::{DefWithBody, HasSource, ModuleSource};
8use ra_db::{FileId, SourceDatabase, SourceDatabaseExt}; 8use ra_db::{FileId, SourceDatabaseExt};
9use ra_prof::profile; 9use ra_prof::profile;
10use ra_syntax::{AstNode, TextRange}; 10use ra_syntax::{AstNode, TextRange};
11use rustc_hash::FxHashMap; 11use rustc_hash::FxHashMap;
@@ -120,15 +120,11 @@ impl NameDefinition {
120 } 120 }
121 if vis.as_str() == "pub" { 121 if vis.as_str() == "pub" {
122 let krate = self.container.krate(); 122 let krate = self.container.krate();
123 let crate_graph = db.crate_graph(); 123 for rev_dep in krate.reverse_dependencies(db) {
124 for crate_id in crate_graph.iter() { 124 let root_file = rev_dep.root_file(db);
125 let mut crate_deps = crate_graph.dependencies(crate_id); 125 let source_root_id = db.file_source_root(root_file);
126 if crate_deps.any(|dep| dep.crate_id() == krate.crate_id()) { 126 let source_root = db.source_root(source_root_id);
127 let root_file = crate_graph.crate_root(crate_id); 127 res.extend(source_root.walk().map(|id| (id, None)));
128 let source_root_id = db.file_source_root(root_file);
129 let source_root = db.source_root(source_root_id);
130 res.extend(source_root.walk().map(|id| (id, None)));
131 }
132 } 128 }
133 return SearchScope::new(res); 129 return SearchScope::new(res);
134 } 130 }
diff --git a/crates/ra_ide/src/runnables.rs b/crates/ra_ide/src/runnables.rs
index 8039a5164..e213e1a06 100644
--- a/crates/ra_ide/src/runnables.rs
+++ b/crates/ra_ide/src/runnables.rs
@@ -1,6 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use hir::Source; 3use hir::InFile;
4use itertools::Itertools; 4use itertools::Itertools;
5use ra_db::SourceDatabase; 5use ra_db::SourceDatabase;
6use ra_syntax::{ 6use ra_syntax::{
@@ -66,8 +66,8 @@ fn runnable_mod(db: &RootDatabase, file_id: FileId, module: ast::Module) -> Opti
66 return None; 66 return None;
67 } 67 }
68 let range = module.syntax().text_range(); 68 let range = module.syntax().text_range();
69 let src = hir::ModuleSource::from_child_node(db, Source::new(file_id.into(), &module.syntax())); 69 let src = hir::ModuleSource::from_child_node(db, InFile::new(file_id.into(), &module.syntax()));
70 let module = hir::Module::from_definition(db, Source::new(file_id.into(), src))?; 70 let module = hir::Module::from_definition(db, InFile::new(file_id.into(), src))?;
71 71
72 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::"); 72 let path = module.path_to_root(db).into_iter().rev().filter_map(|it| it.name(db)).join("::");
73 Some(Runnable { range, kind: RunnableKind::TestMod { path } }) 73 Some(Runnable { range, kind: RunnableKind::TestMod { path } })
diff --git a/crates/ra_ide/src/snapshots/highlighting.html b/crates/ra_ide/src/snapshots/highlighting.html
index b39c4d371..a097cf8e8 100644
--- a/crates/ra_ide/src/snapshots/highlighting.html
+++ b/crates/ra_ide/src/snapshots/highlighting.html
@@ -5,12 +5,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
13.type\.builtin { color: #8CD0D3; }
14.type\.param { color: #20999D; }
12.attribute { color: #94BFF3; } 15.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; }
14.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
15.variable { color: #DCDCCC; } 19.variable { color: #DCDCCC; }
16.variable\.mut { color: #DCDCCC; text-decoration: underline; } 20.variable\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -21,28 +25,37 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
21</style> 25</style>
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> 26<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> { 27<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>, 28 <span class="keyword">pub</span> <span class="field">x</span>: <span class="type.builtin">i32</span>,
25 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type">i32</span>, 29 <span class="keyword">pub</span> <span class="field">y</span>: <span class="type.builtin">i32</span>,
26} 30}
27 31
28<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type">T</span>&gt;() -&gt; <span class="type">T</span> { 32<span class="keyword">fn</span> <span class="function">foo</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type.param">T</span> {
29 <span class="macro">unimplemented</span><span class="macro">!</span>(); 33 <span class="macro">unimplemented</span><span class="macro">!</span>();
30 <span class="function">foo</span>::&lt;<span class="type">i32</span>&gt;(); 34 <span class="function">foo</span>::&lt;<span class="type.builtin">i32</span>&gt;();
31} 35}
32 36
33<span class="comment">// comment</span> 37<span class="comment">// comment</span>
34<span class="keyword">fn</span> <span class="function">main</span>() { 38<span class="keyword">fn</span> <span class="function">main</span>() {
35 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal">92</span>); 39 <span class="macro">println</span><span class="macro">!</span>(<span class="string">"Hello, {}!"</span>, <span class="literal.numeric">92</span>);
36 40
37 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>(); 41 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">vec</span> = <span class="text">Vec</span>::<span class="text">new</span>();
38 <span class="keyword.control">if</span> <span class="keyword">true</span> { 42 <span class="keyword.control">if</span> <span class="keyword">true</span> {
39 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>: <span class="literal">0</span>, <span class="field">y</span>: <span class="literal">1</span> }); 43 <span class="keyword">let</span> <span class="variable">x</span> = <span class="literal.numeric">92</span>;
44 <span class="variable.mut">vec</span>.<span class="text">push</span>(<span class="type">Foo</span> { <span class="field">x</span>, <span class="field">y</span>: <span class="literal.numeric">1</span> });
40 } 45 }
41 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal">0</span>); } 46 <span class="keyword.unsafe">unsafe</span> { <span class="variable.mut">vec</span>.<span class="text">set_len</span>(<span class="literal.numeric">0</span>); }
42 47
43 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal">42</span>; 48 <span class="keyword">let</span> <span class="keyword">mut</span> <span class="variable.mut">x</span> = <span class="literal.numeric">42</span>;
44 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>; 49 <span class="keyword">let</span> <span class="variable.mut">y</span> = &<span class="keyword">mut</span> <span class="variable.mut">x</span>;
45 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>; 50 <span class="keyword">let</span> <span class="variable">z</span> = &<span class="variable.mut">y</span>;
46 51
47 <span class="variable.mut">y</span>; 52 <span class="variable.mut">y</span>;
53}
54
55<span class="keyword">enum</span> <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
56 <span class="constant">V</span>(<span class="type.param">X</span>)
57}
58
59<span class="keyword">impl</span>&lt;<span class="type.param">X</span>&gt; <span class="type">E</span>&lt;<span class="type.param">X</span>&gt; {
60 <span class="keyword">fn</span> <span class="function">new</span>&lt;<span class="type.param">T</span>&gt;() -&gt; <span class="type">E</span>&lt;<span class="type.param">T</span>&gt; {}
48}</code></pre> \ No newline at end of file 61}</code></pre> \ No newline at end of file
diff --git a/crates/ra_ide/src/snapshots/rainbow_highlighting.html b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
index 79f11ea80..110556c09 100644
--- a/crates/ra_ide/src/snapshots/rainbow_highlighting.html
+++ b/crates/ra_ide/src/snapshots/rainbow_highlighting.html
@@ -5,12 +5,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
5 5
6.comment { color: #7F9F7F; } 6.comment { color: #7F9F7F; }
7.string { color: #CC9393; } 7.string { color: #CC9393; }
8.field { color: #94BFF3; }
8.function { color: #93E0E3; } 9.function { color: #93E0E3; }
9.parameter { color: #94BFF3; } 10.parameter { color: #94BFF3; }
10.builtin { color: #DD6718; }
11.text { color: #DCDCCC; } 11.text { color: #DCDCCC; }
12.type { color: #7CB8BB; }
13.type\.builtin { color: #8CD0D3; }
14.type\.param { color: #20999D; }
12.attribute { color: #94BFF3; } 15.attribute { color: #94BFF3; }
13.literal { color: #BFEBBF; } 16.literal { color: #BFEBBF; }
17.literal\.numeric { color: #6A8759; }
14.macro { color: #94BFF3; } 18.macro { color: #94BFF3; }
15.variable { color: #DCDCCC; } 19.variable { color: #DCDCCC; }
16.variable\.mut { color: #DCDCCC; text-decoration: underline; } 20.variable\.mut { color: #DCDCCC; text-decoration: underline; }
diff --git a/crates/ra_ide/src/syntax_highlighting.rs b/crates/ra_ide/src/syntax_highlighting.rs
index 9a3e4c82f..0228ee7e9 100644
--- a/crates/ra_ide/src/syntax_highlighting.rs
+++ b/crates/ra_ide/src/syntax_highlighting.rs
@@ -2,7 +2,7 @@
2 2
3use rustc_hash::{FxHashMap, FxHashSet}; 3use rustc_hash::{FxHashMap, FxHashSet};
4 4
5use hir::{Name, Source}; 5use hir::{InFile, Name};
6use ra_db::SourceDatabase; 6use ra_db::SourceDatabase;
7use ra_prof::profile; 7use ra_prof::profile;
8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T}; 8use ra_syntax::{ast, AstNode, Direction, SyntaxElement, SyntaxKind, SyntaxKind::*, TextRange, T};
@@ -16,6 +16,34 @@ use crate::{
16 FileId, 16 FileId,
17}; 17};
18 18
19pub mod tags {
20 pub(crate) const FIELD: &str = "field";
21 pub(crate) const FUNCTION: &str = "function";
22 pub(crate) const MODULE: &str = "module";
23 pub(crate) const TYPE: &str = "type";
24 pub(crate) const CONSTANT: &str = "constant";
25 pub(crate) const MACRO: &str = "macro";
26 pub(crate) const VARIABLE: &str = "variable";
27 pub(crate) const VARIABLE_MUT: &str = "variable.mut";
28 pub(crate) const TEXT: &str = "text";
29
30 pub(crate) const TYPE_BUILTIN: &str = "type.builtin";
31 pub(crate) const TYPE_SELF: &str = "type.self";
32 pub(crate) const TYPE_PARAM: &str = "type.param";
33 pub(crate) const TYPE_LIFETIME: &str = "type.lifetime";
34
35 pub(crate) const LITERAL_BYTE: &str = "literal.byte";
36 pub(crate) const LITERAL_NUMERIC: &str = "literal.numeric";
37 pub(crate) const LITERAL_CHAR: &str = "literal.char";
38 pub(crate) const LITERAL_COMMENT: &str = "comment";
39 pub(crate) const LITERAL_STRING: &str = "string";
40 pub(crate) const LITERAL_ATTRIBUTE: &str = "attribute";
41
42 pub(crate) const KEYWORD_UNSAFE: &str = "keyword.unsafe";
43 pub(crate) const KEYWORD_CONTROL: &str = "keyword.control";
44 pub(crate) const KEYWORD: &str = "keyword";
45}
46
19#[derive(Debug)] 47#[derive(Debug)]
20pub struct HighlightedRange { 48pub struct HighlightedRange {
21 pub range: TextRange, 49 pub range: TextRange,
@@ -71,17 +99,16 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
71 bindings_shadow_count.clear(); 99 bindings_shadow_count.clear();
72 continue; 100 continue;
73 } 101 }
74 COMMENT => "comment", 102 COMMENT => tags::LITERAL_COMMENT,
75 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => "string", 103 STRING | RAW_STRING | RAW_BYTE_STRING | BYTE_STRING => tags::LITERAL_STRING,
76 ATTR => "attribute", 104 ATTR => tags::LITERAL_ATTRIBUTE,
105 // Special-case field init shorthand
106 NAME_REF if node.parent().and_then(ast::RecordField::cast).is_some() => tags::FIELD,
107 NAME_REF if node.ancestors().any(|it| it.kind() == ATTR) => continue,
77 NAME_REF => { 108 NAME_REF => {
78 if node.ancestors().any(|it| it.kind() == ATTR) {
79 continue;
80 }
81
82 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap(); 109 let name_ref = node.as_node().cloned().and_then(ast::NameRef::cast).unwrap();
83 let name_kind = 110 let name_kind =
84 classify_name_ref(db, Source::new(file_id.into(), &name_ref)).map(|d| d.kind); 111 classify_name_ref(db, InFile::new(file_id.into(), &name_ref)).map(|d| d.kind);
85 112
86 if let Some(Local(local)) = &name_kind { 113 if let Some(Local(local)) = &name_kind {
87 if let Some(name) = local.name(db) { 114 if let Some(name) = local.name(db) {
@@ -90,12 +117,12 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
90 } 117 }
91 }; 118 };
92 119
93 name_kind.map_or("text", |it| highlight_name(db, it)) 120 name_kind.map_or(tags::TEXT, |it| highlight_name(db, it))
94 } 121 }
95 NAME => { 122 NAME => {
96 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap(); 123 let name = node.as_node().cloned().and_then(ast::Name::cast).unwrap();
97 let name_kind = 124 let name_kind =
98 classify_name(db, Source::new(file_id.into(), &name)).map(|d| d.kind); 125 classify_name(db, InFile::new(file_id.into(), &name)).map(|d| d.kind);
99 126
100 if let Some(Local(local)) = &name_kind { 127 if let Some(Local(local)) = &name_kind {
101 if let Some(name) = local.name(db) { 128 if let Some(name) = local.name(db) {
@@ -107,18 +134,21 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
107 134
108 match name_kind { 135 match name_kind {
109 Some(name_kind) => highlight_name(db, name_kind), 136 Some(name_kind) => highlight_name(db, name_kind),
110 None => name.syntax().parent().map_or("function", |x| match x.kind() { 137 None => name.syntax().parent().map_or(tags::FUNCTION, |x| match x.kind() {
111 TYPE_PARAM | STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => "type", 138 STRUCT_DEF | ENUM_DEF | TRAIT_DEF | TYPE_ALIAS_DEF => tags::TYPE,
112 RECORD_FIELD_DEF => "field", 139 TYPE_PARAM => tags::TYPE_PARAM,
113 _ => "function", 140 RECORD_FIELD_DEF => tags::FIELD,
141 _ => tags::FUNCTION,
114 }), 142 }),
115 } 143 }
116 } 144 }
117 INT_NUMBER | FLOAT_NUMBER | CHAR | BYTE => "literal", 145 INT_NUMBER | FLOAT_NUMBER => tags::LITERAL_NUMERIC,
118 LIFETIME => "parameter", 146 BYTE => tags::LITERAL_BYTE,
119 T![unsafe] => "keyword.unsafe", 147 CHAR => tags::LITERAL_CHAR,
120 k if is_control_keyword(k) => "keyword.control", 148 LIFETIME => tags::TYPE_LIFETIME,
121 k if k.is_keyword() => "keyword", 149 T![unsafe] => tags::KEYWORD_UNSAFE,
150 k if is_control_keyword(k) => tags::KEYWORD_CONTROL,
151 k if k.is_keyword() => tags::KEYWORD,
122 _ => { 152 _ => {
123 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) { 153 if let Some(macro_call) = node.as_node().cloned().and_then(ast::MacroCall::cast) {
124 if let Some(path) = macro_call.path() { 154 if let Some(path) = macro_call.path() {
@@ -135,7 +165,7 @@ pub(crate) fn highlight(db: &RootDatabase, file_id: FileId) -> Vec<HighlightedRa
135 } 165 }
136 res.push(HighlightedRange { 166 res.push(HighlightedRange {
137 range: TextRange::from_to(range_start, range_end), 167 range: TextRange::from_to(range_start, range_end),
138 tag: "macro", 168 tag: tags::MACRO,
139 binding_hash: None, 169 binding_hash: None,
140 }) 170 })
141 } 171 }
@@ -211,29 +241,27 @@ pub(crate) fn highlight_as_html(db: &RootDatabase, file_id: FileId, rainbow: boo
211 241
212fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str { 242fn highlight_name(db: &RootDatabase, name_kind: NameKind) -> &'static str {
213 match name_kind { 243 match name_kind {
214 Macro(_) => "macro", 244 Macro(_) => tags::MACRO,
215 Field(_) => "field", 245 Field(_) => tags::FIELD,
216 AssocItem(hir::AssocItem::Function(_)) => "function", 246 AssocItem(hir::AssocItem::Function(_)) => tags::FUNCTION,
217 AssocItem(hir::AssocItem::Const(_)) => "constant", 247 AssocItem(hir::AssocItem::Const(_)) => tags::CONSTANT,
218 AssocItem(hir::AssocItem::TypeAlias(_)) => "type", 248 AssocItem(hir::AssocItem::TypeAlias(_)) => tags::TYPE,
219 Def(hir::ModuleDef::Module(_)) => "module", 249 Def(hir::ModuleDef::Module(_)) => tags::MODULE,
220 Def(hir::ModuleDef::Function(_)) => "function", 250 Def(hir::ModuleDef::Function(_)) => tags::FUNCTION,
221 Def(hir::ModuleDef::Adt(_)) => "type", 251 Def(hir::ModuleDef::Adt(_)) => tags::TYPE,
222 Def(hir::ModuleDef::EnumVariant(_)) => "constant", 252 Def(hir::ModuleDef::EnumVariant(_)) => tags::CONSTANT,
223 Def(hir::ModuleDef::Const(_)) => "constant", 253 Def(hir::ModuleDef::Const(_)) => tags::CONSTANT,
224 Def(hir::ModuleDef::Static(_)) => "constant", 254 Def(hir::ModuleDef::Static(_)) => tags::CONSTANT,
225 Def(hir::ModuleDef::Trait(_)) => "type", 255 Def(hir::ModuleDef::Trait(_)) => tags::TYPE,
226 Def(hir::ModuleDef::TypeAlias(_)) => "type", 256 Def(hir::ModuleDef::TypeAlias(_)) => tags::TYPE,
227 Def(hir::ModuleDef::BuiltinType(_)) => "type", 257 Def(hir::ModuleDef::BuiltinType(_)) => tags::TYPE_BUILTIN,
228 SelfType(_) => "type", 258 SelfType(_) => tags::TYPE_SELF,
229 GenericParam(_) => "type", 259 TypeParam(_) => tags::TYPE_PARAM,
230 Local(local) => { 260 Local(local) => {
231 if local.is_mut(db) { 261 if local.is_mut(db) || local.ty(db).is_mutable_reference() {
232 "variable.mut" 262 tags::VARIABLE_MUT
233 } else if local.ty(db).is_mutable_reference() {
234 "variable.mut"
235 } else { 263 } else {
236 "variable" 264 tags::VARIABLE
237 } 265 }
238 } 266 }
239 } 267 }
@@ -251,12 +279,16 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
251 279
252.comment { color: #7F9F7F; } 280.comment { color: #7F9F7F; }
253.string { color: #CC9393; } 281.string { color: #CC9393; }
282.field { color: #94BFF3; }
254.function { color: #93E0E3; } 283.function { color: #93E0E3; }
255.parameter { color: #94BFF3; } 284.parameter { color: #94BFF3; }
256.builtin { color: #DD6718; }
257.text { color: #DCDCCC; } 285.text { color: #DCDCCC; }
286.type { color: #7CB8BB; }
287.type\\.builtin { color: #8CD0D3; }
288.type\\.param { color: #20999D; }
258.attribute { color: #94BFF3; } 289.attribute { color: #94BFF3; }
259.literal { color: #BFEBBF; } 290.literal { color: #BFEBBF; }
291.literal\\.numeric { color: #6A8759; }
260.macro { color: #94BFF3; } 292.macro { color: #94BFF3; }
261.variable { color: #DCDCCC; } 293.variable { color: #DCDCCC; }
262.variable\\.mut { color: #DCDCCC; text-decoration: underline; } 294.variable\\.mut { color: #DCDCCC; text-decoration: underline; }
@@ -293,7 +325,8 @@ fn main() {
293 325
294 let mut vec = Vec::new(); 326 let mut vec = Vec::new();
295 if true { 327 if true {
296 vec.push(Foo { x: 0, y: 1 }); 328 let x = 92;
329 vec.push(Foo { x, y: 1 });
297 } 330 }
298 unsafe { vec.set_len(0); } 331 unsafe { vec.set_len(0); }
299 332
@@ -303,6 +336,14 @@ fn main() {
303 336
304 y; 337 y;
305} 338}
339
340enum E<X> {
341 V(X)
342}
343
344impl<X> E<X> {
345 fn new<T>() -> E<T> {}
346}
306"# 347"#
307 .trim(), 348 .trim(),
308 ); 349 );
diff --git a/crates/ra_lsp_server/Cargo.toml b/crates/ra_lsp_server/Cargo.toml
index 21aef842c..60cbc38a9 100644
--- a/crates/ra_lsp_server/Cargo.toml
+++ b/crates/ra_lsp_server/Cargo.toml
@@ -13,9 +13,8 @@ relative-path = "1.0.0"
13serde_json = "1.0.34" 13serde_json = "1.0.34"
14serde = { version = "1.0.83", features = ["derive"] } 14serde = { version = "1.0.83", features = ["derive"] }
15crossbeam-channel = "0.4" 15crossbeam-channel = "0.4"
16flexi_logger = "0.14.0"
17log = "0.4.3" 16log = "0.4.3"
18lsp-types = { version = "0.61.0", features = ["proposed"] } 17lsp-types = { version = "0.66.0", features = ["proposed"] }
19rustc-hash = "1.0" 18rustc-hash = "1.0"
20parking_lot = "0.10.0" 19parking_lot = "0.10.0"
21jod-thread = "0.1.0" 20jod-thread = "0.1.0"
@@ -27,6 +26,7 @@ lsp-server = "0.3.0"
27ra_project_model = { path = "../ra_project_model" } 26ra_project_model = { path = "../ra_project_model" }
28ra_prof = { path = "../ra_prof" } 27ra_prof = { path = "../ra_prof" }
29ra_vfs_glob = { path = "../ra_vfs_glob" } 28ra_vfs_glob = { path = "../ra_vfs_glob" }
29env_logger = { version = "0.7.1", default-features = false, features = ["humantime"] }
30 30
31[dev-dependencies] 31[dev-dependencies]
32tempfile = "3" 32tempfile = "3"
diff --git a/crates/ra_lsp_server/build.rs b/crates/ra_lsp_server/build.rs
new file mode 100644
index 000000000..05f9772c0
--- /dev/null
+++ b/crates/ra_lsp_server/build.rs
@@ -0,0 +1,15 @@
1//! Just embed git-hash to `--version`
2
3use std::process::Command;
4
5fn main() {
6 let rev = rev().unwrap_or_else(|| "???????".to_string());
7 println!("cargo:rustc-env=REV={}", rev)
8}
9
10fn rev() -> Option<String> {
11 let output = Command::new("git").args(&["rev-parse", "HEAD"]).output().ok()?;
12 let stdout = String::from_utf8(output.stdout).ok()?;
13 let short_hash = stdout.get(0..7)?;
14 Some(short_hash.to_owned())
15}
diff --git a/crates/ra_lsp_server/src/caps.rs b/crates/ra_lsp_server/src/caps.rs
index eea0965ed..eeca67ee1 100644
--- a/crates/ra_lsp_server/src/caps.rs
+++ b/crates/ra_lsp_server/src/caps.rs
@@ -1,11 +1,12 @@
1//! FIXME: write short doc here 1//! Advertizes the capabilities of the LSP Server.
2 2
3use lsp_types::{ 3use lsp_types::{
4 CodeActionProviderCapability, CodeLensOptions, CompletionOptions, 4 CodeActionProviderCapability, CodeLensOptions, CompletionOptions,
5 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability, GenericCapability, 5 DocumentOnTypeFormattingOptions, FoldingRangeProviderCapability,
6 ImplementationProviderCapability, RenameOptions, RenameProviderCapability, ServerCapabilities, 6 ImplementationProviderCapability, RenameOptions, RenameProviderCapability,
7 SignatureHelpOptions, TextDocumentSyncCapability, TextDocumentSyncKind, 7 SelectionRangeProviderCapability, ServerCapabilities, SignatureHelpOptions,
8 TextDocumentSyncOptions, TypeDefinitionProviderCapability, 8 TextDocumentSyncCapability, TextDocumentSyncKind, TextDocumentSyncOptions,
9 TypeDefinitionProviderCapability, WorkDoneProgressOptions,
9}; 10};
10 11
11pub fn server_capabilities() -> ServerCapabilities { 12pub fn server_capabilities() -> ServerCapabilities {
@@ -21,10 +22,14 @@ pub fn server_capabilities() -> ServerCapabilities {
21 completion_provider: Some(CompletionOptions { 22 completion_provider: Some(CompletionOptions {
22 resolve_provider: None, 23 resolve_provider: None,
23 trigger_characters: Some(vec![":".to_string(), ".".to_string()]), 24 trigger_characters: Some(vec![":".to_string(), ".".to_string()]),
25 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
24 }), 26 }),
25 signature_help_provider: Some(SignatureHelpOptions { 27 signature_help_provider: Some(SignatureHelpOptions {
26 trigger_characters: Some(vec!["(".to_string(), ",".to_string(), ")".to_string()]), 28 trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
29 retrigger_characters: None,
30 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
27 }), 31 }),
32 declaration_provider: None,
28 definition_provider: Some(true), 33 definition_provider: Some(true),
29 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)), 34 type_definition_provider: Some(TypeDefinitionProviderCapability::Simple(true)),
30 implementation_provider: Some(ImplementationProviderCapability::Simple(true)), 35 implementation_provider: Some(ImplementationProviderCapability::Simple(true)),
@@ -40,10 +45,11 @@ pub fn server_capabilities() -> ServerCapabilities {
40 first_trigger_character: "=".to_string(), 45 first_trigger_character: "=".to_string(),
41 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), 46 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]),
42 }), 47 }),
43 selection_range_provider: Some(GenericCapability::default()), 48 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
44 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 49 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
45 rename_provider: Some(RenameProviderCapability::Options(RenameOptions { 50 rename_provider: Some(RenameProviderCapability::Options(RenameOptions {
46 prepare_provider: Some(true), 51 prepare_provider: Some(true),
52 work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
47 })), 53 })),
48 document_link_provider: None, 54 document_link_provider: None,
49 color_provider: None, 55 color_provider: None,
diff --git a/crates/ra_lsp_server/src/config.rs b/crates/ra_lsp_server/src/config.rs
index 8045f3d60..67942aa41 100644
--- a/crates/ra_lsp_server/src/config.rs
+++ b/crates/ra_lsp_server/src/config.rs
@@ -9,6 +9,7 @@
9 9
10use rustc_hash::FxHashMap; 10use rustc_hash::FxHashMap;
11 11
12use ra_project_model::CargoFeatures;
12use serde::{Deserialize, Deserializer}; 13use serde::{Deserialize, Deserializer};
13 14
14/// Client provided initialization options 15/// Client provided initialization options
@@ -37,6 +38,9 @@ pub struct ServerConfig {
37 38
38 /// Fine grained feature flags to disable specific features. 39 /// Fine grained feature flags to disable specific features.
39 pub feature_flags: FxHashMap<String, bool>, 40 pub feature_flags: FxHashMap<String, bool>,
41
42 /// Cargo feature configurations.
43 pub cargo_features: CargoFeatures,
40} 44}
41 45
42impl Default for ServerConfig { 46impl Default for ServerConfig {
@@ -49,6 +53,7 @@ impl Default for ServerConfig {
49 max_inlay_hint_length: None, 53 max_inlay_hint_length: None,
50 with_sysroot: true, 54 with_sysroot: true,
51 feature_flags: FxHashMap::default(), 55 feature_flags: FxHashMap::default(),
56 cargo_features: Default::default(),
52 } 57 }
53 } 58 }
54} 59}
diff --git a/crates/ra_lsp_server/src/conv.rs b/crates/ra_lsp_server/src/conv.rs
index b13093cfe..e93d4ea33 100644
--- a/crates/ra_lsp_server/src/conv.rs
+++ b/crates/ra_lsp_server/src/conv.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Convenience module responsible for translating between rust-analyzer's types and LSP types.
2 2
3use lsp_types::{ 3use lsp_types::{
4 self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation, 4 self, CreateFile, DiagnosticSeverity, DocumentChangeOperation, DocumentChanges, Documentation,
@@ -130,6 +130,11 @@ impl ConvWith<(&LineIndex, LineEndings)> for CompletionItem {
130 deprecated: Some(self.deprecated()), 130 deprecated: Some(self.deprecated()),
131 ..Default::default() 131 ..Default::default()
132 }; 132 };
133
134 if self.deprecated() {
135 res.tags = Some(vec![lsp_types::CompletionItemTag::Deprecated])
136 }
137
133 res.insert_text_format = Some(match self.insert_text_format() { 138 res.insert_text_format = Some(match self.insert_text_format() {
134 InsertTextFormat::Snippet => lsp_types::InsertTextFormat::Snippet, 139 InsertTextFormat::Snippet => lsp_types::InsertTextFormat::Snippet,
135 InsertTextFormat::PlainText => lsp_types::InsertTextFormat::PlainText, 140 InsertTextFormat::PlainText => lsp_types::InsertTextFormat::PlainText,
diff --git a/crates/ra_lsp_server/src/main.rs b/crates/ra_lsp_server/src/main.rs
index e13c8ca14..cdd925c9f 100644
--- a/crates/ra_lsp_server/src/main.rs
+++ b/crates/ra_lsp_server/src/main.rs
@@ -1,24 +1,22 @@
1//! `ra_lsp_server` binary 1//! `ra_lsp_server` binary
2 2
3use flexi_logger::{Duplicate, Logger};
4use lsp_server::Connection; 3use lsp_server::Connection;
5use ra_lsp_server::{show_message, Result, ServerConfig}; 4use ra_lsp_server::{show_message, Result, ServerConfig};
6use ra_prof; 5use ra_prof;
7 6
8fn main() -> Result<()> { 7fn main() -> Result<()> {
9 setup_logging()?; 8 setup_logging()?;
10 run_server()?; 9 match Args::parse()? {
10 Args::Version => println!("rust-analyzer {}", env!("REV")),
11 Args::Run => run_server()?,
12 }
11 Ok(()) 13 Ok(())
12} 14}
13 15
14fn setup_logging() -> Result<()> { 16fn setup_logging() -> Result<()> {
15 std::env::set_var("RUST_BACKTRACE", "short"); 17 std::env::set_var("RUST_BACKTRACE", "short");
16 18
17 let logger = Logger::with_env_or_str("error").duplicate_to_stderr(Duplicate::All); 19 env_logger::try_init()?;
18 match std::env::var("RA_LOG_DIR") {
19 Ok(ref v) if v == "1" => logger.log_to_file().directory("log").start()?,
20 _ => logger.start()?,
21 };
22 20
23 ra_prof::set_filter(match std::env::var("RA_PROFILE") { 21 ra_prof::set_filter(match std::env::var("RA_PROFILE") {
24 Ok(spec) => ra_prof::Filter::from_spec(&spec), 22 Ok(spec) => ra_prof::Filter::from_spec(&spec),
@@ -27,6 +25,19 @@ fn setup_logging() -> Result<()> {
27 Ok(()) 25 Ok(())
28} 26}
29 27
28enum Args {
29 Version,
30 Run,
31}
32
33impl Args {
34 fn parse() -> Result<Args> {
35 let res =
36 if std::env::args().any(|it| it == "--version") { Args::Version } else { Args::Run };
37 Ok(res)
38 }
39}
40
30fn run_server() -> Result<()> { 41fn run_server() -> Result<()> {
31 log::info!("lifecycle: server started"); 42 log::info!("lifecycle: server started");
32 43
diff --git a/crates/ra_lsp_server/src/main_loop.rs b/crates/ra_lsp_server/src/main_loop.rs
index 83845f1e0..dda318e43 100644
--- a/crates/ra_lsp_server/src/main_loop.rs
+++ b/crates/ra_lsp_server/src/main_loop.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! The main loop of `ra_lsp_server` responsible for dispatching LSP requests/replies and
2//! notifications back to the client.
2 3
3mod handlers; 4mod handlers;
4mod subscriptions; 5mod subscriptions;
@@ -67,6 +68,7 @@ pub fn main_loop(
67 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot( 68 let workspace = ra_project_model::ProjectWorkspace::discover_with_sysroot(
68 ws_root.as_path(), 69 ws_root.as_path(),
69 config.with_sysroot, 70 config.with_sysroot,
71 &config.cargo_features,
70 ); 72 );
71 match workspace { 73 match workspace {
72 Ok(workspace) => loaded_workspaces.push(workspace), 74 Ok(workspace) => loaded_workspaces.push(workspace),
@@ -130,7 +132,7 @@ pub fn main_loop(
130 let feature_flags = { 132 let feature_flags = {
131 let mut ff = FeatureFlags::default(); 133 let mut ff = FeatureFlags::default();
132 for (flag, value) in config.feature_flags { 134 for (flag, value) in config.feature_flags {
133 if let Err(_) = ff.set(flag.as_str(), value) { 135 if ff.set(flag.as_str(), value).is_err() {
134 log::error!("unknown feature flag: {:?}", flag); 136 log::error!("unknown feature flag: {:?}", flag);
135 show_message( 137 show_message(
136 req::MessageType::Error, 138 req::MessageType::Error,
@@ -303,7 +305,6 @@ fn loop_turn(
303 log::info!("queued count = {}", queue_count); 305 log::info!("queued count = {}", queue_count);
304 } 306 }
305 307
306 let mut state_changed = false;
307 match event { 308 match event {
308 Event::Task(task) => { 309 Event::Task(task) => {
309 on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state); 310 on_task(task, &connection.sender, &mut loop_state.pending_requests, world_state);
@@ -311,7 +312,6 @@ fn loop_turn(
311 } 312 }
312 Event::Vfs(task) => { 313 Event::Vfs(task) => {
313 world_state.vfs.write().handle_task(task); 314 world_state.vfs.write().handle_task(task);
314 state_changed = true;
315 } 315 }
316 Event::Lib(lib) => { 316 Event::Lib(lib) => {
317 world_state.add_lib(lib); 317 world_state.add_lib(lib);
@@ -336,7 +336,6 @@ fn loop_turn(
336 &mut loop_state.subscriptions, 336 &mut loop_state.subscriptions,
337 not, 337 not,
338 )?; 338 )?;
339 state_changed = true;
340 } 339 }
341 Message::Response(resp) => { 340 Message::Response(resp) => {
342 let removed = loop_state.pending_responses.remove(&resp.id); 341 let removed = loop_state.pending_responses.remove(&resp.id);
@@ -347,7 +346,12 @@ fn loop_turn(
347 }, 346 },
348 }; 347 };
349 348
350 loop_state.pending_libraries.extend(world_state.process_changes()); 349 let mut state_changed = false;
350 if let Some(changes) = world_state.process_changes() {
351 state_changed = true;
352 loop_state.pending_libraries.extend(changes);
353 }
354
351 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS 355 while loop_state.in_flight_libraries < MAX_IN_FLIGHT_LIBS
352 && !loop_state.pending_libraries.is_empty() 356 && !loop_state.pending_libraries.is_empty()
353 { 357 {
@@ -520,7 +524,8 @@ fn on_notification(
520 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) { 524 if let Some(file_id) = state.vfs.write().remove_file_overlay(path.as_path()) {
521 subs.remove_sub(FileId(file_id.0)); 525 subs.remove_sub(FileId(file_id.0));
522 } 526 }
523 let params = req::PublishDiagnosticsParams { uri, diagnostics: Vec::new() }; 527 let params =
528 req::PublishDiagnosticsParams { uri, diagnostics: Vec::new(), version: None };
524 let not = notification_new::<req::PublishDiagnostics>(params); 529 let not = notification_new::<req::PublishDiagnostics>(params);
525 msg_sender.send(not.into()).unwrap(); 530 msg_sender.send(not.into()).unwrap();
526 return Ok(()); 531 return Ok(());
diff --git a/crates/ra_lsp_server/src/main_loop/handlers.rs b/crates/ra_lsp_server/src/main_loop/handlers.rs
index c81fa7f67..39eb3df3e 100644
--- a/crates/ra_lsp_server/src/main_loop/handlers.rs
+++ b/crates/ra_lsp_server/src/main_loop/handlers.rs
@@ -1,4 +1,5 @@
1//! FIXME: write short doc here 1//! This module is responsible for implementing handlers for Lanuage Server Protocol.
2//! The majority of requests are fulfilled by calling into the `ra_ide` crate.
2 3
3use std::{fmt::Write as _, io::Write as _}; 4use std::{fmt::Write as _, io::Write as _};
4 5
@@ -164,7 +165,7 @@ pub fn handle_on_type_formatting(
164 165
165 // in `ra_ide`, the `on_type` invariant is that 166 // in `ra_ide`, the `on_type` invariant is that
166 // `text.char_at(position) == typed_char`. 167 // `text.char_at(position) == typed_char`.
167 position.offset = position.offset - TextUnit::of_char('.'); 168 position.offset -= TextUnit::of_char('.');
168 let char_typed = params.ch.chars().next().unwrap_or('\0'); 169 let char_typed = params.ch.chars().next().unwrap_or('\0');
169 170
170 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`, 171 // We have an assist that inserts ` ` after typing `->` in `fn foo() ->{`,
@@ -480,8 +481,6 @@ pub fn handle_prepare_rename(
480 let _p = profile("handle_prepare_rename"); 481 let _p = profile("handle_prepare_rename");
481 let position = params.try_conv_with(&world)?; 482 let position = params.try_conv_with(&world)?;
482 483
483 // We support renaming references like handle_rename does.
484 // In the future we may want to reject the renaming of things like keywords here too.
485 let optional_change = world.analysis().rename(position, "dummy")?; 484 let optional_change = world.analysis().rename(position, "dummy")?;
486 let range = match optional_change { 485 let range = match optional_change {
487 None => return Ok(None), 486 None => return Ok(None),
@@ -557,12 +556,18 @@ pub fn handle_formatting(
557 let _p = profile("handle_formatting"); 556 let _p = profile("handle_formatting");
558 let file_id = params.text_document.try_conv_with(&world)?; 557 let file_id = params.text_document.try_conv_with(&world)?;
559 let file = world.analysis().file_text(file_id)?; 558 let file = world.analysis().file_text(file_id)?;
559 let crate_ids = world.analysis().crate_for(file_id)?;
560 560
561 let file_line_index = world.analysis().file_line_index(file_id)?; 561 let file_line_index = world.analysis().file_line_index(file_id)?;
562 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index); 562 let end_position = TextUnit::of_str(&file).conv_with(&file_line_index);
563 563
564 use std::process; 564 use std::process;
565 let mut rustfmt = process::Command::new("rustfmt"); 565 let mut rustfmt = process::Command::new("rustfmt");
566 if let Some(&crate_id) = crate_ids.first() {
567 // Assume all crates are in the same edition
568 let edition = world.analysis().crate_edition(crate_id)?;
569 rustfmt.args(&["--edition", &edition.to_string()]);
570 }
566 rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped()); 571 rustfmt.stdin(process::Stdio::piped()).stdout(process::Stdio::piped());
567 572
568 if let Ok(path) = params.text_document.uri.to_file_path() { 573 if let Ok(path) = params.text_document.uri.to_file_path() {
@@ -644,6 +649,7 @@ pub fn handle_code_action(
644 diagnostics: None, 649 diagnostics: None,
645 edit: None, 650 edit: None,
646 command: Some(command), 651 command: Some(command),
652 is_preferred: None,
647 }; 653 };
648 res.push(action.into()); 654 res.push(action.into());
649 } 655 }
@@ -666,6 +672,7 @@ pub fn handle_code_action(
666 diagnostics: None, 672 diagnostics: None,
667 edit: None, 673 edit: None,
668 command: Some(command), 674 command: Some(command),
675 is_preferred: None,
669 }; 676 };
670 res.push(action.into()); 677 res.push(action.into());
671 } 678 }
@@ -824,9 +831,10 @@ pub fn publish_diagnostics(
824 source: Some("rust-analyzer".to_string()), 831 source: Some("rust-analyzer".to_string()),
825 message: d.message, 832 message: d.message,
826 related_information: None, 833 related_information: None,
834 tags: None,
827 }) 835 })
828 .collect(); 836 .collect();
829 Ok(req::PublishDiagnosticsParams { uri, diagnostics }) 837 Ok(req::PublishDiagnosticsParams { uri, diagnostics, version: None })
830} 838}
831 839
832pub fn publish_decorations( 840pub fn publish_decorations(
diff --git a/crates/ra_lsp_server/src/main_loop/pending_requests.rs b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
index e7ea7aa5b..2d2213464 100644
--- a/crates/ra_lsp_server/src/main_loop/pending_requests.rs
+++ b/crates/ra_lsp_server/src/main_loop/pending_requests.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Datastructures that keep track of inflight requests.
2 2
3use std::time::{Duration, Instant}; 3use std::time::{Duration, Instant};
4 4
diff --git a/crates/ra_lsp_server/src/main_loop/subscriptions.rs b/crates/ra_lsp_server/src/main_loop/subscriptions.rs
index 609b2adcc..b0bae90f5 100644
--- a/crates/ra_lsp_server/src/main_loop/subscriptions.rs
+++ b/crates/ra_lsp_server/src/main_loop/subscriptions.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Keeps track of file subscriptions.
2 2
3use ra_ide::FileId; 3use ra_ide::FileId;
4use rustc_hash::FxHashSet; 4use rustc_hash::FxHashSet;
diff --git a/crates/ra_lsp_server/src/markdown.rs b/crates/ra_lsp_server/src/markdown.rs
index f51fc4ade..76bef45cc 100644
--- a/crates/ra_lsp_server/src/markdown.rs
+++ b/crates/ra_lsp_server/src/markdown.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Transforms markdown
2 2
3pub(crate) fn format_docs(src: &str) -> String { 3pub(crate) fn format_docs(src: &str) -> String {
4 let mut processed_lines = Vec::new(); 4 let mut processed_lines = Vec::new();
diff --git a/crates/ra_lsp_server/src/req.rs b/crates/ra_lsp_server/src/req.rs
index 39361b7e8..b34e6f9b8 100644
--- a/crates/ra_lsp_server/src/req.rs
+++ b/crates/ra_lsp_server/src/req.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Defines `rust-analyzer` specific custom messages.
2 2
3use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url}; 3use lsp_types::{Location, Position, Range, TextDocumentIdentifier, Url};
4use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
@@ -10,8 +10,9 @@ pub use lsp_types::{
10 DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions, 10 DidChangeWatchedFilesParams, DidChangeWatchedFilesRegistrationOptions,
11 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse, 11 DocumentOnTypeFormattingParams, DocumentSymbolParams, DocumentSymbolResponse,
12 FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams, 12 FileSystemWatcher, Hover, InitializeResult, MessageType, PublishDiagnosticsParams,
13 ReferenceParams, Registration, RegistrationParams, ShowMessageParams, SignatureHelp, 13 ReferenceParams, Registration, RegistrationParams, SelectionRange, SelectionRangeParams,
14 TextDocumentEdit, TextDocumentPositionParams, TextEdit, WorkspaceEdit, WorkspaceSymbolParams, 14 ShowMessageParams, SignatureHelp, TextDocumentEdit, TextDocumentPositionParams, TextEdit,
15 WorkspaceEdit, WorkspaceSymbolParams,
15}; 16};
16 17
17pub enum AnalyzerStatus {} 18pub enum AnalyzerStatus {}
@@ -67,28 +68,6 @@ pub struct ExpandMacroParams {
67 pub position: Option<Position>, 68 pub position: Option<Position>,
68} 69}
69 70
70pub enum SelectionRangeRequest {}
71
72impl Request for SelectionRangeRequest {
73 type Params = SelectionRangeParams;
74 type Result = Vec<SelectionRange>;
75 const METHOD: &'static str = "textDocument/selectionRange";
76}
77
78#[derive(Deserialize, Debug)]
79#[serde(rename_all = "camelCase")]
80pub struct SelectionRangeParams {
81 pub text_document: TextDocumentIdentifier,
82 pub positions: Vec<Position>,
83}
84
85#[derive(Serialize, Debug)]
86#[serde(rename_all = "camelCase")]
87pub struct SelectionRange {
88 pub range: Range,
89 pub parent: Option<Box<SelectionRange>>,
90}
91
92pub enum FindMatchingBrace {} 71pub enum FindMatchingBrace {}
93 72
94impl Request for FindMatchingBrace { 73impl Request for FindMatchingBrace {
diff --git a/crates/ra_lsp_server/src/world.rs b/crates/ra_lsp_server/src/world.rs
index 927449b45..79431e7e6 100644
--- a/crates/ra_lsp_server/src/world.rs
+++ b/crates/ra_lsp_server/src/world.rs
@@ -1,4 +1,7 @@
1//! FIXME: write short doc here 1//! The context or environment in which the language server functions.
2//! In our server implementation this is know as the `WorldState`.
3//!
4//! Each tick provides an immutable snapshot of the state as `WorldSnapshot`.
2 5
3use std::{ 6use std::{
4 path::{Path, PathBuf}, 7 path::{Path, PathBuf},
@@ -17,11 +20,13 @@ use ra_project_model::{get_rustc_cfg_options, ProjectWorkspace};
17use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch}; 20use ra_vfs::{LineEndings, RootEntry, Vfs, VfsChange, VfsFile, VfsRoot, VfsTask, Watch};
18use ra_vfs_glob::{Glob, RustPackageFilterBuilder}; 21use ra_vfs_glob::{Glob, RustPackageFilterBuilder};
19use relative_path::RelativePathBuf; 22use relative_path::RelativePathBuf;
23use std::path::{Component, Prefix};
20 24
21use crate::{ 25use crate::{
22 main_loop::pending_requests::{CompletedRequest, LatestRequests}, 26 main_loop::pending_requests::{CompletedRequest, LatestRequests},
23 LspError, Result, 27 LspError, Result,
24}; 28};
29use std::str::FromStr;
25 30
26#[derive(Debug, Clone)] 31#[derive(Debug, Clone)]
27pub struct Options { 32pub struct Options {
@@ -140,10 +145,10 @@ impl WorldState {
140 /// FIXME: better API here 145 /// FIXME: better API here
141 pub fn process_changes( 146 pub fn process_changes(
142 &mut self, 147 &mut self,
143 ) -> Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)> { 148 ) -> Option<Vec<(SourceRootId, Vec<(FileId, RelativePathBuf, Arc<String>)>)>> {
144 let changes = self.vfs.write().commit_changes(); 149 let changes = self.vfs.write().commit_changes();
145 if changes.is_empty() { 150 if changes.is_empty() {
146 return Vec::new(); 151 return None;
147 } 152 }
148 let mut libs = Vec::new(); 153 let mut libs = Vec::new();
149 let mut change = AnalysisChange::new(); 154 let mut change = AnalysisChange::new();
@@ -177,7 +182,7 @@ impl WorldState {
177 } 182 }
178 } 183 }
179 self.analysis_host.apply_change(change); 184 self.analysis_host.apply_change(change);
180 libs 185 Some(libs)
181 } 186 }
182 187
183 pub fn add_lib(&mut self, data: LibraryData) { 188 pub fn add_lib(&mut self, data: LibraryData) {
@@ -233,8 +238,8 @@ impl WorldSnapshot {
233 238
234 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> { 239 pub fn file_id_to_uri(&self, id: FileId) -> Result<Url> {
235 let path = self.vfs.read().file2path(VfsFile(id.0)); 240 let path = self.vfs.read().file2path(VfsFile(id.0));
236 let url = Url::from_file_path(&path) 241 let url = url_from_path_with_drive_lowercasing(path)?;
237 .map_err(|_| format!("can't convert path to url: {}", path.display()))?; 242
238 Ok(url) 243 Ok(url)
239 } 244 }
240 245
@@ -279,3 +284,61 @@ impl WorldSnapshot {
279 self.analysis.feature_flags() 284 self.analysis.feature_flags()
280 } 285 }
281} 286}
287
288/// Returns a `Url` object from a given path, will lowercase drive letters if present.
289/// This will only happen when processing windows paths.
290///
291/// When processing non-windows path, this is essentially the same as `Url::from_file_path`.
292fn url_from_path_with_drive_lowercasing(path: impl AsRef<Path>) -> Result<Url> {
293 let component_has_windows_drive = path.as_ref().components().any(|comp| {
294 if let Component::Prefix(c) = comp {
295 match c.kind() {
296 Prefix::Disk(_) | Prefix::VerbatimDisk(_) => return true,
297 _ => return false,
298 }
299 }
300 false
301 });
302
303 // VSCode expects drive letters to be lowercased, where rust will uppercase the drive letters.
304 if component_has_windows_drive {
305 let url_original = Url::from_file_path(&path)
306 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?;
307
308 let drive_partition: Vec<&str> = url_original.as_str().rsplitn(2, ':').collect();
309
310 // There is a drive partition, but we never found a colon.
311 // This should not happen, but in this case we just pass it through.
312 if drive_partition.len() == 1 {
313 return Ok(url_original);
314 }
315
316 let joined = drive_partition[1].to_ascii_lowercase() + ":" + drive_partition[0];
317 let url = Url::from_str(&joined).expect("This came from a valid `Url`");
318
319 Ok(url)
320 } else {
321 Ok(Url::from_file_path(&path)
322 .map_err(|_| format!("can't convert path to url: {}", path.as_ref().display()))?)
323 }
324}
325
326// `Url` is not able to parse windows paths on unix machines.
327#[cfg(target_os = "windows")]
328#[cfg(test)]
329mod path_conversion_windows_tests {
330 use super::url_from_path_with_drive_lowercasing;
331 #[test]
332 fn test_lowercase_drive_letter_with_drive() {
333 let url = url_from_path_with_drive_lowercasing("C:\\Test").unwrap();
334
335 assert_eq!(url.to_string(), "file:///c:/Test");
336 }
337
338 #[test]
339 fn test_drive_without_colon_passthrough() {
340 let url = url_from_path_with_drive_lowercasing(r#"\\localhost\C$\my_dir"#).unwrap();
341
342 assert_eq!(url.to_string(), "file://localhost/C$/my_dir");
343 }
344}
diff --git a/crates/ra_lsp_server/tests/heavy_tests/main.rs b/crates/ra_lsp_server/tests/heavy_tests/main.rs
index 2ba82ab05..dff63a12d 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/main.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/main.rs
@@ -4,7 +4,8 @@ use std::{collections::HashMap, time::Instant};
4 4
5use lsp_types::{ 5use lsp_types::{
6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions, 6 CodeActionContext, DidOpenTextDocumentParams, DocumentFormattingParams, FormattingOptions,
7 Position, Range, TextDocumentItem, TextDocumentPositionParams, 7 PartialResultParams, Position, Range, TextDocumentItem, TextDocumentPositionParams,
8 WorkDoneProgressParams,
8}; 9};
9use ra_lsp_server::req::{ 10use ra_lsp_server::req::{
10 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument, 11 CodeActionParams, CodeActionRequest, Completion, CompletionParams, DidOpenTextDocument,
@@ -12,15 +13,19 @@ use ra_lsp_server::req::{
12}; 13};
13use serde_json::json; 14use serde_json::json;
14use tempfile::TempDir; 15use tempfile::TempDir;
16use test_utils::skip_slow_tests;
15 17
16use crate::support::{project, Project}; 18use crate::support::{project, Project};
17 19
18const LOG: &'static str = "";
19const PROFILE: &'static str = ""; 20const PROFILE: &'static str = "";
20// const PROFILE: &'static str = "*@3>100"; 21// const PROFILE: &'static str = "*@3>100";
21 22
22#[test] 23#[test]
23fn completes_items_from_standard_library() { 24fn completes_items_from_standard_library() {
25 if skip_slow_tests() {
26 return;
27 }
28
24 let project_start = Instant::now(); 29 let project_start = Instant::now();
25 let server = Project::with_fixture( 30 let server = Project::with_fixture(
26 r#" 31 r#"
@@ -44,6 +49,8 @@ use std::collections::Spam;
44 Position::new(0, 23), 49 Position::new(0, 23),
45 ), 50 ),
46 context: None, 51 context: None,
52 partial_result_params: PartialResultParams::default(),
53 work_done_progress_params: WorkDoneProgressParams::default(),
47 }); 54 });
48 assert!(format!("{}", res).contains("HashMap")); 55 assert!(format!("{}", res).contains("HashMap"));
49 eprintln!("completion took {:?}", completion_start.elapsed()); 56 eprintln!("completion took {:?}", completion_start.elapsed());
@@ -51,6 +58,10 @@ use std::collections::Spam;
51 58
52#[test] 59#[test]
53fn test_runnables_no_project() { 60fn test_runnables_no_project() {
61 if skip_slow_tests() {
62 return;
63 }
64
54 let server = project( 65 let server = project(
55 r" 66 r"
56//- lib.rs 67//- lib.rs
@@ -100,6 +111,10 @@ fn foo() {
100 111
101#[test] 112#[test]
102fn test_runnables_project() { 113fn test_runnables_project() {
114 if skip_slow_tests() {
115 return;
116 }
117
103 let code = r#" 118 let code = r#"
104//- foo/Cargo.toml 119//- foo/Cargo.toml
105[package] 120[package]
@@ -171,8 +186,13 @@ fn main() {}
171 186
172#[test] 187#[test]
173fn test_format_document() { 188fn test_format_document() {
189 if skip_slow_tests() {
190 return;
191 }
192
174 let server = project( 193 let server = project(
175 r#" 194 r#"
195//- Cargo.toml
176[package] 196[package]
177name = "foo" 197name = "foo"
178version = "0.0.0" 198version = "0.0.0"
@@ -194,8 +214,12 @@ pub use std::collections::HashMap;
194 options: FormattingOptions { 214 options: FormattingOptions {
195 tab_size: 4, 215 tab_size: 4,
196 insert_spaces: false, 216 insert_spaces: false,
217 insert_final_newline: None,
218 trim_final_newlines: None,
219 trim_trailing_whitespace: None,
197 properties: HashMap::new(), 220 properties: HashMap::new(),
198 }, 221 },
222 work_done_progress_params: WorkDoneProgressParams::default(),
199 }, 223 },
200 json!([ 224 json!([
201 { 225 {
@@ -221,7 +245,77 @@ pub use std::collections::HashMap;
221} 245}
222 246
223#[test] 247#[test]
248fn test_format_document_2018() {
249 if skip_slow_tests() {
250 return;
251 }
252
253 let server = project(
254 r#"
255//- Cargo.toml
256[package]
257name = "foo"
258version = "0.0.0"
259edition = "2018"
260
261//- src/lib.rs
262mod bar;
263
264async fn test() {
265}
266
267fn main() {
268}
269
270pub use std::collections::HashMap;
271"#,
272 );
273 server.wait_until_workspace_is_loaded();
274
275 server.request::<Formatting>(
276 DocumentFormattingParams {
277 text_document: server.doc_id("src/lib.rs"),
278 options: FormattingOptions {
279 tab_size: 4,
280 insert_spaces: false,
281 properties: HashMap::new(),
282 insert_final_newline: None,
283 trim_final_newlines: None,
284 trim_trailing_whitespace: None,
285 },
286 work_done_progress_params: WorkDoneProgressParams::default(),
287 },
288 json!([
289 {
290 "newText": r#"mod bar;
291
292async fn test() {}
293
294fn main() {}
295
296pub use std::collections::HashMap;
297"#,
298 "range": {
299 "end": {
300 "character": 0,
301 "line": 10
302 },
303 "start": {
304 "character": 0,
305 "line": 0
306 }
307 }
308 }
309 ]),
310 );
311}
312
313#[test]
224fn test_missing_module_code_action() { 314fn test_missing_module_code_action() {
315 if skip_slow_tests() {
316 return;
317 }
318
225 let server = project( 319 let server = project(
226 r#" 320 r#"
227//- Cargo.toml 321//- Cargo.toml
@@ -242,6 +336,8 @@ fn main() {}
242 text_document: server.doc_id("src/lib.rs"), 336 text_document: server.doc_id("src/lib.rs"),
243 range: Range::new(Position::new(0, 4), Position::new(0, 7)), 337 range: Range::new(Position::new(0, 4), Position::new(0, 7)),
244 context: empty_context(), 338 context: empty_context(),
339 partial_result_params: PartialResultParams::default(),
340 work_done_progress_params: WorkDoneProgressParams::default(),
245 }, 341 },
246 json!([ 342 json!([
247 { 343 {
@@ -273,6 +369,8 @@ fn main() {}
273 text_document: server.doc_id("src/lib.rs"), 369 text_document: server.doc_id("src/lib.rs"),
274 range: Range::new(Position::new(2, 4), Position::new(2, 7)), 370 range: Range::new(Position::new(2, 4), Position::new(2, 7)),
275 context: empty_context(), 371 context: empty_context(),
372 partial_result_params: PartialResultParams::default(),
373 work_done_progress_params: WorkDoneProgressParams::default(),
276 }, 374 },
277 json!([]), 375 json!([]),
278 ); 376 );
@@ -280,6 +378,10 @@ fn main() {}
280 378
281#[test] 379#[test]
282fn test_missing_module_code_action_in_json_project() { 380fn test_missing_module_code_action_in_json_project() {
381 if skip_slow_tests() {
382 return;
383 }
384
283 let tmp_dir = TempDir::new().unwrap(); 385 let tmp_dir = TempDir::new().unwrap();
284 386
285 let path = tmp_dir.path(); 387 let path = tmp_dir.path();
@@ -317,6 +419,8 @@ fn main() {{}}
317 text_document: server.doc_id("src/lib.rs"), 419 text_document: server.doc_id("src/lib.rs"),
318 range: Range::new(Position::new(0, 4), Position::new(0, 7)), 420 range: Range::new(Position::new(0, 4), Position::new(0, 7)),
319 context: empty_context(), 421 context: empty_context(),
422 partial_result_params: PartialResultParams::default(),
423 work_done_progress_params: WorkDoneProgressParams::default(),
320 }, 424 },
321 json!([ 425 json!([
322 { 426 {
@@ -348,6 +452,8 @@ fn main() {{}}
348 text_document: server.doc_id("src/lib.rs"), 452 text_document: server.doc_id("src/lib.rs"),
349 range: Range::new(Position::new(2, 4), Position::new(2, 7)), 453 range: Range::new(Position::new(2, 4), Position::new(2, 7)),
350 context: empty_context(), 454 context: empty_context(),
455 partial_result_params: PartialResultParams::default(),
456 work_done_progress_params: WorkDoneProgressParams::default(),
351 }, 457 },
352 json!([]), 458 json!([]),
353 ); 459 );
@@ -355,6 +461,10 @@ fn main() {{}}
355 461
356#[test] 462#[test]
357fn diagnostics_dont_block_typing() { 463fn diagnostics_dont_block_typing() {
464 if skip_slow_tests() {
465 return;
466 }
467
358 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect(); 468 let librs: String = (0..10).map(|i| format!("mod m{};", i)).collect();
359 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect(); 469 let libs: String = (0..10).map(|i| format!("//- src/m{}.rs\nfn foo() {{}}\n\n", i)).collect();
360 let server = Project::with_fixture(&format!( 470 let server = Project::with_fixture(&format!(
@@ -423,6 +533,10 @@ fn main() {{}}
423 533
424#[test] 534#[test]
425fn preserves_dos_line_endings() { 535fn preserves_dos_line_endings() {
536 if skip_slow_tests() {
537 return;
538 }
539
426 let server = Project::with_fixture( 540 let server = Project::with_fixture(
427 &" 541 &"
428//- Cargo.toml 542//- Cargo.toml
diff --git a/crates/ra_lsp_server/tests/heavy_tests/support.rs b/crates/ra_lsp_server/tests/heavy_tests/support.rs
index 86073b57d..d5ea52fa9 100644
--- a/crates/ra_lsp_server/tests/heavy_tests/support.rs
+++ b/crates/ra_lsp_server/tests/heavy_tests/support.rs
@@ -7,7 +7,6 @@ use std::{
7}; 7};
8 8
9use crossbeam_channel::{after, select, Receiver}; 9use crossbeam_channel::{after, select, Receiver};
10use flexi_logger::Logger;
11use lsp_server::{Connection, Message, Notification, Request}; 10use lsp_server::{Connection, Message, Notification, Request};
12use lsp_types::{ 11use lsp_types::{
13 notification::{DidOpenTextDocument, Exit}, 12 notification::{DidOpenTextDocument, Exit},
@@ -53,7 +52,7 @@ impl<'a> Project<'a> {
53 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap()); 52 let tmp_dir = self.tmp_dir.unwrap_or_else(|| TempDir::new().unwrap());
54 static INIT: Once = Once::new(); 53 static INIT: Once = Once::new();
55 INIT.call_once(|| { 54 INIT.call_once(|| {
56 let _ = Logger::with_env_or_str(crate::LOG).start().unwrap(); 55 let _ = env_logger::builder().is_test(true).try_init().unwrap();
57 ra_prof::set_filter(if crate::PROFILE.is_empty() { 56 ra_prof::set_filter(if crate::PROFILE.is_empty() {
58 ra_prof::Filter::disabled() 57 ra_prof::Filter::disabled()
59 } else { 58 } else {
diff --git a/crates/ra_mbe/src/lib.rs b/crates/ra_mbe/src/lib.rs
index bbddebe67..2c6ae5658 100644
--- a/crates/ra_mbe/src/lib.rs
+++ b/crates/ra_mbe/src/lib.rs
@@ -67,7 +67,15 @@ impl Shift {
67 .token_trees 67 .token_trees
68 .iter() 68 .iter()
69 .filter_map(|tt| match tt { 69 .filter_map(|tt| match tt {
70 tt::TokenTree::Subtree(subtree) => max_id(subtree), 70 tt::TokenTree::Subtree(subtree) => {
71 let tree_id = max_id(subtree);
72 match subtree.delimiter {
73 Some(it) if it.id != tt::TokenId::unspecified() => {
74 Some(tree_id.map_or(it.id.0, |t| t.max(it.id.0)))
75 }
76 _ => tree_id,
77 }
78 }
71 tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) 79 tt::TokenTree::Leaf(tt::Leaf::Ident(ident))
72 if ident.id != tt::TokenId::unspecified() => 80 if ident.id != tt::TokenId::unspecified() =>
73 { 81 {
@@ -85,9 +93,15 @@ impl Shift {
85 match t { 93 match t {
86 tt::TokenTree::Leaf(leaf) => match leaf { 94 tt::TokenTree::Leaf(leaf) => match leaf {
87 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id), 95 tt::Leaf::Ident(ident) => ident.id = self.shift(ident.id),
88 _ => (), 96 tt::Leaf::Punct(punct) => punct.id = self.shift(punct.id),
97 tt::Leaf::Literal(lit) => lit.id = self.shift(lit.id),
89 }, 98 },
90 tt::TokenTree::Subtree(tt) => self.shift_all(tt), 99 tt::TokenTree::Subtree(tt) => {
100 if let Some(it) = tt.delimiter.as_mut() {
101 it.id = self.shift(it.id);
102 };
103 self.shift_all(tt)
104 }
91 } 105 }
92 } 106 }
93 } 107 }
@@ -104,6 +118,7 @@ impl Shift {
104 } 118 }
105} 119}
106 120
121#[derive(Debug, Eq, PartialEq)]
107pub enum Origin { 122pub enum Origin {
108 Def, 123 Def,
109 Call, 124 Call,
@@ -159,14 +174,14 @@ impl Rule {
159 .expect_subtree() 174 .expect_subtree()
160 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 175 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
161 .clone(); 176 .clone();
162 lhs.delimiter = tt::Delimiter::None; 177 lhs.delimiter = None;
163 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; 178 src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?;
164 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; 179 src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?;
165 let mut rhs = src 180 let mut rhs = src
166 .expect_subtree() 181 .expect_subtree()
167 .map_err(|()| ParseError::Expected("expected subtree".to_string()))? 182 .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
168 .clone(); 183 .clone();
169 rhs.delimiter = tt::Delimiter::None; 184 rhs.delimiter = None;
170 Ok(crate::Rule { lhs, rhs }) 185 Ok(crate::Rule { lhs, rhs })
171 } 186 }
172} 187}
diff --git a/crates/ra_mbe/src/mbe_expander/matcher.rs b/crates/ra_mbe/src/mbe_expander/matcher.rs
index 33b9d483d..e36b5a412 100644
--- a/crates/ra_mbe/src/mbe_expander/matcher.rs
+++ b/crates/ra_mbe/src/mbe_expander/matcher.rs
@@ -16,7 +16,7 @@ impl Bindings {
16 fn push_optional(&mut self, name: &SmolStr) { 16 fn push_optional(&mut self, name: &SmolStr) {
17 // FIXME: Do we have a better way to represent an empty token ? 17 // FIXME: Do we have a better way to represent an empty token ?
18 // Insert an empty subtree for empty token 18 // Insert an empty subtree for empty token
19 let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: vec![] }.into(); 19 let tt = tt::Subtree::default().into();
20 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt))); 20 self.inner.insert(name.clone(), Binding::Fragment(Fragment::Tokens(tt)));
21 } 21 }
22 22
@@ -65,7 +65,7 @@ macro_rules! bail {
65} 65}
66 66
67pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> { 67pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Bindings, ExpandError> {
68 assert!(pattern.delimiter == tt::Delimiter::None); 68 assert!(pattern.delimiter == None);
69 69
70 let mut res = Bindings::default(); 70 let mut res = Bindings::default();
71 let mut src = TtIter::new(src); 71 let mut src = TtIter::new(src);
@@ -106,7 +106,7 @@ fn match_subtree(
106 } 106 }
107 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => { 107 Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
108 let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?; 108 let rhs = src.expect_subtree().map_err(|()| err!("expected subtree"))?;
109 if lhs.delimiter != rhs.delimiter { 109 if lhs.delimiter_kind() != rhs.delimiter_kind() {
110 bail!("mismatched delimiter") 110 bail!("mismatched delimiter")
111 } 111 }
112 let mut src = TtIter::new(rhs); 112 let mut src = TtIter::new(rhs);
@@ -210,7 +210,7 @@ impl<'a> TtIter<'a> {
210 0 => Err(()), 210 0 => Err(()),
211 1 => Ok(res[0].clone()), 211 1 => Ok(res[0].clone()),
212 _ => Ok(tt::TokenTree::Subtree(tt::Subtree { 212 _ => Ok(tt::TokenTree::Subtree(tt::Subtree {
213 delimiter: tt::Delimiter::None, 213 delimiter: None,
214 token_trees: res.into_iter().cloned().collect(), 214 token_trees: res.into_iter().cloned().collect(),
215 })), 215 })),
216 } 216 }
diff --git a/crates/ra_mbe/src/mbe_expander/transcriber.rs b/crates/ra_mbe/src/mbe_expander/transcriber.rs
index ed094d5bb..eda66cd50 100644
--- a/crates/ra_mbe/src/mbe_expander/transcriber.rs
+++ b/crates/ra_mbe/src/mbe_expander/transcriber.rs
@@ -50,7 +50,7 @@ pub(super) fn transcribe(
50 template: &tt::Subtree, 50 template: &tt::Subtree,
51 bindings: &Bindings, 51 bindings: &Bindings,
52) -> Result<tt::Subtree, ExpandError> { 52) -> Result<tt::Subtree, ExpandError> {
53 assert!(template.delimiter == tt::Delimiter::None); 53 assert!(template.delimiter == None);
54 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false }; 54 let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new(), var_expanded: false };
55 expand_subtree(&mut ctx, template) 55 expand_subtree(&mut ctx, template)
56} 56}
@@ -106,9 +106,14 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> Result<Fragment, ExpandError>
106 // ``` 106 // ```
107 // We just treat it a normal tokens 107 // We just treat it a normal tokens
108 let tt = tt::Subtree { 108 let tt = tt::Subtree {
109 delimiter: tt::Delimiter::None, 109 delimiter: None,
110 token_trees: vec![ 110 token_trees: vec![
111 tt::Leaf::from(tt::Punct { char: '$', spacing: tt::Spacing::Alone }).into(), 111 tt::Leaf::from(tt::Punct {
112 char: '$',
113 spacing: tt::Spacing::Alone,
114 id: tt::TokenId::unspecified(),
115 })
116 .into(),
112 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() }) 117 tt::Leaf::from(tt::Ident { text: v.clone(), id: tt::TokenId::unspecified() })
113 .into(), 118 .into(),
114 ], 119 ],
@@ -147,7 +152,7 @@ fn expand_repeat(
147 ctx.var_expanded = false; 152 ctx.var_expanded = false;
148 153
149 while let Ok(mut t) = expand_subtree(ctx, template) { 154 while let Ok(mut t) = expand_subtree(ctx, template) {
150 t.delimiter = tt::Delimiter::None; 155 t.delimiter = None;
151 // if no var expanded in the child, we count it as a fail 156 // if no var expanded in the child, we count it as a fail
152 if !ctx.var_expanded { 157 if !ctx.var_expanded {
153 break; 158 break;
@@ -212,7 +217,7 @@ fn expand_repeat(
212 217
213 // Check if it is a single token subtree without any delimiter 218 // Check if it is a single token subtree without any delimiter
214 // e.g {Delimiter:None> ['>'] /Delimiter:None>} 219 // e.g {Delimiter:None> ['>'] /Delimiter:None>}
215 let tt = tt::Subtree { delimiter: tt::Delimiter::None, token_trees: buf }.into(); 220 let tt = tt::Subtree { delimiter: None, token_trees: buf }.into();
216 Ok(Fragment::Tokens(tt)) 221 Ok(Fragment::Tokens(tt))
217} 222}
218 223
@@ -225,7 +230,7 @@ fn push_fragment(buf: &mut Vec<tt::TokenTree>, fragment: Fragment) {
225 230
226fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) { 231fn push_subtree(buf: &mut Vec<tt::TokenTree>, tt: tt::Subtree) {
227 match tt.delimiter { 232 match tt.delimiter {
228 tt::Delimiter::None => buf.extend(tt.token_trees), 233 None => buf.extend(tt.token_trees),
229 _ => buf.push(tt.into()), 234 _ => buf.push(tt.into()),
230 } 235 }
231} 236}
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs
index 7ef45f6dc..b841c39d3 100644
--- a/crates/ra_mbe/src/subtree_source.rs
+++ b/crates/ra_mbe/src/subtree_source.rs
@@ -70,11 +70,11 @@ impl<'a> SubtreeTokenSource<'a> {
70 } 70 }
71 Some(tt::TokenTree::Subtree(subtree)) => { 71 Some(tt::TokenTree::Subtree(subtree)) => {
72 self.cached_cursor.set(cursor.subtree().unwrap()); 72 self.cached_cursor.set(cursor.subtree().unwrap());
73 cached.push(Some(convert_delim(subtree.delimiter, false))); 73 cached.push(Some(convert_delim(subtree.delimiter_kind(), false)));
74 } 74 }
75 None => { 75 None => {
76 if let Some(subtree) = cursor.end() { 76 if let Some(subtree) = cursor.end() {
77 cached.push(Some(convert_delim(subtree.delimiter, true))); 77 cached.push(Some(convert_delim(subtree.delimiter_kind(), true)));
78 self.cached_cursor.set(cursor.bump()); 78 self.cached_cursor.set(cursor.bump());
79 } 79 }
80 } 80 }
@@ -114,12 +114,12 @@ impl<'a> TokenSource for SubtreeTokenSource<'a> {
114 } 114 }
115} 115}
116 116
117fn convert_delim(d: tt::Delimiter, closing: bool) -> TtToken { 117fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
118 let (kinds, texts) = match d { 118 let (kinds, texts) = match d {
119 tt::Delimiter::Parenthesis => ([T!['('], T![')']], "()"), 119 Some(tt::DelimiterKind::Parenthesis) => ([T!['('], T![')']], "()"),
120 tt::Delimiter::Brace => ([T!['{'], T!['}']], "{}"), 120 Some(tt::DelimiterKind::Brace) => ([T!['{'], T!['}']], "{}"),
121 tt::Delimiter::Bracket => ([T!['['], T![']']], "[]"), 121 Some(tt::DelimiterKind::Bracket) => ([T!['['], T![']']], "[]"),
122 tt::Delimiter::None => ([L_DOLLAR, R_DOLLAR], ""), 122 None => ([L_DOLLAR, R_DOLLAR], ""),
123 }; 123 };
124 124
125 let idx = closing as usize; 125 let idx = closing as usize;
diff --git a/crates/ra_mbe/src/syntax_bridge.rs b/crates/ra_mbe/src/syntax_bridge.rs
index 1de399fee..ea2cac069 100644
--- a/crates/ra_mbe/src/syntax_bridge.rs
+++ b/crates/ra_mbe/src/syntax_bridge.rs
@@ -2,25 +2,45 @@
2 2
3use ra_parser::{FragmentKind, ParseError, TreeSink}; 3use ra_parser::{FragmentKind, ParseError, TreeSink};
4use ra_syntax::{ 4use ra_syntax::{
5 ast, AstNode, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode, 5 ast, AstToken, NodeOrToken, Parse, SmolStr, SyntaxKind, SyntaxKind::*, SyntaxNode,
6 SyntaxTreeBuilder, TextRange, TextUnit, T, 6 SyntaxTreeBuilder, TextRange, TextUnit, T,
7}; 7};
8use rustc_hash::FxHashMap;
8use std::iter::successors; 9use std::iter::successors;
9use tt::buffer::{Cursor, TokenBuffer}; 10use tt::buffer::{Cursor, TokenBuffer};
10 11
11use crate::subtree_source::SubtreeTokenSource; 12use crate::subtree_source::SubtreeTokenSource;
12use crate::ExpandError; 13use crate::ExpandError;
13 14
15#[derive(Debug, PartialEq, Eq, Clone, Copy)]
16pub enum TokenTextRange {
17 Token(TextRange),
18 Delimiter(TextRange, TextRange),
19}
20
21impl TokenTextRange {
22 pub fn by_kind(self, kind: SyntaxKind) -> Option<TextRange> {
23 match self {
24 TokenTextRange::Token(it) => Some(it),
25 TokenTextRange::Delimiter(open, close) => match kind {
26 T!['{'] | T!['('] | T!['['] => Some(open),
27 T!['}'] | T![')'] | T![']'] => Some(close),
28 _ => None,
29 },
30 }
31 }
32}
33
14/// Maps `tt::TokenId` to the relative range of the original token. 34/// Maps `tt::TokenId` to the relative range of the original token.
15#[derive(Debug, PartialEq, Eq, Default)] 35#[derive(Debug, PartialEq, Eq, Default)]
16pub struct TokenMap { 36pub struct TokenMap {
17 /// Maps `tt::TokenId` to the *relative* source range. 37 /// Maps `tt::TokenId` to the *relative* source range.
18 entries: Vec<(tt::TokenId, TextRange)>, 38 entries: Vec<(tt::TokenId, TokenTextRange)>,
19} 39}
20 40
21/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro 41/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
22/// will consume). 42/// will consume).
23pub fn ast_to_token_tree(ast: &ast::TokenTree) -> Option<(tt::Subtree, TokenMap)> { 43pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> Option<(tt::Subtree, TokenMap)> {
24 syntax_node_to_token_tree(ast.syntax()) 44 syntax_node_to_token_tree(ast.syntax())
25} 45}
26 46
@@ -51,7 +71,7 @@ pub fn token_tree_to_syntax_node(
51) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> { 71) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
52 let tmp; 72 let tmp;
53 let tokens = match tt { 73 let tokens = match tt {
54 tt::Subtree { delimiter: tt::Delimiter::None, token_trees } => token_trees.as_slice(), 74 tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(),
55 _ => { 75 _ => {
56 tmp = [tt.clone().into()]; 76 tmp = [tt.clone().into()];
57 &tmp[..] 77 &tmp[..]
@@ -71,17 +91,32 @@ pub fn token_tree_to_syntax_node(
71 91
72impl TokenMap { 92impl TokenMap {
73 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> { 93 pub fn token_by_range(&self, relative_range: TextRange) -> Option<tt::TokenId> {
74 let &(token_id, _) = self.entries.iter().find(|(_, range)| *range == relative_range)?; 94 let &(token_id, _) = self.entries.iter().find(|(_, range)| match range {
95 TokenTextRange::Token(it) => *it == relative_range,
96 TokenTextRange::Delimiter(open, close) => {
97 *open == relative_range || *close == relative_range
98 }
99 })?;
75 Some(token_id) 100 Some(token_id)
76 } 101 }
77 102
78 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TextRange> { 103 pub fn range_by_token(&self, token_id: tt::TokenId) -> Option<TokenTextRange> {
79 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?; 104 let &(_, range) = self.entries.iter().find(|(tid, _)| *tid == token_id)?;
80 Some(range) 105 Some(range)
81 } 106 }
82 107
83 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) { 108 fn insert(&mut self, token_id: tt::TokenId, relative_range: TextRange) {
84 self.entries.push((token_id, relative_range)); 109 self.entries.push((token_id, TokenTextRange::Token(relative_range)));
110 }
111
112 fn insert_delim(
113 &mut self,
114 token_id: tt::TokenId,
115 open_relative_range: TextRange,
116 close_relative_range: TextRange,
117 ) {
118 self.entries
119 .push((token_id, TokenTextRange::Delimiter(open_relative_range, close_relative_range)));
85 } 120 }
86} 121}
87 122
@@ -121,7 +156,10 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
121 token_trees.push(mk_punct('!')); 156 token_trees.push(mk_punct('!'));
122 } 157 }
123 token_trees.push(tt::TokenTree::from(tt::Subtree { 158 token_trees.push(tt::TokenTree::from(tt::Subtree {
124 delimiter: tt::Delimiter::Bracket, 159 delimiter: Some(tt::Delimiter {
160 kind: tt::DelimiterKind::Bracket,
161 id: tt::TokenId::unspecified(),
162 }),
125 token_trees: meta_tkns, 163 token_trees: meta_tkns,
126 })); 164 }));
127 165
@@ -136,11 +174,15 @@ fn convert_doc_comment(token: &ra_syntax::SyntaxToken) -> Option<Vec<tt::TokenTr
136 } 174 }
137 175
138 fn mk_punct(c: char) -> tt::TokenTree { 176 fn mk_punct(c: char) -> tt::TokenTree {
139 tt::TokenTree::from(tt::Leaf::from(tt::Punct { char: c, spacing: tt::Spacing::Alone })) 177 tt::TokenTree::from(tt::Leaf::from(tt::Punct {
178 char: c,
179 spacing: tt::Spacing::Alone,
180 id: tt::TokenId::unspecified(),
181 }))
140 } 182 }
141 183
142 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree { 184 fn mk_doc_literal(comment: &ast::Comment) -> tt::TokenTree {
143 let lit = tt::Literal { text: doc_comment_text(comment) }; 185 let lit = tt::Literal { text: doc_comment_text(comment), id: tt::TokenId::unspecified() };
144 186
145 tt::TokenTree::from(tt::Leaf::from(lit)) 187 tt::TokenTree::from(tt::Leaf::from(lit))
146 } 188 }
@@ -156,7 +198,7 @@ impl Convertor {
156 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> { 198 fn go(&mut self, tt: &SyntaxNode) -> Option<tt::Subtree> {
157 // This tree is empty 199 // This tree is empty
158 if tt.first_child_or_token().is_none() { 200 if tt.first_child_or_token().is_none() {
159 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 201 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
160 } 202 }
161 203
162 let first_child = tt.first_child_or_token()?; 204 let first_child = tt.first_child_or_token()?;
@@ -173,7 +215,7 @@ impl Convertor {
173 .last() 215 .last()
174 .unwrap(); 216 .unwrap();
175 if first_child.kind().is_trivia() { 217 if first_child.kind().is_trivia() {
176 return Some(tt::Subtree { token_trees: vec![], delimiter: tt::Delimiter::None }); 218 return Some(tt::Subtree { token_trees: vec![], delimiter: None });
177 } 219 }
178 220
179 let last_child = successors(Some(last_child), |it| { 221 let last_child = successors(Some(last_child), |it| {
@@ -186,12 +228,16 @@ impl Convertor {
186 .last() 228 .last()
187 .unwrap(); 229 .unwrap();
188 230
189 let (delimiter, skip_first) = match (first_child.kind(), last_child.kind()) { 231 let (delimiter_kind, skip_first) = match (first_child.kind(), last_child.kind()) {
190 (T!['('], T![')']) => (tt::Delimiter::Parenthesis, true), 232 (T!['('], T![')']) => (Some(tt::DelimiterKind::Parenthesis), true),
191 (T!['{'], T!['}']) => (tt::Delimiter::Brace, true), 233 (T!['{'], T!['}']) => (Some(tt::DelimiterKind::Brace), true),
192 (T!['['], T![']']) => (tt::Delimiter::Bracket, true), 234 (T!['['], T![']']) => (Some(tt::DelimiterKind::Bracket), true),
193 _ => (tt::Delimiter::None, false), 235 _ => (None, false),
194 }; 236 };
237 let delimiter = delimiter_kind.map(|kind| tt::Delimiter {
238 kind,
239 id: self.alloc_delim(first_child.text_range(), last_child.text_range()),
240 });
195 241
196 let mut token_trees = Vec::new(); 242 let mut token_trees = Vec::new();
197 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable(); 243 let mut child_iter = tt.children_with_tokens().skip(skip_first as usize).peekable();
@@ -208,13 +254,8 @@ impl Convertor {
208 } else if token.kind().is_trivia() { 254 } else if token.kind().is_trivia() {
209 continue; 255 continue;
210 } else if token.kind().is_punct() { 256 } else if token.kind().is_punct() {
211 assert!( 257 // we need to pull apart joined punctuation tokens
212 token.text().len() == 1, 258 let last_spacing = match child_iter.peek() {
213 "Input ast::token punct must be single char."
214 );
215 let char = token.text().chars().next().unwrap();
216
217 let spacing = match child_iter.peek() {
218 Some(NodeOrToken::Token(token)) => { 259 Some(NodeOrToken::Token(token)) => {
219 if token.kind().is_punct() { 260 if token.kind().is_punct() {
220 tt::Spacing::Joint 261 tt::Spacing::Joint
@@ -224,30 +265,47 @@ impl Convertor {
224 } 265 }
225 _ => tt::Spacing::Alone, 266 _ => tt::Spacing::Alone,
226 }; 267 };
227 268 let spacing_iter = std::iter::repeat(tt::Spacing::Joint)
228 token_trees.push(tt::Leaf::from(tt::Punct { char, spacing }).into()); 269 .take(token.text().len() - 1)
270 .chain(std::iter::once(last_spacing));
271 for (char, spacing) in token.text().chars().zip(spacing_iter) {
272 token_trees.push(
273 tt::Leaf::from(tt::Punct {
274 char,
275 spacing,
276 id: self.alloc(token.text_range()),
277 })
278 .into(),
279 );
280 }
229 } else { 281 } else {
230 let child: tt::TokenTree = 282 macro_rules! make_leaf {
231 if token.kind() == T![true] || token.kind() == T![false] { 283 ($i:ident) => {
232 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into() 284 tt::$i {
233 } else if token.kind().is_keyword() 285 id: self.alloc(token.text_range()),
234 || token.kind() == IDENT 286 text: token.text().clone(),
235 || token.kind() == LIFETIME 287 }
236 { 288 .into()
237 let id = self.alloc(token.text_range());
238 let text = token.text().clone();
239 tt::Leaf::from(tt::Ident { text, id }).into()
240 } else if token.kind().is_literal() {
241 tt::Leaf::from(tt::Literal { text: token.text().clone() }).into()
242 } else {
243 return None;
244 }; 289 };
245 token_trees.push(child); 290 }
291
292 let child: tt::Leaf = match token.kind() {
293 T![true] | T![false] => make_leaf!(Literal),
294 IDENT | LIFETIME => make_leaf!(Ident),
295 k if k.is_keyword() => make_leaf!(Ident),
296 k if k.is_literal() => make_leaf!(Literal),
297 _ => return None,
298 };
299 token_trees.push(child.into());
246 } 300 }
247 } 301 }
248 NodeOrToken::Node(node) => { 302 NodeOrToken::Node(node) => {
249 let child = self.go(&node)?.into(); 303 let child_subtree = self.go(&node)?;
250 token_trees.push(child); 304 if child_subtree.delimiter.is_none() && node.kind() != SyntaxKind::TOKEN_TREE {
305 token_trees.extend(child_subtree.token_trees);
306 } else {
307 token_trees.push(child_subtree.into());
308 }
251 } 309 }
252 }; 310 };
253 } 311 }
@@ -263,11 +321,26 @@ impl Convertor {
263 self.map.insert(token_id, relative_range); 321 self.map.insert(token_id, relative_range);
264 token_id 322 token_id
265 } 323 }
324
325 fn alloc_delim(
326 &mut self,
327 open_abs_range: TextRange,
328 close_abs_range: TextRange,
329 ) -> tt::TokenId {
330 let open_relative_range = open_abs_range - self.global_offset;
331 let close_relative_range = close_abs_range - self.global_offset;
332 let token_id = tt::TokenId(self.next_id);
333 self.next_id += 1;
334
335 self.map.insert_delim(token_id, open_relative_range, close_relative_range);
336 token_id
337 }
266} 338}
267 339
268struct TtTreeSink<'a> { 340struct TtTreeSink<'a> {
269 buf: String, 341 buf: String,
270 cursor: Cursor<'a>, 342 cursor: Cursor<'a>,
343 open_delims: FxHashMap<tt::TokenId, TextUnit>,
271 text_pos: TextUnit, 344 text_pos: TextUnit,
272 inner: SyntaxTreeBuilder, 345 inner: SyntaxTreeBuilder,
273 token_map: TokenMap, 346 token_map: TokenMap,
@@ -282,6 +355,7 @@ impl<'a> TtTreeSink<'a> {
282 TtTreeSink { 355 TtTreeSink {
283 buf: String::new(), 356 buf: String::new(),
284 cursor, 357 cursor,
358 open_delims: FxHashMap::default(),
285 text_pos: 0.into(), 359 text_pos: 0.into(),
286 inner: SyntaxTreeBuilder::default(), 360 inner: SyntaxTreeBuilder::default(),
287 roots: smallvec::SmallVec::new(), 361 roots: smallvec::SmallVec::new(),
@@ -294,16 +368,16 @@ impl<'a> TtTreeSink<'a> {
294 } 368 }
295} 369}
296 370
297fn delim_to_str(d: tt::Delimiter, closing: bool) -> SmolStr { 371fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr {
298 let texts = match d { 372 let texts = match d {
299 tt::Delimiter::Parenthesis => "()", 373 Some(tt::DelimiterKind::Parenthesis) => "()",
300 tt::Delimiter::Brace => "{}", 374 Some(tt::DelimiterKind::Brace) => "{}",
301 tt::Delimiter::Bracket => "[]", 375 Some(tt::DelimiterKind::Bracket) => "[]",
302 tt::Delimiter::None => "", 376 None => return "".into(),
303 }; 377 };
304 378
305 let idx = closing as usize; 379 let idx = closing as usize;
306 let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" }; 380 let text = &texts[idx..texts.len() - (1 - idx)];
307 text.into() 381 text.into()
308} 382}
309 383
@@ -319,34 +393,49 @@ impl<'a> TreeSink for TtTreeSink<'a> {
319 break; 393 break;
320 } 394 }
321 395
322 match self.cursor.token_tree() { 396 let text: SmolStr = match self.cursor.token_tree() {
323 Some(tt::TokenTree::Leaf(leaf)) => { 397 Some(tt::TokenTree::Leaf(leaf)) => {
324 // Mark the range if needed 398 // Mark the range if needed
325 if let tt::Leaf::Ident(ident) = leaf { 399 let id = match leaf {
326 if kind == IDENT { 400 tt::Leaf::Ident(ident) => ident.id,
327 let range = 401 tt::Leaf::Punct(punct) => punct.id,
328 TextRange::offset_len(self.text_pos, TextUnit::of_str(&ident.text)); 402 tt::Leaf::Literal(lit) => lit.id,
329 self.token_map.insert(ident.id, range); 403 };
330 } 404 let text = SmolStr::new(format!("{}", leaf));
331 } 405 let range = TextRange::offset_len(self.text_pos, TextUnit::of_str(&text));
332 406 self.token_map.insert(id, range);
333 self.cursor = self.cursor.bump(); 407 self.cursor = self.cursor.bump();
334 self.buf += &format!("{}", leaf); 408 text
335 } 409 }
336 Some(tt::TokenTree::Subtree(subtree)) => { 410 Some(tt::TokenTree::Subtree(subtree)) => {
337 self.cursor = self.cursor.subtree().unwrap(); 411 self.cursor = self.cursor.subtree().unwrap();
338 self.buf += &delim_to_str(subtree.delimiter, false); 412 if let Some(id) = subtree.delimiter.map(|it| it.id) {
413 self.open_delims.insert(id, self.text_pos);
414 }
415 delim_to_str(subtree.delimiter_kind(), false)
339 } 416 }
340 None => { 417 None => {
341 if let Some(parent) = self.cursor.end() { 418 if let Some(parent) = self.cursor.end() {
342 self.cursor = self.cursor.bump(); 419 self.cursor = self.cursor.bump();
343 self.buf += &delim_to_str(parent.delimiter, true); 420 if let Some(id) = parent.delimiter.map(|it| it.id) {
421 if let Some(open_delim) = self.open_delims.get(&id) {
422 let open_range =
423 TextRange::offset_len(*open_delim, TextUnit::from_usize(1));
424 let close_range =
425 TextRange::offset_len(self.text_pos, TextUnit::from_usize(1));
426 self.token_map.insert_delim(id, open_range, close_range);
427 }
428 }
429 delim_to_str(parent.delimiter_kind(), true)
430 } else {
431 continue;
344 } 432 }
345 } 433 }
346 }; 434 };
435 self.buf += &text;
436 self.text_pos += TextUnit::of_str(&text);
347 } 437 }
348 438
349 self.text_pos += TextUnit::of_str(&self.buf);
350 let text = SmolStr::new(self.buf.as_str()); 439 let text = SmolStr::new(self.buf.as_str());
351 self.buf.clear(); 440 self.buf.clear();
352 self.inner.token(kind, text); 441 self.inner.token(kind, text);
@@ -387,13 +476,16 @@ impl<'a> TreeSink for TtTreeSink<'a> {
387#[cfg(test)] 476#[cfg(test)]
388mod tests { 477mod tests {
389 use super::*; 478 use super::*;
390 use crate::tests::{create_rules, expand}; 479 use crate::tests::parse_macro;
391 use ra_parser::TokenSource; 480 use ra_parser::TokenSource;
392 use ra_syntax::algo::{insert_children, InsertPosition}; 481 use ra_syntax::{
482 algo::{insert_children, InsertPosition},
483 ast::AstNode,
484 };
393 485
394 #[test] 486 #[test]
395 fn convert_tt_token_source() { 487 fn convert_tt_token_source() {
396 let rules = create_rules( 488 let expansion = parse_macro(
397 r#" 489 r#"
398 macro_rules! literals { 490 macro_rules! literals {
399 ($i:ident) => { 491 ($i:ident) => {
@@ -406,8 +498,8 @@ mod tests {
406 } 498 }
407 } 499 }
408 "#, 500 "#,
409 ); 501 )
410 let expansion = expand(&rules, "literals!(foo);"); 502 .expand_tt("literals!(foo);");
411 let tts = &[expansion.into()]; 503 let tts = &[expansion.into()];
412 let buffer = tt::buffer::TokenBuffer::new(tts); 504 let buffer = tt::buffer::TokenBuffer::new(tts);
413 let mut tt_src = SubtreeTokenSource::new(&buffer); 505 let mut tt_src = SubtreeTokenSource::new(&buffer);
@@ -435,7 +527,7 @@ mod tests {
435 527
436 #[test] 528 #[test]
437 fn stmts_token_trees_to_expr_is_err() { 529 fn stmts_token_trees_to_expr_is_err() {
438 let rules = create_rules( 530 let expansion = parse_macro(
439 r#" 531 r#"
440 macro_rules! stmts { 532 macro_rules! stmts {
441 () => { 533 () => {
@@ -446,8 +538,8 @@ mod tests {
446 } 538 }
447 } 539 }
448 "#, 540 "#,
449 ); 541 )
450 let expansion = expand(&rules, "stmts!();"); 542 .expand_tt("stmts!();");
451 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err()); 543 assert!(token_tree_to_syntax_node(&expansion, FragmentKind::Expr).is_err());
452 } 544 }
453 545
@@ -489,6 +581,14 @@ mod tests {
489 let token_tree = ast::TokenTree::cast(token_tree).unwrap(); 581 let token_tree = ast::TokenTree::cast(token_tree).unwrap();
490 let tt = ast_to_token_tree(&token_tree).unwrap().0; 582 let tt = ast_to_token_tree(&token_tree).unwrap().0;
491 583
492 assert_eq!(tt.delimiter, tt::Delimiter::Brace); 584 assert_eq!(tt.delimiter_kind(), Some(tt::DelimiterKind::Brace));
585 }
586
587 #[test]
588 fn test_token_tree_multi_char_punct() {
589 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap();
590 let struct_def = source_file.syntax().descendants().find_map(ast::StructDef::cast).unwrap();
591 let tt = ast_to_token_tree(&struct_def).unwrap().0;
592 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap();
493 } 593 }
494} 594}
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs
index 0109a4d98..e640d115b 100644
--- a/crates/ra_mbe/src/tests.rs
+++ b/crates/ra_mbe/src/tests.rs
@@ -1,5 +1,7 @@
1use std::fmt::Write;
2
1use ra_parser::FragmentKind; 3use ra_parser::FragmentKind;
2use ra_syntax::{ast, AstNode, NodeOrToken, WalkEvent}; 4use ra_syntax::{ast, AstNode, NodeOrToken, SyntaxKind::IDENT, SyntaxNode, WalkEvent, T};
3use test_utils::assert_eq_text; 5use test_utils::assert_eq_text;
4 6
5use super::*; 7use super::*;
@@ -61,13 +63,14 @@ mod rule_parsing {
61 63
62#[test] 64#[test]
63fn test_token_id_shift() { 65fn test_token_id_shift() {
64 let macro_definition = r#" 66 let expansion = parse_macro(
67 r#"
65macro_rules! foobar { 68macro_rules! foobar {
66 ($e:ident) => { foo bar $e } 69 ($e:ident) => { foo bar $e }
67} 70}
68"#; 71"#,
69 let rules = create_rules(macro_definition); 72 )
70 let expansion = expand(&rules, "foobar!(baz);"); 73 .expand_tt("foobar!(baz);");
71 74
72 fn get_id(t: &tt::TokenTree) -> Option<u32> { 75 fn get_id(t: &tt::TokenTree) -> Option<u32> {
73 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t { 76 if let tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) = t {
@@ -77,18 +80,47 @@ macro_rules! foobar {
77 } 80 }
78 81
79 assert_eq!(expansion.token_trees.len(), 3); 82 assert_eq!(expansion.token_trees.len(), 3);
80 // ($e:ident) => { foo bar $e } 83 // {($e:ident) => { foo bar $e }}
81 // 0 1 2 3 4 84 // 012345 67 8 9 T 12
82 assert_eq!(get_id(&expansion.token_trees[0]), Some(2)); 85 assert_eq!(get_id(&expansion.token_trees[0]), Some(9));
83 assert_eq!(get_id(&expansion.token_trees[1]), Some(3)); 86 assert_eq!(get_id(&expansion.token_trees[1]), Some(10));
84 87
85 // So baz should be 5 88 // The input args of macro call include parentheses:
86 assert_eq!(get_id(&expansion.token_trees[2]), Some(5)); 89 // (baz)
90 // So baz should be 12+1+1
91 assert_eq!(get_id(&expansion.token_trees[2]), Some(14));
92}
93
94#[test]
95fn test_token_map() {
96 let expanded = parse_macro(
97 r#"
98macro_rules! foobar {
99 ($e:ident) => { fn $e() {} }
100}
101"#,
102 )
103 .expand_tt("foobar!(baz);");
104
105 let (node, token_map) = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap();
106 let content = node.syntax_node().to_string();
107
108 let get_text = |id, kind| -> String {
109 content[token_map.range_by_token(id).unwrap().by_kind(kind).unwrap()].to_string()
110 };
111
112 assert_eq!(expanded.token_trees.len(), 4);
113 // {($e:ident) => { fn $e() {} }}
114 // 012345 67 8 9 T12 3
115
116 assert_eq!(get_text(tt::TokenId(9), IDENT), "fn");
117 assert_eq!(get_text(tt::TokenId(12), T!['(']), "(");
118 assert_eq!(get_text(tt::TokenId(13), T!['{']), "{");
87} 119}
88 120
89#[test] 121#[test]
90fn test_convert_tt() { 122fn test_convert_tt() {
91 let macro_definition = r#" 123 parse_macro(r#"
92macro_rules! impl_froms { 124macro_rules! impl_froms {
93 ($e:ident: $($v:ident),*) => { 125 ($e:ident: $($v:ident),*) => {
94 $( 126 $(
@@ -100,24 +132,17 @@ macro_rules! impl_froms {
100 )* 132 )*
101 } 133 }
102} 134}
103"#; 135"#)
104 136 .assert_expand_tt(
105 let macro_invocation = r#" 137 "impl_froms!(TokenTree: Leaf, Subtree);",
106impl_froms!(TokenTree: Leaf, Subtree); 138 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
107"#; 139 impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
108 140 );
109 let rules = create_rules(macro_definition);
110 let expansion = expand(&rules, macro_invocation);
111 assert_eq!(
112 expansion.to_string(),
113 "impl From <Leaf > for TokenTree {fn from (it : Leaf) -> TokenTree {TokenTree ::Leaf (it)}} \
114 impl From <Subtree > for TokenTree {fn from (it : Subtree) -> TokenTree {TokenTree ::Subtree (it)}}"
115 )
116} 141}
117 142
118#[test] 143#[test]
119fn test_expr_order() { 144fn test_expr_order() {
120 let rules = create_rules( 145 let expanded = parse_macro(
121 r#" 146 r#"
122 macro_rules! foo { 147 macro_rules! foo {
123 ($ i:expr) => { 148 ($ i:expr) => {
@@ -125,11 +150,10 @@ fn test_expr_order() {
125 } 150 }
126 } 151 }
127"#, 152"#,
128 ); 153 )
129 let expanded = expand(&rules, "foo! { 1 + 1}"); 154 .expand_items("foo! { 1 + 1}");
130 let tree = token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
131 155
132 let dump = format!("{:#?}", tree); 156 let dump = format!("{:#?}", expanded);
133 assert_eq_text!( 157 assert_eq_text!(
134 dump.trim(), 158 dump.trim(),
135 r#"MACRO_ITEMS@[0; 15) 159 r#"MACRO_ITEMS@[0; 15)
@@ -161,7 +185,7 @@ fn test_expr_order() {
161 185
162#[test] 186#[test]
163fn test_fail_match_pattern_by_first_token() { 187fn test_fail_match_pattern_by_first_token() {
164 let rules = create_rules( 188 parse_macro(
165 r#" 189 r#"
166 macro_rules! foo { 190 macro_rules! foo {
167 ($ i:ident) => ( 191 ($ i:ident) => (
@@ -175,16 +199,15 @@ fn test_fail_match_pattern_by_first_token() {
175 ) 199 )
176 } 200 }
177"#, 201"#,
178 ); 202 )
179 203 .assert_expand_items("foo! { foo }", "mod foo {}")
180 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 204 .assert_expand_items("foo! { = bar }", "fn bar () {}")
181 assert_expansion(MacroKind::Items, &rules, "foo! { = bar }", "fn bar () {}"); 205 .assert_expand_items("foo! { + Baz }", "struct Baz ;");
182 assert_expansion(MacroKind::Items, &rules, "foo! { + Baz }", "struct Baz ;");
183} 206}
184 207
185#[test] 208#[test]
186fn test_fail_match_pattern_by_last_token() { 209fn test_fail_match_pattern_by_last_token() {
187 let rules = create_rules( 210 parse_macro(
188 r#" 211 r#"
189 macro_rules! foo { 212 macro_rules! foo {
190 ($ i:ident) => ( 213 ($ i:ident) => (
@@ -198,16 +221,15 @@ fn test_fail_match_pattern_by_last_token() {
198 ) 221 )
199 } 222 }
200"#, 223"#,
201 ); 224 )
202 225 .assert_expand_items("foo! { foo }", "mod foo {}")
203 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 226 .assert_expand_items("foo! { bar = }", "fn bar () {}")
204 assert_expansion(MacroKind::Items, &rules, "foo! { bar = }", "fn bar () {}"); 227 .assert_expand_items("foo! { Baz + }", "struct Baz ;");
205 assert_expansion(MacroKind::Items, &rules, "foo! { Baz + }", "struct Baz ;");
206} 228}
207 229
208#[test] 230#[test]
209fn test_fail_match_pattern_by_word_token() { 231fn test_fail_match_pattern_by_word_token() {
210 let rules = create_rules( 232 parse_macro(
211 r#" 233 r#"
212 macro_rules! foo { 234 macro_rules! foo {
213 ($ i:ident) => ( 235 ($ i:ident) => (
@@ -221,16 +243,15 @@ fn test_fail_match_pattern_by_word_token() {
221 ) 243 )
222 } 244 }
223"#, 245"#,
224 ); 246 )
225 247 .assert_expand_items("foo! { foo }", "mod foo {}")
226 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "mod foo {}"); 248 .assert_expand_items("foo! { spam bar }", "fn bar () {}")
227 assert_expansion(MacroKind::Items, &rules, "foo! { spam bar }", "fn bar () {}"); 249 .assert_expand_items("foo! { eggs Baz }", "struct Baz ;");
228 assert_expansion(MacroKind::Items, &rules, "foo! { eggs Baz }", "struct Baz ;");
229} 250}
230 251
231#[test] 252#[test]
232fn test_match_group_pattern_by_separator_token() { 253fn test_match_group_pattern_by_separator_token() {
233 let rules = create_rules( 254 parse_macro(
234 r#" 255 r#"
235 macro_rules! foo { 256 macro_rules! foo {
236 ($ ($ i:ident),*) => ($ ( 257 ($ ($ i:ident),*) => ($ (
@@ -245,16 +266,15 @@ fn test_match_group_pattern_by_separator_token() {
245 ) 266 )
246 } 267 }
247"#, 268"#,
248 ); 269 )
249 270 .assert_expand_items("foo! { foo, bar }", "mod foo {} mod bar {}")
250 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "mod foo {} mod bar {}"); 271 .assert_expand_items("foo! { foo# bar }", "fn foo () {} fn bar () {}")
251 assert_expansion(MacroKind::Items, &rules, "foo! { foo# bar }", "fn foo () {} fn bar () {}"); 272 .assert_expand_items("foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
252 assert_expansion(MacroKind::Items, &rules, "foo! { Foo,# Bar }", "struct Foo ; struct Bar ;");
253} 273}
254 274
255#[test] 275#[test]
256fn test_match_group_pattern_with_multiple_defs() { 276fn test_match_group_pattern_with_multiple_defs() {
257 let rules = create_rules( 277 parse_macro(
258 r#" 278 r#"
259 macro_rules! foo { 279 macro_rules! foo {
260 ($ ($ i:ident),*) => ( struct Bar { $ ( 280 ($ ($ i:ident),*) => ( struct Bar { $ (
@@ -262,19 +282,13 @@ fn test_match_group_pattern_with_multiple_defs() {
262 )*} ); 282 )*} );
263 } 283 }
264"#, 284"#,
265 ); 285 )
266 286 .assert_expand_items("foo! { foo, bar }", "struct Bar {fn foo {} fn bar {}}");
267 assert_expansion(
268 MacroKind::Items,
269 &rules,
270 "foo! { foo, bar }",
271 "struct Bar {fn foo {} fn bar {}}",
272 );
273} 287}
274 288
275#[test] 289#[test]
276fn test_match_group_pattern_with_multiple_statement() { 290fn test_match_group_pattern_with_multiple_statement() {
277 let rules = create_rules( 291 parse_macro(
278 r#" 292 r#"
279 macro_rules! foo { 293 macro_rules! foo {
280 ($ ($ i:ident),*) => ( fn baz { $ ( 294 ($ ($ i:ident),*) => ( fn baz { $ (
@@ -282,14 +296,13 @@ fn test_match_group_pattern_with_multiple_statement() {
282 )*} ); 296 )*} );
283 } 297 }
284"#, 298"#,
285 ); 299 )
286 300 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
287 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ; bar () ;}");
288} 301}
289 302
290#[test] 303#[test]
291fn test_match_group_pattern_with_multiple_statement_without_semi() { 304fn test_match_group_pattern_with_multiple_statement_without_semi() {
292 let rules = create_rules( 305 parse_macro(
293 r#" 306 r#"
294 macro_rules! foo { 307 macro_rules! foo {
295 ($ ($ i:ident),*) => ( fn baz { $ ( 308 ($ ($ i:ident),*) => ( fn baz { $ (
@@ -297,14 +310,13 @@ fn test_match_group_pattern_with_multiple_statement_without_semi() {
297 );*} ); 310 );*} );
298 } 311 }
299"#, 312"#,
300 ); 313 )
301 314 .assert_expand_items("foo! { foo, bar }", "fn baz {foo () ;bar ()}");
302 assert_expansion(MacroKind::Items, &rules, "foo! { foo, bar }", "fn baz {foo () ;bar ()}");
303} 315}
304 316
305#[test] 317#[test]
306fn test_match_group_empty_fixed_token() { 318fn test_match_group_empty_fixed_token() {
307 let rules = create_rules( 319 parse_macro(
308 r#" 320 r#"
309 macro_rules! foo { 321 macro_rules! foo {
310 ($ ($ i:ident)* #abc) => ( fn baz { $ ( 322 ($ ($ i:ident)* #abc) => ( fn baz { $ (
@@ -312,69 +324,59 @@ fn test_match_group_empty_fixed_token() {
312 )*} ); 324 )*} );
313 } 325 }
314"#, 326"#,
315 ); 327 )
316 328 .assert_expand_items("foo! {#abc}", "fn baz {}");
317 assert_expansion(MacroKind::Items, &rules, "foo! {#abc}", "fn baz {}");
318} 329}
319 330
320#[test] 331#[test]
321fn test_match_group_in_subtree() { 332fn test_match_group_in_subtree() {
322 let rules = create_rules( 333 parse_macro(
323 r#" 334 r#"
324 macro_rules! foo { 335 macro_rules! foo {
325 (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ ( 336 (fn $name:ident {$($i:ident)*} ) => ( fn $name() { $ (
326 $ i (); 337 $ i ();
327 )*} ); 338 )*} );
328 }"#, 339 }"#,
329 ); 340 )
330 341 .assert_expand_items("foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
331 assert_expansion(MacroKind::Items, &rules, "foo! {fn baz {a b} }", "fn baz () {a () ; b () ;}");
332} 342}
333 343
334#[test] 344#[test]
335fn test_match_group_with_multichar_sep() { 345fn test_match_group_with_multichar_sep() {
336 let rules = create_rules( 346 parse_macro(
337 r#" 347 r#"
338 macro_rules! foo { 348 macro_rules! foo {
339 (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} ); 349 (fn $name:ident {$($i:literal)*} ) => ( fn $name() -> bool { $($i)&&*} );
340 }"#, 350 }"#,
341 ); 351 )
342 352 .assert_expand_items("foo! (fn baz {true true} );", "fn baz () -> bool {true &&true}");
343 assert_expansion(
344 MacroKind::Items,
345 &rules,
346 "foo! (fn baz {true true} );",
347 "fn baz () -> bool {true &&true}",
348 );
349} 353}
350 354
351#[test] 355#[test]
352fn test_match_group_zero_match() { 356fn test_match_group_zero_match() {
353 let rules = create_rules( 357 parse_macro(
354 r#" 358 r#"
355 macro_rules! foo { 359 macro_rules! foo {
356 ( $($i:ident)* ) => (); 360 ( $($i:ident)* ) => ();
357 }"#, 361 }"#,
358 ); 362 )
359 363 .assert_expand_items("foo! ();", "");
360 assert_expansion(MacroKind::Items, &rules, "foo! ();", "");
361} 364}
362 365
363#[test] 366#[test]
364fn test_match_group_in_group() { 367fn test_match_group_in_group() {
365 let rules = create_rules( 368 parse_macro(
366 r#" 369 r#"
367 macro_rules! foo { 370 macro_rules! foo {
368 { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* ); 371 { $( ( $($i:ident)* ) )* } => ( $( ( $($i)* ) )* );
369 }"#, 372 }"#,
370 ); 373 )
371 374 .assert_expand_items("foo! ( (a b) );", "(a b)");
372 assert_expansion(MacroKind::Items, &rules, "foo! ( (a b) );", "(a b)");
373} 375}
374 376
375#[test] 377#[test]
376fn test_expand_to_item_list() { 378fn test_expand_to_item_list() {
377 let rules = create_rules( 379 let tree = parse_macro(
378 " 380 "
379 macro_rules! structs { 381 macro_rules! structs {
380 ($($i:ident),*) => { 382 ($($i:ident),*) => {
@@ -382,9 +384,8 @@ fn test_expand_to_item_list() {
382 } 384 }
383 } 385 }
384 ", 386 ",
385 ); 387 )
386 let expansion = expand(&rules, "structs!(Foo, Bar);"); 388 .expand_items("structs!(Foo, Bar);");
387 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Items).unwrap().0.syntax_node();
388 assert_eq!( 389 assert_eq!(
389 format!("{:#?}", tree).trim(), 390 format!("{:#?}", tree).trim(),
390 r#" 391 r#"
@@ -441,7 +442,7 @@ fn test_expand_literals_to_token_tree() {
441 unreachable!("It is not a literal"); 442 unreachable!("It is not a literal");
442 } 443 }
443 444
444 let rules = create_rules( 445 let expansion = parse_macro(
445 r#" 446 r#"
446 macro_rules! literals { 447 macro_rules! literals {
447 ($i:ident) => { 448 ($i:ident) => {
@@ -454,8 +455,8 @@ fn test_expand_literals_to_token_tree() {
454 } 455 }
455 } 456 }
456 "#, 457 "#,
457 ); 458 )
458 let expansion = expand(&rules, "literals!(foo);"); 459 .expand_tt("literals!(foo);");
459 let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees; 460 let stm_tokens = &to_subtree(&expansion.token_trees[0]).token_trees;
460 461
461 // [let] [a] [=] ['c'] [;] 462 // [let] [a] [=] ['c'] [;]
@@ -470,7 +471,7 @@ fn test_expand_literals_to_token_tree() {
470 471
471#[test] 472#[test]
472fn test_two_idents() { 473fn test_two_idents() {
473 let rules = create_rules( 474 parse_macro(
474 r#" 475 r#"
475 macro_rules! foo { 476 macro_rules! foo {
476 ($ i:ident, $ j:ident) => { 477 ($ i:ident, $ j:ident) => {
@@ -478,18 +479,13 @@ fn test_two_idents() {
478 } 479 }
479 } 480 }
480"#, 481"#,
481 ); 482 )
482 assert_expansion( 483 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
483 MacroKind::Items,
484 &rules,
485 "foo! { foo, bar }",
486 "fn foo () {let a = foo ; let b = bar ;}",
487 );
488} 484}
489 485
490#[test] 486#[test]
491fn test_tt_to_stmts() { 487fn test_tt_to_stmts() {
492 let rules = create_rules( 488 let stmts = parse_macro(
493 r#" 489 r#"
494 macro_rules! foo { 490 macro_rules! foo {
495 () => { 491 () => {
@@ -499,11 +495,8 @@ fn test_tt_to_stmts() {
499 } 495 }
500 } 496 }
501"#, 497"#,
502 ); 498 )
503 499 .expand_statements("foo!{}");
504 let expanded = expand(&rules, "foo!{}");
505 let stmts =
506 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node();
507 500
508 assert_eq!( 501 assert_eq!(
509 format!("{:#?}", stmts).trim(), 502 format!("{:#?}", stmts).trim(),
@@ -543,7 +536,7 @@ fn test_tt_to_stmts() {
543 536
544#[test] 537#[test]
545fn test_match_literal() { 538fn test_match_literal() {
546 let rules = create_rules( 539 parse_macro(
547 r#" 540 r#"
548 macro_rules! foo { 541 macro_rules! foo {
549 ('(') => { 542 ('(') => {
@@ -551,8 +544,8 @@ fn test_match_literal() {
551 } 544 }
552 } 545 }
553"#, 546"#,
554 ); 547 )
555 assert_expansion(MacroKind::Items, &rules, "foo! ['('];", "fn foo () {}"); 548 .assert_expand_items("foo! ['('];", "fn foo () {}");
556} 549}
557 550
558// The following tests are port from intellij-rust directly 551// The following tests are port from intellij-rust directly
@@ -560,7 +553,7 @@ fn test_match_literal() {
560 553
561#[test] 554#[test]
562fn test_path() { 555fn test_path() {
563 let rules = create_rules( 556 parse_macro(
564 r#" 557 r#"
565 macro_rules! foo { 558 macro_rules! foo {
566 ($ i:path) => { 559 ($ i:path) => {
@@ -568,11 +561,9 @@ fn test_path() {
568 } 561 }
569 } 562 }
570"#, 563"#,
571 ); 564 )
572 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo ;}"); 565 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo ;}")
573 assert_expansion( 566 .assert_expand_items(
574 MacroKind::Items,
575 &rules,
576 "foo! { bar::<u8>::baz::<u8> }", 567 "foo! { bar::<u8>::baz::<u8> }",
577 "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}", 568 "fn foo () {let a = bar ::< u8 >:: baz ::< u8 > ;}",
578 ); 569 );
@@ -580,7 +571,7 @@ fn test_path() {
580 571
581#[test] 572#[test]
582fn test_two_paths() { 573fn test_two_paths() {
583 let rules = create_rules( 574 parse_macro(
584 r#" 575 r#"
585 macro_rules! foo { 576 macro_rules! foo {
586 ($ i:path, $ j:path) => { 577 ($ i:path, $ j:path) => {
@@ -588,18 +579,13 @@ fn test_two_paths() {
588 } 579 }
589 } 580 }
590"#, 581"#,
591 ); 582 )
592 assert_expansion( 583 .assert_expand_items("foo! { foo, bar }", "fn foo () {let a = foo ; let b = bar ;}");
593 MacroKind::Items,
594 &rules,
595 "foo! { foo, bar }",
596 "fn foo () {let a = foo ; let b = bar ;}",
597 );
598} 584}
599 585
600#[test] 586#[test]
601fn test_path_with_path() { 587fn test_path_with_path() {
602 let rules = create_rules( 588 parse_macro(
603 r#" 589 r#"
604 macro_rules! foo { 590 macro_rules! foo {
605 ($ i:path) => { 591 ($ i:path) => {
@@ -607,13 +593,13 @@ fn test_path_with_path() {
607 } 593 }
608 } 594 }
609"#, 595"#,
610 ); 596 )
611 assert_expansion(MacroKind::Items, &rules, "foo! { foo }", "fn foo () {let a = foo :: bar ;}"); 597 .assert_expand_items("foo! { foo }", "fn foo () {let a = foo :: bar ;}");
612} 598}
613 599
614#[test] 600#[test]
615fn test_expr() { 601fn test_expr() {
616 let rules = create_rules( 602 parse_macro(
617 r#" 603 r#"
618 macro_rules! foo { 604 macro_rules! foo {
619 ($ i:expr) => { 605 ($ i:expr) => {
@@ -621,11 +607,8 @@ fn test_expr() {
621 } 607 }
622 } 608 }
623"#, 609"#,
624 ); 610 )
625 611 .assert_expand_items(
626 assert_expansion(
627 MacroKind::Items,
628 &rules,
629 "foo! { 2 + 2 * baz(3).quux() }", 612 "foo! { 2 + 2 * baz(3).quux() }",
630 "fn bar () {2 + 2 * baz (3) . quux () ;}", 613 "fn bar () {2 + 2 * baz (3) . quux () ;}",
631 ); 614 );
@@ -633,7 +616,7 @@ fn test_expr() {
633 616
634#[test] 617#[test]
635fn test_last_expr() { 618fn test_last_expr() {
636 let rules = create_rules( 619 parse_macro(
637 r#" 620 r#"
638 macro_rules! vec { 621 macro_rules! vec {
639 ($($item:expr),*) => { 622 ($($item:expr),*) => {
@@ -647,10 +630,8 @@ fn test_last_expr() {
647 }; 630 };
648 } 631 }
649"#, 632"#,
650 ); 633 )
651 assert_expansion( 634 .assert_expand_items(
652 MacroKind::Items,
653 &rules,
654 "vec!(1,2,3);", 635 "vec!(1,2,3);",
655 "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}", 636 "{let mut v = Vec :: new () ; v . push (1) ; v . push (2) ; v . push (3) ; v}",
656 ); 637 );
@@ -658,7 +639,7 @@ fn test_last_expr() {
658 639
659#[test] 640#[test]
660fn test_ty() { 641fn test_ty() {
661 let rules = create_rules( 642 parse_macro(
662 r#" 643 r#"
663 macro_rules! foo { 644 macro_rules! foo {
664 ($ i:ty) => ( 645 ($ i:ty) => (
@@ -666,18 +647,13 @@ fn test_ty() {
666 ) 647 )
667 } 648 }
668"#, 649"#,
669 ); 650 )
670 assert_expansion( 651 .assert_expand_items("foo! { Baz<u8> }", "fn bar () -> Baz < u8 > {unimplemented ! ()}");
671 MacroKind::Items,
672 &rules,
673 "foo! { Baz<u8> }",
674 "fn bar () -> Baz < u8 > {unimplemented ! ()}",
675 );
676} 652}
677 653
678#[test] 654#[test]
679fn test_ty_with_complex_type() { 655fn test_ty_with_complex_type() {
680 let rules = create_rules( 656 parse_macro(
681 r#" 657 r#"
682 macro_rules! foo { 658 macro_rules! foo {
683 ($ i:ty) => ( 659 ($ i:ty) => (
@@ -685,20 +661,14 @@ fn test_ty_with_complex_type() {
685 ) 661 )
686 } 662 }
687"#, 663"#,
688 ); 664 )
689
690 // Reference lifetime struct with generic type 665 // Reference lifetime struct with generic type
691 assert_expansion( 666 .assert_expand_items(
692 MacroKind::Items,
693 &rules,
694 "foo! { &'a Baz<u8> }", 667 "foo! { &'a Baz<u8> }",
695 "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}", 668 "fn bar () -> & 'a Baz < u8 > {unimplemented ! ()}",
696 ); 669 )
697
698 // extern "Rust" func type 670 // extern "Rust" func type
699 assert_expansion( 671 .assert_expand_items(
700 MacroKind::Items,
701 &rules,
702 r#"foo! { extern "Rust" fn() -> Ret }"#, 672 r#"foo! { extern "Rust" fn() -> Ret }"#,
703 r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#, 673 r#"fn bar () -> extern "Rust" fn () -> Ret {unimplemented ! ()}"#,
704 ); 674 );
@@ -706,19 +676,19 @@ fn test_ty_with_complex_type() {
706 676
707#[test] 677#[test]
708fn test_pat_() { 678fn test_pat_() {
709 let rules = create_rules( 679 parse_macro(
710 r#" 680 r#"
711 macro_rules! foo { 681 macro_rules! foo {
712 ($ i:pat) => { fn foo() { let $ i; } } 682 ($ i:pat) => { fn foo() { let $ i; } }
713 } 683 }
714"#, 684"#,
715 ); 685 )
716 assert_expansion(MacroKind::Items, &rules, "foo! { (a, b) }", "fn foo () {let (a , b) ;}"); 686 .assert_expand_items("foo! { (a, b) }", "fn foo () {let (a , b) ;}");
717} 687}
718 688
719#[test] 689#[test]
720fn test_stmt() { 690fn test_stmt() {
721 let rules = create_rules( 691 parse_macro(
722 r#" 692 r#"
723 macro_rules! foo { 693 macro_rules! foo {
724 ($ i:stmt) => ( 694 ($ i:stmt) => (
@@ -726,14 +696,14 @@ fn test_stmt() {
726 ) 696 )
727 } 697 }
728"#, 698"#,
729 ); 699 )
730 assert_expansion(MacroKind::Items, &rules, "foo! { 2 }", "fn bar () {2 ;}"); 700 .assert_expand_items("foo! { 2 }", "fn bar () {2 ;}")
731 assert_expansion(MacroKind::Items, &rules, "foo! { let a = 0 }", "fn bar () {let a = 0 ;}"); 701 .assert_expand_items("foo! { let a = 0 }", "fn bar () {let a = 0 ;}");
732} 702}
733 703
734#[test] 704#[test]
735fn test_single_item() { 705fn test_single_item() {
736 let rules = create_rules( 706 parse_macro(
737 r#" 707 r#"
738 macro_rules! foo { 708 macro_rules! foo {
739 ($ i:item) => ( 709 ($ i:item) => (
@@ -741,13 +711,13 @@ fn test_single_item() {
741 ) 711 )
742 } 712 }
743"#, 713"#,
744 ); 714 )
745 assert_expansion(MacroKind::Items, &rules, "foo! {mod c {}}", "mod c {}"); 715 .assert_expand_items("foo! {mod c {}}", "mod c {}");
746} 716}
747 717
748#[test] 718#[test]
749fn test_all_items() { 719fn test_all_items() {
750 let rules = create_rules( 720 parse_macro(
751 r#" 721 r#"
752 macro_rules! foo { 722 macro_rules! foo {
753 ($ ($ i:item)*) => ($ ( 723 ($ ($ i:item)*) => ($ (
@@ -755,10 +725,8 @@ fn test_all_items() {
755 )*) 725 )*)
756 } 726 }
757"#, 727"#,
758 ); 728 ).
759 assert_expansion( 729 assert_expand_items(
760 MacroKind::Items,
761 &rules,
762 r#" 730 r#"
763 foo! { 731 foo! {
764 extern crate a; 732 extern crate a;
@@ -782,19 +750,19 @@ fn test_all_items() {
782 750
783#[test] 751#[test]
784fn test_block() { 752fn test_block() {
785 let rules = create_rules( 753 parse_macro(
786 r#" 754 r#"
787 macro_rules! foo { 755 macro_rules! foo {
788 ($ i:block) => { fn foo() $ i } 756 ($ i:block) => { fn foo() $ i }
789 } 757 }
790"#, 758"#,
791 ); 759 )
792 assert_expansion(MacroKind::Stmts, &rules, "foo! { { 1; } }", "fn foo () {1 ;}"); 760 .assert_expand_statements("foo! { { 1; } }", "fn foo () {1 ;}");
793} 761}
794 762
795#[test] 763#[test]
796fn test_meta() { 764fn test_meta() {
797 let rules = create_rules( 765 parse_macro(
798 r#" 766 r#"
799 macro_rules! foo { 767 macro_rules! foo {
800 ($ i:meta) => ( 768 ($ i:meta) => (
@@ -803,10 +771,8 @@ fn test_meta() {
803 ) 771 )
804 } 772 }
805"#, 773"#,
806 ); 774 )
807 assert_expansion( 775 .assert_expand_items(
808 MacroKind::Items,
809 &rules,
810 r#"foo! { cfg(target_os = "windows") }"#, 776 r#"foo! { cfg(target_os = "windows") }"#,
811 r#"# [cfg (target_os = "windows")] fn bar () {}"#, 777 r#"# [cfg (target_os = "windows")] fn bar () {}"#,
812 ); 778 );
@@ -814,7 +780,7 @@ fn test_meta() {
814 780
815#[test] 781#[test]
816fn test_meta_doc_comments() { 782fn test_meta_doc_comments() {
817 let rules = create_rules( 783 parse_macro(
818 r#" 784 r#"
819 macro_rules! foo { 785 macro_rules! foo {
820 ($(#[$ i:meta])+) => ( 786 ($(#[$ i:meta])+) => (
@@ -823,10 +789,8 @@ fn test_meta_doc_comments() {
823 ) 789 )
824 } 790 }
825"#, 791"#,
826 ); 792 ).
827 assert_expansion( 793 assert_expand_items(
828 MacroKind::Items,
829 &rules,
830 r#"foo! { 794 r#"foo! {
831 /// Single Line Doc 1 795 /// Single Line Doc 1
832 /** 796 /**
@@ -839,69 +803,68 @@ fn test_meta_doc_comments() {
839 803
840#[test] 804#[test]
841fn test_tt_block() { 805fn test_tt_block() {
842 let rules = create_rules( 806 parse_macro(
843 r#" 807 r#"
844 macro_rules! foo { 808 macro_rules! foo {
845 ($ i:tt) => { fn foo() $ i } 809 ($ i:tt) => { fn foo() $ i }
846 } 810 }
847 "#, 811 "#,
848 ); 812 )
849 assert_expansion(MacroKind::Items, &rules, r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#); 813 .assert_expand_items(r#"foo! { { 1; } }"#, r#"fn foo () {1 ;}"#);
850} 814}
851 815
852#[test] 816#[test]
853fn test_tt_group() { 817fn test_tt_group() {
854 let rules = create_rules( 818 parse_macro(
855 r#" 819 r#"
856 macro_rules! foo { 820 macro_rules! foo {
857 ($($ i:tt)*) => { $($ i)* } 821 ($($ i:tt)*) => { $($ i)* }
858 } 822 }
859 "#, 823 "#,
860 ); 824 )
861 assert_expansion(MacroKind::Items, &rules, r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#); 825 .assert_expand_items(r#"foo! { fn foo() {} }"#, r#"fn foo () {}"#);
862} 826}
863#[test] 827#[test]
864fn test_lifetime() { 828fn test_lifetime() {
865 let rules = create_rules( 829 parse_macro(
866 r#" 830 r#"
867 macro_rules! foo { 831 macro_rules! foo {
868 ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } } 832 ($ lt:lifetime) => { struct Ref<$ lt>{ s: &$ lt str } }
869 } 833 }
870"#, 834"#,
871 ); 835 )
872 assert_expansion(MacroKind::Items, &rules, r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#); 836 .assert_expand_items(r#"foo!{'a}"#, r#"struct Ref <'a > {s : &'a str}"#);
873} 837}
874 838
875#[test] 839#[test]
876fn test_literal() { 840fn test_literal() {
877 let rules = create_rules( 841 parse_macro(
878 r#" 842 r#"
879 macro_rules! foo { 843 macro_rules! foo {
880 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;}; 844 ($ type:ty $ lit:literal) => { const VALUE: $ type = $ lit;};
881 } 845 }
882"#, 846"#,
883 ); 847 )
884 assert_expansion(MacroKind::Items, &rules, r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#); 848 .assert_expand_items(r#"foo!(u8 0);"#, r#"const VALUE : u8 = 0 ;"#);
885} 849}
886 850
887#[test] 851#[test]
888fn test_vis() { 852fn test_vis() {
889 let rules = create_rules( 853 parse_macro(
890 r#" 854 r#"
891 macro_rules! foo { 855 macro_rules! foo {
892 ($ vis:vis $ name:ident) => { $ vis fn $ name() {}}; 856 ($ vis:vis $ name:ident) => { $ vis fn $ name() {}};
893 } 857 }
894"#, 858"#,
895 ); 859 )
896 assert_expansion(MacroKind::Items, &rules, r#"foo!(pub foo);"#, r#"pub fn foo () {}"#); 860 .assert_expand_items(r#"foo!(pub foo);"#, r#"pub fn foo () {}"#)
897 861 // test optional cases
898 // test optional casse 862 .assert_expand_items(r#"foo!(foo);"#, r#"fn foo () {}"#);
899 assert_expansion(MacroKind::Items, &rules, r#"foo!(foo);"#, r#"fn foo () {}"#);
900} 863}
901 864
902#[test] 865#[test]
903fn test_inner_macro_rules() { 866fn test_inner_macro_rules() {
904 let rules = create_rules( 867 parse_macro(
905 r#" 868 r#"
906macro_rules! foo { 869macro_rules! foo {
907 ($a:ident, $b:ident, $c:tt) => { 870 ($a:ident, $b:ident, $c:tt) => {
@@ -917,10 +880,8 @@ macro_rules! foo {
917 } 880 }
918} 881}
919"#, 882"#,
920 ); 883 ).
921 assert_expansion( 884 assert_expand_items(
922 MacroKind::Items,
923 &rules,
924 r#"foo!(x,y, 1);"#, 885 r#"foo!(x,y, 1);"#,
925 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#, 886 r#"macro_rules ! bar {($ bi : ident) => {fn $ bi () -> u8 {1}}} bar ! (x) ; fn y () -> u8 {1}"#,
926 ); 887 );
@@ -929,7 +890,7 @@ macro_rules! foo {
929// The following tests are based on real world situations 890// The following tests are based on real world situations
930#[test] 891#[test]
931fn test_vec() { 892fn test_vec() {
932 let rules = create_rules( 893 let fixture = parse_macro(
933 r#" 894 r#"
934 macro_rules! vec { 895 macro_rules! vec {
935 ($($item:expr),*) => { 896 ($($item:expr),*) => {
@@ -944,16 +905,14 @@ fn test_vec() {
944} 905}
945"#, 906"#,
946 ); 907 );
947 assert_expansion(MacroKind::Items, &rules, r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#); 908 fixture
948 assert_expansion( 909 .assert_expand_items(r#"vec!();"#, r#"{let mut v = Vec :: new () ; v}"#)
949 MacroKind::Items, 910 .assert_expand_items(
950 &rules, 911 r#"vec![1u32,2];"#,
951 r#"vec![1u32,2];"#, 912 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#,
952 r#"{let mut v = Vec :: new () ; v . push (1u32) ; v . push (2) ; v}"#, 913 );
953 );
954 914
955 let expansion = expand(&rules, r#"vec![1u32,2];"#); 915 let tree = fixture.expand_expr(r#"vec![1u32,2];"#);
956 let tree = token_tree_to_syntax_node(&expansion, FragmentKind::Expr).unwrap().0.syntax_node();
957 916
958 assert_eq!( 917 assert_eq!(
959 format!("{:#?}", tree).trim(), 918 format!("{:#?}", tree).trim(),
@@ -1027,7 +986,7 @@ fn test_vec() {
1027fn test_winapi_struct() { 986fn test_winapi_struct() {
1028 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366 987 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/macros.rs#L366
1029 988
1030 let rules = create_rules( 989 parse_macro(
1031 r#" 990 r#"
1032macro_rules! STRUCT { 991macro_rules! STRUCT {
1033 ($(#[$attrs:meta])* struct $name:ident { 992 ($(#[$attrs:meta])* struct $name:ident {
@@ -1049,17 +1008,19 @@ macro_rules! STRUCT {
1049 ); 1008 );
1050} 1009}
1051"#, 1010"#,
1052 ); 1011 ).
1053 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs 1012 // from https://github.com/retep998/winapi-rs/blob/a7ef2bca086aae76cf6c4ce4c2552988ed9798ad/src/shared/d3d9caps.rs
1054 assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#, 1013 assert_expand_items(r#"STRUCT!{struct D3DVSHADERCAPS2_0 {Caps: u8,}}"#,
1055 "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); 1014 "# [repr (C)] # [derive (Copy)] pub struct D3DVSHADERCAPS2_0 {pub Caps : u8 ,} impl Clone for D3DVSHADERCAPS2_0 {# [inline] fn clone (& self) -> D3DVSHADERCAPS2_0 {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DVSHADERCAPS2_0 {# [inline] fn default () -> D3DVSHADERCAPS2_0 {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1056 assert_expansion(MacroKind::Items, &rules, r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#, 1015 )
1057 "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"); 1016 .assert_expand_items(r#"STRUCT!{#[cfg_attr(target_arch = "x86", repr(packed))] struct D3DCONTENTPROTECTIONCAPS {Caps : u8 ,}}"#,
1017 "# [repr (C)] # [derive (Copy)] # [cfg_attr (target_arch = \"x86\" , repr (packed))] pub struct D3DCONTENTPROTECTIONCAPS {pub Caps : u8 ,} impl Clone for D3DCONTENTPROTECTIONCAPS {# [inline] fn clone (& self) -> D3DCONTENTPROTECTIONCAPS {* self}} # [cfg (feature = \"impl-default\")] impl Default for D3DCONTENTPROTECTIONCAPS {# [inline] fn default () -> D3DCONTENTPROTECTIONCAPS {unsafe {$crate :: _core :: mem :: zeroed ()}}}"
1018 );
1058} 1019}
1059 1020
1060#[test] 1021#[test]
1061fn test_int_base() { 1022fn test_int_base() {
1062 let rules = create_rules( 1023 parse_macro(
1063 r#" 1024 r#"
1064macro_rules! int_base { 1025macro_rules! int_base {
1065 ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => { 1026 ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
@@ -1072,17 +1033,15 @@ macro_rules! int_base {
1072 } 1033 }
1073} 1034}
1074"#, 1035"#,
1075 ); 1036 ).assert_expand_items(r#" int_base!{Binary for isize as usize -> Binary}"#,
1076
1077 assert_expansion(MacroKind::Items, &rules, r#" int_base!{Binary for isize as usize -> Binary}"#,
1078 "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}" 1037 "# [stable (feature = \"rust1\" , since = \"1.0.0\")] impl fmt ::Binary for isize {fn fmt (& self , f : & mut fmt :: Formatter < \'_ >) -> fmt :: Result {Binary . fmt_int (* self as usize , f)}}"
1079 ); 1038 );
1080} 1039}
1081 1040
1082#[test] 1041#[test]
1083fn test_generate_pattern_iterators() { 1042fn test_generate_pattern_iterators() {
1084 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs 1043 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/str/mod.rs
1085 let rules = create_rules( 1044 parse_macro(
1086 r#" 1045 r#"
1087macro_rules! generate_pattern_iterators { 1046macro_rules! generate_pattern_iterators {
1088 { double ended; with $(#[$common_stability_attribute:meta])*, 1047 { double ended; with $(#[$common_stability_attribute:meta])*,
@@ -1093,11 +1052,7 @@ macro_rules! generate_pattern_iterators {
1093 } 1052 }
1094} 1053}
1095"#, 1054"#,
1096 ); 1055 ).assert_expand_items(
1097
1098 assert_expansion(
1099 MacroKind::Items,
1100 &rules,
1101 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#, 1056 r#"generate_pattern_iterators ! ( double ended ; with # [ stable ( feature = "rust1" , since = "1.0.0" ) ] , Split , RSplit , & 'a str );"#,
1102 "fn foo () {}", 1057 "fn foo () {}",
1103 ); 1058 );
@@ -1106,7 +1061,7 @@ macro_rules! generate_pattern_iterators {
1106#[test] 1061#[test]
1107fn test_impl_fn_for_zst() { 1062fn test_impl_fn_for_zst() {
1108 // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs 1063 // from https://github.com/rust-lang/rust/blob/5d20ff4d2718c820632b38c1e49d4de648a9810b/src/libcore/internal_macros.rs
1109 let rules = create_rules( 1064 parse_macro(
1110 r#" 1065 r#"
1111macro_rules! impl_fn_for_zst { 1066macro_rules! impl_fn_for_zst {
1112 { $( $( #[$attr: meta] )* 1067 { $( $( #[$attr: meta] )*
@@ -1147,9 +1102,7 @@ $body: block; )+
1147} 1102}
1148 } 1103 }
1149"#, 1104"#,
1150 ); 1105 ).assert_expand_items(r#"
1151
1152 assert_expansion(MacroKind::Items, &rules, r#"
1153impl_fn_for_zst ! { 1106impl_fn_for_zst ! {
1154 # [ derive ( Clone ) ] 1107 # [ derive ( Clone ) ]
1155 struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug { 1108 struct CharEscapeDebugContinue impl Fn = | c : char | -> char :: EscapeDebug {
@@ -1166,13 +1119,14 @@ impl_fn_for_zst ! {
1166 } ; 1119 } ;
1167 } 1120 }
1168"#, 1121"#,
1169 "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"); 1122 "# [derive (Clone)] struct CharEscapeDebugContinue ; impl Fn < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDebug {{c . escape_debug_ext (false)}}} impl FnMut < (char ,) > for CharEscapeDebugContinue {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDebugContinue {type Output = char :: EscapeDebug ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDebug {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeUnicode ; impl Fn < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeUnicode {{c . escape_unicode ()}}} impl FnMut < (char ,) > for CharEscapeUnicode {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeUnicode {type Output = char :: EscapeUnicode ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeUnicode {Fn :: call (& self , (c ,))}} # [derive (Clone)] struct CharEscapeDefault ; impl Fn < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call (& self , (c ,) : (char ,)) -> char :: EscapeDefault {{c . escape_default ()}}} impl FnMut < (char ,) > for CharEscapeDefault {# [inline] extern \"rust-call\" fn call_mut (& mut self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (&* self , (c ,))}} impl FnOnce < (char ,) > for CharEscapeDefault {type Output = char :: EscapeDefault ; # [inline] extern \"rust-call\" fn call_once (self , (c ,) : (char ,)) -> char :: EscapeDefault {Fn :: call (& self , (c ,))}}"
1123 );
1170} 1124}
1171 1125
1172#[test] 1126#[test]
1173fn test_impl_nonzero_fmt() { 1127fn test_impl_nonzero_fmt() {
1174 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12 1128 // from https://github.com/rust-lang/rust/blob/316a391dcb7d66dc25f1f9a4ec9d368ef7615005/src/libcore/num/mod.rs#L12
1175 let rules = create_rules( 1129 parse_macro(
1176 r#" 1130 r#"
1177 macro_rules! impl_nonzero_fmt { 1131 macro_rules! impl_nonzero_fmt {
1178 ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { 1132 ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => {
@@ -1180,11 +1134,7 @@ fn test_impl_nonzero_fmt() {
1180 } 1134 }
1181 } 1135 }
1182"#, 1136"#,
1183 ); 1137 ).assert_expand_items(
1184
1185 assert_expansion(
1186 MacroKind::Items,
1187 &rules,
1188 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#, 1138 r#"impl_nonzero_fmt! { # [stable(feature= "nonzero",since="1.28.0")] (Debug,Display,Binary,Octal,LowerHex,UpperHex) for NonZeroU8}"#,
1189 "fn foo () {}", 1139 "fn foo () {}",
1190 ); 1140 );
@@ -1193,7 +1143,7 @@ fn test_impl_nonzero_fmt() {
1193#[test] 1143#[test]
1194fn test_cfg_if_items() { 1144fn test_cfg_if_items() {
1195 // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986 1145 // from https://github.com/rust-lang/rust/blob/33fe1131cadba69d317156847be9a402b89f11bb/src/libstd/macros.rs#L986
1196 let rules = create_rules( 1146 parse_macro(
1197 r#" 1147 r#"
1198 macro_rules! __cfg_if_items { 1148 macro_rules! __cfg_if_items {
1199 (($($not:meta,)*) ; ) => {}; 1149 (($($not:meta,)*) ; ) => {};
@@ -1202,11 +1152,7 @@ fn test_cfg_if_items() {
1202 } 1152 }
1203 } 1153 }
1204"#, 1154"#,
1205 ); 1155 ).assert_expand_items(
1206
1207 assert_expansion(
1208 MacroKind::Items,
1209 &rules,
1210 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#, 1156 r#"__cfg_if_items ! { ( rustdoc , ) ; ( ( ) ( # [ cfg ( any ( target_os = "redox" , unix ) ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as unix ; # [ cfg ( windows ) ] # [ stable ( feature = "rust1" , since = "1.0.0" ) ] pub use sys :: ext as windows ; # [ cfg ( any ( target_os = "linux" , target_os = "l4re" ) ) ] pub mod linux ; ) ) , }"#,
1211 "__cfg_if_items ! {(rustdoc ,) ;}", 1157 "__cfg_if_items ! {(rustdoc ,) ;}",
1212 ); 1158 );
@@ -1215,7 +1161,7 @@ fn test_cfg_if_items() {
1215#[test] 1161#[test]
1216fn test_cfg_if_main() { 1162fn test_cfg_if_main() {
1217 // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9 1163 // from https://github.com/rust-lang/rust/blob/3d211248393686e0f73851fc7548f6605220fbe1/src/libpanic_unwind/macros.rs#L9
1218 let rules = create_rules( 1164 parse_macro(
1219 r#" 1165 r#"
1220 macro_rules! cfg_if { 1166 macro_rules! cfg_if {
1221 ($( 1167 ($(
@@ -1236,9 +1182,7 @@ fn test_cfg_if_main() {
1236 }; 1182 };
1237 } 1183 }
1238"#, 1184"#,
1239 ); 1185 ).assert_expand_items(r#"
1240
1241 assert_expansion(MacroKind::Items, &rules, r#"
1242cfg_if ! { 1186cfg_if ! {
1243 if # [ cfg ( target_env = "msvc" ) ] { 1187 if # [ cfg ( target_env = "msvc" ) ] {
1244 // no extra unwinder support needed 1188 // no extra unwinder support needed
@@ -1250,11 +1194,8 @@ cfg_if ! {
1250 } 1194 }
1251 } 1195 }
1252"#, 1196"#,
1253 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"); 1197 "__cfg_if_items ! {() ; ((target_env = \"msvc\") ()) , ((all (target_arch = \"wasm32\" , not (target_os = \"emscripten\"))) ()) , (() (mod libunwind ; pub use libunwind :: * ;)) ,}"
1254 1198 ).assert_expand_items(
1255 assert_expansion(
1256 MacroKind::Items,
1257 &rules,
1258 r#" 1199 r#"
1259cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , } 1200cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" , target_os = "illumos" ) ) ) ) ) ) , }
1260"#, 1201"#,
@@ -1265,7 +1206,7 @@ cfg_if ! { @ __apply cfg ( all ( not ( any ( not ( any ( target_os = "solaris" ,
1265#[test] 1206#[test]
1266fn test_proptest_arbitrary() { 1207fn test_proptest_arbitrary() {
1267 // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16 1208 // from https://github.com/AltSysrq/proptest/blob/d1c4b049337d2f75dd6f49a095115f7c532e5129/proptest/src/arbitrary/macros.rs#L16
1268 let rules = create_rules( 1209 parse_macro(
1269 r#" 1210 r#"
1270macro_rules! arbitrary { 1211macro_rules! arbitrary {
1271 ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty; 1212 ([$($bounds : tt)*] $typ: ty, $strat: ty, $params: ty;
@@ -1280,22 +1221,21 @@ macro_rules! arbitrary {
1280 }; 1221 };
1281 1222
1282}"#, 1223}"#,
1283 ); 1224 ).assert_expand_items(r#"arbitrary ! ( [ A : Arbitrary ]
1284
1285 assert_expansion(MacroKind::Items, &rules, r#"arbitrary ! ( [ A : Arbitrary ]
1286 Vec < A > , 1225 Vec < A > ,
1287 VecStrategy < A :: Strategy > , 1226 VecStrategy < A :: Strategy > ,
1288 RangedParams1 < A :: Parameters > ; 1227 RangedParams1 < A :: Parameters > ;
1289 args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) } 1228 args => { let product_unpack ! [ range , a ] = args ; vec ( any_with :: < A > ( a ) , range ) }
1290 ) ;"#, 1229 ) ;"#,
1291 "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"); 1230 "impl <A : Arbitrary > $crate :: arbitrary :: Arbitrary for Vec < A > {type Parameters = RangedParams1 < A :: Parameters > ; type Strategy = VecStrategy < A :: Strategy > ; fn arbitrary_with (args : Self :: Parameters) -> Self :: Strategy {{let product_unpack ! [range , a] = args ; vec (any_with :: < A > (a) , range)}}}"
1231 );
1292} 1232}
1293 1233
1294#[test] 1234#[test]
1295fn test_old_ridl() { 1235fn test_old_ridl() {
1296 // This is from winapi 2.8, which do not have a link from github 1236 // This is from winapi 2.8, which do not have a link from github
1297 // 1237 //
1298 let rules = create_rules( 1238 let expanded = parse_macro(
1299 r#" 1239 r#"
1300#[macro_export] 1240#[macro_export]
1301macro_rules! RIDL { 1241macro_rules! RIDL {
@@ -1311,21 +1251,17 @@ macro_rules! RIDL {
1311 } 1251 }
1312 }; 1252 };
1313}"#, 1253}"#,
1314 ); 1254 ).expand_tt(r#"
1255 RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1256 fn GetDataSize(&mut self) -> UINT
1257 }}"#);
1315 1258
1316 let expanded = expand(
1317 &rules,
1318 r#"
1319RIDL!{interface ID3D11Asynchronous(ID3D11AsynchronousVtbl): ID3D11DeviceChild(ID3D11DeviceChildVtbl) {
1320 fn GetDataSize(&mut self) -> UINT
1321}}"#,
1322 );
1323 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}"); 1259 assert_eq!(expanded.to_string(), "impl ID3D11Asynchronous {pub unsafe fn GetDataSize (& mut self) -> UINT {((* self . lpVtbl) .GetDataSize) (self)}}");
1324} 1260}
1325 1261
1326#[test] 1262#[test]
1327fn test_quick_error() { 1263fn test_quick_error() {
1328 let rules = create_rules( 1264 let expanded = parse_macro(
1329 r#" 1265 r#"
1330macro_rules! quick_error { 1266macro_rules! quick_error {
1331 1267
@@ -1348,10 +1284,8 @@ macro_rules! quick_error {
1348 1284
1349} 1285}
1350"#, 1286"#,
1351 ); 1287 )
1352 1288 .expand_tt(
1353 let expanded = expand(
1354 &rules,
1355 r#" 1289 r#"
1356quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [ 1290quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1357 => One : UNIT [] {} 1291 => One : UNIT [] {}
@@ -1365,7 +1299,7 @@ quick_error ! (SORT [enum Wrapped # [derive (Debug)]] items [
1365 1299
1366#[test] 1300#[test]
1367fn test_empty_repeat_vars_in_empty_repeat_vars() { 1301fn test_empty_repeat_vars_in_empty_repeat_vars() {
1368 let rules = create_rules( 1302 parse_macro(
1369 r#" 1303 r#"
1370macro_rules! delegate_impl { 1304macro_rules! delegate_impl {
1371 ([$self_type:ident, $self_wrap:ty, $self_map:ident] 1305 ([$self_type:ident, $self_wrap:ty, $self_map:ident]
@@ -1412,103 +1346,117 @@ macro_rules! delegate_impl {
1412 } 1346 }
1413} 1347}
1414"#, 1348"#,
1415 ); 1349 ).assert_expand_items(
1416
1417 assert_expansion(
1418 MacroKind::Items,
1419 &rules,
1420 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#, 1350 r#"delegate_impl ! {[G , & 'a mut G , deref] pub trait Data : GraphBase {@ section type type NodeWeight ;}}"#,
1421 "impl <> Data for & \'a mut G where G : Data {}", 1351 "impl <> Data for & \'a mut G where G : Data {}",
1422 ); 1352 );
1423} 1353}
1424 1354
1425pub(crate) fn create_rules(macro_definition: &str) -> MacroRules { 1355#[test]
1426 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); 1356fn expr_interpolation() {
1427 let macro_definition = 1357 let expanded = parse_macro(
1428 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 1358 r#"
1359 macro_rules! id {
1360 ($expr:expr) => {
1361 map($expr)
1362 }
1363 }
1364 "#,
1365 )
1366 .expand_expr("id!(x + foo);");
1429 1367
1430 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 1368 assert_eq!(expanded.to_string(), "map(x+foo)");
1431 crate::MacroRules::parse(&definition_tt).unwrap()
1432} 1369}
1433 1370
1434pub(crate) fn expand(rules: &MacroRules, invocation: &str) -> tt::Subtree { 1371pub(crate) struct MacroFixture {
1435 let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); 1372 rules: MacroRules,
1436 let macro_invocation = 1373}
1437 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1438 1374
1439 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap(); 1375impl MacroFixture {
1376 pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree {
1377 let source_file = ast::SourceFile::parse(invocation).ok().unwrap();
1378 let macro_invocation =
1379 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1440 1380
1441 rules.expand(&invocation_tt).unwrap() 1381 let (invocation_tt, _) =
1442} 1382 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
1443 1383
1444pub(crate) enum MacroKind { 1384 self.rules.expand(&invocation_tt).unwrap()
1445 Items, 1385 }
1446 Stmts,
1447}
1448 1386
1449pub(crate) fn assert_expansion( 1387 fn expand_items(&self, invocation: &str) -> SyntaxNode {
1450 kind: MacroKind, 1388 let expanded = self.expand_tt(invocation);
1451 rules: &MacroRules, 1389 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node()
1452 invocation: &str, 1390 }
1453 expected: &str,
1454) -> tt::Subtree {
1455 let expanded = expand(rules, invocation);
1456 assert_eq!(expanded.to_string(), expected);
1457 1391
1458 let expected = expected.replace("$crate", "C_C__C"); 1392 fn expand_statements(&self, invocation: &str) -> SyntaxNode {
1393 let expanded = self.expand_tt(invocation);
1394 token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node()
1395 }
1459 1396
1460 // wrap the given text to a macro call 1397 fn expand_expr(&self, invocation: &str) -> SyntaxNode {
1461 let expected = { 1398 let expanded = self.expand_tt(invocation);
1462 let wrapped = format!("wrap_macro!( {} )", expected); 1399 token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node()
1463 let wrapped = ast::SourceFile::parse(&wrapped); 1400 }
1464 let wrapped = wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1465 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1466 wrapped.delimiter = tt::Delimiter::None;
1467 wrapped
1468 };
1469 let (expanded_tree, expected_tree) = match kind {
1470 MacroKind::Items => {
1471 let expanded_tree =
1472 token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node();
1473 let expected_tree =
1474 token_tree_to_syntax_node(&expected, FragmentKind::Items).unwrap().0.syntax_node();
1475
1476 (
1477 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1478 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1479 )
1480 }
1481 1401
1482 MacroKind::Stmts => { 1402 fn assert_expand_tt(&self, invocation: &str, expected: &str) {
1483 let expanded_tree = token_tree_to_syntax_node(&expanded, FragmentKind::Statements) 1403 let expansion = self.expand_tt(invocation);
1484 .unwrap() 1404 assert_eq!(expansion.to_string(), expected);
1485 .0 1405 }
1486 .syntax_node();
1487 let expected_tree = token_tree_to_syntax_node(&expected, FragmentKind::Statements)
1488 .unwrap()
1489 .0
1490 .syntax_node();
1491
1492 (
1493 debug_dump_ignore_spaces(&expanded_tree).trim().to_string(),
1494 debug_dump_ignore_spaces(&expected_tree).trim().to_string(),
1495 )
1496 }
1497 };
1498 1406
1499 let expected_tree = expected_tree.replace("C_C__C", "$crate"); 1407 fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture {
1500 assert_eq!( 1408 self.assert_expansion(FragmentKind::Items, invocation, expected);
1501 expanded_tree, expected_tree, 1409 self
1502 "\nleft:\n{}\nright:\n{}", 1410 }
1503 expanded_tree, expected_tree, 1411
1504 ); 1412 fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture {
1413 self.assert_expansion(FragmentKind::Statements, invocation, expected);
1414 self
1415 }
1505 1416
1506 expanded 1417 fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) {
1418 let expanded = self.expand_tt(invocation);
1419 assert_eq!(expanded.to_string(), expected);
1420
1421 let expected = expected.replace("$crate", "C_C__C");
1422
1423 // wrap the given text to a macro call
1424 let expected = {
1425 let wrapped = format!("wrap_macro!( {} )", expected);
1426 let wrapped = ast::SourceFile::parse(&wrapped);
1427 let wrapped =
1428 wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
1429 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0;
1430 wrapped.delimiter = None;
1431 wrapped
1432 };
1433
1434 let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node();
1435 let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string();
1436
1437 let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node();
1438 let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string();
1439
1440 let expected_tree = expected_tree.replace("C_C__C", "$crate");
1441 assert_eq!(
1442 expanded_tree, expected_tree,
1443 "\nleft:\n{}\nright:\n{}",
1444 expanded_tree, expected_tree,
1445 );
1446 }
1507} 1447}
1508 1448
1509pub fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String { 1449pub(crate) fn parse_macro(macro_definition: &str) -> MacroFixture {
1510 use std::fmt::Write; 1450 let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap();
1451 let macro_definition =
1452 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
1453
1454 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
1455 let rules = MacroRules::parse(&definition_tt).unwrap();
1456 MacroFixture { rules }
1457}
1511 1458
1459fn debug_dump_ignore_spaces(node: &ra_syntax::SyntaxNode) -> String {
1512 let mut level = 0; 1460 let mut level = 0;
1513 let mut buf = String::new(); 1461 let mut buf = String::new();
1514 macro_rules! indent { 1462 macro_rules! indent {
diff --git a/crates/ra_parser/src/grammar.rs b/crates/ra_parser/src/grammar.rs
index 6e9e212b7..22f64a9f4 100644
--- a/crates/ra_parser/src/grammar.rs
+++ b/crates/ra_parser/src/grammar.rs
@@ -264,7 +264,7 @@ fn name_r(p: &mut Parser, recovery: TokenSet) {
264} 264}
265 265
266fn name(p: &mut Parser) { 266fn name(p: &mut Parser) {
267 name_r(p, TokenSet::empty()) 267 name_r(p, TokenSet::EMPTY)
268} 268}
269 269
270fn name_ref(p: &mut Parser) { 270fn name_ref(p: &mut Parser) {
diff --git a/crates/ra_parser/src/grammar/expressions/atom.rs b/crates/ra_parser/src/grammar/expressions/atom.rs
index f06191963..4ac1d6334 100644
--- a/crates/ra_parser/src/grammar/expressions/atom.rs
+++ b/crates/ra_parser/src/grammar/expressions/atom.rs
@@ -43,6 +43,7 @@ pub(super) const ATOM_EXPR_FIRST: TokenSet =
43 T!['('], 43 T!['('],
44 T!['{'], 44 T!['{'],
45 T!['['], 45 T!['['],
46 L_DOLLAR,
46 T![|], 47 T![|],
47 T![move], 48 T![move],
48 T![box], 49 T![box],
@@ -248,7 +249,12 @@ fn lambda_expr(p: &mut Parser) -> CompletedMarker {
248 p.error("expected `{`"); 249 p.error("expected `{`");
249 } 250 }
250 } 251 }
251 expr(p); 252
253 if p.at_ts(EXPR_FIRST) {
254 expr(p);
255 } else {
256 p.error("expected expression");
257 }
252 m.complete(p, LAMBDA_EXPR) 258 m.complete(p, LAMBDA_EXPR)
253} 259}
254 260
@@ -438,7 +444,7 @@ fn match_arm(p: &mut Parser) -> BlockLike {
438 // } 444 // }
439 attributes::outer_attributes(p); 445 attributes::outer_attributes(p);
440 446
441 patterns::pattern_list_r(p, TokenSet::empty()); 447 patterns::pattern_list_r(p, TokenSet::EMPTY);
442 if p.at(T![if]) { 448 if p.at(T![if]) {
443 match_guard(p); 449 match_guard(p);
444 } 450 }
diff --git a/crates/ra_parser/src/grammar/items.rs b/crates/ra_parser/src/grammar/items.rs
index 370990e21..6e23d9b72 100644
--- a/crates/ra_parser/src/grammar/items.rs
+++ b/crates/ra_parser/src/grammar/items.rs
@@ -33,7 +33,7 @@ pub(super) enum ItemFlavor {
33 33
34pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![ 34pub(super) const ITEM_RECOVERY_SET: TokenSet = token_set![
35 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW, 35 FN_KW, STRUCT_KW, ENUM_KW, IMPL_KW, TRAIT_KW, CONST_KW, STATIC_KW, LET_KW, MOD_KW, PUB_KW,
36 CRATE_KW, USE_KW 36 CRATE_KW, USE_KW, MACRO_KW
37]; 37];
38 38
39pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) { 39pub(super) fn item_or_macro(p: &mut Parser, stop_on_r_curly: bool, flavor: ItemFlavor) {
@@ -249,6 +249,11 @@ fn items_without_modifiers(p: &mut Parser, m: Marker) -> Result<(), Marker> {
249 // } 249 // }
250 adt::struct_def(p, m); 250 adt::struct_def(p, m);
251 } 251 }
252 // test pub_macro_def
253 // pub macro m($:ident) {}
254 T![macro] => {
255 macro_def(p, m);
256 }
252 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => { 257 IDENT if p.at_contextual_kw("union") && p.nth(1) == IDENT => {
253 // test union_items 258 // test union_items
254 // union Foo {} 259 // union Foo {}
@@ -379,6 +384,29 @@ pub(crate) fn mod_item_list(p: &mut Parser) {
379 m.complete(p, ITEM_LIST); 384 m.complete(p, ITEM_LIST);
380} 385}
381 386
387// test macro_def
388// macro m { ($i:ident) => {} }
389// macro m($i:ident) {}
390fn macro_def(p: &mut Parser, m: Marker) {
391 p.expect(T![macro]);
392 name_r(p, ITEM_RECOVERY_SET);
393 if p.at(T!['{']) {
394 token_tree(p);
395 } else if !p.at(T!['(']) {
396 p.error("unmatched `(`");
397 } else {
398 let m = p.start();
399 token_tree(p);
400 match p.current() {
401 T!['{'] | T!['['] | T!['('] => token_tree(p),
402 _ => p.error("expected `{`, `[`, `(`"),
403 }
404 m.complete(p, TOKEN_TREE);
405 }
406
407 m.complete(p, MACRO_DEF);
408}
409
382fn macro_call(p: &mut Parser) -> BlockLike { 410fn macro_call(p: &mut Parser) -> BlockLike {
383 assert!(paths::is_use_path_start(p)); 411 assert!(paths::is_use_path_start(p));
384 paths::use_path(p); 412 paths::use_path(p);
diff --git a/crates/ra_parser/src/grammar/patterns.rs b/crates/ra_parser/src/grammar/patterns.rs
index f5d12278c..422a4e3dc 100644
--- a/crates/ra_parser/src/grammar/patterns.rs
+++ b/crates/ra_parser/src/grammar/patterns.rs
@@ -50,7 +50,7 @@ pub(super) fn pattern_r(p: &mut Parser, recovery_set: TokenSet) {
50 // let m!(x) = 0; 50 // let m!(x) = 0;
51 // } 51 // }
52 if lhs.kind() == PATH_PAT && p.at(T![!]) { 52 if lhs.kind() == PATH_PAT && p.at(T![!]) {
53 let m = lhs.precede(p); 53 let m = lhs.undo_completion(p);
54 items::macro_call_after_excl(p); 54 items::macro_call_after_excl(p);
55 m.complete(p, MACRO_CALL); 55 m.complete(p, MACRO_CALL);
56 } 56 }
diff --git a/crates/ra_parser/src/grammar/type_params.rs b/crates/ra_parser/src/grammar/type_params.rs
index 34406b5bd..50e4900c3 100644
--- a/crates/ra_parser/src/grammar/type_params.rs
+++ b/crates/ra_parser/src/grammar/type_params.rs
@@ -25,6 +25,7 @@ fn type_param_list(p: &mut Parser) {
25 match p.current() { 25 match p.current() {
26 LIFETIME => lifetime_param(p, m), 26 LIFETIME => lifetime_param(p, m),
27 IDENT => type_param(p, m), 27 IDENT => type_param(p, m),
28 CONST_KW => type_const_param(p, m),
28 _ => { 29 _ => {
29 m.abandon(p); 30 m.abandon(p);
30 p.err_and_bump("expected type parameter") 31 p.err_and_bump("expected type parameter")
@@ -62,6 +63,16 @@ fn type_param(p: &mut Parser, m: Marker) {
62 m.complete(p, TYPE_PARAM); 63 m.complete(p, TYPE_PARAM);
63} 64}
64 65
66// test const_param
67// struct S<const N: u32>;
68fn type_const_param(p: &mut Parser, m: Marker) {
69 assert!(p.at(CONST_KW));
70 p.bump(T![const]);
71 name(p);
72 types::ascription(p);
73 m.complete(p, CONST_PARAM);
74}
75
65// test type_param_bounds 76// test type_param_bounds
66// struct S<T: 'a + ?Sized + (Copy)>; 77// struct S<T: 'a + ?Sized + (Copy)>;
67pub(super) fn bounds(p: &mut Parser) { 78pub(super) fn bounds(p: &mut Parser) {
diff --git a/crates/ra_parser/src/lib.rs b/crates/ra_parser/src/lib.rs
index 45241e566..65134277e 100644
--- a/crates/ra_parser/src/lib.rs
+++ b/crates/ra_parser/src/lib.rs
@@ -83,6 +83,7 @@ pub fn parse(token_source: &mut dyn TokenSource, tree_sink: &mut dyn TreeSink) {
83 parse_from_tokens(token_source, tree_sink, grammar::root); 83 parse_from_tokens(token_source, tree_sink, grammar::root);
84} 84}
85 85
86#[derive(Clone, Copy)]
86pub enum FragmentKind { 87pub enum FragmentKind {
87 Path, 88 Path,
88 Expr, 89 Expr,
diff --git a/crates/ra_parser/src/parser.rs b/crates/ra_parser/src/parser.rs
index dafd5247b..1071c46dc 100644
--- a/crates/ra_parser/src/parser.rs
+++ b/crates/ra_parser/src/parser.rs
@@ -208,7 +208,7 @@ impl<'t> Parser<'t> {
208 208
209 /// Create an error node and consume the next token. 209 /// Create an error node and consume the next token.
210 pub(crate) fn err_and_bump(&mut self, message: &str) { 210 pub(crate) fn err_and_bump(&mut self, message: &str) {
211 self.err_recover(message, TokenSet::empty()); 211 self.err_recover(message, TokenSet::EMPTY);
212 } 212 }
213 213
214 /// Create an error node and consume the next token. 214 /// Create an error node and consume the next token.
diff --git a/crates/ra_parser/src/syntax_kind/generated.rs b/crates/ra_parser/src/syntax_kind/generated.rs
index fe0fcdb33..af2945f57 100644
--- a/crates/ra_parser/src/syntax_kind/generated.rs
+++ b/crates/ra_parser/src/syntax_kind/generated.rs
@@ -100,6 +100,7 @@ pub enum SyntaxKind {
100 TRY_KW, 100 TRY_KW,
101 BOX_KW, 101 BOX_KW,
102 AWAIT_KW, 102 AWAIT_KW,
103 MACRO_KW,
103 AUTO_KW, 104 AUTO_KW,
104 DEFAULT_KW, 105 DEFAULT_KW,
105 EXISTENTIAL_KW, 106 EXISTENTIAL_KW,
@@ -136,6 +137,7 @@ pub enum SyntaxKind {
136 TYPE_ALIAS_DEF, 137 TYPE_ALIAS_DEF,
137 MACRO_CALL, 138 MACRO_CALL,
138 TOKEN_TREE, 139 TOKEN_TREE,
140 MACRO_DEF,
139 PAREN_TYPE, 141 PAREN_TYPE,
140 TUPLE_TYPE, 142 TUPLE_TYPE,
141 NEVER_TYPE, 143 NEVER_TYPE,
@@ -227,6 +229,7 @@ pub enum SyntaxKind {
227 TYPE_PARAM_LIST, 229 TYPE_PARAM_LIST,
228 LIFETIME_PARAM, 230 LIFETIME_PARAM,
229 TYPE_PARAM, 231 TYPE_PARAM,
232 CONST_PARAM,
230 TYPE_ARG_LIST, 233 TYPE_ARG_LIST,
231 LIFETIME_ARG, 234 LIFETIME_ARG,
232 TYPE_ARG, 235 TYPE_ARG,
@@ -251,7 +254,7 @@ impl SyntaxKind {
251 | SUPER_KW | IN_KW | WHERE_KW | FOR_KW | LOOP_KW | WHILE_KW | CONTINUE_KW 254 | SUPER_KW | IN_KW | WHERE_KW | FOR_KW | LOOP_KW | WHILE_KW | CONTINUE_KW
252 | BREAK_KW | IF_KW | ELSE_KW | MATCH_KW | CONST_KW | STATIC_KW | MUT_KW | UNSAFE_KW 255 | BREAK_KW | IF_KW | ELSE_KW | MATCH_KW | CONST_KW | STATIC_KW | MUT_KW | UNSAFE_KW
253 | TYPE_KW | REF_KW | LET_KW | MOVE_KW | RETURN_KW | TRY_KW | BOX_KW | AWAIT_KW 256 | TYPE_KW | REF_KW | LET_KW | MOVE_KW | RETURN_KW | TRY_KW | BOX_KW | AWAIT_KW
254 | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true, 257 | MACRO_KW | AUTO_KW | DEFAULT_KW | EXISTENTIAL_KW | UNION_KW => true,
255 _ => false, 258 _ => false,
256 } 259 }
257 } 260 }
@@ -314,6 +317,7 @@ impl SyntaxKind {
314 "try" => TRY_KW, 317 "try" => TRY_KW,
315 "box" => BOX_KW, 318 "box" => BOX_KW,
316 "await" => AWAIT_KW, 319 "await" => AWAIT_KW,
320 "macro" => MACRO_KW,
317 _ => return None, 321 _ => return None,
318 }; 322 };
319 Some(kw) 323 Some(kw)
@@ -628,6 +632,9 @@ macro_rules! T {
628 ( await ) => { 632 ( await ) => {
629 $crate::SyntaxKind::AWAIT_KW 633 $crate::SyntaxKind::AWAIT_KW
630 }; 634 };
635 ( macro ) => {
636 $crate::SyntaxKind::MACRO_KW
637 };
631 ( auto ) => { 638 ( auto ) => {
632 $crate::SyntaxKind::AUTO_KW 639 $crate::SyntaxKind::AUTO_KW
633 }; 640 };
diff --git a/crates/ra_parser/src/token_set.rs b/crates/ra_parser/src/token_set.rs
index 2a6952c01..994017acf 100644
--- a/crates/ra_parser/src/token_set.rs
+++ b/crates/ra_parser/src/token_set.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! A bit-set of `SyntaxKind`s.
2 2
3use crate::SyntaxKind; 3use crate::SyntaxKind;
4 4
@@ -7,9 +7,7 @@ use crate::SyntaxKind;
7pub(crate) struct TokenSet(u128); 7pub(crate) struct TokenSet(u128);
8 8
9impl TokenSet { 9impl TokenSet {
10 pub(crate) const fn empty() -> TokenSet { 10 pub(crate) const EMPTY: TokenSet = TokenSet(0);
11 TokenSet(0)
12 }
13 11
14 pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet { 12 pub(crate) const fn singleton(kind: SyntaxKind) -> TokenSet {
15 TokenSet(mask(kind)) 13 TokenSet(mask(kind))
@@ -30,7 +28,7 @@ const fn mask(kind: SyntaxKind) -> u128 {
30 28
31#[macro_export] 29#[macro_export]
32macro_rules! token_set { 30macro_rules! token_set {
33 ($($t:expr),*) => { TokenSet::empty()$(.union(TokenSet::singleton($t)))* }; 31 ($($t:expr),*) => { TokenSet::EMPTY$(.union(TokenSet::singleton($t)))* };
34 ($($t:expr),* ,) => { token_set!($($t),*) }; 32 ($($t:expr),* ,) => { token_set!($($t),*) };
35} 33}
36 34
diff --git a/crates/ra_prof/src/lib.rs b/crates/ra_prof/src/lib.rs
index 845b2221c..f260c40a3 100644
--- a/crates/ra_prof/src/lib.rs
+++ b/crates/ra_prof/src/lib.rs
@@ -217,7 +217,7 @@ fn print(
217 total: Option<Duration>, 217 total: Option<Duration>,
218) { 218) {
219 let mut last = 0; 219 let mut last = 0;
220 let indent = repeat(" ").take(lvl + 1).collect::<String>(); 220 let indent = repeat(" ").take(lvl).collect::<String>();
221 // We output hierarchy for long calls, but sum up all short calls 221 // We output hierarchy for long calls, but sum up all short calls
222 let mut short = Vec::new(); 222 let mut short = Vec::new();
223 let mut accounted_for = Duration::default(); 223 let mut accounted_for = Duration::default();
@@ -227,7 +227,7 @@ fn print(
227 } 227 }
228 accounted_for += duration; 228 accounted_for += duration;
229 if duration >= longer_than { 229 if duration >= longer_than {
230 writeln!(out, "{} {:6}ms - {}", indent, duration.as_millis(), msg) 230 writeln!(out, "{}{:5}ms - {}", indent, duration.as_millis(), msg)
231 .expect("printing profiling info to stdout"); 231 .expect("printing profiling info to stdout");
232 232
233 print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration)); 233 print(lvl + 1, &msgs[last..i], out, longer_than, Some(duration));
@@ -245,14 +245,14 @@ fn print(
245 count += 1; 245 count += 1;
246 total_duration += *time; 246 total_duration += *time;
247 }); 247 });
248 writeln!(out, "{} {:6}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count) 248 writeln!(out, "{}{:5}ms - {} ({} calls)", indent, total_duration.as_millis(), msg, count)
249 .expect("printing profiling info to stdout"); 249 .expect("printing profiling info to stdout");
250 } 250 }
251 251
252 if let Some(total) = total { 252 if let Some(total) = total {
253 if let Some(unaccounted) = total.checked_sub(accounted_for) { 253 if let Some(unaccounted) = total.checked_sub(accounted_for) {
254 if unaccounted >= longer_than && last > 0 { 254 if unaccounted >= longer_than && last > 0 {
255 writeln!(out, "{} {:6}ms - ???", indent, unaccounted.as_millis()) 255 writeln!(out, "{}{:5}ms - ???", indent, unaccounted.as_millis())
256 .expect("printing profiling info to stdout"); 256 .expect("printing profiling info to stdout");
257 } 257 }
258 } 258 }
diff --git a/crates/ra_project_model/src/cargo_workspace.rs b/crates/ra_project_model/src/cargo_workspace.rs
index 351997dcd..c862d3912 100644
--- a/crates/ra_project_model/src/cargo_workspace.rs
+++ b/crates/ra_project_model/src/cargo_workspace.rs
@@ -6,6 +6,7 @@ use cargo_metadata::{CargoOpt, MetadataCommand};
6use ra_arena::{impl_arena_id, Arena, RawId}; 6use ra_arena::{impl_arena_id, Arena, RawId};
7use ra_db::Edition; 7use ra_db::Edition;
8use rustc_hash::FxHashMap; 8use rustc_hash::FxHashMap;
9use serde::Deserialize;
9 10
10use crate::Result; 11use crate::Result;
11 12
@@ -23,6 +24,26 @@ pub struct CargoWorkspace {
23 pub(crate) workspace_root: PathBuf, 24 pub(crate) workspace_root: PathBuf,
24} 25}
25 26
27#[derive(Deserialize, Clone, Debug, PartialEq, Eq)]
28#[serde(rename_all = "camelCase", default)]
29pub struct CargoFeatures {
30 /// Do not activate the `default` feature.
31 pub no_default_features: bool,
32
33 /// Activate all available features
34 pub all_features: bool,
35
36 /// List of features to activate.
37 /// This will be ignored if `cargo_all_features` is true.
38 pub features: Vec<String>,
39}
40
41impl Default for CargoFeatures {
42 fn default() -> Self {
43 CargoFeatures { no_default_features: false, all_features: true, features: Vec::new() }
44 }
45}
46
26#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] 47#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
27pub struct Package(RawId); 48pub struct Package(RawId);
28impl_arena_id!(Package); 49impl_arena_id!(Package);
@@ -132,9 +153,21 @@ impl Target {
132} 153}
133 154
134impl CargoWorkspace { 155impl CargoWorkspace {
135 pub fn from_cargo_metadata(cargo_toml: &Path) -> Result<CargoWorkspace> { 156 pub fn from_cargo_metadata(
157 cargo_toml: &Path,
158 cargo_features: &CargoFeatures,
159 ) -> Result<CargoWorkspace> {
136 let mut meta = MetadataCommand::new(); 160 let mut meta = MetadataCommand::new();
137 meta.manifest_path(cargo_toml).features(CargoOpt::AllFeatures); 161 meta.manifest_path(cargo_toml);
162 if cargo_features.all_features {
163 meta.features(CargoOpt::AllFeatures);
164 } else if cargo_features.no_default_features {
165 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
166 // https://github.com/oli-obk/cargo_metadata/issues/79
167 meta.features(CargoOpt::NoDefaultFeatures);
168 } else {
169 meta.features(CargoOpt::SomeFeatures(cargo_features.features.clone()));
170 }
138 if let Some(parent) = cargo_toml.parent() { 171 if let Some(parent) = cargo_toml.parent() {
139 meta.current_dir(parent); 172 meta.current_dir(parent);
140 } 173 }
diff --git a/crates/ra_project_model/src/lib.rs b/crates/ra_project_model/src/lib.rs
index 55ff4d6ef..d71b7031a 100644
--- a/crates/ra_project_model/src/lib.rs
+++ b/crates/ra_project_model/src/lib.rs
@@ -18,7 +18,7 @@ use rustc_hash::FxHashMap;
18use serde_json::from_reader; 18use serde_json::from_reader;
19 19
20pub use crate::{ 20pub use crate::{
21 cargo_workspace::{CargoWorkspace, Package, Target, TargetKind}, 21 cargo_workspace::{CargoFeatures, CargoWorkspace, Package, Target, TargetKind},
22 json_project::JsonProject, 22 json_project::JsonProject,
23 sysroot::Sysroot, 23 sysroot::Sysroot,
24}; 24};
@@ -60,11 +60,15 @@ impl PackageRoot {
60} 60}
61 61
62impl ProjectWorkspace { 62impl ProjectWorkspace {
63 pub fn discover(path: &Path) -> Result<ProjectWorkspace> { 63 pub fn discover(path: &Path, cargo_features: &CargoFeatures) -> Result<ProjectWorkspace> {
64 ProjectWorkspace::discover_with_sysroot(path, true) 64 ProjectWorkspace::discover_with_sysroot(path, true, cargo_features)
65 } 65 }
66 66
67 pub fn discover_with_sysroot(path: &Path, with_sysroot: bool) -> Result<ProjectWorkspace> { 67 pub fn discover_with_sysroot(
68 path: &Path,
69 with_sysroot: bool,
70 cargo_features: &CargoFeatures,
71 ) -> Result<ProjectWorkspace> {
68 match find_rust_project_json(path) { 72 match find_rust_project_json(path) {
69 Some(json_path) => { 73 Some(json_path) => {
70 let file = File::open(json_path)?; 74 let file = File::open(json_path)?;
@@ -73,7 +77,7 @@ impl ProjectWorkspace {
73 } 77 }
74 None => { 78 None => {
75 let cargo_toml = find_cargo_toml(path)?; 79 let cargo_toml = find_cargo_toml(path)?;
76 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml)?; 80 let cargo = CargoWorkspace::from_cargo_metadata(&cargo_toml, cargo_features)?;
77 let sysroot = 81 let sysroot =
78 if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() }; 82 if with_sysroot { Sysroot::discover(&cargo_toml)? } else { Sysroot::default() };
79 Ok(ProjectWorkspace::Cargo { cargo, sysroot }) 83 Ok(ProjectWorkspace::Cargo { cargo, sysroot })
diff --git a/crates/ra_syntax/Cargo.toml b/crates/ra_syntax/Cargo.toml
index 5db2b58c0..b6ebb129d 100644
--- a/crates/ra_syntax/Cargo.toml
+++ b/crates/ra_syntax/Cargo.toml
@@ -12,19 +12,20 @@ doctest = false
12 12
13[dependencies] 13[dependencies]
14itertools = "0.8.0" 14itertools = "0.8.0"
15rowan = "0.7.0" 15rowan = "0.8.0"
16rustc_lexer = "0.1.0" 16rustc_lexer = "0.1.0"
17rustc-hash = "1.0.1" 17rustc-hash = "1.0.1"
18arrayvec = "0.5.1" 18arrayvec = "0.5.1"
19once_cell = "1.2.0" 19once_cell = "1.2.0"
20 20
21ra_text_edit = { path = "../ra_text_edit" }
22ra_parser = { path = "../ra_parser" }
23
21# This crate transitively depends on `smol_str` via `rowan`. 24# This crate transitively depends on `smol_str` via `rowan`.
22# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here 25# ideally, `serde` should be enabled by `ra_lsp_server`, but we enable it here
23# to reduce number of compilations 26# to reduce number of compilations
24smol_str = { version = "0.1.12", features = ["serde"] } 27smol_str = { version = "0.1.12", features = ["serde"] }
25 28serde = { version = "1", features = ["derive"] }
26ra_text_edit = { path = "../ra_text_edit" }
27ra_parser = { path = "../ra_parser" }
28 29
29[dev-dependencies] 30[dev-dependencies]
30test_utils = { path = "../test_utils" } 31test_utils = { path = "../test_utils" }
diff --git a/crates/ra_syntax/src/algo.rs b/crates/ra_syntax/src/algo.rs
index 1c075082a..e4061e994 100644
--- a/crates/ra_syntax/src/algo.rs
+++ b/crates/ra_syntax/src/algo.rs
@@ -140,13 +140,13 @@ pub fn insert_children(
140 }); 140 });
141 141
142 let new_children = match &position { 142 let new_children = match &position {
143 InsertPosition::First => to_insert.chain(old_children).collect::<Box<[_]>>(), 143 InsertPosition::First => to_insert.chain(old_children).collect::<Vec<_>>(),
144 InsertPosition::Last => old_children.chain(to_insert).collect::<Box<[_]>>(), 144 InsertPosition::Last => old_children.chain(to_insert).collect::<Vec<_>>(),
145 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => { 145 InsertPosition::Before(anchor) | InsertPosition::After(anchor) => {
146 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 }; 146 let take_anchor = if let InsertPosition::After(_) = position { 1 } else { 0 };
147 let split_at = position_of_child(parent, anchor.clone()) + take_anchor; 147 let split_at = position_of_child(parent, anchor.clone()) + take_anchor;
148 let before = old_children.by_ref().take(split_at).collect::<Vec<_>>(); 148 let before = old_children.by_ref().take(split_at).collect::<Vec<_>>();
149 before.into_iter().chain(to_insert).chain(old_children).collect::<Box<[_]>>() 149 before.into_iter().chain(to_insert).chain(old_children).collect::<Vec<_>>()
150 } 150 }
151 }; 151 };
152 152
@@ -174,7 +174,7 @@ pub fn replace_children(
174 .into_iter() 174 .into_iter()
175 .chain(to_insert.map(to_green_element)) 175 .chain(to_insert.map(to_green_element))
176 .chain(old_children.skip(end + 1 - start)) 176 .chain(old_children.skip(end + 1 - start))
177 .collect::<Box<[_]>>(); 177 .collect::<Vec<_>>();
178 with_children(parent, new_children) 178 with_children(parent, new_children)
179} 179}
180 180
@@ -187,7 +187,7 @@ pub fn replace_descendants(
187 map: &FxHashMap<SyntaxElement, SyntaxElement>, 187 map: &FxHashMap<SyntaxElement, SyntaxElement>,
188) -> SyntaxNode { 188) -> SyntaxNode {
189 // FIXME: this could be made much faster. 189 // FIXME: this could be made much faster.
190 let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Box<[_]>>(); 190 let new_children = parent.children_with_tokens().map(|it| go(map, it)).collect::<Vec<_>>();
191 return with_children(parent, new_children); 191 return with_children(parent, new_children);
192 192
193 fn go( 193 fn go(
@@ -211,7 +211,7 @@ pub fn replace_descendants(
211 211
212fn with_children( 212fn with_children(
213 parent: &SyntaxNode, 213 parent: &SyntaxNode,
214 new_children: Box<[NodeOrToken<rowan::GreenNode, rowan::GreenToken>]>, 214 new_children: Vec<NodeOrToken<rowan::GreenNode, rowan::GreenToken>>,
215) -> SyntaxNode { 215) -> SyntaxNode {
216 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>(); 216 let len = new_children.iter().map(|it| it.text_len()).sum::<TextUnit>();
217 let new_node = 217 let new_node =
diff --git a/crates/ra_syntax/src/ast/edit.rs b/crates/ra_syntax/src/ast/edit.rs
index 95bf9db14..ae5d63927 100644
--- a/crates/ra_syntax/src/ast/edit.rs
+++ b/crates/ra_syntax/src/ast/edit.rs
@@ -104,7 +104,7 @@ impl ast::ItemList {
104 } 104 }
105 }; 105 };
106 106
107 let indent = leading_indent(self.syntax()).unwrap_or("".into()); 107 let indent = leading_indent(self.syntax()).unwrap_or_default();
108 let ws = tokens::WsBuilder::new(&format!("\n{}", indent)); 108 let ws = tokens::WsBuilder::new(&format!("\n{}", indent));
109 let to_insert = iter::once(ws.ws().into()); 109 let to_insert = iter::once(ws.ws().into());
110 match existing_ws { 110 match existing_ws {
@@ -133,7 +133,7 @@ impl ast::RecordFieldList {
133 let space = if is_multiline { 133 let space = if is_multiline {
134 ws = tokens::WsBuilder::new(&format!( 134 ws = tokens::WsBuilder::new(&format!(
135 "\n{} ", 135 "\n{} ",
136 leading_indent(self.syntax()).unwrap_or("".into()) 136 leading_indent(self.syntax()).unwrap_or_default()
137 )); 137 ));
138 ws.ws() 138 ws.ws()
139 } else { 139 } else {
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index c06076e3d..9f9d6e63c 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -312,6 +312,7 @@ impl AstNode for Block {
312 } 312 }
313} 313}
314impl ast::AttrsOwner for Block {} 314impl ast::AttrsOwner for Block {}
315impl ast::ModuleItemOwner for Block {}
315impl Block { 316impl Block {
316 pub fn statements(&self) -> AstChildren<Stmt> { 317 pub fn statements(&self) -> AstChildren<Stmt> {
317 AstChildren::new(&self.syntax) 318 AstChildren::new(&self.syntax)
@@ -550,6 +551,36 @@ impl ConstDef {
550 } 551 }
551} 552}
552#[derive(Debug, Clone, PartialEq, Eq, Hash)] 553#[derive(Debug, Clone, PartialEq, Eq, Hash)]
554pub struct ConstParam {
555 pub(crate) syntax: SyntaxNode,
556}
557impl AstNode for ConstParam {
558 fn can_cast(kind: SyntaxKind) -> bool {
559 match kind {
560 CONST_PARAM => true,
561 _ => false,
562 }
563 }
564 fn cast(syntax: SyntaxNode) -> Option<Self> {
565 if Self::can_cast(syntax.kind()) {
566 Some(Self { syntax })
567 } else {
568 None
569 }
570 }
571 fn syntax(&self) -> &SyntaxNode {
572 &self.syntax
573 }
574}
575impl ast::NameOwner for ConstParam {}
576impl ast::AttrsOwner for ConstParam {}
577impl ast::TypeAscriptionOwner for ConstParam {}
578impl ConstParam {
579 pub fn default_val(&self) -> Option<Expr> {
580 AstChildren::new(&self.syntax).next()
581 }
582}
583#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub struct ContinueExpr { 584pub struct ContinueExpr {
554 pub(crate) syntax: SyntaxNode, 585 pub(crate) syntax: SyntaxNode,
555} 586}
@@ -1425,6 +1456,9 @@ impl LambdaExpr {
1425 pub fn param_list(&self) -> Option<ParamList> { 1456 pub fn param_list(&self) -> Option<ParamList> {
1426 AstChildren::new(&self.syntax).next() 1457 AstChildren::new(&self.syntax).next()
1427 } 1458 }
1459 pub fn ret_type(&self) -> Option<RetType> {
1460 AstChildren::new(&self.syntax).next()
1461 }
1428 pub fn body(&self) -> Option<Expr> { 1462 pub fn body(&self) -> Option<Expr> {
1429 AstChildren::new(&self.syntax).next() 1463 AstChildren::new(&self.syntax).next()
1430 } 1464 }
diff --git a/crates/ra_syntax/src/ast/make.rs b/crates/ra_syntax/src/ast/make.rs
index 40db570da..04a5408fe 100644
--- a/crates/ra_syntax/src/ast/make.rs
+++ b/crates/ra_syntax/src/ast/make.rs
@@ -168,8 +168,7 @@ pub fn let_stmt(pattern: ast::Pat, initializer: Option<ast::Expr>) -> ast::LetSt
168 168
169fn ast_from_text<N: AstNode>(text: &str) -> N { 169fn ast_from_text<N: AstNode>(text: &str) -> N {
170 let parse = SourceFile::parse(text); 170 let parse = SourceFile::parse(text);
171 let res = parse.tree().syntax().descendants().find_map(N::cast).unwrap(); 171 parse.tree().syntax().descendants().find_map(N::cast).unwrap()
172 res
173} 172}
174 173
175pub mod tokens { 174pub mod tokens {
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index d1be40abe..08aafb610 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -94,7 +94,8 @@ Grammar(
94 "return", 94 "return",
95 "try", 95 "try",
96 "box", 96 "box",
97 "await" 97 "await",
98 "macro"
98 ], 99 ],
99 contextual_keywords: [ 100 contextual_keywords: [
100 "auto", 101 "auto",
@@ -140,6 +141,7 @@ Grammar(
140 "TYPE_ALIAS_DEF", 141 "TYPE_ALIAS_DEF",
141 "MACRO_CALL", 142 "MACRO_CALL",
142 "TOKEN_TREE", 143 "TOKEN_TREE",
144 "MACRO_DEF",
143 145
144 "PAREN_TYPE", 146 "PAREN_TYPE",
145 "TUPLE_TYPE", 147 "TUPLE_TYPE",
@@ -243,6 +245,7 @@ Grammar(
243 "TYPE_PARAM_LIST", 245 "TYPE_PARAM_LIST",
244 "LIFETIME_PARAM", 246 "LIFETIME_PARAM",
245 "TYPE_PARAM", 247 "TYPE_PARAM",
248 "CONST_PARAM",
246 "TYPE_ARG_LIST", 249 "TYPE_ARG_LIST",
247 "LIFETIME_ARG", 250 "LIFETIME_ARG",
248 "TYPE_ARG", 251 "TYPE_ARG",
@@ -426,7 +429,7 @@ Grammar(
426 "PathExpr": (options: ["Path"]), 429 "PathExpr": (options: ["Path"]),
427 "LambdaExpr": ( 430 "LambdaExpr": (
428 options: [ 431 options: [
429 "ParamList", 432 "ParamList", "RetType",
430 ["body", "Expr"], 433 ["body", "Expr"],
431 ] 434 ]
432 ), 435 ),
@@ -602,6 +605,10 @@ Grammar(
602 options: [("default_type", "TypeRef")], 605 options: [("default_type", "TypeRef")],
603 traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"], 606 traits: ["NameOwner", "AttrsOwner", "TypeBoundsOwner"],
604 ), 607 ),
608 "ConstParam": (
609 options: [("default_val", "Expr")],
610 traits: ["NameOwner", "AttrsOwner", "TypeAscriptionOwner"],
611 ),
605 "LifetimeParam": ( 612 "LifetimeParam": (
606 traits: ["AttrsOwner"], 613 traits: ["AttrsOwner"],
607 ), 614 ),
@@ -653,6 +660,7 @@ Grammar(
653 ], 660 ],
654 traits: [ 661 traits: [
655 "AttrsOwner", 662 "AttrsOwner",
663 "ModuleItemOwner",
656 ] 664 ]
657 ), 665 ),
658 "ParamList": ( 666 "ParamList": (
@@ -664,14 +672,14 @@ Grammar(
664 "SelfParam": ( 672 "SelfParam": (
665 traits: [ 673 traits: [
666 "TypeAscriptionOwner", 674 "TypeAscriptionOwner",
667 "AttrsOwner", 675 "AttrsOwner",
668 ] 676 ]
669 ), 677 ),
670 "Param": ( 678 "Param": (
671 options: [ "Pat" ], 679 options: [ "Pat" ],
672 traits: [ 680 traits: [
673 "TypeAscriptionOwner", 681 "TypeAscriptionOwner",
674 "AttrsOwner", 682 "AttrsOwner",
675 ] 683 ]
676 ), 684 ),
677 "UseItem": ( 685 "UseItem": (
diff --git a/crates/ra_syntax/src/ptr.rs b/crates/ra_syntax/src/ptr.rs
index e049fce61..db6230aab 100644
--- a/crates/ra_syntax/src/ptr.rs
+++ b/crates/ra_syntax/src/ptr.rs
@@ -1,6 +1,10 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3use std::{iter::successors, marker::PhantomData}; 3use std::{
4 hash::{Hash, Hasher},
5 iter::successors,
6 marker::PhantomData,
7};
4 8
5use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange}; 9use crate::{AstNode, SyntaxKind, SyntaxNode, TextRange};
6 10
@@ -43,7 +47,7 @@ impl SyntaxNodePtr {
43} 47}
44 48
45/// Like `SyntaxNodePtr`, but remembers the type of node 49/// Like `SyntaxNodePtr`, but remembers the type of node
46#[derive(Debug, Hash)] 50#[derive(Debug)]
47pub struct AstPtr<N: AstNode> { 51pub struct AstPtr<N: AstNode> {
48 raw: SyntaxNodePtr, 52 raw: SyntaxNodePtr,
49 _ty: PhantomData<fn() -> N>, 53 _ty: PhantomData<fn() -> N>,
@@ -64,6 +68,12 @@ impl<N: AstNode> PartialEq for AstPtr<N> {
64 } 68 }
65} 69}
66 70
71impl<N: AstNode> Hash for AstPtr<N> {
72 fn hash<H: Hasher>(&self, state: &mut H) {
73 self.raw.hash(state)
74 }
75}
76
67impl<N: AstNode> AstPtr<N> { 77impl<N: AstNode> AstPtr<N> {
68 pub fn new(node: &N) -> AstPtr<N> { 78 pub fn new(node: &N) -> AstPtr<N> {
69 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData } 79 AstPtr { raw: SyntaxNodePtr::new(node.syntax()), _ty: PhantomData }
diff --git a/crates/ra_syntax/src/syntax_node.rs b/crates/ra_syntax/src/syntax_node.rs
index b2f5b8c64..041c6ea8d 100644
--- a/crates/ra_syntax/src/syntax_node.rs
+++ b/crates/ra_syntax/src/syntax_node.rs
@@ -40,7 +40,7 @@ pub use rowan::{Direction, NodeOrToken};
40 40
41pub struct SyntaxTreeBuilder { 41pub struct SyntaxTreeBuilder {
42 errors: Vec<SyntaxError>, 42 errors: Vec<SyntaxError>,
43 inner: GreenNodeBuilder, 43 inner: GreenNodeBuilder<'static>,
44} 44}
45 45
46impl Default for SyntaxTreeBuilder { 46impl Default for SyntaxTreeBuilder {
diff --git a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt b/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt
deleted file mode 100644
index c5be73a5a..000000000
--- a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.txt
+++ /dev/null
@@ -1,328 +0,0 @@
1SOURCE_FILE@[0; 349)
2 MACRO_CALL@[0; 41)
3 PATH@[0; 5)
4 PATH_SEGMENT@[0; 5)
5 NAME_REF@[0; 5)
6 IDENT@[0; 5) "macro"
7 WHITESPACE@[5; 6) " "
8 NAME@[6; 21)
9 IDENT@[6; 21) "parse_use_trees"
10 TOKEN_TREE@[21; 41)
11 L_PAREN@[21; 22) "("
12 DOLLAR@[22; 23) "$"
13 TOKEN_TREE@[23; 32)
14 L_PAREN@[23; 24) "("
15 DOLLAR@[24; 25) "$"
16 IDENT@[25; 26) "s"
17 COLON@[26; 27) ":"
18 IDENT@[27; 31) "expr"
19 R_PAREN@[31; 32) ")"
20 COMMA@[32; 33) ","
21 STAR@[33; 34) "*"
22 WHITESPACE@[34; 35) " "
23 DOLLAR@[35; 36) "$"
24 TOKEN_TREE@[36; 39)
25 L_PAREN@[36; 37) "("
26 COMMA@[37; 38) ","
27 R_PAREN@[38; 39) ")"
28 STAR@[39; 40) "*"
29 R_PAREN@[40; 41) ")"
30 WHITESPACE@[41; 42) " "
31 ERROR@[42; 93)
32 L_CURLY@[42; 43) "{"
33 WHITESPACE@[43; 48) "\n "
34 MACRO_CALL@[48; 91)
35 PATH@[48; 51)
36 PATH_SEGMENT@[48; 51)
37 NAME_REF@[48; 51)
38 IDENT@[48; 51) "vec"
39 EXCL@[51; 52) "!"
40 TOKEN_TREE@[52; 91)
41 L_BRACK@[52; 53) "["
42 WHITESPACE@[53; 62) "\n "
43 DOLLAR@[62; 63) "$"
44 TOKEN_TREE@[63; 84)
45 L_PAREN@[63; 64) "("
46 IDENT@[64; 78) "parse_use_tree"
47 TOKEN_TREE@[78; 82)
48 L_PAREN@[78; 79) "("
49 DOLLAR@[79; 80) "$"
50 IDENT@[80; 81) "s"
51 R_PAREN@[81; 82) ")"
52 COMMA@[82; 83) ","
53 R_PAREN@[83; 84) ")"
54 STAR@[84; 85) "*"
55 WHITESPACE@[85; 90) "\n "
56 R_BRACK@[90; 91) "]"
57 WHITESPACE@[91; 92) "\n"
58 R_CURLY@[92; 93) "}"
59 WHITESPACE@[93; 95) "\n\n"
60 FN_DEF@[95; 348)
61 ATTR@[95; 102)
62 POUND@[95; 96) "#"
63 L_BRACK@[96; 97) "["
64 PATH@[97; 101)
65 PATH_SEGMENT@[97; 101)
66 NAME_REF@[97; 101)
67 IDENT@[97; 101) "test"
68 R_BRACK@[101; 102) "]"
69 WHITESPACE@[102; 103) "\n"
70 FN_KW@[103; 105) "fn"
71 WHITESPACE@[105; 106) " "
72 NAME@[106; 125)
73 IDENT@[106; 125) "test_use_tree_merge"
74 PARAM_LIST@[125; 127)
75 L_PAREN@[125; 126) "("
76 R_PAREN@[126; 127) ")"
77 WHITESPACE@[127; 128) " "
78 BLOCK_EXPR@[128; 348)
79 BLOCK@[128; 348)
80 L_CURLY@[128; 129) "{"
81 WHITESPACE@[129; 134) "\n "
82 EXPR_STMT@[134; 139)
83 PATH_EXPR@[134; 139)
84 PATH@[134; 139)
85 PATH_SEGMENT@[134; 139)
86 NAME_REF@[134; 139)
87 IDENT@[134; 139) "macro"
88 WHITESPACE@[139; 140) " "
89 EXPR_STMT@[140; 154)
90 CALL_EXPR@[140; 154)
91 PATH_EXPR@[140; 150)
92 PATH@[140; 150)
93 PATH_SEGMENT@[140; 150)
94 NAME_REF@[140; 150)
95 IDENT@[140; 150) "test_merge"
96 ARG_LIST@[150; 154)
97 L_PAREN@[150; 151) "("
98 ARRAY_EXPR@[151; 154)
99 L_BRACK@[151; 152) "["
100 ERROR@[152; 153)
101 DOLLAR@[152; 153) "$"
102 PAREN_EXPR@[153; 154)
103 L_PAREN@[153; 154) "("
104 EXPR_STMT@[154; 155)
105 ERROR@[154; 155)
106 DOLLAR@[154; 155) "$"
107 EXPR_STMT@[155; 160)
108 PATH_EXPR@[155; 160)
109 PATH@[155; 160)
110 PATH_SEGMENT@[155; 160)
111 NAME_REF@[155; 160)
112 IDENT@[155; 160) "input"
113 EXPR_STMT@[160; 161)
114 ERROR@[160; 161)
115 COLON@[160; 161) ":"
116 EXPR_STMT@[161; 165)
117 PATH_EXPR@[161; 165)
118 PATH@[161; 165)
119 PATH_SEGMENT@[161; 165)
120 NAME_REF@[161; 165)
121 IDENT@[161; 165) "expr"
122 EXPR_STMT@[165; 166)
123 ERROR@[165; 166)
124 R_PAREN@[165; 166) ")"
125 EXPR_STMT@[166; 167)
126 ERROR@[166; 167)
127 COMMA@[166; 167) ","
128 EXPR_STMT@[167; 170)
129 PREFIX_EXPR@[167; 170)
130 STAR@[167; 168) "*"
131 WHITESPACE@[168; 169) " "
132 ERROR@[169; 170)
133 DOLLAR@[169; 170) "$"
134 EXPR_STMT@[170; 171)
135 PAREN_EXPR@[170; 171)
136 L_PAREN@[170; 171) "("
137 EXPR_STMT@[171; 172)
138 ERROR@[171; 172)
139 COMMA@[171; 172) ","
140 EXPR_STMT@[172; 173)
141 ERROR@[172; 173)
142 R_PAREN@[172; 173) ")"
143 EXPR_STMT@[173; 175)
144 PREFIX_EXPR@[173; 175)
145 STAR@[173; 174) "*"
146 ERROR@[174; 175)
147 R_BRACK@[174; 175) "]"
148 EXPR_STMT@[175; 176)
149 ERROR@[175; 176)
150 COMMA@[175; 176) ","
151 WHITESPACE@[176; 177) " "
152 EXPR_STMT@[177; 180)
153 ARRAY_EXPR@[177; 180)
154 L_BRACK@[177; 178) "["
155 ERROR@[178; 179)
156 DOLLAR@[178; 179) "$"
157 PAREN_EXPR@[179; 180)
158 L_PAREN@[179; 180) "("
159 EXPR_STMT@[180; 181)
160 ERROR@[180; 181)
161 DOLLAR@[180; 181) "$"
162 EXPR_STMT@[181; 187)
163 PATH_EXPR@[181; 187)
164 PATH@[181; 187)
165 PATH_SEGMENT@[181; 187)
166 NAME_REF@[181; 187)
167 IDENT@[181; 187) "output"
168 EXPR_STMT@[187; 188)
169 ERROR@[187; 188)
170 COLON@[187; 188) ":"
171 EXPR_STMT@[188; 192)
172 PATH_EXPR@[188; 192)
173 PATH@[188; 192)
174 PATH_SEGMENT@[188; 192)
175 NAME_REF@[188; 192)
176 IDENT@[188; 192) "expr"
177 EXPR_STMT@[192; 193)
178 ERROR@[192; 193)
179 R_PAREN@[192; 193) ")"
180 EXPR_STMT@[193; 194)
181 ERROR@[193; 194)
182 COMMA@[193; 194) ","
183 EXPR_STMT@[194; 197)
184 PREFIX_EXPR@[194; 197)
185 STAR@[194; 195) "*"
186 WHITESPACE@[195; 196) " "
187 ERROR@[196; 197)
188 DOLLAR@[196; 197) "$"
189 EXPR_STMT@[197; 198)
190 PAREN_EXPR@[197; 198)
191 L_PAREN@[197; 198) "("
192 EXPR_STMT@[198; 199)
193 ERROR@[198; 199)
194 COMMA@[198; 199) ","
195 EXPR_STMT@[199; 200)
196 ERROR@[199; 200)
197 R_PAREN@[199; 200) ")"
198 EXPR_STMT@[200; 202)
199 PREFIX_EXPR@[200; 202)
200 STAR@[200; 201) "*"
201 ERROR@[201; 202)
202 R_BRACK@[201; 202) "]"
203 EXPR_STMT@[202; 203)
204 ERROR@[202; 203)
205 R_PAREN@[202; 203) ")"
206 WHITESPACE@[203; 204) " "
207 BLOCK_EXPR@[204; 346)
208 BLOCK@[204; 346)
209 L_CURLY@[204; 205) "{"
210 WHITESPACE@[205; 214) "\n "
211 EXPR_STMT@[214; 340)
212 MACRO_CALL@[214; 339)
213 PATH@[214; 223)
214 PATH_SEGMENT@[214; 223)
215 NAME_REF@[214; 223)
216 IDENT@[214; 223) "assert_eq"
217 EXCL@[223; 224) "!"
218 TOKEN_TREE@[224; 339)
219 L_PAREN@[224; 225) "("
220 WHITESPACE@[225; 238) "\n "
221 IDENT@[238; 253) "merge_use_trees"
222 TOKEN_TREE@[253; 284)
223 L_PAREN@[253; 254) "("
224 IDENT@[254; 269) "parse_use_trees"
225 EXCL@[269; 270) "!"
226 TOKEN_TREE@[270; 283)
227 L_PAREN@[270; 271) "("
228 DOLLAR@[271; 272) "$"
229 TOKEN_TREE@[272; 281)
230 L_PAREN@[272; 273) "("
231 DOLLAR@[273; 274) "$"
232 IDENT@[274; 279) "input"
233 COMMA@[279; 280) ","
234 R_PAREN@[280; 281) ")"
235 STAR@[281; 282) "*"
236 R_PAREN@[282; 283) ")"
237 R_PAREN@[283; 284) ")"
238 COMMA@[284; 285) ","
239 WHITESPACE@[285; 298) "\n "
240 IDENT@[298; 313) "parse_use_trees"
241 EXCL@[313; 314) "!"
242 TOKEN_TREE@[314; 328)
243 L_PAREN@[314; 315) "("
244 DOLLAR@[315; 316) "$"
245 TOKEN_TREE@[316; 326)
246 L_PAREN@[316; 317) "("
247 DOLLAR@[317; 318) "$"
248 IDENT@[318; 324) "output"
249 COMMA@[324; 325) ","
250 R_PAREN@[325; 326) ")"
251 STAR@[326; 327) "*"
252 R_PAREN@[327; 328) ")"
253 COMMA@[328; 329) ","
254 WHITESPACE@[329; 338) "\n "
255 R_PAREN@[338; 339) ")"
256 SEMI@[339; 340) ";"
257 WHITESPACE@[340; 345) "\n "
258 R_CURLY@[345; 346) "}"
259 WHITESPACE@[346; 347) "\n"
260 R_CURLY@[347; 348) "}"
261 WHITESPACE@[348; 349) "\n"
262error 5: expected EXCL
263error 41: expected SEMI
264error 42: expected an item
265error 139: expected SEMI
266error 152: expected expression
267error 153: expected COMMA
268error 154: expected expression
269error 154: expected R_PAREN
270error 154: expected COMMA
271error 154: expected expression
272error 154: expected R_BRACK
273error 154: expected COMMA
274error 154: expected SEMI
275error 154: expected expression
276error 155: expected SEMI
277error 160: expected SEMI
278error 160: expected expression
279error 161: expected SEMI
280error 165: expected SEMI
281error 165: expected expression
282error 166: expected SEMI
283error 166: expected expression
284error 167: expected SEMI
285error 169: expected expression
286error 170: expected SEMI
287error 171: expected expression
288error 171: expected R_PAREN
289error 171: expected SEMI
290error 171: expected expression
291error 172: expected SEMI
292error 172: expected expression
293error 173: expected SEMI
294error 174: expected expression
295error 175: expected SEMI
296error 175: expected expression
297error 176: expected SEMI
298error 178: expected expression
299error 179: expected COMMA
300error 180: expected expression
301error 180: expected R_PAREN
302error 180: expected COMMA
303error 180: expected expression
304error 180: expected R_BRACK
305error 180: expected SEMI
306error 180: expected expression
307error 181: expected SEMI
308error 187: expected SEMI
309error 187: expected expression
310error 188: expected SEMI
311error 192: expected SEMI
312error 192: expected expression
313error 193: expected SEMI
314error 193: expected expression
315error 194: expected SEMI
316error 196: expected expression
317error 197: expected SEMI
318error 198: expected expression
319error 198: expected R_PAREN
320error 198: expected SEMI
321error 198: expected expression
322error 199: expected SEMI
323error 199: expected expression
324error 200: expected SEMI
325error 201: expected expression
326error 202: expected SEMI
327error 202: expected expression
328error 203: expected SEMI
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
new file mode 100644
index 000000000..a2f74bd87
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.rs
@@ -0,0 +1,5 @@
1fn foo() -> i32 {
2 [1, 2, 3].iter()
3 .map(|it|)
4 .max::<i32>();
5}
diff --git a/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
new file mode 100644
index 000000000..d1544634c
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/err/0039_lambda_recovery.txt
@@ -0,0 +1,83 @@
1SOURCE_FILE@[0; 83)
2 FN_DEF@[0; 82)
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 RET_TYPE@[9; 15)
12 THIN_ARROW@[9; 11) "->"
13 WHITESPACE@[11; 12) " "
14 PATH_TYPE@[12; 15)
15 PATH@[12; 15)
16 PATH_SEGMENT@[12; 15)
17 NAME_REF@[12; 15)
18 IDENT@[12; 15) "i32"
19 WHITESPACE@[15; 16) " "
20 BLOCK_EXPR@[16; 82)
21 BLOCK@[16; 82)
22 L_CURLY@[16; 17) "{"
23 WHITESPACE@[17; 22) "\n "
24 EXPR_STMT@[22; 80)
25 METHOD_CALL_EXPR@[22; 79)
26 METHOD_CALL_EXPR@[22; 57)
27 METHOD_CALL_EXPR@[22; 38)
28 ARRAY_EXPR@[22; 31)
29 L_BRACK@[22; 23) "["
30 LITERAL@[23; 24)
31 INT_NUMBER@[23; 24) "1"
32 COMMA@[24; 25) ","
33 WHITESPACE@[25; 26) " "
34 LITERAL@[26; 27)
35 INT_NUMBER@[26; 27) "2"
36 COMMA@[27; 28) ","
37 WHITESPACE@[28; 29) " "
38 LITERAL@[29; 30)
39 INT_NUMBER@[29; 30) "3"
40 R_BRACK@[30; 31) "]"
41 DOT@[31; 32) "."
42 NAME_REF@[32; 36)
43 IDENT@[32; 36) "iter"
44 ARG_LIST@[36; 38)
45 L_PAREN@[36; 37) "("
46 R_PAREN@[37; 38) ")"
47 WHITESPACE@[38; 47) "\n "
48 DOT@[47; 48) "."
49 NAME_REF@[48; 51)
50 IDENT@[48; 51) "map"
51 ARG_LIST@[51; 57)
52 L_PAREN@[51; 52) "("
53 LAMBDA_EXPR@[52; 56)
54 PARAM_LIST@[52; 56)
55 PIPE@[52; 53) "|"
56 PARAM@[53; 55)
57 BIND_PAT@[53; 55)
58 NAME@[53; 55)
59 IDENT@[53; 55) "it"
60 PIPE@[55; 56) "|"
61 R_PAREN@[56; 57) ")"
62 WHITESPACE@[57; 66) "\n "
63 DOT@[66; 67) "."
64 NAME_REF@[67; 70)
65 IDENT@[67; 70) "max"
66 TYPE_ARG_LIST@[70; 77)
67 COLONCOLON@[70; 72) "::"
68 L_ANGLE@[72; 73) "<"
69 TYPE_ARG@[73; 76)
70 PATH_TYPE@[73; 76)
71 PATH@[73; 76)
72 PATH_SEGMENT@[73; 76)
73 NAME_REF@[73; 76)
74 IDENT@[73; 76) "i32"
75 R_ANGLE@[76; 77) ">"
76 ARG_LIST@[77; 79)
77 L_PAREN@[77; 78) "("
78 R_PAREN@[78; 79) ")"
79 SEMI@[79; 80) ";"
80 WHITESPACE@[80; 81) "\n"
81 R_CURLY@[81; 82) "}"
82 WHITESPACE@[82; 83) "\n"
83error 56: expected expression
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
index 4a714ad6b..b05ccc0ed 100644
--- a/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0129_marco_pat.txt
@@ -16,11 +16,10 @@ SOURCE_FILE@[0; 33)
16 LET_KW@[16; 19) "let" 16 LET_KW@[16; 19) "let"
17 WHITESPACE@[19; 20) " " 17 WHITESPACE@[19; 20) " "
18 MACRO_CALL@[20; 25) 18 MACRO_CALL@[20; 25)
19 PATH_PAT@[20; 21) 19 PATH@[20; 21)
20 PATH@[20; 21) 20 PATH_SEGMENT@[20; 21)
21 PATH_SEGMENT@[20; 21) 21 NAME_REF@[20; 21)
22 NAME_REF@[20; 21) 22 IDENT@[20; 21) "m"
23 IDENT@[20; 21) "m"
24 EXCL@[21; 22) "!" 23 EXCL@[21; 22) "!"
25 TOKEN_TREE@[22; 25) 24 TOKEN_TREE@[22; 25)
26 L_PAREN@[22; 23) "(" 25 L_PAREN@[22; 23) "("
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs
new file mode 100644
index 000000000..8cdb3b703
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.rs
@@ -0,0 +1 @@
struct S<const N: u32>;
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt
new file mode 100644
index 000000000..f81de7bac
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_const_param.txt
@@ -0,0 +1,23 @@
1SOURCE_FILE@[0; 24)
2 STRUCT_DEF@[0; 23)
3 STRUCT_KW@[0; 6) "struct"
4 WHITESPACE@[6; 7) " "
5 NAME@[7; 8)
6 IDENT@[7; 8) "S"
7 TYPE_PARAM_LIST@[8; 22)
8 L_ANGLE@[8; 9) "<"
9 CONST_PARAM@[9; 21)
10 CONST_KW@[9; 14) "const"
11 WHITESPACE@[14; 15) " "
12 NAME@[15; 16)
13 IDENT@[15; 16) "N"
14 COLON@[16; 17) ":"
15 WHITESPACE@[17; 18) " "
16 PATH_TYPE@[18; 21)
17 PATH@[18; 21)
18 PATH_SEGMENT@[18; 21)
19 NAME_REF@[18; 21)
20 IDENT@[18; 21) "u32"
21 R_ANGLE@[21; 22) ">"
22 SEMI@[22; 23) ";"
23 WHITESPACE@[23; 24) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs
new file mode 100644
index 000000000..319a4e2aa
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.rs
@@ -0,0 +1,2 @@
1macro m { ($i:ident) => {} }
2macro m($i:ident) {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt
new file mode 100644
index 000000000..3556099bd
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0147_macro_def.txt
@@ -0,0 +1,45 @@
1SOURCE_FILE@[0; 50)
2 MACRO_DEF@[0; 28)
3 MACRO_KW@[0; 5) "macro"
4 WHITESPACE@[5; 6) " "
5 NAME@[6; 7)
6 IDENT@[6; 7) "m"
7 WHITESPACE@[7; 8) " "
8 TOKEN_TREE@[8; 28)
9 L_CURLY@[8; 9) "{"
10 WHITESPACE@[9; 10) " "
11 TOKEN_TREE@[10; 20)
12 L_PAREN@[10; 11) "("
13 DOLLAR@[11; 12) "$"
14 IDENT@[12; 13) "i"
15 COLON@[13; 14) ":"
16 IDENT@[14; 19) "ident"
17 R_PAREN@[19; 20) ")"
18 WHITESPACE@[20; 21) " "
19 EQ@[21; 22) "="
20 R_ANGLE@[22; 23) ">"
21 WHITESPACE@[23; 24) " "
22 TOKEN_TREE@[24; 26)
23 L_CURLY@[24; 25) "{"
24 R_CURLY@[25; 26) "}"
25 WHITESPACE@[26; 27) " "
26 R_CURLY@[27; 28) "}"
27 WHITESPACE@[28; 29) "\n"
28 MACRO_DEF@[29; 49)
29 MACRO_KW@[29; 34) "macro"
30 WHITESPACE@[34; 35) " "
31 NAME@[35; 36)
32 IDENT@[35; 36) "m"
33 TOKEN_TREE@[36; 49)
34 TOKEN_TREE@[36; 46)
35 L_PAREN@[36; 37) "("
36 DOLLAR@[37; 38) "$"
37 IDENT@[38; 39) "i"
38 COLON@[39; 40) ":"
39 IDENT@[40; 45) "ident"
40 R_PAREN@[45; 46) ")"
41 WHITESPACE@[46; 47) " "
42 TOKEN_TREE@[47; 49)
43 L_CURLY@[47; 48) "{"
44 R_CURLY@[48; 49) "}"
45 WHITESPACE@[49; 50) "\n"
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs
new file mode 100644
index 000000000..3b2be597f
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.rs
@@ -0,0 +1 @@
pub macro m($:ident) {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt
new file mode 100644
index 000000000..cfd79d9c2
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0148_pub_macro_def.txt
@@ -0,0 +1,21 @@
1SOURCE_FILE@[0; 24)
2 MACRO_DEF@[0; 23)
3 VISIBILITY@[0; 3)
4 PUB_KW@[0; 3) "pub"
5 WHITESPACE@[3; 4) " "
6 MACRO_KW@[4; 9) "macro"
7 WHITESPACE@[9; 10) " "
8 NAME@[10; 11)
9 IDENT@[10; 11) "m"
10 TOKEN_TREE@[11; 23)
11 TOKEN_TREE@[11; 20)
12 L_PAREN@[11; 12) "("
13 DOLLAR@[12; 13) "$"
14 COLON@[13; 14) ":"
15 IDENT@[14; 19) "ident"
16 R_PAREN@[19; 20) ")"
17 WHITESPACE@[20; 21) " "
18 TOKEN_TREE@[21; 23)
19 L_CURLY@[21; 22) "{"
20 R_CURLY@[22; 23) "}"
21 WHITESPACE@[23; 24) "\n"
diff --git a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs
index 781047ba1..781047ba1 100644
--- a/crates/ra_syntax/test_data/parser/err/0028_macro_2.0.rs
+++ b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.rs
diff --git a/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt
new file mode 100644
index 000000000..2be523fc3
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/ok/0062_macro_2.0.txt
@@ -0,0 +1,176 @@
1SOURCE_FILE@[0; 349)
2 MACRO_DEF@[0; 93)
3 MACRO_KW@[0; 5) "macro"
4 WHITESPACE@[5; 6) " "
5 NAME@[6; 21)
6 IDENT@[6; 21) "parse_use_trees"
7 TOKEN_TREE@[21; 93)
8 TOKEN_TREE@[21; 41)
9 L_PAREN@[21; 22) "("
10 DOLLAR@[22; 23) "$"
11 TOKEN_TREE@[23; 32)
12 L_PAREN@[23; 24) "("
13 DOLLAR@[24; 25) "$"
14 IDENT@[25; 26) "s"
15 COLON@[26; 27) ":"
16 IDENT@[27; 31) "expr"
17 R_PAREN@[31; 32) ")"
18 COMMA@[32; 33) ","
19 STAR@[33; 34) "*"
20 WHITESPACE@[34; 35) " "
21 DOLLAR@[35; 36) "$"
22 TOKEN_TREE@[36; 39)
23 L_PAREN@[36; 37) "("
24 COMMA@[37; 38) ","
25 R_PAREN@[38; 39) ")"
26 STAR@[39; 40) "*"
27 R_PAREN@[40; 41) ")"
28 WHITESPACE@[41; 42) " "
29 TOKEN_TREE@[42; 93)
30 L_CURLY@[42; 43) "{"
31 WHITESPACE@[43; 48) "\n "
32 IDENT@[48; 51) "vec"
33 EXCL@[51; 52) "!"
34 TOKEN_TREE@[52; 91)
35 L_BRACK@[52; 53) "["
36 WHITESPACE@[53; 62) "\n "
37 DOLLAR@[62; 63) "$"
38 TOKEN_TREE@[63; 84)
39 L_PAREN@[63; 64) "("
40 IDENT@[64; 78) "parse_use_tree"
41 TOKEN_TREE@[78; 82)
42 L_PAREN@[78; 79) "("
43 DOLLAR@[79; 80) "$"
44 IDENT@[80; 81) "s"
45 R_PAREN@[81; 82) ")"
46 COMMA@[82; 83) ","
47 R_PAREN@[83; 84) ")"
48 STAR@[84; 85) "*"
49 WHITESPACE@[85; 90) "\n "
50 R_BRACK@[90; 91) "]"
51 WHITESPACE@[91; 92) "\n"
52 R_CURLY@[92; 93) "}"
53 WHITESPACE@[93; 95) "\n\n"
54 FN_DEF@[95; 348)
55 ATTR@[95; 102)
56 POUND@[95; 96) "#"
57 L_BRACK@[96; 97) "["
58 PATH@[97; 101)
59 PATH_SEGMENT@[97; 101)
60 NAME_REF@[97; 101)
61 IDENT@[97; 101) "test"
62 R_BRACK@[101; 102) "]"
63 WHITESPACE@[102; 103) "\n"
64 FN_KW@[103; 105) "fn"
65 WHITESPACE@[105; 106) " "
66 NAME@[106; 125)
67 IDENT@[106; 125) "test_use_tree_merge"
68 PARAM_LIST@[125; 127)
69 L_PAREN@[125; 126) "("
70 R_PAREN@[126; 127) ")"
71 WHITESPACE@[127; 128) " "
72 BLOCK_EXPR@[128; 348)
73 BLOCK@[128; 348)
74 L_CURLY@[128; 129) "{"
75 WHITESPACE@[129; 134) "\n "
76 MACRO_DEF@[134; 346)
77 MACRO_KW@[134; 139) "macro"
78 WHITESPACE@[139; 140) " "
79 NAME@[140; 150)
80 IDENT@[140; 150) "test_merge"
81 TOKEN_TREE@[150; 346)
82 TOKEN_TREE@[150; 203)
83 L_PAREN@[150; 151) "("
84 TOKEN_TREE@[151; 175)
85 L_BRACK@[151; 152) "["
86 DOLLAR@[152; 153) "$"
87 TOKEN_TREE@[153; 166)
88 L_PAREN@[153; 154) "("
89 DOLLAR@[154; 155) "$"
90 IDENT@[155; 160) "input"
91 COLON@[160; 161) ":"
92 IDENT@[161; 165) "expr"
93 R_PAREN@[165; 166) ")"
94 COMMA@[166; 167) ","
95 STAR@[167; 168) "*"
96 WHITESPACE@[168; 169) " "
97 DOLLAR@[169; 170) "$"
98 TOKEN_TREE@[170; 173)
99 L_PAREN@[170; 171) "("
100 COMMA@[171; 172) ","
101 R_PAREN@[172; 173) ")"
102 STAR@[173; 174) "*"
103 R_BRACK@[174; 175) "]"
104 COMMA@[175; 176) ","
105 WHITESPACE@[176; 177) " "
106 TOKEN_TREE@[177; 202)
107 L_BRACK@[177; 178) "["
108 DOLLAR@[178; 179) "$"
109 TOKEN_TREE@[179; 193)
110 L_PAREN@[179; 180) "("
111 DOLLAR@[180; 181) "$"
112 IDENT@[181; 187) "output"
113 COLON@[187; 188) ":"
114 IDENT@[188; 192) "expr"
115 R_PAREN@[192; 193) ")"
116 COMMA@[193; 194) ","
117 STAR@[194; 195) "*"
118 WHITESPACE@[195; 196) " "
119 DOLLAR@[196; 197) "$"
120 TOKEN_TREE@[197; 200)
121 L_PAREN@[197; 198) "("
122 COMMA@[198; 199) ","
123 R_PAREN@[199; 200) ")"
124 STAR@[200; 201) "*"
125 R_BRACK@[201; 202) "]"
126 R_PAREN@[202; 203) ")"
127 WHITESPACE@[203; 204) " "
128 TOKEN_TREE@[204; 346)
129 L_CURLY@[204; 205) "{"
130 WHITESPACE@[205; 214) "\n "
131 IDENT@[214; 223) "assert_eq"
132 EXCL@[223; 224) "!"
133 TOKEN_TREE@[224; 339)
134 L_PAREN@[224; 225) "("
135 WHITESPACE@[225; 238) "\n "
136 IDENT@[238; 253) "merge_use_trees"
137 TOKEN_TREE@[253; 284)
138 L_PAREN@[253; 254) "("
139 IDENT@[254; 269) "parse_use_trees"
140 EXCL@[269; 270) "!"
141 TOKEN_TREE@[270; 283)
142 L_PAREN@[270; 271) "("
143 DOLLAR@[271; 272) "$"
144 TOKEN_TREE@[272; 281)
145 L_PAREN@[272; 273) "("
146 DOLLAR@[273; 274) "$"
147 IDENT@[274; 279) "input"
148 COMMA@[279; 280) ","
149 R_PAREN@[280; 281) ")"
150 STAR@[281; 282) "*"
151 R_PAREN@[282; 283) ")"
152 R_PAREN@[283; 284) ")"
153 COMMA@[284; 285) ","
154 WHITESPACE@[285; 298) "\n "
155 IDENT@[298; 313) "parse_use_trees"
156 EXCL@[313; 314) "!"
157 TOKEN_TREE@[314; 328)
158 L_PAREN@[314; 315) "("
159 DOLLAR@[315; 316) "$"
160 TOKEN_TREE@[316; 326)
161 L_PAREN@[316; 317) "("
162 DOLLAR@[317; 318) "$"
163 IDENT@[318; 324) "output"
164 COMMA@[324; 325) ","
165 R_PAREN@[325; 326) ")"
166 STAR@[326; 327) "*"
167 R_PAREN@[327; 328) ")"
168 COMMA@[328; 329) ","
169 WHITESPACE@[329; 338) "\n "
170 R_PAREN@[338; 339) ")"
171 SEMI@[339; 340) ";"
172 WHITESPACE@[340; 345) "\n "
173 R_CURLY@[345; 346) "}"
174 WHITESPACE@[346; 347) "\n"
175 R_CURLY@[347; 348) "}"
176 WHITESPACE@[348; 349) "\n"
diff --git a/crates/ra_tt/src/lib.rs b/crates/ra_tt/src/lib.rs
index 20c251ff4..10f424aae 100644
--- a/crates/ra_tt/src/lib.rs
+++ b/crates/ra_tt/src/lib.rs
@@ -33,14 +33,14 @@ impl TokenId {
33 } 33 }
34} 34}
35 35
36#[derive(Debug, Clone, PartialEq, Eq)] 36#[derive(Debug, Clone, PartialEq, Eq, Hash)]
37pub enum TokenTree { 37pub enum TokenTree {
38 Leaf(Leaf), 38 Leaf(Leaf),
39 Subtree(Subtree), 39 Subtree(Subtree),
40} 40}
41impl_froms!(TokenTree: Leaf, Subtree); 41impl_froms!(TokenTree: Leaf, Subtree);
42 42
43#[derive(Debug, Clone, PartialEq, Eq)] 43#[derive(Debug, Clone, PartialEq, Eq, Hash)]
44pub enum Leaf { 44pub enum Leaf {
45 Literal(Literal), 45 Literal(Literal),
46 Punct(Punct), 46 Punct(Punct),
@@ -48,38 +48,45 @@ pub enum Leaf {
48} 48}
49impl_froms!(Leaf: Literal, Punct, Ident); 49impl_froms!(Leaf: Literal, Punct, Ident);
50 50
51#[derive(Debug, Clone, PartialEq, Eq)] 51#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
52pub struct Subtree { 52pub struct Subtree {
53 pub delimiter: Delimiter, 53 pub delimiter: Option<Delimiter>,
54 pub token_trees: Vec<TokenTree>, 54 pub token_trees: Vec<TokenTree>,
55} 55}
56 56
57#[derive(Clone, Copy, Debug, PartialEq, Eq)] 57#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
58pub enum Delimiter { 58pub struct Delimiter {
59 pub id: TokenId,
60 pub kind: DelimiterKind,
61}
62
63#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
64pub enum DelimiterKind {
59 Parenthesis, 65 Parenthesis,
60 Brace, 66 Brace,
61 Bracket, 67 Bracket,
62 None,
63} 68}
64 69
65#[derive(Debug, Clone, PartialEq, Eq)] 70#[derive(Debug, Clone, PartialEq, Eq, Hash)]
66pub struct Literal { 71pub struct Literal {
67 pub text: SmolStr, 72 pub text: SmolStr,
73 pub id: TokenId,
68} 74}
69 75
70#[derive(Debug, Clone, Copy, PartialEq, Eq)] 76#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
71pub struct Punct { 77pub struct Punct {
72 pub char: char, 78 pub char: char,
73 pub spacing: Spacing, 79 pub spacing: Spacing,
80 pub id: TokenId,
74} 81}
75 82
76#[derive(Debug, Clone, Copy, PartialEq, Eq)] 83#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
77pub enum Spacing { 84pub enum Spacing {
78 Alone, 85 Alone,
79 Joint, 86 Joint,
80} 87}
81 88
82#[derive(Debug, Clone, PartialEq, Eq)] 89#[derive(Debug, Clone, PartialEq, Eq, Hash)]
83pub struct Ident { 90pub struct Ident {
84 pub text: SmolStr, 91 pub text: SmolStr,
85 pub id: TokenId, 92 pub id: TokenId,
@@ -96,11 +103,11 @@ impl fmt::Display for TokenTree {
96 103
97impl fmt::Display for Subtree { 104impl fmt::Display for Subtree {
98 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 105 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
99 let (l, r) = match self.delimiter { 106 let (l, r) = match self.delimiter_kind() {
100 Delimiter::Parenthesis => ("(", ")"), 107 Some(DelimiterKind::Parenthesis) => ("(", ")"),
101 Delimiter::Brace => ("{", "}"), 108 Some(DelimiterKind::Brace) => ("{", "}"),
102 Delimiter::Bracket => ("[", "]"), 109 Some(DelimiterKind::Bracket) => ("[", "]"),
103 Delimiter::None => ("", ""), 110 None => ("", ""),
104 }; 111 };
105 f.write_str(l)?; 112 f.write_str(l)?;
106 let mut needs_space = false; 113 let mut needs_space = false;
@@ -164,6 +171,10 @@ impl Subtree {
164 171
165 self.token_trees.len() + children_count 172 self.token_trees.len() + children_count
166 } 173 }
174
175 pub fn delimiter_kind(&self) -> Option<DelimiterKind> {
176 self.delimiter.map(|it| it.kind)
177 }
167} 178}
168 179
169pub mod buffer; 180pub mod buffer;
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index 1244ea8cf..659f77b71 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -207,8 +207,8 @@ pub fn lines_match(expected: &str, actual: &str) -> bool {
207 // Let's not deal with / vs \ (windows...) 207 // Let's not deal with / vs \ (windows...)
208 // First replace backslash-escaped backslashes with forward slashes 208 // First replace backslash-escaped backslashes with forward slashes
209 // which can occur in, for example, JSON output 209 // which can occur in, for example, JSON output
210 let expected = expected.replace("\\\\", "/").replace("\\", "/"); 210 let expected = expected.replace(r"\\", "/").replace(r"\", "/");
211 let mut actual: &str = &actual.replace("\\\\", "/").replace("\\", "/"); 211 let mut actual: &str = &actual.replace(r"\\", "/").replace(r"\", "/");
212 for (i, part) in expected.split("[..]").enumerate() { 212 for (i, part) in expected.split("[..]").enumerate() {
213 match actual.find(part) { 213 match actual.find(part) {
214 Some(j) => { 214 Some(j) => {
@@ -356,6 +356,17 @@ pub fn read_text(path: &Path) -> String {
356 .replace("\r\n", "\n") 356 .replace("\r\n", "\n")
357} 357}
358 358
359pub fn skip_slow_tests() -> bool {
360 let should_skip = std::env::var("CI").is_err() && std::env::var("RUN_SLOW_TESTS").is_err();
361 if should_skip {
362 eprintln!("ignoring slow test")
363 } else {
364 let path = project_dir().join("./target/.slow_tests_cookie");
365 fs::write(&path, ".").unwrap();
366 }
367 should_skip
368}
369
359const REWRITE: bool = false; 370const REWRITE: bool = false;
360 371
361fn assert_equal_text(expected: &str, actual: &str, path: &Path) { 372fn assert_equal_text(expected: &str, actual: &str, path: &Path) {
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 0f64d7e5f..2f6215d6b 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -124,9 +124,8 @@ Logging is done by both rust-analyzer and VS Code, so it might be tricky to
124figure out where logs go. 124figure out where logs go.
125 125
126Inside rust-analyzer, we use the standard `log` crate for logging, and 126Inside rust-analyzer, we use the standard `log` crate for logging, and
127`flexi_logger` for logging frotend. By default, log goes to stderr (the same as 127`env_logger` for logging frontend. By default, log goes to stderr, but the
128with `env_logger`), but the stderr itself is processed by VS Code. To mirror 128stderr itself is processed by VS Code.
129logs to a `./log` directory, set `RA_LOG_DIR=1` environmental variable.
130 129
131To see stderr in the running VS Code instance, go to the "Output" tab of the 130To see stderr in the running VS Code instance, go to the "Output" tab of the
132panel and select `rust-analyzer`. This shows `eprintln!` as well. Note that 131panel and select `rust-analyzer`. This shows `eprintln!` as well. Note that
diff --git a/docs/user/README.md b/docs/user/README.md
index 1b2d98608..968d2e34c 100644
--- a/docs/user/README.md
+++ b/docs/user/README.md
@@ -1,14 +1,19 @@
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 xtask install --server`, which is a shorthand for `cargo 3install lsp server, clone the repository and then run `cargo xtask install
4install --package ra_lsp_server`. The binary is named `ra_lsp_server`, you 4--server` (which is shorthand for `cargo install --path
5should be able to use it with any LSP-compatible editor. We use custom 5./crates/ra_lsp_server`). This will produce a binary named `ra_lsp_server` which
6you should 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 7extensions to LSP, so special client-side support is required to take full
7advantage of rust-analyzer. This repository contains support code for VS Code 8advantage of rust-analyzer. This repository contains support code for VS Code
8and Emacs. 9and Emacs.
9 10
10Rust Analyzer needs sources of rust standard library to work, so you might need 11```
11to execute 12$ git clone [email protected]:rust-analyzer/rust-analyzer && cd rust-analyzer
13$ cargo xtask install --server
14```
15Rust Analyzer needs sources of rust standard library to work, so
16you might also need to execute
12 17
13``` 18```
14$ rustup component add rust-src 19$ rustup component add rust-src
@@ -133,43 +138,31 @@ Prerequisites:
133Installation: 138Installation:
134 139
135* add 140* add
136[ra-emacs-lsp.el](https://github.com/rust-analyzer/rust-analyzer/blob/69ee5c9c5ef212f7911028c9ddf581559e6565c3/editors/emacs/ra-emacs-lsp.el) 141[ra-emacs-lsp.el](../../editors/emacs/ra-emacs-lsp.el)
137to load path and require it in `init.el` 142to load path and require it in `init.el`
138* run `lsp` in a rust buffer 143* run `lsp` in a rust buffer
139* (Optionally) bind commands like `rust-analyzer-join-lines`, `rust-analyzer-extend-selection` and `rust-analyzer-expand-macro` to keys, and enable `rust-analyzer-inlay-hints-mode` to get inline type hints 144* (Optionally) bind commands like `rust-analyzer-join-lines`, `rust-analyzer-extend-selection` and `rust-analyzer-expand-macro` to keys, and enable `rust-analyzer-inlay-hints-mode` to get inline type hints
140 145
141 146
142## Vim and NeoVim 147## Vim and NeoVim (coc-rust-analyzer)
143 148
144Neovim 0.5 has a built in language server. For a quick start configuration of 149* Install coc.nvim by following the instructions at [coc.nvim][] (nodejs required)
145rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer). 150* Run `:CocInstall coc-rust-analyzer` to install [coc-rust-analyzer], this extension implements _most_ of the features supported in the VSCode extension:
146Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})`
147or `lua require'nvim_lsp'.rust_analyzer.setup({})` to quickly get set up.
148
149* Install coc.nvim by following the instructions at [coc.nvim]
150 - You will need nodejs installed.
151 - You may want to include some of the sample vim configurations [from here][coc-vim-conf]
152 - Note that if you use a plugin manager other than `vim-plug`, you may need to manually
153 checkout the `release` branch wherever your plugin manager cloned it. Otherwise you will
154 get errors about a missing javascript file.
155* Run `:CocInstall coc-rust-analyzer` to install [coc-rust-analyzer], this extension implemented _most_ of the features supported in the VSCode extension:
156 - same configurations as VSCode extension, `rust-analyzer.raLspServerPath`, `rust-analyzer.enableCargoWatchOnStartup` etc. 151 - same configurations as VSCode extension, `rust-analyzer.raLspServerPath`, `rust-analyzer.enableCargoWatchOnStartup` etc.
157 - same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.startCargoWatch` etc. 152 - same commands too, `rust-analyzer.analyzerStatus`, `rust-analyzer.startCargoWatch` etc.
158 - highlighting and inlay_hints are not implemented yet 153 - highlighting and inlay_hints are not implemented yet
159 154
160[coc.nvim]: https://github.com/neoclide/coc.nvim 155[coc.nvim]: https://github.com/neoclide/coc.nvim
161[coc-vim-conf]: https://github.com/neoclide/coc.nvim/#example-vim-configuration
162[coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer 156[coc-rust-analyzer]: https://github.com/fannheyward/coc-rust-analyzer
163 157
164## Vim and NeoVim Alternative 158## Vim and NeoVim (LanguageClient-neovim)
165 159
166* Install LanguageClient-neovim by following the instructions [here][lang-client-neovim] 160* Install LanguageClient-neovim by following the instructions [here][lang-client-neovim]
167 - No extra run-time is required as this server is written in Rust
168 - The github project wiki has extra tips on configuration 161 - The github project wiki has extra tips on configuration
169 162
170* Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists): 163* Configure by adding this to your vim/neovim config file (replacing the existing rust specific line if it exists):
171 164
172``` 165```vim
173let g:LanguageClient_serverCommands = { 166let g:LanguageClient_serverCommands = {
174\ 'rust': ['ra_lsp_server'], 167\ 'rust': ['ra_lsp_server'],
175\ } 168\ }
@@ -177,6 +170,13 @@ let g:LanguageClient_serverCommands = {
177 170
178[lang-client-neovim]: https://github.com/autozimu/LanguageClient-neovim 171[lang-client-neovim]: https://github.com/autozimu/LanguageClient-neovim
179 172
173## NeoVim (nvim-lsp)
174
175NeoVim 0.5 (not yet released) has built in language server support. For a quick start configuration
176of rust-analyzer, use [neovim/nvim-lsp](https://github.com/neovim/nvim-lsp#rust_analyzer).
177Once `neovim/nvim-lsp` is installed, you can use `call nvim_lsp#setup("rust_analyzer", {})`
178or `lua require'nvim_lsp'.rust_analyzer.setup({})` to quickly get set up.
179
180 180
181## Sublime Text 3 181## Sublime Text 3
182 182
@@ -208,4 +208,19 @@ Installation:
208 208
209* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer) 209* You can now invoke the command palette and type LSP enable to locally/globally enable the rust-analyzer LSP (type LSP enable, then choose either locally or globally, then select rust-analyzer)
210 210
211* Note that `ra_lsp_server` binary must be in `$PATH` for this to work. If it's not the case, you can specify full path to the binary, which is typically `.cargo/bin/ra_lsp_server`. 211### Setting up the `PATH` variable
212
213On Unix systems, `rustup` adds `~/.cargo/bin` to `PATH` by modifying the shell's
214startup file. Depending on your configuration, your Desktop Environment might not
215actually load it. If you find that `rust-analyzer` only runs when starting the
216editor from the terminal, you will have to set up your `PATH` variable manually.
217
218There are a couple of ways to do that:
219
220- for Code, set `rust-analyzer.raLspServerPath` to `~/.cargo/bin` (the `~` is
221 automatically resolved by the extension)
222- copy the binary to a location that is already in `PATH`, e.g. `/usr/local/bin`
223- on Linux, use PAM to configure the `PATH` variable, by e.g. putting
224 `PATH DEFAULT=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:@{HOME}/.cargo/bin:@{HOME}/.local/bin`
225 in your `~/.pam_environment` file; note that this might interfere with other
226 defaults set by the system administrator via `/etc/environment`.
diff --git a/docs/user/assists.md b/docs/user/assists.md
index 6f4c30bee..334ba450f 100644
--- a/docs/user/assists.md
+++ b/docs/user/assists.md
@@ -3,6 +3,24 @@
3Cursor position or selection is signified by `┃` character. 3Cursor position or selection is signified by `┃` character.
4 4
5 5
6## `add_custom_impl`
7
8Adds impl block for derived trait.
9
10```rust
11// BEFORE
12#[derive(Deb┃ug, Display)]
13struct S;
14
15// AFTER
16#[derive(Display)]
17struct S;
18
19impl Debug for S {
20
21}
22```
23
6## `add_derive` 24## `add_derive`
7 25
8Adds a new `#[derive()]` clause to a struct or enum. 26Adds a new `#[derive()]` clause to a struct or enum.
diff --git a/editors/code/package-lock.json b/editors/code/package-lock.json
index a41497a23..4c5c13646 100644
--- a/editors/code/package-lock.json
+++ b/editors/code/package-lock.json
@@ -60,9 +60,9 @@
60 "dev": true 60 "dev": true
61 }, 61 },
62 "@types/node": { 62 "@types/node": {
63 "version": "10.14.13", 63 "version": "12.12.21",
64 "resolved": "https://registry.npmjs.org/@types/node/-/node-10.14.13.tgz", 64 "resolved": "https://registry.npmjs.org/@types/node/-/node-12.12.21.tgz",
65 "integrity": "sha512-yN/FNNW1UYsRR1wwAoyOwqvDuLDtVXnaJTZ898XIw/Q5cCaeVAlVwvsmXLX5PuiScBYwZsZU4JYSHB3TvfdwvQ==", 65 "integrity": "sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==",
66 "dev": true 66 "dev": true
67 }, 67 },
68 "@types/resolve": { 68 "@types/resolve": {
@@ -81,9 +81,9 @@
81 "dev": true 81 "dev": true
82 }, 82 },
83 "@types/vscode": { 83 "@types/vscode": {
84 "version": "1.37.0", 84 "version": "1.41.0",
85 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.37.0.tgz", 85 "resolved": "https://registry.npmjs.org/@types/vscode/-/vscode-1.41.0.tgz",
86 "integrity": "sha512-PRfeuqYuzk3vjf+puzxltIUWC+AhEGYpFX29/37w30DQSQnpf5AgMVf7GDBAdmTbWTBou+EMFz/Ne6XCM/KxzQ==", 86 "integrity": "sha512-7SfeY5u9jgiELwxyLB3z7l6l/GbN9CqpCQGkcRlB7tKRFBxzbz2PoBfGrLxI1vRfUCIq5+hg5vtDHExwq5j3+A==",
87 "dev": true 87 "dev": true
88 }, 88 },
89 "acorn": { 89 "acorn": {
@@ -131,6 +131,12 @@
131 "sprintf-js": "~1.0.2" 131 "sprintf-js": "~1.0.2"
132 } 132 }
133 }, 133 },
134 "atob": {
135 "version": "2.1.2",
136 "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
137 "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
138 "dev": true
139 },
134 "azure-devops-node-api": { 140 "azure-devops-node-api": {
135 "version": "7.2.0", 141 "version": "7.2.0",
136 "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz", 142 "resolved": "https://registry.npmjs.org/azure-devops-node-api/-/azure-devops-node-api-7.2.0.tgz",
@@ -198,6 +204,17 @@
198 "ansi-styles": "^3.2.1", 204 "ansi-styles": "^3.2.1",
199 "escape-string-regexp": "^1.0.5", 205 "escape-string-regexp": "^1.0.5",
200 "supports-color": "^5.3.0" 206 "supports-color": "^5.3.0"
207 },
208 "dependencies": {
209 "supports-color": {
210 "version": "5.5.0",
211 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
212 "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
213 "dev": true,
214 "requires": {
215 "has-flag": "^3.0.0"
216 }
217 }
201 } 218 }
202 }, 219 },
203 "cheerio": { 220 "cheerio": {
@@ -215,22 +232,44 @@
215 } 232 }
216 }, 233 },
217 "cliui": { 234 "cliui": {
218 "version": "4.1.0", 235 "version": "5.0.0",
219 "resolved": "https://registry.npmjs.org/cliui/-/cliui-4.1.0.tgz", 236 "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz",
220 "integrity": "sha512-4FG+RSG9DL7uEwRUZXZn3SS34DiDPfzP0VOiEwtUWlE+AR2EIg+hSyvrIgUUfhdgR/UkAeW2QHgeP+hWrXs7jQ==", 237 "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==",
221 "dev": true, 238 "dev": true,
222 "requires": { 239 "requires": {
223 "string-width": "^2.1.1", 240 "string-width": "^3.1.0",
224 "strip-ansi": "^4.0.0", 241 "strip-ansi": "^5.2.0",
225 "wrap-ansi": "^2.0.0" 242 "wrap-ansi": "^5.1.0"
243 },
244 "dependencies": {
245 "ansi-regex": {
246 "version": "4.1.0",
247 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
248 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
249 "dev": true
250 },
251 "string-width": {
252 "version": "3.1.0",
253 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
254 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
255 "dev": true,
256 "requires": {
257 "emoji-regex": "^7.0.1",
258 "is-fullwidth-code-point": "^2.0.0",
259 "strip-ansi": "^5.1.0"
260 }
261 },
262 "strip-ansi": {
263 "version": "5.2.0",
264 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
265 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
266 "dev": true,
267 "requires": {
268 "ansi-regex": "^4.1.0"
269 }
270 }
226 } 271 }
227 }, 272 },
228 "code-point-at": {
229 "version": "1.1.0",
230 "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
231 "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=",
232 "dev": true
233 },
234 "color-convert": { 273 "color-convert": {
235 "version": "1.9.3", 274 "version": "1.9.3",
236 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", 275 "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
@@ -247,9 +286,9 @@
247 "dev": true 286 "dev": true
248 }, 287 },
249 "commander": { 288 "commander": {
250 "version": "2.20.0", 289 "version": "2.20.3",
251 "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", 290 "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
252 "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", 291 "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==",
253 "dev": true 292 "dev": true
254 }, 293 },
255 "concat-map": { 294 "concat-map": {
@@ -258,19 +297,6 @@
258 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", 297 "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
259 "dev": true 298 "dev": true
260 }, 299 },
261 "cross-spawn": {
262 "version": "6.0.5",
263 "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz",
264 "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==",
265 "dev": true,
266 "requires": {
267 "nice-try": "^1.0.4",
268 "path-key": "^2.0.1",
269 "semver": "^5.5.0",
270 "shebang-command": "^1.2.0",
271 "which": "^1.2.9"
272 }
273 },
274 "css-select": { 300 "css-select": {
275 "version": "1.2.0", 301 "version": "1.2.0",
276 "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz", 302 "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
@@ -290,12 +316,12 @@
290 "dev": true 316 "dev": true
291 }, 317 },
292 "debug": { 318 "debug": {
293 "version": "3.1.0", 319 "version": "3.2.6",
294 "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz", 320 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
295 "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==", 321 "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
296 "dev": true, 322 "dev": true,
297 "requires": { 323 "requires": {
298 "ms": "2.0.0" 324 "ms": "^2.1.1"
299 } 325 }
300 }, 326 },
301 "decamelize": { 327 "decamelize": {
@@ -304,6 +330,12 @@
304 "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", 330 "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=",
305 "dev": true 331 "dev": true
306 }, 332 },
333 "decode-uri-component": {
334 "version": "0.2.0",
335 "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz",
336 "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=",
337 "dev": true
338 },
307 "define-properties": { 339 "define-properties": {
308 "version": "1.1.3", 340 "version": "1.1.3",
309 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", 341 "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz",
@@ -372,15 +404,6 @@
372 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", 404 "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==",
373 "dev": true 405 "dev": true
374 }, 406 },
375 "end-of-stream": {
376 "version": "1.4.1",
377 "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz",
378 "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==",
379 "dev": true,
380 "requires": {
381 "once": "^1.4.0"
382 }
383 },
384 "entities": { 407 "entities": {
385 "version": "1.1.2", 408 "version": "1.1.2",
386 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz", 409 "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.2.tgz",
@@ -388,23 +411,27 @@
388 "dev": true 411 "dev": true
389 }, 412 },
390 "es-abstract": { 413 "es-abstract": {
391 "version": "1.13.0", 414 "version": "1.16.3",
392 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.13.0.tgz", 415 "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.16.3.tgz",
393 "integrity": "sha512-vDZfg/ykNxQVwup/8E1BZhVzFfBxs9NqMzGcvIJrqg5k2/5Za2bWo40dK2J1pgLngZ7c+Shh8lwYtLGyrwPutg==", 416 "integrity": "sha512-WtY7Fx5LiOnSYgF5eg/1T+GONaGmpvpPdCpSnYij+U2gDTL0UPfWrhDw7b2IYb+9NQJsYpCA0wOQvZfsd6YwRw==",
394 "dev": true, 417 "dev": true,
395 "requires": { 418 "requires": {
396 "es-to-primitive": "^1.2.0", 419 "es-to-primitive": "^1.2.1",
397 "function-bind": "^1.1.1", 420 "function-bind": "^1.1.1",
398 "has": "^1.0.3", 421 "has": "^1.0.3",
422 "has-symbols": "^1.0.1",
399 "is-callable": "^1.1.4", 423 "is-callable": "^1.1.4",
400 "is-regex": "^1.0.4", 424 "is-regex": "^1.0.4",
401 "object-keys": "^1.0.12" 425 "object-inspect": "^1.7.0",
426 "object-keys": "^1.1.1",
427 "string.prototype.trimleft": "^2.1.0",
428 "string.prototype.trimright": "^2.1.0"
402 } 429 }
403 }, 430 },
404 "es-to-primitive": { 431 "es-to-primitive": {
405 "version": "1.2.0", 432 "version": "1.2.1",
406 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.0.tgz", 433 "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz",
407 "integrity": "sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg==", 434 "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==",
408 "dev": true, 435 "dev": true,
409 "requires": { 436 "requires": {
410 "is-callable": "^1.1.4", 437 "is-callable": "^1.1.4",
@@ -439,6 +466,16 @@
439 "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", 466 "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=",
440 "dev": true 467 "dev": true
441 }, 468 },
469 "eslint-plugin-prettier": {
470 "version": "2.7.0",
471 "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-2.7.0.tgz",
472 "integrity": "sha512-CStQYJgALoQBw3FsBzH0VOVDRnJ/ZimUlpLm226U8qgqYJfPOY/CPK6wyRInMxh73HSKg5wyRwdS4BVYYHwokA==",
473 "dev": true,
474 "requires": {
475 "fast-diff": "^1.1.1",
476 "jest-docblock": "^21.0.0"
477 }
478 },
442 "esprima": { 479 "esprima": {
443 "version": "4.0.1", 480 "version": "4.0.1",
444 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", 481 "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz",
@@ -452,25 +489,16 @@
452 "dev": true 489 "dev": true
453 }, 490 },
454 "esutils": { 491 "esutils": {
455 "version": "2.0.2", 492 "version": "2.0.3",
456 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz", 493 "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz",
457 "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs=", 494 "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
458 "dev": true 495 "dev": true
459 }, 496 },
460 "execa": { 497 "fast-diff": {
461 "version": "1.0.0", 498 "version": "1.2.0",
462 "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", 499 "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
463 "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", 500 "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
464 "dev": true, 501 "dev": true
465 "requires": {
466 "cross-spawn": "^6.0.0",
467 "get-stream": "^4.0.0",
468 "is-stream": "^1.1.0",
469 "npm-run-path": "^2.0.0",
470 "p-finally": "^1.0.0",
471 "signal-exit": "^3.0.0",
472 "strip-eof": "^1.0.0"
473 }
474 }, 502 },
475 "fd-slicer": { 503 "fd-slicer": {
476 "version": "1.1.0", 504 "version": "1.1.0",
@@ -517,19 +545,10 @@
517 "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", 545 "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
518 "dev": true 546 "dev": true
519 }, 547 },
520 "get-stream": {
521 "version": "4.1.0",
522 "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz",
523 "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==",
524 "dev": true,
525 "requires": {
526 "pump": "^3.0.0"
527 }
528 },
529 "glob": { 548 "glob": {
530 "version": "7.1.4", 549 "version": "7.1.6",
531 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", 550 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
532 "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", 551 "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
533 "dev": true, 552 "dev": true,
534 "requires": { 553 "requires": {
535 "fs.realpath": "^1.0.0", 554 "fs.realpath": "^1.0.0",
@@ -562,9 +581,9 @@
562 "dev": true 581 "dev": true
563 }, 582 },
564 "has-symbols": { 583 "has-symbols": {
565 "version": "1.0.0", 584 "version": "1.0.1",
566 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", 585 "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz",
567 "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", 586 "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
568 "dev": true 587 "dev": true
569 }, 588 },
570 "he": { 589 "he": {
@@ -595,12 +614,29 @@
595 "requires": { 614 "requires": {
596 "agent-base": "4", 615 "agent-base": "4",
597 "debug": "3.1.0" 616 "debug": "3.1.0"
617 },
618 "dependencies": {
619 "debug": {
620 "version": "3.1.0",
621 "resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
622 "integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
623 "dev": true,
624 "requires": {
625 "ms": "2.0.0"
626 }
627 },
628 "ms": {
629 "version": "2.0.0",
630 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
631 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=",
632 "dev": true
633 }
598 } 634 }
599 }, 635 },
600 "https-proxy-agent": { 636 "https-proxy-agent": {
601 "version": "2.2.3", 637 "version": "2.2.4",
602 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.3.tgz", 638 "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
603 "integrity": "sha512-Ytgnz23gm2DVftnzqRRz2dOXZbGd2uiajSw/95bPp6v53zPRspQjLm/AfBgqbJ2qfeRXWIOMVLpp86+/5yX39Q==", 639 "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
604 "dev": true, 640 "dev": true,
605 "requires": { 641 "requires": {
606 "agent-base": "^4.3.0", 642 "agent-base": "^4.3.0",
@@ -618,9 +654,9 @@
618 } 654 }
619 }, 655 },
620 "inherits": { 656 "inherits": {
621 "version": "2.0.3", 657 "version": "2.0.4",
622 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 658 "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
623 "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 659 "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
624 "dev": true 660 "dev": true
625 }, 661 },
626 "interpret": { 662 "interpret": {
@@ -629,16 +665,10 @@
629 "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", 665 "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==",
630 "dev": true 666 "dev": true
631 }, 667 },
632 "invert-kv": {
633 "version": "2.0.0",
634 "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-2.0.0.tgz",
635 "integrity": "sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA==",
636 "dev": true
637 },
638 "is-buffer": { 668 "is-buffer": {
639 "version": "2.0.3", 669 "version": "2.0.4",
640 "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.3.tgz", 670 "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.4.tgz",
641 "integrity": "sha512-U15Q7MXTuZlrbymiz95PJpZxu8IlipAp4dtS3wOdgPXx3mqBnslrWU14kxfHB+Py/+2PVKSr37dMAgM2A4uArw==", 671 "integrity": "sha512-Kq1rokWXOPXWuaMAqZiJW4XxsmD9zGx9q4aePabbn3qCRGedtH7Cm+zV8WETitMfu1wdh+Rvd6w5egwSngUX2A==",
642 "dev": true 672 "dev": true
643 }, 673 },
644 "is-callable": { 674 "is-callable": {
@@ -683,19 +713,13 @@
683 "has": "^1.0.1" 713 "has": "^1.0.1"
684 } 714 }
685 }, 715 },
686 "is-stream": {
687 "version": "1.1.0",
688 "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
689 "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=",
690 "dev": true
691 },
692 "is-symbol": { 716 "is-symbol": {
693 "version": "1.0.2", 717 "version": "1.0.3",
694 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.2.tgz", 718 "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz",
695 "integrity": "sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw==", 719 "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==",
696 "dev": true, 720 "dev": true,
697 "requires": { 721 "requires": {
698 "has-symbols": "^1.0.0" 722 "has-symbols": "^1.0.1"
699 } 723 }
700 }, 724 },
701 "isexe": { 725 "isexe": {
@@ -704,6 +728,12 @@
704 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", 728 "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=",
705 "dev": true 729 "dev": true
706 }, 730 },
731 "jest-docblock": {
732 "version": "21.2.0",
733 "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-21.2.0.tgz",
734 "integrity": "sha512-5IZ7sY9dBAYSV+YjQ0Ovb540Ku7AO9Z5o2Cg789xj167iQuZ2cG+z0f3Uct6WeYLbU6aQiM2pCs7sZ+4dotydw==",
735 "dev": true
736 },
707 "js-tokens": { 737 "js-tokens": {
708 "version": "4.0.0", 738 "version": "4.0.0",
709 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", 739 "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -720,19 +750,11 @@
720 "esprima": "^4.0.0" 750 "esprima": "^4.0.0"
721 } 751 }
722 }, 752 },
723 "jsonc-parser": { 753 "lines-and-columns": {
724 "version": "2.2.0", 754 "version": "1.1.6",
725 "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-2.2.0.tgz", 755 "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz",
726 "integrity": "sha512-4fLQxW1j/5fWj6p78vAlAafoCKtuBm6ghv+Ij5W2DrDx0qE+ZdEl2c6Ko1mgJNF5ftX1iEWQQ4Ap7+3GlhjkOA==" 756 "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=",
727 }, 757 "dev": true
728 "lcid": {
729 "version": "2.0.0",
730 "resolved": "https://registry.npmjs.org/lcid/-/lcid-2.0.0.tgz",
731 "integrity": "sha512-avPEb8P8EGnwXKClwsNUgryVjllcRqtMYa49NTsbQagYuT1DcXnl1915oxWjoyGrXR6zH/Y0Zc96xWsPcoDKeA==",
732 "dev": true,
733 "requires": {
734 "invert-kv": "^2.0.0"
735 }
736 }, 758 },
737 "linkify-it": { 759 "linkify-it": {
738 "version": "2.2.0", 760 "version": "2.2.0",
@@ -768,6 +790,11 @@
768 "chalk": "^2.0.1" 790 "chalk": "^2.0.1"
769 } 791 }
770 }, 792 },
793 "lookpath": {
794 "version": "1.0.4",
795 "resolved": "https://registry.npmjs.org/lookpath/-/lookpath-1.0.4.tgz",
796 "integrity": "sha512-xVFrWlfo7n8VZs1YjBWKkbSIJU7DKE/0Mep62KeT94V1Ui1IY9w5fXfgiCsDIDZkakIYSXSeaW2FLbCqfw9/Cw=="
797 },
771 "magic-string": { 798 "magic-string": {
772 "version": "0.25.3", 799 "version": "0.25.3",
773 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz", 800 "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.25.3.tgz",
@@ -777,15 +804,6 @@
777 "sourcemap-codec": "^1.4.4" 804 "sourcemap-codec": "^1.4.4"
778 } 805 }
779 }, 806 },
780 "map-age-cleaner": {
781 "version": "0.1.3",
782 "resolved": "https://registry.npmjs.org/map-age-cleaner/-/map-age-cleaner-0.1.3.tgz",
783 "integrity": "sha512-bJzx6nMoP6PDLPBFmg7+xRKeFZvFboMrGlxmNj9ClvX53KrmvM5bXFXEWjbz4cz1AFn+jWJ9z/DJSz7hrs0w3w==",
784 "dev": true,
785 "requires": {
786 "p-defer": "^1.0.0"
787 }
788 },
789 "markdown-it": { 807 "markdown-it": {
790 "version": "8.4.2", 808 "version": "8.4.2",
791 "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz", 809 "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-8.4.2.tgz",
@@ -805,29 +823,12 @@
805 "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=", 823 "integrity": "sha1-/oWy7HWlkDfyrf7BAP1sYBdhFS4=",
806 "dev": true 824 "dev": true
807 }, 825 },
808 "mem": {
809 "version": "4.3.0",
810 "resolved": "https://registry.npmjs.org/mem/-/mem-4.3.0.tgz",
811 "integrity": "sha512-qX2bG48pTqYRVmDB37rn/6PT7LcR8T7oAX3bf99u1Tt1nzxYfxkgqDwUwolPlXweM0XzBOBFzSx4kfp7KP1s/w==",
812 "dev": true,
813 "requires": {
814 "map-age-cleaner": "^0.1.1",
815 "mimic-fn": "^2.0.0",
816 "p-is-promise": "^2.0.0"
817 }
818 },
819 "mime": { 826 "mime": {
820 "version": "1.6.0", 827 "version": "1.6.0",
821 "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", 828 "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
822 "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", 829 "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
823 "dev": true 830 "dev": true
824 }, 831 },
825 "mimic-fn": {
826 "version": "2.1.0",
827 "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
828 "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==",
829 "dev": true
830 },
831 "minimatch": { 832 "minimatch": {
832 "version": "3.0.4", 833 "version": "3.0.4",
833 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", 834 "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
@@ -853,9 +854,9 @@
853 } 854 }
854 }, 855 },
855 "mocha": { 856 "mocha": {
856 "version": "6.2.0", 857 "version": "6.2.2",
857 "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.0.tgz", 858 "resolved": "https://registry.npmjs.org/mocha/-/mocha-6.2.2.tgz",
858 "integrity": "sha512-qwfFgY+7EKAAUAdv7VYMZQknI7YJSGesxHyhn6qD52DV8UcSZs5XwCifcZGMVIE4a5fbmhvbotxC0DLQ0oKohQ==", 859 "integrity": "sha512-FgDS9Re79yU1xz5d+C4rv1G7QagNGHZ+iXF81hO8zY35YZZcLEsJVfFolfsqKFWunATEvNzMK0r/CwWd/szO9A==",
859 "dev": true, 860 "dev": true,
860 "requires": { 861 "requires": {
861 "ansi-colors": "3.2.3", 862 "ansi-colors": "3.2.3",
@@ -878,20 +879,11 @@
878 "supports-color": "6.0.0", 879 "supports-color": "6.0.0",
879 "which": "1.3.1", 880 "which": "1.3.1",
880 "wide-align": "1.1.3", 881 "wide-align": "1.1.3",
881 "yargs": "13.2.2", 882 "yargs": "13.3.0",
882 "yargs-parser": "13.0.0", 883 "yargs-parser": "13.1.1",
883 "yargs-unparser": "1.5.0" 884 "yargs-unparser": "1.6.0"
884 }, 885 },
885 "dependencies": { 886 "dependencies": {
886 "debug": {
887 "version": "3.2.6",
888 "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
889 "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
890 "dev": true,
891 "requires": {
892 "ms": "^2.1.1"
893 }
894 },
895 "glob": { 887 "glob": {
896 "version": "7.1.3", 888 "version": "7.1.3",
897 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", 889 "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz",
@@ -905,28 +897,13 @@
905 "once": "^1.3.0", 897 "once": "^1.3.0",
906 "path-is-absolute": "^1.0.0" 898 "path-is-absolute": "^1.0.0"
907 } 899 }
908 },
909 "ms": {
910 "version": "2.1.1",
911 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
912 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
913 "dev": true
914 },
915 "supports-color": {
916 "version": "6.0.0",
917 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
918 "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
919 "dev": true,
920 "requires": {
921 "has-flag": "^3.0.0"
922 }
923 } 900 }
924 } 901 }
925 }, 902 },
926 "ms": { 903 "ms": {
927 "version": "2.0.0", 904 "version": "2.1.1",
928 "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", 905 "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.1.tgz",
929 "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", 906 "integrity": "sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg==",
930 "dev": true 907 "dev": true
931 }, 908 },
932 "mute-stream": { 909 "mute-stream": {
@@ -935,12 +912,6 @@
935 "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", 912 "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==",
936 "dev": true 913 "dev": true
937 }, 914 },
938 "nice-try": {
939 "version": "1.0.5",
940 "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz",
941 "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==",
942 "dev": true
943 },
944 "node-environment-flags": { 915 "node-environment-flags": {
945 "version": "1.0.5", 916 "version": "1.0.5",
946 "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz", 917 "resolved": "https://registry.npmjs.org/node-environment-flags/-/node-environment-flags-1.0.5.tgz",
@@ -951,15 +922,6 @@
951 "semver": "^5.7.0" 922 "semver": "^5.7.0"
952 } 923 }
953 }, 924 },
954 "npm-run-path": {
955 "version": "2.0.2",
956 "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz",
957 "integrity": "sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8=",
958 "dev": true,
959 "requires": {
960 "path-key": "^2.0.0"
961 }
962 },
963 "nth-check": { 925 "nth-check": {
964 "version": "1.0.2", 926 "version": "1.0.2",
965 "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz", 927 "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.2.tgz",
@@ -969,10 +931,10 @@
969 "boolbase": "~1.0.0" 931 "boolbase": "~1.0.0"
970 } 932 }
971 }, 933 },
972 "number-is-nan": { 934 "object-inspect": {
973 "version": "1.0.1", 935 "version": "1.7.0",
974 "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", 936 "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz",
975 "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", 937 "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==",
976 "dev": true 938 "dev": true
977 }, 939 },
978 "object-keys": { 940 "object-keys": {
@@ -1024,17 +986,6 @@
1024 "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", 986 "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=",
1025 "dev": true 987 "dev": true
1026 }, 988 },
1027 "os-locale": {
1028 "version": "3.1.0",
1029 "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-3.1.0.tgz",
1030 "integrity": "sha512-Z8l3R4wYWM40/52Z+S265okfFj8Kt2cC2MKY+xNi3kFs+XGI7WXu/I309QQQYbRW4ijiZ+yxs9pqEhJh0DqW3Q==",
1031 "dev": true,
1032 "requires": {
1033 "execa": "^1.0.0",
1034 "lcid": "^2.0.0",
1035 "mem": "^4.0.0"
1036 }
1037 },
1038 "os-tmpdir": { 989 "os-tmpdir": {
1039 "version": "1.0.2", 990 "version": "1.0.2",
1040 "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", 991 "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
@@ -1051,24 +1002,6 @@
1051 "os-tmpdir": "^1.0.0" 1002 "os-tmpdir": "^1.0.0"
1052 } 1003 }
1053 }, 1004 },
1054 "p-defer": {
1055 "version": "1.0.0",
1056 "resolved": "https://registry.npmjs.org/p-defer/-/p-defer-1.0.0.tgz",
1057 "integrity": "sha1-n26xgvbJqozXQwBKfU+WsZaw+ww=",
1058 "dev": true
1059 },
1060 "p-finally": {
1061 "version": "1.0.0",
1062 "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz",
1063 "integrity": "sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=",
1064 "dev": true
1065 },
1066 "p-is-promise": {
1067 "version": "2.1.0",
1068 "resolved": "https://registry.npmjs.org/p-is-promise/-/p-is-promise-2.1.0.tgz",
1069 "integrity": "sha512-Y3W0wlRPK8ZMRbNq97l4M5otioeA5lm1z7bkNkxCka8HSPjR0xRWmpCmc9utiaLP9Jb1eD8BgeIxTW4AIF45Pg==",
1070 "dev": true
1071 },
1072 "p-limit": { 1005 "p-limit": {
1073 "version": "2.2.1", 1006 "version": "2.2.1",
1074 "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", 1007 "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz",
@@ -1123,12 +1056,6 @@
1123 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", 1056 "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
1124 "dev": true 1057 "dev": true
1125 }, 1058 },
1126 "path-key": {
1127 "version": "2.0.1",
1128 "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz",
1129 "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=",
1130 "dev": true
1131 },
1132 "path-parse": { 1059 "path-parse": {
1133 "version": "1.0.6", 1060 "version": "1.0.6",
1134 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", 1061 "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz",
@@ -1142,21 +1069,11 @@
1142 "dev": true 1069 "dev": true
1143 }, 1070 },
1144 "prettier": { 1071 "prettier": {
1145 "version": "1.18.2", 1072 "version": "1.19.1",
1146 "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.18.2.tgz", 1073 "resolved": "https://registry.npmjs.org/prettier/-/prettier-1.19.1.tgz",
1147 "integrity": "sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==", 1074 "integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
1148 "dev": true 1075 "dev": true
1149 }, 1076 },
1150 "pump": {
1151 "version": "3.0.0",
1152 "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
1153 "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
1154 "dev": true,
1155 "requires": {
1156 "end-of-stream": "^1.1.0",
1157 "once": "^1.3.1"
1158 }
1159 },
1160 "read": { 1077 "read": {
1161 "version": "1.0.7", 1078 "version": "1.0.7",
1162 "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz", 1079 "resolved": "https://registry.npmjs.org/read/-/read-1.0.7.tgz",
@@ -1207,6 +1124,12 @@
1207 "path-parse": "^1.0.6" 1124 "path-parse": "^1.0.6"
1208 } 1125 }
1209 }, 1126 },
1127 "resolve-url": {
1128 "version": "0.2.1",
1129 "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz",
1130 "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=",
1131 "dev": true
1132 },
1210 "rimraf": { 1133 "rimraf": {
1211 "version": "2.7.1", 1134 "version": "2.7.1",
1212 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", 1135 "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
@@ -1217,9 +1140,9 @@
1217 } 1140 }
1218 }, 1141 },
1219 "rollup": { 1142 "rollup": {
1220 "version": "1.23.1", 1143 "version": "1.27.13",
1221 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.23.1.tgz", 1144 "resolved": "https://registry.npmjs.org/rollup/-/rollup-1.27.13.tgz",
1222 "integrity": "sha512-95C1GZQpr/NIA0kMUQmSjuMDQ45oZfPgDBcN0yZwBG7Kee//m7H68vgIyg+SPuyrTZ5PrXfyLK80OzXeKG5dAA==", 1145 "integrity": "sha512-hDi7M07MpmNSDE8YVwGVFA8L7n8jTLJ4lG65nMAijAyqBe//rtu4JdxjUBE7JqXfdpqxqDTbCDys9WcqdpsQvw==",
1223 "dev": true, 1146 "dev": true,
1224 "requires": { 1147 "requires": {
1225 "@types/estree": "*", 1148 "@types/estree": "*",
@@ -1281,6 +1204,16 @@
1281 } 1204 }
1282 } 1205 }
1283 }, 1206 },
1207 "rollup-plugin-sourcemaps": {
1208 "version": "0.4.2",
1209 "resolved": "https://registry.npmjs.org/rollup-plugin-sourcemaps/-/rollup-plugin-sourcemaps-0.4.2.tgz",
1210 "integrity": "sha1-YhJaqUCHqt97g+9N+vYptHMTXoc=",
1211 "dev": true,
1212 "requires": {
1213 "rollup-pluginutils": "^2.0.1",
1214 "source-map-resolve": "^0.5.0"
1215 }
1216 },
1284 "rollup-plugin-typescript": { 1217 "rollup-plugin-typescript": {
1285 "version": "1.0.1", 1218 "version": "1.0.1",
1286 "resolved": "https://registry.npmjs.org/rollup-plugin-typescript/-/rollup-plugin-typescript-1.0.1.tgz", 1219 "resolved": "https://registry.npmjs.org/rollup-plugin-typescript/-/rollup-plugin-typescript-1.0.1.tgz",
@@ -1318,14 +1251,15 @@
1318 "dev": true 1251 "dev": true
1319 }, 1252 },
1320 "seedrandom": { 1253 "seedrandom": {
1321 "version": "3.0.1", 1254 "version": "3.0.5",
1322 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.1.tgz", 1255 "resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-3.0.5.tgz",
1323 "integrity": "sha512-1/02Y/rUeU1CJBAGLebiC5Lbo5FnB22gQbIFFYTLkwvp1xdABZJH1sn4ZT1MzXmPpzv+Rf/Lu2NcsLJiK4rcDg==" 1256 "integrity": "sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg=="
1324 }, 1257 },
1325 "semver": { 1258 "semver": {
1326 "version": "5.7.0", 1259 "version": "5.7.1",
1327 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", 1260 "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
1328 "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==" 1261 "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==",
1262 "dev": true
1329 }, 1263 },
1330 "set-blocking": { 1264 "set-blocking": {
1331 "version": "2.0.0", 1265 "version": "2.0.0",
@@ -1333,21 +1267,6 @@
1333 "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", 1267 "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=",
1334 "dev": true 1268 "dev": true
1335 }, 1269 },
1336 "shebang-command": {
1337 "version": "1.2.0",
1338 "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz",
1339 "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=",
1340 "dev": true,
1341 "requires": {
1342 "shebang-regex": "^1.0.0"
1343 }
1344 },
1345 "shebang-regex": {
1346 "version": "1.0.0",
1347 "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz",
1348 "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=",
1349 "dev": true
1350 },
1351 "shelljs": { 1270 "shelljs": {
1352 "version": "0.8.3", 1271 "version": "0.8.3",
1353 "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz", 1272 "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.3.tgz",
@@ -1378,10 +1297,23 @@
1378 } 1297 }
1379 } 1298 }
1380 }, 1299 },
1381 "signal-exit": { 1300 "source-map-resolve": {
1382 "version": "3.0.2", 1301 "version": "0.5.2",
1383 "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", 1302 "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz",
1384 "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", 1303 "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==",
1304 "dev": true,
1305 "requires": {
1306 "atob": "^2.1.1",
1307 "decode-uri-component": "^0.2.0",
1308 "resolve-url": "^0.2.1",
1309 "source-map-url": "^0.4.0",
1310 "urix": "^0.1.0"
1311 }
1312 },
1313 "source-map-url": {
1314 "version": "0.4.0",
1315 "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz",
1316 "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=",
1385 "dev": true 1317 "dev": true
1386 }, 1318 },
1387 "sourcemap-codec": { 1319 "sourcemap-codec": {
@@ -1406,6 +1338,26 @@
1406 "strip-ansi": "^4.0.0" 1338 "strip-ansi": "^4.0.0"
1407 } 1339 }
1408 }, 1340 },
1341 "string.prototype.trimleft": {
1342 "version": "2.1.0",
1343 "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz",
1344 "integrity": "sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw==",
1345 "dev": true,
1346 "requires": {
1347 "define-properties": "^1.1.3",
1348 "function-bind": "^1.1.1"
1349 }
1350 },
1351 "string.prototype.trimright": {
1352 "version": "2.1.0",
1353 "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz",
1354 "integrity": "sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg==",
1355 "dev": true,
1356 "requires": {
1357 "define-properties": "^1.1.3",
1358 "function-bind": "^1.1.1"
1359 }
1360 },
1409 "string_decoder": { 1361 "string_decoder": {
1410 "version": "1.3.0", 1362 "version": "1.3.0",
1411 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", 1363 "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
@@ -1424,12 +1376,6 @@
1424 "ansi-regex": "^3.0.0" 1376 "ansi-regex": "^3.0.0"
1425 } 1377 }
1426 }, 1378 },
1427 "strip-eof": {
1428 "version": "1.0.0",
1429 "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz",
1430 "integrity": "sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=",
1431 "dev": true
1432 },
1433 "strip-json-comments": { 1379 "strip-json-comments": {
1434 "version": "2.0.1", 1380 "version": "2.0.1",
1435 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", 1381 "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
@@ -1437,9 +1383,9 @@
1437 "dev": true 1383 "dev": true
1438 }, 1384 },
1439 "supports-color": { 1385 "supports-color": {
1440 "version": "5.5.0", 1386 "version": "6.0.0",
1441 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", 1387 "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.0.0.tgz",
1442 "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", 1388 "integrity": "sha512-on9Kwidc1IUQo+bQdhi8+Tijpo0e1SS6RoGo2guUwn5vdaxw8RXOF9Vb2ws+ihWOmh4JnCJOvaziZWP1VABaLg==",
1443 "dev": true, 1389 "dev": true,
1444 "requires": { 1390 "requires": {
1445 "has-flag": "^3.0.0" 1391 "has-flag": "^3.0.0"
@@ -1461,16 +1407,16 @@
1461 "dev": true 1407 "dev": true
1462 }, 1408 },
1463 "tslint": { 1409 "tslint": {
1464 "version": "5.18.0", 1410 "version": "5.20.1",
1465 "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.18.0.tgz", 1411 "resolved": "https://registry.npmjs.org/tslint/-/tslint-5.20.1.tgz",
1466 "integrity": "sha512-Q3kXkuDEijQ37nXZZLKErssQVnwCV/+23gFEMROi8IlbaBG6tXqLPQJ5Wjcyt/yHPKBC+hD5SzuGaMora+ZS6w==", 1412 "integrity": "sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg==",
1467 "dev": true, 1413 "dev": true,
1468 "requires": { 1414 "requires": {
1469 "@babel/code-frame": "^7.0.0", 1415 "@babel/code-frame": "^7.0.0",
1470 "builtin-modules": "^1.1.1", 1416 "builtin-modules": "^1.1.1",
1471 "chalk": "^2.3.0", 1417 "chalk": "^2.3.0",
1472 "commander": "^2.12.1", 1418 "commander": "^2.12.1",
1473 "diff": "^3.2.0", 1419 "diff": "^4.0.1",
1474 "glob": "^7.1.1", 1420 "glob": "^7.1.1",
1475 "js-yaml": "^3.13.1", 1421 "js-yaml": "^3.13.1",
1476 "minimatch": "^3.0.4", 1422 "minimatch": "^3.0.4",
@@ -1479,6 +1425,14 @@
1479 "semver": "^5.3.0", 1425 "semver": "^5.3.0",
1480 "tslib": "^1.8.0", 1426 "tslib": "^1.8.0",
1481 "tsutils": "^2.29.0" 1427 "tsutils": "^2.29.0"
1428 },
1429 "dependencies": {
1430 "diff": {
1431 "version": "4.0.1",
1432 "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.1.tgz",
1433 "integrity": "sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q==",
1434 "dev": true
1435 }
1482 } 1436 }
1483 }, 1437 },
1484 "tslint-config-prettier": { 1438 "tslint-config-prettier": {
@@ -1487,6 +1441,17 @@
1487 "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==", 1441 "integrity": "sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg==",
1488 "dev": true 1442 "dev": true
1489 }, 1443 },
1444 "tslint-plugin-prettier": {
1445 "version": "2.0.1",
1446 "resolved": "https://registry.npmjs.org/tslint-plugin-prettier/-/tslint-plugin-prettier-2.0.1.tgz",
1447 "integrity": "sha512-4FX9JIx/1rKHIPJNfMb+ooX1gPk5Vg3vNi7+dyFYpLO+O57F4g+b/fo1+W/G0SUOkBLHB/YKScxjX/P+7ZT/Tw==",
1448 "dev": true,
1449 "requires": {
1450 "eslint-plugin-prettier": "^2.2.0",
1451 "lines-and-columns": "^1.1.6",
1452 "tslib": "^1.7.1"
1453 }
1454 },
1490 "tsutils": { 1455 "tsutils": {
1491 "version": "2.29.0", 1456 "version": "2.29.0",
1492 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz", 1457 "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz",
@@ -1513,9 +1478,9 @@
1513 } 1478 }
1514 }, 1479 },
1515 "typescript": { 1480 "typescript": {
1516 "version": "3.5.3", 1481 "version": "3.7.3",
1517 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.5.3.tgz", 1482 "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.7.3.tgz",
1518 "integrity": "sha512-ACzBtm/PhXBDId6a6sDJfroT2pOWt/oOnk4/dElG5G33ZL776N3Y6/6bKZJBFpd+b05F3Ct9qDjMeJmRWtE2/g==", 1483 "integrity": "sha512-Mcr/Qk7hXqFBXMN7p7Lusj1ktCBydylfQM/FZCk5glCNQJrCUKPkMHdo9R0MTFWsC/4kPFvDS0fDPvukfCkFsw==",
1519 "dev": true 1484 "dev": true
1520 }, 1485 },
1521 "uc.micro": { 1486 "uc.micro": {
@@ -1530,6 +1495,12 @@
1530 "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", 1495 "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=",
1531 "dev": true 1496 "dev": true
1532 }, 1497 },
1498 "urix": {
1499 "version": "0.1.0",
1500 "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz",
1501 "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=",
1502 "dev": true
1503 },
1533 "url-join": { 1504 "url-join": {
1534 "version": "1.1.0", 1505 "version": "1.1.0",
1535 "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz", 1506 "resolved": "https://registry.npmjs.org/url-join/-/url-join-1.1.0.tgz",
@@ -1543,9 +1514,9 @@
1543 "dev": true 1514 "dev": true
1544 }, 1515 },
1545 "vsce": { 1516 "vsce": {
1546 "version": "1.67.1", 1517 "version": "1.71.0",
1547 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.67.1.tgz", 1518 "resolved": "https://registry.npmjs.org/vsce/-/vsce-1.71.0.tgz",
1548 "integrity": "sha512-Y/0fnfaLs2cCfytTGmy4Cp1bf9BaxHO7020YePdUwxjAlPlZ9+lm74M9yEFEWXTIug0L0sMax1WMz0TnozIqxg==", 1519 "integrity": "sha512-7k+LPC4oJYPyyxs0a5nh4A8CleQ6+2EMPiAiX/bDyN+PmwJFm2FFPqLRxdIsIWfFnkW4ZMQBf10+W62dCRd9kQ==",
1549 "dev": true, 1520 "dev": true,
1550 "requires": { 1521 "requires": {
1551 "azure-devops-node-api": "^7.2.0", 1522 "azure-devops-node-api": "^7.2.0",
@@ -1571,41 +1542,48 @@
1571 } 1542 }
1572 }, 1543 },
1573 "vscode-jsonrpc": { 1544 "vscode-jsonrpc": {
1574 "version": "4.1.0-next.3", 1545 "version": "5.0.0-next.5",
1575 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-4.1.0-next.3.tgz", 1546 "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-5.0.0-next.5.tgz",
1576 "integrity": "sha512-Z6oxBiMks2+UADV1QHXVooSakjyhI+eHTnXzDyVvVMmegvSfkXk2w6mPEdSkaNHFBdtWW7n20H1yw2nA3A17mg==" 1547 "integrity": "sha512-k9akfglxWgr0dtLNscq2uBq48XJwnhf4EaDxn05KQowRwR0DkNML0zeYqFRLtXZe6x5vpL5ppyu4o6GqL+23YQ=="
1577 }, 1548 },
1578 "vscode-languageclient": { 1549 "vscode-languageclient": {
1579 "version": "5.3.0-next.4", 1550 "version": "6.0.0-next.9",
1580 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-5.3.0-next.4.tgz", 1551 "resolved": "https://registry.npmjs.org/vscode-languageclient/-/vscode-languageclient-6.0.0-next.9.tgz",
1581 "integrity": "sha512-RODuzXErVpJRSgHv+Xei8fwQtZ/iZOWPCqlLl07NTtkzgTAepJf9r4EioZVuTviGJ5DEJ9xs0bjrit8shKtW6Q==", 1552 "integrity": "sha512-NEpeeFM9FKrrRqlBHXGfwpkhtnjruDz3zfFBP+Cymr10qigAEtE/JsODJsIG/ErGqjh3/JXxu8SUOVTGu5oK+w==",
1582 "requires": { 1553 "requires": {
1583 "semver": "^5.5.0", 1554 "semver": "^6.3.0",
1584 "vscode-languageserver-protocol": "3.15.0-next.4" 1555 "vscode-languageserver-protocol": "^3.15.0-next.14"
1556 },
1557 "dependencies": {
1558 "semver": {
1559 "version": "6.3.0",
1560 "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz",
1561 "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw=="
1562 }
1585 } 1563 }
1586 }, 1564 },
1587 "vscode-languageserver-protocol": { 1565 "vscode-languageserver-protocol": {
1588 "version": "3.15.0-next.4", 1566 "version": "3.15.0-next.14",
1589 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.4.tgz", 1567 "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.15.0-next.14.tgz",
1590 "integrity": "sha512-4AgisQ8GWa3irdRu3/UNr3brcSSm0oobmoV1eSOnV7JM32lYyXDnSKB7RuTTXvaAjD/0xQJLEGhkyGHS5gbywA==", 1568 "integrity": "sha512-xUwwno6Q6RFd2Z2EWV9D3dQlsKPnHyiZMNWq+EC7JJdp2WH1gRlD+KPX4UGRCnJK0WI5omqHV313IESPwRY5xA==",
1591 "requires": { 1569 "requires": {
1592 "vscode-jsonrpc": "^4.1.0-next.1", 1570 "vscode-jsonrpc": "^5.0.0-next.5",
1593 "vscode-languageserver-types": "3.15.0-next.1" 1571 "vscode-languageserver-types": "^3.15.0-next.9"
1594 } 1572 }
1595 }, 1573 },
1596 "vscode-languageserver-types": { 1574 "vscode-languageserver-types": {
1597 "version": "3.15.0-next.1", 1575 "version": "3.15.0-next.9",
1598 "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.1.tgz", 1576 "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.15.0-next.9.tgz",
1599 "integrity": "sha512-R0kzmaI8gOGEoU7b9huYQAzgZzRQ/5Q8HKjsIUdfz0MjXcBZ4tr1ik1So1p1O5kGrI1VTCd22Fw/wI7ECGoIPw==" 1577 "integrity": "sha512-Rl/8qJ6932nrHCdPn+9y0x08uLVQaSLRG+U4JzhyKpWU4eJbVaDRoAcz1Llj7CErJGbPr6kdBvShPy5fRfR+Uw=="
1600 }, 1578 },
1601 "vscode-test": { 1579 "vscode-test": {
1602 "version": "1.2.0", 1580 "version": "1.3.0",
1603 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.2.0.tgz", 1581 "resolved": "https://registry.npmjs.org/vscode-test/-/vscode-test-1.3.0.tgz",
1604 "integrity": "sha512-aowqgc8gZe0eflzVUXsBjBrlsJ8eC35kfgfSEeHu9PKA1vQKm/3rVK43TlbxGue8hKtZBElNAJ5QuYklR/vLJA==", 1582 "integrity": "sha512-LddukcBiSU2FVTDr3c1D8lwkiOvwlJdDL2hqVbn6gIz+rpTqUCkMZSKYm94Y1v0WXlHSDQBsXyY+tchWQgGVsw==",
1605 "dev": true, 1583 "dev": true,
1606 "requires": { 1584 "requires": {
1607 "http-proxy-agent": "^2.1.0", 1585 "http-proxy-agent": "^2.1.0",
1608 "https-proxy-agent": "^2.2.1", 1586 "https-proxy-agent": "^2.2.4",
1609 "rimraf": "^2.6.3" 1587 "rimraf": "^2.6.3"
1610 } 1588 }
1611 }, 1589 },
@@ -1634,48 +1612,40 @@
1634 } 1612 }
1635 }, 1613 },
1636 "wrap-ansi": { 1614 "wrap-ansi": {
1637 "version": "2.1.0", 1615 "version": "5.1.0",
1638 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", 1616 "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz",
1639 "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", 1617 "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==",
1640 "dev": true, 1618 "dev": true,
1641 "requires": { 1619 "requires": {
1642 "string-width": "^1.0.1", 1620 "ansi-styles": "^3.2.0",
1643 "strip-ansi": "^3.0.1" 1621 "string-width": "^3.0.0",
1622 "strip-ansi": "^5.0.0"
1644 }, 1623 },
1645 "dependencies": { 1624 "dependencies": {
1646 "ansi-regex": { 1625 "ansi-regex": {
1647 "version": "2.1.1", 1626 "version": "4.1.0",
1648 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", 1627 "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz",
1649 "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", 1628 "integrity": "sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg==",
1650 "dev": true 1629 "dev": true
1651 }, 1630 },
1652 "is-fullwidth-code-point": {
1653 "version": "1.0.0",
1654 "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
1655 "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
1656 "dev": true,
1657 "requires": {
1658 "number-is-nan": "^1.0.0"
1659 }
1660 },
1661 "string-width": { 1631 "string-width": {
1662 "version": "1.0.2", 1632 "version": "3.1.0",
1663 "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", 1633 "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz",
1664 "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", 1634 "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==",
1665 "dev": true, 1635 "dev": true,
1666 "requires": { 1636 "requires": {
1667 "code-point-at": "^1.0.0", 1637 "emoji-regex": "^7.0.1",
1668 "is-fullwidth-code-point": "^1.0.0", 1638 "is-fullwidth-code-point": "^2.0.0",
1669 "strip-ansi": "^3.0.0" 1639 "strip-ansi": "^5.1.0"
1670 } 1640 }
1671 }, 1641 },
1672 "strip-ansi": { 1642 "strip-ansi": {
1673 "version": "3.0.1", 1643 "version": "5.2.0",
1674 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", 1644 "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz",
1675 "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", 1645 "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==",
1676 "dev": true, 1646 "dev": true,
1677 "requires": { 1647 "requires": {
1678 "ansi-regex": "^2.0.0" 1648 "ansi-regex": "^4.1.0"
1679 } 1649 }
1680 } 1650 }
1681 } 1651 }
@@ -1693,22 +1663,21 @@
1693 "dev": true 1663 "dev": true
1694 }, 1664 },
1695 "yargs": { 1665 "yargs": {
1696 "version": "13.2.2", 1666 "version": "13.3.0",
1697 "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.2.2.tgz", 1667 "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.0.tgz",
1698 "integrity": "sha512-WyEoxgyTD3w5XRpAQNYUB9ycVH/PQrToaTXdYXRdOXvEy1l19br+VJsc0vcO8PTGg5ro/l/GY7F/JMEBmI0BxA==", 1668 "integrity": "sha512-2eehun/8ALW8TLoIl7MVaRUrg+yCnenu8B4kBlRxj3GJGDKU1Og7sMXPNm1BYyM1DOJmTZ4YeN/Nwxv+8XJsUA==",
1699 "dev": true, 1669 "dev": true,
1700 "requires": { 1670 "requires": {
1701 "cliui": "^4.0.0", 1671 "cliui": "^5.0.0",
1702 "find-up": "^3.0.0", 1672 "find-up": "^3.0.0",
1703 "get-caller-file": "^2.0.1", 1673 "get-caller-file": "^2.0.1",
1704 "os-locale": "^3.1.0",
1705 "require-directory": "^2.1.1", 1674 "require-directory": "^2.1.1",
1706 "require-main-filename": "^2.0.0", 1675 "require-main-filename": "^2.0.0",
1707 "set-blocking": "^2.0.0", 1676 "set-blocking": "^2.0.0",
1708 "string-width": "^3.0.0", 1677 "string-width": "^3.0.0",
1709 "which-module": "^2.0.0", 1678 "which-module": "^2.0.0",
1710 "y18n": "^4.0.0", 1679 "y18n": "^4.0.0",
1711 "yargs-parser": "^13.0.0" 1680 "yargs-parser": "^13.1.1"
1712 }, 1681 },
1713 "dependencies": { 1682 "dependencies": {
1714 "ansi-regex": { 1683 "ansi-regex": {
@@ -1740,9 +1709,9 @@
1740 } 1709 }
1741 }, 1710 },
1742 "yargs-parser": { 1711 "yargs-parser": {
1743 "version": "13.0.0", 1712 "version": "13.1.1",
1744 "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.0.0.tgz", 1713 "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.1.tgz",
1745 "integrity": "sha512-w2LXjoL8oRdRQN+hOyppuXs+V/fVAYtpcrRxZuF7Kt/Oc+Jr2uAcVntaUTNT6w5ihoWfFDpNY8CPx1QskxZ/pw==", 1714 "integrity": "sha512-oVAVsHz6uFrg3XQheFII8ESO2ssAf9luWuAd6Wexsu4F3OtIW0o8IribPXYrD4WC24LWtPrJlGy87y5udK+dxQ==",
1746 "dev": true, 1715 "dev": true,
1747 "requires": { 1716 "requires": {
1748 "camelcase": "^5.0.0", 1717 "camelcase": "^5.0.0",
@@ -1750,58 +1719,14 @@
1750 } 1719 }
1751 }, 1720 },
1752 "yargs-unparser": { 1721 "yargs-unparser": {
1753 "version": "1.5.0", 1722 "version": "1.6.0",
1754 "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.5.0.tgz", 1723 "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-1.6.0.tgz",
1755 "integrity": "sha512-HK25qidFTCVuj/D1VfNiEndpLIeJN78aqgR23nL3y4N0U/91cOAzqfHlF8n2BvoNDcZmJKin3ddNSvOxSr8flw==", 1724 "integrity": "sha512-W9tKgmSn0DpSatfri0nx52Joq5hVXgeLiqR/5G0sZNDoLZFOr/xjBUDcShCOGNsBnEMNo1KAMBkTej1Hm62HTw==",
1756 "dev": true, 1725 "dev": true,
1757 "requires": { 1726 "requires": {
1758 "flat": "^4.1.0", 1727 "flat": "^4.1.0",
1759 "lodash": "^4.17.11", 1728 "lodash": "^4.17.15",
1760 "yargs": "^12.0.5" 1729 "yargs": "^13.3.0"
1761 },
1762 "dependencies": {
1763 "get-caller-file": {
1764 "version": "1.0.3",
1765 "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz",
1766 "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==",
1767 "dev": true
1768 },
1769 "require-main-filename": {
1770 "version": "1.0.1",
1771 "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz",
1772 "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=",
1773 "dev": true
1774 },
1775 "yargs": {
1776 "version": "12.0.5",
1777 "resolved": "https://registry.npmjs.org/yargs/-/yargs-12.0.5.tgz",
1778 "integrity": "sha512-Lhz8TLaYnxq/2ObqHDql8dX8CJi97oHxrjUcYtzKbbykPtVW9WB+poxI+NM2UIzsMgNCZTIf0AQwsjK5yMAqZw==",
1779 "dev": true,
1780 "requires": {
1781 "cliui": "^4.0.0",
1782 "decamelize": "^1.2.0",
1783 "find-up": "^3.0.0",
1784 "get-caller-file": "^1.0.1",
1785 "os-locale": "^3.0.0",
1786 "require-directory": "^2.1.1",
1787 "require-main-filename": "^1.0.1",
1788 "set-blocking": "^2.0.0",
1789 "string-width": "^2.0.0",
1790 "which-module": "^2.0.0",
1791 "y18n": "^3.2.1 || ^4.0.0",
1792 "yargs-parser": "^11.1.1"
1793 }
1794 },
1795 "yargs-parser": {
1796 "version": "11.1.1",
1797 "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-11.1.1.tgz",
1798 "integrity": "sha512-C6kB/WJDiaxONLJQnF8ccx9SEeoTTLek8RVbaOIsrAUS8VrBEXfmeSnCZxygc+XC2sNMBIwOOnfcxiynjHsVSQ==",
1799 "dev": true,
1800 "requires": {
1801 "camelcase": "^5.0.0",
1802 "decamelize": "^1.2.0"
1803 }
1804 }
1805 } 1730 }
1806 }, 1731 },
1807 "yauzl": { 1732 "yauzl": {
diff --git a/editors/code/package.json b/editors/code/package.json
index e21dfa174..8e7046418 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -13,7 +13,7 @@
13 "Other" 13 "Other"
14 ], 14 ],
15 "engines": { 15 "engines": {
16 "vscode": "^1.37.0" 16 "vscode": "^1.41.0"
17 }, 17 },
18 "scripts": { 18 "scripts": {
19 "vscode:prepublish": "npm run compile", 19 "vscode:prepublish": "npm run compile",
@@ -27,33 +27,37 @@
27 "travis": "npm run compile && npm run test && npm run lint && npm run prettier -- --write && git diff --exit-code" 27 "travis": "npm run compile && npm run test && npm run lint && npm run prettier -- --write && git diff --exit-code"
28 }, 28 },
29 "prettier": { 29 "prettier": {
30 "singleQuote": true,
30 "tabWidth": 4, 31 "tabWidth": 4,
31 "singleQuote": true 32 "trailingComma": "all"
32 }, 33 },
33 "dependencies": { 34 "dependencies": {
34 "seedrandom": "^3.0.1", 35 "lookpath": "^1.0.4",
35 "vscode-languageclient": "^5.3.0-next.4", 36 "seedrandom": "^3.0.5",
37 "vscode-languageclient": "^6.0.0-next.9",
36 "jsonc-parser": "^2.1.0" 38 "jsonc-parser": "^2.1.0"
37 }, 39 },
38 "devDependencies": { 40 "devDependencies": {
39 "@types/glob": "^7.1.1", 41 "@types/glob": "^7.1.1",
40 "@types/mocha": "^5.2.7", 42 "@types/mocha": "^5.2.7",
41 "@types/node": "^10.14.13", 43 "@types/node": "^12.12.21",
42 "@types/seedrandom": "^2.4.28", 44 "@types/seedrandom": "^2.4.28",
43 "@types/vscode": "^1.37.0", 45 "@types/vscode": "^1.41.0",
44 "glob": "^7.1.4", 46 "glob": "^7.1.6",
45 "mocha": "^6.2.0", 47 "mocha": "^6.2.2",
46 "prettier": "^1.18.2", 48 "prettier": "^1.19.1",
47 "rollup": "^1.23.1", 49 "rollup": "^1.27.13",
48 "rollup-plugin-commonjs": "^10.1.0", 50 "rollup-plugin-commonjs": "^10.1.0",
49 "rollup-plugin-node-resolve": "^5.2.0", 51 "rollup-plugin-node-resolve": "^5.2.0",
52 "rollup-plugin-sourcemaps": "^0.4.2",
50 "rollup-plugin-typescript": "^1.0.1", 53 "rollup-plugin-typescript": "^1.0.1",
51 "shx": "^0.3.1", 54 "shx": "^0.3.1",
52 "tslint": "^5.18.0", 55 "tslint": "^5.20.1",
53 "tslint-config-prettier": "^1.18.0", 56 "tslint-config-prettier": "^1.18.0",
54 "typescript": "^3.5.3", 57 "tslint-plugin-prettier": "^2.0.1",
55 "vsce": "^1.67.0", 58 "typescript": "^3.7.3",
56 "vscode-test": "^1.2.0" 59 "vsce": "^1.71.0",
60 "vscode-test": "^1.3.0"
57 }, 61 },
58 "activationEvents": [ 62 "activationEvents": [
59 "onLanguage:rust", 63 "onLanguage:rust",
@@ -279,7 +283,7 @@
279 }, 283 },
280 "rust-analyzer.useClientWatching": { 284 "rust-analyzer.useClientWatching": {
281 "type": "boolean", 285 "type": "boolean",
282 "default": false, 286 "default": true,
283 "description": "client provided file watching instead of notify watching." 287 "description": "client provided file watching instead of notify watching."
284 }, 288 },
285 "rust-analyzer.cargo-watch.arguments": { 289 "rust-analyzer.cargo-watch.arguments": {
@@ -297,6 +301,11 @@
297 "description": "A list of patterns for cargo-watch to ignore (will be passed as `--ignore`)", 301 "description": "A list of patterns for cargo-watch to ignore (will be passed as `--ignore`)",
298 "default": [] 302 "default": []
299 }, 303 },
304 "rust-analyzer.cargo-watch.allTargets": {
305 "type": "boolean",
306 "description": "Check all targets and tests (will be passed as `--all-targets`)",
307 "default": true
308 },
300 "rust-analyzer.trace.server": { 309 "rust-analyzer.trace.server": {
301 "type": "string", 310 "type": "string",
302 "scope": "window", 311 "scope": "window",
@@ -338,6 +347,21 @@
338 "type": "number", 347 "type": "number",
339 "default": 20, 348 "default": 20,
340 "description": "Maximum length for inlay hints" 349 "description": "Maximum length for inlay hints"
350 },
351 "rust-analyzer.cargoFeatures.noDefaultFeatures": {
352 "type": "boolean",
353 "default": false,
354 "description": "Do not activate the `default` feature"
355 },
356 "rust-analyzer.cargoFeatures.allFeatures": {
357 "type": "boolean",
358 "default": true,
359 "description": "Activate all available features"
360 },
361 "rust-analyzer.cargoFeatures.features": {
362 "type": "array",
363 "default": [],
364 "description": "List of features to activate"
341 } 365 }
342 } 366 }
343 }, 367 },
@@ -358,6 +382,20 @@
358 "column": 3 382 "column": 3
359 } 383 }
360 ] 384 ]
385 },
386 {
387 "name": "rustc-json",
388 "patterns": [
389 {
390 "regexp": "^.*\"message\":{\"message\":\"([^\"]*).*?\"file_name\":\"([^\"]+).*?\"line_start\":(\\d+).*?\"line_end\":(\\d+).*?\"column_start\":(\\d+).*?\"column_end\":(\\d+).*}$",
391 "message": 1,
392 "file": 2,
393 "line": 3,
394 "endLine": 4,
395 "column": 5,
396 "endColumn": 6
397 }
398 ]
361 } 399 }
362 ], 400 ],
363 "problemMatchers": [ 401 "problemMatchers": [
@@ -370,6 +408,14 @@
370 "pattern": "$rustc" 408 "pattern": "$rustc"
371 }, 409 },
372 { 410 {
411 "name": "rustc-json",
412 "fileLocation": [
413 "relative",
414 "${workspaceRoot}"
415 ],
416 "pattern": "$rustc-json"
417 },
418 {
373 "name": "rustc-watch", 419 "name": "rustc-watch",
374 "fileLocation": [ 420 "fileLocation": [
375 "relative", 421 "relative",
@@ -483,6 +529,33 @@
483 } 529 }
484 }, 530 },
485 { 531 {
532 "id": "ralsp.literal.numeric",
533 "description": "Color for numeric literals",
534 "defaults": {
535 "dark": "#BECEA8",
536 "light": "#09885A",
537 "highContrast": "#B5CEA8"
538 }
539 },
540 {
541 "id": "ralsp.literal.char",
542 "description": "Color for character literals",
543 "defaults": {
544 "dark": "#BECEA8",
545 "light": "#09885A",
546 "highContrast": "#B5CEA8"
547 }
548 },
549 {
550 "id": "ralsp.literal.byte",
551 "description": "Color for byte literals",
552 "defaults": {
553 "dark": "#BECEA8",
554 "light": "#09885A",
555 "highContrast": "#B5CEA8"
556 }
557 },
558 {
486 "id": "ralsp.macro", 559 "id": "ralsp.macro",
487 "description": "Color for macros", 560 "description": "Color for macros",
488 "defaults": { 561 "defaults": {
@@ -502,7 +575,43 @@
502 }, 575 },
503 { 576 {
504 "id": "ralsp.type", 577 "id": "ralsp.type",
505 "description": "Color for types", 578 "description": "Color for other types (traits, aliases..)",
579 "defaults": {
580 "dark": "#4EC9B0",
581 "light": "#267F99",
582 "highContrast": "#4EC9B0"
583 }
584 },
585 {
586 "id": "ralsp.type.builtin",
587 "description": "Color for built-in types (&str, bool, u16, u32)",
588 "defaults": {
589 "dark": "#4EC9B0",
590 "light": "#267F99",
591 "highContrast": "#4EC9B0"
592 }
593 },
594 {
595 "id": "ralsp.type.lifetime",
596 "description": "Color for lifetimes parameters",
597 "defaults": {
598 "dark": "#4EC9B0",
599 "light": "#267F99",
600 "highContrast": "#4EC9B0"
601 }
602 },
603 {
604 "id": "ralsp.type.self",
605 "description": "Color for `Self` param type",
606 "defaults": {
607 "dark": "#4EC9B0",
608 "light": "#267F99",
609 "highContrast": "#4EC9B0"
610 }
611 },
612 {
613 "id": "ralsp.type.param",
614 "description": "Color for type parameters",
506 "defaults": { 615 "defaults": {
507 "dark": "#4EC9B0", 616 "dark": "#4EC9B0",
508 "light": "#267F99", 617 "light": "#267F99",
diff --git a/editors/code/rollup.config.js b/editors/code/rollup.config.js
index a023b8c3f..1b222bbe7 100644
--- a/editors/code/rollup.config.js
+++ b/editors/code/rollup.config.js
@@ -1,12 +1,14 @@
1import typescript from 'rollup-plugin-typescript'; 1import typescript from 'rollup-plugin-typescript';
2import resolve from 'rollup-plugin-node-resolve'; 2import resolve from 'rollup-plugin-node-resolve';
3import commonjs from 'rollup-plugin-commonjs'; 3import commonjs from 'rollup-plugin-commonjs';
4import sourcemaps from 'rollup-plugin-sourcemaps'
4import nodeBuiltins from 'builtin-modules'; 5import nodeBuiltins from 'builtin-modules';
5 6
6export default { 7export default {
7 input: './src/extension.ts', 8 input: './src/extension.ts',
8 plugins: [ 9 plugins: [
9 typescript(), 10 typescript(),
11 sourcemaps(),
10 resolve(), 12 resolve(),
11 commonjs({ 13 commonjs({
12 namedExports: { 14 namedExports: {
@@ -22,6 +24,7 @@ export default {
22 ], 24 ],
23 output: { 25 output: {
24 file: './bundle/extension.js', 26 file: './bundle/extension.js',
27 sourcemap: true,
25 format: 'cjs', 28 format: 'cjs',
26 } 29 }
27}; 30};
diff --git a/editors/code/src/commands/analyzer_status.ts b/editors/code/src/commands/analyzer_status.ts
index 63f82c92d..2777ced24 100644
--- a/editors/code/src/commands/analyzer_status.ts
+++ b/editors/code/src/commands/analyzer_status.ts
@@ -9,7 +9,7 @@ export class TextDocumentContentProvider
9 public syntaxTree: string = 'Not available'; 9 public syntaxTree: string = 'Not available';
10 10
11 public provideTextDocumentContent( 11 public provideTextDocumentContent(
12 uri: vscode.Uri 12 _uri: vscode.Uri,
13 ): vscode.ProviderResult<string> { 13 ): vscode.ProviderResult<string> {
14 const editor = vscode.window.activeTextEditor; 14 const editor = vscode.window.activeTextEditor;
15 if (editor == null) { 15 if (editor == null) {
@@ -17,7 +17,7 @@ export class TextDocumentContentProvider
17 } 17 }
18 return Server.client.sendRequest<string>( 18 return Server.client.sendRequest<string>(
19 'rust-analyzer/analyzerStatus', 19 'rust-analyzer/analyzerStatus',
20 null 20 null,
21 ); 21 );
22 } 22 }
23 23
@@ -35,8 +35,8 @@ export function makeCommand(context: vscode.ExtensionContext) {
35 context.subscriptions.push( 35 context.subscriptions.push(
36 vscode.workspace.registerTextDocumentContentProvider( 36 vscode.workspace.registerTextDocumentContentProvider(
37 'rust-analyzer-status', 37 'rust-analyzer-status',
38 textDocumentContentProvider 38 textDocumentContentProvider,
39 ) 39 ),
40 ); 40 );
41 41
42 context.subscriptions.push({ 42 context.subscriptions.push({
@@ -44,21 +44,21 @@ export function makeCommand(context: vscode.ExtensionContext) {
44 if (poller != null) { 44 if (poller != null) {
45 clearInterval(poller); 45 clearInterval(poller);
46 } 46 }
47 } 47 },
48 }); 48 });
49 49
50 return async function handle() { 50 return async function handle() {
51 if (poller == null) { 51 if (poller == null) {
52 poller = setInterval( 52 poller = setInterval(
53 () => textDocumentContentProvider.eventEmitter.fire(statusUri), 53 () => textDocumentContentProvider.eventEmitter.fire(statusUri),
54 1000 54 1000,
55 ); 55 );
56 } 56 }
57 const document = await vscode.workspace.openTextDocument(statusUri); 57 const document = await vscode.workspace.openTextDocument(statusUri);
58 return vscode.window.showTextDocument( 58 return vscode.window.showTextDocument(
59 document, 59 document,
60 vscode.ViewColumn.Two, 60 vscode.ViewColumn.Two,
61 true 61 true,
62 ); 62 );
63 }; 63 };
64} 64}
diff --git a/editors/code/src/commands/apply_source_change.ts b/editors/code/src/commands/apply_source_change.ts
index dcd074b8b..8167398b1 100644
--- a/editors/code/src/commands/apply_source_change.ts
+++ b/editors/code/src/commands/apply_source_change.ts
@@ -11,7 +11,7 @@ export interface SourceChange {
11 11
12export async function handle(change: SourceChange) { 12export async function handle(change: SourceChange) {
13 const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit( 13 const wsEdit = Server.client.protocol2CodeConverter.asWorkspaceEdit(
14 change.workspaceEdit 14 change.workspaceEdit,
15 ); 15 );
16 let created; 16 let created;
17 let moved; 17 let moved;
@@ -33,10 +33,10 @@ export async function handle(change: SourceChange) {
33 await vscode.window.showTextDocument(doc); 33 await vscode.window.showTextDocument(doc);
34 } else if (toReveal) { 34 } else if (toReveal) {
35 const uri = Server.client.protocol2CodeConverter.asUri( 35 const uri = Server.client.protocol2CodeConverter.asUri(
36 toReveal.textDocument.uri 36 toReveal.textDocument.uri,
37 ); 37 );
38 const position = Server.client.protocol2CodeConverter.asPosition( 38 const position = Server.client.protocol2CodeConverter.asPosition(
39 toReveal.position 39 toReveal.position,
40 ); 40 );
41 const editor = vscode.window.activeTextEditor; 41 const editor = vscode.window.activeTextEditor;
42 if (!editor || editor.document.uri.toString() !== uri.toString()) { 42 if (!editor || editor.document.uri.toString() !== uri.toString()) {
@@ -48,7 +48,7 @@ export async function handle(change: SourceChange) {
48 editor.selection = new vscode.Selection(position, position); 48 editor.selection = new vscode.Selection(position, position);
49 editor.revealRange( 49 editor.revealRange(
50 new vscode.Range(position, position), 50 new vscode.Range(position, position),
51 vscode.TextEditorRevealType.Default 51 vscode.TextEditorRevealType.Default,
52 ); 52 );
53 } 53 }
54} 54}
diff --git a/editors/code/src/commands/cargo_watch.ts b/editors/code/src/commands/cargo_watch.ts
index 59d4ba97a..ac62bdd48 100644
--- a/editors/code/src/commands/cargo_watch.ts
+++ b/editors/code/src/commands/cargo_watch.ts
@@ -9,13 +9,13 @@ import { StatusDisplay } from './watch_status';
9 9
10import { 10import {
11 mapRustDiagnosticToVsCode, 11 mapRustDiagnosticToVsCode,
12 RustDiagnostic 12 RustDiagnostic,
13} from '../utils/diagnostics/rust'; 13} from '../utils/diagnostics/rust';
14import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection'; 14import SuggestedFixCollection from '../utils/diagnostics/SuggestedFixCollection';
15import { areDiagnosticsEqual } from '../utils/diagnostics/vscode'; 15import { areDiagnosticsEqual } from '../utils/diagnostics/vscode';
16 16
17export async function registerCargoWatchProvider( 17export async function registerCargoWatchProvider(
18 subscriptions: vscode.Disposable[] 18 subscriptions: vscode.Disposable[],
19): Promise<CargoWatchProvider | undefined> { 19): Promise<CargoWatchProvider | undefined> {
20 let cargoExists = false; 20 let cargoExists = false;
21 21
@@ -30,7 +30,7 @@ export async function registerCargoWatchProvider(
30 30
31 if (!cargoExists) { 31 if (!cargoExists) {
32 vscode.window.showErrorMessage( 32 vscode.window.showErrorMessage(
33 `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}` 33 `Couldn\'t find \'Cargo.toml\' at ${cargoTomlPath}`,
34 ); 34 );
35 return; 35 return;
36 } 36 }
@@ -52,13 +52,13 @@ export class CargoWatchProvider implements vscode.Disposable {
52 52
53 constructor() { 53 constructor() {
54 this.diagnosticCollection = vscode.languages.createDiagnosticCollection( 54 this.diagnosticCollection = vscode.languages.createDiagnosticCollection(
55 'rustc' 55 'rustc',
56 ); 56 );
57 this.statusDisplay = new StatusDisplay( 57 this.statusDisplay = new StatusDisplay(
58 Server.config.cargoWatchOptions.command 58 Server.config.cargoWatchOptions.command,
59 ); 59 );
60 this.outputChannel = vscode.window.createOutputChannel( 60 this.outputChannel = vscode.window.createOutputChannel(
61 'Cargo Watch Trace' 61 'Cargo Watch Trace',
62 ); 62 );
63 63
64 // Track `rustc`'s suggested fixes so we can convert them to code actions 64 // Track `rustc`'s suggested fixes so we can convert them to code actions
@@ -68,22 +68,24 @@ export class CargoWatchProvider implements vscode.Disposable {
68 this.suggestedFixCollection, 68 this.suggestedFixCollection,
69 { 69 {
70 providedCodeActionKinds: 70 providedCodeActionKinds:
71 SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS 71 SuggestedFixCollection.PROVIDED_CODE_ACTION_KINDS,
72 } 72 },
73 ); 73 );
74 } 74 }
75 75
76 public start() { 76 public start() {
77 if (this.cargoProcess) { 77 if (this.cargoProcess) {
78 vscode.window.showInformationMessage( 78 vscode.window.showInformationMessage(
79 'Cargo Watch is already running' 79 'Cargo Watch is already running',
80 ); 80 );
81 return; 81 return;
82 } 82 }
83 83
84 let args = 84 let args =
85 Server.config.cargoWatchOptions.command + 85 Server.config.cargoWatchOptions.command + ' --message-format json';
86 ' --all-targets --message-format json'; 86 if (Server.config.cargoWatchOptions.allTargets) {
87 args += ' --all-targets';
88 }
87 if (Server.config.cargoWatchOptions.command.length > 0) { 89 if (Server.config.cargoWatchOptions.command.length > 0) {
88 // Excape the double quote string: 90 // Excape the double quote string:
89 args += ' ' + Server.config.cargoWatchOptions.arguments; 91 args += ' ' + Server.config.cargoWatchOptions.arguments;
@@ -95,7 +97,7 @@ export class CargoWatchProvider implements vscode.Disposable {
95 97
96 const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce( 98 const ignoreFlags = Server.config.cargoWatchOptions.ignore.reduce(
97 (flags, pattern) => [...flags, '--ignore', pattern], 99 (flags, pattern) => [...flags, '--ignore', pattern],
98 [] as string[] 100 [] as string[],
99 ); 101 );
100 102
101 // Start the cargo watch with json message 103 // Start the cargo watch with json message
@@ -105,12 +107,17 @@ export class CargoWatchProvider implements vscode.Disposable {
105 { 107 {
106 stdio: ['ignore', 'pipe', 'pipe'], 108 stdio: ['ignore', 'pipe', 'pipe'],
107 cwd: vscode.workspace.rootPath, 109 cwd: vscode.workspace.rootPath,
108 windowsVerbatimArguments: true 110 windowsVerbatimArguments: true,
109 } 111 },
110 ); 112 );
111 113
114 if (!this.cargoProcess) {
115 vscode.window.showErrorMessage('Cargo Watch failed to start');
116 return;
117 }
118
112 const stdoutData = new LineBuffer(); 119 const stdoutData = new LineBuffer();
113 this.cargoProcess.stdout.on('data', (s: string) => { 120 this.cargoProcess.stdout?.on('data', (s: string) => {
114 stdoutData.processOutput(s, line => { 121 stdoutData.processOutput(s, line => {
115 this.logInfo(line); 122 this.logInfo(line);
116 try { 123 try {
@@ -122,7 +129,7 @@ export class CargoWatchProvider implements vscode.Disposable {
122 }); 129 });
123 130
124 const stderrData = new LineBuffer(); 131 const stderrData = new LineBuffer();
125 this.cargoProcess.stderr.on('data', (s: string) => { 132 this.cargoProcess.stderr?.on('data', (s: string) => {
126 stderrData.processOutput(s, line => { 133 stderrData.processOutput(s, line => {
127 this.logError('Error on cargo-watch : {\n' + line + '}\n'); 134 this.logError('Error on cargo-watch : {\n' + line + '}\n');
128 }); 135 });
@@ -130,7 +137,7 @@ export class CargoWatchProvider implements vscode.Disposable {
130 137
131 this.cargoProcess.on('error', (err: Error) => { 138 this.cargoProcess.on('error', (err: Error) => {
132 this.logError( 139 this.logError(
133 'Error on cargo-watch process : {\n' + err.message + '}\n' 140 'Error on cargo-watch process : {\n' + err.message + '}\n',
134 ); 141 );
135 }); 142 });
136 143
@@ -223,12 +230,12 @@ export class CargoWatchProvider implements vscode.Disposable {
223 const fileUri = location.uri; 230 const fileUri = location.uri;
224 231
225 const diagnostics: vscode.Diagnostic[] = [ 232 const diagnostics: vscode.Diagnostic[] = [
226 ...(this.diagnosticCollection!.get(fileUri) || []) 233 ...(this.diagnosticCollection!.get(fileUri) || []),
227 ]; 234 ];
228 235
229 // If we're building multiple targets it's possible we've already seen this diagnostic 236 // If we're building multiple targets it's possible we've already seen this diagnostic
230 const isDuplicate = diagnostics.some(d => 237 const isDuplicate = diagnostics.some(d =>
231 areDiagnosticsEqual(d, diagnostic) 238 areDiagnosticsEqual(d, diagnostic),
232 ); 239 );
233 if (isDuplicate) { 240 if (isDuplicate) {
234 return; 241 return;
@@ -241,7 +248,7 @@ export class CargoWatchProvider implements vscode.Disposable {
241 for (const suggestedFix of suggestedFixes) { 248 for (const suggestedFix of suggestedFixes) {
242 this.suggestedFixCollection.addSuggestedFixForDiagnostic( 249 this.suggestedFixCollection.addSuggestedFixForDiagnostic(
243 suggestedFix, 250 suggestedFix,
244 diagnostic 251 diagnostic,
245 ); 252 );
246 } 253 }
247 254
@@ -249,7 +256,7 @@ export class CargoWatchProvider implements vscode.Disposable {
249 vscode.commands.executeCommand( 256 vscode.commands.executeCommand(
250 'vscode.executeCodeActionProvider', 257 'vscode.executeCodeActionProvider',
251 fileUri, 258 fileUri,
252 diagnostic.range 259 diagnostic.range,
253 ); 260 );
254 } 261 }
255 } 262 }
diff --git a/editors/code/src/commands/expand_macro.ts b/editors/code/src/commands/expand_macro.ts
index 34e0c8fb3..17c78280a 100644
--- a/editors/code/src/commands/expand_macro.ts
+++ b/editors/code/src/commands/expand_macro.ts
@@ -3,7 +3,7 @@ import { Position, TextDocumentIdentifier } from 'vscode-languageclient';
3import { Server } from '../server'; 3import { Server } from '../server';
4 4
5export const expandMacroUri = vscode.Uri.parse( 5export const expandMacroUri = vscode.Uri.parse(
6 'rust-analyzer://expandMacro/[EXPANSION].rs' 6 'rust-analyzer://expandMacro/[EXPANSION].rs',
7); 7);
8 8
9export class ExpandMacroContentProvider 9export class ExpandMacroContentProvider
@@ -11,7 +11,7 @@ export class ExpandMacroContentProvider
11 public eventEmitter = new vscode.EventEmitter<vscode.Uri>(); 11 public eventEmitter = new vscode.EventEmitter<vscode.Uri>();
12 12
13 public provideTextDocumentContent( 13 public provideTextDocumentContent(
14 uri: vscode.Uri 14 _uri: vscode.Uri,
15 ): vscode.ProviderResult<string> { 15 ): vscode.ProviderResult<string> {
16 async function handle() { 16 async function handle() {
17 const editor = vscode.window.activeTextEditor; 17 const editor = vscode.window.activeTextEditor;
@@ -22,11 +22,11 @@ export class ExpandMacroContentProvider
22 const position = editor.selection.active; 22 const position = editor.selection.active;
23 const request: MacroExpandParams = { 23 const request: MacroExpandParams = {
24 textDocument: { uri: editor.document.uri.toString() }, 24 textDocument: { uri: editor.document.uri.toString() },
25 position 25 position,
26 }; 26 };
27 const expanded = await Server.client.sendRequest<ExpandedMacro>( 27 const expanded = await Server.client.sendRequest<ExpandedMacro>(
28 'rust-analyzer/expandMacro', 28 'rust-analyzer/expandMacro',
29 request 29 request,
30 ); 30 );
31 31
32 if (expanded == null) { 32 if (expanded == null) {
@@ -58,7 +58,7 @@ export function createHandle(provider: ExpandMacroContentProvider) {
58 return vscode.window.showTextDocument( 58 return vscode.window.showTextDocument(
59 document, 59 document,
60 vscode.ViewColumn.Two, 60 vscode.ViewColumn.Two,
61 true 61 true,
62 ); 62 );
63 }; 63 };
64} 64}
diff --git a/editors/code/src/commands/index.ts b/editors/code/src/commands/index.ts
index 2ade6d331..13a696758 100644
--- a/editors/code/src/commands/index.ts
+++ b/editors/code/src/commands/index.ts
@@ -19,5 +19,5 @@ export {
19 runnables, 19 runnables,
20 syntaxTree, 20 syntaxTree,
21 onEnter, 21 onEnter,
22 inlayHints 22 inlayHints,
23}; 23};
diff --git a/editors/code/src/commands/inlay_hints.ts b/editors/code/src/commands/inlay_hints.ts
index 0dbdd94fb..ac7dcce60 100644
--- a/editors/code/src/commands/inlay_hints.ts
+++ b/editors/code/src/commands/inlay_hints.ts
@@ -15,8 +15,8 @@ interface InlayHint {
15 15
16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({ 16const typeHintDecorationType = vscode.window.createTextEditorDecorationType({
17 after: { 17 after: {
18 color: new vscode.ThemeColor('ralsp.inlayHint') 18 color: new vscode.ThemeColor('ralsp.inlayHint'),
19 } 19 },
20}); 20});
21 21
22export class HintsUpdater { 22export class HintsUpdater {
@@ -26,13 +26,13 @@ export class HintsUpdater {
26 if (this.displayHints !== displayHints) { 26 if (this.displayHints !== displayHints) {
27 this.displayHints = displayHints; 27 this.displayHints = displayHints;
28 return this.refreshVisibleEditorsHints( 28 return this.refreshVisibleEditorsHints(
29 displayHints ? undefined : [] 29 displayHints ? undefined : [],
30 ); 30 );
31 } 31 }
32 } 32 }
33 33
34 public async refreshHintsForVisibleEditors( 34 public async refreshHintsForVisibleEditors(
35 cause?: TextDocumentChangeEvent 35 cause?: TextDocumentChangeEvent,
36 ): Promise<void> { 36 ): Promise<void> {
37 if (!this.displayHints) { 37 if (!this.displayHints) {
38 return; 38 return;
@@ -48,21 +48,21 @@ export class HintsUpdater {
48 } 48 }
49 49
50 private async refreshVisibleEditorsHints( 50 private async refreshVisibleEditorsHints(
51 newDecorations?: vscode.DecorationOptions[] 51 newDecorations?: vscode.DecorationOptions[],
52 ) { 52 ) {
53 const promises: Array<Promise<void>> = []; 53 const promises: Array<Promise<void>> = [];
54 54
55 for (const rustEditor of vscode.window.visibleTextEditors.filter( 55 for (const rustEditor of vscode.window.visibleTextEditors.filter(
56 editor => this.isRustDocument(editor.document) 56 editor => this.isRustDocument(editor.document),
57 )) { 57 )) {
58 if (newDecorations !== undefined) { 58 if (newDecorations !== undefined) {
59 promises.push( 59 promises.push(
60 Promise.resolve( 60 Promise.resolve(
61 rustEditor.setDecorations( 61 rustEditor.setDecorations(
62 typeHintDecorationType, 62 typeHintDecorationType,
63 newDecorations 63 newDecorations,
64 ) 64 ),
65 ) 65 ),
66 ); 66 );
67 } else { 67 } else {
68 promises.push(this.updateDecorationsFromServer(rustEditor)); 68 promises.push(this.updateDecorationsFromServer(rustEditor));
@@ -79,7 +79,7 @@ export class HintsUpdater {
79 } 79 }
80 80
81 private async updateDecorationsFromServer( 81 private async updateDecorationsFromServer(
82 editor: TextEditor 82 editor: TextEditor,
83 ): Promise<void> { 83 ): Promise<void> {
84 const newHints = await this.queryHints(editor.document.uri.toString()); 84 const newHints = await this.queryHints(editor.document.uri.toString());
85 if (newHints !== null) { 85 if (newHints !== null) {
@@ -87,20 +87,20 @@ export class HintsUpdater {
87 range: hint.range, 87 range: hint.range,
88 renderOptions: { 88 renderOptions: {
89 after: { 89 after: {
90 contentText: `: ${hint.label}` 90 contentText: `: ${hint.label}`,
91 } 91 },
92 } 92 },
93 })); 93 }));
94 return editor.setDecorations( 94 return editor.setDecorations(
95 typeHintDecorationType, 95 typeHintDecorationType,
96 newDecorations 96 newDecorations,
97 ); 97 );
98 } 98 }
99 } 99 }
100 100
101 private async queryHints(documentUri: string): Promise<InlayHint[] | null> { 101 private async queryHints(documentUri: string): Promise<InlayHint[] | null> {
102 const request: InlayHintsParams = { 102 const request: InlayHintsParams = {
103 textDocument: { uri: documentUri } 103 textDocument: { uri: documentUri },
104 }; 104 };
105 const client = Server.client; 105 const client = Server.client;
106 return client 106 return client
@@ -108,8 +108,8 @@ export class HintsUpdater {
108 .then(() => 108 .then(() =>
109 client.sendRequest<InlayHint[] | null>( 109 client.sendRequest<InlayHint[] | null>(
110 'rust-analyzer/inlayHints', 110 'rust-analyzer/inlayHints',
111 request 111 request,
112 ) 112 ),
113 ); 113 );
114 } 114 }
115} 115}
diff --git a/editors/code/src/commands/join_lines.ts b/editors/code/src/commands/join_lines.ts
index 0d4b12f4d..134ddc801 100644
--- a/editors/code/src/commands/join_lines.ts
+++ b/editors/code/src/commands/join_lines.ts
@@ -4,7 +4,7 @@ import { Range, TextDocumentIdentifier } from 'vscode-languageclient';
4import { Server } from '../server'; 4import { Server } from '../server';
5import { 5import {
6 handle as applySourceChange, 6 handle as applySourceChange,
7 SourceChange 7 SourceChange,
8} from './apply_source_change'; 8} from './apply_source_change';
9 9
10interface JoinLinesParams { 10interface JoinLinesParams {
@@ -19,11 +19,11 @@ export async function handle() {
19 } 19 }
20 const request: JoinLinesParams = { 20 const request: JoinLinesParams = {
21 range: Server.client.code2ProtocolConverter.asRange(editor.selection), 21 range: Server.client.code2ProtocolConverter.asRange(editor.selection),
22 textDocument: { uri: editor.document.uri.toString() } 22 textDocument: { uri: editor.document.uri.toString() },
23 }; 23 };
24 const change = await Server.client.sendRequest<SourceChange>( 24 const change = await Server.client.sendRequest<SourceChange>(
25 'rust-analyzer/joinLines', 25 'rust-analyzer/joinLines',
26 request 26 request,
27 ); 27 );
28 await applySourceChange(change); 28 await applySourceChange(change);
29} 29}
diff --git a/editors/code/src/commands/matching_brace.ts b/editors/code/src/commands/matching_brace.ts
index d86faf405..364208cc7 100644
--- a/editors/code/src/commands/matching_brace.ts
+++ b/editors/code/src/commands/matching_brace.ts
@@ -17,15 +17,15 @@ export async function handle() {
17 textDocument: { uri: editor.document.uri.toString() }, 17 textDocument: { uri: editor.document.uri.toString() },
18 offsets: editor.selections.map(s => { 18 offsets: editor.selections.map(s => {
19 return Server.client.code2ProtocolConverter.asPosition(s.active); 19 return Server.client.code2ProtocolConverter.asPosition(s.active);
20 }) 20 }),
21 }; 21 };
22 const response = await Server.client.sendRequest<Position[]>( 22 const response = await Server.client.sendRequest<Position[]>(
23 'rust-analyzer/findMatchingBrace', 23 'rust-analyzer/findMatchingBrace',
24 request 24 request,
25 ); 25 );
26 editor.selections = editor.selections.map((sel, idx) => { 26 editor.selections = editor.selections.map((sel, idx) => {
27 const active = Server.client.protocol2CodeConverter.asPosition( 27 const active = Server.client.protocol2CodeConverter.asPosition(
28 response[idx] 28 response[idx],
29 ); 29 );
30 const anchor = sel.isEmpty ? active : sel.anchor; 30 const anchor = sel.isEmpty ? active : sel.anchor;
31 return new vscode.Selection(anchor, active); 31 return new vscode.Selection(anchor, active);
diff --git a/editors/code/src/commands/on_enter.ts b/editors/code/src/commands/on_enter.ts
index 16dcb70c8..772c64b3c 100644
--- a/editors/code/src/commands/on_enter.ts
+++ b/editors/code/src/commands/on_enter.ts
@@ -3,7 +3,7 @@ import * as lc from 'vscode-languageclient';
3import { Server } from '../server'; 3import { Server } from '../server';
4import { 4import {
5 handle as applySourceChange, 5 handle as applySourceChange,
6 SourceChange 6 SourceChange,
7} from './apply_source_change'; 7} from './apply_source_change';
8 8
9export async function handle(event: { text: string }): Promise<boolean> { 9export async function handle(event: { text: string }): Promise<boolean> {
@@ -18,12 +18,12 @@ export async function handle(event: { text: string }): Promise<boolean> {
18 const request: lc.TextDocumentPositionParams = { 18 const request: lc.TextDocumentPositionParams = {
19 textDocument: { uri: editor.document.uri.toString() }, 19 textDocument: { uri: editor.document.uri.toString() },
20 position: Server.client.code2ProtocolConverter.asPosition( 20 position: Server.client.code2ProtocolConverter.asPosition(
21 editor.selection.active 21 editor.selection.active,
22 ) 22 ),
23 }; 23 };
24 const change = await Server.client.sendRequest<undefined | SourceChange>( 24 const change = await Server.client.sendRequest<undefined | SourceChange>(
25 'rust-analyzer/onEnter', 25 'rust-analyzer/onEnter',
26 request 26 request,
27 ); 27 );
28 if (!change) { 28 if (!change) {
29 return false; 29 return false;
diff --git a/editors/code/src/commands/parent_module.ts b/editors/code/src/commands/parent_module.ts
index 9d30b7b59..ad49e1bdb 100644
--- a/editors/code/src/commands/parent_module.ts
+++ b/editors/code/src/commands/parent_module.ts
@@ -11,12 +11,12 @@ export async function handle() {
11 const request: lc.TextDocumentPositionParams = { 11 const request: lc.TextDocumentPositionParams = {
12 textDocument: { uri: editor.document.uri.toString() }, 12 textDocument: { uri: editor.document.uri.toString() },
13 position: Server.client.code2ProtocolConverter.asPosition( 13 position: Server.client.code2ProtocolConverter.asPosition(
14 editor.selection.active 14 editor.selection.active,
15 ) 15 ),
16 }; 16 };
17 const response = await Server.client.sendRequest<lc.Location[]>( 17 const response = await Server.client.sendRequest<lc.Location[]>(
18 'rust-analyzer/parentModule', 18 'rust-analyzer/parentModule',
19 request 19 request,
20 ); 20 );
21 const loc = response[0]; 21 const loc = response[0];
22 if (loc == null) { 22 if (loc == null) {
diff --git a/editors/code/src/commands/runnables.ts b/editors/code/src/commands/runnables.ts
index ac59bf60d..cf980e257 100644
--- a/editors/code/src/commands/runnables.ts
+++ b/editors/code/src/commands/runnables.ts
@@ -46,17 +46,17 @@ function createTask(spec: Runnable): vscode.Task {
46 label: spec.label, 46 label: spec.label,
47 command: spec.bin, 47 command: spec.bin,
48 args: spec.args, 48 args: spec.args,
49 env: spec.env 49 env: spec.env,
50 }; 50 };
51 51
52 const execOption: vscode.ShellExecutionOptions = { 52 const execOption: vscode.ShellExecutionOptions = {
53 cwd: spec.cwd || '.', 53 cwd: spec.cwd || '.',
54 env: definition.env 54 env: definition.env,
55 }; 55 };
56 const exec = new vscode.ShellExecution( 56 const exec = new vscode.ShellExecution(
57 definition.command, 57 definition.command,
58 definition.args, 58 definition.args,
59 execOption 59 execOption,
60 ); 60 );
61 61
62 const f = vscode.workspace.workspaceFolders![0]; 62 const f = vscode.workspace.workspaceFolders![0];
@@ -66,30 +66,30 @@ function createTask(spec: Runnable): vscode.Task {
66 definition.label, 66 definition.label,
67 TASK_SOURCE, 67 TASK_SOURCE,
68 exec, 68 exec,
69 ['$rustc'] 69 ['$rustc'],
70 ); 70 );
71 t.presentationOptions.clear = true; 71 t.presentationOptions.clear = true;
72 return t; 72 return t;
73} 73}
74 74
75let prevRunnable: RunnableQuickPick | undefined; 75let prevRunnable: RunnableQuickPick | undefined;
76export async function handle() { 76export async function handle(): Promise<vscode.TaskExecution | undefined> {
77 const editor = vscode.window.activeTextEditor; 77 const editor = vscode.window.activeTextEditor;
78 if (editor == null || editor.document.languageId !== 'rust') { 78 if (editor == null || editor.document.languageId !== 'rust') {
79 return; 79 return;
80 } 80 }
81 const textDocument: lc.TextDocumentIdentifier = { 81 const textDocument: lc.TextDocumentIdentifier = {
82 uri: editor.document.uri.toString() 82 uri: editor.document.uri.toString(),
83 }; 83 };
84 const params: RunnablesParams = { 84 const params: RunnablesParams = {
85 textDocument, 85 textDocument,
86 position: Server.client.code2ProtocolConverter.asPosition( 86 position: Server.client.code2ProtocolConverter.asPosition(
87 editor.selection.active 87 editor.selection.active,
88 ) 88 ),
89 }; 89 };
90 const runnables = await Server.client.sendRequest<Runnable[]>( 90 const runnables = await Server.client.sendRequest<Runnable[]>(
91 'rust-analyzer/runnables', 91 'rust-analyzer/runnables',
92 params 92 params,
93 ); 93 );
94 const items: RunnableQuickPick[] = []; 94 const items: RunnableQuickPick[] = [];
95 if (prevRunnable) { 95 if (prevRunnable) {
@@ -105,12 +105,14 @@ export async function handle() {
105 items.push(new RunnableQuickPick(r)); 105 items.push(new RunnableQuickPick(r));
106 } 106 }
107 const item = await vscode.window.showQuickPick(items); 107 const item = await vscode.window.showQuickPick(items);
108 if (item) { 108 if (!item) {
109 item.detail = 'rerun'; 109 return;
110 prevRunnable = item;
111 const task = createTask(item.runnable);
112 return await vscode.tasks.executeTask(task);
113 } 110 }
111
112 item.detail = 'rerun';
113 prevRunnable = item;
114 const task = createTask(item.runnable);
115 return await vscode.tasks.executeTask(task);
114} 116}
115 117
116export async function handleSingle(runnable: Runnable) { 118export async function handleSingle(runnable: Runnable) {
@@ -124,7 +126,7 @@ export async function handleSingle(runnable: Runnable) {
124 task.presentationOptions = { 126 task.presentationOptions = {
125 reveal: vscode.TaskRevealKind.Always, 127 reveal: vscode.TaskRevealKind.Always,
126 panel: vscode.TaskPanelKind.Dedicated, 128 panel: vscode.TaskPanelKind.Dedicated,
127 clear: true 129 clear: true,
128 }; 130 };
129 131
130 return vscode.tasks.executeTask(task); 132 return vscode.tasks.executeTask(task);
@@ -136,7 +138,7 @@ export async function handleSingle(runnable: Runnable) {
136 * that, when accepted, allow us to `cargo install cargo-watch` and then run it. 138 * that, when accepted, allow us to `cargo install cargo-watch` and then run it.
137 */ 139 */
138export async function interactivelyStartCargoWatch( 140export async function interactivelyStartCargoWatch(
139 context: vscode.ExtensionContext 141 context: vscode.ExtensionContext,
140): Promise<CargoWatchProvider | undefined> { 142): Promise<CargoWatchProvider | undefined> {
141 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') { 143 if (Server.config.cargoWatchOptions.enableOnStartup === 'disabled') {
142 return; 144 return;
@@ -146,7 +148,7 @@ export async function interactivelyStartCargoWatch(
146 const watch = await vscode.window.showInformationMessage( 148 const watch = await vscode.window.showInformationMessage(
147 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)', 149 'Start watching changes with cargo? (Executes `cargo watch`, provides inline diagnostics)',
148 'yes', 150 'yes',
149 'no' 151 'no',
150 ); 152 );
151 if (watch !== 'yes') { 153 if (watch !== 'yes') {
152 return; 154 return;
@@ -157,12 +159,12 @@ export async function interactivelyStartCargoWatch(
157} 159}
158 160
159export async function startCargoWatch( 161export async function startCargoWatch(
160 context: vscode.ExtensionContext 162 context: vscode.ExtensionContext,
161): Promise<CargoWatchProvider | undefined> { 163): Promise<CargoWatchProvider | undefined> {
162 const execPromise = util.promisify(child_process.exec); 164 const execPromise = util.promisify(child_process.exec);
163 165
164 const { stderr, code = 0 } = await execPromise( 166 const { stderr, code = 0 } = await execPromise(
165 'cargo watch --version' 167 'cargo watch --version',
166 ).catch(e => e); 168 ).catch(e => e);
167 169
168 if (stderr.includes('no such subcommand: `watch`')) { 170 if (stderr.includes('no such subcommand: `watch`')) {
@@ -171,14 +173,14 @@ export async function startCargoWatch(
171 const install = await vscode.window.showInformationMessage( 173 const install = await vscode.window.showInformationMessage(
172 msg, 174 msg,
173 'yes', 175 'yes',
174 'no' 176 'no',
175 ); 177 );
176 if (install !== 'yes') { 178 if (install !== 'yes') {
177 return; 179 return;
178 } 180 }
179 181
180 const label = 'install-cargo-watch'; 182 const label = 'install-cargo-watch';
181 const taskFinished = new Promise((resolve, reject) => { 183 const taskFinished = new Promise((resolve, _reject) => {
182 const disposable = vscode.tasks.onDidEndTask(({ execution }) => { 184 const disposable = vscode.tasks.onDidEndTask(({ execution }) => {
183 if (execution.task.name === label) { 185 if (execution.task.name === label) {
184 disposable.dispose(); 186 disposable.dispose();
@@ -192,20 +194,20 @@ export async function startCargoWatch(
192 label, 194 label,
193 bin: 'cargo', 195 bin: 'cargo',
194 args: ['install', 'cargo-watch'], 196 args: ['install', 'cargo-watch'],
195 env: {} 197 env: {},
196 }) 198 }),
197 ); 199 );
198 await taskFinished; 200 await taskFinished;
199 const output = await execPromise('cargo watch --version').catch(e => e); 201 const output = await execPromise('cargo watch --version').catch(e => e);
200 if (output.stderr !== '') { 202 if (output.stderr !== '') {
201 vscode.window.showErrorMessage( 203 vscode.window.showErrorMessage(
202 `Couldn't install \`cargo-\`watch: ${output.stderr}` 204 `Couldn't install \`cargo-\`watch: ${output.stderr}`,
203 ); 205 );
204 return; 206 return;
205 } 207 }
206 } else if (code !== 0) { 208 } else if (code !== 0) {
207 vscode.window.showErrorMessage( 209 vscode.window.showErrorMessage(
208 `\`cargo watch\` failed with ${code}: ${stderr}` 210 `\`cargo watch\` failed with ${code}: ${stderr}`,
209 ); 211 );
210 return; 212 return;
211 } 213 }
diff --git a/editors/code/src/commands/syntaxTree.ts b/editors/code/src/commands/syntaxTree.ts
index 2f50fe14b..89a80550c 100644
--- a/editors/code/src/commands/syntaxTree.ts
+++ b/editors/code/src/commands/syntaxTree.ts
@@ -11,7 +11,7 @@ export class SyntaxTreeContentProvider
11 public syntaxTree: string = 'Not available'; 11 public syntaxTree: string = 'Not available';
12 12
13 public provideTextDocumentContent( 13 public provideTextDocumentContent(
14 uri: vscode.Uri 14 uri: vscode.Uri,
15 ): vscode.ProviderResult<string> { 15 ): vscode.ProviderResult<string> {
16 const editor = vscode.window.activeTextEditor; 16 const editor = vscode.window.activeTextEditor;
17 if (editor == null) { 17 if (editor == null) {
@@ -25,17 +25,17 @@ export class SyntaxTreeContentProvider
25 range = editor.selection.isEmpty 25 range = editor.selection.isEmpty
26 ? undefined 26 ? undefined
27 : Server.client.code2ProtocolConverter.asRange( 27 : Server.client.code2ProtocolConverter.asRange(
28 editor.selection 28 editor.selection,
29 ); 29 );
30 } 30 }
31 31
32 const request: SyntaxTreeParams = { 32 const request: SyntaxTreeParams = {
33 textDocument: { uri: editor.document.uri.toString() }, 33 textDocument: { uri: editor.document.uri.toString() },
34 range 34 range,
35 }; 35 };
36 return Server.client.sendRequest<SyntaxTreeResult>( 36 return Server.client.sendRequest<SyntaxTreeResult>(
37 'rust-analyzer/syntaxTree', 37 'rust-analyzer/syntaxTree',
38 request 38 request,
39 ); 39 );
40 } 40 }
41 41
@@ -70,7 +70,7 @@ export function createHandle(provider: SyntaxTreeContentProvider) {
70 return vscode.window.showTextDocument( 70 return vscode.window.showTextDocument(
71 document, 71 document,
72 vscode.ViewColumn.Two, 72 vscode.ViewColumn.Two,
73 true 73 true,
74 ); 74 );
75 }; 75 };
76} 76}
diff --git a/editors/code/src/commands/watch_status.ts b/editors/code/src/commands/watch_status.ts
index 6c1f9041b..8d64394c7 100644
--- a/editors/code/src/commands/watch_status.ts
+++ b/editors/code/src/commands/watch_status.ts
@@ -13,7 +13,7 @@ export class StatusDisplay implements vscode.Disposable {
13 constructor(command: string) { 13 constructor(command: string) {
14 this.statusBarItem = vscode.window.createStatusBarItem( 14 this.statusBarItem = vscode.window.createStatusBarItem(
15 vscode.StatusBarAlignment.Left, 15 vscode.StatusBarAlignment.Left,
16 10 16 10,
17 ); 17 );
18 this.command = command; 18 this.command = command;
19 this.statusBarItem.hide(); 19 this.statusBarItem.hide();
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index 4cedbea46..c06dddb1c 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -14,6 +14,13 @@ export interface CargoWatchOptions {
14 command: string; 14 command: string;
15 trace: CargoWatchTraceOptions; 15 trace: CargoWatchTraceOptions;
16 ignore: string[]; 16 ignore: string[];
17 allTargets: boolean;
18}
19
20export interface CargoFeatures {
21 noDefaultFeatures: boolean;
22 allFeatures: boolean;
23 features: string[];
17} 24}
18 25
19export class Config { 26export class Config {
@@ -25,21 +32,30 @@ export class Config {
25 public displayInlayHints = true; 32 public displayInlayHints = true;
26 public maxInlayHintLength: null | number = null; 33 public maxInlayHintLength: null | number = null;
27 public excludeGlobs = []; 34 public excludeGlobs = [];
28 public useClientWatching = false; 35 public useClientWatching = true;
29 public featureFlags = {}; 36 public featureFlags = {};
37 // for internal use
38 public withSysroot: null | boolean = null;
30 public cargoWatchOptions: CargoWatchOptions = { 39 public cargoWatchOptions: CargoWatchOptions = {
31 enableOnStartup: 'ask', 40 enableOnStartup: 'ask',
32 trace: 'off', 41 trace: 'off',
33 arguments: '', 42 arguments: '',
34 command: '', 43 command: '',
35 ignore: [] 44 ignore: [],
45 allTargets: true,
46 };
47 public cargoFeatures: CargoFeatures = {
48 noDefaultFeatures: false,
49 allFeatures: true,
50 features: [],
36 }; 51 };
37 52
38 private prevEnhancedTyping: null | boolean = null; 53 private prevEnhancedTyping: null | boolean = null;
54 private prevCargoFeatures: null | CargoFeatures = null;
39 55
40 constructor() { 56 constructor() {
41 vscode.workspace.onDidChangeConfiguration(_ => 57 vscode.workspace.onDidChangeConfiguration(_ =>
42 this.userConfigChanged() 58 this.userConfigChanged(),
43 ); 59 );
44 this.userConfigChanged(); 60 this.userConfigChanged();
45 } 61 }
@@ -49,6 +65,8 @@ export class Config {
49 65
50 Server.highlighter.removeHighlights(); 66 Server.highlighter.removeHighlights();
51 67
68 let requireReloadMessage = null;
69
52 if (config.has('highlightingOn')) { 70 if (config.has('highlightingOn')) {
53 this.highlightingOn = config.get('highlightingOn') as boolean; 71 this.highlightingOn = config.get('highlightingOn') as boolean;
54 if (this.highlightingOn) { 72 if (this.highlightingOn) {
@@ -59,13 +77,13 @@ export class Config {
59 77
60 if (config.has('rainbowHighlightingOn')) { 78 if (config.has('rainbowHighlightingOn')) {
61 this.rainbowHighlightingOn = config.get( 79 this.rainbowHighlightingOn = config.get(
62 'rainbowHighlightingOn' 80 'rainbowHighlightingOn',
63 ) as boolean; 81 ) as boolean;
64 } 82 }
65 83
66 if (config.has('enableEnhancedTyping')) { 84 if (config.has('enableEnhancedTyping')) {
67 this.enableEnhancedTyping = config.get( 85 this.enableEnhancedTyping = config.get(
68 'enableEnhancedTyping' 86 'enableEnhancedTyping',
69 ) as boolean; 87 ) as boolean;
70 88
71 if (this.prevEnhancedTyping === null) { 89 if (this.prevEnhancedTyping === null) {
@@ -76,19 +94,8 @@ export class Config {
76 } 94 }
77 95
78 if (this.prevEnhancedTyping !== this.enableEnhancedTyping) { 96 if (this.prevEnhancedTyping !== this.enableEnhancedTyping) {
79 const reloadAction = 'Reload now'; 97 requireReloadMessage =
80 vscode.window 98 'Changing enhanced typing setting requires a reload';
81 .showInformationMessage(
82 'Changing enhanced typing setting requires a reload',
83 reloadAction
84 )
85 .then(selectedAction => {
86 if (selectedAction === reloadAction) {
87 vscode.commands.executeCommand(
88 'workbench.action.reloadWindow'
89 );
90 }
91 });
92 this.prevEnhancedTyping = this.enableEnhancedTyping; 99 this.prevEnhancedTyping = this.enableEnhancedTyping;
93 } 100 }
94 101
@@ -106,28 +113,35 @@ export class Config {
106 if (config.has('trace.cargo-watch')) { 113 if (config.has('trace.cargo-watch')) {
107 this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>( 114 this.cargoWatchOptions.trace = config.get<CargoWatchTraceOptions>(
108 'trace.cargo-watch', 115 'trace.cargo-watch',
109 'off' 116 'off',
110 ); 117 );
111 } 118 }
112 119
113 if (config.has('cargo-watch.arguments')) { 120 if (config.has('cargo-watch.arguments')) {
114 this.cargoWatchOptions.arguments = config.get<string>( 121 this.cargoWatchOptions.arguments = config.get<string>(
115 'cargo-watch.arguments', 122 'cargo-watch.arguments',
116 '' 123 '',
117 ); 124 );
118 } 125 }
119 126
120 if (config.has('cargo-watch.command')) { 127 if (config.has('cargo-watch.command')) {
121 this.cargoWatchOptions.command = config.get<string>( 128 this.cargoWatchOptions.command = config.get<string>(
122 'cargo-watch.command', 129 'cargo-watch.command',
123 '' 130 '',
124 ); 131 );
125 } 132 }
126 133
127 if (config.has('cargo-watch.ignore')) { 134 if (config.has('cargo-watch.ignore')) {
128 this.cargoWatchOptions.ignore = config.get<string[]>( 135 this.cargoWatchOptions.ignore = config.get<string[]>(
129 'cargo-watch.ignore', 136 'cargo-watch.ignore',
130 [] 137 [],
138 );
139 }
140
141 if (config.has('cargo-watch.allTargets')) {
142 this.cargoWatchOptions.allTargets = config.get<boolean>(
143 'cargo-watch.allTargets',
144 true,
131 ); 145 );
132 } 146 }
133 147
@@ -140,17 +154,68 @@ export class Config {
140 } 154 }
141 if (config.has('maxInlayHintLength')) { 155 if (config.has('maxInlayHintLength')) {
142 this.maxInlayHintLength = config.get( 156 this.maxInlayHintLength = config.get(
143 'maxInlayHintLength' 157 'maxInlayHintLength',
144 ) as number; 158 ) as number;
145 } 159 }
146 if (config.has('excludeGlobs')) { 160 if (config.has('excludeGlobs')) {
147 this.excludeGlobs = config.get('excludeGlobs') || []; 161 this.excludeGlobs = config.get('excludeGlobs') || [];
148 } 162 }
149 if (config.has('useClientWatching')) { 163 if (config.has('useClientWatching')) {
150 this.useClientWatching = config.get('useClientWatching') || false; 164 this.useClientWatching = config.get('useClientWatching') || true;
151 } 165 }
152 if (config.has('featureFlags')) { 166 if (config.has('featureFlags')) {
153 this.featureFlags = config.get('featureFlags') || {}; 167 this.featureFlags = config.get('featureFlags') || {};
154 } 168 }
169 if (config.has('withSysroot')) {
170 this.withSysroot = config.get('withSysroot') || false;
171 }
172
173 if (config.has('cargoFeatures.noDefaultFeatures')) {
174 this.cargoFeatures.noDefaultFeatures = config.get(
175 'cargoFeatures.noDefaultFeatures',
176 false,
177 );
178 }
179 if (config.has('cargoFeatures.allFeatures')) {
180 this.cargoFeatures.allFeatures = config.get(
181 'cargoFeatures.allFeatures',
182 true,
183 );
184 }
185 if (config.has('cargoFeatures.features')) {
186 this.cargoFeatures.features = config.get(
187 'cargoFeatures.features',
188 [],
189 );
190 }
191
192 if (
193 this.prevCargoFeatures !== null &&
194 (this.cargoFeatures.allFeatures !==
195 this.prevCargoFeatures.allFeatures ||
196 this.cargoFeatures.noDefaultFeatures !==
197 this.prevCargoFeatures.noDefaultFeatures ||
198 this.cargoFeatures.features.length !==
199 this.prevCargoFeatures.features.length ||
200 this.cargoFeatures.features.some(
201 (v, i) => v !== this.prevCargoFeatures!.features[i],
202 ))
203 ) {
204 requireReloadMessage = 'Changing cargo features requires a reload';
205 }
206 this.prevCargoFeatures = { ...this.cargoFeatures };
207
208 if (requireReloadMessage !== null) {
209 const reloadAction = 'Reload now';
210 vscode.window
211 .showInformationMessage(requireReloadMessage, reloadAction)
212 .then(selectedAction => {
213 if (selectedAction === reloadAction) {
214 vscode.commands.executeCommand(
215 'workbench.action.reloadWindow',
216 );
217 }
218 });
219 }
155 } 220 }
156} 221}
diff --git a/editors/code/src/events/change_active_text_editor.ts b/editors/code/src/events/change_active_text_editor.ts
index 64be56225..74b91bd48 100644
--- a/editors/code/src/events/change_active_text_editor.ts
+++ b/editors/code/src/events/change_active_text_editor.ts
@@ -3,7 +3,7 @@ import { TextDocumentIdentifier } from 'vscode-languageclient';
3 3
4import { 4import {
5 SyntaxTreeContentProvider, 5 SyntaxTreeContentProvider,
6 syntaxTreeUri 6 syntaxTreeUri,
7} from '../commands/syntaxTree'; 7} from '../commands/syntaxTree';
8import { Decoration } from '../highlighting'; 8import { Decoration } from '../highlighting';
9import { Server } from '../server'; 9import { Server } from '../server';
@@ -21,11 +21,11 @@ export function makeHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
21 } 21 }
22 22
23 const params: TextDocumentIdentifier = { 23 const params: TextDocumentIdentifier = {
24 uri: editor.document.uri.toString() 24 uri: editor.document.uri.toString(),
25 }; 25 };
26 const decorations = await Server.client.sendRequest<Decoration[]>( 26 const decorations = await Server.client.sendRequest<Decoration[]>(
27 'rust-analyzer/decorationsRequest', 27 'rust-analyzer/decorationsRequest',
28 params 28 params,
29 ); 29 );
30 Server.highlighter.setHighlights(editor, decorations); 30 Server.highlighter.setHighlights(editor, decorations);
31 }; 31 };
diff --git a/editors/code/src/events/change_text_document.ts b/editors/code/src/events/change_text_document.ts
index 89488bc61..2e998e889 100644
--- a/editors/code/src/events/change_text_document.ts
+++ b/editors/code/src/events/change_text_document.ts
@@ -2,7 +2,7 @@ import * as vscode from 'vscode';
2 2
3import { 3import {
4 SyntaxTreeContentProvider, 4 SyntaxTreeContentProvider,
5 syntaxTreeUri 5 syntaxTreeUri,
6} from '../commands/syntaxTree'; 6} from '../commands/syntaxTree';
7 7
8export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) { 8export function createHandler(syntaxTreeProvider: SyntaxTreeContentProvider) {
diff --git a/editors/code/src/extension.ts b/editors/code/src/extension.ts
index 683497dfd..815f3692c 100644
--- a/editors/code/src/extension.ts
+++ b/editors/code/src/extension.ts
@@ -7,14 +7,14 @@ import { ExpandMacroContentProvider } from './commands/expand_macro';
7import { HintsUpdater } from './commands/inlay_hints'; 7import { HintsUpdater } from './commands/inlay_hints';
8import { 8import {
9 interactivelyStartCargoWatch, 9 interactivelyStartCargoWatch,
10 startCargoWatch 10 startCargoWatch,
11} from './commands/runnables'; 11} from './commands/runnables';
12import { SyntaxTreeContentProvider } from './commands/syntaxTree'; 12import { SyntaxTreeContentProvider } from './commands/syntaxTree';
13import * as events from './events'; 13import * as events from './events';
14import * as notifications from './notifications'; 14import * as notifications from './notifications';
15import { Server } from './server'; 15import { Server } from './server';
16 16
17export function activate(context: vscode.ExtensionContext) { 17export async function activate(context: vscode.ExtensionContext) {
18 function disposeOnDeactivation(disposable: vscode.Disposable) { 18 function disposeOnDeactivation(disposable: vscode.Disposable) {
19 context.subscriptions.push(disposable); 19 context.subscriptions.push(disposable);
20 } 20 }
@@ -24,7 +24,7 @@ export function activate(context: vscode.ExtensionContext) {
24 } 24 }
25 function overrideCommand( 25 function overrideCommand(
26 name: string, 26 name: string,
27 f: (...args: any[]) => Promise<boolean> 27 f: (...args: any[]) => Promise<boolean>,
28 ) { 28 ) {
29 const defaultCmd = `default:${name}`; 29 const defaultCmd = `default:${name}`;
30 const original = (...args: any[]) => 30 const original = (...args: any[]) =>
@@ -46,7 +46,7 @@ export function activate(context: vscode.ExtensionContext) {
46 }); 46 });
47 } catch (_) { 47 } catch (_) {
48 vscode.window.showWarningMessage( 48 vscode.window.showWarningMessage(
49 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings' 49 'Enhanced typing feature is disabled because of incompatibility with VIM extension, consider turning off rust-analyzer.enableEnhancedTyping: https://github.com/rust-analyzer/rust-analyzer/blob/master/docs/user/README.md#settings',
50 ); 50 );
51 } 51 }
52 } 52 }
@@ -54,14 +54,14 @@ export function activate(context: vscode.ExtensionContext) {
54 // Commands are requests from vscode to the language server 54 // Commands are requests from vscode to the language server
55 registerCommand( 55 registerCommand(
56 'rust-analyzer.analyzerStatus', 56 'rust-analyzer.analyzerStatus',
57 commands.analyzerStatus.makeCommand(context) 57 commands.analyzerStatus.makeCommand(context),
58 ); 58 );
59 registerCommand('rust-analyzer.collectGarbage', () => 59 registerCommand('rust-analyzer.collectGarbage', () =>
60 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null) 60 Server.client.sendRequest<null>('rust-analyzer/collectGarbage', null),
61 ); 61 );
62 registerCommand( 62 registerCommand(
63 'rust-analyzer.matchingBrace', 63 'rust-analyzer.matchingBrace',
64 commands.matchingBrace.handle 64 commands.matchingBrace.handle,
65 ); 65 );
66 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle); 66 registerCommand('rust-analyzer.joinLines', commands.joinLines.handle);
67 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle); 67 registerCommand('rust-analyzer.parentModule', commands.parentModule.handle);
@@ -70,7 +70,7 @@ export function activate(context: vscode.ExtensionContext) {
70 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle); 70 registerCommand('rust-analyzer.runSingle', commands.runnables.handleSingle);
71 registerCommand( 71 registerCommand(
72 'rust-analyzer.applySourceChange', 72 'rust-analyzer.applySourceChange',
73 commands.applySourceChange.handle 73 commands.applySourceChange.handle,
74 ); 74 );
75 registerCommand( 75 registerCommand(
76 'rust-analyzer.showReferences', 76 'rust-analyzer.showReferences',
@@ -79,9 +79,9 @@ export function activate(context: vscode.ExtensionContext) {
79 'editor.action.showReferences', 79 'editor.action.showReferences',
80 vscode.Uri.parse(uri), 80 vscode.Uri.parse(uri),
81 Server.client.protocol2CodeConverter.asPosition(position), 81 Server.client.protocol2CodeConverter.asPosition(position),
82 locations.map(Server.client.protocol2CodeConverter.asLocation) 82 locations.map(Server.client.protocol2CodeConverter.asLocation),
83 ); 83 );
84 } 84 },
85 ); 85 );
86 86
87 if (Server.config.enableEnhancedTyping) { 87 if (Server.config.enableEnhancedTyping) {
@@ -89,48 +89,49 @@ export function activate(context: vscode.ExtensionContext) {
89 } 89 }
90 90
91 // Notifications are events triggered by the language server 91 // Notifications are events triggered by the language server
92 const allNotifications: Iterable< 92 const allNotifications: Iterable<[
93 [string, lc.GenericNotificationHandler] 93 string,
94 > = [ 94 lc.GenericNotificationHandler,
95 ]> = [
95 [ 96 [
96 'rust-analyzer/publishDecorations', 97 'rust-analyzer/publishDecorations',
97 notifications.publishDecorations.handle 98 notifications.publishDecorations.handle,
98 ] 99 ],
99 ]; 100 ];
100 const syntaxTreeContentProvider = new SyntaxTreeContentProvider(); 101 const syntaxTreeContentProvider = new SyntaxTreeContentProvider();
101 const expandMacroContentProvider = new ExpandMacroContentProvider(); 102 const expandMacroContentProvider = new ExpandMacroContentProvider();
102 103
103 // The events below are plain old javascript events, triggered and handled by vscode 104 // The events below are plain old javascript events, triggered and handled by vscode
104 vscode.window.onDidChangeActiveTextEditor( 105 vscode.window.onDidChangeActiveTextEditor(
105 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider) 106 events.changeActiveTextEditor.makeHandler(syntaxTreeContentProvider),
106 ); 107 );
107 108
108 disposeOnDeactivation( 109 disposeOnDeactivation(
109 vscode.workspace.registerTextDocumentContentProvider( 110 vscode.workspace.registerTextDocumentContentProvider(
110 'rust-analyzer', 111 'rust-analyzer',
111 syntaxTreeContentProvider 112 syntaxTreeContentProvider,
112 ) 113 ),
113 ); 114 );
114 disposeOnDeactivation( 115 disposeOnDeactivation(
115 vscode.workspace.registerTextDocumentContentProvider( 116 vscode.workspace.registerTextDocumentContentProvider(
116 'rust-analyzer', 117 'rust-analyzer',
117 expandMacroContentProvider 118 expandMacroContentProvider,
118 ) 119 ),
119 ); 120 );
120 121
121 registerCommand( 122 registerCommand(
122 'rust-analyzer.syntaxTree', 123 'rust-analyzer.syntaxTree',
123 commands.syntaxTree.createHandle(syntaxTreeContentProvider) 124 commands.syntaxTree.createHandle(syntaxTreeContentProvider),
124 ); 125 );
125 registerCommand( 126 registerCommand(
126 'rust-analyzer.expandMacro', 127 'rust-analyzer.expandMacro',
127 commands.expandMacro.createHandle(expandMacroContentProvider) 128 commands.expandMacro.createHandle(expandMacroContentProvider),
128 ); 129 );
129 130
130 vscode.workspace.onDidChangeTextDocument( 131 vscode.workspace.onDidChangeTextDocument(
131 events.changeTextDocument.createHandler(syntaxTreeContentProvider), 132 events.changeTextDocument.createHandler(syntaxTreeContentProvider),
132 null, 133 null,
133 context.subscriptions 134 context.subscriptions,
134 ); 135 );
135 136
136 const startServer = () => Server.start(allNotifications); 137 const startServer = () => Server.start(allNotifications);
@@ -159,7 +160,11 @@ export function activate(context: vscode.ExtensionContext) {
159 }); 160 });
160 161
161 // Start the language server, finally! 162 // Start the language server, finally!
162 startServer(); 163 try {
164 await startServer();
165 } catch (e) {
166 vscode.window.showErrorMessage(e.message);
167 }
163 168
164 if (Server.config.displayInlayHints) { 169 if (Server.config.displayInlayHints) {
165 const hintsUpdater = new HintsUpdater(); 170 const hintsUpdater = new HintsUpdater();
@@ -173,25 +178,25 @@ export function activate(context: vscode.ExtensionContext) {
173 editorChangeDisposable.dispose(); 178 editorChangeDisposable.dispose();
174 } 179 }
175 return hintsUpdater.refreshHintsForVisibleEditors(); 180 return hintsUpdater.refreshHintsForVisibleEditors();
176 } 181 },
177 ); 182 );
178 183
179 disposeOnDeactivation( 184 disposeOnDeactivation(
180 vscode.window.onDidChangeVisibleTextEditors(_ => 185 vscode.window.onDidChangeVisibleTextEditors(_ =>
181 hintsUpdater.refreshHintsForVisibleEditors() 186 hintsUpdater.refreshHintsForVisibleEditors(),
182 ) 187 ),
183 ); 188 );
184 disposeOnDeactivation( 189 disposeOnDeactivation(
185 vscode.workspace.onDidChangeTextDocument(e => 190 vscode.workspace.onDidChangeTextDocument(e =>
186 hintsUpdater.refreshHintsForVisibleEditors(e) 191 hintsUpdater.refreshHintsForVisibleEditors(e),
187 ) 192 ),
188 ); 193 );
189 disposeOnDeactivation( 194 disposeOnDeactivation(
190 vscode.workspace.onDidChangeConfiguration(_ => 195 vscode.workspace.onDidChangeConfiguration(_ =>
191 hintsUpdater.toggleHintsDisplay( 196 hintsUpdater.toggleHintsDisplay(
192 Server.config.displayInlayHints 197 Server.config.displayInlayHints,
193 ) 198 ),
194 ) 199 ),
195 ); 200 );
196 }); 201 });
197 } 202 }
@@ -204,10 +209,10 @@ export function deactivate(): Thenable<void> {
204 return Server.client.stop(); 209 return Server.client.stop();
205} 210}
206 211
207async function reloadServer(startServer: () => void) { 212async function reloadServer(startServer: () => Promise<void>) {
208 if (Server.client != null) { 213 if (Server.client != null) {
209 vscode.window.showInformationMessage('Reloading rust-analyzer...'); 214 vscode.window.showInformationMessage('Reloading rust-analyzer...');
210 await Server.client.stop(); 215 await Server.client.stop();
211 startServer(); 216 await startServer();
212 } 217 }
213} 218}
diff --git a/editors/code/src/highlighting.ts b/editors/code/src/highlighting.ts
index 0a38c9ef6..68eae0941 100644
--- a/editors/code/src/highlighting.ts
+++ b/editors/code/src/highlighting.ts
@@ -67,7 +67,7 @@ export class Highlighter {
67 > { 67 > {
68 const decoration = ( 68 const decoration = (
69 tag: string, 69 tag: string,
70 textDecoration?: string 70 textDecoration?: string,
71 ): [string, vscode.TextEditorDecorationType] => { 71 ): [string, vscode.TextEditorDecorationType] => {
72 const rule = scopesMapper.toRule(tag, scopes.find); 72 const rule = scopesMapper.toRule(tag, scopes.find);
73 73
@@ -90,9 +90,10 @@ export class Highlighter {
90 } 90 }
91 }; 91 };
92 92
93 const decorations: Iterable< 93 const decorations: Iterable<[
94 [string, vscode.TextEditorDecorationType] 94 string,
95 > = [ 95 vscode.TextEditorDecorationType,
96 ]> = [
96 decoration('comment'), 97 decoration('comment'),
97 decoration('string'), 98 decoration('string'),
98 decoration('keyword'), 99 decoration('keyword'),
@@ -101,16 +102,23 @@ export class Highlighter {
101 decoration('function'), 102 decoration('function'),
102 decoration('parameter'), 103 decoration('parameter'),
103 decoration('constant'), 104 decoration('constant'),
105 decoration('type.builtin'),
106 decoration('type.generic'),
107 decoration('type.lifetime'),
108 decoration('type.param'),
109 decoration('type.self'),
104 decoration('type'), 110 decoration('type'),
105 decoration('builtin'),
106 decoration('text'), 111 decoration('text'),
107 decoration('attribute'), 112 decoration('attribute'),
108 decoration('literal'), 113 decoration('literal'),
114 decoration('literal.numeric'),
115 decoration('literal.char'),
116 decoration('literal.byte'),
109 decoration('macro'), 117 decoration('macro'),
110 decoration('variable'), 118 decoration('variable'),
111 decoration('variable.mut', 'underline'), 119 decoration('variable.mut', 'underline'),
112 decoration('field'), 120 decoration('field'),
113 decoration('module') 121 decoration('module'),
114 ]; 122 ];
115 123
116 return new Map<string, vscode.TextEditorDecorationType>(decorations); 124 return new Map<string, vscode.TextEditorDecorationType>(decorations);
@@ -139,7 +147,6 @@ export class Highlighter {
139 // 147 //
140 // Note: decoration objects need to be kept around so we can dispose them 148 // Note: decoration objects need to be kept around so we can dispose them
141 // if the user disables syntax highlighting 149 // if the user disables syntax highlighting
142
143 if (this.decorations == null) { 150 if (this.decorations == null) {
144 this.decorations = Highlighter.initDecorations(); 151 this.decorations = Highlighter.initDecorations();
145 } 152 }
@@ -168,23 +175,22 @@ export class Highlighter {
168 colorfulIdents 175 colorfulIdents
169 .get(d.bindingHash)![0] 176 .get(d.bindingHash)![0]
170 .push( 177 .push(
171 Server.client.protocol2CodeConverter.asRange(d.range) 178 Server.client.protocol2CodeConverter.asRange(d.range),
172 ); 179 );
173 } else { 180 } else {
174 byTag 181 byTag
175 .get(d.tag)! 182 .get(d.tag)!
176 .push( 183 .push(
177 Server.client.protocol2CodeConverter.asRange(d.range) 184 Server.client.protocol2CodeConverter.asRange(d.range),
178 ); 185 );
179 } 186 }
180 } 187 }
181 188
182 for (const tag of byTag.keys()) { 189 for (const tag of byTag.keys()) {
183 const dec = this.decorations.get( 190 const dec = this.decorations.get(
184 tag 191 tag,
185 ) as vscode.TextEditorDecorationType; 192 ) as vscode.TextEditorDecorationType;
186 const ranges = byTag.get(tag)!; 193 const ranges = byTag.get(tag)!;
187
188 editor.setDecorations(dec, ranges); 194 editor.setDecorations(dec, ranges);
189 } 195 }
190 196
@@ -192,7 +198,7 @@ export class Highlighter {
192 const textDecoration = mut ? 'underline' : undefined; 198 const textDecoration = mut ? 'underline' : undefined;
193 const dec = vscode.window.createTextEditorDecorationType({ 199 const dec = vscode.window.createTextEditorDecorationType({
194 light: { color: fancify(hash, 'light'), textDecoration }, 200 light: { color: fancify(hash, 'light'), textDecoration },
195 dark: { color: fancify(hash, 'dark'), textDecoration } 201 dark: { color: fancify(hash, 'dark'), textDecoration },
196 }); 202 });
197 editor.setDecorations(dec, ranges); 203 editor.setDecorations(dec, ranges);
198 } 204 }
diff --git a/editors/code/src/notifications/publish_decorations.ts b/editors/code/src/notifications/publish_decorations.ts
index 3180019b7..f23e286ad 100644
--- a/editors/code/src/notifications/publish_decorations.ts
+++ b/editors/code/src/notifications/publish_decorations.ts
@@ -9,11 +9,16 @@ export interface PublishDecorationsParams {
9} 9}
10 10
11export function handle(params: PublishDecorationsParams) { 11export function handle(params: PublishDecorationsParams) {
12 const targetEditor = vscode.window.visibleTextEditors.find( 12 const targetEditor = vscode.window.visibleTextEditors.find(editor => {
13 editor => editor.document.uri.toString() === params.uri 13 const unescapedUri = unescape(editor.document.uri.toString());
14 ); 14 // Unescaped URI looks like:
15 // file:///c:/Workspace/ra-test/src/main.rs
16 return unescapedUri === params.uri;
17 });
18
15 if (!Server.config.highlightingOn || !targetEditor) { 19 if (!Server.config.highlightingOn || !targetEditor) {
16 return; 20 return;
17 } 21 }
22
18 Server.highlighter.setHighlights(targetEditor, params.decorations); 23 Server.highlighter.setHighlights(targetEditor, params.decorations);
19} 24}
diff --git a/editors/code/src/server.ts b/editors/code/src/server.ts
index 7907b70bc..5ace1d0fa 100644
--- a/editors/code/src/server.ts
+++ b/editors/code/src/server.ts
@@ -1,4 +1,5 @@
1import { homedir } from 'os'; 1import { lookpath } from 'lookpath';
2import { homedir, platform } from 'os';
2import * as lc from 'vscode-languageclient'; 3import * as lc from 'vscode-languageclient';
3 4
4import { window, workspace } from 'vscode'; 5import { window, workspace } from 'vscode';
@@ -17,8 +18,8 @@ export class Server {
17 public static config = new Config(); 18 public static config = new Config();
18 public static client: lc.LanguageClient; 19 public static client: lc.LanguageClient;
19 20
20 public static start( 21 public static async start(
21 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]> 22 notificationHandlers: Iterable<[string, lc.GenericNotificationHandler]>,
22 ) { 23 ) {
23 // '.' Is the fallback if no folder is open 24 // '.' Is the fallback if no folder is open
24 // TODO?: Workspace folders support Uri's (eg: file://test.txt). It might be a good idea to test if the uri points to a file. 25 // TODO?: Workspace folders support Uri's (eg: file://test.txt). It might be a good idea to test if the uri points to a file.
@@ -27,16 +28,26 @@ export class Server {
27 folder = workspace.workspaceFolders[0].uri.fsPath.toString(); 28 folder = workspace.workspaceFolders[0].uri.fsPath.toString();
28 } 29 }
29 30
31 const command = expandPathResolving(this.config.raLspServerPath);
32 // FIXME: remove check when the following issue is fixed:
33 // https://github.com/otiai10/lookpath/issues/4
34 if (platform() !== 'win32') {
35 if (!(await lookpath(command))) {
36 throw new Error(
37 `Cannot find rust-analyzer server \`${command}\` in PATH.`,
38 );
39 }
40 }
30 const run: lc.Executable = { 41 const run: lc.Executable = {
31 command: expandPathResolving(this.config.raLspServerPath), 42 command,
32 options: { cwd: folder } 43 options: { cwd: folder },
33 }; 44 };
34 const serverOptions: lc.ServerOptions = { 45 const serverOptions: lc.ServerOptions = {
35 run, 46 run,
36 debug: run 47 debug: run,
37 }; 48 };
38 const traceOutputChannel = window.createOutputChannel( 49 const traceOutputChannel = window.createOutputChannel(
39 'Rust Analyzer Language Server Trace' 50 'Rust Analyzer Language Server Trace',
40 ); 51 );
41 const clientOptions: lc.LanguageClientOptions = { 52 const clientOptions: lc.LanguageClientOptions = {
42 documentSelector: [{ scheme: 'file', language: 'rust' }], 53 documentSelector: [{ scheme: 'file', language: 'rust' }],
@@ -46,16 +57,18 @@ export class Server {
46 maxInlayHintLength: Server.config.maxInlayHintLength, 57 maxInlayHintLength: Server.config.maxInlayHintLength,
47 excludeGlobs: Server.config.excludeGlobs, 58 excludeGlobs: Server.config.excludeGlobs,
48 useClientWatching: Server.config.useClientWatching, 59 useClientWatching: Server.config.useClientWatching,
49 featureFlags: Server.config.featureFlags 60 featureFlags: Server.config.featureFlags,
61 withSysroot: Server.config.withSysroot,
62 cargoFeatures: Server.config.cargoFeatures,
50 }, 63 },
51 traceOutputChannel 64 traceOutputChannel,
52 }; 65 };
53 66
54 Server.client = new lc.LanguageClient( 67 Server.client = new lc.LanguageClient(
55 'rust-analyzer', 68 'rust-analyzer',
56 'Rust Analyzer Language Server', 69 'Rust Analyzer Language Server',
57 serverOptions, 70 serverOptions,
58 clientOptions 71 clientOptions,
59 ); 72 );
60 // HACK: This is an awful way of filtering out the decorations notifications 73 // HACK: This is an awful way of filtering out the decorations notifications
61 // However, pending proper support, this is the most effecitve approach 74 // However, pending proper support, this is the most effecitve approach
@@ -68,10 +81,10 @@ export class Server {
68 if (typeof messageOrDataObject === 'string') { 81 if (typeof messageOrDataObject === 'string') {
69 if ( 82 if (
70 messageOrDataObject.includes( 83 messageOrDataObject.includes(
71 'rust-analyzer/publishDecorations' 84 'rust-analyzer/publishDecorations',
72 ) || 85 ) ||
73 messageOrDataObject.includes( 86 messageOrDataObject.includes(
74 'rust-analyzer/decorationsRequest' 87 'rust-analyzer/decorationsRequest',
75 ) 88 )
76 ) { 89 ) {
77 // Don't log publish decorations requests 90 // Don't log publish decorations requests
@@ -83,7 +96,7 @@ export class Server {
83 // @ts-ignore 96 // @ts-ignore
84 Server.client.logObjectTrace(messageOrDataObject); 97 Server.client.logObjectTrace(messageOrDataObject);
85 } 98 }
86 } 99 },
87 }; 100 };
88 Server.client.registerProposedFeatures(); 101 Server.client.registerProposedFeatures();
89 Server.client.onReady().then(() => { 102 Server.client.onReady().then(() => {
diff --git a/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json b/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
new file mode 100644
index 000000000..bfef33c7d
--- /dev/null
+++ b/editors/code/src/test/fixtures/rust-diagnostics/error/E0277.json
@@ -0,0 +1,261 @@
1{
2 "rendered": "error[E0277]: can't compare `{integer}` with `&str`\n --> src/main.rs:2:5\n |\n2 | assert_eq!(1, \"love\");\n | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `{integer} == &str`\n |\n = help: the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`\n = note: this error originates in a macro outside of the current crate (in Nightly builds, run with -Z external-macro-backtrace for more info)\n\n",
3 "children": [
4 {
5 "children": [],
6 "code": null,
7 "level": "help",
8 "message": "the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`",
9 "rendered": null,
10 "spans": []
11 }
12 ],
13 "code": {
14 "code": "E0277",
15 "explanation": "\nYou tried to use a type which doesn't implement some trait in a place which\nexpected that trait. Erroneous code example:\n\n```compile_fail,E0277\n// here we declare the Foo trait with a bar method\ntrait Foo {\n fn bar(&self);\n}\n\n// we now declare a function which takes an object implementing the Foo trait\nfn some_func<T: Foo>(foo: T) {\n foo.bar();\n}\n\nfn main() {\n // we now call the method with the i32 type, which doesn't implement\n // the Foo trait\n some_func(5i32); // error: the trait bound `i32 : Foo` is not satisfied\n}\n```\n\nIn order to fix this error, verify that the type you're using does implement\nthe trait. Example:\n\n```\ntrait Foo {\n fn bar(&self);\n}\n\nfn some_func<T: Foo>(foo: T) {\n foo.bar(); // we can now use this method since i32 implements the\n // Foo trait\n}\n\n// we implement the trait on the i32 type\nimpl Foo for i32 {\n fn bar(&self) {}\n}\n\nfn main() {\n some_func(5i32); // ok!\n}\n```\n\nOr in a generic context, an erroneous code example would look like:\n\n```compile_fail,E0277\nfn some_func<T>(foo: T) {\n println!(\"{:?}\", foo); // error: the trait `core::fmt::Debug` is not\n // implemented for the type `T`\n}\n\nfn main() {\n // We now call the method with the i32 type,\n // which *does* implement the Debug trait.\n some_func(5i32);\n}\n```\n\nNote that the error here is in the definition of the generic function: Although\nwe only call it with a parameter that does implement `Debug`, the compiler\nstill rejects the function: It must work with all possible input types. In\norder to make this example compile, we need to restrict the generic type we're\naccepting:\n\n```\nuse std::fmt;\n\n// Restrict the input type to types that implement Debug.\nfn some_func<T: fmt::Debug>(foo: T) {\n println!(\"{:?}\", foo);\n}\n\nfn main() {\n // Calling the method is still fine, as i32 implements Debug.\n some_func(5i32);\n\n // This would fail to compile now:\n // struct WithoutDebug;\n // some_func(WithoutDebug);\n}\n```\n\nRust only looks at the signature of the called function, as such it must\nalready specify all requirements that will be used for every type parameter.\n"
16 },
17 "level": "error",
18 "message": "can't compare `{integer}` with `&str`",
19 "spans": [
20 {
21 "byte_end": 155,
22 "byte_start": 153,
23 "column_end": 33,
24 "column_start": 31,
25 "expansion": {
26 "def_site_span": {
27 "byte_end": 940,
28 "byte_start": 0,
29 "column_end": 6,
30 "column_start": 1,
31 "expansion": null,
32 "file_name": "<::core::macros::assert_eq macros>",
33 "is_primary": false,
34 "label": null,
35 "line_end": 36,
36 "line_start": 1,
37 "suggested_replacement": null,
38 "suggestion_applicability": null,
39 "text": [
40 {
41 "highlight_end": 35,
42 "highlight_start": 1,
43 "text": "($ left : expr, $ right : expr) =>"
44 },
45 {
46 "highlight_end": 3,
47 "highlight_start": 1,
48 "text": "({"
49 },
50 {
51 "highlight_end": 33,
52 "highlight_start": 1,
53 "text": " match (& $ left, & $ right)"
54 },
55 {
56 "highlight_end": 7,
57 "highlight_start": 1,
58 "text": " {"
59 },
60 {
61 "highlight_end": 34,
62 "highlight_start": 1,
63 "text": " (left_val, right_val) =>"
64 },
65 {
66 "highlight_end": 11,
67 "highlight_start": 1,
68 "text": " {"
69 },
70 {
71 "highlight_end": 46,
72 "highlight_start": 1,
73 "text": " if ! (* left_val == * right_val)"
74 },
75 {
76 "highlight_end": 15,
77 "highlight_start": 1,
78 "text": " {"
79 },
80 {
81 "highlight_end": 25,
82 "highlight_start": 1,
83 "text": " panic !"
84 },
85 {
86 "highlight_end": 57,
87 "highlight_start": 1,
88 "text": " (r#\"assertion failed: `(left == right)`"
89 },
90 {
91 "highlight_end": 16,
92 "highlight_start": 1,
93 "text": " left: `{:?}`,"
94 },
95 {
96 "highlight_end": 18,
97 "highlight_start": 1,
98 "text": " right: `{:?}`\"#,"
99 },
100 {
101 "highlight_end": 47,
102 "highlight_start": 1,
103 "text": " & * left_val, & * right_val)"
104 },
105 {
106 "highlight_end": 15,
107 "highlight_start": 1,
108 "text": " }"
109 },
110 {
111 "highlight_end": 11,
112 "highlight_start": 1,
113 "text": " }"
114 },
115 {
116 "highlight_end": 7,
117 "highlight_start": 1,
118 "text": " }"
119 },
120 {
121 "highlight_end": 42,
122 "highlight_start": 1,
123 "text": " }) ; ($ left : expr, $ right : expr,) =>"
124 },
125 {
126 "highlight_end": 49,
127 "highlight_start": 1,
128 "text": "({ $ crate :: assert_eq ! ($ left, $ right) }) ;"
129 },
130 {
131 "highlight_end": 53,
132 "highlight_start": 1,
133 "text": "($ left : expr, $ right : expr, $ ($ arg : tt) +) =>"
134 },
135 {
136 "highlight_end": 3,
137 "highlight_start": 1,
138 "text": "({"
139 },
140 {
141 "highlight_end": 37,
142 "highlight_start": 1,
143 "text": " match (& ($ left), & ($ right))"
144 },
145 {
146 "highlight_end": 7,
147 "highlight_start": 1,
148 "text": " {"
149 },
150 {
151 "highlight_end": 34,
152 "highlight_start": 1,
153 "text": " (left_val, right_val) =>"
154 },
155 {
156 "highlight_end": 11,
157 "highlight_start": 1,
158 "text": " {"
159 },
160 {
161 "highlight_end": 46,
162 "highlight_start": 1,
163 "text": " if ! (* left_val == * right_val)"
164 },
165 {
166 "highlight_end": 15,
167 "highlight_start": 1,
168 "text": " {"
169 },
170 {
171 "highlight_end": 25,
172 "highlight_start": 1,
173 "text": " panic !"
174 },
175 {
176 "highlight_end": 57,
177 "highlight_start": 1,
178 "text": " (r#\"assertion failed: `(left == right)`"
179 },
180 {
181 "highlight_end": 16,
182 "highlight_start": 1,
183 "text": " left: `{:?}`,"
184 },
185 {
186 "highlight_end": 22,
187 "highlight_start": 1,
188 "text": " right: `{:?}`: {}\"#,"
189 },
190 {
191 "highlight_end": 72,
192 "highlight_start": 1,
193 "text": " & * left_val, & * right_val, $ crate :: format_args !"
194 },
195 {
196 "highlight_end": 33,
197 "highlight_start": 1,
198 "text": " ($ ($ arg) +))"
199 },
200 {
201 "highlight_end": 15,
202 "highlight_start": 1,
203 "text": " }"
204 },
205 {
206 "highlight_end": 11,
207 "highlight_start": 1,
208 "text": " }"
209 },
210 {
211 "highlight_end": 7,
212 "highlight_start": 1,
213 "text": " }"
214 },
215 {
216 "highlight_end": 6,
217 "highlight_start": 1,
218 "text": " }) ;"
219 }
220 ]
221 },
222 "macro_decl_name": "assert_eq!",
223 "span": {
224 "byte_end": 38,
225 "byte_start": 16,
226 "column_end": 27,
227 "column_start": 5,
228 "expansion": null,
229 "file_name": "src/main.rs",
230 "is_primary": false,
231 "label": null,
232 "line_end": 2,
233 "line_start": 2,
234 "suggested_replacement": null,
235 "suggestion_applicability": null,
236 "text": [
237 {
238 "highlight_end": 27,
239 "highlight_start": 5,
240 "text": " assert_eq!(1, \"love\");"
241 }
242 ]
243 }
244 },
245 "file_name": "<::core::macros::assert_eq macros>",
246 "is_primary": true,
247 "label": "no implementation for `{integer} == &str`",
248 "line_end": 7,
249 "line_start": 7,
250 "suggested_replacement": null,
251 "suggestion_applicability": null,
252 "text": [
253 {
254 "highlight_end": 33,
255 "highlight_start": 31,
256 "text": " if ! (* left_val == * right_val)"
257 }
258 ]
259 }
260 ]
261}
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
index 6c7f436f3..2b25eb705 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFix.test.ts
@@ -6,12 +6,12 @@ import SuggestedFix from '../../../utils/diagnostics/SuggestedFix';
6 6
7const location1 = new vscode.Location( 7const location1 = new vscode.Location(
8 vscode.Uri.file('/file/1'), 8 vscode.Uri.file('/file/1'),
9 new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)) 9 new vscode.Range(new vscode.Position(1, 2), new vscode.Position(3, 4)),
10); 10);
11 11
12const location2 = new vscode.Location( 12const location2 = new vscode.Location(
13 vscode.Uri.file('/file/2'), 13 vscode.Uri.file('/file/2'),
14 new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)) 14 new vscode.Range(new vscode.Position(5, 6), new vscode.Position(7, 8)),
15); 15);
16 16
17describe('SuggestedFix', () => { 17describe('SuggestedFix', () => {
@@ -20,13 +20,13 @@ describe('SuggestedFix', () => {
20 const suggestion1 = new SuggestedFix( 20 const suggestion1 = new SuggestedFix(
21 'Replace me!', 21 'Replace me!',
22 location1, 22 location1,
23 'With this!' 23 'With this!',
24 ); 24 );
25 25
26 const suggestion2 = new SuggestedFix( 26 const suggestion2 = new SuggestedFix(
27 'Replace me!', 27 'Replace me!',
28 location1, 28 location1,
29 'With this!' 29 'With this!',
30 ); 30 );
31 31
32 assert(suggestion1.isEqual(suggestion2)); 32 assert(suggestion1.isEqual(suggestion2));
@@ -36,13 +36,13 @@ describe('SuggestedFix', () => {
36 const suggestion1 = new SuggestedFix( 36 const suggestion1 = new SuggestedFix(
37 'Replace me!', 37 'Replace me!',
38 location1, 38 location1,
39 'With this!' 39 'With this!',
40 ); 40 );
41 41
42 const suggestion2 = new SuggestedFix( 42 const suggestion2 = new SuggestedFix(
43 'Not the same title!', 43 'Not the same title!',
44 location1, 44 location1,
45 'With this!' 45 'With this!',
46 ); 46 );
47 47
48 assert(!suggestion1.isEqual(suggestion2)); 48 assert(!suggestion1.isEqual(suggestion2));
@@ -52,13 +52,13 @@ describe('SuggestedFix', () => {
52 const suggestion1 = new SuggestedFix( 52 const suggestion1 = new SuggestedFix(
53 'Replace me!', 53 'Replace me!',
54 location1, 54 location1,
55 'With this!' 55 'With this!',
56 ); 56 );
57 57
58 const suggestion2 = new SuggestedFix( 58 const suggestion2 = new SuggestedFix(
59 'Replace me!', 59 'Replace me!',
60 location1, 60 location1,
61 'With something else!' 61 'With something else!',
62 ); 62 );
63 63
64 assert(!suggestion1.isEqual(suggestion2)); 64 assert(!suggestion1.isEqual(suggestion2));
@@ -68,13 +68,13 @@ describe('SuggestedFix', () => {
68 const suggestion1 = new SuggestedFix( 68 const suggestion1 = new SuggestedFix(
69 'Replace me!', 69 'Replace me!',
70 location1, 70 location1,
71 'With this!' 71 'With this!',
72 ); 72 );
73 73
74 const suggestion2 = new SuggestedFix( 74 const suggestion2 = new SuggestedFix(
75 'Replace me!', 75 'Replace me!',
76 location2, 76 location2,
77 'With this!' 77 'With this!',
78 ); 78 );
79 79
80 assert(!suggestion1.isEqual(suggestion2)); 80 assert(!suggestion1.isEqual(suggestion2));
@@ -85,14 +85,14 @@ describe('SuggestedFix', () => {
85 'Replace me!', 85 'Replace me!',
86 location1, 86 location1,
87 'With this!', 87 'With this!',
88 SuggestionApplicability.MachineApplicable 88 SuggestionApplicability.MachineApplicable,
89 ); 89 );
90 90
91 const suggestion2 = new SuggestedFix( 91 const suggestion2 = new SuggestedFix(
92 'Replace me!', 92 'Replace me!',
93 location2, 93 location2,
94 'With this!', 94 'With this!',
95 SuggestionApplicability.HasPlaceholders 95 SuggestionApplicability.HasPlaceholders,
96 ); 96 );
97 97
98 assert(!suggestion1.isEqual(suggestion2)); 98 assert(!suggestion1.isEqual(suggestion2));
@@ -104,7 +104,7 @@ describe('SuggestedFix', () => {
104 const suggestion = new SuggestedFix( 104 const suggestion = new SuggestedFix(
105 'Replace me!', 105 'Replace me!',
106 location1, 106 location1,
107 'With this!' 107 'With this!',
108 ); 108 );
109 109
110 const codeAction = suggestion.toCodeAction(); 110 const codeAction = suggestion.toCodeAction();
@@ -114,7 +114,8 @@ describe('SuggestedFix', () => {
114 114
115 const edit = codeAction.edit; 115 const edit = codeAction.edit;
116 if (!edit) { 116 if (!edit) {
117 return assert.fail('Code Action edit unexpectedly missing'); 117 assert.fail('Code Action edit unexpectedly missing');
118 return;
118 } 119 }
119 120
120 const editEntries = edit.entries(); 121 const editEntries = edit.entries();
diff --git a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
index f0328893e..ef09013f4 100644
--- a/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
+++ b/editors/code/src/test/utils/diagnotics/SuggestedFixCollection.test.ts
@@ -8,20 +8,20 @@ const uri1 = vscode.Uri.file('/file/1');
8const uri2 = vscode.Uri.file('/file/2'); 8const uri2 = vscode.Uri.file('/file/2');
9 9
10const mockDocument1 = ({ 10const mockDocument1 = ({
11 uri: uri1 11 uri: uri1,
12} as unknown) as vscode.TextDocument; 12} as unknown) as vscode.TextDocument;
13 13
14const mockDocument2 = ({ 14const mockDocument2 = ({
15 uri: uri2 15 uri: uri2,
16} as unknown) as vscode.TextDocument; 16} as unknown) as vscode.TextDocument;
17 17
18const range1 = new vscode.Range( 18const range1 = new vscode.Range(
19 new vscode.Position(1, 2), 19 new vscode.Position(1, 2),
20 new vscode.Position(3, 4) 20 new vscode.Position(3, 4),
21); 21);
22const range2 = new vscode.Range( 22const range2 = new vscode.Range(
23 new vscode.Position(5, 6), 23 new vscode.Position(5, 6),
24 new vscode.Position(7, 8) 24 new vscode.Position(7, 8),
25); 25);
26 26
27const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic'); 27const diagnostic1 = new vscode.Diagnostic(range1, 'First diagnostic');
@@ -32,7 +32,7 @@ function suggestion1(): SuggestedFix {
32 return new SuggestedFix( 32 return new SuggestedFix(
33 'Replace me!', 33 'Replace me!',
34 new vscode.Location(uri1, range1), 34 new vscode.Location(uri1, range1),
35 'With this!' 35 'With this!',
36 ); 36 );
37} 37}
38 38
@@ -44,7 +44,7 @@ describe('SuggestedFixCollection', () => {
44 // Specify the document and range that exactly matches 44 // Specify the document and range that exactly matches
45 const codeActions = suggestedFixes.provideCodeActions( 45 const codeActions = suggestedFixes.provideCodeActions(
46 mockDocument1, 46 mockDocument1,
47 range1 47 range1,
48 ); 48 );
49 49
50 assert.strictEqual(codeActions.length, 1); 50 assert.strictEqual(codeActions.length, 1);
@@ -53,7 +53,8 @@ describe('SuggestedFixCollection', () => {
53 53
54 const { diagnostics } = codeAction; 54 const { diagnostics } = codeAction;
55 if (!diagnostics) { 55 if (!diagnostics) {
56 return assert.fail('Diagnostics unexpectedly missing'); 56 assert.fail('Diagnostics unexpectedly missing');
57 return;
57 } 58 }
58 59
59 assert.strictEqual(diagnostics.length, 1); 60 assert.strictEqual(diagnostics.length, 1);
@@ -66,7 +67,7 @@ describe('SuggestedFixCollection', () => {
66 67
67 const codeActions = suggestedFixes.provideCodeActions( 68 const codeActions = suggestedFixes.provideCodeActions(
68 mockDocument1, 69 mockDocument1,
69 range2 70 range2,
70 ); 71 );
71 72
72 assert(!codeActions || codeActions.length === 0); 73 assert(!codeActions || codeActions.length === 0);
@@ -78,7 +79,7 @@ describe('SuggestedFixCollection', () => {
78 79
79 const codeActions = suggestedFixes.provideCodeActions( 80 const codeActions = suggestedFixes.provideCodeActions(
80 mockDocument2, 81 mockDocument2,
81 range1 82 range1,
82 ); 83 );
83 84
84 assert(!codeActions || codeActions.length === 0); 85 assert(!codeActions || codeActions.length === 0);
@@ -91,7 +92,7 @@ describe('SuggestedFixCollection', () => {
91 92
92 const codeActions = suggestedFixes.provideCodeActions( 93 const codeActions = suggestedFixes.provideCodeActions(
93 mockDocument1, 94 mockDocument1,
94 range1 95 range1,
95 ); 96 );
96 97
97 assert(!codeActions || codeActions.length === 0); 98 assert(!codeActions || codeActions.length === 0);
@@ -106,7 +107,7 @@ describe('SuggestedFixCollection', () => {
106 107
107 const codeActions = suggestedFixes.provideCodeActions( 108 const codeActions = suggestedFixes.provideCodeActions(
108 mockDocument1, 109 mockDocument1,
109 range1 110 range1,
110 ); 111 );
111 112
112 assert.strictEqual(codeActions.length, 1); 113 assert.strictEqual(codeActions.length, 1);
@@ -114,7 +115,8 @@ describe('SuggestedFixCollection', () => {
114 const { diagnostics } = codeAction; 115 const { diagnostics } = codeAction;
115 116
116 if (!diagnostics) { 117 if (!diagnostics) {
117 return assert.fail('Diagnostics unexpectedly missing'); 118 assert.fail('Diagnostics unexpectedly missing');
119 return;
118 } 120 }
119 121
120 // We should be associated with both diagnostics 122 // We should be associated with both diagnostics
diff --git a/editors/code/src/test/utils/diagnotics/rust.test.ts b/editors/code/src/test/utils/diagnotics/rust.test.ts
index 327d15046..358325cc8 100644
--- a/editors/code/src/test/utils/diagnotics/rust.test.ts
+++ b/editors/code/src/test/utils/diagnotics/rust.test.ts
@@ -6,14 +6,14 @@ import {
6 MappedRustDiagnostic, 6 MappedRustDiagnostic,
7 mapRustDiagnosticToVsCode, 7 mapRustDiagnosticToVsCode,
8 RustDiagnostic, 8 RustDiagnostic,
9 SuggestionApplicability 9 SuggestionApplicability,
10} from '../../../utils/diagnostics/rust'; 10} from '../../../utils/diagnostics/rust';
11 11
12function loadDiagnosticFixture(name: string): RustDiagnostic { 12function loadDiagnosticFixture(name: string): RustDiagnostic {
13 const jsonText = fs 13 const jsonText = fs
14 .readFileSync( 14 .readFileSync(
15 // We're actually in our JavaScript output directory, climb out 15 // We're actually in our JavaScript output directory, climb out
16 `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json` 16 `${__dirname}/../../../../src/test/fixtures/rust-diagnostics/${name}.json`,
17 ) 17 )
18 .toString(); 18 .toString();
19 19
@@ -33,12 +33,12 @@ function mapFixtureToVsCode(name: string): MappedRustDiagnostic {
33describe('mapRustDiagnosticToVsCode', () => { 33describe('mapRustDiagnosticToVsCode', () => {
34 it('should map an incompatible type for trait error', () => { 34 it('should map an incompatible type for trait error', () => {
35 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 35 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
36 'error/E0053' 36 'error/E0053',
37 ); 37 );
38 38
39 assert.strictEqual( 39 assert.strictEqual(
40 diagnostic.severity, 40 diagnostic.severity,
41 vscode.DiagnosticSeverity.Error 41 vscode.DiagnosticSeverity.Error,
42 ); 42 );
43 assert.strictEqual(diagnostic.source, 'rustc'); 43 assert.strictEqual(diagnostic.source, 'rustc');
44 assert.strictEqual( 44 assert.strictEqual(
@@ -46,8 +46,8 @@ describe('mapRustDiagnosticToVsCode', () => {
46 [ 46 [
47 `method \`next\` has an incompatible type for trait`, 47 `method \`next\` has an incompatible type for trait`,
48 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``, 48 `expected type \`fn(&mut ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&ty::Ref<M>>\``,
49 ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\`` 49 ` found type \`fn(&ty::list_iter::ListIterator<'list, M>) -> std::option::Option<&'list ty::Ref<M>>\``,
50 ].join('\n') 50 ].join('\n'),
51 ); 51 );
52 assert.strictEqual(diagnostic.code, 'E0053'); 52 assert.strictEqual(diagnostic.code, 'E0053');
53 assert.deepStrictEqual(diagnostic.tags, []); 53 assert.deepStrictEqual(diagnostic.tags, []);
@@ -61,24 +61,24 @@ describe('mapRustDiagnosticToVsCode', () => {
61 61
62 it('should map an unused variable warning', () => { 62 it('should map an unused variable warning', () => {
63 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 63 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
64 'warning/unused_variables' 64 'warning/unused_variables',
65 ); 65 );
66 66
67 assert.strictEqual( 67 assert.strictEqual(
68 diagnostic.severity, 68 diagnostic.severity,
69 vscode.DiagnosticSeverity.Warning 69 vscode.DiagnosticSeverity.Warning,
70 ); 70 );
71 assert.strictEqual( 71 assert.strictEqual(
72 diagnostic.message, 72 diagnostic.message,
73 [ 73 [
74 'unused variable: `foo`', 74 'unused variable: `foo`',
75 '#[warn(unused_variables)] on by default' 75 '#[warn(unused_variables)] on by default',
76 ].join('\n') 76 ].join('\n'),
77 ); 77 );
78 assert.strictEqual(diagnostic.code, 'unused_variables'); 78 assert.strictEqual(diagnostic.code, 'unused_variables');
79 assert.strictEqual(diagnostic.source, 'rustc'); 79 assert.strictEqual(diagnostic.source, 'rustc');
80 assert.deepStrictEqual(diagnostic.tags, [ 80 assert.deepStrictEqual(diagnostic.tags, [
81 vscode.DiagnosticTag.Unnecessary 81 vscode.DiagnosticTag.Unnecessary,
82 ]); 82 ]);
83 83
84 // No related information 84 // No related information
@@ -89,29 +89,29 @@ describe('mapRustDiagnosticToVsCode', () => {
89 const [suggestedFix] = suggestedFixes; 89 const [suggestedFix] = suggestedFixes;
90 assert.strictEqual( 90 assert.strictEqual(
91 suggestedFix.title, 91 suggestedFix.title,
92 'consider prefixing with an underscore: `_foo`' 92 'consider prefixing with an underscore: `_foo`',
93 ); 93 );
94 assert.strictEqual( 94 assert.strictEqual(
95 suggestedFix.applicability, 95 suggestedFix.applicability,
96 SuggestionApplicability.MachineApplicable 96 SuggestionApplicability.MachineApplicable,
97 ); 97 );
98 }); 98 });
99 99
100 it('should map a wrong number of parameters error', () => { 100 it('should map a wrong number of parameters error', () => {
101 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 101 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
102 'error/E0061' 102 'error/E0061',
103 ); 103 );
104 104
105 assert.strictEqual( 105 assert.strictEqual(
106 diagnostic.severity, 106 diagnostic.severity,
107 vscode.DiagnosticSeverity.Error 107 vscode.DiagnosticSeverity.Error,
108 ); 108 );
109 assert.strictEqual( 109 assert.strictEqual(
110 diagnostic.message, 110 diagnostic.message,
111 [ 111 [
112 'this function takes 2 parameters but 3 parameters were supplied', 112 'this function takes 2 parameters but 3 parameters were supplied',
113 'expected 2 parameters' 113 'expected 2 parameters',
114 ].join('\n') 114 ].join('\n'),
115 ); 115 );
116 assert.strictEqual(diagnostic.code, 'E0061'); 116 assert.strictEqual(diagnostic.code, 'E0061');
117 assert.strictEqual(diagnostic.source, 'rustc'); 117 assert.strictEqual(diagnostic.source, 'rustc');
@@ -120,7 +120,8 @@ describe('mapRustDiagnosticToVsCode', () => {
120 // One related information for the original definition 120 // One related information for the original definition
121 const relatedInformation = diagnostic.relatedInformation; 121 const relatedInformation = diagnostic.relatedInformation;
122 if (!relatedInformation) { 122 if (!relatedInformation) {
123 return assert.fail('Related information unexpectedly undefined'); 123 assert.fail('Related information unexpectedly undefined');
124 return;
124 } 125 }
125 assert.strictEqual(relatedInformation.length, 1); 126 assert.strictEqual(relatedInformation.length, 1);
126 const [related] = relatedInformation; 127 const [related] = relatedInformation;
@@ -132,12 +133,12 @@ describe('mapRustDiagnosticToVsCode', () => {
132 133
133 it('should map a Clippy copy pass by ref warning', () => { 134 it('should map a Clippy copy pass by ref warning', () => {
134 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 135 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
135 'clippy/trivially_copy_pass_by_ref' 136 'clippy/trivially_copy_pass_by_ref',
136 ); 137 );
137 138
138 assert.strictEqual( 139 assert.strictEqual(
139 diagnostic.severity, 140 diagnostic.severity,
140 vscode.DiagnosticSeverity.Warning 141 vscode.DiagnosticSeverity.Warning,
141 ); 142 );
142 assert.strictEqual(diagnostic.source, 'clippy'); 143 assert.strictEqual(diagnostic.source, 'clippy');
143 assert.strictEqual( 144 assert.strictEqual(
@@ -145,8 +146,8 @@ describe('mapRustDiagnosticToVsCode', () => {
145 [ 146 [
146 'this argument is passed by reference, but would be more efficient if passed by value', 147 'this argument is passed by reference, but would be more efficient if passed by value',
147 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]', 148 '#[warn(clippy::trivially_copy_pass_by_ref)] implied by #[warn(clippy::all)]',
148 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref' 149 'for further information visit https://rust-lang.github.io/rust-clippy/master/index.html#trivially_copy_pass_by_ref',
149 ].join('\n') 150 ].join('\n'),
150 ); 151 );
151 assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref'); 152 assert.strictEqual(diagnostic.code, 'trivially_copy_pass_by_ref');
152 assert.deepStrictEqual(diagnostic.tags, []); 153 assert.deepStrictEqual(diagnostic.tags, []);
@@ -154,7 +155,8 @@ describe('mapRustDiagnosticToVsCode', () => {
154 // One related information for the lint definition 155 // One related information for the lint definition
155 const relatedInformation = diagnostic.relatedInformation; 156 const relatedInformation = diagnostic.relatedInformation;
156 if (!relatedInformation) { 157 if (!relatedInformation) {
157 return assert.fail('Related information unexpectedly undefined'); 158 assert.fail('Related information unexpectedly undefined');
159 return;
158 } 160 }
159 assert.strictEqual(relatedInformation.length, 1); 161 assert.strictEqual(relatedInformation.length, 1);
160 const [related] = relatedInformation; 162 const [related] = relatedInformation;
@@ -165,27 +167,27 @@ describe('mapRustDiagnosticToVsCode', () => {
165 const [suggestedFix] = suggestedFixes; 167 const [suggestedFix] = suggestedFixes;
166 assert.strictEqual( 168 assert.strictEqual(
167 suggestedFix.title, 169 suggestedFix.title,
168 'consider passing by value instead: `self`' 170 'consider passing by value instead: `self`',
169 ); 171 );
170 // Clippy does not mark this with any applicability 172 // Clippy does not mark this with any applicability
171 assert.strictEqual( 173 assert.strictEqual(
172 suggestedFix.applicability, 174 suggestedFix.applicability,
173 SuggestionApplicability.Unspecified 175 SuggestionApplicability.Unspecified,
174 ); 176 );
175 }); 177 });
176 178
177 it('should map a mismatched type error', () => { 179 it('should map a mismatched type error', () => {
178 const { diagnostic, suggestedFixes } = mapFixtureToVsCode( 180 const { diagnostic, suggestedFixes } = mapFixtureToVsCode(
179 'error/E0308' 181 'error/E0308',
180 ); 182 );
181 183
182 assert.strictEqual( 184 assert.strictEqual(
183 diagnostic.severity, 185 diagnostic.severity,
184 vscode.DiagnosticSeverity.Error 186 vscode.DiagnosticSeverity.Error,
185 ); 187 );
186 assert.strictEqual( 188 assert.strictEqual(
187 diagnostic.message, 189 diagnostic.message,
188 ['mismatched types', 'expected usize, found u32'].join('\n') 190 ['mismatched types', 'expected usize, found u32'].join('\n'),
189 ); 191 );
190 assert.strictEqual(diagnostic.code, 'E0308'); 192 assert.strictEqual(diagnostic.code, 'E0308');
191 assert.strictEqual(diagnostic.source, 'rustc'); 193 assert.strictEqual(diagnostic.source, 'rustc');
@@ -197,4 +199,38 @@ describe('mapRustDiagnosticToVsCode', () => {
197 // There are no suggested fixes 199 // There are no suggested fixes
198 assert.strictEqual(suggestedFixes.length, 0); 200 assert.strictEqual(suggestedFixes.length, 0);
199 }); 201 });
202
203 it('should map a macro invocation location to normal file path', () => {
204 const { location, diagnostic, suggestedFixes } = mapFixtureToVsCode(
205 'error/E0277',
206 );
207
208 assert.strictEqual(
209 diagnostic.severity,
210 vscode.DiagnosticSeverity.Error,
211 );
212 assert.strictEqual(
213 diagnostic.message,
214 [
215 "can't compare `{integer}` with `&str`",
216 'the trait `std::cmp::PartialEq<&str>` is not implemented for `{integer}`',
217 ].join('\n'),
218 );
219 assert.strictEqual(diagnostic.code, 'E0277');
220 assert.strictEqual(diagnostic.source, 'rustc');
221 assert.deepStrictEqual(diagnostic.tags, []);
222
223 // No related information
224 assert.deepStrictEqual(diagnostic.relatedInformation, []);
225
226 // There are no suggested fixes
227 assert.strictEqual(suggestedFixes.length, 0);
228
229 // The file url should be normal file
230 // Ignore the first part because it depends on vs workspace location
231 assert.strictEqual(
232 location.uri.path.substr(-'src/main.rs'.length),
233 'src/main.rs',
234 );
235 });
200}); 236});
diff --git a/editors/code/src/test/utils/diagnotics/vscode.test.ts b/editors/code/src/test/utils/diagnotics/vscode.test.ts
index 542dec1f5..4944dd032 100644
--- a/editors/code/src/test/utils/diagnotics/vscode.test.ts
+++ b/editors/code/src/test/utils/diagnotics/vscode.test.ts
@@ -5,12 +5,12 @@ import { areDiagnosticsEqual } from '../../../utils/diagnostics/vscode';
5 5
6const range1 = new vscode.Range( 6const range1 = new vscode.Range(
7 new vscode.Position(1, 2), 7 new vscode.Position(1, 2),
8 new vscode.Position(3, 4) 8 new vscode.Position(3, 4),
9); 9);
10 10
11const range2 = new vscode.Range( 11const range2 = new vscode.Range(
12 new vscode.Position(5, 6), 12 new vscode.Position(5, 6),
13 new vscode.Position(7, 8) 13 new vscode.Position(7, 8),
14); 14);
15 15
16describe('areDiagnosticsEqual', () => { 16describe('areDiagnosticsEqual', () => {
@@ -18,13 +18,13 @@ describe('areDiagnosticsEqual', () => {
18 const diagnostic1 = new vscode.Diagnostic( 18 const diagnostic1 = new vscode.Diagnostic(
19 range1, 19 range1,
20 'Hello, world!', 20 'Hello, world!',
21 vscode.DiagnosticSeverity.Error 21 vscode.DiagnosticSeverity.Error,
22 ); 22 );
23 23
24 const diagnostic2 = new vscode.Diagnostic( 24 const diagnostic2 = new vscode.Diagnostic(
25 range1, 25 range1,
26 'Hello, world!', 26 'Hello, world!',
27 vscode.DiagnosticSeverity.Error 27 vscode.DiagnosticSeverity.Error,
28 ); 28 );
29 29
30 assert(areDiagnosticsEqual(diagnostic1, diagnostic2)); 30 assert(areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -34,14 +34,14 @@ describe('areDiagnosticsEqual', () => {
34 const diagnostic1 = new vscode.Diagnostic( 34 const diagnostic1 = new vscode.Diagnostic(
35 range1, 35 range1,
36 'Hello, world!', 36 'Hello, world!',
37 vscode.DiagnosticSeverity.Error 37 vscode.DiagnosticSeverity.Error,
38 ); 38 );
39 diagnostic1.source = 'rustc'; 39 diagnostic1.source = 'rustc';
40 40
41 const diagnostic2 = new vscode.Diagnostic( 41 const diagnostic2 = new vscode.Diagnostic(
42 range1, 42 range1,
43 'Hello, world!', 43 'Hello, world!',
44 vscode.DiagnosticSeverity.Error 44 vscode.DiagnosticSeverity.Error,
45 ); 45 );
46 diagnostic2.source = 'clippy'; 46 diagnostic2.source = 'clippy';
47 47
@@ -52,13 +52,13 @@ describe('areDiagnosticsEqual', () => {
52 const diagnostic1 = new vscode.Diagnostic( 52 const diagnostic1 = new vscode.Diagnostic(
53 range1, 53 range1,
54 'Hello, world!', 54 'Hello, world!',
55 vscode.DiagnosticSeverity.Error 55 vscode.DiagnosticSeverity.Error,
56 ); 56 );
57 57
58 const diagnostic2 = new vscode.Diagnostic( 58 const diagnostic2 = new vscode.Diagnostic(
59 range2, 59 range2,
60 'Hello, world!', 60 'Hello, world!',
61 vscode.DiagnosticSeverity.Error 61 vscode.DiagnosticSeverity.Error,
62 ); 62 );
63 63
64 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 64 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -68,13 +68,13 @@ describe('areDiagnosticsEqual', () => {
68 const diagnostic1 = new vscode.Diagnostic( 68 const diagnostic1 = new vscode.Diagnostic(
69 range1, 69 range1,
70 'Hello, world!', 70 'Hello, world!',
71 vscode.DiagnosticSeverity.Error 71 vscode.DiagnosticSeverity.Error,
72 ); 72 );
73 73
74 const diagnostic2 = new vscode.Diagnostic( 74 const diagnostic2 = new vscode.Diagnostic(
75 range1, 75 range1,
76 'Goodbye!, world!', 76 'Goodbye!, world!',
77 vscode.DiagnosticSeverity.Error 77 vscode.DiagnosticSeverity.Error,
78 ); 78 );
79 79
80 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 80 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
@@ -84,13 +84,13 @@ describe('areDiagnosticsEqual', () => {
84 const diagnostic1 = new vscode.Diagnostic( 84 const diagnostic1 = new vscode.Diagnostic(
85 range1, 85 range1,
86 'Hello, world!', 86 'Hello, world!',
87 vscode.DiagnosticSeverity.Warning 87 vscode.DiagnosticSeverity.Warning,
88 ); 88 );
89 89
90 const diagnostic2 = new vscode.Diagnostic( 90 const diagnostic2 = new vscode.Diagnostic(
91 range1, 91 range1,
92 'Hello, world!', 92 'Hello, world!',
93 vscode.DiagnosticSeverity.Error 93 vscode.DiagnosticSeverity.Error,
94 ); 94 );
95 95
96 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2)); 96 assert(!areDiagnosticsEqual(diagnostic1, diagnostic2));
diff --git a/editors/code/src/test/utils/index.ts b/editors/code/src/test/utils/index.ts
index 16715a286..9927daaf6 100644
--- a/editors/code/src/test/utils/index.ts
+++ b/editors/code/src/test/utils/index.ts
@@ -17,7 +17,7 @@ import * as path from 'path';
17export function run(): Promise<void> { 17export function run(): Promise<void> {
18 // Create the mocha test 18 // Create the mocha test
19 const mocha = new Mocha({ 19 const mocha = new Mocha({
20 ui: 'bdd' 20 ui: 'bdd',
21 }); 21 });
22 mocha.useColors(true); 22 mocha.useColors(true);
23 23
diff --git a/editors/code/src/utils/diagnostics/SuggestedFix.ts b/editors/code/src/utils/diagnostics/SuggestedFix.ts
index b1be2a225..6e660bb61 100644
--- a/editors/code/src/utils/diagnostics/SuggestedFix.ts
+++ b/editors/code/src/utils/diagnostics/SuggestedFix.ts
@@ -24,7 +24,7 @@ export default class SuggestedFix {
24 title: string, 24 title: string,
25 location: vscode.Location, 25 location: vscode.Location,
26 replacement: string, 26 replacement: string,
27 applicability: SuggestionApplicability = SuggestionApplicability.Unspecified 27 applicability: SuggestionApplicability = SuggestionApplicability.Unspecified,
28 ) { 28 ) {
29 this.title = title; 29 this.title = title;
30 this.location = location; 30 this.location = location;
@@ -51,7 +51,7 @@ export default class SuggestedFix {
51 public toCodeAction(): vscode.CodeAction { 51 public toCodeAction(): vscode.CodeAction {
52 const codeAction = new vscode.CodeAction( 52 const codeAction = new vscode.CodeAction(
53 this.title, 53 this.title,
54 vscode.CodeActionKind.QuickFix 54 vscode.CodeActionKind.QuickFix,
55 ); 55 );
56 56
57 const edit = new vscode.WorkspaceEdit(); 57 const edit = new vscode.WorkspaceEdit();
diff --git a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
index 132ce12f8..57c9856cf 100644
--- a/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
+++ b/editors/code/src/utils/diagnostics/SuggestedFixCollection.ts
@@ -38,13 +38,13 @@ export default class SuggestedFixCollection
38 */ 38 */
39 public addSuggestedFixForDiagnostic( 39 public addSuggestedFixForDiagnostic(
40 suggestedFix: SuggestedFix, 40 suggestedFix: SuggestedFix,
41 diagnostic: vscode.Diagnostic 41 diagnostic: vscode.Diagnostic,
42 ): void { 42 ): void {
43 const fileUriString = suggestedFix.location.uri.toString(); 43 const fileUriString = suggestedFix.location.uri.toString();
44 const fileSuggestions = this.suggestedFixes.get(fileUriString) || []; 44 const fileSuggestions = this.suggestedFixes.get(fileUriString) || [];
45 45
46 const existingSuggestion = fileSuggestions.find(s => 46 const existingSuggestion = fileSuggestions.find(s =>
47 s.isEqual(suggestedFix) 47 s.isEqual(suggestedFix),
48 ); 48 );
49 49
50 if (existingSuggestion) { 50 if (existingSuggestion) {
@@ -65,7 +65,7 @@ export default class SuggestedFixCollection
65 */ 65 */
66 public provideCodeActions( 66 public provideCodeActions(
67 document: vscode.TextDocument, 67 document: vscode.TextDocument,
68 range: vscode.Range 68 range: vscode.Range,
69 ): vscode.CodeAction[] { 69 ): vscode.CodeAction[] {
70 const documentUriString = document.uri.toString(); 70 const documentUriString = document.uri.toString();
71 71
diff --git a/editors/code/src/utils/diagnostics/rust.ts b/editors/code/src/utils/diagnostics/rust.ts
index 0550d0372..1f0c0d3e4 100644
--- a/editors/code/src/utils/diagnostics/rust.ts
+++ b/editors/code/src/utils/diagnostics/rust.ts
@@ -7,7 +7,13 @@ export enum SuggestionApplicability {
7 MachineApplicable = 'MachineApplicable', 7 MachineApplicable = 'MachineApplicable',
8 HasPlaceholders = 'HasPlaceholders', 8 HasPlaceholders = 'HasPlaceholders',
9 MaybeIncorrect = 'MaybeIncorrect', 9 MaybeIncorrect = 'MaybeIncorrect',
10 Unspecified = 'Unspecified' 10 Unspecified = 'Unspecified',
11}
12
13export interface RustDiagnosticSpanMacroExpansion {
14 span: RustDiagnosticSpan;
15 macro_decl_name: string;
16 def_site_span?: RustDiagnosticSpan;
11} 17}
12 18
13// Reference: 19// Reference:
@@ -20,6 +26,7 @@ export interface RustDiagnosticSpan {
20 is_primary: boolean; 26 is_primary: boolean;
21 file_name: string; 27 file_name: string;
22 label?: string; 28 label?: string;
29 expansion?: RustDiagnosticSpanMacroExpansion;
23 suggested_replacement?: string; 30 suggested_replacement?: string;
24 suggestion_applicability?: SuggestionApplicability; 31 suggestion_applicability?: SuggestionApplicability;
25} 32}
@@ -61,15 +68,46 @@ function mapLevelToSeverity(s: string): vscode.DiagnosticSeverity {
61} 68}
62 69
63/** 70/**
71 * Check whether a file name is from macro invocation
72 */
73function isFromMacro(fileName: string): boolean {
74 return fileName.startsWith('<') && fileName.endsWith('>');
75}
76
77/**
78 * Converts a Rust macro span to a VsCode location recursively
79 */
80function mapMacroSpanToLocation(
81 spanMacro: RustDiagnosticSpanMacroExpansion,
82): vscode.Location | undefined {
83 if (!isFromMacro(spanMacro.span.file_name)) {
84 return mapSpanToLocation(spanMacro.span);
85 }
86
87 if (spanMacro.span.expansion) {
88 return mapMacroSpanToLocation(spanMacro.span.expansion);
89 }
90
91 return;
92}
93
94/**
64 * Converts a Rust span to a VsCode location 95 * Converts a Rust span to a VsCode location
65 */ 96 */
66function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location { 97function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
98 if (isFromMacro(span.file_name) && span.expansion) {
99 const macroLoc = mapMacroSpanToLocation(span.expansion);
100 if (macroLoc) {
101 return macroLoc;
102 }
103 }
104
67 const fileName = path.join(vscode.workspace.rootPath || '', span.file_name); 105 const fileName = path.join(vscode.workspace.rootPath || '', span.file_name);
68 const fileUri = vscode.Uri.file(fileName); 106 const fileUri = vscode.Uri.file(fileName);
69 107
70 const range = new vscode.Range( 108 const range = new vscode.Range(
71 new vscode.Position(span.line_start - 1, span.column_start - 1), 109 new vscode.Position(span.line_start - 1, span.column_start - 1),
72 new vscode.Position(span.line_end - 1, span.column_end - 1) 110 new vscode.Position(span.line_end - 1, span.column_end - 1),
73 ); 111 );
74 112
75 return new vscode.Location(fileUri, range); 113 return new vscode.Location(fileUri, range);
@@ -81,7 +119,7 @@ function mapSpanToLocation(span: RustDiagnosticSpan): vscode.Location {
81 * If the span is unlabelled this will return `undefined`. 119 * If the span is unlabelled this will return `undefined`.
82 */ 120 */
83function mapSecondarySpanToRelated( 121function mapSecondarySpanToRelated(
84 span: RustDiagnosticSpan 122 span: RustDiagnosticSpan,
85): vscode.DiagnosticRelatedInformation | undefined { 123): vscode.DiagnosticRelatedInformation | undefined {
86 if (!span.label) { 124 if (!span.label) {
87 // Nothing to label this with 125 // Nothing to label this with
@@ -107,7 +145,7 @@ function isUnusedOrUnnecessary(rd: RustDiagnostic): boolean {
107 'unused_attributes', 145 'unused_attributes',
108 'unused_imports', 146 'unused_imports',
109 'unused_macros', 147 'unused_macros',
110 'unused_variables' 148 'unused_variables',
111 ].includes(rd.code.code); 149 ].includes(rd.code.code);
112} 150}
113 151
@@ -157,13 +195,13 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
157 title, 195 title,
158 location, 196 location,
159 span.suggested_replacement, 197 span.suggested_replacement,
160 span.suggestion_applicability 198 span.suggestion_applicability,
161 ) 199 ),
162 }; 200 };
163 } else { 201 } else {
164 const related = new vscode.DiagnosticRelatedInformation( 202 const related = new vscode.DiagnosticRelatedInformation(
165 location, 203 location,
166 rd.message 204 rd.message,
167 ); 205 );
168 206
169 return { related }; 207 return { related };
@@ -183,7 +221,7 @@ function mapRustChildDiagnostic(rd: RustDiagnostic): MappedRustChildDiagnostic {
183 * If the diagnostic has no primary span this will return `undefined` 221 * If the diagnostic has no primary span this will return `undefined`
184 */ 222 */
185export function mapRustDiagnosticToVsCode( 223export function mapRustDiagnosticToVsCode(
186 rd: RustDiagnostic 224 rd: RustDiagnostic,
187): MappedRustDiagnostic | undefined { 225): MappedRustDiagnostic | undefined {
188 const primarySpan = rd.spans.find(s => s.is_primary); 226 const primarySpan = rd.spans.find(s => s.is_primary);
189 if (!primarySpan) { 227 if (!primarySpan) {
@@ -223,7 +261,7 @@ export function mapRustDiagnosticToVsCode(
223 const suggestedFixes = []; 261 const suggestedFixes = [];
224 for (const child of rd.children) { 262 for (const child of rd.children) {
225 const { related, suggestedFix, messageLine } = mapRustChildDiagnostic( 263 const { related, suggestedFix, messageLine } = mapRustChildDiagnostic(
226 child 264 child,
227 ); 265 );
228 266
229 if (related) { 267 if (related) {
@@ -256,6 +294,6 @@ export function mapRustDiagnosticToVsCode(
256 return { 294 return {
257 location, 295 location,
258 diagnostic: vd, 296 diagnostic: vd,
259 suggestedFixes 297 suggestedFixes,
260 }; 298 };
261} 299}
diff --git a/editors/code/src/utils/diagnostics/vscode.ts b/editors/code/src/utils/diagnostics/vscode.ts
index d8b85b720..f4a5450e2 100644
--- a/editors/code/src/utils/diagnostics/vscode.ts
+++ b/editors/code/src/utils/diagnostics/vscode.ts
@@ -3,7 +3,7 @@ import * as vscode from 'vscode';
3/** Compares two `vscode.Diagnostic`s for equality */ 3/** Compares two `vscode.Diagnostic`s for equality */
4export function areDiagnosticsEqual( 4export function areDiagnosticsEqual(
5 left: vscode.Diagnostic, 5 left: vscode.Diagnostic,
6 right: vscode.Diagnostic 6 right: vscode.Diagnostic,
7): boolean { 7): boolean {
8 return ( 8 return (
9 left.source === right.source && 9 left.source === right.source &&
diff --git a/editors/code/src/utils/processes.ts b/editors/code/src/utils/processes.ts
index da8be9eb1..a1d6b7eaf 100644
--- a/editors/code/src/utils/processes.ts
+++ b/editors/code/src/utils/processes.ts
@@ -22,7 +22,7 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
22 // Ignore stderr since this is otherwise piped to parent.stderr 22 // Ignore stderr since this is otherwise piped to parent.stderr
23 // which might be already closed. 23 // which might be already closed.
24 const options: any = { 24 const options: any = {
25 stdio: ['pipe', 'pipe', 'ignore'] 25 stdio: ['pipe', 'pipe', 'ignore'],
26 }; 26 };
27 if (cwd) { 27 if (cwd) {
28 options.cwd = cwd; 28 options.cwd = cwd;
@@ -30,7 +30,7 @@ export function terminate(process: ChildProcess, cwd?: string): boolean {
30 cp.execFileSync( 30 cp.execFileSync(
31 'taskkill', 31 'taskkill',
32 ['/T', '/F', '/PID', process.pid.toString()], 32 ['/T', '/F', '/PID', process.pid.toString()],
33 options 33 options,
34 ); 34 );
35 return true; 35 return true;
36 } catch (err) { 36 } catch (err) {
diff --git a/editors/code/tsconfig.json b/editors/code/tsconfig.json
index 9ad2e967b..5e11c3775 100644
--- a/editors/code/tsconfig.json
+++ b/editors/code/tsconfig.json
@@ -1,13 +1,16 @@
1{ 1{
2 "compilerOptions": { 2 "compilerOptions": {
3 "module": "commonjs", 3 "module": "commonjs",
4 "target": "es6", 4 "target": "es2018",
5 "outDir": "out", 5 "outDir": "out",
6 "lib": ["es6"], 6 "lib": ["es2018"],
7 "sourceMap": true, 7 "sourceMap": true,
8 "rootDir": "src", 8 "rootDir": "src",
9 "strict": true, 9 "strict": true,
10 "noUnusedLocals": true 10 "noUnusedLocals": true,
11 "noUnusedParameters": true,
12 "noImplicitReturns": true,
13 "noFallthroughCasesInSwitch": true
11 }, 14 },
12 "exclude": ["node_modules", ".vscode-test"] 15 "exclude": ["node_modules", ".vscode-test"]
13} 16}
diff --git a/editors/code/tslint.json b/editors/code/tslint.json
index bdeb4895e..f06fa5fab 100644
--- a/editors/code/tslint.json
+++ b/editors/code/tslint.json
@@ -1,9 +1,15 @@
1{ 1{
2 "defaultSeverity": "error", 2 "defaultSeverity": "error",
3 "extends": ["tslint:recommended", "tslint-config-prettier"], 3 "extends": [
4 "tslint:recommended",
5 "tslint-config-prettier",
6 "tslint-plugin-prettier"
7 ],
4 "rules": { 8 "rules": {
5 "quotemark": [true, "single"],
6 "interface-name": false, 9 "interface-name": false,
7 "object-literal-sort-keys": false 10 "prettier": true,
11 "object-literal-sort-keys": false,
12 // Allow `_bar` to sort with tsc's `noUnusedParameters` option
13 "variable-name": [true, "allow-leading-underscore"]
8 } 14 }
9} 15}
diff --git a/xtask/src/lib.rs b/xtask/src/lib.rs
index 7332a4072..40a6682be 100644
--- a/xtask/src/lib.rs
+++ b/xtask/src/lib.rs
@@ -79,7 +79,7 @@ pub fn run_rustfmt(mode: Mode) -> Result<()> {
79} 79}
80 80
81pub fn install_rustfmt() -> Result<()> { 81pub fn install_rustfmt() -> Result<()> {
82 run(&format!("rustup install {}", TOOLCHAIN), ".")?; 82 run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
83 run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".") 83 run(&format!("rustup component add rustfmt --toolchain {}", TOOLCHAIN), ".")
84} 84}
85 85
@@ -125,7 +125,7 @@ pub fn run_clippy() -> Result<()> {
125} 125}
126 126
127pub fn install_clippy() -> Result<()> { 127pub fn install_clippy() -> Result<()> {
128 run(&format!("rustup install {}", TOOLCHAIN), ".")?; 128 run(&format!("rustup toolchain install {}", TOOLCHAIN), ".")?;
129 run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".") 129 run(&format!("rustup component add clippy --toolchain {}", TOOLCHAIN), ".")
130} 130}
131 131
@@ -144,6 +144,7 @@ pub fn run_fuzzer() -> Result<()> {
144} 144}
145 145
146pub fn reformat_staged_files() -> Result<()> { 146pub fn reformat_staged_files() -> Result<()> {
147 run_rustfmt(Mode::Overwrite)?;
147 let root = project_root(); 148 let root = project_root();
148 let output = Command::new("git") 149 let output = Command::new("git")
149 .arg("diff") 150 .arg("diff")
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index c97bfec97..4201c6a6a 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -20,7 +20,7 @@ use xtask::{
20}; 20};
21 21
22// Latest stable, feel free to send a PR if this lags behind. 22// Latest stable, feel free to send a PR if this lags behind.
23const REQUIRED_RUST_VERSION: u32 = 39; 23const REQUIRED_RUST_VERSION: u32 = 40;
24 24
25struct InstallOpt { 25struct InstallOpt {
26 client: Option<ClientOpt>, 26 client: Option<ClientOpt>,
@@ -182,7 +182,8 @@ fn install_client(ClientOpt::VsCode: ClientOpt) -> Result<()> {
182 eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin") 182 eprintln!("\nERROR: `npm --version` failed, `npm` is required to build the VS Code plugin")
183 } 183 }
184 184
185 Cmd { unix: r"npm ci", windows: r"cmd.exe /c npm ci", work_dir: "./editors/code" }.run()?; 185 Cmd { unix: r"npm install", windows: r"cmd.exe /c npm install", work_dir: "./editors/code" }
186 .run()?;
186 Cmd { 187 Cmd {
187 unix: r"npm run package --scripts-prepend-node-path", 188 unix: r"npm run package --scripts-prepend-node-path",
188 windows: r"cmd.exe /c npm run package", 189 windows: r"cmd.exe /c npm run package",