aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/release.yaml32
-rw-r--r--Cargo.lock15
-rw-r--r--README.md20
-rw-r--r--crates/ra_assists/src/assist_ctx.rs109
-rw-r--r--crates/ra_assists/src/doc_tests.rs2
-rw-r--r--crates/ra_assists/src/doc_tests/generated.rs32
-rw-r--r--crates/ra_assists/src/handlers/add_new.rs14
-rw-r--r--crates/ra_assists/src/handlers/auto_import.rs99
-rw-r--r--crates/ra_assists/src/handlers/fill_match_arms.rs6
-rw-r--r--crates/ra_assists/src/handlers/merge_match_arms.rs8
-rw-r--r--crates/ra_assists/src/handlers/move_guard.rs6
-rw-r--r--crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs (renamed from crates/ra_assists/src/handlers/add_import.rs)114
-rw-r--r--crates/ra_assists/src/lib.rs70
-rw-r--r--crates/ra_hir/src/code_model.rs28
-rw-r--r--crates/ra_hir/src/lib.rs3
-rw-r--r--crates/ra_hir/src/source_analyzer.rs8
-rw-r--r--crates/ra_hir_def/src/body/lower.rs15
-rw-r--r--crates/ra_hir_def/src/body/scope.rs6
-rw-r--r--crates/ra_hir_def/src/expr.rs5
-rw-r--r--crates/ra_hir_def/src/generics.rs73
-rw-r--r--crates/ra_hir_def/src/resolver.rs10
-rw-r--r--crates/ra_hir_def/src/type_ref.rs42
-rw-r--r--crates/ra_hir_expand/src/name.rs7
-rw-r--r--crates/ra_hir_ty/src/db.rs34
-rw-r--r--crates/ra_hir_ty/src/infer.rs66
-rw-r--r--crates/ra_hir_ty/src/infer/coerce.rs18
-rw-r--r--crates/ra_hir_ty/src/infer/expr.rs28
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs19
-rw-r--r--crates/ra_hir_ty/src/infer/path.rs60
-rw-r--r--crates/ra_hir_ty/src/lib.rs262
-rw-r--r--crates/ra_hir_ty/src/lower.rs577
-rw-r--r--crates/ra_hir_ty/src/marks.rs1
-rw-r--r--crates/ra_hir_ty/src/method_resolution.rs6
-rw-r--r--crates/ra_hir_ty/src/tests/coercion.rs26
-rw-r--r--crates/ra_hir_ty/src/tests/method_resolution.rs48
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs4
-rw-r--r--crates/ra_hir_ty/src/tests/regression.rs2
-rw-r--r--crates/ra_hir_ty/src/tests/simple.rs42
-rw-r--r--crates/ra_hir_ty/src/tests/traits.rs312
-rw-r--r--crates/ra_hir_ty/src/traits/chalk.rs33
-rw-r--r--crates/ra_hir_ty/src/utils.rs91
-rw-r--r--crates/ra_ide/src/assists.rs24
-rw-r--r--crates/ra_ide/src/completion/complete_scope.rs136
-rw-r--r--crates/ra_ide/src/inlay_hints.rs5
-rw-r--r--crates/ra_lsp_server/src/lib.rs8
-rw-r--r--crates/ra_lsp_server/src/main.rs17
-rw-r--r--crates/ra_lsp_server/src/main_loop/handlers.rs79
-rw-r--r--crates/ra_parser/src/grammar/expressions/atom.rs4
-rw-r--r--crates/ra_parser/src/grammar/params.rs4
-rw-r--r--crates/ra_parser/src/grammar/patterns.rs67
-rw-r--r--crates/ra_parser/src/syntax_kind/generated.rs4
-rw-r--r--crates/ra_project_model/src/sysroot.rs3
-rw-r--r--crates/ra_syntax/Cargo.toml2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs83
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0030_cond.txt86
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0066_match_arm.txt38
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.rs3
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0111_tuple_pat.txt62
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.rs8
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0156_or_pattern.txt112
-rw-r--r--crates/ra_text_edit/src/lib.rs4
-rw-r--r--crates/ra_text_edit/src/text_edit.rs6
-rw-r--r--docs/dev/README.md11
-rw-r--r--docs/user/README.md96
-rw-r--r--docs/user/assists.md28
-rw-r--r--editors/code/package-lock.json25
-rw-r--r--editors/code/package.json11
-rw-r--r--editors/code/src/client.ts22
-rw-r--r--editors/code/src/config.ts94
-rw-r--r--editors/code/src/ctx.ts12
-rw-r--r--editors/code/src/installation/download_file.ts40
-rw-r--r--editors/code/src/installation/fetch_latest_artifact_metadata.ts46
-rw-r--r--editors/code/src/installation/interfaces.ts55
-rw-r--r--editors/code/src/installation/language_server.ts147
-rw-r--r--editors/code/tsconfig.json2
-rw-r--r--xtask/src/ast_src.rs8
-rw-r--r--xtask/src/cmd.rs9
-rw-r--r--xtask/src/install.rs36
-rw-r--r--xtask/src/lib.rs46
-rw-r--r--xtask/src/main.rs6
-rw-r--r--xtask/src/pre_commit.rs2
81 files changed, 2550 insertions, 1254 deletions
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 77c92512a..ff7a95ee1 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -95,9 +95,6 @@ jobs:
95 - name: Copy vscode extension 95 - name: Copy vscode extension
96 run: mkdir -p ./dist/code && cp ./editors/code/*.vsix ./dist/ 96 run: mkdir -p ./dist/code && cp ./editors/code/*.vsix ./dist/
97 97
98 - name: Copy emacs mode
99 run: cp ./editors/emacs/rust-analyzer.el ./dist/rust-analyzer.el
100
101 - name: Upload artifacts 98 - name: Upload artifacts
102 uses: actions/upload-artifact@v1 99 uses: actions/upload-artifact@v1
103 with: 100 with:
@@ -109,6 +106,17 @@ jobs:
109 runs-on: ubuntu-latest 106 runs-on: ubuntu-latest
110 needs: ['build-server', 'build-clients'] 107 needs: ['build-server', 'build-clients']
111 steps: 108 steps:
109 - name: Install Nodejs
110 uses: actions/setup-node@v1
111 with:
112 node-version: 12.x
113
114 - run: echo "::set-env name=TAG::$(date --iso)"
115 - run: 'echo "TAG: $TAG"'
116
117 - name: Checkout repository
118 uses: actions/checkout@v1
119
112 - uses: actions/download-artifact@v1 120 - uses: actions/download-artifact@v1
113 with: 121 with:
114 name: editor-plugins 122 name: editor-plugins
@@ -127,9 +135,6 @@ jobs:
127 path: dist 135 path: dist
128 - run: ls -all ./dist 136 - run: ls -all ./dist
129 137
130 - run: echo "::set-env name=TAG::$(date --iso)"
131 - run: 'echo "TAG: $TAG"'
132
133 - name: Create Release 138 - name: Create Release
134 id: create_release 139 id: create_release
135 # uses: actions/create-release@v1 140 # uses: actions/create-release@v1
@@ -179,11 +184,10 @@ jobs:
179 asset_name: rust-analyzer-0.1.0.vsix 184 asset_name: rust-analyzer-0.1.0.vsix
180 asset_content_type: application/octet-stream 185 asset_content_type: application/octet-stream
181 186
182 - uses: actions/[email protected] 187 - run: npm ci
183 env: 188 working-directory: ./editors/code
184 GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 189
185 with: 190 - name: Publish Extension
186 upload_url: ${{ steps.create_release.outputs.upload_url }} 191 working-directory: ./editors/code
187 asset_path: ./dist/rust-analyzer.el 192 # token from https://dev.azure.com/rust-analyzer/
188 asset_name: rust-analyzer.el 193 run: ./node_modules/vsce/out/vsce publish 0.1.$(date +%Y%m%d) --pat ${{ secrets.MARKETPLACE_TOKEN }}
189 asset_content_type: text/plain
diff --git a/Cargo.lock b/Cargo.lock
index e29ff898d..847653696 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -110,9 +110,9 @@ dependencies = [
110 110
111[[package]] 111[[package]]
112name = "byteorder" 112name = "byteorder"
113version = "1.3.2" 113version = "1.3.4"
114source = "registry+https://github.com/rust-lang/crates.io-index" 114source = "registry+https://github.com/rust-lang/crates.io-index"
115checksum = "a7c3dd8985a7111efc5c80b44e23ecdd8c007de8ade3b96595387e812b957cf5" 115checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de"
116 116
117[[package]] 117[[package]]
118name = "c2-chacha" 118name = "c2-chacha"
@@ -1563,12 +1563,9 @@ checksum = "4c691c0e608126e00913e33f0ccf3727d5fc84573623b8d65b2df340b5201783"
1563 1563
1564[[package]] 1564[[package]]
1565name = "rustc-hash" 1565name = "rustc-hash"
1566version = "1.0.1" 1566version = "1.1.0"
1567source = "registry+https://github.com/rust-lang/crates.io-index" 1567source = "registry+https://github.com/rust-lang/crates.io-index"
1568checksum = "7540fc8b0c49f096ee9c961cda096467dce8084bec6bdca2fc83895fd9b28cb8" 1568checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
1569dependencies = [
1570 "byteorder",
1571]
1572 1569
1573[[package]] 1570[[package]]
1574name = "rustc_lexer" 1571name = "rustc_lexer"
@@ -1675,9 +1672,9 @@ dependencies = [
1675 1672
1676[[package]] 1673[[package]]
1677name = "serde_json" 1674name = "serde_json"
1678version = "1.0.46" 1675version = "1.0.47"
1679source = "registry+https://github.com/rust-lang/crates.io-index" 1676source = "registry+https://github.com/rust-lang/crates.io-index"
1680checksum = "21b01d7f0288608a01dca632cf1df859df6fd6ffa885300fc275ce2ba6221953" 1677checksum = "15913895b61e0be854afd32fd4163fcd2a3df34142cf2cb961b310ce694cbf90"
1681dependencies = [ 1678dependencies = [
1682 "itoa", 1679 "itoa",
1683 "ryu", 1680 "ryu",
diff --git a/README.md b/README.md
index 2f6ed1e05..fabb8479d 100644
--- a/README.md
+++ b/README.md
@@ -2,13 +2,13 @@
2 <img src="https://user-images.githubusercontent.com/1711539/72443316-5a79f280-37ae-11ea-858f-035209ece2dd.png" alt="rust-analyzer logo"> 2 <img src="https://user-images.githubusercontent.com/1711539/72443316-5a79f280-37ae-11ea-858f-035209ece2dd.png" alt="rust-analyzer logo">
3</p> 3</p>
4 4
5Rust Analyzer is an **experimental** modular compiler frontend for the Rust 5rust-analyzer is an **experimental** modular compiler frontend for the Rust
6language. It is a part of a larger rls-2.0 effort to create excellent IDE 6language. It is a part of a larger rls-2.0 effort to create excellent IDE
7support for Rust. If you want to get involved, check the rls-2.0 working group: 7support for Rust. If you want to get involved, check the rls-2.0 working group:
8 8
9https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0 9https://rust-lang.zulipchat.com/#narrow/stream/185405-t-compiler.2Fwg-rls-2.2E0
10 10
11Work on the Rust Analyzer is sponsored by 11Work on rust-analyzer is sponsored by
12 12
13[<img src="https://user-images.githubusercontent.com/1711539/58105231-cf306900-7bee-11e9-83d8-9f1102e59d29.png" alt="Ferrous Systems" width="300">](https://ferrous-systems.com/) 13[<img src="https://user-images.githubusercontent.com/1711539/58105231-cf306900-7bee-11e9-83d8-9f1102e59d29.png" alt="Ferrous Systems" width="300">](https://ferrous-systems.com/)
14- [Mozilla](https://www.mozilla.org/en-US/) 14- [Mozilla](https://www.mozilla.org/en-US/)
@@ -16,17 +16,17 @@ Work on the Rust Analyzer is sponsored by
16 16
17## Language Server Quick Start 17## Language Server Quick Start
18 18
19Rust Analyzer is a work-in-progress, so you'll have to build it from source, and 19rust-analyzer is a work-in-progress, so you might encounter critical bugs. That
20you might encounter critical bugs. That said, it is complete enough to provide a 20said, it is complete enough to provide a useful IDE experience and some people
21useful IDE experience and some people use it as a daily driver. 21use it as a daily driver.
22 22
23To build rust-analyzer, you need: 23To build rust-analyzer, you need:
24 24
25* latest stable rust for language server itself 25* latest stable Rust for the language server itself
26* latest stable npm and VS Code for VS Code extension 26* latest stable npm and VS Code for VS Code extension
27 27
28To quickly install rust-analyzer with VS Code extension with standard setup 28To quickly install the rust-analyzer language server and VS Code extension with
29(`code` and `cargo` in `$PATH`, etc), use this: 29standard setup (`code` and `cargo` in `$PATH`, etc), use this:
30 30
31``` 31```
32# clone the repo 32# clone the repo
@@ -44,8 +44,8 @@ cannot start, see [./docs/user](./docs/user).
44 44
45## Documentation 45## Documentation
46 46
47If you want to **contribute** to rust-analyzer or just curious about how things work 47If you want to **contribute** to rust-analyzer or are just curious about how
48under the hood, check the [./docs/dev](./docs/dev) folder. 48things work under the hood, check the [./docs/dev](./docs/dev) folder.
49 49
50If you want to **use** rust-analyzer's language server with your editor of 50If you want to **use** rust-analyzer's language server with your editor of
51choice, check [./docs/user](./docs/user) folder. It also contains some tips & tricks to help 51choice, check [./docs/user](./docs/user) folder. It also contains some tips & tricks to help
diff --git a/crates/ra_assists/src/assist_ctx.rs b/crates/ra_assists/src/assist_ctx.rs
index 81f999090..5aab5fb8b 100644
--- a/crates/ra_assists/src/assist_ctx.rs
+++ b/crates/ra_assists/src/assist_ctx.rs
@@ -1,5 +1,4 @@
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 either::Either;
3use hir::{InFile, SourceAnalyzer, SourceBinder}; 2use hir::{InFile, SourceAnalyzer, SourceBinder};
4use ra_db::{FileRange, SourceDatabase}; 3use ra_db::{FileRange, SourceDatabase};
5use ra_fmt::{leading_indent, reindent}; 4use ra_fmt::{leading_indent, reindent};
@@ -11,12 +10,36 @@ use ra_syntax::{
11}; 10};
12use ra_text_edit::TextEditBuilder; 11use ra_text_edit::TextEditBuilder;
13 12
14use crate::{AssistAction, AssistId, AssistLabel, ResolvedAssist}; 13use crate::{AssistAction, AssistId, AssistLabel, GroupLabel, ResolvedAssist};
15 14
16#[derive(Clone, Debug)] 15#[derive(Clone, Debug)]
17pub(crate) enum Assist { 16pub(crate) struct Assist(pub(crate) Vec<AssistInfo>);
18 Unresolved { label: AssistLabel }, 17
19 Resolved { assist: ResolvedAssist }, 18#[derive(Clone, Debug)]
19pub(crate) struct AssistInfo {
20 pub(crate) label: AssistLabel,
21 pub(crate) group_label: Option<GroupLabel>,
22 pub(crate) action: Option<AssistAction>,
23}
24
25impl AssistInfo {
26 fn new(label: AssistLabel) -> AssistInfo {
27 AssistInfo { label, group_label: None, action: None }
28 }
29
30 fn resolved(self, action: AssistAction) -> AssistInfo {
31 AssistInfo { action: Some(action), ..self }
32 }
33
34 fn with_group(self, group_label: GroupLabel) -> AssistInfo {
35 AssistInfo { group_label: Some(group_label), ..self }
36 }
37
38 pub(crate) fn into_resolved(self) -> Option<ResolvedAssist> {
39 let label = self.label;
40 let group_label = self.group_label;
41 self.action.map(|action| ResolvedAssist { label, group_label, action })
42 }
20} 43}
21 44
22pub(crate) type AssistHandler = fn(AssistCtx) -> Option<Assist>; 45pub(crate) type AssistHandler = fn(AssistCtx) -> Option<Assist>;
@@ -84,44 +107,21 @@ impl<'a> AssistCtx<'a> {
84 ) -> Option<Assist> { 107 ) -> Option<Assist> {
85 let label = AssistLabel::new(label.into(), id); 108 let label = AssistLabel::new(label.into(), id);
86 109
87 let assist = if self.should_compute_edit { 110 let mut info = AssistInfo::new(label);
111 if self.should_compute_edit {
88 let action = { 112 let action = {
89 let mut edit = ActionBuilder::default(); 113 let mut edit = ActionBuilder::default();
90 f(&mut edit); 114 f(&mut edit);
91 edit.build() 115 edit.build()
92 }; 116 };
93 Assist::Resolved { assist: ResolvedAssist { label, action_data: Either::Left(action) } } 117 info = info.resolved(action)
94 } else {
95 Assist::Unresolved { label }
96 }; 118 };
97 119
98 Some(assist) 120 Some(Assist(vec![info]))
99 } 121 }
100 122
101 pub(crate) fn add_assist_group( 123 pub(crate) fn add_assist_group(self, group_name: impl Into<String>) -> AssistGroup<'a> {
102 self, 124 AssistGroup { ctx: self, group_name: group_name.into(), assists: Vec::new() }
103 id: AssistId,
104 label: impl Into<String>,
105 f: impl FnOnce() -> Vec<ActionBuilder>,
106 ) -> Option<Assist> {
107 let label = AssistLabel::new(label.into(), id);
108 let assist = if self.should_compute_edit {
109 let actions = f();
110 assert!(!actions.is_empty(), "Assist cannot have no");
111
112 Assist::Resolved {
113 assist: ResolvedAssist {
114 label,
115 action_data: Either::Right(
116 actions.into_iter().map(ActionBuilder::build).collect(),
117 ),
118 },
119 }
120 } else {
121 Assist::Unresolved { label }
122 };
123
124 Some(assist)
125 } 125 }
126 126
127 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> { 127 pub(crate) fn token_at_offset(&self) -> TokenAtOffset<SyntaxToken> {
@@ -155,20 +155,48 @@ impl<'a> AssistCtx<'a> {
155 } 155 }
156} 156}
157 157
158pub(crate) struct AssistGroup<'a> {
159 ctx: AssistCtx<'a>,
160 group_name: String,
161 assists: Vec<AssistInfo>,
162}
163
164impl<'a> AssistGroup<'a> {
165 pub(crate) fn add_assist(
166 &mut self,
167 id: AssistId,
168 label: impl Into<String>,
169 f: impl FnOnce(&mut ActionBuilder),
170 ) {
171 let label = AssistLabel::new(label.into(), id);
172
173 let mut info = AssistInfo::new(label).with_group(GroupLabel(self.group_name.clone()));
174 if self.ctx.should_compute_edit {
175 let action = {
176 let mut edit = ActionBuilder::default();
177 f(&mut edit);
178 edit.build()
179 };
180 info = info.resolved(action)
181 };
182
183 self.assists.push(info)
184 }
185
186 pub(crate) fn finish(self) -> Option<Assist> {
187 assert!(!self.assists.is_empty());
188 Some(Assist(self.assists))
189 }
190}
191
158#[derive(Default)] 192#[derive(Default)]
159pub(crate) struct ActionBuilder { 193pub(crate) struct ActionBuilder {
160 edit: TextEditBuilder, 194 edit: TextEditBuilder,
161 cursor_position: Option<TextUnit>, 195 cursor_position: Option<TextUnit>,
162 target: Option<TextRange>, 196 target: Option<TextRange>,
163 label: Option<String>,
164} 197}
165 198
166impl ActionBuilder { 199impl ActionBuilder {
167 /// Adds a custom label to the action, if it needs to be different from the assist label
168 pub(crate) fn label(&mut self, label: impl Into<String>) {
169 self.label = Some(label.into())
170 }
171
172 /// Replaces specified `range` of text with a given string. 200 /// Replaces specified `range` of text with a given string.
173 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) { 201 pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
174 self.edit.replace(range, replace_with.into()) 202 self.edit.replace(range, replace_with.into())
@@ -227,7 +255,6 @@ impl ActionBuilder {
227 edit: self.edit.finish(), 255 edit: self.edit.finish(),
228 cursor_position: self.cursor_position, 256 cursor_position: self.cursor_position,
229 target: self.target, 257 target: self.target,
230 label: self.label,
231 } 258 }
232 } 259 }
233} 260}
diff --git a/crates/ra_assists/src/doc_tests.rs b/crates/ra_assists/src/doc_tests.rs
index ae0e5605c..c0f9bc1fb 100644
--- a/crates/ra_assists/src/doc_tests.rs
+++ b/crates/ra_assists/src/doc_tests.rs
@@ -30,6 +30,6 @@ fn check(assist_id: &str, before: &str, after: &str) {
30 ) 30 )
31 }); 31 });
32 32
33 let actual = assist.get_first_action().edit.apply(&before); 33 let actual = assist.action.edit.apply(&before);
34 assert_eq_text!(after, &actual); 34 assert_eq_text!(after, &actual);
35} 35}
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs
index 0d95b957b..4ab09b167 100644
--- a/crates/ra_assists/src/doc_tests/generated.rs
+++ b/crates/ra_assists/src/doc_tests/generated.rs
@@ -1,4 +1,4 @@
1//! Generated file, do not edit by hand, see `crate/ra_tools/src/codegen` 1//! Generated file, do not edit by hand, see `xtask/src/codegen`
2 2
3use super::check; 3use super::check;
4 4
@@ -161,21 +161,6 @@ impl Trait<u32> for () {
161} 161}
162 162
163#[test] 163#[test]
164fn doctest_add_import() {
165 check(
166 "add_import",
167 r#####"
168fn process(map: std::collections::<|>HashMap<String, String>) {}
169"#####,
170 r#####"
171use std::collections::HashMap;
172
173fn process(map: HashMap<String, String>) {}
174"#####,
175 )
176}
177
178#[test]
179fn doctest_add_new() { 164fn doctest_add_new() {
180 check( 165 check(
181 "add_new", 166 "add_new",
@@ -592,6 +577,21 @@ fn handle(action: Action) {
592} 577}
593 578
594#[test] 579#[test]
580fn doctest_replace_qualified_name_with_use() {
581 check(
582 "replace_qualified_name_with_use",
583 r#####"
584fn process(map: std::collections::<|>HashMap<String, String>) {}
585"#####,
586 r#####"
587use std::collections::HashMap;
588
589fn process(map: HashMap<String, String>) {}
590"#####,
591 )
592}
593
594#[test]
595fn doctest_split_import() { 595fn doctest_split_import() {
596 check( 596 check(
597 "split_import", 597 "split_import",
diff --git a/crates/ra_assists/src/handlers/add_new.rs b/crates/ra_assists/src/handlers/add_new.rs
index a08639311..2701eddb8 100644
--- a/crates/ra_assists/src/handlers/add_new.rs
+++ b/crates/ra_assists/src/handlers/add_new.rs
@@ -1,5 +1,5 @@
1use format_buf::format; 1use format_buf::format;
2use hir::InFile; 2use hir::{Adt, InFile};
3use join_to_string::join; 3use join_to_string::join;
4use ra_syntax::{ 4use ra_syntax::{
5 ast::{ 5 ast::{
@@ -135,16 +135,22 @@ fn find_struct_impl(ctx: &AssistCtx, strukt: &ast::StructDef) -> Option<Option<a
135 })?; 135 })?;
136 let mut sb = ctx.source_binder(); 136 let mut sb = ctx.source_binder();
137 137
138 let struct_ty = { 138 let struct_def = {
139 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() }; 139 let src = InFile { file_id: ctx.frange.file_id.into(), value: strukt.clone() };
140 sb.to_def(src)?.ty(db) 140 sb.to_def(src)?
141 }; 141 };
142 142
143 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| { 143 let block = module.descendants().filter_map(ast::ImplBlock::cast).find_map(|impl_blk| {
144 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() }; 144 let src = InFile { file_id: ctx.frange.file_id.into(), value: impl_blk.clone() };
145 let blk = sb.to_def(src)?; 145 let blk = sb.to_def(src)?;
146 146
147 let same_ty = blk.target_ty(db) == struct_ty; 147 // FIXME: handle e.g. `struct S<T>; impl<U> S<U> {}`
148 // (we currently use the wrong type parameter)
149 // also we wouldn't want to use e.g. `impl S<u32>`
150 let same_ty = match blk.target_ty(db).as_adt() {
151 Some(def) => def == Adt::Struct(struct_def),
152 None => false,
153 };
148 let not_trait_impl = blk.target_trait(db).is_none(); 154 let not_trait_impl = blk.target_trait(db).is_none();
149 155
150 if !(same_ty && not_trait_impl) { 156 if !(same_ty && not_trait_impl) {
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs
index 84b5474f9..1fb701da5 100644
--- a/crates/ra_assists/src/handlers/auto_import.rs
+++ b/crates/ra_assists/src/handlers/auto_import.rs
@@ -1,13 +1,9 @@
1use hir::ModPath;
2use ra_ide_db::imports_locator::ImportsLocator; 1use ra_ide_db::imports_locator::ImportsLocator;
3use ra_syntax::{ 2use ra_syntax::ast::{self, AstNode};
4 ast::{self, AstNode},
5 SyntaxNode,
6};
7 3
8use crate::{ 4use crate::{
9 assist_ctx::{ActionBuilder, Assist, AssistCtx}, 5 assist_ctx::{Assist, AssistCtx},
10 auto_import_text_edit, AssistId, 6 insert_use_statement, AssistId,
11}; 7};
12use std::collections::BTreeSet; 8use std::collections::BTreeSet;
13 9
@@ -31,31 +27,34 @@ use std::collections::BTreeSet;
31// # pub mod std { pub mod collections { pub struct HashMap { } } } 27// # pub mod std { pub mod collections { pub struct HashMap { } } }
32// ``` 28// ```
33pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> { 29pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
34 let path_to_import: ast::Path = ctx.find_node_at_offset()?; 30 let path_under_caret: ast::Path = ctx.find_node_at_offset()?;
35 let path_to_import_syntax = path_to_import.syntax(); 31 if path_under_caret.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
36 if path_to_import_syntax.ancestors().find_map(ast::UseItem::cast).is_some() {
37 return None; 32 return None;
38 } 33 }
39 let name_to_import =
40 path_to_import_syntax.descendants().find_map(ast::NameRef::cast)?.syntax().to_string();
41 34
42 let module = path_to_import_syntax.ancestors().find_map(ast::Module::cast); 35 let module = path_under_caret.syntax().ancestors().find_map(ast::Module::cast);
43 let position = match module.and_then(|it| it.item_list()) { 36 let position = match module.and_then(|it| it.item_list()) {
44 Some(item_list) => item_list.syntax().clone(), 37 Some(item_list) => item_list.syntax().clone(),
45 None => { 38 None => {
46 let current_file = path_to_import_syntax.ancestors().find_map(ast::SourceFile::cast)?; 39 let current_file =
40 path_under_caret.syntax().ancestors().find_map(ast::SourceFile::cast)?;
47 current_file.syntax().clone() 41 current_file.syntax().clone()
48 } 42 }
49 }; 43 };
50 let source_analyzer = ctx.source_analyzer(&position, None); 44 let source_analyzer = ctx.source_analyzer(&position, None);
51 let module_with_name_to_import = source_analyzer.module()?; 45 let module_with_name_to_import = source_analyzer.module()?;
52 if source_analyzer.resolve_path(ctx.db, &path_to_import).is_some() { 46
47 let name_ref_to_import =
48 path_under_caret.syntax().descendants().find_map(ast::NameRef::cast)?;
49 if source_analyzer
50 .resolve_path(ctx.db, &name_ref_to_import.syntax().ancestors().find_map(ast::Path::cast)?)
51 .is_some()
52 {
53 return None; 53 return None;
54 } 54 }
55 55
56 let mut imports_locator = ImportsLocator::new(ctx.db); 56 let name_to_import = name_ref_to_import.syntax().to_string();
57 57 let proposed_imports = ImportsLocator::new(ctx.db)
58 let proposed_imports = imports_locator
59 .find_imports(&name_to_import) 58 .find_imports(&name_to_import)
60 .into_iter() 59 .into_iter()
61 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def)) 60 .filter_map(|module_def| module_with_name_to_import.find_use_path(ctx.db, module_def))
@@ -67,24 +66,24 @@ pub(crate) fn auto_import(ctx: AssistCtx) -> Option<Assist> {
67 return None; 66 return None;
68 } 67 }
69 68
70 ctx.add_assist_group(AssistId("auto_import"), format!("Import {}", name_to_import), || { 69 let mut group = ctx.add_assist_group(format!("Import {}", name_to_import));
71 proposed_imports 70 for import in proposed_imports {
72 .into_iter() 71 group.add_assist(AssistId("auto_import"), format!("Import `{}`", &import), |edit| {
73 .map(|import| import_to_action(import, &position, &path_to_import_syntax)) 72 edit.target(path_under_caret.syntax().text_range());
74 .collect() 73 insert_use_statement(
75 }) 74 &position,
76} 75 path_under_caret.syntax(),
77 76 &import,
78fn import_to_action(import: ModPath, position: &SyntaxNode, anchor: &SyntaxNode) -> ActionBuilder { 77 edit.text_edit_builder(),
79 let mut action_builder = ActionBuilder::default(); 78 );
80 action_builder.label(format!("Import `{}`", &import)); 79 });
81 auto_import_text_edit(position, anchor, &import, action_builder.text_edit_builder()); 80 }
82 action_builder 81 group.finish()
83} 82}
84 83
85#[cfg(test)] 84#[cfg(test)]
86mod tests { 85mod tests {
87 use crate::helpers::{check_assist, check_assist_not_applicable}; 86 use crate::helpers::{check_assist, check_assist_not_applicable, check_assist_target};
88 87
89 use super::*; 88 use super::*;
90 89
@@ -255,4 +254,40 @@ mod tests {
255 ", 254 ",
256 ); 255 );
257 } 256 }
257
258 #[test]
259 fn auto_import_target() {
260 check_assist_target(
261 auto_import,
262 r"
263 struct AssistInfo {
264 group_label: Option<<|>GroupLabel>,
265 }
266
267 mod m { pub struct GroupLabel; }
268 ",
269 "GroupLabel",
270 )
271 }
272
273 #[test]
274 fn not_applicable_when_path_start_is_imported() {
275 check_assist_not_applicable(
276 auto_import,
277 r"
278 pub mod mod1 {
279 pub mod mod2 {
280 pub mod mod3 {
281 pub struct TestStruct;
282 }
283 }
284 }
285
286 use mod1::mod2;
287 fn main() {
288 mod2::mod3::TestStruct<|>
289 }
290 ",
291 );
292 }
258} 293}
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs
index 0908fc246..ae2437ed3 100644
--- a/crates/ra_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ra_assists/src/handlers/fill_match_arms.rs
@@ -75,10 +75,10 @@ pub(crate) fn fill_match_arms(ctx: AssistCtx) -> Option<Assist> {
75} 75}
76 76
77fn is_trivial(arm: &ast::MatchArm) -> bool { 77fn is_trivial(arm: &ast::MatchArm) -> bool {
78 arm.pats().any(|pat| match pat { 78 match arm.pat() {
79 ast::Pat::PlaceholderPat(..) => true, 79 Some(ast::Pat::PlaceholderPat(..)) => true,
80 _ => false, 80 _ => false,
81 }) 81 }
82} 82}
83 83
84fn resolve_enum_def( 84fn resolve_enum_def(
diff --git a/crates/ra_assists/src/handlers/merge_match_arms.rs b/crates/ra_assists/src/handlers/merge_match_arms.rs
index 670614dd8..b2a194cb5 100644
--- a/crates/ra_assists/src/handlers/merge_match_arms.rs
+++ b/crates/ra_assists/src/handlers/merge_match_arms.rs
@@ -75,7 +75,7 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
75 } else { 75 } else {
76 arms_to_merge 76 arms_to_merge
77 .iter() 77 .iter()
78 .flat_map(ast::MatchArm::pats) 78 .filter_map(ast::MatchArm::pat)
79 .map(|x| x.syntax().to_string()) 79 .map(|x| x.syntax().to_string())
80 .collect::<Vec<String>>() 80 .collect::<Vec<String>>()
81 .join(" | ") 81 .join(" | ")
@@ -96,10 +96,10 @@ pub(crate) fn merge_match_arms(ctx: AssistCtx) -> Option<Assist> {
96} 96}
97 97
98fn contains_placeholder(a: &ast::MatchArm) -> bool { 98fn contains_placeholder(a: &ast::MatchArm) -> bool {
99 a.pats().any(|x| match x { 99 match a.pat() {
100 ra_syntax::ast::Pat::PlaceholderPat(..) => true, 100 Some(ra_syntax::ast::Pat::PlaceholderPat(..)) => true,
101 _ => false, 101 _ => false,
102 }) 102 }
103} 103}
104 104
105fn next_arm(arm: &ast::MatchArm) -> Option<ast::MatchArm> { 105fn next_arm(arm: &ast::MatchArm) -> Option<ast::MatchArm> {
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs
index 2b91ce7c4..a61a2ba3e 100644
--- a/crates/ra_assists/src/handlers/move_guard.rs
+++ b/crates/ra_assists/src/handlers/move_guard.rs
@@ -90,7 +90,7 @@ pub(crate) fn move_guard_to_arm_body(ctx: AssistCtx) -> Option<Assist> {
90// ``` 90// ```
91pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { 91pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
92 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?; 92 let match_arm: MatchArm = ctx.find_node_at_offset::<MatchArm>()?;
93 let last_match_pat = match_arm.pats().last()?; 93 let match_pat = match_arm.pat()?;
94 94
95 let arm_body = match_arm.expr()?; 95 let arm_body = match_arm.expr()?;
96 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?; 96 let if_expr: IfExpr = IfExpr::cast(arm_body.syntax().clone())?;
@@ -122,8 +122,8 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> {
122 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()), 122 _ => edit.replace(if_expr.syntax().text_range(), then_block.syntax().text()),
123 } 123 }
124 124
125 edit.insert(last_match_pat.syntax().text_range().end(), buf); 125 edit.insert(match_pat.syntax().text_range().end(), buf);
126 edit.set_cursor(last_match_pat.syntax().text_range().end() + TextUnit::from(1)); 126 edit.set_cursor(match_pat.syntax().text_range().end() + TextUnit::from(1));
127 }, 127 },
128 ) 128 )
129} 129}
diff --git a/crates/ra_assists/src/handlers/add_import.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
index f03dddac8..b70c88ec2 100644
--- a/crates/ra_assists/src/handlers/add_import.rs
+++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs
@@ -12,10 +12,10 @@ use crate::{
12 AssistId, 12 AssistId,
13}; 13};
14 14
15/// This function produces sequence of text edits into edit 15/// Creates and inserts a use statement for the given path to import.
16/// to import the target path in the most appropriate scope given 16/// The use statement is inserted in the scope most appropriate to the
17/// the cursor position 17/// the cursor position given, additionally merged with the existing use imports.
18pub fn auto_import_text_edit( 18pub fn insert_use_statement(
19 // Ideally the position of the cursor, used to 19 // Ideally the position of the cursor, used to
20 position: &SyntaxNode, 20 position: &SyntaxNode,
21 // The statement to use as anchor (last resort) 21 // The statement to use as anchor (last resort)
@@ -37,9 +37,9 @@ pub fn auto_import_text_edit(
37 } 37 }
38} 38}
39 39
40// Assist: add_import 40// Assist: replace_qualified_name_with_use
41// 41//
42// Adds a use statement for a given fully-qualified path. 42// Adds a use statement for a given fully-qualified name.
43// 43//
44// ``` 44// ```
45// fn process(map: std::collections::<|>HashMap<String, String>) {} 45// fn process(map: std::collections::<|>HashMap<String, String>) {}
@@ -50,7 +50,7 @@ pub fn auto_import_text_edit(
50// 50//
51// fn process(map: HashMap<String, String>) {} 51// fn process(map: HashMap<String, String>) {}
52// ``` 52// ```
53pub(crate) fn add_import(ctx: AssistCtx) -> Option<Assist> { 53pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> {
54 let path: ast::Path = ctx.find_node_at_offset()?; 54 let path: ast::Path = ctx.find_node_at_offset()?;
55 // We don't want to mess with use statements 55 // We don't want to mess with use statements
56 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() { 56 if path.syntax().ancestors().find_map(ast::UseItem::cast).is_some() {
@@ -72,9 +72,13 @@ pub(crate) fn add_import(ctx: AssistCtx) -> Option<Assist> {
72 } 72 }
73 }; 73 };
74 74
75 ctx.add_assist(AssistId("add_import"), format!("Import {}", fmt_segments(&segments)), |edit| { 75 ctx.add_assist(
76 apply_auto_import(&position, &path, &segments, edit.text_edit_builder()); 76 AssistId("replace_qualified_name_with_use"),
77 }) 77 "Replace qualified path with use",
78 |edit| {
79 replace_with_use(&position, &path, &segments, edit.text_edit_builder());
80 },
81 )
78} 82}
79 83
80fn collect_path_segments_raw( 84fn collect_path_segments_raw(
@@ -107,12 +111,6 @@ fn collect_path_segments_raw(
107 Some(segments.len() - oldlen) 111 Some(segments.len() - oldlen)
108} 112}
109 113
110fn fmt_segments(segments: &[SmolStr]) -> String {
111 let mut buf = String::new();
112 fmt_segments_raw(segments, &mut buf);
113 buf
114}
115
116fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) { 114fn fmt_segments_raw(segments: &[SmolStr], buf: &mut String) {
117 let mut iter = segments.iter(); 115 let mut iter = segments.iter();
118 if let Some(s) = iter.next() { 116 if let Some(s) = iter.next() {
@@ -558,7 +556,7 @@ fn make_assist_add_nested_import(
558 } 556 }
559} 557}
560 558
561fn apply_auto_import( 559fn replace_with_use(
562 container: &SyntaxNode, 560 container: &SyntaxNode,
563 path: &ast::Path, 561 path: &ast::Path,
564 target: &[SmolStr], 562 target: &[SmolStr],
@@ -567,7 +565,7 @@ fn apply_auto_import(
567 let action = best_action_for_target(container.clone(), path.syntax().clone(), target); 565 let action = best_action_for_target(container.clone(), path.syntax().clone(), target);
568 make_assist(&action, target, edit); 566 make_assist(&action, target, edit);
569 if let Some(last) = path.segment() { 567 if let Some(last) = path.segment() {
570 // Here we are assuming the assist will provide a correct use statement 568 // Here we are assuming the assist will provide a correct use statement
571 // so we can delete the path qualifier 569 // so we can delete the path qualifier
572 edit.delete(TextRange::from_to( 570 edit.delete(TextRange::from_to(
573 path.syntax().text_range().start(), 571 path.syntax().text_range().start(),
@@ -603,9 +601,9 @@ mod tests {
603 use super::*; 601 use super::*;
604 602
605 #[test] 603 #[test]
606 fn test_auto_import_add_use_no_anchor() { 604 fn test_replace_add_use_no_anchor() {
607 check_assist( 605 check_assist(
608 add_import, 606 replace_qualified_name_with_use,
609 " 607 "
610std::fmt::Debug<|> 608std::fmt::Debug<|>
611 ", 609 ",
@@ -617,9 +615,9 @@ Debug<|>
617 ); 615 );
618 } 616 }
619 #[test] 617 #[test]
620 fn test_auto_import_add_use_no_anchor_with_item_below() { 618 fn test_replace_add_use_no_anchor_with_item_below() {
621 check_assist( 619 check_assist(
622 add_import, 620 replace_qualified_name_with_use,
623 " 621 "
624std::fmt::Debug<|> 622std::fmt::Debug<|>
625 623
@@ -638,9 +636,9 @@ fn main() {
638 } 636 }
639 637
640 #[test] 638 #[test]
641 fn test_auto_import_add_use_no_anchor_with_item_above() { 639 fn test_replace_add_use_no_anchor_with_item_above() {
642 check_assist( 640 check_assist(
643 add_import, 641 replace_qualified_name_with_use,
644 " 642 "
645fn main() { 643fn main() {
646} 644}
@@ -659,9 +657,9 @@ Debug<|>
659 } 657 }
660 658
661 #[test] 659 #[test]
662 fn test_auto_import_add_use_no_anchor_2seg() { 660 fn test_replace_add_use_no_anchor_2seg() {
663 check_assist( 661 check_assist(
664 add_import, 662 replace_qualified_name_with_use,
665 " 663 "
666std::fmt<|>::Debug 664std::fmt<|>::Debug
667 ", 665 ",
@@ -674,9 +672,9 @@ fmt<|>::Debug
674 } 672 }
675 673
676 #[test] 674 #[test]
677 fn test_auto_import_add_use() { 675 fn test_replace_add_use() {
678 check_assist( 676 check_assist(
679 add_import, 677 replace_qualified_name_with_use,
680 " 678 "
681use stdx; 679use stdx;
682 680
@@ -694,9 +692,9 @@ impl Debug<|> for Foo {
694 } 692 }
695 693
696 #[test] 694 #[test]
697 fn test_auto_import_file_use_other_anchor() { 695 fn test_replace_file_use_other_anchor() {
698 check_assist( 696 check_assist(
699 add_import, 697 replace_qualified_name_with_use,
700 " 698 "
701impl std::fmt::Debug<|> for Foo { 699impl std::fmt::Debug<|> for Foo {
702} 700}
@@ -711,9 +709,9 @@ impl Debug<|> for Foo {
711 } 709 }
712 710
713 #[test] 711 #[test]
714 fn test_auto_import_add_use_other_anchor_indent() { 712 fn test_replace_add_use_other_anchor_indent() {
715 check_assist( 713 check_assist(
716 add_import, 714 replace_qualified_name_with_use,
717 " 715 "
718 impl std::fmt::Debug<|> for Foo { 716 impl std::fmt::Debug<|> for Foo {
719 } 717 }
@@ -728,9 +726,9 @@ impl Debug<|> for Foo {
728 } 726 }
729 727
730 #[test] 728 #[test]
731 fn test_auto_import_split_different() { 729 fn test_replace_split_different() {
732 check_assist( 730 check_assist(
733 add_import, 731 replace_qualified_name_with_use,
734 " 732 "
735use std::fmt; 733use std::fmt;
736 734
@@ -747,9 +745,9 @@ impl io<|> for Foo {
747 } 745 }
748 746
749 #[test] 747 #[test]
750 fn test_auto_import_split_self_for_use() { 748 fn test_replace_split_self_for_use() {
751 check_assist( 749 check_assist(
752 add_import, 750 replace_qualified_name_with_use,
753 " 751 "
754use std::fmt; 752use std::fmt;
755 753
@@ -766,9 +764,9 @@ impl Debug<|> for Foo {
766 } 764 }
767 765
768 #[test] 766 #[test]
769 fn test_auto_import_split_self_for_target() { 767 fn test_replace_split_self_for_target() {
770 check_assist( 768 check_assist(
771 add_import, 769 replace_qualified_name_with_use,
772 " 770 "
773use std::fmt::Debug; 771use std::fmt::Debug;
774 772
@@ -785,9 +783,9 @@ impl fmt<|> for Foo {
785 } 783 }
786 784
787 #[test] 785 #[test]
788 fn test_auto_import_add_to_nested_self_nested() { 786 fn test_replace_add_to_nested_self_nested() {
789 check_assist( 787 check_assist(
790 add_import, 788 replace_qualified_name_with_use,
791 " 789 "
792use std::fmt::{Debug, nested::{Display}}; 790use std::fmt::{Debug, nested::{Display}};
793 791
@@ -804,9 +802,9 @@ impl nested<|> for Foo {
804 } 802 }
805 803
806 #[test] 804 #[test]
807 fn test_auto_import_add_to_nested_self_already_included() { 805 fn test_replace_add_to_nested_self_already_included() {
808 check_assist( 806 check_assist(
809 add_import, 807 replace_qualified_name_with_use,
810 " 808 "
811use std::fmt::{Debug, nested::{self, Display}}; 809use std::fmt::{Debug, nested::{self, Display}};
812 810
@@ -823,9 +821,9 @@ impl nested<|> for Foo {
823 } 821 }
824 822
825 #[test] 823 #[test]
826 fn test_auto_import_add_to_nested_nested() { 824 fn test_replace_add_to_nested_nested() {
827 check_assist( 825 check_assist(
828 add_import, 826 replace_qualified_name_with_use,
829 " 827 "
830use std::fmt::{Debug, nested::{Display}}; 828use std::fmt::{Debug, nested::{Display}};
831 829
@@ -842,9 +840,9 @@ impl Debug<|> for Foo {
842 } 840 }
843 841
844 #[test] 842 #[test]
845 fn test_auto_import_split_common_target_longer() { 843 fn test_replace_split_common_target_longer() {
846 check_assist( 844 check_assist(
847 add_import, 845 replace_qualified_name_with_use,
848 " 846 "
849use std::fmt::Debug; 847use std::fmt::Debug;
850 848
@@ -861,9 +859,9 @@ impl Display<|> for Foo {
861 } 859 }
862 860
863 #[test] 861 #[test]
864 fn test_auto_import_split_common_use_longer() { 862 fn test_replace_split_common_use_longer() {
865 check_assist( 863 check_assist(
866 add_import, 864 replace_qualified_name_with_use,
867 " 865 "
868use std::fmt::nested::Debug; 866use std::fmt::nested::Debug;
869 867
@@ -880,9 +878,9 @@ impl Display<|> for Foo {
880 } 878 }
881 879
882 #[test] 880 #[test]
883 fn test_auto_import_use_nested_import() { 881 fn test_replace_use_nested_import() {
884 check_assist( 882 check_assist(
885 add_import, 883 replace_qualified_name_with_use,
886 " 884 "
887use crate::{ 885use crate::{
888 ty::{Substs, Ty}, 886 ty::{Substs, Ty},
@@ -903,9 +901,9 @@ fn foo() { lower<|>::trait_env() }
903 } 901 }
904 902
905 #[test] 903 #[test]
906 fn test_auto_import_alias() { 904 fn test_replace_alias() {
907 check_assist( 905 check_assist(
908 add_import, 906 replace_qualified_name_with_use,
909 " 907 "
910use std::fmt as foo; 908use std::fmt as foo;
911 909
@@ -922,9 +920,9 @@ impl Debug<|> for Foo {
922 } 920 }
923 921
924 #[test] 922 #[test]
925 fn test_auto_import_not_applicable_one_segment() { 923 fn test_replace_not_applicable_one_segment() {
926 check_assist_not_applicable( 924 check_assist_not_applicable(
927 add_import, 925 replace_qualified_name_with_use,
928 " 926 "
929impl foo<|> for Foo { 927impl foo<|> for Foo {
930} 928}
@@ -933,9 +931,9 @@ impl foo<|> for Foo {
933 } 931 }
934 932
935 #[test] 933 #[test]
936 fn test_auto_import_not_applicable_in_use() { 934 fn test_replace_not_applicable_in_use() {
937 check_assist_not_applicable( 935 check_assist_not_applicable(
938 add_import, 936 replace_qualified_name_with_use,
939 " 937 "
940use std::fmt<|>; 938use std::fmt<|>;
941", 939",
@@ -943,9 +941,9 @@ use std::fmt<|>;
943 } 941 }
944 942
945 #[test] 943 #[test]
946 fn test_auto_import_add_use_no_anchor_in_mod_mod() { 944 fn test_replace_add_use_no_anchor_in_mod_mod() {
947 check_assist( 945 check_assist(
948 add_import, 946 replace_qualified_name_with_use,
949 " 947 "
950mod foo { 948mod foo {
951 mod bar { 949 mod bar {
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs
index eca6dec4b..828a8e9e8 100644
--- a/crates/ra_assists/src/lib.rs
+++ b/crates/ra_assists/src/lib.rs
@@ -12,16 +12,13 @@ mod doc_tests;
12mod utils; 12mod utils;
13pub mod ast_transform; 13pub mod ast_transform;
14 14
15use std::cmp::Ordering;
16
17use either::Either;
18use ra_db::FileRange; 15use ra_db::FileRange;
19use ra_ide_db::RootDatabase; 16use ra_ide_db::RootDatabase;
20use ra_syntax::{TextRange, TextUnit}; 17use ra_syntax::{TextRange, TextUnit};
21use ra_text_edit::TextEdit; 18use ra_text_edit::TextEdit;
22 19
23pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler}; 20pub(crate) use crate::assist_ctx::{Assist, AssistCtx, AssistHandler};
24pub use crate::handlers::add_import::auto_import_text_edit; 21pub use crate::handlers::replace_qualified_name_with_use::insert_use_statement;
25 22
26/// Unique identifier of the assist, should not be shown to the user 23/// Unique identifier of the assist, should not be shown to the user
27/// directly. 24/// directly.
@@ -35,6 +32,9 @@ pub struct AssistLabel {
35 pub id: AssistId, 32 pub id: AssistId,
36} 33}
37 34
35#[derive(Clone, Debug)]
36pub struct GroupLabel(pub String);
37
38impl AssistLabel { 38impl AssistLabel {
39 pub(crate) fn new(label: String, id: AssistId) -> AssistLabel { 39 pub(crate) fn new(label: String, id: AssistId) -> AssistLabel {
40 // FIXME: make fields private, so that this invariant can't be broken 40 // FIXME: make fields private, so that this invariant can't be broken
@@ -45,7 +45,6 @@ impl AssistLabel {
45 45
46#[derive(Debug, Clone)] 46#[derive(Debug, Clone)]
47pub struct AssistAction { 47pub struct AssistAction {
48 pub label: Option<String>,
49 pub edit: TextEdit, 48 pub edit: TextEdit,
50 pub cursor_position: Option<TextUnit>, 49 pub cursor_position: Option<TextUnit>,
51 // FIXME: This belongs to `AssistLabel` 50 // FIXME: This belongs to `AssistLabel`
@@ -55,16 +54,8 @@ pub struct AssistAction {
55#[derive(Debug, Clone)] 54#[derive(Debug, Clone)]
56pub struct ResolvedAssist { 55pub struct ResolvedAssist {
57 pub label: AssistLabel, 56 pub label: AssistLabel,
58 pub action_data: Either<AssistAction, Vec<AssistAction>>, 57 pub group_label: Option<GroupLabel>,
59} 58 pub action: AssistAction,
60
61impl ResolvedAssist {
62 pub fn get_first_action(&self) -> AssistAction {
63 match &self.action_data {
64 Either::Left(action) => action.clone(),
65 Either::Right(actions) => actions[0].clone(),
66 }
67 }
68} 59}
69 60
70/// Return all the assists applicable at the given position. 61/// Return all the assists applicable at the given position.
@@ -76,10 +67,8 @@ pub fn unresolved_assists(db: &RootDatabase, range: FileRange) -> Vec<AssistLabe
76 handlers::all() 67 handlers::all()
77 .iter() 68 .iter()
78 .filter_map(|f| f(ctx.clone())) 69 .filter_map(|f| f(ctx.clone()))
79 .map(|a| match a { 70 .flat_map(|it| it.0)
80 Assist::Unresolved { label } => label, 71 .map(|a| a.label)
81 Assist::Resolved { .. } => unreachable!(),
82 })
83 .collect() 72 .collect()
84} 73}
85 74
@@ -92,24 +81,13 @@ pub fn resolved_assists(db: &RootDatabase, range: FileRange) -> Vec<ResolvedAssi
92 let mut a = handlers::all() 81 let mut a = handlers::all()
93 .iter() 82 .iter()
94 .filter_map(|f| f(ctx.clone())) 83 .filter_map(|f| f(ctx.clone()))
95 .map(|a| match a { 84 .flat_map(|it| it.0)
96 Assist::Resolved { assist } => assist, 85 .map(|it| it.into_resolved().unwrap())
97 Assist::Unresolved { .. } => unreachable!(),
98 })
99 .collect::<Vec<_>>(); 86 .collect::<Vec<_>>();
100 sort_assists(&mut a); 87 a.sort_by_key(|it| it.action.target.map_or(TextUnit::from(!0u32), |it| it.len()));
101 a 88 a
102} 89}
103 90
104fn sort_assists(assists: &mut [ResolvedAssist]) {
105 assists.sort_by(|a, b| match (a.get_first_action().target, b.get_first_action().target) {
106 (Some(a), Some(b)) => a.len().cmp(&b.len()),
107 (Some(_), None) => Ordering::Less,
108 (None, Some(_)) => Ordering::Greater,
109 (None, None) => Ordering::Equal,
110 });
111}
112
113mod handlers { 91mod handlers {
114 use crate::AssistHandler; 92 use crate::AssistHandler;
115 93
@@ -133,7 +111,7 @@ mod handlers {
133 mod replace_if_let_with_match; 111 mod replace_if_let_with_match;
134 mod split_import; 112 mod split_import;
135 mod remove_dbg; 113 mod remove_dbg;
136 pub(crate) mod add_import; 114 pub(crate) mod replace_qualified_name_with_use;
137 mod add_missing_impl_members; 115 mod add_missing_impl_members;
138 mod move_guard; 116 mod move_guard;
139 mod move_bounds; 117 mod move_bounds;
@@ -158,7 +136,7 @@ mod handlers {
158 replace_if_let_with_match::replace_if_let_with_match, 136 replace_if_let_with_match::replace_if_let_with_match,
159 split_import::split_import, 137 split_import::split_import,
160 remove_dbg::remove_dbg, 138 remove_dbg::remove_dbg,
161 add_import::add_import, 139 replace_qualified_name_with_use::replace_qualified_name_with_use,
162 add_missing_impl_members::add_missing_impl_members, 140 add_missing_impl_members::add_missing_impl_members,
163 add_missing_impl_members::add_missing_default_members, 141 add_missing_impl_members::add_missing_default_members,
164 inline_local_variable::inline_local_variable, 142 inline_local_variable::inline_local_variable,
@@ -184,7 +162,7 @@ mod helpers {
184 use ra_syntax::TextRange; 162 use ra_syntax::TextRange;
185 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range}; 163 use test_utils::{add_cursor, assert_eq_text, extract_offset, extract_range};
186 164
187 use crate::{Assist, AssistCtx, AssistHandler}; 165 use crate::{AssistCtx, AssistHandler};
188 166
189 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) { 167 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
190 let (mut db, file_id) = RootDatabase::with_single_file(text); 168 let (mut db, file_id) = RootDatabase::with_single_file(text);
@@ -202,10 +180,7 @@ mod helpers {
202 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 180 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
203 let assist = 181 let assist =
204 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); 182 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable");
205 let action = match assist { 183 let action = assist.0[0].action.clone().unwrap();
206 Assist::Unresolved { .. } => unreachable!(),
207 Assist::Resolved { assist } => assist.get_first_action(),
208 };
209 184
210 let actual = action.edit.apply(&before); 185 let actual = action.edit.apply(&before);
211 let actual_cursor_pos = match action.cursor_position { 186 let actual_cursor_pos = match action.cursor_position {
@@ -225,10 +200,7 @@ mod helpers {
225 let frange = FileRange { file_id, range }; 200 let frange = FileRange { file_id, range };
226 let assist = 201 let assist =
227 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); 202 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable");
228 let action = match assist { 203 let action = assist.0[0].action.clone().unwrap();
229 Assist::Unresolved { .. } => unreachable!(),
230 Assist::Resolved { assist } => assist.get_first_action(),
231 };
232 204
233 let mut actual = action.edit.apply(&before); 205 let mut actual = action.edit.apply(&before);
234 if let Some(pos) = action.cursor_position { 206 if let Some(pos) = action.cursor_position {
@@ -244,10 +216,7 @@ mod helpers {
244 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) }; 216 FileRange { file_id, range: TextRange::offset_len(before_cursor_pos, 0.into()) };
245 let assist = 217 let assist =
246 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); 218 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable");
247 let action = match assist { 219 let action = assist.0[0].action.clone().unwrap();
248 Assist::Unresolved { .. } => unreachable!(),
249 Assist::Resolved { assist } => assist.get_first_action(),
250 };
251 220
252 let range = action.target.expect("expected target on action"); 221 let range = action.target.expect("expected target on action");
253 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 222 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
@@ -259,10 +228,7 @@ mod helpers {
259 let frange = FileRange { file_id, range }; 228 let frange = FileRange { file_id, range };
260 let assist = 229 let assist =
261 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable"); 230 assist(AssistCtx::new(&db, frange, true)).expect("code action is not applicable");
262 let action = match assist { 231 let action = assist.0[0].action.clone().unwrap();
263 Assist::Unresolved { .. } => unreachable!(),
264 Assist::Resolved { assist } => assist.get_first_action(),
265 };
266 232
267 let range = action.target.expect("expected target on action"); 233 let range = action.target.expect("expected target on action");
268 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target); 234 assert_eq_text!(&before[range.start().to_usize()..range.end().to_usize()], target);
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs
index eaacf8c9e..4d9641728 100644
--- a/crates/ra_hir/src/code_model.rs
+++ b/crates/ra_hir/src/code_model.rs
@@ -10,9 +10,9 @@ use hir_def::{
10 per_ns::PerNs, 10 per_ns::PerNs,
11 resolver::HasResolver, 11 resolver::HasResolver,
12 type_ref::{Mutability, TypeRef}, 12 type_ref::{Mutability, TypeRef},
13 AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, HasModule, ImplId, LocalEnumVariantId, 13 AdtId, ConstId, DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId,
14 LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 14 LocalEnumVariantId, LocalModuleId, LocalStructFieldId, Lookup, ModuleId, StaticId, StructId,
15 TypeParamId, UnionId, 15 TraitId, TypeAliasId, TypeParamId, UnionId,
16}; 16};
17use hir_expand::{ 17use hir_expand::{
18 diagnostics::DiagnosticSink, 18 diagnostics::DiagnosticSink,
@@ -21,7 +21,7 @@ use hir_expand::{
21}; 21};
22use hir_ty::{ 22use hir_ty::{
23 autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy, 23 autoderef, display::HirFormatter, expr::ExprValidator, method_resolution, ApplicationTy,
24 Canonical, InEnvironment, TraitEnvironment, Ty, TyDefId, TypeCtor, TypeWalk, 24 Canonical, InEnvironment, Substs, TraitEnvironment, Ty, TyDefId, TypeCtor,
25}; 25};
26use ra_db::{CrateId, Edition, FileId}; 26use ra_db::{CrateId, Edition, FileId};
27use ra_prof::profile; 27use ra_prof::profile;
@@ -270,7 +270,13 @@ impl StructField {
270 270
271 pub fn ty(&self, db: &impl HirDatabase) -> Type { 271 pub fn ty(&self, db: &impl HirDatabase) -> Type {
272 let var_id = self.parent.into(); 272 let var_id = self.parent.into();
273 let ty = db.field_types(var_id)[self.id].clone(); 273 let generic_def_id: GenericDefId = match self.parent {
274 VariantDef::Struct(it) => it.id.into(),
275 VariantDef::Union(it) => it.id.into(),
276 VariantDef::EnumVariant(it) => it.parent.id.into(),
277 };
278 let substs = Substs::type_params(db, generic_def_id);
279 let ty = db.field_types(var_id)[self.id].clone().subst(&substs);
274 Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty) 280 Type::new(db, self.parent.module(db).id.krate.into(), var_id, ty)
275 } 281 }
276 282
@@ -755,7 +761,7 @@ pub struct TypeParam {
755impl TypeParam { 761impl TypeParam {
756 pub fn name(self, db: &impl HirDatabase) -> Name { 762 pub fn name(self, db: &impl HirDatabase) -> Name {
757 let params = db.generic_params(self.id.parent); 763 let params = db.generic_params(self.id.parent);
758 params.types[self.id.local_id].name.clone() 764 params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
759 } 765 }
760 766
761 pub fn module(self, db: &impl HirDatabase) -> Module { 767 pub fn module(self, db: &impl HirDatabase) -> Module {
@@ -789,8 +795,9 @@ impl ImplBlock {
789 pub fn target_ty(&self, db: &impl HirDatabase) -> Type { 795 pub fn target_ty(&self, db: &impl HirDatabase) -> Type {
790 let impl_data = db.impl_data(self.id); 796 let impl_data = db.impl_data(self.id);
791 let resolver = self.id.resolver(db); 797 let resolver = self.id.resolver(db);
798 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
792 let environment = TraitEnvironment::lower(db, &resolver); 799 let environment = TraitEnvironment::lower(db, &resolver);
793 let ty = Ty::from_hir(db, &resolver, &impl_data.target_type); 800 let ty = Ty::from_hir(&ctx, &impl_data.target_type);
794 Type { 801 Type {
795 krate: self.id.lookup(db).container.module(db).krate, 802 krate: self.id.lookup(db).container.module(db).krate,
796 ty: InEnvironment { value: ty, environment }, 803 ty: InEnvironment { value: ty, environment },
@@ -851,9 +858,10 @@ impl Type {
851 fn from_def( 858 fn from_def(
852 db: &impl HirDatabase, 859 db: &impl HirDatabase,
853 krate: CrateId, 860 krate: CrateId,
854 def: impl HasResolver + Into<TyDefId>, 861 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>,
855 ) -> Type { 862 ) -> Type {
856 let ty = db.ty(def.into()); 863 let substs = Substs::type_params(db, def);
864 let ty = db.ty(def.into()).subst(&substs);
857 Type::new(db, krate, def, ty) 865 Type::new(db, krate, def, ty)
858 } 866 }
859 867
@@ -950,7 +958,7 @@ impl Type {
950 match a_ty.ctor { 958 match a_ty.ctor {
951 TypeCtor::Tuple { .. } => { 959 TypeCtor::Tuple { .. } => {
952 for ty in a_ty.parameters.iter() { 960 for ty in a_ty.parameters.iter() {
953 let ty = ty.clone().subst(&a_ty.parameters); 961 let ty = ty.clone();
954 res.push(self.derived(ty)); 962 res.push(self.derived(ty));
955 } 963 }
956 } 964 }
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs
index 86e422779..e1c7b7a20 100644
--- a/crates/ra_hir/src/lib.rs
+++ b/crates/ra_hir/src/lib.rs
@@ -58,7 +58,6 @@ pub use hir_def::{
58 type_ref::Mutability, 58 type_ref::Mutability,
59}; 59};
60pub use hir_expand::{ 60pub use hir_expand::{
61 name::{name, Name}, 61 name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
62 HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin,
63}; 62};
64pub use hir_ty::{display::HirDisplay, CallableDef}; 63pub use hir_ty::{display::HirDisplay, CallableDef};
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs
index 4f8fc9602..bb9a35c5d 100644
--- a/crates/ra_hir/src/source_analyzer.rs
+++ b/crates/ra_hir/src/source_analyzer.rs
@@ -178,6 +178,10 @@ impl SourceAnalyzer {
178 } 178 }
179 } 179 }
180 180
181 fn trait_env(&self, db: &impl HirDatabase) -> Arc<TraitEnvironment> {
182 TraitEnvironment::lower(db, &self.resolver)
183 }
184
181 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> { 185 pub fn type_of(&self, db: &impl HirDatabase, expr: &ast::Expr) -> Option<Type> {
182 let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) { 186 let expr_id = if let Some(expr) = self.expand_expr(db, InFile::new(self.file_id, expr)) {
183 self.body_source_map.as_ref()?.node_expr(expr.as_ref())? 187 self.body_source_map.as_ref()?.node_expr(expr.as_ref())?
@@ -186,14 +190,14 @@ impl SourceAnalyzer {
186 }; 190 };
187 191
188 let ty = self.infer.as_ref()?[expr_id].clone(); 192 let ty = self.infer.as_ref()?[expr_id].clone();
189 let environment = TraitEnvironment::lower(db, &self.resolver); 193 let environment = self.trait_env(db);
190 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) 194 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
191 } 195 }
192 196
193 pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> { 197 pub fn type_of_pat(&self, db: &impl HirDatabase, pat: &ast::Pat) -> Option<Type> {
194 let pat_id = self.pat_id(pat)?; 198 let pat_id = self.pat_id(pat)?;
195 let ty = self.infer.as_ref()?[pat_id].clone(); 199 let ty = self.infer.as_ref()?[pat_id].clone();
196 let environment = TraitEnvironment::lower(db, &self.resolver); 200 let environment = self.trait_env(db);
197 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } }) 201 Some(Type { krate: self.resolver.krate()?, ty: InEnvironment { value: ty, environment } })
198 } 202 }
199 203
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs
index e656f9a41..fe0973fc7 100644
--- a/crates/ra_hir_def/src/body/lower.rs
+++ b/crates/ra_hir_def/src/body/lower.rs
@@ -164,9 +164,9 @@ where
164 let match_expr = self.collect_expr_opt(condition.expr()); 164 let match_expr = self.collect_expr_opt(condition.expr());
165 let placeholder_pat = self.missing_pat(); 165 let placeholder_pat = self.missing_pat();
166 let arms = vec![ 166 let arms = vec![
167 MatchArm { pats: vec![pat], expr: then_branch, guard: None }, 167 MatchArm { pat, expr: then_branch, guard: None },
168 MatchArm { 168 MatchArm {
169 pats: vec![placeholder_pat], 169 pat: placeholder_pat,
170 expr: else_branch.unwrap_or_else(|| self.empty_block()), 170 expr: else_branch.unwrap_or_else(|| self.empty_block()),
171 guard: None, 171 guard: None,
172 }, 172 },
@@ -203,8 +203,8 @@ where
203 let placeholder_pat = self.missing_pat(); 203 let placeholder_pat = self.missing_pat();
204 let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); 204 let break_ = self.alloc_expr_desugared(Expr::Break { expr: None });
205 let arms = vec![ 205 let arms = vec![
206 MatchArm { pats: vec![pat], expr: body, guard: None }, 206 MatchArm { pat, expr: body, guard: None },
207 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, 207 MatchArm { pat: placeholder_pat, expr: break_, guard: None },
208 ]; 208 ];
209 let match_expr = 209 let match_expr =
210 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); 210 self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms });
@@ -250,7 +250,7 @@ where
250 match_arm_list 250 match_arm_list
251 .arms() 251 .arms()
252 .map(|arm| MatchArm { 252 .map(|arm| MatchArm {
253 pats: arm.pats().map(|p| self.collect_pat(p)).collect(), 253 pat: self.collect_pat_opt(arm.pat()),
254 expr: self.collect_expr_opt(arm.expr()), 254 expr: self.collect_expr_opt(arm.expr()),
255 guard: arm 255 guard: arm
256 .guard() 256 .guard()
@@ -587,6 +587,11 @@ where
587 let path = p.path().and_then(|path| self.expander.parse_path(path)); 587 let path = p.path().and_then(|path| self.expander.parse_path(path));
588 path.map(Pat::Path).unwrap_or(Pat::Missing) 588 path.map(Pat::Path).unwrap_or(Pat::Missing)
589 } 589 }
590 ast::Pat::OrPat(p) => {
591 let pats = p.pats().map(|p| self.collect_pat(p)).collect();
592 Pat::Or(pats)
593 }
594 ast::Pat::ParenPat(p) => return self.collect_pat_opt(p.pat()),
590 ast::Pat::TuplePat(p) => { 595 ast::Pat::TuplePat(p) => {
591 let args = p.args().map(|p| self.collect_pat(p)).collect(); 596 let args = p.args().map(|p| self.collect_pat(p)).collect();
592 Pat::Tuple(args) 597 Pat::Tuple(args)
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs
index a63552327..a58a7b21f 100644
--- a/crates/ra_hir_def/src/body/scope.rs
+++ b/crates/ra_hir_def/src/body/scope.rs
@@ -158,9 +158,7 @@ fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope
158 compute_expr_scopes(*expr, body, scopes, scope); 158 compute_expr_scopes(*expr, body, scopes, scope);
159 for arm in arms { 159 for arm in arms {
160 let scope = scopes.new_scope(scope); 160 let scope = scopes.new_scope(scope);
161 for pat in &arm.pats { 161 scopes.add_bindings(body, scope, arm.pat);
162 scopes.add_bindings(body, scope, *pat);
163 }
164 scopes.set_scope(arm.expr, scope); 162 scopes.set_scope(arm.expr, scope);
165 compute_expr_scopes(arm.expr, body, scopes, scope); 163 compute_expr_scopes(arm.expr, body, scopes, scope);
166 } 164 }
@@ -194,7 +192,7 @@ mod tests {
194 let (off, code) = extract_offset(code); 192 let (off, code) = extract_offset(code);
195 let code = { 193 let code = {
196 let mut buf = String::new(); 194 let mut buf = String::new();
197 let off = u32::from(off) as usize; 195 let off = off.to_usize();
198 buf.push_str(&code[..off]); 196 buf.push_str(&code[..off]);
199 buf.push_str("marker"); 197 buf.push_str("marker");
200 buf.push_str(&code[off..]); 198 buf.push_str(&code[off..]);
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs
index a75ef9970..5a84e08ed 100644
--- a/crates/ra_hir_def/src/expr.rs
+++ b/crates/ra_hir_def/src/expr.rs
@@ -202,7 +202,7 @@ pub enum Array {
202 202
203#[derive(Debug, Clone, Eq, PartialEq)] 203#[derive(Debug, Clone, Eq, PartialEq)]
204pub struct MatchArm { 204pub struct MatchArm {
205 pub pats: Vec<PatId>, 205 pub pat: PatId,
206 pub guard: Option<ExprId>, 206 pub guard: Option<ExprId>,
207 pub expr: ExprId, 207 pub expr: ExprId,
208} 208}
@@ -382,6 +382,7 @@ pub enum Pat {
382 Missing, 382 Missing,
383 Wild, 383 Wild,
384 Tuple(Vec<PatId>), 384 Tuple(Vec<PatId>),
385 Or(Vec<PatId>),
385 Record { 386 Record {
386 path: Option<Path>, 387 path: Option<Path>,
387 args: Vec<RecordFieldPat>, 388 args: Vec<RecordFieldPat>,
@@ -420,7 +421,7 @@ impl Pat {
420 Pat::Bind { subpat, .. } => { 421 Pat::Bind { subpat, .. } => {
421 subpat.iter().copied().for_each(f); 422 subpat.iter().copied().for_each(f);
422 } 423 }
423 Pat::Tuple(args) | Pat::TupleStruct { args, .. } => { 424 Pat::Or(args) | Pat::Tuple(args) | Pat::TupleStruct { args, .. } => {
424 args.iter().copied().for_each(f); 425 args.iter().copied().for_each(f);
425 } 426 }
426 Pat::Ref { pat, .. } => f(*pat), 427 Pat::Ref { pat, .. } => f(*pat),
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs
index e9c28c730..f765e6edc 100644
--- a/crates/ra_hir_def/src/generics.rs
+++ b/crates/ra_hir_def/src/generics.rs
@@ -27,8 +27,16 @@ use crate::{
27/// Data about a generic parameter (to a function, struct, impl, ...). 27/// Data about a generic parameter (to a function, struct, impl, ...).
28#[derive(Clone, PartialEq, Eq, Debug)] 28#[derive(Clone, PartialEq, Eq, Debug)]
29pub struct TypeParamData { 29pub struct TypeParamData {
30 pub name: Name, 30 pub name: Option<Name>,
31 pub default: Option<TypeRef>, 31 pub default: Option<TypeRef>,
32 pub provenance: TypeParamProvenance,
33}
34
35#[derive(Copy, Clone, PartialEq, Eq, Debug)]
36pub enum TypeParamProvenance {
37 TypeParamList,
38 TraitSelf,
39 ArgumentImplTrait,
32} 40}
33 41
34/// Data about the generic parameters of a function, struct, impl, etc. 42/// Data about the generic parameters of a function, struct, impl, etc.
@@ -45,10 +53,17 @@ pub struct GenericParams {
45/// associated type bindings like `Iterator<Item = u32>`. 53/// associated type bindings like `Iterator<Item = u32>`.
46#[derive(Clone, PartialEq, Eq, Debug)] 54#[derive(Clone, PartialEq, Eq, Debug)]
47pub struct WherePredicate { 55pub struct WherePredicate {
48 pub type_ref: TypeRef, 56 pub target: WherePredicateTarget,
49 pub bound: TypeBound, 57 pub bound: TypeBound,
50} 58}
51 59
60#[derive(Clone, PartialEq, Eq, Debug)]
61pub enum WherePredicateTarget {
62 TypeRef(TypeRef),
63 /// For desugared where predicates that can directly refer to a type param.
64 TypeParam(LocalTypeParamId),
65}
66
52type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>; 67type SourceMap = ArenaMap<LocalTypeParamId, Either<ast::TraitDef, ast::TypeParam>>;
53 68
54impl GenericParams { 69impl GenericParams {
@@ -68,6 +83,11 @@ impl GenericParams {
68 GenericDefId::FunctionId(it) => { 83 GenericDefId::FunctionId(it) => {
69 let src = it.lookup(db).source(db); 84 let src = it.lookup(db).source(db);
70 generics.fill(&mut sm, &src.value); 85 generics.fill(&mut sm, &src.value);
86 // lower `impl Trait` in arguments
87 let data = db.function_data(it);
88 for param in &data.params {
89 generics.fill_implicit_impl_trait_args(param);
90 }
71 src.file_id 91 src.file_id
72 } 92 }
73 GenericDefId::AdtId(AdtId::StructId(it)) => { 93 GenericDefId::AdtId(AdtId::StructId(it)) => {
@@ -89,8 +109,11 @@ impl GenericParams {
89 let src = it.lookup(db).source(db); 109 let src = it.lookup(db).source(db);
90 110
91 // traits get the Self type as an implicit first type parameter 111 // traits get the Self type as an implicit first type parameter
92 let self_param_id = 112 let self_param_id = generics.types.alloc(TypeParamData {
93 generics.types.alloc(TypeParamData { name: name![Self], default: None }); 113 name: Some(name![Self]),
114 default: None,
115 provenance: TypeParamProvenance::TraitSelf,
116 });
94 sm.insert(self_param_id, Either::Left(src.value.clone())); 117 sm.insert(self_param_id, Either::Left(src.value.clone()));
95 // add super traits as bounds on Self 118 // add super traits as bounds on Self
96 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar 119 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
@@ -142,7 +165,11 @@ impl GenericParams {
142 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 165 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
143 // FIXME: Use `Path::from_src` 166 // FIXME: Use `Path::from_src`
144 let default = type_param.default_type().map(TypeRef::from_ast); 167 let default = type_param.default_type().map(TypeRef::from_ast);
145 let param = TypeParamData { name: name.clone(), default }; 168 let param = TypeParamData {
169 name: Some(name.clone()),
170 default,
171 provenance: TypeParamProvenance::TypeParamList,
172 };
146 let param_id = self.types.alloc(param); 173 let param_id = self.types.alloc(param);
147 sm.insert(param_id, Either::Right(type_param.clone())); 174 sm.insert(param_id, Either::Right(type_param.clone()));
148 175
@@ -170,11 +197,43 @@ impl GenericParams {
170 return; 197 return;
171 } 198 }
172 let bound = TypeBound::from_ast(bound); 199 let bound = TypeBound::from_ast(bound);
173 self.where_predicates.push(WherePredicate { type_ref, bound }); 200 self.where_predicates
201 .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound });
202 }
203
204 fn fill_implicit_impl_trait_args(&mut self, type_ref: &TypeRef) {
205 type_ref.walk(&mut |type_ref| {
206 if let TypeRef::ImplTrait(bounds) = type_ref {
207 let param = TypeParamData {
208 name: None,
209 default: None,
210 provenance: TypeParamProvenance::ArgumentImplTrait,
211 };
212 let param_id = self.types.alloc(param);
213 for bound in bounds {
214 self.where_predicates.push(WherePredicate {
215 target: WherePredicateTarget::TypeParam(param_id),
216 bound: bound.clone(),
217 });
218 }
219 }
220 });
174 } 221 }
175 222
176 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { 223 pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
177 self.types.iter().find_map(|(id, p)| if &p.name == name { Some(id) } else { None }) 224 self.types
225 .iter()
226 .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
227 }
228
229 pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
230 self.types.iter().find_map(|(id, p)| {
231 if p.provenance == TypeParamProvenance::TraitSelf {
232 Some(id)
233 } else {
234 None
235 }
236 })
178 } 237 }
179} 238}
180 239
diff --git a/crates/ra_hir_def/src/resolver.rs b/crates/ra_hir_def/src/resolver.rs
index f7bac5801..05cf4646a 100644
--- a/crates/ra_hir_def/src/resolver.rs
+++ b/crates/ra_hir_def/src/resolver.rs
@@ -490,10 +490,12 @@ impl Scope {
490 } 490 }
491 Scope::GenericParams { params, def } => { 491 Scope::GenericParams { params, def } => {
492 for (local_id, param) in params.types.iter() { 492 for (local_id, param) in params.types.iter() {
493 f( 493 if let Some(name) = &param.name {
494 param.name.clone(), 494 f(
495 ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }), 495 name.clone(),
496 ) 496 ScopeDef::GenericParam(TypeParamId { local_id, parent: *def }),
497 )
498 }
497 } 499 }
498 } 500 }
499 Scope::ImplBlockScope(i) => { 501 Scope::ImplBlockScope(i) => {
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs
index 5f10e9a88..102fdb13d 100644
--- a/crates/ra_hir_def/src/type_ref.rs
+++ b/crates/ra_hir_def/src/type_ref.rs
@@ -124,6 +124,48 @@ impl TypeRef {
124 pub(crate) fn unit() -> TypeRef { 124 pub(crate) fn unit() -> TypeRef {
125 TypeRef::Tuple(Vec::new()) 125 TypeRef::Tuple(Vec::new())
126 } 126 }
127
128 pub fn walk(&self, f: &mut impl FnMut(&TypeRef)) {
129 go(self, f);
130
131 fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
132 f(type_ref);
133 match type_ref {
134 TypeRef::Fn(types) | TypeRef::Tuple(types) => types.iter().for_each(|t| go(t, f)),
135 TypeRef::RawPtr(type_ref, _)
136 | TypeRef::Reference(type_ref, _)
137 | TypeRef::Array(type_ref)
138 | TypeRef::Slice(type_ref) => go(&type_ref, f),
139 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
140 for bound in bounds {
141 match bound {
142 TypeBound::Path(path) => go_path(path, f),
143 TypeBound::Error => (),
144 }
145 }
146 }
147 TypeRef::Path(path) => go_path(path, f),
148 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
149 };
150 }
151
152 fn go_path(path: &Path, f: &mut impl FnMut(&TypeRef)) {
153 if let Some(type_ref) = path.type_anchor() {
154 go(type_ref, f);
155 }
156 for segment in path.segments().iter() {
157 if let Some(args_and_bindings) = segment.args_and_bindings {
158 for arg in &args_and_bindings.args {
159 let crate::path::GenericArg::Type(type_ref) = arg;
160 go(type_ref, f);
161 }
162 for (_, type_ref) in &args_and_bindings.bindings {
163 go(type_ref, f);
164 }
165 }
166 }
167 }
168 }
127} 169}
128 170
129pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> { 171pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> {
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs
index 133805bdb..b2e10f445 100644
--- a/crates/ra_hir_expand/src/name.rs
+++ b/crates/ra_hir_expand/src/name.rs
@@ -187,13 +187,6 @@ pub mod known {
187 PartialOrd, 187 PartialOrd,
188 Eq, 188 Eq,
189 PartialEq, 189 PartialEq,
190 // FIXME delete those after `ImportResolver` is removed.
191 hash,
192 fmt,
193 io,
194 Display,
195 Iterator,
196 Hasher,
197 ); 190 );
198 191
199 // self/Self cannot be used as an identifier 192 // self/Self cannot be used as an identifier
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs
index eb521c7a0..e9bfcfa17 100644
--- a/crates/ra_hir_ty/src/db.rs
+++ b/crates/ra_hir_ty/src/db.rs
@@ -3,17 +3,18 @@
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::{ 5use hir_def::{
6 db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, VariantId, 6 db::DefDatabase, DefWithBodyId, GenericDefId, ImplId, LocalStructFieldId, TraitId, TypeParamId,
7 VariantId,
7}; 8};
8use ra_arena::map::ArenaMap; 9use ra_arena::map::ArenaMap;
9use ra_db::{salsa, CrateId}; 10use ra_db::{impl_intern_key, salsa, CrateId};
10use ra_prof::profile; 11use ra_prof::profile;
11 12
12use crate::{ 13use crate::{
13 method_resolution::CrateImplBlocks, 14 method_resolution::CrateImplBlocks,
14 traits::{chalk, AssocTyValue, Impl}, 15 traits::{chalk, AssocTyValue, Impl},
15 CallableDef, FnSig, GenericPredicate, InferenceResult, Substs, TraitRef, Ty, TyDefId, TypeCtor, 16 Binders, CallableDef, GenericPredicate, InferenceResult, PolyFnSig, Substs, TraitRef, Ty,
16 ValueTyDefId, 17 TyDefId, TypeCtor, ValueTyDefId,
17}; 18};
18 19
19#[salsa::query_group(HirDatabaseStorage)] 20#[salsa::query_group(HirDatabaseStorage)]
@@ -27,34 +28,33 @@ pub trait HirDatabase: DefDatabase {
27 28
28 #[salsa::invoke(crate::lower::ty_query)] 29 #[salsa::invoke(crate::lower::ty_query)]
29 #[salsa::cycle(crate::lower::ty_recover)] 30 #[salsa::cycle(crate::lower::ty_recover)]
30 fn ty(&self, def: TyDefId) -> Ty; 31 fn ty(&self, def: TyDefId) -> Binders<Ty>;
31 32
32 #[salsa::invoke(crate::lower::value_ty_query)] 33 #[salsa::invoke(crate::lower::value_ty_query)]
33 fn value_ty(&self, def: ValueTyDefId) -> Ty; 34 fn value_ty(&self, def: ValueTyDefId) -> Binders<Ty>;
34 35
35 #[salsa::invoke(crate::lower::impl_self_ty_query)] 36 #[salsa::invoke(crate::lower::impl_self_ty_query)]
36 #[salsa::cycle(crate::lower::impl_self_ty_recover)] 37 #[salsa::cycle(crate::lower::impl_self_ty_recover)]
37 fn impl_self_ty(&self, def: ImplId) -> Ty; 38 fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
38 39
39 #[salsa::invoke(crate::lower::impl_trait_query)] 40 #[salsa::invoke(crate::lower::impl_trait_query)]
40 fn impl_trait(&self, def: ImplId) -> Option<TraitRef>; 41 fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
41 42
42 #[salsa::invoke(crate::lower::field_types_query)] 43 #[salsa::invoke(crate::lower::field_types_query)]
43 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Ty>>; 44 fn field_types(&self, var: VariantId) -> Arc<ArenaMap<LocalStructFieldId, Binders<Ty>>>;
44 45
45 #[salsa::invoke(crate::callable_item_sig)] 46 #[salsa::invoke(crate::callable_item_sig)]
46 fn callable_item_signature(&self, def: CallableDef) -> FnSig; 47 fn callable_item_signature(&self, def: CallableDef) -> PolyFnSig;
47 48
48 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)] 49 #[salsa::invoke(crate::lower::generic_predicates_for_param_query)]
49 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)] 50 #[salsa::cycle(crate::lower::generic_predicates_for_param_recover)]
50 fn generic_predicates_for_param( 51 fn generic_predicates_for_param(
51 &self, 52 &self,
52 def: GenericDefId, 53 param_id: TypeParamId,
53 param_idx: u32, 54 ) -> Arc<[Binders<GenericPredicate>]>;
54 ) -> Arc<[GenericPredicate]>;
55 55
56 #[salsa::invoke(crate::lower::generic_predicates_query)] 56 #[salsa::invoke(crate::lower::generic_predicates_query)]
57 fn generic_predicates(&self, def: GenericDefId) -> Arc<[GenericPredicate]>; 57 fn generic_predicates(&self, def: GenericDefId) -> Arc<[Binders<GenericPredicate>]>;
58 58
59 #[salsa::invoke(crate::lower::generic_defaults_query)] 59 #[salsa::invoke(crate::lower::generic_defaults_query)]
60 fn generic_defaults(&self, def: GenericDefId) -> Substs; 60 fn generic_defaults(&self, def: GenericDefId) -> Substs;
@@ -77,6 +77,8 @@ pub trait HirDatabase: DefDatabase {
77 #[salsa::interned] 77 #[salsa::interned]
78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; 78 fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId;
79 #[salsa::interned] 79 #[salsa::interned]
80 fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId;
81 #[salsa::interned]
80 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; 82 fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId;
81 #[salsa::interned] 83 #[salsa::interned]
82 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId; 84 fn intern_assoc_ty_value(&self, assoc_ty_value: AssocTyValue) -> crate::traits::AssocTyValueId;
@@ -117,3 +119,7 @@ fn infer(db: &impl HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
117fn hir_database_is_object_safe() { 119fn hir_database_is_object_safe() {
118 fn _assert_object_safe(_: &dyn HirDatabase) {} 120 fn _assert_object_safe(_: &dyn HirDatabase) {}
119} 121}
122
123#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
124pub struct GlobalTypeParamId(salsa::InternId);
125impl_intern_key!(GlobalTypeParamId);
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs
index e2eda3134..a9d958c8b 100644
--- a/crates/ra_hir_ty/src/infer.rs
+++ b/crates/ra_hir_ty/src/infer.rs
@@ -34,7 +34,6 @@ use hir_expand::{diagnostics::DiagnosticSink, name::name};
34use ra_arena::map::ArenaMap; 34use ra_arena::map::ArenaMap;
35use ra_prof::profile; 35use ra_prof::profile;
36use ra_syntax::SmolStr; 36use ra_syntax::SmolStr;
37use test_utils::tested_by;
38 37
39use super::{ 38use super::{
40 primitive::{FloatTy, IntTy}, 39 primitive::{FloatTy, IntTy},
@@ -42,7 +41,9 @@ use super::{
42 ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment, 41 ApplicationTy, GenericPredicate, InEnvironment, ProjectionTy, Substs, TraitEnvironment,
43 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain, 42 TraitRef, Ty, TypeCtor, TypeWalk, Uncertain,
44}; 43};
45use crate::{db::HirDatabase, infer::diagnostics::InferenceDiagnostic}; 44use crate::{
45 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode,
46};
46 47
47pub(crate) use unify::unify; 48pub(crate) use unify::unify;
48 49
@@ -271,38 +272,21 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
271 self.result.diagnostics.push(diagnostic); 272 self.result.diagnostics.push(diagnostic);
272 } 273 }
273 274
274 fn make_ty(&mut self, type_ref: &TypeRef) -> Ty { 275 fn make_ty_with_mode(
275 let ty = Ty::from_hir( 276 &mut self,
276 self.db, 277 type_ref: &TypeRef,
277 // FIXME use right resolver for block 278 impl_trait_mode: ImplTraitLoweringMode,
278 &self.resolver, 279 ) -> Ty {
279 type_ref, 280 // FIXME use right resolver for block
280 ); 281 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
282 .with_impl_trait_mode(impl_trait_mode);
283 let ty = Ty::from_hir(&ctx, type_ref);
281 let ty = self.insert_type_vars(ty); 284 let ty = self.insert_type_vars(ty);
282 self.normalize_associated_types_in(ty) 285 self.normalize_associated_types_in(ty)
283 } 286 }
284 287
285 /// Replaces `impl Trait` in `ty` by type variables and obligations for 288 fn make_ty(&mut self, type_ref: &TypeRef) -> Ty {
286 /// those variables. This is done for function arguments when calling a 289 self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
287 /// function, and for return types when inside the function body, i.e. in
288 /// the cases where the `impl Trait` is 'transparent'. In other cases, `impl
289 /// Trait` is represented by `Ty::Opaque`.
290 fn insert_vars_for_impl_trait(&mut self, ty: Ty) -> Ty {
291 ty.fold(&mut |ty| match ty {
292 Ty::Opaque(preds) => {
293 tested_by!(insert_vars_for_impl_trait);
294 let var = self.table.new_type_var();
295 let var_subst = Substs::builder(1).push(var.clone()).build();
296 self.obligations.extend(
297 preds
298 .iter()
299 .map(|pred| pred.clone().subst_bound_vars(&var_subst))
300 .filter_map(Obligation::from_predicate),
301 );
302 var
303 }
304 _ => ty,
305 })
306 } 290 }
307 291
308 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 292 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
@@ -446,19 +430,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
446 None => return (Ty::Unknown, None), 430 None => return (Ty::Unknown, None),
447 }; 431 };
448 let resolver = &self.resolver; 432 let resolver = &self.resolver;
433 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
449 // FIXME: this should resolve assoc items as well, see this example: 434 // FIXME: this should resolve assoc items as well, see this example:
450 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521 435 // https://play.rust-lang.org/?gist=087992e9e22495446c01c0d4e2d69521
451 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) { 436 match resolver.resolve_path_in_type_ns_fully(self.db, path.mod_path()) {
452 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => { 437 Some(TypeNs::AdtId(AdtId::StructId(strukt))) => {
453 let substs = Ty::substs_from_path(self.db, resolver, path, strukt.into()); 438 let substs = Ty::substs_from_path(&ctx, path, strukt.into());
454 let ty = self.db.ty(strukt.into()); 439 let ty = self.db.ty(strukt.into());
455 let ty = self.insert_type_vars(ty.apply_substs(substs)); 440 let ty = self.insert_type_vars(ty.subst(&substs));
456 (ty, Some(strukt.into())) 441 (ty, Some(strukt.into()))
457 } 442 }
458 Some(TypeNs::EnumVariantId(var)) => { 443 Some(TypeNs::EnumVariantId(var)) => {
459 let substs = Ty::substs_from_path(self.db, resolver, path, var.into()); 444 let substs = Ty::substs_from_path(&ctx, path, var.into());
460 let ty = self.db.ty(var.parent.into()); 445 let ty = self.db.ty(var.parent.into());
461 let ty = self.insert_type_vars(ty.apply_substs(substs)); 446 let ty = self.insert_type_vars(ty.subst(&substs));
462 (ty, Some(var.into())) 447 (ty, Some(var.into()))
463 } 448 }
464 Some(_) | None => (Ty::Unknown, None), 449 Some(_) | None => (Ty::Unknown, None),
@@ -471,13 +456,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
471 456
472 fn collect_fn(&mut self, data: &FunctionData) { 457 fn collect_fn(&mut self, data: &FunctionData) {
473 let body = Arc::clone(&self.body); // avoid borrow checker problem 458 let body = Arc::clone(&self.body); // avoid borrow checker problem
474 for (type_ref, pat) in data.params.iter().zip(body.params.iter()) { 459 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver)
475 let ty = self.make_ty(type_ref); 460 .with_impl_trait_mode(ImplTraitLoweringMode::Param);
461 let param_tys =
462 data.params.iter().map(|type_ref| Ty::from_hir(&ctx, type_ref)).collect::<Vec<_>>();
463 for (ty, pat) in param_tys.into_iter().zip(body.params.iter()) {
464 let ty = self.insert_type_vars(ty);
465 let ty = self.normalize_associated_types_in(ty);
476 466
477 self.infer_pat(*pat, &ty, BindingMode::default()); 467 self.infer_pat(*pat, &ty, BindingMode::default());
478 } 468 }
479 let return_ty = self.make_ty(&data.ret_type); 469 let return_ty = self.make_ty_with_mode(&data.ret_type, ImplTraitLoweringMode::Disallowed); // FIXME implement RPIT
480 self.return_ty = self.insert_vars_for_impl_trait(return_ty); 470 self.return_ty = return_ty;
481 } 471 }
482 472
483 fn infer_body(&mut self) { 473 fn infer_body(&mut self) {
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs
index 83c0c2c3f..f68a1439f 100644
--- a/crates/ra_hir_ty/src/infer/coerce.rs
+++ b/crates/ra_hir_ty/src/infer/coerce.rs
@@ -57,8 +57,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
57 let trait_ref = db.impl_trait(impl_id)?; 57 let trait_ref = db.impl_trait(impl_id)?;
58 58
59 // `CoerseUnsized` has one generic parameter for the target type. 59 // `CoerseUnsized` has one generic parameter for the target type.
60 let cur_from_ty = trait_ref.substs.0.get(0)?; 60 let cur_from_ty = trait_ref.value.substs.0.get(0)?;
61 let cur_to_ty = trait_ref.substs.0.get(1)?; 61 let cur_to_ty = trait_ref.value.substs.0.get(1)?;
62 62
63 match (&cur_from_ty, cur_to_ty) { 63 match (&cur_from_ty, cur_to_ty) {
64 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => { 64 (ty_app!(ctor1, st1), ty_app!(ctor2, st2)) => {
@@ -66,9 +66,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
66 // This works for smart-pointer-like coercion, which covers all impls from std. 66 // This works for smart-pointer-like coercion, which covers all impls from std.
67 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| { 67 st1.iter().zip(st2.iter()).enumerate().find_map(|(i, (ty1, ty2))| {
68 match (ty1, ty2) { 68 match (ty1, ty2) {
69 (Ty::Param { idx: p1, .. }, Ty::Param { idx: p2, .. }) 69 (Ty::Bound(idx1), Ty::Bound(idx2)) if idx1 != idx2 => {
70 if p1 != p2 =>
71 {
72 Some(((*ctor1, *ctor2), i)) 70 Some(((*ctor1, *ctor2), i))
73 } 71 }
74 _ => None, 72 _ => None,
@@ -256,8 +254,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
256 let unsize_generic_index = { 254 let unsize_generic_index = {
257 let mut index = None; 255 let mut index = None;
258 let mut multiple_param = false; 256 let mut multiple_param = false;
259 field_tys[last_field_id].walk(&mut |ty| match ty { 257 field_tys[last_field_id].value.walk(&mut |ty| match ty {
260 &Ty::Param { idx, .. } => { 258 &Ty::Bound(idx) => {
261 if index.is_none() { 259 if index.is_none() {
262 index = Some(idx); 260 index = Some(idx);
263 } else if Some(idx) != index { 261 } else if Some(idx) != index {
@@ -276,10 +274,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
276 // Check other fields do not involve it. 274 // Check other fields do not involve it.
277 let mut multiple_used = false; 275 let mut multiple_used = false;
278 fields.for_each(|(field_id, _data)| { 276 fields.for_each(|(field_id, _data)| {
279 field_tys[field_id].walk(&mut |ty| match ty { 277 field_tys[field_id].value.walk(&mut |ty| match ty {
280 &Ty::Param { idx, .. } if idx == unsize_generic_index => { 278 &Ty::Bound(idx) if idx == unsize_generic_index => multiple_used = true,
281 multiple_used = true
282 }
283 _ => {} 279 _ => {}
284 }) 280 })
285 }); 281 });
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs
index 31259a01d..186857b8b 100644
--- a/crates/ra_hir_ty/src/infer/expr.rs
+++ b/crates/ra_hir_ty/src/infer/expr.rs
@@ -10,7 +10,7 @@ use hir_def::{
10 resolver::resolver_for_expr, 10 resolver::resolver_for_expr,
11 AdtId, AssocContainerId, Lookup, StructFieldId, 11 AdtId, AssocContainerId, Lookup, StructFieldId,
12}; 12};
13use hir_expand::name::{name, Name}; 13use hir_expand::name::Name;
14use ra_syntax::ast::RangeOp; 14use ra_syntax::ast::RangeOp;
15 15
16use crate::{ 16use crate::{
@@ -19,8 +19,8 @@ use crate::{
19 method_resolution, op, 19 method_resolution, op,
20 traits::InEnvironment, 20 traits::InEnvironment,
21 utils::{generics, variant_data, Generics}, 21 utils::{generics, variant_data, Generics},
22 ApplicationTy, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, Ty, 22 ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef,
23 TypeCtor, TypeWalk, Uncertain, 23 Ty, TypeCtor, Uncertain,
24}; 24};
25 25
26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch}; 26use super::{BindingMode, Expectation, InferenceContext, InferenceDiagnostic, TypeMismatch};
@@ -168,9 +168,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
168 let mut result_ty = self.table.new_maybe_never_type_var(); 168 let mut result_ty = self.table.new_maybe_never_type_var();
169 169
170 for arm in arms { 170 for arm in arms {
171 for &pat in &arm.pats { 171 let _pat_ty = self.infer_pat(arm.pat, &input_ty, BindingMode::default());
172 let _pat_ty = self.infer_pat(pat, &input_ty, BindingMode::default());
173 }
174 if let Some(guard_expr) = arm.guard { 172 if let Some(guard_expr) = arm.guard {
175 self.infer_expr( 173 self.infer_expr(
176 guard_expr, 174 guard_expr,
@@ -236,8 +234,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
236 self.result.record_field_resolutions.insert(field.expr, field_def); 234 self.result.record_field_resolutions.insert(field.expr, field_def);
237 } 235 }
238 let field_ty = field_def 236 let field_ty = field_def
239 .map_or(Ty::Unknown, |it| field_types[it.local_id].clone()) 237 .map_or(Ty::Unknown, |it| field_types[it.local_id].clone().subst(&substs));
240 .subst(&substs);
241 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 238 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
242 } 239 }
243 if let Some(expr) = spread { 240 if let Some(expr) = spread {
@@ -588,10 +585,10 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
588 self.write_method_resolution(tgt_expr, func); 585 self.write_method_resolution(tgt_expr, func);
589 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into()))) 586 (ty, self.db.value_ty(func.into()), Some(generics(self.db, func.into())))
590 } 587 }
591 None => (receiver_ty, Ty::Unknown, None), 588 None => (receiver_ty, Binders::new(0, Ty::Unknown), None),
592 }; 589 };
593 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); 590 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
594 let method_ty = method_ty.apply_substs(substs); 591 let method_ty = method_ty.subst(&substs);
595 let method_ty = self.insert_type_vars(method_ty); 592 let method_ty = self.insert_type_vars(method_ty);
596 self.register_obligations_for_call(&method_ty); 593 self.register_obligations_for_call(&method_ty);
597 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 594 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
@@ -635,7 +632,6 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
635 continue; 632 continue;
636 } 633 }
637 634
638 let param_ty = self.insert_vars_for_impl_trait(param_ty);
639 let param_ty = self.normalize_associated_types_in(param_ty); 635 let param_ty = self.normalize_associated_types_in(param_ty);
640 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone())); 636 self.infer_expr_coerce(arg, &Expectation::has_type(param_ty.clone()));
641 } 637 }
@@ -648,13 +644,15 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
648 generic_args: Option<&GenericArgs>, 644 generic_args: Option<&GenericArgs>,
649 receiver_ty: &Ty, 645 receiver_ty: &Ty,
650 ) -> Substs { 646 ) -> Substs {
651 let (total_len, _parent_len, child_len) = 647 let (parent_params, self_params, type_params, impl_trait_params) =
652 def_generics.as_ref().map_or((0, 0, 0), |g| g.len_split()); 648 def_generics.as_ref().map_or((0, 0, 0, 0), |g| g.provenance_split());
649 assert_eq!(self_params, 0); // method shouldn't have another Self param
650 let total_len = parent_params + type_params + impl_trait_params;
653 let mut substs = Vec::with_capacity(total_len); 651 let mut substs = Vec::with_capacity(total_len);
654 // Parent arguments are unknown, except for the receiver type 652 // Parent arguments are unknown, except for the receiver type
655 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) { 653 if let Some(parent_generics) = def_generics.as_ref().map(|p| p.iter_parent()) {
656 for (_id, param) in parent_generics { 654 for (_id, param) in parent_generics {
657 if param.name == name![Self] { 655 if param.provenance == hir_def::generics::TypeParamProvenance::TraitSelf {
658 substs.push(receiver_ty.clone()); 656 substs.push(receiver_ty.clone());
659 } else { 657 } else {
660 substs.push(Ty::Unknown); 658 substs.push(Ty::Unknown);
@@ -664,7 +662,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
664 // handle provided type arguments 662 // handle provided type arguments
665 if let Some(generic_args) = generic_args { 663 if let Some(generic_args) = generic_args {
666 // if args are provided, it should be all of them, but we can't rely on that 664 // if args are provided, it should be all of them, but we can't rely on that
667 for arg in generic_args.args.iter().take(child_len) { 665 for arg in generic_args.args.iter().take(type_params) {
668 match arg { 666 match arg {
669 GenericArg::Type(type_ref) => { 667 GenericArg::Type(type_ref) => {
670 let ty = self.make_ty(type_ref); 668 let ty = self.make_ty(type_ref);
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs
index a14662884..a5dfdf6c4 100644
--- a/crates/ra_hir_ty/src/infer/pat.rs
+++ b/crates/ra_hir_ty/src/infer/pat.rs
@@ -12,7 +12,7 @@ use hir_expand::name::Name;
12use test_utils::tested_by; 12use test_utils::tested_by;
13 13
14use super::{BindingMode, InferenceContext}; 14use super::{BindingMode, InferenceContext};
15use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor, TypeWalk}; 15use crate::{db::HirDatabase, utils::variant_data, Substs, Ty, TypeCtor};
16 16
17impl<'a, D: HirDatabase> InferenceContext<'a, D> { 17impl<'a, D: HirDatabase> InferenceContext<'a, D> {
18 fn infer_tuple_struct_pat( 18 fn infer_tuple_struct_pat(
@@ -34,8 +34,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
34 let expected_ty = var_data 34 let expected_ty = var_data
35 .as_ref() 35 .as_ref()
36 .and_then(|d| d.field(&Name::new_tuple_field(i))) 36 .and_then(|d| d.field(&Name::new_tuple_field(i)))
37 .map_or(Ty::Unknown, |field| field_tys[field].clone()) 37 .map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
38 .subst(&substs);
39 let expected_ty = self.normalize_associated_types_in(expected_ty); 38 let expected_ty = self.normalize_associated_types_in(expected_ty);
40 self.infer_pat(subpat, &expected_ty, default_bm); 39 self.infer_pat(subpat, &expected_ty, default_bm);
41 } 40 }
@@ -65,7 +64,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
65 for subpat in subpats { 64 for subpat in subpats {
66 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); 65 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
67 let expected_ty = 66 let expected_ty =
68 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone()).subst(&substs); 67 matching_field.map_or(Ty::Unknown, |field| field_tys[field].clone().subst(&substs));
69 let expected_ty = self.normalize_associated_types_in(expected_ty); 68 let expected_ty = self.normalize_associated_types_in(expected_ty);
70 self.infer_pat(subpat.pat, &expected_ty, default_bm); 69 self.infer_pat(subpat.pat, &expected_ty, default_bm);
71 } 70 }
@@ -83,6 +82,7 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
83 82
84 let is_non_ref_pat = match &body[pat] { 83 let is_non_ref_pat = match &body[pat] {
85 Pat::Tuple(..) 84 Pat::Tuple(..)
85 | Pat::Or(..)
86 | Pat::TupleStruct { .. } 86 | Pat::TupleStruct { .. }
87 | Pat::Record { .. } 87 | Pat::Record { .. }
88 | Pat::Range { .. } 88 | Pat::Range { .. }
@@ -127,6 +127,17 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
127 127
128 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys)) 128 Ty::apply(TypeCtor::Tuple { cardinality: args.len() as u16 }, Substs(inner_tys))
129 } 129 }
130 Pat::Or(ref pats) => {
131 if let Some((first_pat, rest)) = pats.split_first() {
132 let ty = self.infer_pat(*first_pat, expected, default_bm);
133 for pat in rest {
134 self.infer_pat(*pat, expected, default_bm);
135 }
136 ty
137 } else {
138 Ty::Unknown
139 }
140 }
130 Pat::Ref { pat, mutability } => { 141 Pat::Ref { pat, mutability } => {
131 let expectation = match expected.as_reference() { 142 let expectation = match expected.as_reference() {
132 Some((inner_ty, exp_mut)) => { 143 Some((inner_ty, exp_mut)) => {
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs
index 2c1d4831d..686ce7a21 100644
--- a/crates/ra_hir_ty/src/infer/path.rs
+++ b/crates/ra_hir_ty/src/infer/path.rs
@@ -9,9 +9,9 @@ use hir_def::{
9}; 9};
10use hir_expand::name::Name; 10use hir_expand::name::Name;
11 11
12use crate::{db::HirDatabase, method_resolution, Substs, Ty, TypeWalk, ValueTyDefId}; 12use crate::{db::HirDatabase, method_resolution, Substs, Ty, ValueTyDefId};
13 13
14use super::{ExprOrPatId, InferenceContext, TraitEnvironment, TraitRef}; 14use super::{ExprOrPatId, InferenceContext, TraitRef};
15 15
16impl<'a, D: HirDatabase> InferenceContext<'a, D> { 16impl<'a, D: HirDatabase> InferenceContext<'a, D> {
17 pub(super) fn infer_path( 17 pub(super) fn infer_path(
@@ -39,7 +39,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
39 } 39 }
40 let ty = self.make_ty(type_ref); 40 let ty = self.make_ty(type_ref);
41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1); 41 let remaining_segments_for_ty = path.segments().take(path.segments().len() - 1);
42 let ty = Ty::from_type_relative_path(self.db, resolver, ty, remaining_segments_for_ty); 42 let ctx = crate::lower::TyLoweringContext::new(self.db, &resolver);
43 let ty = Ty::from_type_relative_path(&ctx, ty, remaining_segments_for_ty);
43 self.resolve_ty_assoc_item( 44 self.resolve_ty_assoc_item(
44 ty, 45 ty,
45 &path.segments().last().expect("path had at least one segment").name, 46 &path.segments().last().expect("path had at least one segment").name,
@@ -69,12 +70,16 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
69 ValueNs::EnumVariantId(it) => it.into(), 70 ValueNs::EnumVariantId(it) => it.into(),
70 }; 71 };
71 72
72 let mut ty = self.db.value_ty(typable); 73 let ty = self.db.value_ty(typable);
73 if let Some(self_subst) = self_subst { 74 // self_subst is just for the parent
74 ty = ty.subst(&self_subst); 75 let parent_substs = self_subst.unwrap_or_else(Substs::empty);
75 } 76 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
76 let substs = Ty::substs_from_path(self.db, &self.resolver, path, typable); 77 let substs = Ty::substs_from_path(&ctx, path, typable);
77 let ty = ty.subst(&substs); 78 let full_substs = Substs::builder(substs.len())
79 .use_parent_substs(&parent_substs)
80 .fill(substs.0[parent_substs.len()..].iter().cloned())
81 .build();
82 let ty = ty.subst(&full_substs);
78 Some(ty) 83 Some(ty)
79 } 84 }
80 85
@@ -98,13 +103,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
98 (TypeNs::TraitId(trait_), true) => { 103 (TypeNs::TraitId(trait_), true) => {
99 let segment = 104 let segment =
100 remaining_segments.last().expect("there should be at least one segment here"); 105 remaining_segments.last().expect("there should be at least one segment here");
101 let trait_ref = TraitRef::from_resolved_path( 106 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
102 self.db, 107 let trait_ref =
103 &self.resolver, 108 TraitRef::from_resolved_path(&ctx, trait_.into(), resolved_segment, None);
104 trait_.into(),
105 resolved_segment,
106 None,
107 );
108 self.resolve_trait_assoc_item(trait_ref, segment, id) 109 self.resolve_trait_assoc_item(trait_ref, segment, id)
109 } 110 }
110 (def, _) => { 111 (def, _) => {
@@ -114,9 +115,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
114 // as Iterator>::Item::default`) 115 // as Iterator>::Item::default`)
115 let remaining_segments_for_ty = 116 let remaining_segments_for_ty =
116 remaining_segments.take(remaining_segments.len() - 1); 117 remaining_segments.take(remaining_segments.len() - 1);
118 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
117 let ty = Ty::from_partly_resolved_hir_path( 119 let ty = Ty::from_partly_resolved_hir_path(
118 self.db, 120 &ctx,
119 &self.resolver,
120 def, 121 def,
121 resolved_segment, 122 resolved_segment,
122 remaining_segments_for_ty, 123 remaining_segments_for_ty,
@@ -173,13 +174,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
173 AssocItemId::ConstId(c) => ValueNs::ConstId(c), 174 AssocItemId::ConstId(c) => ValueNs::ConstId(c),
174 AssocItemId::TypeAliasId(_) => unreachable!(), 175 AssocItemId::TypeAliasId(_) => unreachable!(),
175 }; 176 };
176 let substs = Substs::build_for_def(self.db, item)
177 .use_parent_substs(&trait_ref.substs)
178 .fill_with_params()
179 .build();
180 177
181 self.write_assoc_resolution(id, item); 178 self.write_assoc_resolution(id, item);
182 Some((def, Some(substs))) 179 Some((def, Some(trait_ref.substs)))
183 } 180 }
184 181
185 fn resolve_ty_assoc_item( 182 fn resolve_ty_assoc_item(
@@ -193,14 +190,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
193 } 190 }
194 191
195 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone()); 192 let canonical_ty = self.canonicalizer().canonicalize_ty(ty.clone());
196 let env = TraitEnvironment::lower(self.db, &self.resolver);
197 let krate = self.resolver.krate()?; 193 let krate = self.resolver.krate()?;
198 let traits_in_scope = self.resolver.traits_in_scope(self.db); 194 let traits_in_scope = self.resolver.traits_in_scope(self.db);
199 195
200 method_resolution::iterate_method_candidates( 196 method_resolution::iterate_method_candidates(
201 &canonical_ty.value, 197 &canonical_ty.value,
202 self.db, 198 self.db,
203 env, 199 self.trait_env.clone(),
204 krate, 200 krate,
205 &traits_in_scope, 201 &traits_in_scope,
206 Some(name), 202 Some(name),
@@ -219,12 +215,8 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
219 .fill(iter::repeat_with(|| self.table.new_type_var())) 215 .fill(iter::repeat_with(|| self.table.new_type_var()))
220 .build(); 216 .build();
221 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); 217 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs);
222 let substs = Substs::build_for_def(self.db, item)
223 .use_parent_substs(&impl_substs)
224 .fill_with_params()
225 .build();
226 self.unify(&impl_self_ty, &ty); 218 self.unify(&impl_self_ty, &ty);
227 Some(substs) 219 Some(impl_substs)
228 } 220 }
229 AssocContainerId::TraitId(trait_) => { 221 AssocContainerId::TraitId(trait_) => {
230 // we're picking this method 222 // we're picking this method
@@ -232,15 +224,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
232 .push(ty.clone()) 224 .push(ty.clone())
233 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 225 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
234 .build(); 226 .build();
235 let substs = Substs::build_for_def(self.db, item)
236 .use_parent_substs(&trait_substs)
237 .fill_with_params()
238 .build();
239 self.obligations.push(super::Obligation::Trait(TraitRef { 227 self.obligations.push(super::Obligation::Trait(TraitRef {
240 trait_, 228 trait_,
241 substs: trait_substs, 229 substs: trait_substs.clone(),
242 })); 230 }));
243 Some(substs) 231 Some(trait_substs)
244 } 232 }
245 AssocContainerId::ContainerId(_) => None, 233 AssocContainerId::ContainerId(_) => None,
246 }; 234 };
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs
index 08d501ccd..c5fe18c85 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, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, 47 expr::ExprId, generics::TypeParamProvenance, type_ref::Mutability, AdtId, AssocContainerId,
48 HasModule, Lookup, TraitId, TypeAliasId, 48 DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, TypeParamId,
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};
@@ -60,7 +60,9 @@ use display::{HirDisplay, HirFormatter};
60pub use autoderef::autoderef; 60pub use autoderef::autoderef;
61pub use infer::{do_infer_query, InferTy, InferenceResult}; 61pub use infer::{do_infer_query, InferTy, InferenceResult};
62pub use lower::CallableDef; 62pub use lower::CallableDef;
63pub use lower::{callable_item_sig, TyDefId, ValueTyDefId}; 63pub use lower::{
64 callable_item_sig, ImplTraitLoweringMode, TyDefId, TyLoweringContext, ValueTyDefId,
65};
64pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; 66pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment};
65 67
66/// A type constructor or type name: this might be something like the primitive 68/// A type constructor or type name: this might be something like the primitive
@@ -285,22 +287,20 @@ pub enum Ty {
285 /// trait and all its parameters are fully known. 287 /// trait and all its parameters are fully known.
286 Projection(ProjectionTy), 288 Projection(ProjectionTy),
287 289
288 /// A type parameter; for example, `T` in `fn f<T>(x: T) {} 290 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
289 Param { 291 /// {}` when we're type-checking the body of that function. In this
290 /// The index of the parameter (starting with parameters from the 292 /// situation, we know this stands for *some* type, but don't know the exact
291 /// surrounding impl, then the current function). 293 /// type.
292 idx: u32, 294 Param(TypeParamId),
293 /// The name of the parameter, for displaying. 295
294 // FIXME get rid of this 296 /// A bound type variable. This is used in various places: when representing
295 name: Name, 297 /// some polymorphic type like the type of function `fn f<T>`, the type
296 }, 298 /// parameters get turned into variables; during trait resolution, inference
297 299 /// variables get turned into bound variables and back; and in `Dyn` the
298 /// A bound type variable. Used during trait resolution to represent Chalk 300 /// `Self` type is represented with a bound variable as well.
299 /// variables, and in `Dyn` and `Opaque` bounds to represent the `Self` type.
300 Bound(u32), 301 Bound(u32),
301 302
302 /// A type variable used during type checking. Not to be confused with a 303 /// A type variable used during type checking.
303 /// type parameter.
304 Infer(InferTy), 304 Infer(InferTy),
305 305
306 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust). 306 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
@@ -364,15 +364,19 @@ 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(crate) fn identity(generic_params: &Generics) -> Substs { 367 pub(crate) fn type_params_for_generics(generic_params: &Generics) -> Substs {
368 Substs( 368 Substs(generic_params.iter().map(|(id, _)| Ty::Param(id)).collect())
369 generic_params.iter().map(|(idx, p)| Ty::Param { idx, name: p.name.clone() }).collect(), 369 }
370 ) 370
371 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
372 pub fn type_params(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> Substs {
373 let params = generics(db, def.into());
374 Substs::type_params_for_generics(&params)
371 } 375 }
372 376
373 /// Return Substs that replace each parameter by a bound variable. 377 /// Return Substs that replace each parameter by a bound variable.
374 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs { 378 pub(crate) fn bound_vars(generic_params: &Generics) -> Substs {
375 Substs(generic_params.iter().map(|(idx, _p)| Ty::Bound(idx)).collect()) 379 Substs(generic_params.iter().enumerate().map(|(idx, _)| Ty::Bound(idx as u32)).collect())
376 } 380 }
377 381
378 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder { 382 pub fn build_for_def(db: &impl HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
@@ -420,11 +424,6 @@ impl SubstsBuilder {
420 self.fill((starting_from..).map(Ty::Bound)) 424 self.fill((starting_from..).map(Ty::Bound))
421 } 425 }
422 426
423 pub fn fill_with_params(self) -> Self {
424 let start = self.vec.len() as u32;
425 self.fill((start..).map(|idx| Ty::Param { idx, name: Name::missing() }))
426 }
427
428 pub fn fill_with_unknown(self) -> Self { 427 pub fn fill_with_unknown(self) -> Self {
429 self.fill(iter::repeat(Ty::Unknown)) 428 self.fill(iter::repeat(Ty::Unknown))
430 } 429 }
@@ -451,6 +450,32 @@ impl Deref for Substs {
451 } 450 }
452} 451}
453 452
453#[derive(Copy, Clone, PartialEq, Eq, Debug)]
454pub struct Binders<T> {
455 pub num_binders: usize,
456 pub value: T,
457}
458
459impl<T> Binders<T> {
460 pub fn new(num_binders: usize, value: T) -> Self {
461 Self { num_binders, value }
462 }
463}
464
465impl<T: TypeWalk> Binders<T> {
466 /// Substitutes all variables.
467 pub fn subst(self, subst: &Substs) -> T {
468 assert_eq!(subst.len(), self.num_binders);
469 self.value.subst_bound_vars(subst)
470 }
471
472 /// Substitutes just a prefix of the variables (shifting the rest).
473 pub fn subst_prefix(self, subst: &Substs) -> Binders<T> {
474 assert!(subst.len() < self.num_binders);
475 Binders::new(self.num_binders - subst.len(), self.value.subst_bound_vars(subst))
476 }
477}
478
454/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait. 479/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
455/// Name to be bikeshedded: TraitBound? TraitImplements? 480/// Name to be bikeshedded: TraitBound? TraitImplements?
456#[derive(Clone, PartialEq, Eq, Debug, Hash)] 481#[derive(Clone, PartialEq, Eq, Debug, Hash)]
@@ -551,6 +576,9 @@ pub struct FnSig {
551 params_and_return: Arc<[Ty]>, 576 params_and_return: Arc<[Ty]>,
552} 577}
553 578
579/// A polymorphic function signature.
580pub type PolyFnSig = Binders<FnSig>;
581
554impl FnSig { 582impl FnSig {
555 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig { 583 pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
556 params.push(ret); 584 params.push(ret);
@@ -730,22 +758,7 @@ pub trait TypeWalk {
730 self 758 self
731 } 759 }
732 760
733 /// Replaces type parameters in this type using the given `Substs`. (So e.g. 761 /// Substitutes `Ty::Bound` vars with the given substitution.
734 /// if `self` is `&[T]`, where type parameter T has index 0, and the
735 /// `Substs` contain `u32` at index 0, we'll have `&[u32]` afterwards.)
736 fn subst(self, substs: &Substs) -> Self
737 where
738 Self: Sized,
739 {
740 self.fold(&mut |ty| match ty {
741 Ty::Param { idx, name } => {
742 substs.get(idx as usize).cloned().unwrap_or(Ty::Param { idx, name })
743 }
744 ty => ty,
745 })
746 }
747
748 /// Substitutes `Ty::Bound` vars (as opposed to type parameters).
749 fn subst_bound_vars(mut self, substs: &Substs) -> Self 762 fn subst_bound_vars(mut self, substs: &Substs) -> Self
750 where 763 where
751 Self: Sized, 764 Self: Sized,
@@ -755,6 +768,9 @@ pub trait TypeWalk {
755 &mut Ty::Bound(idx) => { 768 &mut Ty::Bound(idx) => {
756 if idx as usize >= binders && (idx as usize - binders) < substs.len() { 769 if idx as usize >= binders && (idx as usize - binders) < substs.len() {
757 *ty = substs.0[idx as usize - binders].clone(); 770 *ty = substs.0[idx as usize - binders].clone();
771 } else if idx as usize >= binders + substs.len() {
772 // shift free binders
773 *ty = Ty::Bound(idx - substs.len() as u32);
758 } 774 }
759 } 775 }
760 _ => {} 776 _ => {}
@@ -880,7 +896,7 @@ impl HirDisplay for ApplicationTy {
880 write!(f, ") -> {}", sig.ret().display(f.db))?; 896 write!(f, ") -> {}", sig.ret().display(f.db))?;
881 } 897 }
882 TypeCtor::FnDef(def) => { 898 TypeCtor::FnDef(def) => {
883 let sig = f.db.callable_item_signature(def); 899 let sig = f.db.callable_item_signature(def).subst(&self.parameters);
884 let name = match def { 900 let name = match def {
885 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(), 901 CallableDef::FunctionId(ff) => f.db.function_data(ff).name.clone(),
886 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(), 902 CallableDef::StructId(s) => f.db.struct_data(s).name.clone(),
@@ -896,9 +912,16 @@ impl HirDisplay for ApplicationTy {
896 } 912 }
897 } 913 }
898 if self.parameters.len() > 0 { 914 if self.parameters.len() > 0 {
899 write!(f, "<")?; 915 let generics = generics(f.db, def.into());
900 f.write_joined(&*self.parameters.0, ", ")?; 916 let (parent_params, self_param, type_params, _impl_trait_params) =
901 write!(f, ">")?; 917 generics.provenance_split();
918 let total_len = parent_params + self_param + type_params;
919 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
920 if total_len > 0 {
921 write!(f, "<")?;
922 f.write_joined(&self.parameters.0[..total_len], ", ")?;
923 write!(f, ">")?;
924 }
902 } 925 }
903 write!(f, "(")?; 926 write!(f, "(")?;
904 f.write_joined(sig.params(), ", ")?; 927 f.write_joined(sig.params(), ", ")?;
@@ -1009,7 +1032,24 @@ impl HirDisplay for Ty {
1009 match self { 1032 match self {
1010 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?, 1033 Ty::Apply(a_ty) => a_ty.hir_fmt(f)?,
1011 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?, 1034 Ty::Projection(p_ty) => p_ty.hir_fmt(f)?,
1012 Ty::Param { name, .. } => write!(f, "{}", name)?, 1035 Ty::Param(id) => {
1036 let generics = generics(f.db, id.parent);
1037 let param_data = &generics.params.types[id.local_id];
1038 match param_data.provenance {
1039 TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
1040 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
1041 }
1042 TypeParamProvenance::ArgumentImplTrait => {
1043 write!(f, "impl ")?;
1044 let bounds = f.db.generic_predicates_for_param(*id);
1045 let substs = Substs::type_params_for_generics(&generics);
1046 write_bounds_like_dyn_trait(
1047 &bounds.iter().map(|b| b.clone().subst(&substs)).collect::<Vec<_>>(),
1048 f,
1049 )?;
1050 }
1051 }
1052 }
1013 Ty::Bound(idx) => write!(f, "?{}", idx)?, 1053 Ty::Bound(idx) => write!(f, "?{}", idx)?,
1014 Ty::Dyn(predicates) | Ty::Opaque(predicates) => { 1054 Ty::Dyn(predicates) | Ty::Opaque(predicates) => {
1015 match self { 1055 match self {
@@ -1017,66 +1057,7 @@ impl HirDisplay for Ty {
1017 Ty::Opaque(_) => write!(f, "impl ")?, 1057 Ty::Opaque(_) => write!(f, "impl ")?,
1018 _ => unreachable!(), 1058 _ => unreachable!(),
1019 }; 1059 };
1020 // Note: This code is written to produce nice results (i.e. 1060 write_bounds_like_dyn_trait(&predicates, f)?;
1021 // corresponding to surface Rust) for types that can occur in
1022 // actual Rust. It will have weird results if the predicates
1023 // aren't as expected (i.e. self types = $0, projection
1024 // predicates for a certain trait come after the Implemented
1025 // predicate for that trait).
1026 let mut first = true;
1027 let mut angle_open = false;
1028 for p in predicates.iter() {
1029 match p {
1030 GenericPredicate::Implemented(trait_ref) => {
1031 if angle_open {
1032 write!(f, ">")?;
1033 }
1034 if !first {
1035 write!(f, " + ")?;
1036 }
1037 // We assume that the self type is $0 (i.e. the
1038 // existential) here, which is the only thing that's
1039 // possible in actual Rust, and hence don't print it
1040 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
1041 if trait_ref.substs.len() > 1 {
1042 write!(f, "<")?;
1043 f.write_joined(&trait_ref.substs[1..], ", ")?;
1044 // there might be assoc type bindings, so we leave the angle brackets open
1045 angle_open = true;
1046 }
1047 }
1048 GenericPredicate::Projection(projection_pred) => {
1049 // in types in actual Rust, these will always come
1050 // after the corresponding Implemented predicate
1051 if angle_open {
1052 write!(f, ", ")?;
1053 } else {
1054 write!(f, "<")?;
1055 angle_open = true;
1056 }
1057 let name =
1058 f.db.type_alias_data(projection_pred.projection_ty.associated_ty)
1059 .name
1060 .clone();
1061 write!(f, "{} = ", name)?;
1062 projection_pred.ty.hir_fmt(f)?;
1063 }
1064 GenericPredicate::Error => {
1065 if angle_open {
1066 // impl Trait<X, {error}>
1067 write!(f, ", ")?;
1068 } else if !first {
1069 // impl Trait + {error}
1070 write!(f, " + ")?;
1071 }
1072 p.hir_fmt(f)?;
1073 }
1074 }
1075 first = false;
1076 }
1077 if angle_open {
1078 write!(f, ">")?;
1079 }
1080 } 1061 }
1081 Ty::Unknown => write!(f, "{{unknown}}")?, 1062 Ty::Unknown => write!(f, "{{unknown}}")?,
1082 Ty::Infer(..) => write!(f, "_")?, 1063 Ty::Infer(..) => write!(f, "_")?,
@@ -1085,6 +1066,71 @@ impl HirDisplay for Ty {
1085 } 1066 }
1086} 1067}
1087 1068
1069fn write_bounds_like_dyn_trait(
1070 predicates: &[GenericPredicate],
1071 f: &mut HirFormatter<impl HirDatabase>,
1072) -> fmt::Result {
1073 // Note: This code is written to produce nice results (i.e.
1074 // corresponding to surface Rust) for types that can occur in
1075 // actual Rust. It will have weird results if the predicates
1076 // aren't as expected (i.e. self types = $0, projection
1077 // predicates for a certain trait come after the Implemented
1078 // predicate for that trait).
1079 let mut first = true;
1080 let mut angle_open = false;
1081 for p in predicates.iter() {
1082 match p {
1083 GenericPredicate::Implemented(trait_ref) => {
1084 if angle_open {
1085 write!(f, ">")?;
1086 }
1087 if !first {
1088 write!(f, " + ")?;
1089 }
1090 // We assume that the self type is $0 (i.e. the
1091 // existential) here, which is the only thing that's
1092 // possible in actual Rust, and hence don't print it
1093 write!(f, "{}", f.db.trait_data(trait_ref.trait_).name.clone())?;
1094 if trait_ref.substs.len() > 1 {
1095 write!(f, "<")?;
1096 f.write_joined(&trait_ref.substs[1..], ", ")?;
1097 // there might be assoc type bindings, so we leave the angle brackets open
1098 angle_open = true;
1099 }
1100 }
1101 GenericPredicate::Projection(projection_pred) => {
1102 // in types in actual Rust, these will always come
1103 // after the corresponding Implemented predicate
1104 if angle_open {
1105 write!(f, ", ")?;
1106 } else {
1107 write!(f, "<")?;
1108 angle_open = true;
1109 }
1110 let name =
1111 f.db.type_alias_data(projection_pred.projection_ty.associated_ty).name.clone();
1112 write!(f, "{} = ", name)?;
1113 projection_pred.ty.hir_fmt(f)?;
1114 }
1115 GenericPredicate::Error => {
1116 if angle_open {
1117 // impl Trait<X, {error}>
1118 write!(f, ", ")?;
1119 } else if !first {
1120 // impl Trait + {error}
1121 write!(f, " + ")?;
1122 }
1123 p.hir_fmt(f)?;
1124 }
1125 }
1126 first = false;
1127 }
1128 if angle_open {
1129 write!(f, ">")?;
1130 }
1131 Ok(())
1132}
1133
1088impl TraitRef { 1134impl TraitRef {
1089 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result { 1135 fn hir_fmt_ext(&self, f: &mut HirFormatter<impl HirDatabase>, use_as: bool) -> fmt::Result {
1090 if f.should_truncate() { 1136 if f.should_truncate() {
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs
index 2c2ecee9c..c68c5852b 100644
--- a/crates/ra_hir_ty/src/lower.rs
+++ b/crates/ra_hir_ty/src/lower.rs
@@ -10,12 +10,13 @@ use std::sync::Arc;
10 10
11use hir_def::{ 11use hir_def::{
12 builtin_type::BuiltinType, 12 builtin_type::BuiltinType,
13 generics::WherePredicate, 13 generics::{TypeParamProvenance, WherePredicate, WherePredicateTarget},
14 path::{GenericArg, Path, PathSegment, PathSegments}, 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, 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, TypeParamId, UnionId,
19 VariantId,
19}; 20};
20use ra_arena::map::ArenaMap; 21use ra_arena::map::ArenaMap;
21use ra_db::CrateId; 22use ra_db::CrateId;
@@ -27,63 +28,158 @@ use crate::{
27 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice, 28 all_super_traits, associated_type_by_name_including_super_traits, generics, make_mut_slice,
28 variant_data, 29 variant_data,
29 }, 30 },
30 FnSig, GenericPredicate, ProjectionPredicate, ProjectionTy, Substs, TraitEnvironment, TraitRef, 31 Binders, FnSig, GenericPredicate, PolyFnSig, ProjectionPredicate, ProjectionTy, Substs,
31 Ty, TypeCtor, TypeWalk, 32 TraitEnvironment, TraitRef, Ty, TypeCtor,
32}; 33};
33 34
35#[derive(Debug)]
36pub struct TyLoweringContext<'a, DB: HirDatabase> {
37 pub db: &'a DB,
38 pub resolver: &'a Resolver,
39 /// Note: Conceptually, it's thinkable that we could be in a location where
40 /// some type params should be represented as placeholders, and others
41 /// should be converted to variables. I think in practice, this isn't
42 /// possible currently, so this should be fine for now.
43 pub type_param_mode: TypeParamLoweringMode,
44 pub impl_trait_mode: ImplTraitLoweringMode,
45 pub impl_trait_counter: std::cell::Cell<u16>,
46}
47
48impl<'a, DB: HirDatabase> TyLoweringContext<'a, DB> {
49 pub fn new(db: &'a DB, resolver: &'a Resolver) -> Self {
50 let impl_trait_counter = std::cell::Cell::new(0);
51 let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
52 let type_param_mode = TypeParamLoweringMode::Placeholder;
53 Self { db, resolver, impl_trait_mode, impl_trait_counter, type_param_mode }
54 }
55
56 pub fn with_impl_trait_mode(self, impl_trait_mode: ImplTraitLoweringMode) -> Self {
57 Self { impl_trait_mode, ..self }
58 }
59
60 pub fn with_type_param_mode(self, type_param_mode: TypeParamLoweringMode) -> Self {
61 Self { type_param_mode, ..self }
62 }
63}
64
65#[derive(Copy, Clone, Debug, PartialEq, Eq)]
66pub enum ImplTraitLoweringMode {
67 /// `impl Trait` gets lowered into an opaque type that doesn't unify with
68 /// anything except itself. This is used in places where values flow 'out',
69 /// i.e. for arguments of the function we're currently checking, and return
70 /// types of functions we're calling.
71 Opaque,
72 /// `impl Trait` gets lowered into a type variable. Used for argument
73 /// position impl Trait when inside the respective function, since it allows
74 /// us to support that without Chalk.
75 Param,
76 /// `impl Trait` gets lowered into a variable that can unify with some
77 /// type. This is used in places where values flow 'in', i.e. for arguments
78 /// of functions we're calling, and the return type of the function we're
79 /// currently checking.
80 Variable,
81 /// `impl Trait` is disallowed and will be an error.
82 Disallowed,
83}
84
85#[derive(Copy, Clone, Debug, PartialEq, Eq)]
86pub enum TypeParamLoweringMode {
87 Placeholder,
88 Variable,
89}
90
34impl Ty { 91impl Ty {
35 pub fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { 92 pub fn from_hir(ctx: &TyLoweringContext<'_, impl HirDatabase>, type_ref: &TypeRef) -> Self {
36 match type_ref { 93 match type_ref {
37 TypeRef::Never => Ty::simple(TypeCtor::Never), 94 TypeRef::Never => Ty::simple(TypeCtor::Never),
38 TypeRef::Tuple(inner) => { 95 TypeRef::Tuple(inner) => {
39 let inner_tys: