aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/base_db/src/fixture.rs68
-rw-r--r--crates/base_db/src/input.rs1
-rw-r--r--crates/flycheck/Cargo.toml1
-rw-r--r--crates/flycheck/src/lib.rs68
-rw-r--r--crates/hir/Cargo.toml2
-rw-r--r--crates/hir/src/display.rs4
-rw-r--r--crates/hir/src/lib.rs121
-rw-r--r--crates/hir/src/semantics.rs11
-rw-r--r--crates/hir/src/source_analyzer.rs44
-rw-r--r--crates/hir_def/src/attr.rs196
-rw-r--r--crates/hir_def/src/body.rs26
-rw-r--r--crates/hir_def/src/body/lower.rs105
-rw-r--r--crates/hir_def/src/body/tests.rs12
-rw-r--r--crates/hir_def/src/body/tests/block.rs24
-rw-r--r--crates/hir_def/src/child_by_source.rs4
-rw-r--r--crates/hir_def/src/db.rs18
-rw-r--r--crates/hir_def/src/diagnostics.rs5
-rw-r--r--crates/hir_def/src/expr.rs19
-rw-r--r--crates/hir_def/src/find_path.rs667
-rw-r--r--crates/hir_def/src/generics.rs62
-rw-r--r--crates/hir_def/src/intern.rs27
-rw-r--r--crates/hir_def/src/item_scope.rs13
-rw-r--r--crates/hir_def/src/item_tree.rs78
-rw-r--r--crates/hir_def/src/item_tree/lower.rs11
-rw-r--r--crates/hir_def/src/lib.rs76
-rw-r--r--crates/hir_def/src/nameres.rs55
-rw-r--r--crates/hir_def/src/nameres/collector.rs80
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs59
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs6
-rw-r--r--crates/hir_def/src/path.rs15
-rw-r--r--crates/hir_def/src/path/lower.rs19
-rw-r--r--crates/hir_def/src/resolver.rs3
-rw-r--r--crates/hir_def/src/test_db.rs51
-rw-r--r--crates/hir_def/src/type_ref.rs18
-rw-r--r--crates/hir_def/src/visibility.rs16
-rw-r--r--crates/hir_expand/src/builtin_derive.rs10
-rw-r--r--crates/hir_expand/src/builtin_macro.rs19
-rw-r--r--crates/hir_expand/src/db.rs2
-rw-r--r--crates/hir_expand/src/eager.rs24
-rw-r--r--crates/hir_expand/src/lib.rs21
-rw-r--r--crates/hir_expand/src/name.rs1
-rw-r--r--crates/hir_ty/Cargo.toml8
-rw-r--r--crates/hir_ty/src/autoderef.rs68
-rw-r--r--crates/hir_ty/src/builder.rs30
-rw-r--r--crates/hir_ty/src/chalk_cast.rs73
-rw-r--r--crates/hir_ty/src/chalk_db.rs (renamed from crates/hir_ty/src/traits/chalk.rs)262
-rw-r--r--crates/hir_ty/src/chalk_ext.rs294
-rw-r--r--crates/hir_ty/src/db.rs87
-rw-r--r--crates/hir_ty/src/diagnostics.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/decl_check.rs169
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs14
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs4
-rw-r--r--crates/hir_ty/src/display.rs275
-rw-r--r--crates/hir_ty/src/infer.rs165
-rw-r--r--crates/hir_ty/src/infer/coerce.rs29
-rw-r--r--crates/hir_ty/src/infer/expr.rs91
-rw-r--r--crates/hir_ty/src/infer/pat.rs59
-rw-r--r--crates/hir_ty/src/infer/path.rs18
-rw-r--r--crates/hir_ty/src/infer/unify.rs218
-rw-r--r--crates/hir_ty/src/interner.rs (renamed from crates/hir_ty/src/traits/chalk/interner.rs)170
-rw-r--r--crates/hir_ty/src/lib.rs1290
-rw-r--r--crates/hir_ty/src/lower.rs300
-rw-r--r--crates/hir_ty/src/mapping.rs154
-rw-r--r--crates/hir_ty/src/method_resolution.rs329
-rw-r--r--crates/hir_ty/src/op.rs66
-rw-r--r--crates/hir_ty/src/primitive.rs5
-rw-r--r--crates/hir_ty/src/tests/macros.rs201
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs57
-rw-r--r--crates/hir_ty/src/tests/patterns.rs28
-rw-r--r--crates/hir_ty/src/tests/regression.rs38
-rw-r--r--crates/hir_ty/src/tests/simple.rs51
-rw-r--r--crates/hir_ty/src/tests/traits.rs1467
-rw-r--r--crates/hir_ty/src/tls.rs (renamed from crates/hir_ty/src/traits/chalk/tls.rs)14
-rw-r--r--crates/hir_ty/src/traits.rs140
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs575
-rw-r--r--crates/hir_ty/src/utils.rs53
-rw-r--r--crates/hir_ty/src/walk.rs150
-rw-r--r--crates/ide/src/diagnostics.rs157
-rw-r--r--crates/ide/src/diagnostics/field_shorthand.rs8
-rw-r--r--crates/ide/src/diagnostics/fixes.rs60
-rw-r--r--crates/ide/src/diagnostics/unlinked_file.rs14
-rw-r--r--crates/ide/src/doc_links.rs190
-rw-r--r--crates/ide/src/expand_macro.rs67
-rw-r--r--crates/ide/src/folding_ranges.rs17
-rw-r--r--crates/ide/src/goto_definition.rs82
-rw-r--r--crates/ide/src/hover.rs42
-rw-r--r--crates/ide/src/lib.rs42
-rw-r--r--crates/ide/src/move_item.rs100
-rw-r--r--crates/ide/src/prime_caches.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs73
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs104
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs24
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html2
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs46
-rw-r--r--crates/ide/src/typing.rs368
-rw-r--r--crates/ide/src/typing/on_enter.rs230
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs33
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs276
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs73
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs370
-rw-r--r--crates/ide_assists/src/handlers/flip_comma.rs18
-rw-r--r--crates/ide_assists/src/handlers/generate_deref.rs227
-rw-r--r--crates/ide_assists/src/handlers/inline_local_variable.rs223
-rw-r--r--crates/ide_assists/src/handlers/introduce_named_lifetime.rs112
-rw-r--r--crates/ide_assists/src/handlers/remove_dbg.rs105
-rw-r--r--crates/ide_assists/src/handlers/reorder_fields.rs89
-rw-r--r--crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs108
-rw-r--r--crates/ide_assists/src/lib.rs4
-rw-r--r--crates/ide_assists/src/tests.rs7
-rw-r--r--crates/ide_assists/src/tests/generated.rs27
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs116
-rw-r--r--crates/ide_completion/src/item.rs2
-rw-r--r--crates/ide_completion/src/lib.rs28
-rw-r--r--crates/ide_db/src/apply_change.rs6
-rw-r--r--crates/ide_db/src/call_info.rs10
-rw-r--r--crates/ide_db/src/call_info/tests.rs27
-rw-r--r--crates/ide_db/src/helpers.rs5
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs8
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs22
-rw-r--r--crates/ide_db/src/helpers/rust_doc.rs34
-rw-r--r--crates/mbe/src/syntax_bridge.rs2
-rw-r--r--crates/mbe/src/tests/expand.rs42
-rw-r--r--crates/parser/src/grammar.rs37
-rw-r--r--crates/parser/src/grammar/attributes.rs28
-rw-r--r--crates/parser/src/grammar/patterns.rs6
-rw-r--r--crates/parser/src/grammar/types.rs10
-rw-r--r--crates/paths/src/lib.rs7
-rw-r--r--crates/proc_macro_api/Cargo.toml7
-rw-r--r--crates/proc_macro_api/src/lib.rs1
-rw-r--r--crates/project_model/src/build_data.rs294
-rw-r--r--crates/project_model/src/workspace.rs10
-rw-r--r--crates/rust-analyzer/Cargo.toml2
-rw-r--r--crates/rust-analyzer/build.rs3
-rw-r--r--crates/rust-analyzer/src/benchmarks.rs7
-rw-r--r--crates/rust-analyzer/src/bin/flags.rs3
-rw-r--r--crates/rust-analyzer/src/bin/main.rs16
-rw-r--r--crates/rust-analyzer/src/bin/rustc_wrapper.rs46
-rw-r--r--crates/rust-analyzer/src/caps.rs2
-rw-r--r--crates/rust-analyzer/src/cli/analysis_stats.rs63
-rw-r--r--crates/rust-analyzer/src/cli/diagnostics.rs6
-rw-r--r--crates/rust-analyzer/src/cli/load_cargo.rs10
-rw-r--r--crates/rust-analyzer/src/cli/ssr.rs9
-rw-r--r--crates/rust-analyzer/src/config.rs43
-rw-r--r--crates/rust-analyzer/src/diagnostics.rs1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt1
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs57
-rw-r--r--crates/rust-analyzer/src/from_proto.rs30
-rw-r--r--crates/rust-analyzer/src/global_state.rs63
-rw-r--r--crates/rust-analyzer/src/handlers.rs130
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs38
-rw-r--r--crates/rust-analyzer/src/lsp_utils.rs24
-rw-r--r--crates/rust-analyzer/src/main_loop.rs110
-rw-r--r--crates/rust-analyzer/src/markdown.rs22
-rw-r--r--crates/rust-analyzer/src/op_queue.rs38
-rw-r--r--crates/rust-analyzer/src/reload.rs215
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs5
-rw-r--r--crates/rust-analyzer/src/to_proto.rs185
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/main.rs2
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs32
-rw-r--r--crates/stdx/Cargo.toml5
-rw-r--r--crates/stdx/src/lib.rs31
-rw-r--r--crates/stdx/src/process.rs238
-rw-r--r--crates/syntax/Cargo.toml6
-rw-r--r--crates/syntax/src/ast/edit_in_place.rs153
-rw-r--r--crates/syntax/src/ast/make.rs26
-rw-r--r--crates/syntax/src/ast/node_ext.rs12
-rw-r--r--crates/syntax/src/ted.rs7
-rw-r--r--crates/syntax/src/validation/block.rs2
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast48
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast58
-rw-r--r--crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs1
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rast218
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_attrs.rs (renamed from crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs)6
-rw-r--r--crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast178
-rw-r--r--crates/test_utils/src/assert_linear.rs112
-rw-r--r--crates/test_utils/src/bench_fixture.rs3
-rw-r--r--crates/test_utils/src/fixture.rs62
-rw-r--r--crates/test_utils/src/lib.rs3
-rw-r--r--crates/vfs/Cargo.toml1
-rw-r--r--crates/vfs/src/path_interner.rs29
186 files changed, 9452 insertions, 5947 deletions
diff --git a/crates/base_db/src/fixture.rs b/crates/base_db/src/fixture.rs
index 8d4641355..0132565e4 100644
--- a/crates/base_db/src/fixture.rs
+++ b/crates/base_db/src/fixture.rs
@@ -1,62 +1,4 @@
1//! Fixtures are strings containing rust source code with optional metadata. 1//! A set of high-level utility fixture methods to use in tests.
2//! A fixture without metadata is parsed into a single source file.
3//! Use this to test functionality local to one file.
4//!
5//! Simple Example:
6//! ```
7//! r#"
8//! fn main() {
9//! println!("Hello World")
10//! }
11//! "#
12//! ```
13//!
14//! Metadata can be added to a fixture after a `//-` comment.
15//! The basic form is specifying filenames,
16//! which is also how to define multiple files in a single test fixture
17//!
18//! Example using two files in the same crate:
19//! ```
20//! "
21//! //- /main.rs
22//! mod foo;
23//! fn main() {
24//! foo::bar();
25//! }
26//!
27//! //- /foo.rs
28//! pub fn bar() {}
29//! "
30//! ```
31//!
32//! Example using two crates with one file each, with one crate depending on the other:
33//! ```
34//! r#"
35//! //- /main.rs crate:a deps:b
36//! fn main() {
37//! b::foo();
38//! }
39//! //- /lib.rs crate:b
40//! pub fn b() {
41//! println!("Hello World")
42//! }
43//! "#
44//! ```
45//!
46//! Metadata allows specifying all settings and variables
47//! that are available in a real rust project:
48//! - crate names via `crate:cratename`
49//! - dependencies via `deps:dep1,dep2`
50//! - configuration settings via `cfg:dbg=false,opt_level=2`
51//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
52//!
53//! Example using all available metadata:
54//! ```
55//! "
56//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
57//! fn insert_source_code_here() {}
58//! "
59//! ```
60use std::{mem, str::FromStr, sync::Arc}; 2use std::{mem, str::FromStr, sync::Arc};
61 3
62use cfg::CfgOptions; 4use cfg::CfgOptions;
@@ -93,7 +35,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
93 fn with_position(ra_fixture: &str) -> (Self, FilePosition) { 35 fn with_position(ra_fixture: &str) -> (Self, FilePosition) {
94 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); 36 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
95 let offset = match range_or_offset { 37 let offset = match range_or_offset {
96 RangeOrOffset::Range(_) => panic!(), 38 RangeOrOffset::Range(_) => panic!("Expected a cursor position, got a range instead"),
97 RangeOrOffset::Offset(it) => it, 39 RangeOrOffset::Offset(it) => it,
98 }; 40 };
99 (db, FilePosition { file_id, offset }) 41 (db, FilePosition { file_id, offset })
@@ -103,7 +45,7 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
103 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture); 45 let (db, file_id, range_or_offset) = Self::with_range_or_offset(ra_fixture);
104 let range = match range_or_offset { 46 let range = match range_or_offset {
105 RangeOrOffset::Range(it) => it, 47 RangeOrOffset::Range(it) => it,
106 RangeOrOffset::Offset(_) => panic!(), 48 RangeOrOffset::Offset(_) => panic!("Expected a cursor range, got a position instead"),
107 }; 49 };
108 (db, FileRange { file_id, range }) 50 (db, FileRange { file_id, range })
109 } 51 }
@@ -112,7 +54,9 @@ pub trait WithFixture: Default + SourceDatabaseExt + 'static {
112 let fixture = ChangeFixture::parse(ra_fixture); 54 let fixture = ChangeFixture::parse(ra_fixture);
113 let mut db = Self::default(); 55 let mut db = Self::default();
114 fixture.change.apply(&mut db); 56 fixture.change.apply(&mut db);
115 let (file_id, range_or_offset) = fixture.file_position.unwrap(); 57 let (file_id, range_or_offset) = fixture
58 .file_position
59 .expect("Could not find file position in fixture. Did you forget to add an `$0`?");
116 (db, file_id, range_or_offset) 60 (db, file_id, range_or_offset)
117 } 61 }
118 62
diff --git a/crates/base_db/src/input.rs b/crates/base_db/src/input.rs
index 07628935f..0ef77ef5d 100644
--- a/crates/base_db/src/input.rs
+++ b/crates/base_db/src/input.rs
@@ -239,6 +239,7 @@ impl CrateGraph {
239 name: CrateName, 239 name: CrateName,
240 to: CrateId, 240 to: CrateId,
241 ) -> Result<(), CyclicDependenciesError> { 241 ) -> Result<(), CyclicDependenciesError> {
242 let _p = profile::span("add_dep");
242 if self.dfs_find(from, to, &mut FxHashSet::default()) { 243 if self.dfs_find(from, to, &mut FxHashSet::default()) {
243 return Err(CyclicDependenciesError { 244 return Err(CyclicDependenciesError {
244 from: (from, self[from].display_name.clone()), 245 from: (from, self[from].display_name.clone()),
diff --git a/crates/flycheck/Cargo.toml b/crates/flycheck/Cargo.toml
index 2a1a21b28..18b9ce7df 100644
--- a/crates/flycheck/Cargo.toml
+++ b/crates/flycheck/Cargo.toml
@@ -13,6 +13,7 @@ doctest = false
13crossbeam-channel = "0.5.0" 13crossbeam-channel = "0.5.0"
14log = "0.4.8" 14log = "0.4.8"
15cargo_metadata = "0.13" 15cargo_metadata = "0.13"
16serde = { version = "1.0.106", features = ["derive"] }
16serde_json = "1.0.48" 17serde_json = "1.0.48"
17jod-thread = "0.1.1" 18jod-thread = "0.1.1"
18 19
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index e2a59497a..1682d8bde 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -4,13 +4,14 @@
4 4
5use std::{ 5use std::{
6 fmt, 6 fmt,
7 io::{self, BufReader}, 7 io::{self, BufRead, BufReader},
8 path::PathBuf, 8 path::PathBuf,
9 process::{self, Command, Stdio}, 9 process::{self, Command, Stdio},
10 time::Duration, 10 time::Duration,
11}; 11};
12 12
13use crossbeam_channel::{never, select, unbounded, Receiver, Sender}; 13use crossbeam_channel::{never, select, unbounded, Receiver, Sender};
14use serde::Deserialize;
14use stdx::JodChild; 15use stdx::JodChild;
15 16
16pub use cargo_metadata::diagnostic::{ 17pub use cargo_metadata::diagnostic::{
@@ -128,7 +129,7 @@ struct FlycheckActor {
128 129
129enum Event { 130enum Event {
130 Restart(Restart), 131 Restart(Restart),
131 CheckEvent(Option<cargo_metadata::Message>), 132 CheckEvent(Option<CargoMessage>),
132} 133}
133 134
134impl FlycheckActor { 135impl FlycheckActor {
@@ -180,21 +181,16 @@ impl FlycheckActor {
180 self.progress(Progress::DidFinish(res)); 181 self.progress(Progress::DidFinish(res));
181 } 182 }
182 Event::CheckEvent(Some(message)) => match message { 183 Event::CheckEvent(Some(message)) => match message {
183 cargo_metadata::Message::CompilerArtifact(msg) => { 184 CargoMessage::CompilerArtifact(msg) => {
184 self.progress(Progress::DidCheckCrate(msg.target.name)); 185 self.progress(Progress::DidCheckCrate(msg.target.name));
185 } 186 }
186 187
187 cargo_metadata::Message::CompilerMessage(msg) => { 188 CargoMessage::Diagnostic(msg) => {
188 self.send(Message::AddDiagnostic { 189 self.send(Message::AddDiagnostic {
189 workspace_root: self.workspace_root.clone(), 190 workspace_root: self.workspace_root.clone(),
190 diagnostic: msg.message, 191 diagnostic: msg,
191 }); 192 });
192 } 193 }
193
194 cargo_metadata::Message::BuildScriptExecuted(_)
195 | cargo_metadata::Message::BuildFinished(_)
196 | cargo_metadata::Message::TextLine(_)
197 | _ => {}
198 }, 194 },
199 } 195 }
200 } 196 }
@@ -261,7 +257,7 @@ struct CargoHandle {
261 child: JodChild, 257 child: JodChild,
262 #[allow(unused)] 258 #[allow(unused)]
263 thread: jod_thread::JoinHandle<io::Result<bool>>, 259 thread: jod_thread::JoinHandle<io::Result<bool>>,
264 receiver: Receiver<cargo_metadata::Message>, 260 receiver: Receiver<CargoMessage>,
265} 261}
266 262
267impl CargoHandle { 263impl CargoHandle {
@@ -294,14 +290,11 @@ impl CargoHandle {
294 290
295struct CargoActor { 291struct CargoActor {
296 child_stdout: process::ChildStdout, 292 child_stdout: process::ChildStdout,
297 sender: Sender<cargo_metadata::Message>, 293 sender: Sender<CargoMessage>,
298} 294}
299 295
300impl CargoActor { 296impl CargoActor {
301 fn new( 297 fn new(child_stdout: process::ChildStdout, sender: Sender<CargoMessage>) -> CargoActor {
302 child_stdout: process::ChildStdout,
303 sender: Sender<cargo_metadata::Message>,
304 ) -> CargoActor {
305 CargoActor { child_stdout, sender } 298 CargoActor { child_stdout, sender }
306 } 299 }
307 fn run(self) -> io::Result<bool> { 300 fn run(self) -> io::Result<bool> {
@@ -315,7 +308,7 @@ impl CargoActor {
315 // erroneus output. 308 // erroneus output.
316 let stdout = BufReader::new(self.child_stdout); 309 let stdout = BufReader::new(self.child_stdout);
317 let mut read_at_least_one_message = false; 310 let mut read_at_least_one_message = false;
318 for message in cargo_metadata::Message::parse_stream(stdout) { 311 for message in stdout.lines() {
319 let message = match message { 312 let message = match message {
320 Ok(message) => message, 313 Ok(message) => message,
321 Err(err) => { 314 Err(err) => {
@@ -326,13 +319,44 @@ impl CargoActor {
326 319
327 read_at_least_one_message = true; 320 read_at_least_one_message = true;
328 321
329 // Skip certain kinds of messages to only spend time on what's useful 322 // Try to deserialize a message from Cargo or Rustc.
330 match &message { 323 let mut deserializer = serde_json::Deserializer::from_str(&message);
331 cargo_metadata::Message::CompilerArtifact(artifact) if artifact.fresh => (), 324 deserializer.disable_recursion_limit();
332 cargo_metadata::Message::BuildScriptExecuted(_) => (), 325 if let Ok(message) = JsonMessage::deserialize(&mut deserializer) {
333 _ => self.sender.send(message).unwrap(), 326 match message {
327 // Skip certain kinds of messages to only spend time on what's useful
328 JsonMessage::Cargo(message) => match message {
329 cargo_metadata::Message::CompilerArtifact(artifact) if !artifact.fresh => {
330 self.sender.send(CargoMessage::CompilerArtifact(artifact)).unwrap()
331 }
332 cargo_metadata::Message::CompilerMessage(msg) => {
333 self.sender.send(CargoMessage::Diagnostic(msg.message)).unwrap()
334 }
335
336 cargo_metadata::Message::CompilerArtifact(_)
337 | cargo_metadata::Message::BuildScriptExecuted(_)
338 | cargo_metadata::Message::BuildFinished(_)
339 | cargo_metadata::Message::TextLine(_)
340 | _ => (),
341 },
342 JsonMessage::Rustc(message) => {
343 self.sender.send(CargoMessage::Diagnostic(message)).unwrap()
344 }
345 }
334 } 346 }
335 } 347 }
336 Ok(read_at_least_one_message) 348 Ok(read_at_least_one_message)
337 } 349 }
338} 350}
351
352enum CargoMessage {
353 CompilerArtifact(cargo_metadata::Artifact),
354 Diagnostic(Diagnostic),
355}
356
357#[derive(Deserialize)]
358#[serde(untagged)]
359enum JsonMessage {
360 Cargo(cargo_metadata::Message),
361 Rustc(Diagnostic),
362}
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index 2ef5bcbc9..9e329656f 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
13log = "0.4.8" 13log = "0.4.8"
14rustc-hash = "1.1.0" 14rustc-hash = "1.1.0"
15either = "1.5.3" 15either = "1.5.3"
16arrayvec = "0.6" 16arrayvec = "0.7"
17itertools = "0.10.0" 17itertools = "0.10.0"
18smallvec = "1.4.0" 18smallvec = "1.4.0"
19 19
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 993772aac..01a4d205f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -9,6 +9,7 @@ use hir_ty::display::{
9 write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError, 9 write_bounds_like_dyn_trait_with_prefix, write_visibility, HirDisplay, HirDisplayError,
10 HirFormatter, 10 HirFormatter,
11}; 11};
12use hir_ty::Interner;
12use syntax::ast::{self, NameOwner}; 13use syntax::ast::{self, NameOwner};
13 14
14use crate::{ 15use crate::{
@@ -235,7 +236,8 @@ impl HirDisplay for TypeParam {
235 write!(f, "{}", self.name(f.db))?; 236 write!(f, "{}", self.name(f.db))?;
236 let bounds = f.db.generic_predicates_for_param(self.id); 237 let bounds = f.db.generic_predicates_for_param(self.id);
237 let substs = TyBuilder::type_params_subst(f.db, self.id.parent); 238 let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
238 let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>(); 239 let predicates =
240 bounds.iter().cloned().map(|b| b.substitute(&Interner, &substs)).collect::<Vec<_>>();
239 if !(predicates.is_empty() || f.omit_verbose_types()) { 241 if !(predicates.is_empty() || f.omit_verbose_types()) {
240 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; 242 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
241 } 243 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 19901ed33..0acfa582a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -53,12 +53,14 @@ use hir_def::{
53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
54use hir_ty::{ 54use hir_ty::{
55 autoderef, could_unify, 55 autoderef, could_unify,
56 method_resolution::{self, TyFingerprint}, 56 method_resolution::{self, def_crates, TyFingerprint},
57 primitive::UintTy, 57 primitive::UintTy,
58 traits::{FnTrait, Solution, SolutionVariables}, 58 subst_prefix,
59 traits::FnTrait,
59 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, 60 AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
60 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Substitution, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
61 TraitEnvironment, Ty, TyBuilder, TyDefId, TyKind, TyVariableKind, WhereClause, 62 TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
63 WhereClause,
62}; 64};
63use itertools::Itertools; 65use itertools::Itertools;
64use rustc_hash::FxHashSet; 66use rustc_hash::FxHashSet;
@@ -515,7 +517,7 @@ impl Field {
515 VariantDef::Variant(it) => it.parent.id.into(), 517 VariantDef::Variant(it) => it.parent.id.into(),
516 }; 518 };
517 let substs = TyBuilder::type_params_subst(db, generic_def_id); 519 let substs = TyBuilder::type_params_subst(db, generic_def_id);
518 let ty = db.field_types(var_id)[self.id].clone().subst(&substs); 520 let ty = db.field_types(var_id)[self.id].clone().substitute(&Interner, &substs);
519 Type::new(db, self.parent.module(db).id.krate(), var_id, ty) 521 Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
520 } 522 }
521 523
@@ -701,7 +703,7 @@ impl_from!(Struct, Union, Enum for Adt);
701impl Adt { 703impl Adt {
702 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { 704 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
703 let subst = db.generic_defaults(self.into()); 705 let subst = db.generic_defaults(self.into());
704 subst.iter().any(|ty| ty.value.is_unknown()) 706 subst.iter().any(|ty| ty.skip_binders().is_unknown())
705 } 707 }
706 708
707 /// Turns this ADT into a type. Any type parameters of the ADT will be 709 /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -1088,7 +1090,7 @@ pub struct TypeAlias {
1088impl TypeAlias { 1090impl TypeAlias {
1089 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool { 1091 pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
1090 let subst = db.generic_defaults(self.id.into()); 1092 let subst = db.generic_defaults(self.id.into());
1091 subst.iter().any(|ty| ty.value.is_unknown()) 1093 subst.iter().any(|ty| ty.skip_binders().is_unknown())
1092 } 1094 }
1093 1095
1094 pub fn module(self, db: &dyn HirDatabase) -> Module { 1096 pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -1502,7 +1504,7 @@ impl TypeParam {
1502 let krate = self.id.parent.module(db.upcast()).krate(); 1504 let krate = self.id.parent.module(db.upcast()).krate();
1503 let ty = params.get(local_idx)?.clone(); 1505 let ty = params.get(local_idx)?.clone();
1504 let subst = TyBuilder::type_params_subst(db, self.id.parent); 1506 let subst = TyBuilder::type_params_subst(db, self.id.parent);
1505 let ty = ty.subst(&subst.prefix(local_idx)); 1507 let ty = ty.substitute(&Interner, &subst_prefix(&subst, local_idx));
1506 Some(Type::new_with_resolver_inner(db, krate, &resolver, ty)) 1508 Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
1507 } 1509 }
1508} 1510}
@@ -1567,7 +1569,7 @@ impl Impl {
1567 } 1569 }
1568 1570
1569 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> { 1571 pub fn all_for_type(db: &dyn HirDatabase, Type { krate, ty, .. }: Type) -> Vec<Impl> {
1570 let def_crates = match ty.def_crates(db, krate) { 1572 let def_crates = match def_crates(db, &ty, krate) {
1571 Some(def_crates) => def_crates, 1573 Some(def_crates) => def_crates,
1572 None => return Vec::new(), 1574 None => return Vec::new(),
1573 }; 1575 };
@@ -1578,11 +1580,24 @@ impl Impl {
1578 ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty)) 1580 ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
1579 }; 1581 };
1580 1582
1583 let fp = TyFingerprint::for_inherent_impl(&ty);
1584 let fp = if let Some(fp) = fp {
1585 fp
1586 } else {
1587 return Vec::new();
1588 };
1589
1581 let mut all = Vec::new(); 1590 let mut all = Vec::new();
1582 def_crates.iter().for_each(|&id| { 1591 def_crates.iter().for_each(|&id| {
1583 all.extend(db.inherent_impls_in_crate(id).all_impls().map(Self::from).filter(filter)) 1592 all.extend(
1593 db.inherent_impls_in_crate(id)
1594 .for_self_ty(&ty)
1595 .into_iter()
1596 .cloned()
1597 .map(Self::from)
1598 .filter(filter),
1599 )
1584 }); 1600 });
1585 let fp = TyFingerprint::for_impl(&ty);
1586 for id in def_crates 1601 for id in def_crates
1587 .iter() 1602 .iter()
1588 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db)) 1603 .flat_map(|&id| Crate { id }.transitive_reverse_dependencies(db))
@@ -1590,13 +1605,12 @@ impl Impl {
1590 .chain(def_crates.iter().copied()) 1605 .chain(def_crates.iter().copied())
1591 .unique() 1606 .unique()
1592 { 1607 {
1593 match fp { 1608 all.extend(
1594 Some(fp) => all.extend( 1609 db.trait_impls_in_crate(id)
1595 db.trait_impls_in_crate(id).for_self_ty(fp).map(Self::from).filter(filter), 1610 .for_self_ty_without_blanket_impls(fp)
1596 ), 1611 .map(Self::from)
1597 None => all 1612 .filter(filter),
1598 .extend(db.trait_impls_in_crate(id).all_impls().map(Self::from).filter(filter)), 1613 );
1599 }
1600 } 1614 }
1601 all 1615 all
1602 } 1616 }
@@ -1789,7 +1803,7 @@ impl Type {
1789 .build(); 1803 .build();
1790 1804
1791 let goal = Canonical { 1805 let goal = Canonical {
1792 value: hir_ty::InEnvironment::new(self.env.env.clone(), trait_ref.cast(&Interner)), 1806 value: hir_ty::InEnvironment::new(&self.env.env, trait_ref.cast(&Interner)),
1793 binders: CanonicalVarKinds::empty(&Interner), 1807 binders: CanonicalVarKinds::empty(&Interner),
1794 }; 1808 };
1795 1809
@@ -1806,9 +1820,9 @@ impl Type {
1806 .push(self.ty.clone()) 1820 .push(self.ty.clone())
1807 .fill(args.iter().map(|t| t.ty.clone())) 1821 .fill(args.iter().map(|t| t.ty.clone()))
1808 .build(); 1822 .build();
1809 let goal = Canonical::new( 1823 let goal = hir_ty::make_canonical(
1810 InEnvironment::new( 1824 InEnvironment::new(
1811 self.env.env.clone(), 1825 &self.env.env,
1812 AliasEq { 1826 AliasEq {
1813 alias: AliasTy::Projection(projection), 1827 alias: AliasTy::Projection(projection),
1814 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 1828 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
@@ -1820,9 +1834,10 @@ impl Type {
1820 ); 1834 );
1821 1835
1822 match db.trait_solve(self.krate, goal)? { 1836 match db.trait_solve(self.krate, goal)? {
1823 Solution::Unique(SolutionVariables(subst)) => subst 1837 Solution::Unique(s) => s
1824 .value 1838 .value
1825 .interned(&Interner) 1839 .subst
1840 .as_slice(&Interner)
1826 .first() 1841 .first()
1827 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())), 1842 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
1828 Solution::Ambig(_) => None, 1843 Solution::Ambig(_) => None,
@@ -1875,7 +1890,7 @@ impl Type {
1875 1890
1876 fn go(ty: &Ty) -> bool { 1891 fn go(ty: &Ty) -> bool {
1877 match ty.kind(&Interner) { 1892 match ty.kind(&Interner) {
1878 TyKind::Unknown => true, 1893 TyKind::Error => true,
1879 1894
1880 TyKind::Adt(_, substs) 1895 TyKind::Adt(_, substs)
1881 | TyKind::AssociatedType(_, substs) 1896 | TyKind::AssociatedType(_, substs)
@@ -1886,9 +1901,10 @@ impl Type {
1886 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go) 1901 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
1887 } 1902 }
1888 1903
1889 TyKind::Array(ty) | TyKind::Slice(ty) | TyKind::Raw(_, ty) | TyKind::Ref(_, ty) => { 1904 TyKind::Array(ty, _)
1890 go(ty) 1905 | TyKind::Slice(ty)
1891 } 1906 | TyKind::Raw(_, ty)
1907 | TyKind::Ref(_, _, ty) => go(ty),
1892 1908
1893 TyKind::Scalar(_) 1909 TyKind::Scalar(_)
1894 | TyKind::Str 1910 | TyKind::Str
@@ -1899,7 +1915,9 @@ impl Type {
1899 | TyKind::Dyn(_) 1915 | TyKind::Dyn(_)
1900 | TyKind::Function(_) 1916 | TyKind::Function(_)
1901 | TyKind::Alias(_) 1917 | TyKind::Alias(_)
1902 | TyKind::ForeignType(_) => false, 1918 | TyKind::Foreign(_)
1919 | TyKind::Generator(..)
1920 | TyKind::GeneratorWitness(..) => false,
1903 } 1921 }
1904 } 1922 }
1905 } 1923 }
@@ -1915,7 +1933,7 @@ impl Type {
1915 .iter() 1933 .iter()
1916 .map(|(local_id, ty)| { 1934 .map(|(local_id, ty)| {
1917 let def = Field { parent: variant_id.into(), id: local_id }; 1935 let def = Field { parent: variant_id.into(), id: local_id };
1918 let ty = ty.clone().subst(substs); 1936 let ty = ty.clone().substitute(&Interner, substs);
1919 (def, self.derived(ty)) 1937 (def, self.derived(ty))
1920 }) 1938 })
1921 .collect() 1939 .collect()
@@ -1952,7 +1970,7 @@ impl Type {
1952 krate: Crate, 1970 krate: Crate,
1953 mut callback: impl FnMut(AssocItem) -> Option<T>, 1971 mut callback: impl FnMut(AssocItem) -> Option<T>,
1954 ) -> Option<T> { 1972 ) -> Option<T> {
1955 for krate in self.ty.def_crates(db, krate.id)? { 1973 for krate in def_crates(db, &self.ty, krate.id)? {
1956 let impls = db.inherent_impls_in_crate(krate); 1974 let impls = db.inherent_impls_in_crate(krate);
1957 1975
1958 for impl_def in impls.for_self_ty(&self.ty) { 1976 for impl_def in impls.for_self_ty(&self.ty) {
@@ -1969,9 +1987,9 @@ impl Type {
1969 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { 1987 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ {
1970 self.ty 1988 self.ty
1971 .strip_references() 1989 .strip_references()
1972 .substs() 1990 .as_adt()
1973 .into_iter() 1991 .into_iter()
1974 .flat_map(|substs| substs.iter(&Interner)) 1992 .flat_map(|(_, substs)| substs.iter(&Interner))
1975 .filter_map(|arg| arg.ty(&Interner).cloned()) 1993 .filter_map(|arg| arg.ty(&Interner).cloned())
1976 .map(move |ty| self.derived(ty)) 1994 .map(move |ty| self.derived(ty))
1977 } 1995 }
@@ -2048,6 +2066,18 @@ impl Type {
2048 self.ty.dyn_trait().map(Into::into) 2066 self.ty.dyn_trait().map(Into::into)
2049 } 2067 }
2050 2068
2069 /// If a type can be represented as `dyn Trait`, returns all traits accessible via this type,
2070 /// or an empty iterator otherwise.
2071 pub fn applicable_inherent_traits<'a>(
2072 &'a self,
2073 db: &'a dyn HirDatabase,
2074 ) -> impl Iterator<Item = Trait> + 'a {
2075 self.autoderef(db)
2076 .filter_map(|derefed_type| derefed_type.ty.dyn_trait())
2077 .flat_map(move |dyn_trait_id| hir_ty::all_super_traits(db.upcast(), dyn_trait_id))
2078 .map(Trait::from)
2079 }
2080
2051 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> { 2081 pub fn as_impl_traits(&self, db: &dyn HirDatabase) -> Option<Vec<Trait>> {
2052 self.ty.impl_trait_bounds(db).map(|it| { 2082 self.ty.impl_trait_bounds(db).map(|it| {
2053 it.into_iter() 2083 it.into_iter()
@@ -2112,18 +2142,22 @@ impl Type {
2112 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) { 2142 fn walk_type(db: &dyn HirDatabase, type_: &Type, cb: &mut impl FnMut(Type)) {
2113 let ty = type_.ty.strip_references(); 2143 let ty = type_.ty.strip_references();
2114 match ty.kind(&Interner) { 2144 match ty.kind(&Interner) {
2115 TyKind::Adt(..) => { 2145 TyKind::Adt(_, substs) => {
2116 cb(type_.derived(ty.clone())); 2146 cb(type_.derived(ty.clone()));
2147 walk_substs(db, type_, &substs, cb);
2117 } 2148 }
2118 TyKind::AssociatedType(..) => { 2149 TyKind::AssociatedType(_, substs) => {
2119 if let Some(_) = ty.associated_type_parent_trait(db) { 2150 if let Some(_) = ty.associated_type_parent_trait(db) {
2120 cb(type_.derived(ty.clone())); 2151 cb(type_.derived(ty.clone()));
2121 } 2152 }
2153 walk_substs(db, type_, &substs, cb);
2122 } 2154 }
2123 TyKind::OpaqueType(..) => { 2155 TyKind::OpaqueType(_, subst) => {
2124 if let Some(bounds) = ty.impl_trait_bounds(db) { 2156 if let Some(bounds) = ty.impl_trait_bounds(db) {
2125 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); 2157 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
2126 } 2158 }
2159
2160 walk_substs(db, type_, subst, cb);
2127 } 2161 }
2128 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { 2162 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
2129 if let Some(bounds) = ty.impl_trait_bounds(db) { 2163 if let Some(bounds) = ty.impl_trait_bounds(db) {
@@ -2146,15 +2180,24 @@ impl Type {
2146 ); 2180 );
2147 } 2181 }
2148 2182
2149 TyKind::Ref(_, ty) | TyKind::Raw(_, ty) | TyKind::Array(ty) | TyKind::Slice(ty) => { 2183 TyKind::Ref(_, _, ty)
2184 | TyKind::Raw(_, ty)
2185 | TyKind::Array(ty, _)
2186 | TyKind::Slice(ty) => {
2150 walk_type(db, &type_.derived(ty.clone()), cb); 2187 walk_type(db, &type_.derived(ty.clone()), cb);
2151 } 2188 }
2152 2189
2190 TyKind::FnDef(_, substs)
2191 | TyKind::Tuple(_, substs)
2192 | TyKind::Closure(.., substs) => {
2193 walk_substs(db, type_, &substs, cb);
2194 }
2195 TyKind::Function(hir_ty::FnPointer { substitution, .. }) => {
2196 walk_substs(db, type_, &substitution.0, cb);
2197 }
2198
2153 _ => {} 2199 _ => {}
2154 } 2200 }
2155 if let Some(substs) = ty.substs() {
2156 walk_substs(db, type_, &substs, cb);
2157 }
2158 } 2201 }
2159 2202
2160 walk_type(db, self, &mut cb); 2203 walk_type(db, self, &mut cb);
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 3bf722d2a..62500602a 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -6,10 +6,11 @@ use std::{cell::RefCell, fmt, iter::successors};
6 6
7use base_db::{FileId, FileRange}; 7use base_db::{FileId, FileRange};
8use hir_def::{ 8use hir_def::{
9 body,
9 resolver::{self, HasResolver, Resolver, TypeNs}, 10 resolver::{self, HasResolver, Resolver, TypeNs},
10 AsMacroCall, FunctionId, TraitId, VariantId, 11 AsMacroCall, FunctionId, TraitId, VariantId,
11}; 12};
12use hir_expand::{hygiene::Hygiene, name::AsName, ExpansionInfo}; 13use hir_expand::{name::AsName, ExpansionInfo};
13use hir_ty::associated_type_shorthand_candidates; 14use hir_ty::associated_type_shorthand_candidates;
14use itertools::Itertools; 15use itertools::Itertools;
15use rustc_hash::{FxHashMap, FxHashSet}; 16use rustc_hash::{FxHashMap, FxHashSet};
@@ -494,9 +495,9 @@ impl<'db> SemanticsImpl<'db> {
494 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 495 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
495 // FIXME: this erases Substs 496 // FIXME: this erases Substs
496 let func = self.resolve_method_call(call)?; 497 let func = self.resolve_method_call(call)?;
497 let ty = self.db.value_ty(func.into()); 498 let (ty, _) = self.db.value_ty(func.into()).into_value_and_skipped_binders();
498 let resolver = self.analyze(call.syntax()).resolver; 499 let resolver = self.analyze(call.syntax()).resolver;
499 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?; 500 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
500 let mut res = ty.as_callable(self.db)?; 501 let mut res = ty.as_callable(self.db)?;
501 res.is_bound_method = true; 502 res.is_bound_method = true;
502 Some(res) 503 Some(res)
@@ -853,8 +854,8 @@ impl<'a> SemanticsScope<'a> {
853 /// Resolve a path as-if it was written at the given scope. This is 854 /// Resolve a path as-if it was written at the given scope. This is
854 /// necessary a heuristic, as it doesn't take hygiene into account. 855 /// necessary a heuristic, as it doesn't take hygiene into account.
855 pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> { 856 pub fn speculative_resolve(&self, path: &ast::Path) -> Option<PathResolution> {
856 let hygiene = Hygiene::new(self.db.upcast(), self.file_id); 857 let ctx = body::LowerCtx::new(self.db.upcast(), self.file_id);
857 let path = Path::from_src(path.clone(), &hygiene)?; 858 let path = Path::from_src(path.clone(), &ctx)?;
858 resolve_hir_path(self.db, &self.resolver, &path) 859 resolve_hir_path(self.db, &self.resolver, &path)
859 } 860 }
860} 861}
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 8e9ea0a03..0895bd6f1 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -9,6 +9,7 @@ use std::{iter::once, sync::Arc};
9 9
10use hir_def::{ 10use hir_def::{
11 body::{ 11 body::{
12 self,
12 scope::{ExprScopes, ScopeId}, 13 scope::{ExprScopes, ScopeId},
13 Body, BodySourceMap, 14 Body, BodySourceMap,
14 }, 15 },
@@ -20,7 +21,7 @@ use hir_def::{
20use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 21use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
21use hir_ty::{ 22use hir_ty::{
22 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields}, 23 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
23 InferenceResult, Substitution, TyLoweringContext, 24 InferenceResult, Interner, Substitution, TyExt, TyLoweringContext,
24}; 25};
25use syntax::{ 26use syntax::{
26 ast::{self, AstNode}, 27 ast::{self, AstNode},
@@ -161,14 +162,15 @@ impl SourceAnalyzer {
161 db: &dyn HirDatabase, 162 db: &dyn HirDatabase,
162 field: &ast::RecordExprField, 163 field: &ast::RecordExprField,
163 ) -> Option<(Field, Option<Local>)> { 164 ) -> Option<(Field, Option<Local>)> {
164 let expr_id = 165 let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
165 self.body_source_map.as_ref()?.node_field(InFile::new(self.file_id, field))?; 166 let expr = ast::Expr::from(record_expr);
167 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
166 168
169 let local_name = field.field_name()?.as_name();
167 let local = if field.name_ref().is_some() { 170 let local = if field.name_ref().is_some() {
168 None 171 None
169 } else { 172 } else {
170 let local_name = field.field_name()?.as_name(); 173 let path = ModPath::from_segments(PathKind::Plain, once(local_name.clone()));
171 let path = ModPath::from_segments(PathKind::Plain, once(local_name));
172 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) { 174 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
173 Some(ValueNs::LocalBinding(pat_id)) => { 175 Some(ValueNs::LocalBinding(pat_id)) => {
174 Some(Local { pat_id, parent: self.resolver.body_owner()? }) 176 Some(Local { pat_id, parent: self.resolver.body_owner()? })
@@ -176,18 +178,24 @@ impl SourceAnalyzer {
176 _ => None, 178 _ => None,
177 } 179 }
178 }; 180 };
179 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; 181 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
180 Some((struct_field.into(), local)) 182 let variant_data = variant.variant_data(db.upcast());
183 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
184 Some((field.into(), local))
181 } 185 }
182 186
183 pub(crate) fn resolve_record_pat_field( 187 pub(crate) fn resolve_record_pat_field(
184 &self, 188 &self,
185 _db: &dyn HirDatabase, 189 db: &dyn HirDatabase,
186 field: &ast::RecordPatField, 190 field: &ast::RecordPatField,
187 ) -> Option<Field> { 191 ) -> Option<Field> {
188 let pat_id = self.pat_id(&field.pat()?)?; 192 let field_name = field.field_name()?.as_name();
189 let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?; 193 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
190 Some(struct_field.into()) 194 let pat_id = self.pat_id(&record_pat.into())?;
195 let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
196 let variant_data = variant.variant_data(db.upcast());
197 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
198 Some(field.into())
191 } 199 }
192 200
193 pub(crate) fn resolve_macro_call( 201 pub(crate) fn resolve_macro_call(
@@ -195,8 +203,8 @@ impl SourceAnalyzer {
195 db: &dyn HirDatabase, 203 db: &dyn HirDatabase,
196 macro_call: InFile<&ast::MacroCall>, 204 macro_call: InFile<&ast::MacroCall>,
197 ) -> Option<MacroDef> { 205 ) -> Option<MacroDef> {
198 let hygiene = Hygiene::new(db.upcast(), macro_call.file_id); 206 let ctx = body::LowerCtx::new(db.upcast(), macro_call.file_id);
199 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &hygiene))?; 207 let path = macro_call.value.path().and_then(|ast| Path::from_src(ast, &ctx))?;
200 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into()) 208 self.resolver.resolve_path_as_macro(db.upcast(), path.mod_path()).map(|it| it.into())
201 } 209 }
202 210
@@ -274,7 +282,9 @@ impl SourceAnalyzer {
274 } 282 }
275 283
276 // This must be a normal source file rather than macro file. 284 // This must be a normal source file rather than macro file.
277 let hir_path = Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; 285 let hygiene = Hygiene::new(db.upcast(), self.file_id);
286 let ctx = body::LowerCtx::with_hygiene(&hygiene);
287 let hir_path = Path::from_src(path.clone(), &ctx)?;
278 288
279 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we 289 // Case where path is a qualifier of another path, e.g. foo::bar::Baz where we
280 // trying to resolve foo::bar. 290 // trying to resolve foo::bar.
@@ -299,7 +309,7 @@ impl SourceAnalyzer {
299 let infer = self.infer.as_ref()?; 309 let infer = self.infer.as_ref()?;
300 310
301 let expr_id = self.expr_id(db, &literal.clone().into())?; 311 let expr_id = self.expr_id(db, &literal.clone().into())?;
302 let substs = infer.type_of_expr[expr_id].substs()?; 312 let substs = infer.type_of_expr[expr_id].as_adt()?.1;
303 313
304 let (variant, missing_fields, _exhaustive) = 314 let (variant, missing_fields, _exhaustive) =
305 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; 315 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
@@ -317,7 +327,7 @@ impl SourceAnalyzer {
317 let infer = self.infer.as_ref()?; 327 let infer = self.infer.as_ref()?;
318 328
319 let pat_id = self.pat_id(&pattern.clone().into())?; 329 let pat_id = self.pat_id(&pattern.clone().into())?;
320 let substs = infer.type_of_pat[pat_id].substs()?; 330 let substs = infer.type_of_pat[pat_id].as_adt()?.1;
321 331
322 let (variant, missing_fields, _exhaustive) = 332 let (variant, missing_fields, _exhaustive) =
323 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; 333 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
@@ -339,7 +349,7 @@ impl SourceAnalyzer {
339 .into_iter() 349 .into_iter()
340 .map(|local_id| { 350 .map(|local_id| {
341 let field = FieldId { parent: variant, local_id }; 351 let field = FieldId { parent: variant, local_id };
342 let ty = field_types[local_id].clone().subst(substs); 352 let ty = field_types[local_id].clone().substitute(&Interner, substs);
343 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty)) 353 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty))
344 }) 354 })
345 .collect() 355 .collect()
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 442c5fb5b..d9294d93a 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -1,18 +1,22 @@
1//! A higher level attributes based on TokenTree, with also some shortcuts. 1//! A higher level attributes based on TokenTree, with also some shortcuts.
2 2
3use std::{ops, sync::Arc}; 3use std::{
4 convert::{TryFrom, TryInto},
5 ops,
6 sync::Arc,
7};
4 8
5use base_db::CrateId; 9use base_db::CrateId;
6use cfg::{CfgExpr, CfgOptions}; 10use cfg::{CfgExpr, CfgOptions};
7use either::Either; 11use either::Either;
8use hir_expand::{hygiene::Hygiene, name::AsName, AstId, InFile}; 12use hir_expand::{hygiene::Hygiene, name::AsName, AstId, AttrId, InFile};
9use itertools::Itertools; 13use itertools::Itertools;
10use la_arena::ArenaMap; 14use la_arena::ArenaMap;
11use mbe::ast_to_token_tree; 15use mbe::ast_to_token_tree;
12use smallvec::{smallvec, SmallVec}; 16use smallvec::{smallvec, SmallVec};
13use syntax::{ 17use syntax::{
14 ast::{self, AstNode, AttrsOwner}, 18 ast::{self, AstNode, AttrsOwner},
15 match_ast, AstToken, SmolStr, SyntaxNode, 19 match_ast, AstPtr, AstToken, SmolStr, SyntaxNode, TextRange, TextSize,
16}; 20};
17use tt::Subtree; 21use tt::Subtree;
18 22
@@ -94,13 +98,16 @@ impl RawAttrs {
94 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { 98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
95 let entries = collect_attrs(owner) 99 let entries = collect_attrs(owner)
96 .enumerate() 100 .enumerate()
97 .flat_map(|(i, attr)| match attr { 101 .flat_map(|(i, attr)| {
98 Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), 102 let index = AttrId(i as u32);
99 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 103 match attr {
100 index: i as u32, 104 Either::Left(attr) => Attr::from_src(attr, hygiene, index),
101 input: Some(AttrInput::Literal(SmolStr::new(doc))), 105 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
102 path: Interned::new(ModPath::from(hir_expand::name!(doc))), 106 id: index,
103 }), 107 input: Some(AttrInput::Literal(SmolStr::new(doc))),
108 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109 }),
110 }
104 }) 111 })
105 .collect::<Arc<_>>(); 112 .collect::<Arc<_>>();
106 113
@@ -157,7 +164,7 @@ impl RawAttrs {
157 let cfg = parts.next().unwrap(); 164 let cfg = parts.next().unwrap();
158 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; 165 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
159 let cfg = CfgExpr::parse(&cfg); 166 let cfg = CfgExpr::parse(&cfg);
160 let index = attr.index; 167 let index = attr.id;
161 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 168 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
162 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 169 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
163 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; 170 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
@@ -211,12 +218,11 @@ impl Attrs {
211 let mut res = ArenaMap::default(); 218 let mut res = ArenaMap::default();
212 219
213 for (id, fld) in src.value.iter() { 220 for (id, fld) in src.value.iter() {
214 let attrs = match fld { 221 let owner: &dyn AttrsOwner = match fld {
215 Either::Left(_tuple) => Attrs::default(), 222 Either::Left(tuple) => tuple,
216 Either::Right(record) => { 223 Either::Right(record) => record,
217 RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
218 }
219 }; 224 };
225 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
220 226
221 res.insert(id, attrs); 227 res.insert(id, attrs);
222 } 228 }
@@ -400,10 +406,14 @@ impl AttrsWithOwner {
400 return AttrSourceMap { attrs }; 406 return AttrSourceMap { attrs };
401 } 407 }
402 AttrDefId::FieldId(id) => { 408 AttrDefId::FieldId(id) => {
403 id.parent.child_source(db).map(|source| match &source[id.local_id] { 409 let map = db.fields_attrs_source_map(id.parent);
404 Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()), 410 let file_id = id.parent.file_id(db);
405 Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()), 411 let root = db.parse_or_expand(file_id).unwrap();
406 }) 412 let owner = match &map[id.local_id] {
413 Either::Left(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
414 Either::Right(it) => ast::AttrsOwnerNode::new(it.to_node(&root)),
415 };
416 InFile::new(file_id, owner)
407 } 417 }
408 AttrDefId::AdtId(adt) => match adt { 418 AttrDefId::AdtId(adt) => match adt {
409 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 419 AdtId::StructId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -411,10 +421,12 @@ impl AttrsWithOwner {
411 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 421 AdtId::EnumId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
412 }, 422 },
413 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 423 AttrDefId::FunctionId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
414 AttrDefId::EnumVariantId(id) => id 424 AttrDefId::EnumVariantId(id) => {
415 .parent 425 let map = db.variants_attrs_source_map(id.parent);
416 .child_source(db) 426 let file_id = id.parent.lookup(db).id.file_id();
417 .map(|source| ast::AttrsOwnerNode::new(source[id.local_id].clone())), 427 let root = db.parse_or_expand(file_id).unwrap();
428 InFile::new(file_id, ast::AttrsOwnerNode::new(map[id.local_id].to_node(&root)))
429 }
418 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 430 AttrDefId::StaticId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
419 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 431 AttrDefId::ConstId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
420 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new), 432 AttrDefId::TraitId(id) => id.lookup(db).source(db).map(ast::AttrsOwnerNode::new),
@@ -452,6 +464,55 @@ impl AttrsWithOwner {
452 .collect(), 464 .collect(),
453 } 465 }
454 } 466 }
467
468 pub fn docs_with_rangemap(
469 &self,
470 db: &dyn DefDatabase,
471 ) -> Option<(Documentation, DocsRangeMap)> {
472 // FIXME: code duplication in `docs` above
473 let docs = self.by_key("doc").attrs().flat_map(|attr| match attr.input.as_ref()? {
474 AttrInput::Literal(s) => Some((s, attr.id)),
475 AttrInput::TokenTree(_) => None,
476 });
477 let indent = docs
478 .clone()
479 .flat_map(|(s, _)| s.lines())
480 .filter(|line| !line.chars().all(|c| c.is_whitespace()))
481 .map(|line| line.chars().take_while(|c| c.is_whitespace()).count())
482 .min()
483 .unwrap_or(0);
484 let mut buf = String::new();
485 let mut mapping = Vec::new();
486 for (doc, idx) in docs {
487 // str::lines doesn't yield anything for the empty string
488 if !doc.is_empty() {
489 for line in doc.split('\n') {
490 let line = line.trim_end();
491 let line_len = line.len();
492 let (offset, line) = match line.char_indices().nth(indent) {
493 Some((offset, _)) => (offset, &line[offset..]),
494 None => (0, line),
495 };
496 let buf_offset = buf.len();
497 buf.push_str(line);
498 mapping.push((
499 TextRange::new(buf_offset.try_into().ok()?, buf.len().try_into().ok()?),
500 idx,
501 TextRange::new(offset.try_into().ok()?, line_len.try_into().ok()?),
502 ));
503 buf.push('\n');
504 }
505 } else {
506 buf.push('\n');
507 }
508 }
509 buf.pop();
510 if buf.is_empty() {
511 None
512 } else {
513 Some((Documentation(buf), DocsRangeMap { mapping, source: self.source_map(db).attrs }))
514 }
515 }
455} 516}
456 517
457fn inner_attributes( 518fn inner_attributes(
@@ -484,7 +545,7 @@ fn inner_attributes(
484 _ => return None, 545 _ => return None,
485 } 546 }
486 }; 547 };
487 let attrs = attrs.filter(|attr| attr.excl_token().is_some()); 548 let attrs = attrs.filter(|attr| attr.kind().is_inner());
488 let docs = docs.filter(|doc| doc.is_inner()); 549 let docs = docs.filter(|doc| doc.is_inner());
489 Some((attrs, docs)) 550 Some((attrs, docs))
490} 551}
@@ -502,15 +563,53 @@ impl AttrSourceMap {
502 /// the attribute represented by `Attr`. 563 /// the attribute represented by `Attr`.
503 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> { 564 pub fn source_of(&self, attr: &Attr) -> InFile<&Either<ast::Attr, ast::Comment>> {
504 self.attrs 565 self.attrs
505 .get(attr.index as usize) 566 .get(attr.id.0 as usize)
506 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 567 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id))
507 .as_ref() 568 .as_ref()
508 } 569 }
509} 570}
510 571
572/// A struct to map text ranges from [`Documentation`] back to TextRanges in the syntax tree.
573pub struct DocsRangeMap {
574 source: Vec<InFile<Either<ast::Attr, ast::Comment>>>,
575 // (docstring-line-range, attr_index, attr-string-range)
576 // a mapping from the text range of a line of the [`Documentation`] to the attribute index and
577 // the original (untrimmed) syntax doc line
578 mapping: Vec<(TextRange, AttrId, TextRange)>,
579}
580
581impl DocsRangeMap {
582 pub fn map(&self, range: TextRange) -> Option<InFile<TextRange>> {
583 let found = self.mapping.binary_search_by(|(probe, ..)| probe.ordering(range)).ok()?;
584 let (line_docs_range, idx, original_line_src_range) = self.mapping[found].clone();
585 if !line_docs_range.contains_range(range) {
586 return None;
587 }
588
589 let relative_range = range - line_docs_range.start();
590
591 let &InFile { file_id, value: ref source } = &self.source[idx.0 as usize];
592 match source {
593 Either::Left(_) => None, // FIXME, figure out a nice way to handle doc attributes here
594 // as well as for whats done in syntax highlight doc injection
595 Either::Right(comment) => {
596 let text_range = comment.syntax().text_range();
597 let range = TextRange::at(
598 text_range.start()
599 + TextSize::try_from(comment.prefix().len()).ok()?
600 + original_line_src_range.start()
601 + relative_range.start(),
602 text_range.len().min(range.len()),
603 );
604 Some(InFile { file_id, value: range })
605 }
606 }
607 }
608}
609
511#[derive(Debug, Clone, PartialEq, Eq)] 610#[derive(Debug, Clone, PartialEq, Eq)]
512pub struct Attr { 611pub struct Attr {
513 index: u32, 612 pub(crate) id: AttrId,
514 pub(crate) path: Interned<ModPath>, 613 pub(crate) path: Interned<ModPath>,
515 pub(crate) input: Option<AttrInput>, 614 pub(crate) input: Option<AttrInput>,
516} 615}
@@ -524,7 +623,7 @@ pub enum AttrInput {
524} 623}
525 624
526impl Attr { 625impl Attr {
527 fn from_src(ast: ast::Attr, hygiene: &Hygiene, index: u32) -> Option<Attr> { 626 fn from_src(ast: ast::Attr, hygiene: &Hygiene, id: AttrId) -> Option<Attr> {
528 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?); 627 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
529 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 628 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
530 let value = match lit.kind() { 629 let value = match lit.kind() {
@@ -537,7 +636,7 @@ impl Attr {
537 } else { 636 } else {
538 None 637 None
539 }; 638 };
540 Some(Attr { index, path, input }) 639 Some(Attr { id, path, input })
541 } 640 }
542 641
543 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths 642 /// Parses this attribute as a `#[derive]`, returns an iterator that yields all contained paths
@@ -641,7 +740,7 @@ fn collect_attrs(
641 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax()) 740 let (inner_attrs, inner_docs) = inner_attributes(owner.syntax())
642 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs))); 741 .map_or((None, None), |(attrs, docs)| (Some(attrs), Some(docs)));
643 742
644 let outer_attrs = owner.attrs().filter(|attr| attr.excl_token().is_none()); 743 let outer_attrs = owner.attrs().filter(|attr| attr.kind().is_outer());
645 let attrs = outer_attrs 744 let attrs = outer_attrs
646 .chain(inner_attrs.into_iter().flatten()) 745 .chain(inner_attrs.into_iter().flatten())
647 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr))); 746 .map(|attr| (attr.syntax().text_range().start(), Either::Left(attr)));
@@ -652,7 +751,38 @@ fn collect_attrs(
652 .chain(inner_docs.into_iter().flatten()) 751 .chain(inner_docs.into_iter().flatten())
653 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text))); 752 .map(|docs_text| (docs_text.syntax().text_range().start(), Either::Right(docs_text)));
654 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved 753 // sort here by syntax node offset because the source can have doc attributes and doc strings be interleaved
655 let attrs: Vec<_> = docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).collect(); 754 docs.chain(attrs).sorted_by_key(|&(offset, _)| offset).map(|(_, attr)| attr)
755}
756
757pub(crate) fn variants_attrs_source_map(
758 db: &dyn DefDatabase,
759 def: EnumId,
760) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>> {
761 let mut res = ArenaMap::default();
762 let child_source = def.child_source(db);
763
764 for (idx, variant) in child_source.value.iter() {
765 res.insert(idx, AstPtr::new(variant));
766 }
767
768 Arc::new(res)
769}
770
771pub(crate) fn fields_attrs_source_map(
772 db: &dyn DefDatabase,
773 def: VariantId,
774) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>> {
775 let mut res = ArenaMap::default();
776 let child_source = def.child_source(db);
777
778 for (idx, variant) in child_source.value.iter() {
779 res.insert(
780 idx,
781 variant
782 .as_ref()
783 .either(|l| Either::Left(AstPtr::new(l)), |r| Either::Right(AstPtr::new(r))),
784 );
785 }
656 786
657 attrs.into_iter().map(|(_, attr)| attr) 787 Arc::new(res)
658} 788}
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 96b959967..131f424cc 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -21,7 +21,7 @@ use profile::Count;
21use rustc_hash::FxHashMap; 21use rustc_hash::FxHashMap;
22use syntax::{ast, AstNode, AstPtr}; 22use syntax::{ast, AstNode, AstPtr};
23 23
24pub(crate) use lower::LowerCtx; 24pub use lower::LowerCtx;
25 25
26use crate::{ 26use crate::{
27 attr::{Attrs, RawAttrs}, 27 attr::{Attrs, RawAttrs},
@@ -37,13 +37,15 @@ use crate::{
37 37
38/// A subset of Expander that only deals with cfg attributes. We only need it to 38/// A subset of Expander that only deals with cfg attributes. We only need it to
39/// avoid cyclic queries in crate def map during enum processing. 39/// avoid cyclic queries in crate def map during enum processing.
40#[derive(Debug)]
40pub(crate) struct CfgExpander { 41pub(crate) struct CfgExpander {
41 cfg_options: CfgOptions, 42 cfg_options: CfgOptions,
42 hygiene: Hygiene, 43 hygiene: Hygiene,
43 krate: CrateId, 44 krate: CrateId,
44} 45}
45 46
46pub(crate) struct Expander { 47#[derive(Debug)]
48pub struct Expander {
47 cfg_expander: CfgExpander, 49 cfg_expander: CfgExpander,
48 def_map: Arc<DefMap>, 50 def_map: Arc<DefMap>,
49 current_file_id: HirFileId, 51 current_file_id: HirFileId,
@@ -80,11 +82,7 @@ impl CfgExpander {
80} 82}
81 83
82impl Expander { 84impl Expander {
83 pub(crate) fn new( 85 pub fn new(db: &dyn DefDatabase, current_file_id: HirFileId, module: ModuleId) -> Expander {
84 db: &dyn DefDatabase,
85 current_file_id: HirFileId,
86 module: ModuleId,
87 ) -> Expander {
88 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate); 86 let cfg_expander = CfgExpander::new(db, current_file_id, module.krate);
89 let def_map = module.def_map(db); 87 let def_map = module.def_map(db);
90 let ast_id_map = db.ast_id_map(current_file_id); 88 let ast_id_map = db.ast_id_map(current_file_id);
@@ -98,7 +96,7 @@ impl Expander {
98 } 96 }
99 } 97 }
100 98
101 pub(crate) fn enter_expand<T: ast::AstNode>( 99 pub fn enter_expand<T: ast::AstNode>(
102 &mut self, 100 &mut self,
103 db: &dyn DefDatabase, 101 db: &dyn DefDatabase,
104 macro_call: ast::MacroCall, 102 macro_call: ast::MacroCall,
@@ -170,7 +168,7 @@ impl Expander {
170 Ok(ExpandResult { value: Some((mark, node)), err }) 168 Ok(ExpandResult { value: Some((mark, node)), err })
171 } 169 }
172 170
173 pub(crate) fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) { 171 pub fn exit(&mut self, db: &dyn DefDatabase, mut mark: Mark) {
174 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id); 172 self.cfg_expander.hygiene = Hygiene::new(db.upcast(), mark.file_id);
175 self.current_file_id = mark.file_id; 173 self.current_file_id = mark.file_id;
176 self.ast_id_map = mem::take(&mut mark.ast_id_map); 174 self.ast_id_map = mem::take(&mut mark.ast_id_map);
@@ -190,8 +188,13 @@ impl Expander {
190 &self.cfg_expander.cfg_options 188 &self.cfg_expander.cfg_options
191 } 189 }
192 190
191 pub fn current_file_id(&self) -> HirFileId {
192 self.current_file_id
193 }
194
193 fn parse_path(&mut self, path: ast::Path) -> Option<Path> { 195 fn parse_path(&mut self, path: ast::Path) -> Option<Path> {
194 Path::from_src(path, &self.cfg_expander.hygiene) 196 let ctx = LowerCtx::with_hygiene(&self.cfg_expander.hygiene);
197 Path::from_src(path, &ctx)
195 } 198 }
196 199
197 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> { 200 fn resolve_path_as_macro(&self, db: &dyn DefDatabase, path: &ModPath) -> Option<MacroDefId> {
@@ -204,7 +207,8 @@ impl Expander {
204 } 207 }
205} 208}
206 209
207pub(crate) struct Mark { 210#[derive(Debug)]
211pub struct Mark {
208 file_id: HirFileId, 212 file_id: HirFileId,
209 ast_id_map: Arc<AstIdMap>, 213 ast_id_map: Arc<AstIdMap>,
210 bomb: DropBomb, 214 bomb: DropBomb,
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 63e89a1f4..c11da30d2 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -1,10 +1,11 @@
1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr` 1//! Transforms `ast::Expr` into an equivalent `hir_def::expr::Expr`
2//! representation. 2//! representation.
3 3
4use std::mem; 4use std::{mem, sync::Arc};
5 5
6use either::Either; 6use either::Either;
7use hir_expand::{ 7use hir_expand::{
8 ast_id_map::{AstIdMap, FileAstId},
8 hygiene::Hygiene, 9 hygiene::Hygiene,
9 name::{name, AsName, Name}, 10 name::{name, AsName, Name},
10 ExpandError, HirFileId, 11 ExpandError, HirFileId,
@@ -30,6 +31,7 @@ use crate::{
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 31 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
31 Statement, 32 Statement,
32 }, 33 },
34 intern::Interned,
33 item_scope::BuiltinShadowMode, 35 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 36 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 37 type_ref::{Mutability, Rawness, TypeRef},
@@ -38,20 +40,39 @@ use crate::{
38 40
39use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource}; 41use super::{diagnostics::BodyDiagnostic, ExprSource, PatSource};
40 42
41pub(crate) struct LowerCtx { 43pub struct LowerCtx {
42 hygiene: Hygiene, 44 hygiene: Hygiene,
45 file_id: Option<HirFileId>,
46 source_ast_id_map: Option<Arc<AstIdMap>>,
43} 47}
44 48
45impl LowerCtx { 49impl LowerCtx {
46 pub(crate) fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { 50 pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self {
47 LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } 51 LowerCtx {
52 hygiene: Hygiene::new(db.upcast(), file_id),
53 file_id: Some(file_id),
54 source_ast_id_map: Some(db.ast_id_map(file_id)),
55 }
48 } 56 }
49 pub(crate) fn with_hygiene(hygiene: &Hygiene) -> Self { 57
50 LowerCtx { hygiene: hygiene.clone() } 58 pub fn with_hygiene(hygiene: &Hygiene) -> Self {
59 LowerCtx { hygiene: hygiene.clone(), file_id: None, source_ast_id_map: None }
60 }
61
62 pub(crate) fn hygiene(&self) -> &Hygiene {
63 &self.hygiene
64 }
65
66 pub(crate) fn file_id(&self) -> HirFileId {
67 self.file_id.unwrap()
51 } 68 }
52 69
53 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> { 70 pub(crate) fn lower_path(&self, ast: ast::Path) -> Option<Path> {
54 Path::from_src(ast, &self.hygiene) 71 Path::from_src(ast, self)
72 }
73
74 pub(crate) fn ast_id<N: AstNode>(&self, item: &N) -> Option<FileAstId<N>> {
75 self.source_ast_id_map.as_ref().map(|ast_id_map| ast_id_map.ast_id(item))
55 } 76 }
56} 77}
57 78
@@ -322,8 +343,10 @@ impl ExprCollector<'_> {
322 Vec::new() 343 Vec::new()
323 }; 344 };
324 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 345 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
325 let generic_args = 346 let generic_args = e
326 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 347 .generic_arg_list()
348 .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
349 .map(Box::new);
327 self.alloc_expr( 350 self.alloc_expr(
328 Expr::MethodCall { receiver, method_name, args, generic_args }, 351 Expr::MethodCall { receiver, method_name, args, generic_args },
329 syntax_ptr, 352 syntax_ptr,
@@ -385,7 +408,7 @@ impl ExprCollector<'_> {
385 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 408 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
386 } 409 }
387 ast::Expr::RecordExpr(e) => { 410 ast::Expr::RecordExpr(e) => {
388 let path = e.path().and_then(|path| self.expander.parse_path(path)); 411 let path = e.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
389 let record_lit = if let Some(nfl) = e.record_expr_field_list() { 412 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
390 let fields = nfl 413 let fields = nfl
391 .fields() 414 .fields()
@@ -430,7 +453,7 @@ impl ExprCollector<'_> {
430 } 453 }
431 ast::Expr::CastExpr(e) => { 454 ast::Expr::CastExpr(e) => {
432 let expr = self.collect_expr_opt(e.expr()); 455 let expr = self.collect_expr_opt(e.expr());
433 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); 456 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
434 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 457 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
435 } 458 }
436 ast::Expr::RefExpr(e) => { 459 ast::Expr::RefExpr(e) => {
@@ -464,13 +487,16 @@ impl ExprCollector<'_> {
464 if let Some(pl) = e.param_list() { 487 if let Some(pl) = e.param_list() {
465 for param in pl.params() { 488 for param in pl.params() {
466 let pat = self.collect_pat_opt(param.pat()); 489 let pat = self.collect_pat_opt(param.pat());
467 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 490 let type_ref =
491 param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
468 args.push(pat); 492 args.push(pat);
469 arg_types.push(type_ref); 493 arg_types.push(type_ref);
470 } 494 }
471 } 495 }
472 let ret_type = 496 let ret_type = e
473 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); 497 .ret_type()
498 .and_then(|r| r.ty())
499 .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
474 let body = self.collect_expr_opt(e.body()); 500 let body = self.collect_expr_opt(e.body());
475 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 501 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
476 } 502 }
@@ -525,8 +551,9 @@ impl ExprCollector<'_> {
525 } 551 }
526 } 552 }
527 ast::Expr::MacroCall(e) => { 553 ast::Expr::MacroCall(e) => {
554 let macro_ptr = AstPtr::new(&e);
528 let mut ids = vec![]; 555 let mut ids = vec![];
529 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { 556 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
530 ids.push(match expansion { 557 ids.push(match expansion {
531 Some(it) => this.collect_expr(it), 558 Some(it) => this.collect_expr(it),
532 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 559 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -549,7 +576,7 @@ impl ExprCollector<'_> {
549 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>( 576 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
550 &mut self, 577 &mut self,
551 e: ast::MacroCall, 578 e: ast::MacroCall,
552 syntax_ptr: AstPtr<ast::Expr>, 579 syntax_ptr: AstPtr<ast::MacroCall>,
553 is_error_recoverable: bool, 580 is_error_recoverable: bool,
554 mut collector: F, 581 mut collector: F,
555 ) { 582 ) {
@@ -561,9 +588,13 @@ impl ExprCollector<'_> {
561 588
562 let res = match res { 589 let res = match res {
563 Ok(res) => res, 590 Ok(res) => res,
564 Err(UnresolvedMacro) => { 591 Err(UnresolvedMacro { path }) => {
565 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 592 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
566 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, 593 UnresolvedMacroCall {
594 file: outer_file,
595 node: syntax_ptr.cast().unwrap(),
596 path,
597 },
567 )); 598 ));
568 collector(self, None); 599 collector(self, None);
569 return; 600 return;
@@ -625,7 +656,8 @@ impl ExprCollector<'_> {
625 return; 656 return;
626 } 657 }
627 let pat = self.collect_pat_opt(stmt.pat()); 658 let pat = self.collect_pat_opt(stmt.pat());
628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 659 let type_ref =
660 stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
629 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 661 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); 662 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
631 } 663 }
@@ -636,10 +668,14 @@ impl ExprCollector<'_> {
636 668
637 // Note that macro could be expended to multiple statements 669 // Note that macro could be expended to multiple statements
638 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 670 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
671 let macro_ptr = AstPtr::new(&m);
639 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 672 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
640 673
641 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 674 self.collect_macro_call(
642 match expansion { 675 m,
676 macro_ptr,
677 false,
678 |this, expansion| match expansion {
643 Some(expansion) => { 679 Some(expansion) => {
644 let statements: ast::MacroStmts = expansion; 680 let statements: ast::MacroStmts = expansion;
645 681
@@ -653,8 +689,8 @@ impl ExprCollector<'_> {
653 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); 689 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
654 this.statements_in_scope.push(Statement::Expr(expr)); 690 this.statements_in_scope.push(Statement::Expr(expr));
655 } 691 }
656 } 692 },
657 }); 693 );
658 } else { 694 } else {
659 let expr = self.collect_expr_opt(stmt.expr()); 695 let expr = self.collect_expr_opt(stmt.expr());
660 self.statements_in_scope.push(Statement::Expr(expr)); 696 self.statements_in_scope.push(Statement::Expr(expr));
@@ -755,7 +791,7 @@ impl ExprCollector<'_> {
755 } 791 }
756 } 792 }
757 ast::Pat::TupleStructPat(p) => { 793 ast::Pat::TupleStructPat(p) => {
758 let path = p.path().and_then(|path| self.expander.parse_path(path)); 794 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
759 let (args, ellipsis) = self.collect_tuple_pat(p.fields()); 795 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
760 Pat::TupleStruct { path, args, ellipsis } 796 Pat::TupleStruct { path, args, ellipsis }
761 } 797 }
@@ -765,7 +801,7 @@ impl ExprCollector<'_> {
765 Pat::Ref { pat, mutability } 801 Pat::Ref { pat, mutability }
766 } 802 }
767 ast::Pat::PathPat(p) => { 803 ast::Pat::PathPat(p) => {
768 let path = p.path().and_then(|path| self.expander.parse_path(path)); 804 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
769 path.map(Pat::Path).unwrap_or(Pat::Missing) 805 path.map(Pat::Path).unwrap_or(Pat::Missing)
770 } 806 }
771 ast::Pat::OrPat(p) => { 807 ast::Pat::OrPat(p) => {
@@ -779,7 +815,7 @@ impl ExprCollector<'_> {
779 } 815 }
780 ast::Pat::WildcardPat(_) => Pat::Wild, 816 ast::Pat::WildcardPat(_) => Pat::Wild,
781 ast::Pat::RecordPat(p) => { 817 ast::Pat::RecordPat(p) => {
782 let path = p.path().and_then(|path| self.expander.parse_path(path)); 818 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
783 let args: Vec<_> = p 819 let args: Vec<_> = p
784 .record_pat_field_list() 820 .record_pat_field_list()
785 .expect("every struct should have a field list") 821 .expect("every struct should have a field list")
@@ -841,8 +877,23 @@ impl ExprCollector<'_> {
841 Pat::Missing 877 Pat::Missing
842 } 878 }
843 } 879 }
880 ast::Pat::MacroPat(mac) => match mac.macro_call() {
881 Some(call) => {
882 let macro_ptr = AstPtr::new(&call);
883 let mut pat = None;
884 self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
885 pat = Some(this.collect_pat_opt(expanded_pat));
886 });
887
888 match pat {
889 Some(pat) => return pat,
890 None => Pat::Missing,
891 }
892 }
893 None => Pat::Missing,
894 },
844 // FIXME: implement 895 // FIXME: implement
845 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 896 ast::Pat::RangePat(_) => Pat::Missing,
846 }; 897 };
847 let ptr = AstPtr::new(&pat); 898 let ptr = AstPtr::new(&pat);
848 self.alloc_pat(pattern, Either::Left(ptr)) 899 self.alloc_pat(pattern, Either::Left(ptr))
diff --git a/crates/hir_def/src/body/tests.rs b/crates/hir_def/src/body/tests.rs
index faa133297..3e8f16306 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -40,6 +40,14 @@ fn block_def_map_at(ra_fixture: &str) -> String {
40 module.def_map(&db).dump(&db) 40 module.def_map(&db).dump(&db)
41} 41}
42 42
43fn check_block_scopes_at(ra_fixture: &str, expect: Expect) {
44 let (db, position) = crate::test_db::TestDB::with_position(ra_fixture);
45
46 let module = db.module_at_position(position);
47 let actual = module.def_map(&db).dump_block_scopes(&db);
48 expect.assert_eq(&actual);
49}
50
43fn check_at(ra_fixture: &str, expect: Expect) { 51fn check_at(ra_fixture: &str, expect: Expect) {
44 let actual = block_def_map_at(ra_fixture); 52 let actual = block_def_map_at(ra_fixture);
45 expect.assert_eq(&actual); 53 expect.assert_eq(&actual);
@@ -143,7 +151,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 151 //^^^^^^^^^^^^^ could not convert tokens
144 152
145 env!("OUT_DIR"); 153 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 154 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 155
148 compile_error!("compile_error works"); 156 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 157 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
@@ -180,7 +188,7 @@ fn unresolved_macro_diag() {
180 r#" 188 r#"
181fn f() { 189fn f() {
182 m!(); 190 m!();
183 //^^^^ unresolved macro call 191 //^^^^ unresolved macro `m!`
184} 192}
185 "#, 193 "#,
186 ); 194 );
diff --git a/crates/hir_def/src/body/tests/block.rs b/crates/hir_def/src/body/tests/block.rs
index 3b6ba4cde..bc3d0f138 100644
--- a/crates/hir_def/src/body/tests/block.rs
+++ b/crates/hir_def/src/body/tests/block.rs
@@ -134,6 +134,30 @@ struct Struct {}
134} 134}
135 135
136#[test] 136#[test]
137fn nested_module_scoping() {
138 check_block_scopes_at(
139 r#"
140fn f() {
141 mod module {
142 struct Struct {}
143 fn f() {
144 use self::Struct;
145 $0
146 }
147 }
148}
149 "#,
150 expect![[r#"
151 BlockId(1) in ModuleId { krate: CrateId(0), block: Some(BlockId(0)), local_id: Idx::<ModuleData>(0) }
152 BlockId(0) in ModuleId { krate: CrateId(0), block: None, local_id: Idx::<ModuleData>(0) }
153 crate scope
154 "#]],
155 );
156 // FIXME: The module nesting here is wrong!
157 // The first block map should be located in module #1 (`mod module`), not #0 (BlockId(0) root module)
158}
159
160#[test]
137fn legacy_macro_items() { 161fn legacy_macro_items() {
138 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded 162 // Checks that legacy-scoped `macro_rules!` from parent namespaces are resolved and expanded
139 // correctly. 163 // correctly.
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index f40a7f80d..f2e809ca9 100644
--- a/crates/hir_def/src/child_by_source.rs
+++ b/crates/hir_def/src/child_by_source.rs
@@ -80,6 +80,10 @@ impl ChildBySource for ModuleId {
80impl ChildBySource for ItemScope { 80impl ChildBySource for ItemScope {
81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { 81 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
82 self.declarations().for_each(|item| add_module_def(db, res, item)); 82 self.declarations().for_each(|item| add_module_def(db, res, item));
83 self.unnamed_consts().for_each(|konst| {
84 let src = konst.lookup(db).source(db);
85 res[keys::CONST].insert(src, konst);
86 });
83 self.impls().for_each(|imp| add_impl(db, res, imp)); 87 self.impls().for_each(|imp| add_impl(db, res, imp));
84 88
85 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) { 89 fn add_module_def(db: &dyn DefDatabase, map: &mut DynMap, item: ModuleDefId) {
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 068b2ee38..7eadc8e0d 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -2,9 +2,10 @@
2use std::sync::Arc; 2use std::sync::Arc;
3 3
4use base_db::{salsa, CrateId, SourceDatabase, Upcast}; 4use base_db::{salsa, CrateId, SourceDatabase, Upcast};
5use either::Either;
5use hir_expand::{db::AstDatabase, HirFileId}; 6use hir_expand::{db::AstDatabase, HirFileId};
6use la_arena::ArenaMap; 7use la_arena::ArenaMap;
7use syntax::SmolStr; 8use syntax::{ast, AstPtr, SmolStr};
8 9
9use crate::{ 10use crate::{
10 adt::{EnumData, StructData}, 11 adt::{EnumData, StructData},
@@ -13,6 +14,7 @@ use crate::{
13 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData}, 14 data::{ConstData, FunctionData, ImplData, StaticData, TraitData, TypeAliasData},
14 generics::GenericParams, 15 generics::GenericParams,
15 import_map::ImportMap, 16 import_map::ImportMap,
17 intern::Interned,
16 item_tree::ItemTree, 18 item_tree::ItemTree,
17 lang_item::{LangItemTarget, LangItems}, 19 lang_item::{LangItemTarget, LangItems},
18 nameres::DefMap, 20 nameres::DefMap,
@@ -113,7 +115,7 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
113 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>; 115 fn expr_scopes(&self, def: DefWithBodyId) -> Arc<ExprScopes>;
114 116
115 #[salsa::invoke(GenericParams::generic_params_query)] 117 #[salsa::invoke(GenericParams::generic_params_query)]
116 fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>; 118 fn generic_params(&self, def: GenericDefId) -> Interned<GenericParams>;
117 119
118 #[salsa::invoke(Attrs::variants_attrs_query)] 120 #[salsa::invoke(Attrs::variants_attrs_query)]
119 fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>; 121 fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>;
@@ -121,6 +123,18 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
121 #[salsa::invoke(Attrs::fields_attrs_query)] 123 #[salsa::invoke(Attrs::fields_attrs_query)]
122 fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>; 124 fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
123 125
126 #[salsa::invoke(crate::attr::variants_attrs_source_map)]
127 fn variants_attrs_source_map(
128 &self,
129 def: EnumId,
130 ) -> Arc<ArenaMap<LocalEnumVariantId, AstPtr<ast::Variant>>>;
131
132 #[salsa::invoke(crate::attr::fields_attrs_source_map)]
133 fn fields_attrs_source_map(
134 &self,
135 def: VariantId,
136 ) -> Arc<ArenaMap<LocalFieldId, Either<AstPtr<ast::TupleField>, AstPtr<ast::RecordField>>>>;
137
124 #[salsa::invoke(AttrsWithOwner::attrs_query)] 138 #[salsa::invoke(AttrsWithOwner::attrs_query)]
125 fn attrs(&self, def: AttrDefId) -> AttrsWithOwner; 139 fn attrs(&self, def: AttrDefId) -> AttrsWithOwner;
126 140
diff --git a/crates/hir_def/src/diagnostics.rs b/crates/hir_def/src/diagnostics.rs
index 97abf8653..a71ae2668 100644
--- a/crates/hir_def/src/diagnostics.rs
+++ b/crates/hir_def/src/diagnostics.rs
@@ -8,7 +8,7 @@ use hir_expand::diagnostics::{Diagnostic, DiagnosticCode, DiagnosticSink};
8use hir_expand::{HirFileId, InFile}; 8use hir_expand::{HirFileId, InFile};
9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange}; 9use syntax::{ast, AstPtr, SyntaxNodePtr, TextRange};
10 10
11use crate::{db::DefDatabase, DefWithBodyId}; 11use crate::{db::DefDatabase, path::ModPath, DefWithBodyId};
12 12
13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) { 13pub fn validate_body(db: &dyn DefDatabase, owner: DefWithBodyId, sink: &mut DiagnosticSink<'_>) {
14 let source_map = db.body_with_source_map(owner).1; 14 let source_map = db.body_with_source_map(owner).1;
@@ -103,6 +103,7 @@ impl Diagnostic for UnresolvedImport {
103pub struct UnresolvedMacroCall { 103pub struct UnresolvedMacroCall {
104 pub file: HirFileId, 104 pub file: HirFileId,
105 pub node: AstPtr<ast::MacroCall>, 105 pub node: AstPtr<ast::MacroCall>,
106 pub path: ModPath,
106} 107}
107 108
108impl Diagnostic for UnresolvedMacroCall { 109impl Diagnostic for UnresolvedMacroCall {
@@ -110,7 +111,7 @@ impl Diagnostic for UnresolvedMacroCall {
110 DiagnosticCode("unresolved-macro-call") 111 DiagnosticCode("unresolved-macro-call")
111 } 112 }
112 fn message(&self) -> String { 113 fn message(&self) -> String {
113 "unresolved macro call".to_string() 114 format!("unresolved macro `{}!`", self.path)
114 } 115 }
115 fn display_source(&self) -> InFile<SyntaxNodePtr> { 116 fn display_source(&self) -> InFile<SyntaxNodePtr> {
116 InFile::new(self.file, self.node.clone().into()) 117 InFile::new(self.file, self.node.clone().into())
diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs
index 6c7376fad..b4ad984bd 100644
--- a/crates/hir_def/src/expr.rs
+++ b/crates/hir_def/src/expr.rs
@@ -18,6 +18,7 @@ use syntax::ast::RangeOp;
18 18
19use crate::{ 19use crate::{
20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}, 20 builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
21 intern::Interned,
21 path::{GenericArgs, Path}, 22 path::{GenericArgs, Path},
22 type_ref::{Mutability, Rawness, TypeRef}, 23 type_ref::{Mutability, Rawness, TypeRef},
23 BlockId, 24 BlockId,
@@ -86,7 +87,7 @@ pub enum Expr {
86 receiver: ExprId, 87 receiver: ExprId,
87 method_name: Name, 88 method_name: Name,
88 args: Vec<ExprId>, 89 args: Vec<ExprId>,
89 generic_args: Option<GenericArgs>, 90 generic_args: Option<Box<GenericArgs>>,
90 }, 91 },
91 Match { 92 Match {
92 expr: ExprId, 93 expr: ExprId,
@@ -106,7 +107,7 @@ pub enum Expr {
106 expr: Option<ExprId>, 107 expr: Option<ExprId>,
107 }, 108 },
108 RecordLit { 109 RecordLit {
109 path: Option<Path>, 110 path: Option<Box<Path>>,
110 fields: Vec<RecordLitField>, 111 fields: Vec<RecordLitField>,
111 spread: Option<ExprId>, 112 spread: Option<ExprId>,
112 }, 113 },
@@ -131,7 +132,7 @@ pub enum Expr {
131 }, 132 },
132 Cast { 133 Cast {
133 expr: ExprId, 134 expr: ExprId,
134 type_ref: TypeRef, 135 type_ref: Interned<TypeRef>,
135 }, 136 },
136 Ref { 137 Ref {
137 expr: ExprId, 138 expr: ExprId,
@@ -161,8 +162,8 @@ pub enum Expr {
161 }, 162 },
162 Lambda { 163 Lambda {
163 args: Vec<PatId>, 164 args: Vec<PatId>,
164 arg_types: Vec<Option<TypeRef>>, 165 arg_types: Vec<Option<Interned<TypeRef>>>,
165 ret_type: Option<TypeRef>, 166 ret_type: Option<Interned<TypeRef>>,
166 body: ExprId, 167 body: ExprId,
167 }, 168 },
168 Tuple { 169 Tuple {
@@ -240,7 +241,7 @@ pub struct RecordLitField {
240 241
241#[derive(Debug, Clone, Eq, PartialEq)] 242#[derive(Debug, Clone, Eq, PartialEq)]
242pub enum Statement { 243pub enum Statement {
243 Let { pat: PatId, type_ref: Option<TypeRef>, initializer: Option<ExprId> }, 244 Let { pat: PatId, type_ref: Option<Interned<TypeRef>>, initializer: Option<ExprId> },
244 Expr(ExprId), 245 Expr(ExprId),
245} 246}
246 247
@@ -412,13 +413,13 @@ pub enum Pat {
412 Wild, 413 Wild,
413 Tuple { args: Vec<PatId>, ellipsis: Option<usize> }, 414 Tuple { args: Vec<PatId>, ellipsis: Option<usize> },
414 Or(Vec<PatId>), 415 Or(Vec<PatId>),
415 Record { path: Option<Path>, args: Vec<RecordFieldPat>, ellipsis: bool }, 416 Record { path: Option<Box<Path>>, args: Vec<RecordFieldPat>, ellipsis: bool },
416 Range { start: ExprId, end: ExprId }, 417 Range { start: ExprId, end: ExprId },
417 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> }, 418 Slice { prefix: Vec<PatId>, slice: Option<PatId>, suffix: Vec<PatId> },
418 Path(Path), 419 Path(Box<Path>),
419 Lit(ExprId), 420 Lit(ExprId),
420 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> }, 421 Bind { mode: BindingAnnotation, name: Name, subpat: Option<PatId> },
421 TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, 422 TupleStruct { path: Option<Box<Path>>, args: Vec<PatId>, ellipsis: Option<usize> },
422 Ref { pat: PatId, mutability: Mutability }, 423 Ref { pat: PatId, mutability: Mutability },
423 Box { inner: PatId }, 424 Box { inner: PatId },
424 ConstBlock(ExprId), 425 ConstBlock(ExprId),
diff --git a/crates/hir_def/src/find_path.rs b/crates/hir_def/src/find_path.rs
index 109d3552f..dc3f2908f 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -119,8 +119,7 @@ fn find_path_inner(
119 119
120 // - if the item is the crate root, return `crate` 120 // - if the item is the crate root, return `crate`
121 let root = def_map.crate_root(db); 121 let root = def_map.crate_root(db);
122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) && def_map.block_id().is_none() { 122 if item == ItemInNs::Types(ModuleDefId::ModuleId(root)) {
123 // FIXME: the `block_id()` check should be unnecessary, but affects the result
124 return Some(ModPath::from_segments(PathKind::Crate, Vec::new())); 123 return Some(ModPath::from_segments(PathKind::Crate, Vec::new()));
125 } 124 }
126 125
@@ -131,7 +130,7 @@ fn find_path_inner(
131 } 130 }
132 131
133 // - if the item is the crate root of a dependency crate, return the name from the extern prelude 132 // - if the item is the crate root of a dependency crate, return the name from the extern prelude
134 for (name, def_id) in def_map.extern_prelude() { 133 for (name, def_id) in root.def_map(db).extern_prelude() {
135 if item == ItemInNs::Types(*def_id) { 134 if item == ItemInNs::Types(*def_id) {
136 let name = scope_name.unwrap_or_else(|| name.clone()); 135 let name = scope_name.unwrap_or_else(|| name.clone());
137 return Some(ModPath::from_segments(PathKind::Plain, vec![name])); 136 return Some(ModPath::from_segments(PathKind::Plain, vec![name]));
@@ -298,6 +297,7 @@ fn find_local_import_locations(
298 let data = &def_map[from.local_id]; 297 let data = &def_map[from.local_id];
299 let mut worklist = 298 let mut worklist =
300 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>(); 299 data.children.values().map(|child| def_map.module_id(*child)).collect::<Vec<_>>();
300 // FIXME: do we need to traverse out of block expressions here?
301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) { 301 for ancestor in iter::successors(from.containing_module(db), |m| m.containing_module(db)) {
302 worklist.push(ancestor); 302 worklist.push(ancestor);
303 } 303 }
@@ -425,106 +425,142 @@ mod tests {
425 425
426 #[test] 426 #[test]
427 fn same_module() { 427 fn same_module() {
428 let code = r#" 428 check_found_path(
429 //- /main.rs 429 r#"
430 struct S; 430struct S;
431 $0 431$0
432 "#; 432 "#,
433 check_found_path(code, "S", "S", "crate::S", "self::S"); 433 "S",
434 "S",
435 "crate::S",
436 "self::S",
437 );
434 } 438 }
435 439
436 #[test] 440 #[test]
437 fn enum_variant() { 441 fn enum_variant() {
438 let code = r#" 442 check_found_path(
439 //- /main.rs 443 r#"
440 enum E { A } 444enum E { A }
441 $0 445$0
442 "#; 446 "#,
443 check_found_path(code, "E::A", "E::A", "E::A", "E::A"); 447 "E::A",
448 "E::A",
449 "E::A",
450 "E::A",
451 );
444 } 452 }
445 453
446 #[test] 454 #[test]
447 fn sub_module() { 455 fn sub_module() {
448 let code = r#" 456 check_found_path(
449 //- /main.rs 457 r#"
450 mod foo { 458mod foo {
451 pub struct S; 459 pub struct S;
452 } 460}
453 $0 461$0
454 "#; 462 "#,
455 check_found_path(code, "foo::S", "foo::S", "crate::foo::S", "self::foo::S"); 463 "foo::S",
464 "foo::S",
465 "crate::foo::S",
466 "self::foo::S",
467 );
456 } 468 }
457 469
458 #[test] 470 #[test]
459 fn super_module() { 471 fn super_module() {
460 let code = r#" 472 check_found_path(
461 //- /main.rs 473 r#"
462 mod foo; 474//- /main.rs
463 //- /foo.rs 475mod foo;
464 mod bar; 476//- /foo.rs
465 struct S; 477mod bar;
466 //- /foo/bar.rs 478struct S;
467 $0 479//- /foo/bar.rs
468 "#; 480$0
469 check_found_path(code, "super::S", "super::S", "crate::foo::S", "super::S"); 481 "#,
482 "super::S",
483 "super::S",
484 "crate::foo::S",
485 "super::S",
486 );
470 } 487 }
471 488
472 #[test] 489 #[test]
473 fn self_module() { 490 fn self_module() {
474 let code = r#" 491 check_found_path(
475 //- /main.rs 492 r#"
476 mod foo; 493//- /main.rs
477 //- /foo.rs 494mod foo;
478 $0 495//- /foo.rs
479 "#; 496$0
480 check_found_path(code, "self", "self", "crate::foo", "self"); 497 "#,
498 "self",
499 "self",
500 "crate::foo",
501 "self",
502 );
481 } 503 }
482 504
483 #[test] 505 #[test]
484 fn crate_root() { 506 fn crate_root() {
485 let code = r#" 507 check_found_path(
486 //- /main.rs 508 r#"
487 mod foo; 509//- /main.rs
488 //- /foo.rs 510mod foo;
489 $0 511//- /foo.rs
490 "#; 512$0
491 check_found_path(code, "crate", "crate", "crate", "crate"); 513 "#,
514 "crate",
515 "crate",
516 "crate",
517 "crate",
518 );
492 } 519 }
493 520
494 #[test] 521 #[test]
495 fn same_crate() { 522 fn same_crate() {
496 let code = r#" 523 check_found_path(
497 //- /main.rs 524 r#"
498 mod foo; 525//- /main.rs
499 struct S; 526mod foo;
500 //- /foo.rs 527struct S;
501 $0 528//- /foo.rs
502 "#; 529$0
503 check_found_path(code, "crate::S", "crate::S", "crate::S", "crate::S"); 530 "#,
531 "crate::S",
532 "crate::S",
533 "crate::S",
534 "crate::S",
535 );
504 } 536 }
505 537
506 #[test] 538 #[test]
507 fn different_crate() { 539 fn different_crate() {
508 let code = r#" 540 check_found_path(
509 //- /main.rs crate:main deps:std 541 r#"
510 $0 542//- /main.rs crate:main deps:std
511 //- /std.rs crate:std 543$0
512 pub struct S; 544//- /std.rs crate:std
513 "#; 545pub struct S;
514 check_found_path(code, "std::S", "std::S", "std::S", "std::S"); 546 "#,
547 "std::S",
548 "std::S",
549 "std::S",
550 "std::S",
551 );
515 } 552 }
516 553
517 #[test] 554 #[test]
518 fn different_crate_renamed() { 555 fn different_crate_renamed() {
519 let code = r#"
520 //- /main.rs crate:main deps:std
521 extern crate std as std_renamed;
522 $0
523 //- /std.rs crate:std
524 pub struct S;
525 "#;
526 check_found_path( 556 check_found_path(
527 code, 557 r#"
558//- /main.rs crate:main deps:std
559extern crate std as std_renamed;
560$0
561//- /std.rs crate:std
562pub struct S;
563 "#,
528 "std_renamed::S", 564 "std_renamed::S",
529 "std_renamed::S", 565 "std_renamed::S",
530 "std_renamed::S", 566 "std_renamed::S",
@@ -537,41 +573,38 @@ mod tests {
537 cov_mark::check!(partially_imported); 573 cov_mark::check!(partially_imported);
538 // Tests that short paths are used even for external items, when parts of the path are 574 // Tests that short paths are used even for external items, when parts of the path are
539 // already in scope. 575 // already in scope.
540 let code = r#" 576 check_found_path(
541 //- /main.rs crate:main deps:syntax 577 r#"
578//- /main.rs crate:main deps:syntax
542 579
543 use syntax::ast; 580use syntax::ast;
544 $0 581$0
545 582
546 //- /lib.rs crate:syntax 583//- /lib.rs crate:syntax
547 pub mod ast { 584pub mod ast {
548 pub enum ModuleItem { 585 pub enum ModuleItem {
549 A, B, C, 586 A, B, C,
550 } 587 }
551 } 588}
552 "#; 589 "#,
553 check_found_path(
554 code,
555 "ast::ModuleItem", 590 "ast::ModuleItem",
556 "syntax::ast::ModuleItem", 591 "syntax::ast::ModuleItem",
557 "syntax::ast::ModuleItem", 592 "syntax::ast::ModuleItem",
558 "syntax::ast::ModuleItem", 593 "syntax::ast::ModuleItem",
559 ); 594 );
560 595
561 let code = r#"
562 //- /main.rs crate:main deps:syntax
563
564 $0
565
566 //- /lib.rs crate:syntax
567 pub mod ast {
568 pub enum ModuleItem {
569 A, B, C,
570 }
571 }
572 "#;
573 check_found_path( 596 check_found_path(
574 code, 597 r#"
598//- /main.rs crate:main deps:syntax
599$0
600
601//- /lib.rs crate:syntax
602pub mod ast {
603 pub enum ModuleItem {
604 A, B, C,
605 }
606}
607 "#,
575 "syntax::ast::ModuleItem", 608 "syntax::ast::ModuleItem",
576 "syntax::ast::ModuleItem", 609 "syntax::ast::ModuleItem",
577 "syntax::ast::ModuleItem", 610 "syntax::ast::ModuleItem",
@@ -581,68 +614,86 @@ mod tests {
581 614
582 #[test] 615 #[test]
583 fn same_crate_reexport() { 616 fn same_crate_reexport() {
584 let code = r#" 617 check_found_path(
585 //- /main.rs 618 r#"
586 mod bar { 619mod bar {
587 mod foo { pub(super) struct S; } 620 mod foo { pub(super) struct S; }
588 pub(crate) use foo::*; 621 pub(crate) use foo::*;
589 } 622}
590 $0 623$0
591 "#; 624 "#,
592 check_found_path(code, "bar::S", "bar::S", "crate::bar::S", "self::bar::S"); 625 "bar::S",
626 "bar::S",
627 "crate::bar::S",
628 "self::bar::S",
629 );
593 } 630 }
594 631
595 #[test] 632 #[test]
596 fn same_crate_reexport_rename() { 633 fn same_crate_reexport_rename() {
597 let code = r#" 634 check_found_path(
598 //- /main.rs 635 r#"
599 mod bar { 636mod bar {
600 mod foo { pub(super) struct S; } 637 mod foo { pub(super) struct S; }
601 pub(crate) use foo::S as U; 638 pub(crate) use foo::S as U;
602 } 639}
603 $0 640$0
604 "#; 641 "#,
605 check_found_path(code, "bar::U", "bar::U", "crate::bar::U", "self::bar::U"); 642 "bar::U",
643 "bar::U",
644 "crate::bar::U",
645 "self::bar::U",
646 );
606 } 647 }
607 648
608 #[test] 649 #[test]
609 fn different_crate_reexport() { 650 fn different_crate_reexport() {
610 let code = r#" 651 check_found_path(
611 //- /main.rs crate:main deps:std 652 r#"
612 $0 653//- /main.rs crate:main deps:std
613 //- /std.rs crate:std deps:core 654$0
614 pub use core::S; 655//- /std.rs crate:std deps:core
615 //- /core.rs crate:core 656pub use core::S;
616 pub struct S; 657//- /core.rs crate:core
617 "#; 658pub struct S;
618 check_found_path(code, "std::S", "std::S", "std::S", "std::S"); 659 "#,
660 "std::S",
661 "std::S",
662 "std::S",
663 "std::S",
664 );
619 } 665 }
620 666
621 #[test] 667 #[test]
622 fn prelude() { 668 fn prelude() {
623 let code = r#" 669 check_found_path(
624 //- /main.rs crate:main deps:std 670 r#"
625 $0 671//- /main.rs crate:main deps:std
626 //- /std.rs crate:std 672$0
627 pub mod prelude { pub struct S; } 673//- /std.rs crate:std
628 #[prelude_import] 674pub mod prelude { pub struct S; }
629 pub use prelude::*; 675#[prelude_import]
630 "#; 676pub use prelude::*;
631 check_found_path(code, "S", "S", "S", "S"); 677 "#,
678 "S",
679 "S",
680 "S",
681 "S",
682 );
632 } 683 }
633 684
634 #[test] 685 #[test]
635 fn enum_variant_from_prelude() { 686 fn enum_variant_from_prelude() {
636 let code = r#" 687 let code = r#"
637 //- /main.rs crate:main deps:std 688//- /main.rs crate:main deps:std
638 $0 689$0
639 //- /std.rs crate:std 690//- /std.rs crate:std
640 pub mod prelude { 691pub mod prelude {
641 pub enum Option<T> { Some(T), None } 692 pub enum Option<T> { Some(T), None }
642 pub use Option::*; 693 pub use Option::*;
643 } 694}
644 #[prelude_import] 695#[prelude_import]
645 pub use prelude::*; 696pub use prelude::*;
646 "#; 697 "#;
647 check_found_path(code, "None", "None", "None", "None"); 698 check_found_path(code, "None", "None", "None", "None");
648 check_found_path(code, "Some", "Some", "Some", "Some"); 699 check_found_path(code, "Some", "Some", "Some", "Some");
@@ -650,71 +701,85 @@ mod tests {
650 701
651 #[test] 702 #[test]
652 fn shortest_path() { 703 fn shortest_path() {
653 let code = r#" 704 check_found_path(
654 //- /main.rs 705 r#"
655 pub mod foo; 706//- /main.rs
656 pub mod baz; 707pub mod foo;
657 struct S; 708pub mod baz;
658 $0 709struct S;
659 //- /foo.rs 710$0
660 pub mod bar { pub struct S; } 711//- /foo.rs
661 //- /baz.rs 712pub mod bar { pub struct S; }
662 pub use crate::foo::bar::S; 713//- /baz.rs
663 "#; 714pub use crate::foo::bar::S;
664 check_found_path(code, "baz::S", "baz::S", "crate::baz::S", "self::baz::S"); 715 "#,
716 "baz::S",
717 "baz::S",
718 "crate::baz::S",
719 "self::baz::S",
720 );
665 } 721 }
666 722
667 #[test] 723 #[test]
668 fn discount_private_imports() { 724 fn discount_private_imports() {
669 let code = r#" 725 check_found_path(
670 //- /main.rs 726 r#"
671 mod foo; 727//- /main.rs
672 pub mod bar { pub struct S; } 728mod foo;
673 use bar::S; 729pub mod bar { pub struct S; }
674 //- /foo.rs 730use bar::S;
675 $0 731//- /foo.rs
676 "#; 732$0
677 // crate::S would be shorter, but using private imports seems wrong 733 "#,
678 check_found_path(code, "crate::bar::S", "crate::bar::S", "crate::bar::S", "crate::bar::S"); 734 // crate::S would be shorter, but using private imports seems wrong
735 "crate::bar::S",
736 "crate::bar::S",
737 "crate::bar::S",
738 "crate::bar::S",
739 );
679 } 740 }
680 741
681 #[test] 742 #[test]
682 fn import_cycle() { 743 fn import_cycle() {
683 let code = r#" 744 check_found_path(
684 //- /main.rs 745 r#"
685 pub mod foo; 746//- /main.rs
686 pub mod bar; 747pub mod foo;
687 pub mod baz; 748pub mod bar;
688 //- /bar.rs 749pub mod baz;
689 $0 750//- /bar.rs
690 //- /foo.rs 751$0
691 pub use super::baz; 752//- /foo.rs
692 pub struct S; 753pub use super::baz;
693 //- /baz.rs 754pub struct S;
694 pub use super::foo; 755//- /baz.rs
695 "#; 756pub use super::foo;
696 check_found_path(code, "crate::foo::S", "crate::foo::S", "crate::foo::S", "crate::foo::S"); 757 "#,
758 "crate::foo::S",
759 "crate::foo::S",
760 "crate::foo::S",
761 "crate::foo::S",
762 );
697 } 763 }
698 764
699 #[test] 765 #[test]
700 fn prefer_std_paths_over_alloc() { 766 fn prefer_std_paths_over_alloc() {
701 cov_mark::check!(prefer_std_paths); 767 cov_mark::check!(prefer_std_paths);
702 let code = r#" 768 check_found_path(
703 //- /main.rs crate:main deps:alloc,std 769 r#"
704 $0 770//- /main.rs crate:main deps:alloc,std
771$0
705 772
706 //- /std.rs crate:std deps:alloc 773//- /std.rs crate:std deps:alloc
707 pub mod sync { 774pub mod sync {
708 pub use alloc::sync::Arc; 775 pub use alloc::sync::Arc;
709 } 776}
710 777
711 //- /zzz.rs crate:alloc 778//- /zzz.rs crate:alloc
712 pub mod sync { 779pub mod sync {
713 pub struct Arc; 780 pub struct Arc;
714 } 781}
715 "#; 782 "#,
716 check_found_path(
717 code,
718 "std::sync::Arc", 783 "std::sync::Arc",
719 "std::sync::Arc", 784 "std::sync::Arc",
720 "std::sync::Arc", 785 "std::sync::Arc",
@@ -725,26 +790,25 @@ mod tests {
725 #[test] 790 #[test]
726 fn prefer_core_paths_over_std() { 791 fn prefer_core_paths_over_std() {
727 cov_mark::check!(prefer_no_std_paths); 792 cov_mark::check!(prefer_no_std_paths);
728 let code = r#" 793 check_found_path(
729 //- /main.rs crate:main deps:core,std 794 r#"
730 #![no_std] 795//- /main.rs crate:main deps:core,std
796#![no_std]
731 797
732 $0 798$0
733 799
734 //- /std.rs crate:std deps:core 800//- /std.rs crate:std deps:core
735 801
736 pub mod fmt { 802pub mod fmt {
737 pub use core::fmt::Error; 803 pub use core::fmt::Error;
738 } 804}
739 805
740 //- /zzz.rs crate:core 806//- /zzz.rs crate:core
741 807
742 pub mod fmt { 808pub mod fmt {
743 pub struct Error; 809 pub struct Error;
744 } 810}
745 "#; 811 "#,
746 check_found_path(
747 code,
748 "core::fmt::Error", 812 "core::fmt::Error",
749 "core::fmt::Error", 813 "core::fmt::Error",
750 "core::fmt::Error", 814 "core::fmt::Error",
@@ -754,26 +818,25 @@ mod tests {
754 818
755 #[test] 819 #[test]
756 fn prefer_alloc_paths_over_std() { 820 fn prefer_alloc_paths_over_std() {
757 let code = r#" 821 check_found_path(
758 //- /main.rs crate:main deps:alloc,std 822 r#"
759 #![no_std] 823//- /main.rs crate:main deps:alloc,std
824#![no_std]
760 825
761 $0 826$0
762 827
763 //- /std.rs crate:std deps:alloc 828//- /std.rs crate:std deps:alloc
764 829
765 pub mod sync { 830pub mod sync {
766 pub use alloc::sync::Arc; 831 pub use alloc::sync::Arc;
767 } 832}
768 833
769 //- /zzz.rs crate:alloc 834//- /zzz.rs crate:alloc
770 835
771 pub mod sync { 836pub mod sync {
772 pub struct Arc; 837 pub struct Arc;
773 } 838}
774 "#; 839 "#,
775 check_found_path(
776 code,
777 "alloc::sync::Arc", 840 "alloc::sync::Arc",
778 "alloc::sync::Arc", 841 "alloc::sync::Arc",
779 "alloc::sync::Arc", 842 "alloc::sync::Arc",
@@ -783,20 +846,19 @@ mod tests {
783 846
784 #[test] 847 #[test]
785 fn prefer_shorter_paths_if_not_alloc() { 848 fn prefer_shorter_paths_if_not_alloc() {
786 let code = r#" 849 check_found_path(
787 //- /main.rs crate:main deps:megaalloc,std 850 r#"
788 $0 851//- /main.rs crate:main deps:megaalloc,std
852$0
789 853
790 //- /std.rs crate:std deps:megaalloc 854//- /std.rs crate:std deps:megaalloc
791 pub mod sync { 855pub mod sync {
792 pub use megaalloc::sync::Arc; 856 pub use megaalloc::sync::Arc;
793 } 857}
794 858
795 //- /zzz.rs crate:megaalloc 859//- /zzz.rs crate:megaalloc
796 pub struct Arc; 860pub struct Arc;
797 "#; 861 "#,
798 check_found_path(
799 code,
800 "megaalloc::Arc", 862 "megaalloc::Arc",
801 "megaalloc::Arc", 863 "megaalloc::Arc",
802 "megaalloc::Arc", 864 "megaalloc::Arc",
@@ -807,12 +869,11 @@ mod tests {
807 #[test] 869 #[test]
808 fn builtins_are_in_scope() { 870 fn builtins_are_in_scope() {
809 let code = r#" 871 let code = r#"
810 //- /main.rs 872$0
811 $0
812 873
813 pub mod primitive { 874pub mod primitive {
814 pub use u8; 875 pub use u8;
815 } 876}
816 "#; 877 "#;
817 check_found_path(code, "u8", "u8", "u8", "u8"); 878 check_found_path(code, "u8", "u8", "u8", "u8");
818 check_found_path(code, "u16", "u16", "u16", "u16"); 879 check_found_path(code, "u16", "u16", "u16", "u16");
@@ -822,10 +883,10 @@ mod tests {
822 fn inner_items() { 883 fn inner_items() {
823 check_found_path( 884 check_found_path(
824 r#" 885 r#"
825 fn main() { 886fn main() {
826 struct Inner {} 887 struct Inner {}
827 $0 888 $0
828 } 889}
829 "#, 890 "#,
830 "Inner", 891 "Inner",
831 "Inner", 892 "Inner",
@@ -838,12 +899,12 @@ mod tests {
838 fn inner_items_from_outer_scope() { 899 fn inner_items_from_outer_scope() {
839 check_found_path( 900 check_found_path(
840 r#" 901 r#"
841 fn main() { 902fn main() {
842 struct Struct {} 903 struct Struct {}
843 { 904 {
844 $0 905 $0
845 } 906 }
846 } 907}
847 "#, 908 "#,
848 "Struct", 909 "Struct",
849 "Struct", 910 "Struct",
@@ -857,14 +918,14 @@ mod tests {
857 cov_mark::check!(prefixed_in_block_expression); 918 cov_mark::check!(prefixed_in_block_expression);
858 check_found_path( 919 check_found_path(
859 r#" 920 r#"
860 fn main() { 921fn main() {
861 mod module { 922 mod module {
862 struct Struct {} 923 struct Struct {}
863 } 924 }
864 { 925 {
865 $0 926 $0
866 } 927 }
867 } 928}
868 "#, 929 "#,
869 "module::Struct", 930 "module::Struct",
870 "module::Struct", 931 "module::Struct",
@@ -877,19 +938,65 @@ mod tests {
877 fn outer_items_with_inner_items_present() { 938 fn outer_items_with_inner_items_present() {
878 check_found_path( 939 check_found_path(
879 r#" 940 r#"
880 mod module { 941mod module {
881 pub struct CompleteMe; 942 pub struct CompleteMe;
882 } 943}
883 944
884 fn main() { 945fn main() {
885 fn inner() {} 946 fn inner() {}
886 $0 947 $0
887 } 948}
888 "#, 949 "#,
950 // FIXME: these could use fewer/better prefixes
889 "module::CompleteMe", 951 "module::CompleteMe",
890 "module::CompleteMe",
891 "crate::module::CompleteMe", 952 "crate::module::CompleteMe",
892 "self::module::CompleteMe", 953 "crate::module::CompleteMe",
954 "crate::module::CompleteMe",
955 )
956 }
957
958 #[test]
959 fn from_inside_module() {
960 // This worked correctly, but the test suite logic was broken.
961 cov_mark::check!(submodule_in_testdb);
962 check_found_path(
963 r#"
964mod baz {
965 pub struct Foo {}
966}
967
968mod bar {
969 fn bar() {
970 $0
971 }
972}
973 "#,
974 "crate::baz::Foo",
975 "crate::baz::Foo",
976 "crate::baz::Foo",
977 "crate::baz::Foo",
978 )
979 }
980
981 #[test]
982 fn from_inside_module_with_inner_items() {
983 check_found_path(
984 r#"
985mod baz {
986 pub struct Foo {}
987}
988
989mod bar {
990 fn bar() {
991 fn inner() {}
992 $0
993 }
994}
995 "#,
996 "crate::baz::Foo",
997 "crate::baz::Foo",
998 "crate::baz::Foo",
999 "crate::baz::Foo",
893 ) 1000 )
894 } 1001 }
895 1002
@@ -920,4 +1027,34 @@ pub mod name {
920 "self::name::AsName", 1027 "self::name::AsName",
921 ); 1028 );
922 } 1029 }
1030
1031 #[test]
1032 fn extern_crate() {
1033 check_found_path(
1034 r#"
1035//- /main.rs crate:main deps:dep
1036$0
1037//- /dep.rs crate:dep
1038"#,
1039 "dep",
1040 "dep",
1041 "dep",
1042 "dep",
1043 );
1044
1045 check_found_path(
1046 r#"
1047//- /main.rs crate:main deps:dep
1048fn f() {
1049 fn inner() {}
1050 $0
1051}
1052//- /dep.rs crate:dep
1053"#,
1054 "dep",
1055 "dep",
1056 "dep",
1057 "dep",
1058 );
1059 }
923} 1060}
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 7c6cbff11..de5acced8 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -2,7 +2,6 @@
2//! structs, impls, traits, etc. This module provides a common HIR for these 2//! structs, impls, traits, etc. This module provides a common HIR for these
3//! generic parameters. See also the `Generics` type and the `generics_of` query 3//! generic parameters. See also the `Generics` type and the `generics_of` query
4//! in rustc. 4//! in rustc.
5use std::sync::Arc;
6 5
7use base_db::FileId; 6use base_db::FileId;
8use either::Either; 7use either::Either;
@@ -18,6 +17,7 @@ use crate::{
18 child_by_source::ChildBySource, 17 child_by_source::ChildBySource,
19 db::DefDatabase, 18 db::DefDatabase,
20 dyn_map::DynMap, 19 dyn_map::DynMap,
20 intern::Interned,
21 keys, 21 keys,
22 src::{HasChildSource, HasSource}, 22 src::{HasChildSource, HasSource},
23 type_ref::{LifetimeRef, TypeBound, TypeRef}, 23 type_ref::{LifetimeRef, TypeBound, TypeRef},
@@ -26,27 +26,27 @@ use crate::{
26}; 26};
27 27
28/// Data about a generic type parameter (to a function, struct, impl, ...). 28/// Data about a generic type parameter (to a function, struct, impl, ...).
29#[derive(Clone, PartialEq, Eq, Debug)] 29#[derive(Clone, PartialEq, Eq, Debug, Hash)]
30pub struct TypeParamData { 30pub struct TypeParamData {
31 pub name: Option<Name>, 31 pub name: Option<Name>,
32 pub default: Option<TypeRef>, 32 pub default: Option<Interned<TypeRef>>,
33 pub provenance: TypeParamProvenance, 33 pub provenance: TypeParamProvenance,
34} 34}
35 35
36/// Data about a generic lifetime parameter (to a function, struct, impl, ...). 36/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
37#[derive(Clone, PartialEq, Eq, Debug)] 37#[derive(Clone, PartialEq, Eq, Debug, Hash)]
38pub struct LifetimeParamData { 38pub struct LifetimeParamData {
39 pub name: Name, 39 pub name: Name,
40} 40}
41 41
42/// Data about a generic const parameter (to a function, struct, impl, ...). 42/// Data about a generic const parameter (to a function, struct, impl, ...).
43#[derive(Clone, PartialEq, Eq, Debug)] 43#[derive(Clone, PartialEq, Eq, Debug, Hash)]
44pub struct ConstParamData { 44pub struct ConstParamData {
45 pub name: Name, 45 pub name: Name,
46 pub ty: TypeRef, 46 pub ty: Interned<TypeRef>,
47} 47}
48 48
49#[derive(Copy, Clone, PartialEq, Eq, Debug)] 49#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
50pub enum TypeParamProvenance { 50pub enum TypeParamProvenance {
51 TypeParamList, 51 TypeParamList,
52 TraitSelf, 52 TraitSelf,
@@ -54,7 +54,7 @@ pub enum TypeParamProvenance {
54} 54}
55 55
56/// Data about the generic parameters of a function, struct, impl, etc. 56/// Data about the generic parameters of a function, struct, impl, etc.
57#[derive(Clone, PartialEq, Eq, Debug, Default)] 57#[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
58pub struct GenericParams { 58pub struct GenericParams {
59 pub types: Arena<TypeParamData>, 59 pub types: Arena<TypeParamData>,
60 pub lifetimes: Arena<LifetimeParamData>, 60 pub lifetimes: Arena<LifetimeParamData>,
@@ -66,16 +66,16 @@ pub struct GenericParams {
66/// where clauses like `where T: Foo + Bar` are turned into multiple of these. 66/// where clauses like `where T: Foo + Bar` are turned into multiple of these.
67/// It might still result in multiple actual predicates though, because of 67/// It might still result in multiple actual predicates though, because of
68/// associated type bindings like `Iterator<Item = u32>`. 68/// associated type bindings like `Iterator<Item = u32>`.
69#[derive(Clone, PartialEq, Eq, Debug)] 69#[derive(Clone, PartialEq, Eq, Debug, Hash)]
70pub enum WherePredicate { 70pub enum WherePredicate {
71 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound }, 71 TypeBound { target: WherePredicateTypeTarget, bound: TypeBound },
72 Lifetime { target: LifetimeRef, bound: LifetimeRef }, 72 Lifetime { target: LifetimeRef, bound: LifetimeRef },
73 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound }, 73 ForLifetime { lifetimes: Box<[Name]>, target: WherePredicateTypeTarget, bound: TypeBound },
74} 74}
75 75
76#[derive(Clone, PartialEq, Eq, Debug)] 76#[derive(Clone, PartialEq, Eq, Debug, Hash)]
77pub enum WherePredicateTypeTarget { 77pub enum WherePredicateTypeTarget {
78 TypeRef(TypeRef), 78 TypeRef(Interned<TypeRef>),
79 /// For desugared where predicates that can directly refer to a type param. 79 /// For desugared where predicates that can directly refer to a type param.
80 TypeParam(LocalTypeParamId), 80 TypeParam(LocalTypeParamId),
81} 81}
@@ -91,7 +91,7 @@ impl GenericParams {
91 pub(crate) fn generic_params_query( 91 pub(crate) fn generic_params_query(
92 db: &dyn DefDatabase, 92 db: &dyn DefDatabase,
93 def: GenericDefId, 93 def: GenericDefId,
94 ) -> Arc<GenericParams> { 94 ) -> Interned<GenericParams> {
95 let _p = profile::span("generic_params_query"); 95 let _p = profile::span("generic_params_query");
96 96
97 let generics = match def { 97 let generics = match def {
@@ -99,47 +99,49 @@ impl GenericParams {
99 let id = id.lookup(db).id; 99 let id = id.lookup(db).id;
100 let tree = id.item_tree(db); 100 let tree = id.item_tree(db);
101 let item = &tree[id.value]; 101 let item = &tree[id.value];
102 tree[item.generic_params].clone() 102 item.generic_params.clone()
103 } 103 }
104 GenericDefId::AdtId(AdtId::StructId(id)) => { 104 GenericDefId::AdtId(AdtId::StructId(id)) => {
105 let id = id.lookup(db).id; 105 let id = id.lookup(db).id;
106 let tree = id.item_tree(db); 106 let tree = id.item_tree(db);
107 let item = &tree[id.value]; 107 let item = &tree[id.value];
108 tree[item.generic_params].clone() 108 item.generic_params.clone()
109 } 109 }
110 GenericDefId::AdtId(AdtId::EnumId(id)) => { 110 GenericDefId::AdtId(AdtId::EnumId(id)) => {
111 let id = id.lookup(db).id; 111 let id = id.lookup(db).id;
112 let tree = id.item_tree(db); 112 let tree = id.item_tree(db);
113 let item = &tree[id.value]; 113 let item = &tree[id.value];
114 tree[item.generic_params].clone() 114 item.generic_params.clone()
115 } 115 }
116 GenericDefId::AdtId(AdtId::UnionId(id)) => { 116 GenericDefId::AdtId(AdtId::UnionId(id)) => {
117 let id = id.lookup(db).id; 117 let id = id.lookup(db).id;
118 let tree = id.item_tree(db); 118 let tree = id.item_tree(db);
119 let item = &tree[id.value]; 119 let item = &tree[id.value];
120 tree[item.generic_params].clone() 120 item.generic_params.clone()
121 } 121 }
122 GenericDefId::TraitId(id) => { 122 GenericDefId::TraitId(id) => {
123 let id = id.lookup(db).id; 123 let id = id.lookup(db).id;
124 let tree = id.item_tree(db); 124 let tree = id.item_tree(db);
125 let item = &tree[id.value]; 125 let item = &tree[id.value];
126 tree[item.generic_params].clone() 126 item.generic_params.clone()
127 } 127 }
128 GenericDefId::TypeAliasId(id) => { 128 GenericDefId::TypeAliasId(id) => {
129 let id = id.lookup(db).id; 129 let id = id.lookup(db).id;
130 let tree = id.item_tree(db); 130 let tree = id.item_tree(db);
131 let item = &tree[id.value]; 131 let item = &tree[id.value];
132 tree[item.generic_params].clone() 132 item.generic_params.clone()
133 } 133 }
134 GenericDefId::ImplId(id) => { 134 GenericDefId::ImplId(id) => {
135 let id = id.lookup(db).id; 135 let id = id.lookup(db).id;
136 let tree = id.item_tree(db); 136 let tree = id.item_tree(db);
137 let item = &tree[id.value]; 137 let item = &tree[id.value];
138 tree[item.generic_params].clone() 138 item.generic_params.clone()
139 }
140 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => {
141 Interned::new(GenericParams::default())
139 } 142 }
140 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => GenericParams::default(),
141 }; 143 };
142 Arc::new(generics) 144 generics
143 } 145 }
144 146
145 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { 147 fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) {
@@ -217,6 +219,7 @@ impl GenericParams {
217 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(), 219 GenericDefId::EnumVariantId(_) | GenericDefId::ConstId(_) => FileId(!0).into(),
218 }; 220 };
219 221
222 generics.shrink_to_fit();
220 (generics, InFile::new(file_id, sm)) 223 (generics, InFile::new(file_id, sm))
221 } 224 }
222 225
@@ -256,7 +259,8 @@ impl GenericParams {
256 for type_param in params.type_params() { 259 for type_param in params.type_params() {
257 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); 260 let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
258 // FIXME: Use `Path::from_src` 261 // FIXME: Use `Path::from_src`
259 let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); 262 let default =
263 type_param.default_type().map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
260 let param = TypeParamData { 264 let param = TypeParamData {
261 name: Some(name.clone()), 265 name: Some(name.clone()),
262 default, 266 default,
@@ -280,7 +284,7 @@ impl GenericParams {
280 for const_param in params.const_params() { 284 for const_param in params.const_params() {
281 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name()); 285 let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
282 let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it)); 286 let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
283 let param = ConstParamData { name, ty }; 287 let param = ConstParamData { name, ty: Interned::new(ty) };
284 let param_id = self.consts.alloc(param); 288 let param_id = self.consts.alloc(param);
285 sm.const_params.insert(param_id, const_param.clone()); 289 sm.const_params.insert(param_id, const_param.clone());
286 } 290 }
@@ -334,11 +338,11 @@ impl GenericParams {
334 (Either::Left(type_ref), bound) => match hrtb_lifetimes { 338 (Either::Left(type_ref), bound) => match hrtb_lifetimes {
335 Some(hrtb_lifetimes) => WherePredicate::ForLifetime { 339 Some(hrtb_lifetimes) => WherePredicate::ForLifetime {
336 lifetimes: hrtb_lifetimes.clone(), 340 lifetimes: hrtb_lifetimes.clone(),
337 target: WherePredicateTypeTarget::TypeRef(type_ref), 341 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
338 bound, 342 bound,
339 }, 343 },
340 None => WherePredicate::TypeBound { 344 None => WherePredicate::TypeBound {
341 target: WherePredicateTypeTarget::TypeRef(type_ref), 345 target: WherePredicateTypeTarget::TypeRef(Interned::new(type_ref)),
342 bound, 346 bound,
343 }, 347 },
344 }, 348 },
@@ -369,6 +373,14 @@ impl GenericParams {
369 }); 373 });
370 } 374 }
371 375
376 pub(crate) fn shrink_to_fit(&mut self) {
377 let Self { consts, lifetimes, types, where_predicates } = self;
378 consts.shrink_to_fit();
379 lifetimes.shrink_to_fit();
380 types.shrink_to_fit();
381 where_predicates.shrink_to_fit();
382 }
383
372 pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> { 384 pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
373 self.types 385 self.types
374 .iter() 386 .iter()
diff --git a/crates/hir_def/src/intern.rs b/crates/hir_def/src/intern.rs
index d163f633f..abc304ef0 100644
--- a/crates/hir_def/src/intern.rs
+++ b/crates/hir_def/src/intern.rs
@@ -5,7 +5,7 @@
5use std::{ 5use std::{
6 collections::HashMap, 6 collections::HashMap,
7 fmt::{self, Debug}, 7 fmt::{self, Debug},
8 hash::{BuildHasherDefault, Hash}, 8 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref, 9 ops::Deref,
10 sync::Arc, 10 sync::Arc,
11}; 11};
@@ -14,11 +14,12 @@ use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
14use once_cell::sync::OnceCell; 14use once_cell::sync::OnceCell;
15use rustc_hash::FxHasher; 15use rustc_hash::FxHasher;
16 16
17use crate::generics::GenericParams;
18
17type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>; 19type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
18type Guard<T> = 20type Guard<T> =
19 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>; 21 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
20 22
21#[derive(Hash)]
22pub struct Interned<T: Internable + ?Sized> { 23pub struct Interned<T: Internable + ?Sized> {
23 arc: Arc<T>, 24 arc: Arc<T>,
24} 25}
@@ -135,6 +136,13 @@ impl PartialEq for Interned<str> {
135 136
136impl Eq for Interned<str> {} 137impl Eq for Interned<str> {}
137 138
139impl<T: Internable + ?Sized> Hash for Interned<T> {
140 fn hash<H: Hasher>(&self, state: &mut H) {
141 // NOTE: Cast disposes vtable pointer / slice/str length.
142 state.write_usize(Arc::as_ptr(&self.arc) as *const () as usize)
143 }
144}
145
138impl<T: Internable + ?Sized> AsRef<T> for Interned<T> { 146impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
139 #[inline] 147 #[inline]
140 fn as_ref(&self) -> &T { 148 fn as_ref(&self) -> &T {
@@ -183,7 +191,10 @@ pub trait Internable: Hash + Eq + 'static {
183 fn storage() -> &'static InternStorage<Self>; 191 fn storage() -> &'static InternStorage<Self>;
184} 192}
185 193
186macro_rules! impl_internable { 194/// Implements `Internable` for a given list of types, making them usable with `Interned`.
195#[macro_export]
196#[doc(hidden)]
197macro_rules! _impl_internable {
187 ( $($t:path),+ $(,)? ) => { $( 198 ( $($t:path),+ $(,)? ) => { $(
188 impl Internable for $t { 199 impl Internable for $t {
189 fn storage() -> &'static InternStorage<Self> { 200 fn storage() -> &'static InternStorage<Self> {
@@ -194,4 +205,12 @@ macro_rules! impl_internable {
194 )+ }; 205 )+ };
195} 206}
196 207
197impl_internable!(crate::type_ref::TypeRef, crate::type_ref::TraitRef, crate::path::ModPath, str); 208pub use crate::_impl_internable as impl_internable;
209
210impl_internable!(
211 crate::type_ref::TypeRef,
212 crate::type_ref::TraitRef,
213 crate::path::ModPath,
214 GenericParams,
215 str,
216);
diff --git a/crates/hir_def/src/item_scope.rs b/crates/hir_def/src/item_scope.rs
index a8ee5eeac..9014468ea 100644
--- a/crates/hir_def/src/item_scope.rs
+++ b/crates/hir_def/src/item_scope.rs
@@ -11,7 +11,7 @@ use rustc_hash::{FxHashMap, FxHashSet};
11use stdx::format_to; 11use stdx::format_to;
12 12
13use crate::{ 13use crate::{
14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ImplId, 14 db::DefDatabase, per_ns::PerNs, visibility::Visibility, AdtId, BuiltinType, ConstId, ImplId,
15 LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId, 15 LocalModuleId, MacroDefId, ModuleDefId, ModuleId, TraitId,
16}; 16};
17 17
@@ -37,6 +37,7 @@ pub struct ItemScope {
37 37
38 defs: Vec<ModuleDefId>, 38 defs: Vec<ModuleDefId>,
39 impls: Vec<ImplId>, 39 impls: Vec<ImplId>,
40 unnamed_consts: Vec<ConstId>,
40 /// Traits imported via `use Trait as _;`. 41 /// Traits imported via `use Trait as _;`.
41 unnamed_trait_imports: FxHashMap<TraitId, Visibility>, 42 unnamed_trait_imports: FxHashMap<TraitId, Visibility>,
42 /// Macros visible in current module in legacy textual scope 43 /// Macros visible in current module in legacy textual scope
@@ -106,6 +107,10 @@ impl ItemScope {
106 .map(|(_, v)| v) 107 .map(|(_, v)| v)
107 } 108 }
108 109
110 pub fn unnamed_consts(&self) -> impl Iterator<Item = ConstId> + '_ {
111 self.unnamed_consts.iter().copied()
112 }
113
109 /// Iterate over all module scoped macros 114 /// Iterate over all module scoped macros
110 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a { 115 pub(crate) fn macros<'a>(&'a self) -> impl Iterator<Item = (&'a Name, MacroDefId)> + 'a {
111 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_))) 116 self.entries().filter_map(|(name, def)| def.take_macros().map(|macro_| (name, macro_)))
@@ -156,6 +161,10 @@ impl ItemScope {
156 self.impls.push(imp) 161 self.impls.push(imp)
157 } 162 }
158 163
164 pub(crate) fn define_unnamed_const(&mut self, konst: ConstId) {
165 self.unnamed_consts.push(konst);
166 }
167
159 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) { 168 pub(crate) fn define_legacy_macro(&mut self, name: Name, mac: MacroDefId) {
160 self.legacy_macros.insert(name, mac); 169 self.legacy_macros.insert(name, mac);
161 } 170 }
@@ -295,6 +304,7 @@ impl ItemScope {
295 unresolved, 304 unresolved,
296 defs, 305 defs,
297 impls, 306 impls,
307 unnamed_consts,
298 unnamed_trait_imports, 308 unnamed_trait_imports,
299 legacy_macros, 309 legacy_macros,
300 } = self; 310 } = self;
@@ -304,6 +314,7 @@ impl ItemScope {
304 unresolved.shrink_to_fit(); 314 unresolved.shrink_to_fit();
305 defs.shrink_to_fit(); 315 defs.shrink_to_fit();
306 impls.shrink_to_fit(); 316 impls.shrink_to_fit();
317 unnamed_consts.shrink_to_fit();
307 unnamed_trait_imports.shrink_to_fit(); 318 unnamed_trait_imports.shrink_to_fit();
308 legacy_macros.shrink_to_fit(); 319 legacy_macros.shrink_to_fit();
309 } 320 }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 739906778..eaeca01bd 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -58,13 +58,6 @@ impl fmt::Debug for RawVisibilityId {
58 } 58 }
59} 59}
60 60
61#[derive(Debug, Copy, Clone, Eq, PartialEq)]
62pub struct GenericParamsId(u32);
63
64impl GenericParamsId {
65 pub const EMPTY: Self = GenericParamsId(u32::max_value());
66}
67
68/// The item tree of a source file. 61/// The item tree of a source file.
69#[derive(Debug, Default, Eq, PartialEq)] 62#[derive(Debug, Default, Eq, PartialEq)]
70pub struct ItemTree { 63pub struct ItemTree {
@@ -106,6 +99,16 @@ impl ItemTree {
106 // items. 99 // items.
107 ctx.lower_macro_stmts(stmts) 100 ctx.lower_macro_stmts(stmts)
108 }, 101 },
102 ast::Pat(_pat) => {
103 // FIXME: This occurs because macros in pattern position are treated as inner
104 // items and expanded during block DefMap computation
105 return Default::default();
106 },
107 ast::Type(ty) => {
108 // Types can contain inner items. We return an empty item tree in this case, but
109 // still need to collect inner items.
110 ctx.lower_inner_items(ty.syntax())
111 },
109 ast::Expr(e) => { 112 ast::Expr(e) => {
110 // Macros can expand to expressions. We return an empty item tree in this case, but 113 // Macros can expand to expressions. We return an empty item tree in this case, but
111 // still need to collect inner items. 114 // still need to collect inner items.
@@ -146,7 +149,6 @@ impl ItemTree {
146 macro_rules, 149 macro_rules,
147 macro_defs, 150 macro_defs,
148 vis, 151 vis,
149 generics,
150 inner_items, 152 inner_items,
151 } = &mut **data; 153 } = &mut **data;
152 154
@@ -170,7 +172,6 @@ impl ItemTree {
170 macro_defs.shrink_to_fit(); 172 macro_defs.shrink_to_fit();
171 173
172 vis.arena.shrink_to_fit(); 174 vis.arena.shrink_to_fit();
173 generics.arena.shrink_to_fit();
174 175
175 inner_items.shrink_to_fit(); 176 inner_items.shrink_to_fit();
176 } 177 }
@@ -195,13 +196,6 @@ impl ItemTree {
195 self.raw_attrs(of).clone().filter(db, krate) 196 self.raw_attrs(of).clone().filter(db, krate)
196 } 197 }
197 198
198 pub fn all_inner_items(&self) -> impl Iterator<Item = ModItem> + '_ {
199 match &self.data {
200 Some(data) => Some(data.inner_items.values().flatten().copied()).into_iter().flatten(),
201 None => None.into_iter().flatten(),
202 }
203 }
204
205 pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] { 199 pub fn inner_items_of_block(&self, block: FileAstId<ast::BlockExpr>) -> &[ModItem] {
206 match &self.data { 200 match &self.data {
207 Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]), 201 Some(data) => data.inner_items.get(&block).map(|it| &**it).unwrap_or(&[]),
@@ -242,32 +236,6 @@ static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKi
242static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); 236static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
243 237
244#[derive(Default, Debug, Eq, PartialEq)] 238#[derive(Default, Debug, Eq, PartialEq)]
245struct GenericParamsStorage {
246 arena: Arena<GenericParams>,
247}
248
249impl GenericParamsStorage {
250 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
251 if params.types.is_empty()
252 && params.lifetimes.is_empty()
253 && params.consts.is_empty()
254 && params.where_predicates.is_empty()
255 {
256 return GenericParamsId::EMPTY;
257 }
258
259 GenericParamsId(self.arena.alloc(params).into_raw().into())
260 }
261}
262
263static EMPTY_GENERICS: GenericParams = GenericParams {
264 types: Arena::new(),
265 lifetimes: Arena::new(),
266 consts: Arena::new(),
267 where_predicates: Vec::new(),
268};
269
270#[derive(Default, Debug, Eq, PartialEq)]
271struct ItemTreeData { 239struct ItemTreeData {
272 imports: Arena<Import>, 240 imports: Arena<Import>,
273 extern_crates: Arena<ExternCrate>, 241 extern_crates: Arena<ExternCrate>,
@@ -289,7 +257,6 @@ struct ItemTreeData {
289 macro_defs: Arena<MacroDef>, 257 macro_defs: Arena<MacroDef>,
290 258
291 vis: ItemVisibilities, 259 vis: ItemVisibilities,
292 generics: GenericParamsStorage,
293 260
294 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, 261 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
295} 262}
@@ -508,17 +475,6 @@ impl Index<RawVisibilityId> for ItemTree {
508 } 475 }
509} 476}
510 477
511impl Index<GenericParamsId> for ItemTree {
512 type Output = GenericParams;
513
514 fn index(&self, index: GenericParamsId) -> &Self::Output {
515 match index {
516 GenericParamsId::EMPTY => &EMPTY_GENERICS,
517 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
518 }
519 }
520}
521
522impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 478impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
523 type Output = N; 479 type Output = N;
524 fn index(&self, id: FileItemTreeId<N>) -> &N { 480 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -555,7 +511,7 @@ pub struct ExternCrate {
555pub struct Function { 511pub struct Function {
556 pub name: Name, 512 pub name: Name,
557 pub visibility: RawVisibilityId, 513 pub visibility: RawVisibilityId,
558 pub generic_params: GenericParamsId, 514 pub generic_params: Interned<GenericParams>,
559 pub abi: Option<Interned<str>>, 515 pub abi: Option<Interned<str>>,
560 pub params: IdRange<Param>, 516 pub params: IdRange<Param>,
561 pub ret_type: Interned<TypeRef>, 517 pub ret_type: Interned<TypeRef>,
@@ -590,7 +546,7 @@ impl FnFlags {
590pub struct Struct { 546pub struct Struct {
591 pub name: Name, 547 pub name: Name,
592 pub visibility: RawVisibilityId, 548 pub visibility: RawVisibilityId,
593 pub generic_params: GenericParamsId, 549 pub generic_params: Interned<GenericParams>,
594 pub fields: Fields, 550 pub fields: Fields,
595 pub ast_id: FileAstId<ast::Struct>, 551 pub ast_id: FileAstId<ast::Struct>,
596 pub kind: StructDefKind, 552 pub kind: StructDefKind,
@@ -610,7 +566,7 @@ pub enum StructDefKind {
610pub struct Union { 566pub struct Union {
611 pub name: Name, 567 pub name: Name,
612 pub visibility: RawVisibilityId, 568 pub visibility: RawVisibilityId,
613 pub generic_params: GenericParamsId, 569 pub generic_params: Interned<GenericParams>,
614 pub fields: Fields, 570 pub fields: Fields,
615 pub ast_id: FileAstId<ast::Union>, 571 pub ast_id: FileAstId<ast::Union>,
616} 572}
@@ -619,7 +575,7 @@ pub struct Union {
619pub struct Enum { 575pub struct Enum {
620 pub name: Name, 576 pub name: Name,
621 pub visibility: RawVisibilityId, 577 pub visibility: RawVisibilityId,
622 pub generic_params: GenericParamsId, 578 pub generic_params: Interned<GenericParams>,
623 pub variants: IdRange<Variant>, 579 pub variants: IdRange<Variant>,
624 pub ast_id: FileAstId<ast::Enum>, 580 pub ast_id: FileAstId<ast::Enum>,
625} 581}
@@ -648,7 +604,7 @@ pub struct Static {
648pub struct Trait { 604pub struct Trait {
649 pub name: Name, 605 pub name: Name,
650 pub visibility: RawVisibilityId, 606 pub visibility: RawVisibilityId,
651 pub generic_params: GenericParamsId, 607 pub generic_params: Interned<GenericParams>,
652 pub is_auto: bool, 608 pub is_auto: bool,
653 pub is_unsafe: bool, 609 pub is_unsafe: bool,
654 pub bounds: Box<[TypeBound]>, 610 pub bounds: Box<[TypeBound]>,
@@ -658,7 +614,7 @@ pub struct Trait {
658 614
659#[derive(Debug, Clone, Eq, PartialEq)] 615#[derive(Debug, Clone, Eq, PartialEq)]
660pub struct Impl { 616pub struct Impl {
661 pub generic_params: GenericParamsId, 617 pub generic_params: Interned<GenericParams>,
662 pub target_trait: Option<Interned<TraitRef>>, 618 pub target_trait: Option<Interned<TraitRef>>,
663 pub self_ty: Interned<TypeRef>, 619 pub self_ty: Interned<TypeRef>,
664 pub is_negative: bool, 620 pub is_negative: bool,
@@ -672,7 +628,7 @@ pub struct TypeAlias {
672 pub visibility: RawVisibilityId, 628 pub visibility: RawVisibilityId,
673 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 629 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
674 pub bounds: Box<[TypeBound]>, 630 pub bounds: Box<[TypeBound]>,
675 pub generic_params: GenericParamsId, 631 pub generic_params: Interned<GenericParams>,
676 pub type_ref: Option<Interned<TypeRef>>, 632 pub type_ref: Option<Interned<TypeRef>>,
677 pub is_extern: bool, 633 pub is_extern: bool,
678 pub ast_id: FileAstId<ast::TypeAlias>, 634 pub ast_id: FileAstId<ast::TypeAlias>,
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index ab7ad8310..45b099cf3 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -189,7 +189,7 @@ impl Ctx {
189 block_stack.push(self.source_ast_id_map.ast_id(&block)); 189 block_stack.push(self.source_ast_id_map.ast_id(&block));
190 }, 190 },
191 ast::Item(item) => { 191 ast::Item(item) => {
192 // FIXME: This triggers for macro calls in expression position 192 // FIXME: This triggers for macro calls in expression/pattern/type position
193 let mod_items = self.lower_mod_item(&item, true); 193 let mod_items = self.lower_mod_item(&item, true);
194 let current_block = block_stack.last(); 194 let current_block = block_stack.last();
195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
@@ -434,7 +434,7 @@ impl Ctx {
434 let mut res = Function { 434 let mut res = Function {
435 name, 435 name,
436 visibility, 436 visibility,
437 generic_params: GenericParamsId::EMPTY, 437 generic_params: Interned::new(GenericParams::default()),
438 abi, 438 abi,
439 params, 439 params,
440 ret_type: Interned::new(ret_type), 440 ret_type: Interned::new(ret_type),
@@ -682,7 +682,7 @@ impl Ctx {
682 &mut self, 682 &mut self,
683 owner: GenericsOwner<'_>, 683 owner: GenericsOwner<'_>,
684 node: &impl ast::GenericParamsOwner, 684 node: &impl ast::GenericParamsOwner,
685 ) -> GenericParamsId { 685 ) -> Interned<GenericParams> {
686 // Generics are part of item headers and may contain inner items we need to collect. 686 // Generics are part of item headers and may contain inner items we need to collect.
687 if let Some(params) = node.generic_param_list() { 687 if let Some(params) = node.generic_param_list() {
688 self.collect_inner_items(params.syntax()); 688 self.collect_inner_items(params.syntax());
@@ -698,7 +698,7 @@ impl Ctx {
698 &mut self, 698 &mut self,
699 owner: GenericsOwner<'_>, 699 owner: GenericsOwner<'_>,
700 node: &impl ast::GenericParamsOwner, 700 node: &impl ast::GenericParamsOwner,
701 ) -> GenericParamsId { 701 ) -> Interned<GenericParams> {
702 let mut sm = &mut Default::default(); 702 let mut sm = &mut Default::default();
703 let mut generics = GenericParams::default(); 703 let mut generics = GenericParams::default();
704 match owner { 704 match owner {
@@ -739,7 +739,8 @@ impl Ctx {
739 } 739 }
740 } 740 }
741 741
742 self.data().generics.alloc(generics) 742 generics.shrink_to_fit();
743 Interned::new(generics)
743 } 744 }
744 745
745 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> { 746 fn lower_type_bounds(&mut self, node: &impl ast::TypeBoundsOwner) -> Vec<TypeBound> {
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index f408e510a..25694f037 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -27,6 +27,7 @@ pub mod dyn_map;
27pub mod keys; 27pub mod keys;
28 28
29pub mod item_tree; 29pub mod item_tree;
30pub mod intern;
30 31
31pub mod adt; 32pub mod adt;
32pub mod data; 33pub mod data;
@@ -49,22 +50,23 @@ pub mod import_map;
49 50
50#[cfg(test)] 51#[cfg(test)]
51mod test_db; 52mod test_db;
52mod intern;
53 53
54use std::{ 54use std::{
55 hash::{Hash, Hasher}, 55 hash::{Hash, Hasher},
56 sync::Arc, 56 sync::Arc,
57}; 57};
58 58
59use adt::VariantData;
59use base_db::{impl_intern_key, salsa, CrateId}; 60use base_db::{impl_intern_key, salsa, CrateId};
60use hir_expand::{ 61use hir_expand::{
61 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
62 eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, 63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
63 hygiene::Hygiene, 64 hygiene::Hygiene,
64 AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 65 AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
65}; 66};
66use la_arena::Idx; 67use la_arena::Idx;
67use nameres::DefMap; 68use nameres::DefMap;
69use path::ModPath;
68use syntax::ast; 70use syntax::ast;
69 71
70use crate::builtin_type::BuiltinType; 72use crate::builtin_type::BuiltinType;
@@ -106,6 +108,18 @@ impl ModuleId {
106 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> { 108 pub fn containing_module(&self, db: &dyn db::DefDatabase) -> Option<ModuleId> {
107 self.def_map(db).containing_module(self.local_id) 109 self.def_map(db).containing_module(self.local_id)
108 } 110 }
111
112 /// Returns `true` if this module represents a block expression.
113 ///
114 /// Returns `false` if this module is a submodule *inside* a block expression
115 /// (eg. `m` in `{ mod m {} }`).
116 pub fn is_block_root(&self, db: &dyn db::DefDatabase) -> bool {
117 if self.block.is_none() {
118 return false;
119 }
120
121 self.def_map(db)[self.local_id].parent.is_none()
122 }
109} 123}
110 124
111/// An ID of a module, **local** to a specific crate 125/// An ID of a module, **local** to a specific crate
@@ -434,6 +448,16 @@ impl_from!(
434 for AttrDefId 448 for AttrDefId
435); 449);
436 450
451impl From<AssocContainerId> for AttrDefId {
452 fn from(acid: AssocContainerId) -> Self {
453 match acid {
454 AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
455 AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
456 AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
457 }
458 }
459}
460
437#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 461#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
438pub enum VariantId { 462pub enum VariantId {
439 EnumVariantId(EnumVariantId), 463 EnumVariantId(EnumVariantId),
@@ -442,6 +466,26 @@ pub enum VariantId {
442} 466}
443impl_from!(EnumVariantId, StructId, UnionId for VariantId); 467impl_from!(EnumVariantId, StructId, UnionId for VariantId);
444 468
469impl VariantId {
470 pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
471 match self {
472 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
473 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
474 VariantId::EnumVariantId(it) => {
475 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
476 }
477 }
478 }
479
480 pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
481 match self {
482 VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
483 VariantId::StructId(it) => it.lookup(db).id.file_id(),
484 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
485 }
486 }
487}
488
445trait Intern { 489trait Intern {
446 type ID; 490 type ID;
447 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID; 491 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
@@ -644,7 +688,10 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
644 } 688 }
645} 689}
646 690
647pub struct UnresolvedMacro; 691#[derive(Debug)]
692pub struct UnresolvedMacro {
693 pub path: ModPath,
694}
648 695
649fn macro_call_as_call_id( 696fn macro_call_as_call_id(
650 call: &AstIdWithPath<ast::MacroCall>, 697 call: &AstIdWithPath<ast::MacroCall>,
@@ -653,7 +700,8 @@ fn macro_call_as_call_id(
653 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 700 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
654 error_sink: &mut dyn FnMut(mbe::ExpandError), 701 error_sink: &mut dyn FnMut(mbe::ExpandError),
655) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 702) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
656 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; 703 let def: MacroDefId =
704 resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
657 705
658 let res = if let MacroDefKind::BuiltInEager(..) = def.kind { 706 let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
659 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); 707 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
@@ -669,24 +717,36 @@ fn macro_call_as_call_id(
669 ) 717 )
670 .map(MacroCallId::from) 718 .map(MacroCallId::from)
671 } else { 719 } else {
672 Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into()) 720 Ok(def
721 .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id })
722 .into())
673 }; 723 };
674 Ok(res) 724 Ok(res)
675} 725}
676 726
677fn derive_macro_as_call_id( 727fn derive_macro_as_call_id(
678 item_attr: &AstIdWithPath<ast::Item>, 728 item_attr: &AstIdWithPath<ast::Item>,
729 derive_attr: AttrId,
679 db: &dyn db::DefDatabase, 730 db: &dyn db::DefDatabase,
680 krate: CrateId, 731 krate: CrateId,
681 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 732 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
682) -> Result<MacroCallId, UnresolvedMacro> { 733) -> Result<MacroCallId, UnresolvedMacro> {
683 let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?; 734 let def: MacroDefId = resolver(item_attr.path.clone())
684 let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?; 735 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
736 let last_segment = item_attr
737 .path
738 .segments()
739 .last()
740 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
685 let res = def 741 let res = def
686 .as_lazy_macro( 742 .as_lazy_macro(
687 db.upcast(), 743 db.upcast(),
688 krate, 744 krate,
689 MacroCallKind::Derive(item_attr.ast_id, last_segment.to_string()), 745 MacroCallKind::Derive {
746 ast_id: item_attr.ast_id,
747 derive_name: last_segment.to_string(),
748 derive_attr,
749 },
690 ) 750 )
691 .into(); 751 .into();
692 Ok(res) 752 Ok(res)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 7dd68219f..ba027c44a 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -410,6 +410,20 @@ impl DefMap {
410 } 410 }
411 } 411 }
412 412
413 pub fn dump_block_scopes(&self, db: &dyn DefDatabase) -> String {
414 let mut buf = String::new();
415 let mut arc;
416 let mut current_map = self;
417 while let Some(block) = &current_map.block {
418 format_to!(buf, "{:?} in {:?}\n", block.block, block.parent);
419 arc = block.parent.def_map(db);
420 current_map = &*arc;
421 }
422
423 format_to!(buf, "crate scope\n");
424 buf
425 }
426
413 fn shrink_to_fit(&mut self) { 427 fn shrink_to_fit(&mut self) {
414 // Exhaustive match to require handling new fields. 428 // Exhaustive match to require handling new fields.
415 let Self { 429 let Self {
@@ -481,7 +495,7 @@ mod diagnostics {
481 495
482 UnresolvedProcMacro { ast: MacroCallKind }, 496 UnresolvedProcMacro { ast: MacroCallKind },
483 497
484 UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, 498 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
485 499
486 MacroError { ast: MacroCallKind, message: String }, 500 MacroError { ast: MacroCallKind, message: String },
487 } 501 }
@@ -546,8 +560,9 @@ mod diagnostics {
546 pub(super) fn unresolved_macro_call( 560 pub(super) fn unresolved_macro_call(
547 container: LocalModuleId, 561 container: LocalModuleId,
548 ast: AstId<ast::MacroCall>, 562 ast: AstId<ast::MacroCall>,
563 path: ModPath,
549 ) -> Self { 564 ) -> Self {
550 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } 565 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
551 } 566 }
552 567
553 pub(super) fn add_to( 568 pub(super) fn add_to(
@@ -613,12 +628,12 @@ mod diagnostics {
613 DiagnosticKind::UnresolvedProcMacro { ast } => { 628 DiagnosticKind::UnresolvedProcMacro { ast } => {
614 let mut precise_location = None; 629 let mut precise_location = None;
615 let (file, ast, name) = match ast { 630 let (file, ast, name) = match ast {
616 MacroCallKind::FnLike(ast) => { 631 MacroCallKind::FnLike { ast_id } => {
617 let node = ast.to_node(db.upcast()); 632 let node = ast_id.to_node(db.upcast());
618 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 633 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
619 } 634 }
620 MacroCallKind::Derive(ast, name) => { 635 MacroCallKind::Derive { ast_id, derive_name, .. } => {
621 let node = ast.to_node(db.upcast()); 636 let node = ast_id.to_node(db.upcast());
622 637
623 // Compute the precise location of the macro name's token in the derive 638 // Compute the precise location of the macro name's token in the derive
624 // list. 639 // list.
@@ -639,7 +654,7 @@ mod diagnostics {
639 }); 654 });
640 for token in tokens { 655 for token in tokens {
641 if token.kind() == SyntaxKind::IDENT 656 if token.kind() == SyntaxKind::IDENT
642 && token.text() == name.as_str() 657 && token.text() == derive_name.as_str()
643 { 658 {
644 precise_location = Some(token.text_range()); 659 precise_location = Some(token.text_range());
645 break 'outer; 660 break 'outer;
@@ -648,9 +663,9 @@ mod diagnostics {
648 } 663 }
649 664
650 ( 665 (
651 ast.file_id, 666 ast_id.file_id,
652 SyntaxNodePtr::from(AstPtr::new(&node)), 667 SyntaxNodePtr::from(AstPtr::new(&node)),
653 Some(name.clone()), 668 Some(derive_name.clone()),
654 ) 669 )
655 } 670 }
656 }; 671 };
@@ -662,20 +677,24 @@ mod diagnostics {
662 }); 677 });
663 } 678 }
664 679
665 DiagnosticKind::UnresolvedMacroCall { ast } => { 680 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
666 let node = ast.to_node(db.upcast()); 681 let node = ast.to_node(db.upcast());
667 sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); 682 sink.push(UnresolvedMacroCall {
683 file: ast.file_id,
684 node: AstPtr::new(&node),
685 path: path.clone(),
686 });
668 } 687 }
669 688
670 DiagnosticKind::MacroError { ast, message } => { 689 DiagnosticKind::MacroError { ast, message } => {
671 let (file, ast) = match ast { 690 let (file, ast) = match ast {
672 MacroCallKind::FnLike(ast) => { 691 MacroCallKind::FnLike { ast_id, .. } => {
673 let node = ast.to_node(db.upcast()); 692 let node = ast_id.to_node(db.upcast());
674 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 693 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
675 } 694 }
676 MacroCallKind::Derive(ast, _) => { 695 MacroCallKind::Derive { ast_id, .. } => {
677 let node = ast.to_node(db.upcast()); 696 let node = ast_id.to_node(db.upcast());
678 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 697 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
679 } 698 }
680 }; 699 };
681 sink.push(MacroError { file, node: ast, message: message.clone() }); 700 sink.push(MacroError { file, node: ast, message: message.clone() });
diff --git a/crates/hir_def/src/nameres/collector.rs b/crates/hir_def/src/nameres/collector.rs
index 4ddc791ce..05ceb1efb 100644
--- a/crates/hir_def/src/nameres/collector.rs
+++ b/crates/hir_def/src/nameres/collector.rs
@@ -13,7 +13,7 @@ use hir_expand::{
13 builtin_macro::find_builtin_macro, 13 builtin_macro::find_builtin_macro,
14 name::{AsName, Name}, 14 name::{AsName, Name},
15 proc_macro::ProcMacroExpander, 15 proc_macro::ProcMacroExpander,
16 HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 16 AttrId, HirFileId, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
17}; 17};
18use hir_expand::{InFile, MacroCallLoc}; 18use hir_expand::{InFile, MacroCallLoc};
19use rustc_hash::{FxHashMap, FxHashSet}; 19use rustc_hash::{FxHashMap, FxHashSet};
@@ -215,8 +215,8 @@ struct MacroDirective {
215 215
216#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
217enum MacroDirectiveKind { 217enum MacroDirectiveKind {
218 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
219 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
220} 220}
221 221
222struct DefData<'a> { 222struct DefData<'a> {
@@ -478,7 +478,7 @@ impl DefCollector<'_> {
478 self.def_map.edition, 478 self.def_map.edition,
479 ); 479 );
480 480
481 let res = self.def_map.resolve_name_in_extern_prelude(&extern_crate.name); 481 let res = self.def_map.resolve_name_in_extern_prelude(self.db, &extern_crate.name);
482 482
483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use); 484 cov_mark::hit!(macro_rules_from_other_crates_are_visible_with_macro_use);
@@ -534,6 +534,7 @@ impl DefCollector<'_> {
534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
535 if import.is_extern_crate { 535 if import.is_extern_crate {
536 let res = self.def_map.resolve_name_in_extern_prelude( 536 let res = self.def_map.resolve_name_in_extern_prelude(
537 self.db,
537 &import 538 &import
538 .path 539 .path
539 .as_ident() 540 .as_ident()
@@ -806,13 +807,7 @@ impl DefCollector<'_> {
806 let mut res = ReachedFixedPoint::Yes; 807 let mut res = ReachedFixedPoint::Yes;
807 macros.retain(|directive| { 808 macros.retain(|directive| {
808 match &directive.kind { 809 match &directive.kind {
809 MacroDirectiveKind::FnLike { ast_id, legacy } => { 810 MacroDirectiveKind::FnLike { ast_id } => {
810 if let Some(call_id) = legacy {
811 res = ReachedFixedPoint::No;
812 resolved.push((directive.module_id, *call_id, directive.depth));
813 return false;
814 }
815
816 match macro_call_as_call_id( 811 match macro_call_as_call_id(
817 ast_id, 812 ast_id,
818 self.db, 813 self.db,
@@ -834,19 +829,23 @@ impl DefCollector<'_> {
834 res = ReachedFixedPoint::No; 829 res = ReachedFixedPoint::No;
835 return false; 830 return false;
836 } 831 }
837 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
838 } 833 }
839 } 834 }
840 MacroDirectiveKind::Derive { ast_id } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
841 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { 836 match derive_macro_as_call_id(
842 self.resolve_derive_macro(directive.module_id, &path) 837 ast_id,
843 }) { 838 *derive_attr,
839 self.db,
840 self.def_map.krate,
841 |path| self.resolve_derive_macro(directive.module_id, &path),
842 ) {
844 Ok(call_id) => { 843 Ok(call_id) => {
845 resolved.push((directive.module_id, call_id, 0)); 844 resolved.push((directive.module_id, call_id, directive.depth));
846 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
847 return false; 846 return false;
848 } 847 }
849 Err(UnresolvedMacro) => (), 848 Err(UnresolvedMacro { .. }) => (),
850 } 849 }
851 } 850 }
852 } 851 }
@@ -944,10 +943,11 @@ impl DefCollector<'_> {
944 &mut |_| (), 943 &mut |_| (),
945 ) { 944 ) {
946 Ok(_) => (), 945 Ok(_) => (),
947 Err(UnresolvedMacro) => { 946 Err(UnresolvedMacro { path }) => {
948 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( 947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
949 directive.module_id, 948 directive.module_id,
950 ast_id.ast_id, 949 ast_id.ast_id,
950 path,
951 )); 951 ));
952 } 952 }
953 }, 953 },
@@ -1169,19 +1169,27 @@ impl ModCollector<'_, '_> {
1169 } 1169 }
1170 ModItem::Const(id) => { 1170 ModItem::Const(id) => {
1171 let it = &self.item_tree[id]; 1171 let it = &self.item_tree[id];
1172 1172 let const_id = ConstLoc {
1173 if let Some(name) = &it.name { 1173 container: module.into(),
1174 def = Some(DefData { 1174 id: ItemTreeId::new(self.file_id, id),
1175 id: ConstLoc { 1175 }
1176 container: module.into(), 1176 .intern(self.def_collector.db);
1177 id: ItemTreeId::new(self.file_id, id), 1177
1178 } 1178 match &it.name {
1179 .intern(self.def_collector.db) 1179 Some(name) => {
1180 .into(), 1180 def = Some(DefData {
1181 name, 1181 id: const_id.into(),
1182 visibility: &self.item_tree[it.visibility], 1182 name,
1183 has_constructor: false, 1183 visibility: &self.item_tree[it.visibility],
1184 }); 1184 has_constructor: false,
1185 });
1186 }
1187 None => {
1188 // const _: T = ...;
1189 self.def_collector.def_map.modules[self.module_id]
1190 .scope
1191 .define_unnamed_const(const_id);
1192 }
1185 } 1193 }
1186 } 1194 }
1187 ModItem::Static(id) => { 1195 ModItem::Static(id) => {
@@ -1366,7 +1374,7 @@ impl ModCollector<'_, '_> {
1366 self.def_collector.unexpanded_macros.push(MacroDirective { 1374 self.def_collector.unexpanded_macros.push(MacroDirective {
1367 module_id: self.module_id, 1375 module_id: self.module_id,
1368 depth: self.macro_depth + 1, 1376 depth: self.macro_depth + 1,
1369 kind: MacroDirectiveKind::Derive { ast_id }, 1377 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
1370 }); 1378 });
1371 } 1379 }
1372 } 1380 }
@@ -1518,12 +1526,12 @@ impl ModCollector<'_, '_> {
1518 // Built-in macro failed eager expansion. 1526 // Built-in macro failed eager expansion.
1519 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1527 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1520 self.module_id, 1528 self.module_id,
1521 MacroCallKind::FnLike(ast_id.ast_id), 1529 MacroCallKind::FnLike { ast_id: ast_id.ast_id },
1522 error.unwrap().to_string(), 1530 error.unwrap().to_string(),
1523 )); 1531 ));
1524 return; 1532 return;
1525 } 1533 }
1526 Err(UnresolvedMacro) => (), 1534 Err(UnresolvedMacro { .. }) => (),
1527 } 1535 }
1528 1536
1529 // Case 2: resolve in module scope, expand during name resolution. 1537 // Case 2: resolve in module scope, expand during name resolution.
@@ -1535,7 +1543,7 @@ impl ModCollector<'_, '_> {
1535 self.def_collector.unexpanded_macros.push(MacroDirective { 1543 self.def_collector.unexpanded_macros.push(MacroDirective {
1536 module_id: self.module_id, 1544 module_id: self.module_id,
1537 depth: self.macro_depth + 1, 1545 depth: self.macro_depth + 1,
1538 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, 1546 kind: MacroDirectiveKind::FnLike { ast_id },
1539 }); 1547 });
1540 } 1548 }
1541 1549
diff --git a/crates/hir_def/src/nameres/path_resolution.rs b/crates/hir_def/src/nameres/path_resolution.rs
index 60471937c..c984148c3 100644
--- a/crates/hir_def/src/nameres/path_resolution.rs
+++ b/crates/hir_def/src/nameres/path_resolution.rs
@@ -60,12 +60,26 @@ impl ResolvePathResult {
60} 60}
61 61
62impl DefMap { 62impl DefMap {
63 pub(super) fn resolve_name_in_extern_prelude(&self, name: &Name) -> PerNs { 63 pub(super) fn resolve_name_in_extern_prelude(
64 &self,
65 db: &dyn DefDatabase,
66 name: &Name,
67 ) -> PerNs {
64 if name == &name!(self) { 68 if name == &name!(self) {
65 cov_mark::hit!(extern_crate_self_as); 69 cov_mark::hit!(extern_crate_self_as);
66 return PerNs::types(self.module_id(self.root).into(), Visibility::Public); 70 return PerNs::types(self.module_id(self.root).into(), Visibility::Public);
67 } 71 }
68 self.extern_prelude 72
73 let arc;
74 let root = match self.block {
75 Some(_) => {
76 arc = self.crate_root(db).def_map(db);
77 &*arc
78 }
79 None => self,
80 };
81
82 root.extern_prelude
69 .get(name) 83 .get(name)
70 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)) 84 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public))
71 } 85 }
@@ -191,7 +205,7 @@ impl DefMap {
191 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes), 205 None => return ResolvePathResult::empty(ReachedFixedPoint::Yes),
192 }; 206 };
193 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment); 207 log::debug!("resolving {:?} in crate root (+ extern prelude)", segment);
194 self.resolve_name_in_crate_root_or_extern_prelude(&segment) 208 self.resolve_name_in_crate_root_or_extern_prelude(db, &segment)
195 } 209 }
196 PathKind::Plain => { 210 PathKind::Plain => {
197 let (_, segment) = match segments.next() { 211 let (_, segment) = match segments.next() {
@@ -373,7 +387,13 @@ impl DefMap {
373 .get_legacy_macro(name) 387 .get_legacy_macro(name)
374 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public)); 388 .map_or_else(PerNs::none, |m| PerNs::macros(m, Visibility::Public));
375 let from_scope = self[module].scope.get(name); 389 let from_scope = self[module].scope.get(name);
376 let from_builtin = BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none); 390 let from_builtin = match self.block {
391 Some(_) => {
392 // Only resolve to builtins in the root `DefMap`.
393 PerNs::none()
394 }
395 None => BUILTIN_SCOPE.get(name).copied().unwrap_or_else(PerNs::none),
396 };
377 let from_scope_or_builtin = match shadow { 397 let from_scope_or_builtin = match shadow {
378 BuiltinShadowMode::Module => from_scope.or(from_builtin), 398 BuiltinShadowMode::Module => from_scope.or(from_builtin),
379 BuiltinShadowMode::Other => { 399 BuiltinShadowMode::Other => {
@@ -384,24 +404,31 @@ impl DefMap {
384 } 404 }
385 } 405 }
386 }; 406 };
387 // Give precedence to names in outer `DefMap`s over the extern prelude; only check prelude 407 let from_extern_prelude = self
388 // from the crate DefMap. 408 .extern_prelude
389 let from_extern_prelude = match self.block { 409 .get(name)
390 Some(_) => PerNs::none(), 410 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public));
391 None => self
392 .extern_prelude
393 .get(name)
394 .map_or(PerNs::none(), |&it| PerNs::types(it, Visibility::Public)),
395 };
396 411
397 let from_prelude = self.resolve_in_prelude(db, name); 412 let from_prelude = self.resolve_in_prelude(db, name);
398 413
399 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude) 414 from_legacy_macro.or(from_scope_or_builtin).or(from_extern_prelude).or(from_prelude)
400 } 415 }
401 416
402 fn resolve_name_in_crate_root_or_extern_prelude(&self, name: &Name) -> PerNs { 417 fn resolve_name_in_crate_root_or_extern_prelude(
403 let from_crate_root = self[self.root].scope.get(name); 418 &self,
404 let from_extern_prelude = self.resolve_name_in_extern_prelude(name); 419 db: &dyn DefDatabase,
420 name: &Name,
421 ) -> PerNs {
422 let arc;
423 let crate_def_map = match self.block {
424 Some(_) => {
425 arc = self.crate_root(db).def_map(db);
426 &arc
427 }
428 None => self,
429 };
430 let from_crate_root = crate_def_map[crate_def_map.root].scope.get(name);
431 let from_extern_prelude = self.resolve_name_in_extern_prelude(db, name);
405 432
406 from_crate_root.or(from_extern_prelude) 433 from_crate_root.or(from_extern_prelude)
407 } 434 }
diff --git a/crates/hir_def/src/nameres/tests/diagnostics.rs b/crates/hir_def/src/nameres/tests/diagnostics.rs
index fefdadb22..543975e07 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -170,7 +170,7 @@ fn unresolved_legacy_scope_macro() {
170 170
171 m!(); 171 m!();
172 m2!(); 172 m2!();
173 //^^^^^^ unresolved macro call 173 //^^^^^^ unresolved macro `self::m2!`
174 "#, 174 "#,
175 ); 175 );
176} 176}
@@ -187,7 +187,7 @@ fn unresolved_module_scope_macro() {
187 187
188 self::m!(); 188 self::m!();
189 self::m2!(); 189 self::m2!();
190 //^^^^^^^^^^^^ unresolved macro call 190 //^^^^^^^^^^^^ unresolved macro `self::m2!`
191 "#, 191 "#,
192 ); 192 );
193} 193}
@@ -233,7 +233,7 @@ fn good_out_dir_diagnostic() {
233 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
234 234
235 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
237 "#, 237 "#,
238 ); 238 );
239} 239}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index a3e83e2cf..509f77850 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -48,7 +48,8 @@ pub enum ImportAlias {
48 48
49impl ModPath { 49impl ModPath {
50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> { 50 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<ModPath> {
51 lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone()) 51 let ctx = LowerCtx::with_hygiene(hygiene);
52 lower::lower_path(path, &ctx).map(|it| (*it.mod_path).clone())
52 } 53 }
53 54
54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 55 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -122,7 +123,7 @@ impl ModPath {
122pub struct Path { 123pub struct Path {
123 /// Type based path like `<T>::foo`. 124 /// Type based path like `<T>::foo`.
124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. 125 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
125 type_anchor: Option<Box<TypeRef>>, 126 type_anchor: Option<Interned<TypeRef>>,
126 mod_path: Interned<ModPath>, 127 mod_path: Interned<ModPath>,
127 /// Invariant: the same len as `self.mod_path.segments` 128 /// Invariant: the same len as `self.mod_path.segments`
128 generic_args: Vec<Option<Arc<GenericArgs>>>, 129 generic_args: Vec<Option<Arc<GenericArgs>>>,
@@ -167,8 +168,8 @@ pub enum GenericArg {
167impl Path { 168impl Path {
168 /// Converts an `ast::Path` to `Path`. Works with use trees. 169 /// Converts an `ast::Path` to `Path`. Works with use trees.
169 /// It correctly handles `$crate` based path from macro call. 170 /// It correctly handles `$crate` based path from macro call.
170 pub fn from_src(path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 171 pub fn from_src(path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
171 lower::lower_path(path, hygiene) 172 lower::lower_path(path, ctx)
172 } 173 }
173 174
174 /// Converts a known mod path to `Path`. 175 /// Converts a known mod path to `Path`.
@@ -289,6 +290,12 @@ impl From<Name> for Path {
289 } 290 }
290} 291}
291 292
293impl From<Name> for Box<Path> {
294 fn from(name: Name) -> Box<Path> {
295 Box::new(Path::from(name))
296 }
297}
298
292impl From<Name> for ModPath { 299impl From<Name> for ModPath {
293 fn from(name: Name) -> ModPath { 300 fn from(name: Name) -> ModPath {
294 ModPath::from_segments(PathKind::Plain, iter::once(name)) 301 ModPath::from_segments(PathKind::Plain, iter::once(name))
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index 28f6244da..1df6db525 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -6,10 +6,7 @@ use crate::intern::Interned;
6use std::sync::Arc; 6use std::sync::Arc;
7 7
8use either::Either; 8use either::Either;
9use hir_expand::{ 9use hir_expand::name::{name, AsName};
10 hygiene::Hygiene,
11 name::{name, AsName},
12};
13use syntax::ast::{self, AstNode, TypeBoundsOwner}; 10use syntax::ast::{self, AstNode, TypeBoundsOwner};
14 11
15use super::AssociatedTypeBinding; 12use super::AssociatedTypeBinding;
@@ -23,12 +20,12 @@ pub(super) use lower_use::lower_use_tree;
23 20
24/// Converts an `ast::Path` to `Path`. Works with use trees. 21/// Converts an `ast::Path` to `Path`. Works with use trees.
25/// It correctly handles `$crate` based path from macro call. 22/// It correctly handles `$crate` based path from macro call.
26pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> { 23pub(super) fn lower_path(mut path: ast::Path, ctx: &LowerCtx) -> Option<Path> {
27 let mut kind = PathKind::Plain; 24 let mut kind = PathKind::Plain;
28 let mut type_anchor = None; 25 let mut type_anchor = None;
29 let mut segments = Vec::new(); 26 let mut segments = Vec::new();
30 let mut generic_args = Vec::new(); 27 let mut generic_args = Vec::new();
31 let ctx = LowerCtx::with_hygiene(hygiene); 28 let hygiene = ctx.hygiene();
32 loop { 29 loop {
33 let segment = path.segment()?; 30 let segment = path.segment()?;
34 31
@@ -43,10 +40,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
43 Either::Left(name) => { 40 Either::Left(name) => {
44 let args = segment 41 let args = segment
45 .generic_arg_list() 42 .generic_arg_list()
46 .and_then(|it| lower_generic_args(&ctx, it)) 43 .and_then(|it| lower_generic_args(ctx, it))
47 .or_else(|| { 44 .or_else(|| {
48 lower_generic_args_from_fn_path( 45 lower_generic_args_from_fn_path(
49 &ctx, 46 ctx,
50 segment.param_list(), 47 segment.param_list(),
51 segment.ret_type(), 48 segment.ret_type(),
52 ) 49 )
@@ -64,17 +61,17 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
64 ast::PathSegmentKind::Type { type_ref, trait_ref } => { 61 ast::PathSegmentKind::Type { type_ref, trait_ref } => {
65 assert!(path.qualifier().is_none()); // this can only occur at the first segment 62 assert!(path.qualifier().is_none()); // this can only occur at the first segment
66 63
67 let self_type = TypeRef::from_ast(&ctx, type_ref?); 64 let self_type = TypeRef::from_ast(ctx, type_ref?);
68 65
69 match trait_ref { 66 match trait_ref {
70 // <T>::foo 67 // <T>::foo
71 None => { 68 None => {
72 type_anchor = Some(Box::new(self_type)); 69 type_anchor = Some(Interned::new(self_type));
73 kind = PathKind::Plain; 70 kind = PathKind::Plain;
74 } 71 }
75 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 72 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
76 Some(trait_ref) => { 73 Some(trait_ref) => {
77 let path = Path::from_src(trait_ref.path()?, hygiene)?; 74 let path = Path::from_src(trait_ref.path()?, ctx)?;
78 let mod_path = (*path.mod_path).clone(); 75 let mod_path = (*path.mod_path).clone();
79 let num_segments = path.mod_path.segments.len(); 76 let num_segments = path.mod_path.segments.len();
80 kind = mod_path.kind; 77 kind = mod_path.kind;
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index a73585ee7..0391cc49b 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -14,6 +14,7 @@ use crate::{
14 db::DefDatabase, 14 db::DefDatabase,
15 expr::{ExprId, LabelId, PatId}, 15 expr::{ExprId, LabelId, PatId},
16 generics::GenericParams, 16 generics::GenericParams,
17 intern::Interned,
17 item_scope::{BuiltinShadowMode, BUILTIN_SCOPE}, 18 item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
18 nameres::DefMap, 19 nameres::DefMap,
19 path::{ModPath, PathKind}, 20 path::{ModPath, PathKind},
@@ -50,7 +51,7 @@ enum Scope {
50 /// All the items and imported names of a module 51 /// All the items and imported names of a module
51 ModuleScope(ModuleItemMap), 52 ModuleScope(ModuleItemMap),
52 /// Brings the generic parameters of an item into scope 53 /// Brings the generic parameters of an item into scope
53 GenericParams { def: GenericDefId, params: Arc<GenericParams> }, 54 GenericParams { def: GenericDefId, params: Interned<GenericParams> },
54 /// Brings `Self` in `impl` block into scope 55 /// Brings `Self` in `impl` block into scope
55 ImplDefScope(ImplId), 56 ImplDefScope(ImplId),
56 /// Brings `Self` in enum, struct and union definitions into scope 57 /// Brings `Self` in enum, struct and union definitions into scope
diff --git a/crates/hir_def/src/test_db.rs b/crates/hir_def/src/test_db.rs
index dd36106f8..8fa703a57 100644
--- a/crates/hir_def/src/test_db.rs
+++ b/crates/hir_def/src/test_db.rs
@@ -15,7 +15,12 @@ use rustc_hash::FxHashSet;
15use syntax::{algo, ast, AstNode, TextRange, TextSize}; 15use syntax::{algo, ast, AstNode, TextRange, TextSize};
16use test_utils::extract_annotations; 16use test_utils::extract_annotations;
17 17
18use crate::{db::DefDatabase, nameres::DefMap, src::HasSource, Lookup, ModuleDefId, ModuleId}; 18use crate::{
19 db::DefDatabase,
20 nameres::{DefMap, ModuleSource},
21 src::HasSource,
22 LocalModuleId, Lookup, ModuleDefId, ModuleId,
23};
19 24
20#[salsa::database( 25#[salsa::database(
21 base_db::SourceDatabaseExtStorage, 26 base_db::SourceDatabaseExtStorage,
@@ -87,10 +92,11 @@ impl TestDB {
87 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId { 92 pub(crate) fn module_at_position(&self, position: FilePosition) -> ModuleId {
88 let file_module = self.module_for_file(position.file_id); 93 let file_module = self.module_for_file(position.file_id);
89 let mut def_map = file_module.def_map(self); 94 let mut def_map = file_module.def_map(self);
95 let module = self.mod_at_position(&def_map, position);
90 96
91 def_map = match self.block_at_position(&def_map, position) { 97 def_map = match self.block_at_position(&def_map, position) {
92 Some(it) => it, 98 Some(it) => it,
93 None => return file_module, 99 None => return def_map.module_id(module),
94 }; 100 };
95 loop { 101 loop {
96 let new_map = self.block_at_position(&def_map, position); 102 let new_map = self.block_at_position(&def_map, position);
@@ -106,6 +112,47 @@ impl TestDB {
106 } 112 }
107 } 113 }
108 114
115 /// Finds the smallest/innermost module in `def_map` containing `position`.
116 fn mod_at_position(&self, def_map: &DefMap, position: FilePosition) -> LocalModuleId {
117 let mut size = None;
118 let mut res = def_map.root();
119 for (module, data) in def_map.modules() {
120 let src = data.definition_source(self);
121 if src.file_id != position.file_id.into() {
122 continue;
123 }
124
125 let range = match src.value {
126 ModuleSource::SourceFile(it) => it.syntax().text_range(),
127 ModuleSource::Module(it) => it.syntax().text_range(),
128 ModuleSource::BlockExpr(it) => it.syntax().text_range(),
129 };
130
131 if !range.contains(position.offset) {
132 continue;
133 }
134
135 let new_size = match size {
136 None => range.len(),
137 Some(size) => {
138 if range.len() < size {
139 range.len()
140 } else {
141 size
142 }
143 }
144 };
145
146 if size != Some(new_size) {
147 cov_mark::hit!(submodule_in_testdb);
148 size = Some(new_size);
149 res = module;
150 }
151 }
152
153 res
154 }
155
109 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> { 156 fn block_at_position(&self, def_map: &DefMap, position: FilePosition) -> Option<Arc<DefMap>> {
110 // Find the smallest (innermost) function in `def_map` containing the cursor. 157 // Find the smallest (innermost) function in `def_map` containing the cursor.
111 let mut size = None; 158 let mut size = None;
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 4c24aae94..ea29da5da 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -1,6 +1,7 @@
1//! HIR for references to types. Paths in these are not yet resolved. They can 1//! HIR for references to types. Paths in these are not yet resolved. They can
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3use hir_expand::name::Name; 3
4use hir_expand::{name::Name, AstId, InFile};
4use syntax::ast; 5use syntax::ast;
5 6
6use crate::{body::LowerCtx, path::Path}; 7use crate::{body::LowerCtx, path::Path};
@@ -68,6 +69,7 @@ impl TraitRef {
68 } 69 }
69 } 70 }
70} 71}
72
71/// Compare ty::Ty 73/// Compare ty::Ty
72#[derive(Clone, PartialEq, Eq, Hash, Debug)] 74#[derive(Clone, PartialEq, Eq, Hash, Debug)]
73pub enum TypeRef { 75pub enum TypeRef {
@@ -84,6 +86,7 @@ pub enum TypeRef {
84 // For 86 // For
85 ImplTrait(Vec<TypeBound>), 87 ImplTrait(Vec<TypeBound>),
86 DynTrait(Vec<TypeBound>), 88 DynTrait(Vec<TypeBound>),
89 Macro(AstId<ast::MacroCall>),
87 Error, 90 Error,
88} 91}
89 92
@@ -116,7 +119,7 @@ pub enum TypeBound {
116 119
117impl TypeRef { 120impl TypeRef {
118 /// Converts an `ast::TypeRef` to a `hir::TypeRef`. 121 /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
119 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self { 122 pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
120 match node { 123 match node {
121 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()), 124 ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
122 ast::Type::TupleType(inner) => { 125 ast::Type::TupleType(inner) => {
@@ -176,8 +179,13 @@ impl TypeRef {
176 ast::Type::DynTraitType(inner) => { 179 ast::Type::DynTraitType(inner) => {
177 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) 180 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
178 } 181 }
179 // FIXME: Macros in type position are not yet supported. 182 ast::Type::MacroType(mt) => match mt.macro_call() {
180 ast::Type::MacroType(_) => TypeRef::Error, 183 Some(mc) => ctx
184 .ast_id(&mc)
185 .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
186 .unwrap_or(TypeRef::Error),
187 None => TypeRef::Error,
188 },
181 } 189 }
182 } 190 }
183 191
@@ -215,7 +223,7 @@ impl TypeRef {
215 } 223 }
216 } 224 }
217 TypeRef::Path(path) => go_path(path, f), 225 TypeRef::Path(path) => go_path(path, f),
218 TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {} 226 TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
219 }; 227 };
220 } 228 }
221 229
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 7d00a37c4..d4b7c9970 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -11,7 +11,7 @@ use crate::{
11 nameres::DefMap, 11 nameres::DefMap,
12 path::{ModPath, PathKind}, 12 path::{ModPath, PathKind},
13 resolver::HasResolver, 13 resolver::HasResolver,
14 FunctionId, HasModule, LocalFieldId, ModuleDefId, ModuleId, VariantId, 14 FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
15}; 15};
16 16
17/// Visibility of an item, not yet resolved. 17/// Visibility of an item, not yet resolved.
@@ -25,7 +25,7 @@ pub enum RawVisibility {
25} 25}
26 26
27impl RawVisibility { 27impl RawVisibility {
28 pub(crate) const fn private() -> RawVisibility { 28 pub(crate) fn private() -> RawVisibility {
29 RawVisibility::Module(ModPath::from_kind(PathKind::Super(0))) 29 RawVisibility::Module(ModPath::from_kind(PathKind::Super(0)))
30 } 30 }
31 31
@@ -123,11 +123,19 @@ impl Visibility {
123 def_map: &DefMap, 123 def_map: &DefMap,
124 mut from_module: crate::LocalModuleId, 124 mut from_module: crate::LocalModuleId,
125 ) -> bool { 125 ) -> bool {
126 let to_module = match self { 126 let mut to_module = match self {
127 Visibility::Module(m) => m, 127 Visibility::Module(m) => m,
128 Visibility::Public => return true, 128 Visibility::Public => return true,
129 }; 129 };
130 130
131 // `to_module` might be the root module of a block expression. Those have the same
132 // visibility as the containing module (even though no items are directly nameable from
133 // there, getting this right is important for method resolution).
134 // In that case, we adjust the visibility of `to_module` to point to the containing module.
135 if to_module.is_block_root(db) {
136 to_module = to_module.containing_module(db).unwrap();
137 }
138
131 // from_module needs to be a descendant of to_module 139 // from_module needs to be a descendant of to_module
132 let mut def_map = def_map; 140 let mut def_map = def_map;
133 let mut parent_arc; 141 let mut parent_arc;
@@ -217,6 +225,6 @@ pub(crate) fn field_visibilities_query(
217 225
218/// Resolve visibility of a function. 226/// Resolve visibility of a function.
219pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { 227pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
220 let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db); 228 let resolver = def.resolver(db);
221 db.function_data(def).visibility.resolve(db, &resolver) 229 db.function_data(def).visibility.resolve(db, &resolver)
222} 230}
diff --git a/crates/hir_expand/src/builtin_derive.rs b/crates/hir_expand/src/builtin_derive.rs
index 6ece4b289..537c03028 100644
--- a/crates/hir_expand/src/builtin_derive.rs
+++ b/crates/hir_expand/src/builtin_derive.rs
@@ -269,7 +269,7 @@ mod tests {
269 use expect_test::{expect, Expect}; 269 use expect_test::{expect, Expect};
270 use name::AsName; 270 use name::AsName;
271 271
272 use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; 272 use crate::{test_db::TestDB, AstId, AttrId, MacroCallId, MacroCallKind, MacroCallLoc};
273 273
274 use super::*; 274 use super::*;
275 275
@@ -308,7 +308,7 @@ $0
308 308
309 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap(); 309 let expander = BuiltinDeriveExpander::find_by_name(&name).unwrap();
310 310
311 let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); 311 let ast_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0]));
312 312
313 let loc = MacroCallLoc { 313 let loc = MacroCallLoc {
314 def: MacroDefId { 314 def: MacroDefId {
@@ -317,7 +317,11 @@ $0
317 local_inner: false, 317 local_inner: false,
318 }, 318 },
319 krate: CrateId(0), 319 krate: CrateId(0),
320 kind: MacroCallKind::Derive(attr_id, name.to_string()), 320 kind: MacroCallKind::Derive {
321 ast_id,
322 derive_name: name.to_string(),
323 derive_attr: AttrId(0),
324 },
321 }; 325 };
322 326
323 let id: MacroCallId = db.intern_macro(loc).into(); 327 let id: MacroCallId = db.intern_macro(loc).into();
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 75ec4196b..179de61f9 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -110,6 +110,7 @@ register_builtin! {
110 (format_args_nl, FormatArgsNl) => format_args_expand, 110 (format_args_nl, FormatArgsNl) => format_args_expand,
111 (llvm_asm, LlvmAsm) => asm_expand, 111 (llvm_asm, LlvmAsm) => asm_expand,
112 (asm, Asm) => asm_expand, 112 (asm, Asm) => asm_expand,
113 (global_asm, GlobalAsm) => global_asm_expand,
113 (cfg, Cfg) => cfg_expand, 114 (cfg, Cfg) => cfg_expand,
114 (core_panic, CorePanic) => panic_expand, 115 (core_panic, CorePanic) => panic_expand,
115 (std_panic, StdPanic) => panic_expand, 116 (std_panic, StdPanic) => panic_expand,
@@ -274,6 +275,15 @@ fn asm_expand(
274 ExpandResult::ok(expanded) 275 ExpandResult::ok(expanded)
275} 276}
276 277
278fn global_asm_expand(
279 _db: &dyn AstDatabase,
280 _id: LazyMacroId,
281 _tt: &tt::Subtree,
282) -> ExpandResult<tt::Subtree> {
283 // Expand to nothing (at item-level)
284 ExpandResult::ok(quote! {})
285}
286
277fn cfg_expand( 287fn cfg_expand(
278 db: &dyn AstDatabase, 288 db: &dyn AstDatabase,
279 id: LazyMacroId, 289 id: LazyMacroId,
@@ -490,7 +500,7 @@ fn env_expand(
490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. 500 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
491 if key == "OUT_DIR" { 501 if key == "OUT_DIR" {
492 err = Some(mbe::ExpandError::Other( 502 err = Some(mbe::ExpandError::Other(
493 r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(), 503 r#"`OUT_DIR` not set, enable "run build scripts" to fix"#.into(),
494 )); 504 ));
495 } 505 }
496 506
@@ -566,10 +576,9 @@ mod tests {
566 let loc = MacroCallLoc { 576 let loc = MacroCallLoc {
567 def, 577 def,
568 krate, 578 krate,
569 kind: MacroCallKind::FnLike(AstId::new( 579 kind: MacroCallKind::FnLike {
570 file_id.into(), 580 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
571 ast_id_map.ast_id(&macro_call), 581 },
572 )),
573 }; 582 };
574 583
575 let id: MacroCallId = db.intern_macro(loc).into(); 584 let id: MacroCallId = db.intern_macro(loc).into();
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index 10fe60821..1e4b0cc19 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -439,6 +439,8 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
439 match parent.kind() { 439 match parent.kind() {
440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
441 MACRO_STMTS => FragmentKind::Statements, 441 MACRO_STMTS => FragmentKind::Statements,
442 MACRO_PAT => FragmentKind::Pattern,
443 MACRO_TYPE => FragmentKind::Type,
442 ITEM_LIST => FragmentKind::Items, 444 ITEM_LIST => FragmentKind::Items,
443 LET_STMT => { 445 LET_STMT => {
444 // FIXME: Handle LHS Pattern 446 // FIXME: Handle LHS Pattern
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 9705526fa..f12132f84 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -29,8 +29,9 @@ use base_db::CrateId;
29use mbe::ExpandResult; 29use mbe::ExpandResult;
30use parser::FragmentKind; 30use parser::FragmentKind;
31use std::sync::Arc; 31use std::sync::Arc;
32use syntax::{algo::SyntaxRewriter, SyntaxNode}; 32use syntax::{ted, SyntaxNode};
33 33
34#[derive(Debug)]
34pub struct ErrorEmitted { 35pub struct ErrorEmitted {
35 _private: (), 36 _private: (),
36} 37}
@@ -174,8 +175,9 @@ fn lazy_expand(
174) -> ExpandResult<Option<InFile<SyntaxNode>>> { 175) -> ExpandResult<Option<InFile<SyntaxNode>>> {
175 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 176 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
176 177
177 let id: MacroCallId = 178 let id: MacroCallId = def
178 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 179 .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) })
180 .into();
179 181
180 let err = db.macro_expand_error(id); 182 let err = db.macro_expand_error(id);
181 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)); 183 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
@@ -190,10 +192,10 @@ fn eager_macro_recur(
190 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, 192 macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>,
191 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), 193 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
192) -> Result<SyntaxNode, ErrorEmitted> { 194) -> Result<SyntaxNode, ErrorEmitted> {
193 let original = curr.value.clone(); 195 let original = curr.value.clone().clone_for_update();
194 196
195 let children = curr.value.descendants().filter_map(ast::MacroCall::cast); 197 let children = original.descendants().filter_map(ast::MacroCall::cast);
196 let mut rewriter = SyntaxRewriter::default(); 198 let mut replacements = Vec::new();
197 199
198 // Collect replacement 200 // Collect replacement
199 for child in children { 201 for child in children {
@@ -212,6 +214,7 @@ fn eager_macro_recur(
212 .into(); 214 .into();
213 db.parse_or_expand(id.as_file()) 215 db.parse_or_expand(id.as_file())
214 .expect("successful macro expansion should be parseable") 216 .expect("successful macro expansion should be parseable")
217 .clone_for_update()
215 } 218 }
216 MacroDefKind::Declarative(_) 219 MacroDefKind::Declarative(_)
217 | MacroDefKind::BuiltIn(..) 220 | MacroDefKind::BuiltIn(..)
@@ -225,15 +228,14 @@ fn eager_macro_recur(
225 } 228 }
226 }; 229 };
227 230
228 // check if the whole original sytnax is replaced 231 // check if the whole original syntax is replaced
229 // Note that SyntaxRewriter cannot replace the root node itself
230 if child.syntax() == &original { 232 if child.syntax() == &original {
231 return Ok(insert); 233 return Ok(insert);
232 } 234 }
233 235
234 rewriter.replace(child.syntax(), &insert); 236 replacements.push((child, insert));
235 } 237 }
236 238
237 let res = rewriter.rewrite(&original); 239 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
238 Ok(res) 240 Ok(original)
239} 241}
diff --git a/crates/hir_expand/src/lib.rs b/crates/hir_expand/src/lib.rs
index 3e332ee47..a0e6aec62 100644
--- a/crates/hir_expand/src/lib.rs
+++ b/crates/hir_expand/src/lib.rs
@@ -290,22 +290,27 @@ pub struct MacroCallLoc {
290 290
291#[derive(Debug, Clone, PartialEq, Eq, Hash)] 291#[derive(Debug, Clone, PartialEq, Eq, Hash)]
292pub enum MacroCallKind { 292pub enum MacroCallKind {
293 FnLike(AstId<ast::MacroCall>), 293 FnLike { ast_id: AstId<ast::MacroCall> },
294 Derive(AstId<ast::Item>, String), 294 Derive { ast_id: AstId<ast::Item>, derive_name: String, derive_attr: AttrId },
295} 295}
296 296
297#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
298pub struct AttrId(pub u32);
299
297impl MacroCallKind { 300impl MacroCallKind {
298 fn file_id(&self) -> HirFileId { 301 fn file_id(&self) -> HirFileId {
299 match self { 302 match self {
300 MacroCallKind::FnLike(ast_id) => ast_id.file_id, 303 MacroCallKind::FnLike { ast_id, .. } => ast_id.file_id,
301 MacroCallKind::Derive(ast_id, _) => ast_id.file_id, 304 MacroCallKind::Derive { ast_id, .. } => ast_id.file_id,
302 } 305 }
303 } 306 }
304 307
305 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> { 308 fn node(&self, db: &dyn db::AstDatabase) -> InFile<SyntaxNode> {
306 match self { 309 match self {
307 MacroCallKind::FnLike(ast_id) => ast_id.with_value(ast_id.to_node(db).syntax().clone()), 310 MacroCallKind::FnLike { ast_id, .. } => {
308 MacroCallKind::Derive(ast_id, _) => { 311 ast_id.with_value(ast_id.to_node(db).syntax().clone())
312 }
313 MacroCallKind::Derive { ast_id, .. } => {
309 ast_id.with_value(ast_id.to_node(db).syntax().clone()) 314 ast_id.with_value(ast_id.to_node(db).syntax().clone())
310 } 315 }
311 } 316 }
@@ -313,10 +318,10 @@ impl MacroCallKind {
313 318
314 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> { 319 fn arg(&self, db: &dyn db::AstDatabase) -> Option<SyntaxNode> {
315 match self { 320 match self {
316 MacroCallKind::FnLike(ast_id) => { 321 MacroCallKind::FnLike { ast_id, .. } => {
317 Some(ast_id.to_node(db).token_tree()?.syntax().clone()) 322 Some(ast_id.to_node(db).token_tree()?.syntax().clone())
318 } 323 }
319 MacroCallKind::Derive(ast_id, _) => Some(ast_id.to_node(db).syntax().clone()), 324 MacroCallKind::Derive { ast_id, .. } => Some(ast_id.to_node(db).syntax().clone()),
320 } 325 }
321 } 326 }
322} 327}
diff --git a/crates/hir_expand/src/name.rs b/crates/hir_expand/src/name.rs
index a0f8766b0..bcfd3e524 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -221,6 +221,7 @@ pub mod known {
221 option_env, 221 option_env,
222 llvm_asm, 222 llvm_asm,
223 asm, 223 asm,
224 global_asm,
224 // Builtin derives 225 // Builtin derives
225 Copy, 226 Copy,
226 Clone, 227 Clone,
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 030b7eebe..66b3418f2 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -12,15 +12,15 @@ doctest = false
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = { version = "1.1", features = ["thread-local"] }
14itertools = "0.10.0" 14itertools = "0.10.0"
15arrayvec = "0.6" 15arrayvec = "0.7"
16smallvec = "1.2.0" 16smallvec = "1.2.0"
17ena = "0.14.0" 17ena = "0.14.0"
18log = "0.4.8" 18log = "0.4.8"
19rustc-hash = "1.1.0" 19rustc-hash = "1.1.0"
20scoped-tls = "1" 20scoped-tls = "1"
21chalk-solve = { version = "0.60", default-features = false } 21chalk-solve = { version = "0.64", default-features = false }
22chalk-ir = "0.60" 22chalk-ir = "0.64"
23chalk-recursive = "0.60" 23chalk-recursive = "0.64"
24la-arena = { version = "0.2.0", path = "../../lib/arena" } 24la-arena = { version = "0.2.0", path = "../../lib/arena" }
25 25
26stdx = { path = "../stdx", version = "0.0.0" } 26stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index 70c56cc45..2c07494a9 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -6,16 +6,15 @@
6use std::iter::successors; 6use std::iter::successors;
7 7
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::cast::Cast; 9use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, VariableKind};
10use hir_def::lang_item::LangItemTarget; 10use hir_def::lang_item::LangItemTarget;
11use hir_expand::name::name; 11use hir_expand::name::name;
12use log::{info, warn}; 12use log::{info, warn};
13 13
14use crate::{ 14use crate::{
15 db::HirDatabase, 15 db::HirDatabase, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
16 traits::{InEnvironment, Solution}, 16 DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner, Ty, 17 TyKind,
18 TyBuilder, TyKind,
19}; 18};
20 19
21const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -37,18 +36,28 @@ pub(crate) fn deref(
37 krate: CrateId, 36 krate: CrateId,
38 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
39) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
40 if let Some(derefed) = ty.goal.value.builtin_deref() { 39 let _p = profile::span("deref");
40 if let Some(derefed) = builtin_deref(&ty.goal.value) {
41 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) 41 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
42 } else { 42 } else {
43 deref_by_trait(db, krate, ty) 43 deref_by_trait(db, krate, ty)
44 } 44 }
45} 45}
46 46
47fn builtin_deref(ty: &Ty) -> Option<Ty> {
48 match ty.kind(&Interner) {
49 TyKind::Ref(.., ty) => Some(ty.clone()),
50 TyKind::Raw(.., ty) => Some(ty.clone()),
51 _ => None,
52 }
53}
54
47fn deref_by_trait( 55fn deref_by_trait(
48 db: &dyn HirDatabase, 56 db: &dyn HirDatabase,
49 krate: CrateId, 57 krate: CrateId,
50 ty: InEnvironment<&Canonical<Ty>>, 58 ty: InEnvironment<&Canonical<Ty>>,
51) -> Option<Canonical<Ty>> { 59) -> Option<Canonical<Ty>> {
60 let _p = profile::span("deref_by_trait");
52 let deref_trait = match db.lang_item(krate, "deref".into())? { 61 let deref_trait = match db.lang_item(krate, "deref".into())? {
53 LangItemTarget::TraitId(it) => it, 62 LangItemTarget::TraitId(it) => it,
54 _ => return None, 63 _ => return None,
@@ -97,7 +106,7 @@ fn deref_by_trait(
97 binders: CanonicalVarKinds::from_iter( 106 binders: CanonicalVarKinds::from_iter(
98 &Interner, 107 &Interner,
99 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new( 108 ty.goal.binders.iter(&Interner).cloned().chain(Some(chalk_ir::WithKind::new(
100 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 109 VariableKind::Ty(chalk_ir::TyVariableKind::General),
101 chalk_ir::UniverseIndex::ROOT, 110 chalk_ir::UniverseIndex::ROOT,
102 ))), 111 ))),
103 ), 112 ),
@@ -122,23 +131,25 @@ fn deref_by_trait(
122 // assumptions will be broken. We would need to properly introduce 131 // assumptions will be broken. We would need to properly introduce
123 // new variables in that case 132 // new variables in that case
124 133
125 for i in 1..vars.0.binders.len(&Interner) { 134 for i in 1..vars.binders.len(&Interner) {
126 if vars.0.value.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner) 135 if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
127 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 136 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
128 { 137 {
129 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); 138 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
130 return None; 139 return None;
131 } 140 }
132 } 141 }
133 Some(Canonical { 142 // FIXME: we remove lifetime variables here since they can confuse
143 // the method resolution code later
144 Some(fixup_lifetime_variables(Canonical {
134 value: vars 145 value: vars
135 .0
136 .value 146 .value
137 .at(&Interner, vars.0.value.len(&Interner) - 1) 147 .subst
148 .at(&Interner, vars.value.subst.len(&Interner) - 1)
138 .assert_ty_ref(&Interner) 149 .assert_ty_ref(&Interner)
139 .clone(), 150 .clone(),
140 binders: vars.0.binders.clone(), 151 binders: vars.binders.clone(),
141 }) 152 }))
142 } 153 }
143 Solution::Ambig(_) => { 154 Solution::Ambig(_) => {
144 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); 155 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
@@ -146,3 +157,32 @@ fn deref_by_trait(
146 } 157 }
147 } 158 }
148} 159}
160
161fn fixup_lifetime_variables<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
162 c: Canonical<T>,
163) -> Canonical<T> {
164 // Removes lifetime variables from the Canonical, replacing them by static lifetimes.
165 let mut i = 0;
166 let subst = Substitution::from_iter(
167 &Interner,
168 c.binders.iter(&Interner).map(|vk| match vk.kind {
169 VariableKind::Ty(_) => {
170 let index = i;
171 i += 1;
172 BoundVar::new(DebruijnIndex::INNERMOST, index).to_ty(&Interner).cast(&Interner)
173 }
174 VariableKind::Lifetime => static_lifetime().cast(&Interner),
175 VariableKind::Const(_) => unimplemented!(),
176 }),
177 );
178 let binders = CanonicalVarKinds::from_iter(
179 &Interner,
180 c.binders.iter(&Interner).filter(|vk| match vk.kind {
181 VariableKind::Ty(_) => true,
182 VariableKind::Lifetime => false,
183 VariableKind::Const(_) => true,
184 }),
185 );
186 let value = subst.apply(c.value, &Interner);
187 Canonical { binders, value }
188}
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 4a9a8058f..e25ef866d 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -4,6 +4,7 @@ use std::iter;
4 4
5use chalk_ir::{ 5use chalk_ir::{
6 cast::{Cast, CastTo, Caster}, 6 cast::{Cast, CastTo, Caster},
7 fold::Fold,
7 interner::HasInterner, 8 interner::HasInterner,
8 AdtId, BoundVar, DebruijnIndex, Safety, Scalar, 9 AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
9}; 10};
@@ -12,8 +13,8 @@ use smallvec::SmallVec;
12 13
13use crate::{ 14use crate::{
14 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, 15 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
15 CallableSig, FnPointer, FnSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, 16 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
16 TyDefId, TyKind, TypeWalk, ValueTyDefId, 17 TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId,
17}; 18};
18 19
19/// This is a builder for `Ty` or anything that needs a `Substitution`. 20/// This is a builder for `Ty` or anything that needs a `Substitution`.
@@ -32,8 +33,7 @@ impl<D> TyBuilder<D> {
32 33
33 fn build_internal(self) -> (D, Substitution) { 34 fn build_internal(self) -> (D, Substitution) {
34 assert_eq!(self.vec.len(), self.param_count); 35 assert_eq!(self.vec.len(), self.param_count);
35 // FIXME: would be good to have a way to construct a chalk_ir::Substitution from the interned form 36 let subst = Substitution::from_iter(&Interner, self.vec);
36 let subst = Substitution(self.vec);
37 (self.data, subst) 37 (self.data, subst)
38 } 38 }
39 39
@@ -54,7 +54,7 @@ impl<D> TyBuilder<D> {
54 } 54 }
55 55
56 pub fn fill_with_unknown(self) -> Self { 56 pub fn fill_with_unknown(self) -> Self {
57 self.fill(iter::repeat(TyKind::Unknown.intern(&Interner))) 57 self.fill(iter::repeat(TyKind::Error.intern(&Interner)))
58 } 58 }
59 59
60 pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self { 60 pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self {
@@ -78,9 +78,12 @@ impl TyBuilder<()> {
78 78
79 pub fn fn_ptr(sig: CallableSig) -> Ty { 79 pub fn fn_ptr(sig: CallableSig) -> Ty {
80 TyKind::Function(FnPointer { 80 TyKind::Function(FnPointer {
81 num_args: sig.params().len(), 81 num_binders: 0,
82 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs }, 82 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
83 substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()), 83 substitution: FnSubst(Substitution::from_iter(
84 &Interner,
85 sig.params_and_return.iter().cloned(),
86 )),
84 }) 87 })
85 .intern(&Interner) 88 .intern(&Interner)
86 } 89 }
@@ -138,8 +141,9 @@ impl TyBuilder<hir_def::AdtId> {
138 self.vec.push(fallback().cast(&Interner)); 141 self.vec.push(fallback().cast(&Interner));
139 } else { 142 } else {
140 // each default can depend on the previous parameters 143 // each default can depend on the previous parameters
141 let subst_so_far = Substitution(self.vec.clone()); 144 let subst_so_far = Substitution::from_iter(&Interner, self.vec.clone());
142 self.vec.push(default_ty.clone().subst(&subst_so_far).cast(&Interner)); 145 self.vec
146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner));
143 } 147 }
144 } 148 }
145 self 149 self
@@ -192,15 +196,15 @@ impl TyBuilder<TypeAliasId> {
192 } 196 }
193} 197}
194 198
195impl<T: TypeWalk + HasInterner<Interner = Interner>> TyBuilder<Binders<T>> { 199impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
196 fn subst_binders(b: Binders<T>) -> Self { 200 fn subst_binders(b: Binders<T>) -> Self {
197 let param_count = b.num_binders; 201 let param_count = b.binders.len(&Interner);
198 TyBuilder::new(b, param_count) 202 TyBuilder::new(b, param_count)
199 } 203 }
200 204
201 pub fn build(self) -> T { 205 pub fn build(self) -> <T as Fold<Interner>>::Result {
202 let (b, subst) = self.build_internal(); 206 let (b, subst) = self.build_internal();
203 b.subst(&subst) 207 b.substitute(&Interner, &subst)
204 } 208 }
205} 209}
206 210
diff --git a/crates/hir_ty/src/chalk_cast.rs b/crates/hir_ty/src/chalk_cast.rs
deleted file mode 100644
index df6492113..000000000
--- a/crates/hir_ty/src/chalk_cast.rs
+++ /dev/null
@@ -1,73 +0,0 @@
1//! Implementations of the Chalk `Cast` trait for our types.
2
3use chalk_ir::{
4 cast::{Cast, CastTo},
5 interner::HasInterner,
6};
7
8use crate::{AliasEq, DomainGoal, GenericArg, GenericArgData, Interner, TraitRef, Ty, WhereClause};
9
10macro_rules! has_interner {
11 ($t:ty) => {
12 impl HasInterner for $t {
13 type Interner = crate::Interner;
14 }
15 };
16}
17
18has_interner!(WhereClause);
19has_interner!(DomainGoal);
20has_interner!(GenericArg);
21has_interner!(Ty);
22
23impl CastTo<WhereClause> for TraitRef {
24 fn cast_to(self, _interner: &Interner) -> WhereClause {
25 WhereClause::Implemented(self)
26 }
27}
28
29impl CastTo<WhereClause> for AliasEq {
30 fn cast_to(self, _interner: &Interner) -> WhereClause {
31 WhereClause::AliasEq(self)
32 }
33}
34
35impl CastTo<DomainGoal> for WhereClause {
36 fn cast_to(self, _interner: &Interner) -> DomainGoal {
37 DomainGoal::Holds(self)
38 }
39}
40
41impl CastTo<GenericArg> for Ty {
42 fn cast_to(self, interner: &Interner) -> GenericArg {
43 GenericArg::new(interner, GenericArgData::Ty(self))
44 }
45}
46
47macro_rules! transitive_impl {
48 ($a:ty, $b:ty, $c:ty) => {
49 impl CastTo<$c> for $a {
50 fn cast_to(self, interner: &Interner) -> $c {
51 self.cast::<$b>(interner).cast(interner)
52 }
53 }
54 };
55}
56
57// In Chalk, these can be done as blanket impls, but that doesn't work here
58// because of coherence
59
60transitive_impl!(TraitRef, WhereClause, DomainGoal);
61transitive_impl!(AliasEq, WhereClause, DomainGoal);
62
63macro_rules! reflexive_impl {
64 ($a:ty) => {
65 impl CastTo<$a> for $a {
66 fn cast_to(self, _interner: &Interner) -> $a {
67 self
68 }
69 }
70 };
71}
72
73reflexive_impl!(GenericArg);
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/chalk_db.rs
index 541e6082f..8f054d06b 100644
--- a/crates/hir_ty/src/traits/chalk.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -1,52 +1,47 @@
1//! Conversion code from/to Chalk. 1//! The implementation of `RustIrDatabase` for Chalk, which provides information
2//! about the code that Chalk needs.
2use std::sync::Arc; 3use std::sync::Arc;
3 4
4use log::debug; 5use log::debug;
5 6
6use chalk_ir::{fold::shift::Shift, CanonicalVarKinds}; 7use chalk_ir::{cast::Cast, fold::shift::Shift, CanonicalVarKinds};
7use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait}; 8use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
8 9
9use base_db::{salsa::InternKey, CrateId}; 10use base_db::CrateId;
10use hir_def::{ 11use hir_def::{
11 lang_item::{lang_attr, LangItemTarget}, 12 lang_item::{lang_attr, LangItemTarget},
12 AssocContainerId, AssocItemId, HasModule, Lookup, TypeAliasId, 13 AssocContainerId, AssocItemId, GenericDefId, HasModule, Lookup, TypeAliasId,
13}; 14};
14use hir_expand::name::name; 15use hir_expand::name::name;
15 16
16use super::ChalkContext;
17use crate::{ 17use crate::{
18 db::HirDatabase, 18 db::HirDatabase,
19 display::HirDisplay, 19 display::HirDisplay,
20 from_assoc_type_id, 20 from_assoc_type_id, from_chalk_trait_id, make_only_type_binders,
21 mapping::{from_chalk, ToChalk, TypeAliasAsValue},
21 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS}, 22 method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
22 to_assoc_type_id, to_chalk_trait_id, 23 to_assoc_type_id, to_chalk_trait_id,
24 traits::ChalkContext,
23 utils::generics, 25 utils::generics,
24 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, ProjectionTy, Substitution, 26 AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
25 TraitRef, Ty, TyBuilder, TyKind, WhereClause, 27 ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
28 TyExt, TyKind, WhereClause,
26}; 29};
27use mapping::{
28 convert_where_clauses, generic_predicate_to_inline_bound, make_binders, TypeAliasAsValue,
29};
30
31pub use self::interner::Interner;
32pub(crate) use self::interner::*;
33 30
34pub(super) mod tls; 31pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
35mod interner; 32pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>;
36mod mapping; 33pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>;
37 34pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>;
38pub(crate) trait ToChalk { 35pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>;
39 type Chalk; 36
40 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk; 37pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
41 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self; 38pub(crate) type TraitId = chalk_ir::TraitId<Interner>;
42} 39pub(crate) type AdtId = chalk_ir::AdtId<Interner>;
43 40pub(crate) type ImplId = chalk_ir::ImplId<Interner>;
44pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T 41pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>;
45where 42pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>;
46 T: ToChalk<Chalk = ChalkT>, 43pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>;
47{ 44pub(crate) type Variances = chalk_ir::Variances<Interner>;
48 T::from_chalk(db, chalk)
49}
50 45
51impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { 46impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
52 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> { 47 fn associated_ty_data(&self, id: AssocTypeId) -> Arc<AssociatedTyDatum> {
@@ -84,9 +79,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
84 binders: &CanonicalVarKinds<Interner>, 79 binders: &CanonicalVarKinds<Interner>,
85 ) -> Vec<ImplId> { 80 ) -> Vec<ImplId> {
86 debug!("impls_for_trait {:?}", trait_id); 81 debug!("impls_for_trait {:?}", trait_id);
87 let trait_: hir_def::TraitId = from_chalk(self.db, trait_id); 82 let trait_: hir_def::TraitId = from_chalk_trait_id(trait_id);
88 83
89 let ty: Ty = from_chalk(self.db, parameters[0].assert_ty_ref(&Interner).clone()); 84 let ty: Ty = parameters[0].assert_ty_ref(&Interner).clone();
90 85
91 fn binder_kind( 86 fn binder_kind(
92 ty: &Ty, 87 ty: &Ty,
@@ -103,7 +98,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
103 None 98 None
104 } 99 }
105 100
106 let self_ty_fp = TyFingerprint::for_impl(&ty); 101 let self_ty_fp = TyFingerprint::for_trait_impl(&ty);
107 let fps: &[TyFingerprint] = match binder_kind(&ty, binders) { 102 let fps: &[TyFingerprint] = match binder_kind(&ty, binders) {
108 Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS, 103 Some(chalk_ir::TyVariableKind::Integer) => &ALL_INT_FPS,
109 Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS, 104 Some(chalk_ir::TyVariableKind::Float) => &ALL_FLOAT_FPS,
@@ -166,7 +161,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
166 Some(LangItemTarget::TraitId(trait_)) => trait_, 161 Some(LangItemTarget::TraitId(trait_)) => trait_,
167 _ => return None, 162 _ => return None,
168 }; 163 };
169 Some(trait_.to_chalk(self.db)) 164 Some(to_chalk_trait_id(trait_))
170 } 165 }
171 166
172 fn program_clauses_for_env( 167 fn program_clauses_for_env(
@@ -184,16 +179,16 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
184 .db 179 .db
185 .return_type_impl_traits(func) 180 .return_type_impl_traits(func)
186 .expect("impl trait id without impl traits"); 181 .expect("impl trait id without impl traits");
187 let data = &datas.value.impl_traits[idx as usize]; 182 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
183 let data = &datas.impl_traits[idx as usize];
188 let bound = OpaqueTyDatumBound { 184 let bound = OpaqueTyDatumBound {
189 bounds: make_binders( 185 bounds: make_only_type_binders(
190 data.bounds.value.iter().cloned().map(|b| b.to_chalk(self.db)).collect(),
191 1, 186 1,
187 data.bounds.skip_binders().iter().cloned().collect(),
192 ), 188 ),
193 where_clauses: make_binders(vec![], 0), 189 where_clauses: make_only_type_binders(0, vec![]),
194 }; 190 };
195 let num_vars = datas.num_binders; 191 chalk_ir::Binders::new(binders, bound)
196 make_binders(bound, num_vars)
197 } 192 }
198 crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => { 193 crate::ImplTraitId::AsyncBlockTypeImplTrait(..) => {
199 if let Some((future_trait, future_output)) = self 194 if let Some((future_trait, future_output)) = self
@@ -215,7 +210,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
215 let impl_bound = WhereClause::Implemented(TraitRef { 210 let impl_bound = WhereClause::Implemented(TraitRef {
216 trait_id: to_chalk_trait_id(future_trait), 211 trait_id: to_chalk_trait_id(future_trait),
217 // Self type as the first parameter. 212 // Self type as the first parameter.
218 substitution: Substitution::single( 213 substitution: Substitution::from1(
214 &Interner,
219 TyKind::BoundVar(BoundVar { 215 TyKind::BoundVar(BoundVar {
220 debruijn: DebruijnIndex::INNERMOST, 216 debruijn: DebruijnIndex::INNERMOST,
221 index: 0, 217 index: 0,
@@ -227,7 +223,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
227 alias: AliasTy::Projection(ProjectionTy { 223 alias: AliasTy::Projection(ProjectionTy {
228 associated_ty_id: to_assoc_type_id(future_output), 224 associated_ty_id: to_assoc_type_id(future_output),
229 // Self type as the first parameter. 225 // Self type as the first parameter.
230 substitution: Substitution::single( 226 substitution: Substitution::from1(
227 &Interner,
231 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 228 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
232 .intern(&Interner), 229 .intern(&Interner),
233 ), 230 ),
@@ -237,25 +234,25 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
237 .intern(&Interner), 234 .intern(&Interner),
238 }); 235 });
239 let bound = OpaqueTyDatumBound { 236 let bound = OpaqueTyDatumBound {
240 bounds: make_binders( 237 bounds: make_only_type_binders(
238 1,
241 vec![ 239 vec![
242 wrap_in_empty_binders(impl_bound).to_chalk(self.db), 240 crate::wrap_empty_binders(impl_bound),
243 wrap_in_empty_binders(proj_bound).to_chalk(self.db), 241 crate::wrap_empty_binders(proj_bound),
244 ], 242 ],
245 1,
246 ), 243 ),
247 where_clauses: make_binders(vec![], 0), 244 where_clauses: make_only_type_binders(0, vec![]),
248 }; 245 };
249 // The opaque type has 1 parameter. 246 // The opaque type has 1 parameter.
250 make_binders(bound, 1) 247 make_only_type_binders(1, bound)
251 } else { 248 } else {
252 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback. 249 // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
253 let bound = OpaqueTyDatumBound { 250 let bound = OpaqueTyDatumBound {
254 bounds: make_binders(vec![], 0), 251 bounds: make_only_type_binders(0, vec![]),
255 where_clauses: make_binders(vec![], 0), 252 where_clauses: make_only_type_binders(0, vec![]),
256 }; 253 };
257 // The opaque type has 1 parameter. 254 // The opaque type has 1 parameter.
258 make_binders(bound, 1) 255 make_only_type_binders(1, bound)
259 } 256 }
260 } 257 }
261 }; 258 };
@@ -265,7 +262,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
265 262
266 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { 263 fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> {
267 // FIXME: actually provide the hidden type; it is relevant for auto traits 264 // FIXME: actually provide the hidden type; it is relevant for auto traits
268 TyKind::Unknown.intern(&Interner).to_chalk(self.db) 265 TyKind::Error.intern(&Interner)
269 } 266 }
270 267
271 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool { 268 fn is_object_safe(&self, _trait_id: chalk_ir::TraitId<Interner>) -> bool {
@@ -286,33 +283,32 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
286 _closure_id: chalk_ir::ClosureId<Interner>, 283 _closure_id: chalk_ir::ClosureId<Interner>,
287 substs: &chalk_ir::Substitution<Interner>, 284 substs: &chalk_ir::Substitution<Interner>,
288 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> { 285 ) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
289 let sig_ty: Ty = 286 let sig_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
290 from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
291 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr"); 287 let sig = &sig_ty.callable_sig(self.db).expect("first closure param should be fn ptr");
292 let io = rust_ir::FnDefInputsAndOutputDatum { 288 let io = rust_ir::FnDefInputsAndOutputDatum {
293 argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(), 289 argument_types: sig.params().iter().cloned().collect(),
294 return_type: sig.ret().clone().to_chalk(self.db), 290 return_type: sig.ret().clone(),
295 }; 291 };
296 make_binders(io.shifted_in(&Interner), 0) 292 make_only_type_binders(0, io.shifted_in(&Interner))
297 } 293 }
298 fn closure_upvars( 294 fn closure_upvars(
299 &self, 295 &self,
300 _closure_id: chalk_ir::ClosureId<Interner>, 296 _closure_id: chalk_ir::ClosureId<Interner>,
301 _substs: &chalk_ir::Substitution<Interner>, 297 _substs: &chalk_ir::Substitution<Interner>,
302 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> { 298 ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
303 let ty = TyBuilder::unit().to_chalk(self.db); 299 let ty = TyBuilder::unit();
304 make_binders(ty, 0) 300 make_only_type_binders(0, ty)
305 } 301 }
306 fn closure_fn_substitution( 302 fn closure_fn_substitution(
307 &self, 303 &self,
308 _closure_id: chalk_ir::ClosureId<Interner>, 304 _closure_id: chalk_ir::ClosureId<Interner>,
309 _substs: &chalk_ir::Substitution<Interner>, 305 _substs: &chalk_ir::Substitution<Interner>,
310 ) -> chalk_ir::Substitution<Interner> { 306 ) -> chalk_ir::Substitution<Interner> {
311 Substitution::empty(&Interner).to_chalk(self.db) 307 Substitution::empty(&Interner)
312 } 308 }
313 309
314 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String { 310 fn trait_name(&self, trait_id: chalk_ir::TraitId<Interner>) -> String {
315 let id = from_chalk(self.db, trait_id); 311 let id = from_chalk_trait_id(trait_id);
316 self.db.trait_data(id).name.to_string() 312 self.db.trait_data(id).name.to_string()
317 } 313 }
318 fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String { 314 fn adt_name(&self, chalk_ir::AdtId(adt_id): AdtId) -> String {
@@ -403,10 +399,10 @@ pub(crate) fn associated_ty_data_query(
403 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); 399 let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars);
404 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; 400 let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses };
405 let datum = AssociatedTyDatum { 401 let datum = AssociatedTyDatum {
406 trait_id: trait_.to_chalk(db), 402 trait_id: to_chalk_trait_id(trait_),
407 id, 403 id,
408 name: type_alias, 404 name: type_alias,
409 binders: make_binders(bound_data, generic_params.len()), 405 binders: make_only_type_binders(generic_params.len(), bound_data),
410 }; 406 };
411 Arc::new(datum) 407 Arc::new(datum)
412} 408}
@@ -417,7 +413,7 @@ pub(crate) fn trait_datum_query(
417 trait_id: TraitId, 413 trait_id: TraitId,
418) -> Arc<TraitDatum> { 414) -> Arc<TraitDatum> {
419 debug!("trait_datum {:?}", trait_id); 415 debug!("trait_datum {:?}", trait_id);
420 let trait_: hir_def::TraitId = from_chalk(db, trait_id); 416 let trait_ = from_chalk_trait_id(trait_id);
421 let trait_data = db.trait_data(trait_); 417 let trait_data = db.trait_data(trait_);
422 debug!("trait {:?} = {:?}", trait_id, trait_data.name); 418 debug!("trait {:?} = {:?}", trait_id, trait_data.name);
423 let generic_params = generics(db.upcast(), trait_.into()); 419 let generic_params = generics(db.upcast(), trait_.into());
@@ -439,7 +435,7 @@ pub(crate) fn trait_datum_query(
439 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); 435 lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
440 let trait_datum = TraitDatum { 436 let trait_datum = TraitDatum {
441 id: trait_id, 437 id: trait_id,
442 binders: make_binders(trait_datum_bound, bound_vars.len(&Interner)), 438 binders: make_only_type_binders(bound_vars.len(&Interner), trait_datum_bound),
443 flags, 439 flags,
444 associated_ty_ids, 440 associated_ty_ids,
445 well_known, 441 well_known,
@@ -508,7 +504,7 @@ pub(crate) fn struct_datum_query(
508 // FIXME set ADT kind 504 // FIXME set ADT kind
509 kind: rust_ir::AdtKind::Struct, 505 kind: rust_ir::AdtKind::Struct,
510 id: struct_id, 506 id: struct_id,
511 binders: make_binders(struct_datum_bound, num_params), 507 binders: make_only_type_binders(num_params, struct_datum_bound),
512 flags, 508 flags,
513 }; 509 };
514 Arc::new(struct_datum) 510 Arc::new(struct_datum)
@@ -535,7 +531,8 @@ fn impl_def_datum(
535 .impl_trait(impl_id) 531 .impl_trait(impl_id)
536 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk 532 // ImplIds for impls where the trait ref can't be resolved should never reach Chalk
537 .expect("invalid impl passed to Chalk") 533 .expect("invalid impl passed to Chalk")
538 .value; 534 .into_value_and_skipped_binders()
535 .0;
539 let impl_data = db.impl_data(impl_id); 536 let impl_data = db.impl_data(impl_id);
540 537
541 let generic_params = generics(db.upcast(), impl_id.into()); 538 let generic_params = generics(db.upcast(), impl_id.into());
@@ -555,7 +552,6 @@ fn impl_def_datum(
555 trait_ref.display(db), 552 trait_ref.display(db),
556 where_clauses 553 where_clauses
557 ); 554 );
558 let trait_ref = trait_ref.to_chalk(db);
559 555
560 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; 556 let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive };
561 557
@@ -577,7 +573,7 @@ fn impl_def_datum(
577 .collect(); 573 .collect();
578 debug!("impl_datum: {:?}", impl_datum_bound); 574 debug!("impl_datum: {:?}", impl_datum_bound);
579 let impl_datum = ImplDatum { 575 let impl_datum = ImplDatum {
580 binders: make_binders(impl_datum_bound, bound_vars.len(&Interner)), 576 binders: make_only_type_binders(bound_vars.len(&Interner), impl_datum_bound),
581 impl_type, 577 impl_type,
582 polarity, 578 polarity,
583 associated_ty_value_ids, 579 associated_ty_value_ids,
@@ -605,18 +601,22 @@ fn type_alias_associated_ty_value(
605 _ => panic!("assoc ty value should be in impl"), 601 _ => panic!("assoc ty value should be in impl"),
606 }; 602 };
607 603
608 let trait_ref = db.impl_trait(impl_id).expect("assoc ty value should not exist").value; // we don't return any assoc ty values if the impl'd trait can't be resolved 604 let trait_ref = db
605 .impl_trait(impl_id)
606 .expect("assoc ty value should not exist")
607 .into_value_and_skipped_binders()
608 .0; // we don't return any assoc ty values if the impl'd trait can't be resolved
609 609
610 let assoc_ty = db 610 let assoc_ty = db
611 .trait_data(trait_ref.hir_trait_id()) 611 .trait_data(trait_ref.hir_trait_id())
612 .associated_type_by_name(&type_alias_data.name) 612 .associated_type_by_name(&type_alias_data.name)
613 .expect("assoc ty value should not exist"); // validated when building the impl data as well 613 .expect("assoc ty value should not exist"); // validated when building the impl data as well
614 let ty = db.ty(type_alias.into()); 614 let (ty, binders) = db.ty(type_alias.into()).into_value_and_skipped_binders();
615 let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; 615 let value_bound = rust_ir::AssociatedTyValueBound { ty };
616 let value = rust_ir::AssociatedTyValue { 616 let value = rust_ir::AssociatedTyValue {
617 impl_id: impl_id.to_chalk(db), 617 impl_id: impl_id.to_chalk(db),
618 associated_ty_id: to_assoc_type_id(assoc_ty), 618 associated_ty_id: to_assoc_type_id(assoc_ty),
619 value: make_binders(value_bound, ty.num_binders), 619 value: chalk_ir::Binders::new(binders, value_bound),
620 }; 620 };
621 Arc::new(value) 621 Arc::new(value)
622} 622}
@@ -628,34 +628,25 @@ pub(crate) fn fn_def_datum_query(
628) -> Arc<FnDefDatum> { 628) -> Arc<FnDefDatum> {
629 let callable_def: CallableDefId = from_chalk(db, fn_def_id); 629 let callable_def: CallableDefId = from_chalk(db, fn_def_id);
630 let generic_params = generics(db.upcast(), callable_def.into()); 630 let generic_params = generics(db.upcast(), callable_def.into());
631 let sig = db.callable_item_signature(callable_def); 631 let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
632 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST); 632 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
633 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); 633 let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
634 let bound = rust_ir::FnDefDatumBound { 634 let bound = rust_ir::FnDefDatumBound {
635 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway 635 // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
636 inputs_and_output: make_binders( 636 inputs_and_output: make_only_type_binders(
637 0,
637 rust_ir::FnDefInputsAndOutputDatum { 638 rust_ir::FnDefInputsAndOutputDatum {
638 argument_types: sig 639 argument_types: sig.params().iter().cloned().collect(),
639 .value 640 return_type: sig.ret().clone(),
640 .params()
641 .iter()
642 .map(|ty| ty.clone().to_chalk(db))
643 .collect(),
644 return_type: sig.value.ret().clone().to_chalk(db),
645 } 641 }
646 .shifted_in(&Interner), 642 .shifted_in(&Interner),
647 0,
648 ), 643 ),
649 where_clauses, 644 where_clauses,
650 }; 645 };
651 let datum = FnDefDatum { 646 let datum = FnDefDatum {
652 id: fn_def_id, 647 id: fn_def_id,
653 sig: chalk_ir::FnSig { 648 sig: chalk_ir::FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: sig.is_varargs },
654 abi: (), 649 binders: chalk_ir::Binders::new(binders, bound),
655 safety: chalk_ir::Safety::Safe,
656 variadic: sig.value.is_varargs,
657 },
658 binders: make_binders(bound, sig.num_binders),
659 }; 650 };
660 Arc::new(datum) 651 Arc::new(datum)
661} 652}
@@ -685,42 +676,65 @@ pub(crate) fn adt_variance_query(
685 ) 676 )
686} 677}
687 678
688impl From<FnDefId> for crate::db::InternedCallableDefId { 679pub(super) fn convert_where_clauses(
689 fn from(fn_def_id: FnDefId) -> Self { 680 db: &dyn HirDatabase,
690 InternKey::from_intern_id(fn_def_id.0) 681 def: GenericDefId,
691 } 682 substs: &Substitution,
692} 683) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
693 684 let generic_predicates = db.generic_predicates(def);
694impl From<crate::db::InternedCallableDefId> for FnDefId { 685 let mut result = Vec::with_capacity(generic_predicates.len());
695 fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self { 686 for pred in generic_predicates.iter() {
696 chalk_ir::FnDefId(callable_def_id.as_intern_id()) 687 result.push(pred.clone().substitute(&Interner, substs));
697 } 688 }
698} 689 result
699
700impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
701 fn from(id: OpaqueTyId) -> Self {
702 InternKey::from_intern_id(id.0)
703 }
704}
705
706impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
707 fn from(id: crate::db::InternedOpaqueTyId) -> Self {
708 chalk_ir::OpaqueTyId(id.as_intern_id())
709 }
710}
711
712impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
713 fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
714 Self::from_intern_id(id.0)
715 }
716} 690}
717 691
718impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> { 692pub(super) fn generic_predicate_to_inline_bound(
719 fn from(id: crate::db::InternedClosureId) -> Self { 693 db: &dyn HirDatabase,
720 chalk_ir::ClosureId(id.as_intern_id()) 694 pred: &QuantifiedWhereClause,
695 self_ty: &Ty,
696) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
697 // An InlineBound is like a GenericPredicate, except the self type is left out.
698 // We don't have a special type for this, but Chalk does.
699 let self_ty_shifted_in = self_ty.clone().shifted_in_from(&Interner, DebruijnIndex::ONE);
700 let (pred, binders) = pred.as_ref().into_value_and_skipped_binders();
701 match pred {
702 WhereClause::Implemented(trait_ref) => {
703 if trait_ref.self_type_parameter(&Interner) != self_ty_shifted_in {
704 // we can only convert predicates back to type bounds if they
705 // have the expected self type
706 return None;
707 }
708 let args_no_self = trait_ref.substitution.as_slice(&Interner)[1..]
709 .iter()
710 .map(|ty| ty.clone().cast(&Interner))
711 .collect();
712 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
713 Some(chalk_ir::Binders::new(binders, rust_ir::InlineBound::TraitBound(trait_bound)))
714 }
715 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
716 if projection_ty.self_type_parameter(&Interner) != self_ty_shifted_in {
717 return None;
718 }
719 let trait_ = projection_ty.trait_(db);
720 let args_no_self = projection_ty.substitution.as_slice(&Interner)[1..]
721 .iter()
722 .map(|ty| ty.clone().cast(&Interner))
723 .collect();
724 let alias_eq_bound = rust_ir::AliasEqBound {
725 value: ty.clone(),
726 trait_bound: rust_ir::TraitBound {
727 trait_id: to_chalk_trait_id(trait_),
728 args_no_self,
729 },
730 associated_ty_id: projection_ty.associated_ty_id,
731 parameters: Vec::new(), // FIXME we don't support generic associated types yet
732 };
733 Some(chalk_ir::Binders::new(
734 binders,
735 rust_ir::InlineBound::AliasEqBound(alias_eq_bound),
736 ))
737 }
738 _ => None,
721 } 739 }
722} 740}
723
724fn wrap_in_empty_binders<T: crate::TypeWalk>(value: T) -> crate::Binders<T> {
725 crate::Binders::wrap_empty(value)
726}
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index b7463366b..8c4542956 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -1,13 +1,305 @@
1//! Various extensions traits for Chalk types. 1//! Various extensions traits for Chalk types.
2 2
3use crate::{Interner, Ty, TyKind}; 3use chalk_ir::Mutability;
4use hir_def::{
5 type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, Lookup, TraitId,
6};
7
8use crate::{
9 db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
10 from_placeholder_idx, to_chalk_trait_id, AdtId, AliasEq, AliasTy, Binders, CallableDefId,
11 CallableSig, FnPointer, ImplTraitId, Interner, Lifetime, ProjectionTy, QuantifiedWhereClause,
12 Substitution, TraitRef, Ty, TyBuilder, TyKind, WhereClause,
13};
4 14
5pub trait TyExt { 15pub trait TyExt {
6 fn is_unit(&self) -> bool; 16 fn is_unit(&self) -> bool;
17 fn is_never(&self) -> bool;
18 fn is_unknown(&self) -> bool;
19
20 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)>;
21 fn as_tuple(&self) -> Option<&Substitution>;
22 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId>;
23 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)>;
24 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)>;
25 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId>;
26
27 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId>;
28 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig>;
29
30 fn strip_references(&self) -> &Ty;
31
32 /// If this is a `dyn Trait`, returns that trait.
33 fn dyn_trait(&self) -> Option<TraitId>;
34
35 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>>;
36 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId>;
37
38 /// FIXME: Get rid of this, it's not a good abstraction
39 fn equals_ctor(&self, other: &Ty) -> bool;
7} 40}
8 41
9impl TyExt for Ty { 42impl TyExt for Ty {
10 fn is_unit(&self) -> bool { 43 fn is_unit(&self) -> bool {
11 matches!(self.kind(&Interner), TyKind::Tuple(0, _)) 44 matches!(self.kind(&Interner), TyKind::Tuple(0, _))
12 } 45 }
46
47 fn is_never(&self) -> bool {
48 matches!(self.kind(&Interner), TyKind::Never)
49 }
50
51 fn is_unknown(&self) -> bool {
52 matches!(self.kind(&Interner), TyKind::Error)
53 }
54
55 fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
56 match self.kind(&Interner) {
57 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
58 _ => None,
59 }
60 }
61
62 fn as_tuple(&self) -> Option<&Substitution> {
63 match self.kind(&Interner) {
64 TyKind::Tuple(_, substs) => Some(substs),
65 _ => None,
66 }
67 }
68
69 fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
70 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
71 Some(func)
72 } else {
73 None
74 }
75 }
76 fn as_reference(&self) -> Option<(&Ty, Lifetime, Mutability)> {
77 match self.kind(&Interner) {
78 TyKind::Ref(mutability, lifetime, ty) => Some((ty, lifetime.clone(), *mutability)),
79 _ => None,
80 }
81 }
82
83 fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
84 match self.kind(&Interner) {
85 TyKind::Ref(mutability, _, ty) => Some((ty, Rawness::Ref, *mutability)),
86 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
87 _ => None,
88 }
89 }
90
91 fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
92 match *self.kind(&Interner) {
93 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
94 TyKind::FnDef(callable, ..) => {
95 Some(db.lookup_intern_callable_def(callable.into()).into())
96 }
97 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
98 TyKind::Foreign(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
99 _ => None,
100 }
101 }
102
103 fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
104 match self.kind(&Interner) {
105 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
106 _ => None,
107 }
108 }
109
110 fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
111 match self.kind(&Interner) {
112 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
113 TyKind::FnDef(def, parameters) => {
114 let callable_def = db.lookup_intern_callable_def((*def).into());
115 let sig = db.callable_item_signature(callable_def);
116 Some(sig.substitute(&Interner, &parameters))
117 }
118 TyKind::Closure(.., substs) => {
119 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
120 sig_param.callable_sig(db)
121 }
122 _ => None,
123 }
124 }
125
126 fn dyn_trait(&self) -> Option<TraitId> {
127 let trait_ref = match self.kind(&Interner) {
128 TyKind::Dyn(dyn_ty) => dyn_ty.bounds.skip_binders().interned().get(0).and_then(|b| {
129 match b.skip_binders() {
130 WhereClause::Implemented(trait_ref) => Some(trait_ref),
131 _ => None,
132 }
133 }),
134 _ => None,
135 }?;
136 Some(from_chalk_trait_id(trait_ref.trait_id))
137 }
138
139 fn strip_references(&self) -> &Ty {
140 let mut t: &Ty = self;
141 while let TyKind::Ref(_mutability, _lifetime, ty) = t.kind(&Interner) {
142 t = ty;
143 }
144 t
145 }
146
147 fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
148 match self.kind(&Interner) {
149 TyKind::OpaqueType(opaque_ty_id, ..) => {
150 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
151 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
152 let krate = def.module(db.upcast()).krate();
153 if let Some(future_trait) = db
154 .lang_item(krate, "future_trait".into())
155 .and_then(|item| item.as_trait())
156 {
157 // This is only used by type walking.
158 // Parameters will be walked outside, and projection predicate is not used.
159 // So just provide the Future trait.
160 let impl_bound = Binders::empty(
161 &Interner,
162 WhereClause::Implemented(TraitRef {
163 trait_id: to_chalk_trait_id(future_trait),
164 substitution: Substitution::empty(&Interner),
165 }),
166 );
167 Some(vec![impl_bound])
168 } else {
169 None
170 }
171 }
172 ImplTraitId::ReturnTypeImplTrait(..) => None,
173 }
174 }
175 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
176 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
177 {
178 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
179 db.return_type_impl_traits(func).map(|it| {
180 let data = (*it)
181 .as_ref()
182 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
183 data.substitute(&Interner, &opaque_ty.substitution)
184 })
185 }
186 // It always has an parameter for Future::Output type.
187 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
188 };
189
190 predicates.map(|it| it.into_value_and_skipped_binders().0)
191 }
192 TyKind::Placeholder(idx) => {
193 let id = from_placeholder_idx(db, *idx);
194 let generic_params = db.generic_params(id.parent);
195 let param_data = &generic_params.types[id.local_id];
196 match param_data.provenance {
197 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
198 let substs = TyBuilder::type_params_subst(db, id.parent);
199 let predicates = db
200 .generic_predicates(id.parent)
201 .into_iter()
202 .map(|pred| pred.clone().substitute(&Interner, &substs))
203 .filter(|wc| match &wc.skip_binders() {
204 WhereClause::Implemented(tr) => {
205 &tr.self_type_parameter(&Interner) == self
206 }
207 WhereClause::AliasEq(AliasEq {
208 alias: AliasTy::Projection(proj),
209 ty: _,
210 }) => &proj.self_type_parameter(&Interner) == self,
211 _ => false,
212 })
213 .collect::<Vec<_>>();
214
215 Some(predicates)
216 }
217 _ => None,
218 }
219 }
220 _ => None,
221 }
222 }
223
224 fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
225 match self.kind(&Interner) {
226 TyKind::AssociatedType(id, ..) => {
227 match from_assoc_type_id(*id).lookup(db.upcast()).container {
228 AssocContainerId::TraitId(trait_id) => Some(trait_id),
229 _ => None,
230 }
231 }
232 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
233 match from_assoc_type_id(projection_ty.associated_ty_id)
234 .lookup(db.upcast())
235 .container
236 {
237 AssocContainerId::TraitId(trait_id) => Some(trait_id),
238 _ => None,
239 }
240 }
241 _ => None,
242 }
243 }
244
245 fn equals_ctor(&self, other: &Ty) -> bool {
246 match (self.kind(&Interner), other.kind(&Interner)) {
247 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
248 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_, _), TyKind::Array(_, _)) => {
249 true
250 }
251 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
252 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
253 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
254 ty_id == ty_id2
255 }
256 (TyKind::Foreign(ty_id, ..), TyKind::Foreign(ty_id2, ..)) => ty_id == ty_id2,
257 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
258 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
259 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
260 mutability == mutability2
261 }
262 (
263 TyKind::Function(FnPointer { num_binders, sig, .. }),
264 TyKind::Function(FnPointer { num_binders: num_binders2, sig: sig2, .. }),
265 ) => num_binders == num_binders2 && sig == sig2,
266 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
267 cardinality == cardinality2
268 }
269 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
270 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
271 _ => false,
272 }
273 }
274}
275
276pub trait ProjectionTyExt {
277 fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef;
278 fn trait_(&self, db: &dyn HirDatabase) -> TraitId;
279}
280
281impl ProjectionTyExt for ProjectionTy {
282 fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
283 TraitRef {
284 trait_id: to_chalk_trait_id(self.trait_(db)),
285 substitution: self.substitution.clone(),
286 }
287 }
288
289 fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
290 match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
291 AssocContainerId::TraitId(it) => it,
292 _ => panic!("projection ty without parent trait"),
293 }
294 }
295}
296
297pub trait TraitRefExt {
298 fn hir_trait_id(&self) -> TraitId;
299}
300
301impl TraitRefExt for TraitRef {
302 fn hir_trait_id(&self) -> TraitId {
303 from_chalk_trait_id(self.trait_id)
304 }
13} 305}
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 58e4247c6..cf67d4266 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -1,18 +1,19 @@
1//! FIXME: write short doc here 1//! The home of `HirDatabase`, which is the Salsa database containing all the
2//! type inference-related queries.
2 3
3use std::sync::Arc; 4use std::sync::Arc;
4 5
5use base_db::{impl_intern_key, salsa, CrateId, Upcast}; 6use base_db::{impl_intern_key, salsa, CrateId, Upcast};
6use hir_def::{ 7use hir_def::{
7 db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId, 8 db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId,
8 LocalFieldId, TypeParamId, VariantId, 9 LifetimeParamId, LocalFieldId, TypeParamId, VariantId,
9}; 10};
10use la_arena::ArenaMap; 11use la_arena::ArenaMap;
11 12
12use crate::{ 13use crate::{
14 chalk_db,
13 method_resolution::{InherentImpls, TraitImpls}, 15 method_resolution::{InherentImpls, TraitImpls},
14 traits::chalk, 16 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, Interner, PolyFnSig,
15 Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, PolyFnSig,
16 QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId, 17 QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
17}; 18};
18use hir_expand::name::Name; 19use hir_expand::name::Name;
@@ -86,51 +87,68 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
86 #[salsa::interned] 87 #[salsa::interned]
87 fn intern_type_param_id(&self, param_id: TypeParamId) -> InternedTypeParamId; 88 fn intern_type_param_id(&self, param_id: TypeParamId) -> InternedTypeParamId;
88 #[salsa::interned] 89 #[salsa::interned]
90 fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
91 #[salsa::interned]
92 fn intern_const_param_id(&self, param_id: ConstParamId) -> InternedConstParamId;
93 #[salsa::interned]
89 fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId; 94 fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
90 #[salsa::interned] 95 #[salsa::interned]
91 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId; 96 fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
92 97
93 #[salsa::invoke(chalk::associated_ty_data_query)] 98 #[salsa::invoke(chalk_db::associated_ty_data_query)]
94 fn associated_ty_data(&self, id: chalk::AssocTypeId) -> Arc<chalk::AssociatedTyDatum>; 99 fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
95 100
96 #[salsa::invoke(chalk::trait_datum_query)] 101 #[salsa::invoke(chalk_db::trait_datum_query)]
97 fn trait_datum(&self, krate: CrateId, trait_id: chalk::TraitId) -> Arc<chalk::TraitDatum>; 102 fn trait_datum(&self, krate: CrateId, trait_id: chalk_db::TraitId)
103 -> Arc<chalk_db::TraitDatum>;
98 104
99 #[salsa::invoke(chalk::struct_datum_query)] 105 #[salsa::invoke(chalk_db::struct_datum_query)]
100 fn struct_datum(&self, krate: CrateId, struct_id: chalk::AdtId) -> Arc<chalk::StructDatum>; 106 fn struct_datum(
107 &self,
108 krate: CrateId,
109 struct_id: chalk_db::AdtId,
110 ) -> Arc<chalk_db::StructDatum>;
101 111
102 #[salsa::invoke(crate::traits::chalk::impl_datum_query)] 112 #[salsa::invoke(chalk_db::impl_datum_query)]
103 fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; 113 fn impl_datum(&self, krate: CrateId, impl_id: chalk_db::ImplId) -> Arc<chalk_db::ImplDatum>;
104 114
105 #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] 115 #[salsa::invoke(chalk_db::fn_def_datum_query)]
106 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk::FnDefDatum>; 116 fn fn_def_datum(&self, krate: CrateId, fn_def_id: FnDefId) -> Arc<chalk_db::FnDefDatum>;
107 117
108 #[salsa::invoke(crate::traits::chalk::fn_def_variance_query)] 118 #[salsa::invoke(chalk_db::fn_def_variance_query)]
109 fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk::Variances; 119 fn fn_def_variance(&self, krate: CrateId, fn_def_id: FnDefId) -> chalk_db::Variances;
110 120
111 #[salsa::invoke(crate::traits::chalk::adt_variance_query)] 121 #[salsa::invoke(chalk_db::adt_variance_query)]
112 fn adt_variance(&self, krate: CrateId, adt_id: chalk::AdtId) -> chalk::Variances; 122 fn adt_variance(&self, krate: CrateId, adt_id: chalk_db::AdtId) -> chalk_db::Variances;
113 123
114 #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] 124 #[salsa::invoke(chalk_db::associated_ty_value_query)]
115 fn associated_ty_value( 125 fn associated_ty_value(
116 &self, 126 &self,
117 krate: CrateId, 127 krate: CrateId,
118 id: chalk::AssociatedTyValueId, 128 id: chalk_db::AssociatedTyValueId,
119 ) -> Arc<chalk::AssociatedTyValue>; 129 ) -> Arc<chalk_db::AssociatedTyValue>;
120 130
121 #[salsa::invoke(crate::traits::trait_solve_query)] 131 #[salsa::invoke(trait_solve_wait)]
132 #[salsa::transparent]
122 fn trait_solve( 133 fn trait_solve(
123 &self, 134 &self,
124 krate: CrateId, 135 krate: CrateId,
125 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>, 136 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
126 ) -> Option<crate::traits::Solution>; 137 ) -> Option<crate::Solution>;
127 138
128 #[salsa::invoke(crate::traits::chalk::program_clauses_for_chalk_env_query)] 139 #[salsa::invoke(crate::traits::trait_solve_query)]
140 fn trait_solve_query(
141 &self,
142 krate: CrateId,
143 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
144 ) -> Option<crate::Solution>;
145
146 #[salsa::invoke(chalk_db::program_clauses_for_chalk_env_query)]
129 fn program_clauses_for_chalk_env( 147 fn program_clauses_for_chalk_env(
130 &self, 148 &self,
131 krate: CrateId, 149 krate: CrateId,
132 env: chalk_ir::Environment<chalk::Interner>, 150 env: chalk_ir::Environment<Interner>,
133 ) -> chalk_ir::ProgramClauses<chalk::Interner>; 151 ) -> chalk_ir::ProgramClauses<Interner>;
134} 152}
135 153
136fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> { 154fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult> {
@@ -146,6 +164,15 @@ fn infer_wait(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<InferenceResult>
146 db.infer_query(def) 164 db.infer_query(def)
147} 165}
148 166
167fn trait_solve_wait(
168 db: &dyn HirDatabase,
169 krate: CrateId,
170 goal: crate::Canonical<crate::InEnvironment<crate::DomainGoal>>,
171) -> Option<crate::Solution> {
172 let _p = profile::span("trait_solve::wait");
173 db.trait_solve_query(krate, goal)
174}
175
149#[test] 176#[test]
150fn hir_database_is_object_safe() { 177fn hir_database_is_object_safe() {
151 fn _assert_object_safe(_: &dyn HirDatabase) {} 178 fn _assert_object_safe(_: &dyn HirDatabase) {}
@@ -156,6 +183,14 @@ pub struct InternedTypeParamId(salsa::InternId);
156impl_intern_key!(InternedTypeParamId); 183impl_intern_key!(InternedTypeParamId);
157 184
158#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 185#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
186pub struct InternedLifetimeParamId(salsa::InternId);
187impl_intern_key!(InternedLifetimeParamId);
188
189#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
190pub struct InternedConstParamId(salsa::InternId);
191impl_intern_key!(InternedConstParamId);
192
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
159pub struct InternedOpaqueTyId(salsa::InternId); 194pub struct InternedOpaqueTyId(salsa::InternId);
160impl_intern_key!(InternedOpaqueTyId); 195impl_intern_key!(InternedOpaqueTyId);
161 196
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index 86f937e1d..84fc8ce14 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -1,4 +1,4 @@
1//! FIXME: write short doc here 1//! Type inference-based diagnostics.
2mod expr; 2mod expr;
3mod match_check; 3mod match_check;
4mod unsafe_check; 4mod unsafe_check;
diff --git a/crates/hir_ty/src/diagnostics/decl_check.rs b/crates/hir_ty/src/diagnostics/decl_check.rs
index 1c9f9ede7..075dc4131 100644
--- a/crates/hir_ty/src/diagnostics/decl_check.rs
+++ b/crates/hir_ty/src/diagnostics/decl_check.rs
@@ -35,6 +35,8 @@ use crate::{
35}; 35};
36 36
37mod allow { 37mod allow {
38 pub(super) const BAD_STYLE: &str = "bad_style";
39 pub(super) const NONSTANDARD_STYLE: &str = "nonstandard_style";
38 pub(super) const NON_SNAKE_CASE: &str = "non_snake_case"; 40 pub(super) const NON_SNAKE_CASE: &str = "non_snake_case";
39 pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals"; 41 pub(super) const NON_UPPER_CASE_GLOBAL: &str = "non_upper_case_globals";
40 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types"; 42 pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
@@ -83,10 +85,39 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
83 } 85 }
84 86
85 /// Checks whether not following the convention is allowed for this item. 87 /// Checks whether not following the convention is allowed for this item.
86 /// 88 fn allowed(&self, id: AttrDefId, allow_name: &str, recursing: bool) -> bool {
87 /// Currently this method doesn't check parent attributes. 89 let is_allowed = |def_id| {
88 fn allowed(&self, id: AttrDefId, allow_name: &str) -> bool { 90 let attrs = self.db.attrs(def_id);
89 self.db.attrs(id).by_key("allow").tt_values().any(|tt| tt.to_string().contains(allow_name)) 91 // don't bug the user about directly no_mangle annotated stuff, they can't do anything about it
92 (!recursing && attrs.by_key("no_mangle").exists())
93 || attrs.by_key("allow").tt_values().any(|tt| {
94 let allows = tt.to_string();
95 allows.contains(allow_name)
96 || allows.contains(allow::BAD_STYLE)
97 || allows.contains(allow::NONSTANDARD_STYLE)
98 })
99 };
100
101 is_allowed(id)
102 // go upwards one step or give up
103 || match id {
104 AttrDefId::ModuleId(m) => m.containing_module(self.db.upcast()).map(|v| v.into()),
105 AttrDefId::FunctionId(f) => Some(f.lookup(self.db.upcast()).container.into()),
106 AttrDefId::StaticId(sid) => Some(sid.lookup(self.db.upcast()).container.into()),
107 AttrDefId::ConstId(cid) => Some(cid.lookup(self.db.upcast()).container.into()),
108 AttrDefId::TraitId(tid) => Some(tid.lookup(self.db.upcast()).container.into()),
109 AttrDefId::ImplId(iid) => Some(iid.lookup(self.db.upcast()).container.into()),
110 // These warnings should not explore macro definitions at all
111 AttrDefId::MacroDefId(_) => None,
112 // Will never occur under an enum/struct/union/type alias
113 AttrDefId::AdtId(_) => None,
114 AttrDefId::FieldId(_) => None,
115 AttrDefId::EnumVariantId(_) => None,
116 AttrDefId::TypeAliasId(_) => None,
117 AttrDefId::GenericParamId(_) => None,
118 }
119 .map(|mid| self.allowed(mid, allow_name, true))
120 .unwrap_or(false)
90 } 121 }
91 122
92 fn validate_func(&mut self, func: FunctionId) { 123 fn validate_func(&mut self, func: FunctionId) {
@@ -109,7 +140,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
109 } 140 }
110 141
111 // Check whether non-snake case identifiers are allowed for this function. 142 // Check whether non-snake case identifiers are allowed for this function.
112 if self.allowed(func.into(), allow::NON_SNAKE_CASE) { 143 if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
113 return; 144 return;
114 } 145 }
115 146
@@ -328,8 +359,9 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
328 fn validate_struct(&mut self, struct_id: StructId) { 359 fn validate_struct(&mut self, struct_id: StructId) {
329 let data = self.db.struct_data(struct_id); 360 let data = self.db.struct_data(struct_id);
330 361
331 let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES); 362 let non_camel_case_allowed =
332 let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE); 363 self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES, false);
364 let non_snake_case_allowed = self.allowed(struct_id.into(), allow::NON_SNAKE_CASE, false);
333 365
334 // Check the structure name. 366 // Check the structure name.
335 let struct_name = data.name.to_string(); 367 let struct_name = data.name.to_string();
@@ -461,7 +493,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
461 let data = self.db.enum_data(enum_id); 493 let data = self.db.enum_data(enum_id);
462 494
463 // Check whether non-camel case names are allowed for this enum. 495 // Check whether non-camel case names are allowed for this enum.
464 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { 496 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
465 return; 497 return;
466 } 498 }
467 499
@@ -584,7 +616,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
584 fn validate_const(&mut self, const_id: ConstId) { 616 fn validate_const(&mut self, const_id: ConstId) {
585 let data = self.db.const_data(const_id); 617 let data = self.db.const_data(const_id);
586 618
587 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 619 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
588 return; 620 return;
589 } 621 }
590 622
@@ -632,7 +664,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
632 return; 664 return;
633 } 665 }
634 666
635 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 667 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
636 return; 668 return;
637 } 669 }
638 670
@@ -867,23 +899,116 @@ fn main() {
867 fn allow_attributes() { 899 fn allow_attributes() {
868 check_diagnostics( 900 check_diagnostics(
869 r#" 901 r#"
870 #[allow(non_snake_case)] 902#[allow(non_snake_case)]
871 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ 903fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
872 let OtherVar = SOME_VAR + 1; 904 // cov_flags generated output from elsewhere in this file
873 OtherVar 905 extern "C" {
906 #[no_mangle]
907 static lower_case: u8;
874 } 908 }
875 909
876 #[allow(non_snake_case, non_camel_case_types)] 910 let OtherVar = SOME_VAR + 1;
877 pub struct some_type { 911 OtherVar
878 SOME_FIELD: u8, 912}
879 SomeField: u16, 913
914#[allow(nonstandard_style)]
915mod CheckNonstandardStyle {
916 fn HiImABadFnName() {}
917}
918
919#[allow(bad_style)]
920mod CheckBadStyle {
921 fn HiImABadFnName() {}
922}
923
924mod F {
925 #![allow(non_snake_case)]
926 fn CheckItWorksWithModAttr(BAD_NAME_HI: u8) {}
927}
928
929#[allow(non_snake_case, non_camel_case_types)]
930pub struct some_type {
931 SOME_FIELD: u8,
932 SomeField: u16,
933}
934
935#[allow(non_upper_case_globals)]
936pub const some_const: u8 = 10;
937
938#[allow(non_upper_case_globals)]
939pub static SomeStatic: u8 = 10;
940 "#,
941 );
880 } 942 }
881 943
882 #[allow(non_upper_case_globals)] 944 #[test]
883 pub const some_const: u8 = 10; 945 fn allow_attributes_crate_attr() {
946 check_diagnostics(
947 r#"
948#![allow(non_snake_case)]
884 949
885 #[allow(non_upper_case_globals)] 950mod F {
886 pub static SomeStatic: u8 = 10; 951 fn CheckItWorksWithCrateAttr(BAD_NAME_HI: u8) {}
952}
953 "#,
954 );
955 }
956
957 #[test]
958 #[ignore]
959 fn bug_trait_inside_fn() {
960 // FIXME:
961 // This is broken, and in fact, should not even be looked at by this
962 // lint in the first place. There's weird stuff going on in the
963 // collection phase.
964 // It's currently being brought in by:
965 // * validate_func on `a` recursing into modules
966 // * then it finds the trait and then the function while iterating
967 // through modules
968 // * then validate_func is called on Dirty
969 // * ... which then proceeds to look at some unknown module taking no
970 // attrs from either the impl or the fn a, and then finally to the root
971 // module
972 //
973 // It should find the attribute on the trait, but it *doesn't even see
974 // the trait* as far as I can tell.
975
976 check_diagnostics(
977 r#"
978trait T { fn a(); }
979struct U {}
980impl T for U {
981 fn a() {
982 // this comes out of bitflags, mostly
983 #[allow(non_snake_case)]
984 trait __BitFlags {
985 const HiImAlsoBad: u8 = 2;
986 #[inline]
987 fn Dirty(&self) -> bool {
988 false
989 }
990 }
991
992 }
993}
994 "#,
995 );
996 }
997
998 #[test]
999 #[ignore]
1000 fn bug_traits_arent_checked() {
1001 // FIXME: Traits and functions in traits aren't currently checked by
1002 // r-a, even though rustc will complain about them.
1003 check_diagnostics(
1004 r#"
1005trait BAD_TRAIT {
1006 // ^^^^^^^^^ Trait `BAD_TRAIT` should have CamelCase name, e.g. `BadTrait`
1007 fn BAD_FUNCTION();
1008 // ^^^^^^^^^^^^ Function `BAD_FUNCTION` should have snake_case name, e.g. `bad_function`
1009 fn BadFunction();
1010 // ^^^^^^^^^^^^ Function `BadFunction` should have snake_case name, e.g. `bad_function`
1011}
887 "#, 1012 "#,
888 ); 1013 );
889 } 1014 }
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 8169b759f..79602c3dd 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -14,7 +14,6 @@ use crate::{
14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
15 MissingPatFields, RemoveThisSemicolon, 15 MissingPatFields, RemoveThisSemicolon,
16 }, 16 },
17 utils::variant_data,
18 AdtId, InferenceResult, Interner, TyExt, TyKind, 17 AdtId, InferenceResult, Interner, TyExt, TyKind,
19}; 18};
20 19
@@ -104,7 +103,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
104 let root = source_ptr.file_syntax(db.upcast()); 103 let root = source_ptr.file_syntax(db.upcast());
105 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) { 104 if let ast::Expr::RecordExpr(record_expr) = &source_ptr.value.to_node(&root) {
106 if let Some(_) = record_expr.record_expr_field_list() { 105 if let Some(_) = record_expr.record_expr_field_list() {
107 let variant_data = variant_data(db.upcast(), variant_def); 106 let variant_data = variant_def.variant_data(db.upcast());
108 let missed_fields = missed_fields 107 let missed_fields = missed_fields
109 .into_iter() 108 .into_iter()
110 .map(|idx| variant_data.fields()[idx].name.clone()) 109 .map(|idx| variant_data.fields()[idx].name.clone())
@@ -135,7 +134,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
135 let root = source_ptr.file_syntax(db.upcast()); 134 let root = source_ptr.file_syntax(db.upcast());
136 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) { 135 if let ast::Pat::RecordPat(record_pat) = expr.to_node(&root) {
137 if let Some(_) = record_pat.record_pat_field_list() { 136 if let Some(_) = record_pat.record_pat_field_list() {
138 let variant_data = variant_data(db.upcast(), variant_def); 137 let variant_data = variant_def.variant_data(db.upcast());
139 let missed_fields = missed_fields 138 let missed_fields = missed_fields
140 .into_iter() 139 .into_iter()
141 .map(|idx| variant_data.fields()[idx].name.clone()) 140 .map(|idx| variant_data.fields()[idx].name.clone())
@@ -245,7 +244,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
245 Some(callee) => callee, 244 Some(callee) => callee,
246 None => return, 245 None => return,
247 }; 246 };
248 let sig = db.callable_item_signature(callee.into()).value; 247 let sig =
248 db.callable_item_signature(callee.into()).into_value_and_skipped_binders().0;
249 249
250 (sig, args) 250 (sig, args)
251 } 251 }
@@ -314,7 +314,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
314 if pat_ty == match_expr_ty 314 if pat_ty == match_expr_ty
315 || match_expr_ty 315 || match_expr_ty
316 .as_reference() 316 .as_reference()
317 .map(|(match_expr_ty, _)| match_expr_ty == pat_ty) 317 .map(|(match_expr_ty, ..)| match_expr_ty == pat_ty)
318 .unwrap_or(false) 318 .unwrap_or(false)
319 { 319 {
320 // If we had a NotUsefulMatchArm diagnostic, we could 320 // If we had a NotUsefulMatchArm diagnostic, we could
@@ -452,7 +452,7 @@ pub fn record_literal_missing_fields(
452 return None; 452 return None;
453 } 453 }
454 454
455 let variant_data = variant_data(db.upcast(), variant_def); 455 let variant_data = variant_def.variant_data(db.upcast());
456 456
457 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 457 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
458 let missed_fields: Vec<LocalFieldId> = variant_data 458 let missed_fields: Vec<LocalFieldId> = variant_data
@@ -482,7 +482,7 @@ pub fn record_pattern_missing_fields(
482 return None; 482 return None;
483 } 483 }
484 484
485 let variant_data = variant_data(db.upcast(), variant_def); 485 let variant_data = variant_def.variant_data(db.upcast());
486 486
487 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 487 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
488 let missed_fields: Vec<LocalFieldId> = variant_data 488 let missed_fields: Vec<LocalFieldId> = variant_data
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 34291578a..e9762622f 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -227,7 +227,7 @@ use hir_def::{
227use la_arena::Idx; 227use la_arena::Idx;
228use smallvec::{smallvec, SmallVec}; 228use smallvec::{smallvec, SmallVec};
229 229
230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyKind}; 230use crate::{db::HirDatabase, AdtId, InferenceResult, Interner, TyExt, TyKind};
231 231
232#[derive(Debug, Clone, Copy)] 232#[derive(Debug, Clone, Copy)]
233/// Either a pattern from the source code being analyzed, represented as 233/// Either a pattern from the source code being analyzed, represented as
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index b5efe9df5..ed97dc0e3 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -11,7 +11,9 @@ use hir_def::{
11}; 11};
12use hir_expand::diagnostics::DiagnosticSink; 12use hir_expand::diagnostics::DiagnosticSink;
13 13
14use crate::{db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyKind}; 14use crate::{
15 db::HirDatabase, diagnostics::MissingUnsafe, InferenceResult, Interner, TyExt, TyKind,
16};
15 17
16pub(super) struct UnsafeValidator<'a, 'b: 'a> { 18pub(super) struct UnsafeValidator<'a, 'b: 'a> {
17 owner: DefWithBodyId, 19 owner: DefWithBodyId,
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 385bd9405..4fb7d9cf2 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1,9 +1,15 @@
1//! FIXME: write short doc here 1//! The `HirDisplay` trait, which serves two purposes: Turning various bits from
2//! HIR back into source code, and just displaying them for debugging/testing
3//! purposes.
2 4
3use std::{array, fmt}; 5use std::{
6 array,
7 fmt::{self, Debug},
8};
4 9
5use chalk_ir::Mutability; 10use chalk_ir::BoundVar;
6use hir_def::{ 11use hir_def::{
12 body,
7 db::DefDatabase, 13 db::DefDatabase,
8 find_path, 14 find_path,
9 generics::TypeParamProvenance, 15 generics::TypeParamProvenance,
@@ -13,13 +19,15 @@ use hir_def::{
13 visibility::Visibility, 19 visibility::Visibility,
14 AssocContainerId, Lookup, ModuleId, TraitId, 20 AssocContainerId, Lookup, ModuleId, TraitId,
15}; 21};
16use hir_expand::name::Name; 22use hir_expand::{hygiene::Hygiene, name::Name};
17 23
18use crate::{ 24use crate::{
19 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, 25 const_from_placeholder_idx, db::HirDatabase, from_assoc_type_id, from_foreign_def_id,
20 to_assoc_type_id, traits::chalk::from_chalk, utils::generics, AdtId, AliasEq, AliasTy, 26 from_placeholder_idx, lt_from_placeholder_idx, mapping::from_chalk, primitive, subst_prefix,
21 CallableDefId, CallableSig, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, OpaqueTy, 27 to_assoc_type_id, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const,
22 ProjectionTy, QuantifiedWhereClause, Scalar, TraitRef, Ty, TyExt, TyKind, WhereClause, 28 ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
29 LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
30 Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
23}; 31};
24 32
25pub struct HirFormatter<'a> { 33pub struct HirFormatter<'a> {
@@ -46,6 +54,10 @@ pub trait HirDisplay {
46 where 54 where
47 Self: Sized, 55 Self: Sized,
48 { 56 {
57 assert!(
58 !matches!(display_target, DisplayTarget::SourceCode { .. }),
59 "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
60 );
49 HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target } 61 HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
50 } 62 }
51 63
@@ -230,7 +242,7 @@ where
230 Err(HirDisplayError::FmtError) => Err(fmt::Error), 242 Err(HirDisplayError::FmtError) => Err(fmt::Error),
231 Err(HirDisplayError::DisplaySourceCodeError(_)) => { 243 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
232 // This should never happen 244 // This should never happen
233 panic!("HirDisplay failed when calling Display::fmt!") 245 panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
234 } 246 }
235 } 247 }
236 } 248 }
@@ -251,16 +263,12 @@ impl HirDisplay for ProjectionTy {
251 } 263 }
252 264
253 let trait_ = f.db.trait_data(self.trait_(f.db)); 265 let trait_ = f.db.trait_data(self.trait_(f.db));
254 let first_parameter = self.self_type_parameter().into_displayable( 266 write!(f, "<")?;
255 f.db, 267 self.self_type_parameter(&Interner).hir_fmt(f)?;
256 f.max_size, 268 write!(f, " as {}", trait_.name)?;
257 f.omit_verbose_types,
258 f.display_target,
259 );
260 write!(f, "<{} as {}", first_parameter, trait_.name)?;
261 if self.substitution.len(&Interner) > 1 { 269 if self.substitution.len(&Interner) > 1 {
262 write!(f, "<")?; 270 write!(f, "<")?;
263 f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?; 271 f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
264 write!(f, ">")?; 272 write!(f, ">")?;
265 } 273 }
266 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; 274 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@@ -282,10 +290,35 @@ impl HirDisplay for GenericArg {
282 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 290 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
283 match self.interned() { 291 match self.interned() {
284 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f), 292 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
293 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
294 crate::GenericArgData::Const(c) => c.hir_fmt(f),
295 }
296 }
297}
298
299impl HirDisplay for Const {
300 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
301 let data = self.interned();
302 match data.value {
303 ConstValue::BoundVar(idx) => idx.hir_fmt(f),
304 ConstValue::InferenceVar(..) => write!(f, "_"),
305 ConstValue::Placeholder(idx) => {
306 let id = const_from_placeholder_idx(f.db, idx);
307 let generics = generics(f.db.upcast(), id.parent);
308 let param_data = &generics.params.consts[id.local_id];
309 write!(f, "{}", param_data.name)
310 }
311 ConstValue::Concrete(_) => write!(f, "_"),
285 } 312 }
286 } 313 }
287} 314}
288 315
316impl HirDisplay for BoundVar {
317 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
318 write!(f, "?{}.{}", self.debruijn.depth(), self.index)
319 }
320}
321
289impl HirDisplay for Ty { 322impl HirDisplay for Ty {
290 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 323 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
291 if f.should_truncate() { 324 if f.should_truncate() {
@@ -305,15 +338,14 @@ impl HirDisplay for Ty {
305 t.hir_fmt(f)?; 338 t.hir_fmt(f)?;
306 write!(f, "]")?; 339 write!(f, "]")?;
307 } 340 }
308 TyKind::Array(t) => { 341 TyKind::Array(t, c) => {
309 write!(f, "[")?; 342 write!(f, "[")?;
310 t.hir_fmt(f)?; 343 t.hir_fmt(f)?;
311 write!(f, "; _]")?; 344 write!(f, "; ")?;
345 c.hir_fmt(f)?;
346 write!(f, "]")?;
312 } 347 }
313 TyKind::Raw(m, t) | TyKind::Ref(m, t) => { 348 TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
314 let ty_display =
315 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
316
317 if matches!(self.kind(&Interner), TyKind::Raw(..)) { 349 if matches!(self.kind(&Interner), TyKind::Raw(..)) {
318 write!( 350 write!(
319 f, 351 f,
@@ -352,8 +384,8 @@ impl HirDisplay for Ty {
352 let data = (*datas) 384 let data = (*datas)
353 .as_ref() 385 .as_ref()
354 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 386 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
355 let bounds = data.subst(parameters); 387 let bounds = data.substitute(&Interner, parameters);
356 bounds.value 388 bounds.into_value_and_skipped_binders().0
357 } else { 389 } else {
358 Vec::new() 390 Vec::new()
359 } 391 }
@@ -368,16 +400,16 @@ impl HirDisplay for Ty {
368 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) 400 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
369 && predicates.len() <= 2 401 && predicates.len() <= 2
370 { 402 {
371 return write!(f, "{}", ty_display); 403 return t.hir_fmt(f);
372 } 404 }
373 } 405 }
374 406
375 if predicates.len() > 1 { 407 if predicates.len() > 1 {
376 write!(f, "(")?; 408 write!(f, "(")?;
377 write!(f, "{}", ty_display)?; 409 t.hir_fmt(f)?;
378 write!(f, ")")?; 410 write!(f, ")")?;
379 } else { 411 } else {
380 write!(f, "{}", ty_display)?; 412 t.hir_fmt(f)?;
381 } 413 }
382 } 414 }
383 TyKind::Tuple(_, substs) => { 415 TyKind::Tuple(_, substs) => {
@@ -387,7 +419,7 @@ impl HirDisplay for Ty {
387 write!(f, ",)")?; 419 write!(f, ",)")?;
388 } else { 420 } else {
389 write!(f, "(")?; 421 write!(f, "(")?;
390 f.write_joined(&*substs.0, ", ")?; 422 f.write_joined(&*substs.as_slice(&Interner), ", ")?;
391 write!(f, ")")?; 423 write!(f, ")")?;
392 } 424 }
393 } 425 }
@@ -397,7 +429,7 @@ impl HirDisplay for Ty {
397 } 429 }
398 TyKind::FnDef(def, parameters) => { 430 TyKind::FnDef(def, parameters) => {
399 let def = from_chalk(f.db, *def); 431 let def = from_chalk(f.db, *def);
400 let sig = f.db.callable_item_signature(def).subst(parameters); 432 let sig = f.db.callable_item_signature(def).substitute(&Interner, parameters);
401 match def { 433 match def {
402 CallableDefId::FunctionId(ff) => { 434 CallableDefId::FunctionId(ff) => {
403 write!(f, "fn {}", f.db.function_data(ff).name)? 435 write!(f, "fn {}", f.db.function_data(ff).name)?
@@ -415,7 +447,7 @@ impl HirDisplay for Ty {
415 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? 447 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
416 if total_len > 0 { 448 if total_len > 0 {
417 write!(f, "<")?; 449 write!(f, "<")?;
418 f.write_joined(&parameters.0[..total_len], ", ")?; 450 f.write_joined(&parameters.as_slice(&Interner)[..total_len], ", ")?;
419 write!(f, ">")?; 451 write!(f, ">")?;
420 } 452 }
421 } 453 }
@@ -424,14 +456,8 @@ impl HirDisplay for Ty {
424 write!(f, ")")?; 456 write!(f, ")")?;
425 let ret = sig.ret(); 457 let ret = sig.ret();
426 if !ret.is_unit() { 458 if !ret.is_unit() {
427 let ret_display = ret.into_displayable( 459 write!(f, " -> ")?;
428 f.db, 460 ret.hir_fmt(f)?;
429 f.max_size,
430 f.omit_verbose_types,
431 f.display_target,
432 );
433
434 write!(f, " -> {}", ret_display)?;
435 } 461 }
436 } 462 }
437 TyKind::Adt(AdtId(def_id), parameters) => { 463 TyKind::Adt(AdtId(def_id), parameters) => {
@@ -468,7 +494,7 @@ impl HirDisplay for Ty {
468 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 494 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
469 .filter(|defaults| !defaults.is_empty()) 495 .filter(|defaults| !defaults.is_empty())
470 { 496 {
471 None => parameters.0.as_ref(), 497 None => parameters.as_slice(&Interner),
472 Some(default_parameters) => { 498 Some(default_parameters) => {
473 let mut default_from = 0; 499 let mut default_from = 0;
474 for (i, parameter) in parameters.iter(&Interner).enumerate() { 500 for (i, parameter) in parameters.iter(&Interner).enumerate() {
@@ -476,13 +502,15 @@ impl HirDisplay for Ty {
476 parameter.assert_ty_ref(&Interner).kind(&Interner), 502 parameter.assert_ty_ref(&Interner).kind(&Interner),
477 default_parameters.get(i), 503 default_parameters.get(i),
478 ) { 504 ) {
479 (&TyKind::Unknown, _) | (_, None) => { 505 (&TyKind::Error, _) | (_, None) => {
480 default_from = i + 1; 506 default_from = i + 1;
481 } 507 }
482 (_, Some(default_parameter)) => { 508 (_, Some(default_parameter)) => {
483 let actual_default = default_parameter 509 let actual_default =
484 .clone() 510 default_parameter.clone().substitute(
485 .subst(&parameters.prefix(i)); 511 &Interner,
512 &subst_prefix(parameters, i),
513 );
486 if parameter.assert_ty_ref(&Interner) != &actual_default 514 if parameter.assert_ty_ref(&Interner) != &actual_default
487 { 515 {
488 default_from = i + 1; 516 default_from = i + 1;
@@ -490,11 +518,11 @@ impl HirDisplay for Ty {
490 } 518 }
491 } 519 }
492 } 520 }
493 &parameters.0[0..default_from] 521 &parameters.as_slice(&Interner)[0..default_from]
494 } 522 }
495 } 523 }
496 } else { 524 } else {
497 parameters.0.as_ref() 525 parameters.as_slice(&Interner)
498 }; 526 };
499 if !parameters_to_write.is_empty() { 527 if !parameters_to_write.is_empty() {
500 write!(f, "<")?; 528 write!(f, "<")?;
@@ -517,7 +545,7 @@ impl HirDisplay for Ty {
517 write!(f, "{}::{}", trait_.name, type_alias_data.name)?; 545 write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
518 if parameters.len(&Interner) > 0 { 546 if parameters.len(&Interner) > 0 {
519 write!(f, "<")?; 547 write!(f, "<")?;
520 f.write_joined(&*parameters.0, ", ")?; 548 f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
521 write!(f, ">")?; 549 write!(f, ">")?;
522 } 550 }
523 } else { 551 } else {
@@ -529,7 +557,7 @@ impl HirDisplay for Ty {
529 projection_ty.hir_fmt(f)?; 557 projection_ty.hir_fmt(f)?;
530 } 558 }
531 } 559 }
532 TyKind::ForeignType(type_alias) => { 560 TyKind::Foreign(type_alias) => {
533 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias)); 561 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
534 write!(f, "{}", type_alias.name)?; 562 write!(f, "{}", type_alias.name)?;
535 } 563 }
@@ -542,8 +570,8 @@ impl HirDisplay for Ty {
542 let data = (*datas) 570 let data = (*datas)
543 .as_ref() 571 .as_ref()
544 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 572 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
545 let bounds = data.subst(&parameters); 573 let bounds = data.substitute(&Interner, &parameters);
546 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?; 574 write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
547 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution 575 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
548 } 576 }
549 ImplTraitId::AsyncBlockTypeImplTrait(..) => { 577 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
@@ -571,13 +599,8 @@ impl HirDisplay for Ty {
571 write!(f, "|")?; 599 write!(f, "|")?;
572 }; 600 };
573 601
574 let ret_display = sig.ret().into_displayable( 602 write!(f, " -> ")?;
575 f.db, 603 sig.ret().hir_fmt(f)?;
576 f.max_size,
577 f.omit_verbose_types,
578 f.display_target,
579 );
580 write!(f, " -> {}", ret_display)?;
581 } else { 604 } else {
582 write!(f, "{{closure}}")?; 605 write!(f, "{{closure}}")?;
583 } 606 }
@@ -592,25 +615,26 @@ impl HirDisplay for Ty {
592 } 615 }
593 TypeParamProvenance::ArgumentImplTrait => { 616 TypeParamProvenance::ArgumentImplTrait => {
594 let substs = generics.type_params_subst(f.db); 617 let substs = generics.type_params_subst(f.db);
595 let bounds = f 618 let bounds =
596 .db 619 f.db.generic_predicates(id.parent)
597 .generic_predicates(id.parent) 620 .into_iter()
598 .into_iter() 621 .map(|pred| pred.clone().substitute(&Interner, &substs))
599 .map(|pred| pred.clone().subst(&substs)) 622 .filter(|wc| match &wc.skip_binders() {
600 .filter(|wc| match &wc.skip_binders() { 623 WhereClause::Implemented(tr) => {
601 WhereClause::Implemented(tr) => tr.self_type_parameter() == self, 624 &tr.self_type_parameter(&Interner) == self
602 WhereClause::AliasEq(AliasEq { 625 }
603 alias: AliasTy::Projection(proj), 626 WhereClause::AliasEq(AliasEq {
604 ty: _, 627 alias: AliasTy::Projection(proj),
605 }) => proj.self_type_parameter() == self, 628 ty: _,
606 _ => false, 629 }) => &proj.self_type_parameter(&Interner) == self,
607 }) 630 _ => false,
608 .collect::<Vec<_>>(); 631 })
632 .collect::<Vec<_>>();
609 write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?; 633 write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
610 } 634 }
611 } 635 }
612 } 636 }
613 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 637 TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
614 TyKind::Dyn(dyn_ty) => { 638 TyKind::Dyn(dyn_ty) => {
615 write_bounds_like_dyn_trait_with_prefix( 639 write_bounds_like_dyn_trait_with_prefix(
616 "dyn", 640 "dyn",
@@ -628,15 +652,15 @@ impl HirDisplay for Ty {
628 let data = (*datas) 652 let data = (*datas)
629 .as_ref() 653 .as_ref()
630 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 654 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
631 let bounds = data.subst(&opaque_ty.substitution); 655 let bounds = data.substitute(&Interner, &opaque_ty.substitution);
632 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?; 656 write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
633 } 657 }
634 ImplTraitId::AsyncBlockTypeImplTrait(..) => { 658 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
635 write!(f, "{{async block}}")?; 659 write!(f, "{{async block}}")?;
636 } 660 }
637 }; 661 };
638 } 662 }
639 TyKind::Unknown => { 663 TyKind::Error => {
640 if f.display_target.is_source_code() { 664 if f.display_target.is_source_code() {
641 return Err(HirDisplayError::DisplaySourceCodeError( 665 return Err(HirDisplayError::DisplaySourceCodeError(
642 DisplaySourceCodeError::UnknownType, 666 DisplaySourceCodeError::UnknownType,
@@ -645,6 +669,8 @@ impl HirDisplay for Ty {
645 write!(f, "{{unknown}}")?; 669 write!(f, "{{unknown}}")?;
646 } 670 }
647 TyKind::InferenceVar(..) => write!(f, "_")?, 671 TyKind::InferenceVar(..) => write!(f, "_")?,
672 TyKind::Generator(..) => write!(f, "{{generator}}")?,
673 TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
648 } 674 }
649 Ok(()) 675 Ok(())
650 } 676 }
@@ -664,9 +690,8 @@ impl HirDisplay for CallableSig {
664 write!(f, ")")?; 690 write!(f, ")")?;
665 let ret = self.ret(); 691 let ret = self.ret();
666 if !ret.is_unit() { 692 if !ret.is_unit() {
667 let ret_display = 693 write!(f, " -> ")?;
668 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); 694 ret.hir_fmt(f)?;
669 write!(f, " -> {}", ret_display)?;
670 } 695 }
671 Ok(()) 696 Ok(())
672 } 697 }
@@ -723,17 +748,17 @@ fn write_bounds_like_dyn_trait(
723 if !first { 748 if !first {
724 write!(f, " + ")?; 749 write!(f, " + ")?;
725 } 750 }
726 // We assume that the self type is $0 (i.e. the 751 // We assume that the self type is ^0.0 (i.e. the
727 // existential) here, which is the only thing that's 752 // existential) here, which is the only thing that's
728 // possible in actual Rust, and hence don't print it 753 // possible in actual Rust, and hence don't print it
729 write!(f, "{}", f.db.trait_data(trait_).name)?; 754 write!(f, "{}", f.db.trait_data(trait_).name)?;
730 if let [_, params @ ..] = &*trait_ref.substitution.0 { 755 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(&Interner) {
731 if is_fn_trait { 756 if is_fn_trait {
732 if let Some(args) = 757 if let Some(args) =
733 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple()) 758 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
734 { 759 {
735 write!(f, "(")?; 760 write!(f, "(")?;
736 f.write_joined(&*args.0, ", ")?; 761 f.write_joined(args.as_slice(&Interner), ", ")?;
737 write!(f, ")")?; 762 write!(f, ")")?;
738 } 763 }
739 } else if !params.is_empty() { 764 } else if !params.is_empty() {
@@ -765,6 +790,10 @@ fn write_bounds_like_dyn_trait(
765 } 790 }
766 ty.hir_fmt(f)?; 791 ty.hir_fmt(f)?;
767 } 792 }
793
794 // FIXME implement these
795 WhereClause::LifetimeOutlives(_) => {}
796 WhereClause::TypeOutlives(_) => {}
768 } 797 }
769 first = false; 798 first = false;
770 } 799 }
@@ -774,31 +803,29 @@ fn write_bounds_like_dyn_trait(
774 Ok(()) 803 Ok(())
775} 804}
776 805
777impl TraitRef { 806fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
778 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> { 807 if f.should_truncate() {
779 if f.should_truncate() { 808 return write!(f, "{}", TYPE_HINT_TRUNCATION);
780 return write!(f, "{}", TYPE_HINT_TRUNCATION); 809 }
781 }
782 810
783 self.self_type_parameter().hir_fmt(f)?; 811 tr.self_type_parameter(&Interner).hir_fmt(f)?;
784 if use_as { 812 if use_as {
785 write!(f, " as ")?; 813 write!(f, " as ")?;
786 } else { 814 } else {
787 write!(f, ": ")?; 815 write!(f, ": ")?;
788 } 816 }
789 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?; 817 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
790 if self.substitution.len(&Interner) > 1 { 818 if tr.substitution.len(&Interner) > 1 {
791 write!(f, "<")?; 819 write!(f, "<")?;
792 f.write_joined(&self.substitution.interned(&Interner)[1..], ", ")?; 820 f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
793 write!(f, ">")?; 821 write!(f, ">")?;
794 }
795 Ok(())
796 } 822 }
823 Ok(())
797} 824}
798 825
799impl HirDisplay for TraitRef { 826impl HirDisplay for TraitRef {
800 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 827 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
801 self.hir_fmt_ext(f, false) 828 fmt_trait_ref(self, f, false)
802 } 829 }
803} 830}
804 831
@@ -812,7 +839,7 @@ impl HirDisplay for WhereClause {
812 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 839 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
813 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 840 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
814 write!(f, "<")?; 841 write!(f, "<")?;
815 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; 842 fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
816 write!( 843 write!(
817 f, 844 f,
818 ">::{} = ", 845 ">::{} = ",
@@ -821,20 +848,44 @@ impl HirDisplay for WhereClause {
821 ty.hir_fmt(f)?; 848 ty.hir_fmt(f)?;
822 } 849 }
823 WhereClause::AliasEq(_) => write!(f, "{{error}}")?, 850 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
851
852 // FIXME implement these
853 WhereClause::TypeOutlives(..) => {}
854 WhereClause::LifetimeOutlives(..) => {}
824 } 855 }
825 Ok(()) 856 Ok(())
826 } 857 }
827} 858}
828 859
860impl HirDisplay for LifetimeOutlives {
861 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
862 self.a.hir_fmt(f)?;
863 write!(f, ": ")?;
864 self.b.hir_fmt(f)
865 }
866}
867
829impl HirDisplay for Lifetime { 868impl HirDisplay for Lifetime {
830 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 869 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
870 self.interned().hir_fmt(f)
871 }
872}
873
874impl HirDisplay for LifetimeData {
875 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
831 match self { 876 match self {
832 Lifetime::Parameter(id) => { 877 LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
878 LifetimeData::InferenceVar(_) => write!(f, "_"),
879 LifetimeData::Placeholder(idx) => {
880 let id = lt_from_placeholder_idx(f.db, *idx);
833 let generics = generics(f.db.upcast(), id.parent); 881 let generics = generics(f.db.upcast(), id.parent);
834 let param_data = &generics.params.lifetimes[id.local_id]; 882 let param_data = &generics.params.lifetimes[id.local_id];
835 write!(f, "{}", &param_data.name) 883 write!(f, "{}", param_data.name)
836 } 884 }
837 Lifetime::Static => write!(f, "'static"), 885 LifetimeData::Static => write!(f, "'static"),
886 LifetimeData::Empty(_) => Ok(()),
887 LifetimeData::Erased => Ok(()),
888 LifetimeData::Phantom(_, _) => Ok(()),
838 } 889 }
839 } 890 }
840} 891}
@@ -845,9 +896,11 @@ impl HirDisplay for DomainGoal {
845 DomainGoal::Holds(wc) => { 896 DomainGoal::Holds(wc) => {
846 write!(f, "Holds(")?; 897 write!(f, "Holds(")?;
847 wc.hir_fmt(f)?; 898 wc.hir_fmt(f)?;
848 write!(f, ")") 899 write!(f, ")")?;
849 } 900 }
901 _ => write!(f, "?")?,
850 } 902 }
903 Ok(())
851 } 904 }
852} 905}
853 906
@@ -945,6 +998,18 @@ impl HirDisplay for TypeRef {
945 write!(f, "dyn ")?; 998 write!(f, "dyn ")?;
946 f.write_joined(bounds, " + ")?; 999 f.write_joined(bounds, " + ")?;
947 } 1000 }
1001 TypeRef::Macro(macro_call) => {
1002 let macro_call = macro_call.to_node(f.db.upcast());
1003 let ctx = body::LowerCtx::with_hygiene(&Hygiene::new_unhygienic());
1004 match macro_call.path() {
1005 Some(path) => match Path::from_src(path, &ctx) {
1006 Some(path) => path.hir_fmt(f)?,
1007 None => write!(f, "{{macro}}")?,
1008 },
1009 None => write!(f, "{{macro}}")?,
1010 }
1011 write!(f, "!(..)")?;
1012 }
948 TypeRef::Error => write!(f, "{{error}}")?, 1013 TypeRef::Error => write!(f, "{{error}}")?,
949 } 1014 }
950 Ok(()) 1015 Ok(())
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 1b1d4458c..bf2da2d4a 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -18,7 +18,7 @@ use std::mem;
18use std::ops::Index; 18use std::ops::Index;
19use std::sync::Arc; 19use std::sync::Arc;
20 20
21use chalk_ir::{cast::Cast, Mutability}; 21use chalk_ir::{cast::Cast, DebruijnIndex, Mutability};
22use hir_def::{ 22use hir_def::{
23 body::Body, 23 body::Body,
24 data::{ConstData, FunctionData, StaticData}, 24 data::{ConstData, FunctionData, StaticData},
@@ -37,12 +37,12 @@ use stdx::impl_from;
37use syntax::SmolStr; 37use syntax::SmolStr;
38 38
39use super::{ 39use super::{
40 traits::{DomainGoal, Guidance, Solution}, 40 DomainGoal, Guidance, InEnvironment, ProjectionTy, Solution, TraitEnvironment, TraitRef, Ty,
41 InEnvironment, ProjectionTy, TraitEnvironment, TraitRef, Ty, TypeWalk,
42}; 41};
43use crate::{ 42use crate::{
44 db::HirDatabase, infer::diagnostics::InferenceDiagnostic, lower::ImplTraitLoweringMode, 43 db::HirDatabase, fold_tys, infer::diagnostics::InferenceDiagnostic,
45 to_assoc_type_id, AliasEq, AliasTy, Interner, TyBuilder, TyKind, 44 lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Canonical, Interner,
45 TyBuilder, TyExt, TyKind,
46}; 46};
47 47
48// This lint has a false positive here. See the link below for details. 48// This lint has a false positive here. See the link below for details.
@@ -120,7 +120,7 @@ struct InternedStandardTypes {
120 120
121impl Default for InternedStandardTypes { 121impl Default for InternedStandardTypes {
122 fn default() -> Self { 122 fn default() -> Self {
123 InternedStandardTypes { unknown: TyKind::Unknown.intern(&Interner) } 123 InternedStandardTypes { unknown: TyKind::Error.intern(&Interner) }
124 } 124 }
125} 125}
126 126
@@ -131,10 +131,7 @@ pub struct InferenceResult {
131 method_resolutions: FxHashMap<ExprId, FunctionId>, 131 method_resolutions: FxHashMap<ExprId, FunctionId>,
132 /// For each field access expr, records the field it resolves to. 132 /// For each field access expr, records the field it resolves to.
133 field_resolutions: FxHashMap<ExprId, FieldId>, 133 field_resolutions: FxHashMap<ExprId, FieldId>,
134 /// For each field in record literal, records the field it resolves to. 134 /// For each struct literal or pattern, records the variant it resolves to.
135 record_field_resolutions: FxHashMap<ExprId, FieldId>,
136 record_pat_field_resolutions: FxHashMap<PatId, FieldId>,
137 /// For each struct literal, records the variant it resolves to.
138 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>, 135 variant_resolutions: FxHashMap<ExprOrPatId, VariantId>,
139 /// For each associated item record what it resolves to 136 /// For each associated item record what it resolves to
140 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>, 137 assoc_resolutions: FxHashMap<ExprOrPatId, AssocItemId>,
@@ -153,12 +150,6 @@ impl InferenceResult {
153 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> { 150 pub fn field_resolution(&self, expr: ExprId) -> Option<FieldId> {
154 self.field_resolutions.get(&expr).copied() 151 self.field_resolutions.get(&expr).copied()
155 } 152 }
156 pub fn record_field_resolution(&self, expr: ExprId) -> Option<FieldId> {
157 self.record_field_resolutions.get(&expr).copied()
158 }
159 pub fn record_pat_field_resolution(&self, pat: PatId) -> Option<FieldId> {
160 self.record_pat_field_resolutions.get(&pat).copied()
161 }
162 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> { 153 pub fn variant_resolution_for_expr(&self, id: ExprId) -> Option<VariantId> {
163 self.variant_resolutions.get(&id.into()).copied() 154 self.variant_resolutions.get(&id.into()).copied()
164 } 155 }
@@ -247,7 +238,7 @@ impl<'a> InferenceContext<'a> {
247 table: unify::InferenceTable::new(), 238 table: unify::InferenceTable::new(),
248 obligations: Vec::default(), 239 obligations: Vec::default(),
249 last_obligations_check: None, 240 last_obligations_check: None,
250 return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature 241 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature
251 trait_env: owner 242 trait_env: owner
252 .as_generic_def_id() 243 .as_generic_def_id()
253 .map_or_else(Default::default, |d| db.trait_environment(d)), 244 .map_or_else(Default::default, |d| db.trait_environment(d)),
@@ -261,7 +252,7 @@ impl<'a> InferenceContext<'a> {
261 } 252 }
262 253
263 fn err_ty(&self) -> Ty { 254 fn err_ty(&self) -> Ty {
264 TyKind::Unknown.intern(&Interner) 255 TyKind::Error.intern(&Interner)
265 } 256 }
266 257
267 fn resolve_all(mut self) -> InferenceResult { 258 fn resolve_all(mut self) -> InferenceResult {
@@ -326,13 +317,13 @@ impl<'a> InferenceContext<'a> {
326 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it. 317 /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
327 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 318 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
328 match ty.kind(&Interner) { 319 match ty.kind(&Interner) {
329 TyKind::Unknown => self.table.new_type_var(), 320 TyKind::Error => self.table.new_type_var(),
330 _ => ty, 321 _ => ty,
331 } 322 }
332 } 323 }
333 324
334 fn insert_type_vars(&mut self, ty: Ty) -> Ty { 325 fn insert_type_vars(&mut self, ty: Ty) -> Ty {
335 ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) 326 fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
336 } 327 }
337 328
338 fn resolve_obligations_as_possible(&mut self) { 329 fn resolve_obligations_as_possible(&mut self) {
@@ -345,17 +336,24 @@ impl<'a> InferenceContext<'a> {
345 self.last_obligations_check = Some(self.table.revision); 336 self.last_obligations_check = Some(self.table.revision);
346 let obligations = mem::replace(&mut self.obligations, Vec::new()); 337 let obligations = mem::replace(&mut self.obligations, Vec::new());
347 for obligation in obligations { 338 for obligation in obligations {
348 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); 339 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
349 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); 340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
350 let solution = 341 let solution =
351 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); 342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
352 343
353 match solution { 344 match solution {
354 Some(Solution::Unique(substs)) => { 345 Some(Solution::Unique(canonical_subst)) => {
355 canonicalized.apply_solution(self, substs.0); 346 canonicalized.apply_solution(
347 self,
348 Canonical {
349 binders: canonical_subst.binders,
350 // FIXME: handle constraints
351 value: canonical_subst.value.subst,
352 },
353 );
356 } 354 }
357 Some(Solution::Ambig(Guidance::Definite(substs))) => { 355 Some(Solution::Ambig(Guidance::Definite(substs))) => {
358 canonicalized.apply_solution(self, substs.0); 356 canonicalized.apply_solution(self, substs);
359 self.obligations.push(obligation); 357 self.obligations.push(obligation);
360 } 358 }
361 Some(_) => { 359 Some(_) => {
@@ -436,12 +434,16 @@ impl<'a> InferenceContext<'a> {
436 /// to do it as well. 434 /// to do it as well.
437 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
438 let ty = self.resolve_ty_as_possible(ty); 436 let ty = self.resolve_ty_as_possible(ty);
439 ty.fold(&mut |ty| match ty.kind(&Interner) { 437 fold_tys(
440 TyKind::Alias(AliasTy::Projection(proj_ty)) => { 438 ty,
441 self.normalize_projection_ty(proj_ty.clone()) 439 |ty, _| match ty.kind(&Interner) {
442 } 440 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
443 _ => ty, 441 self.normalize_projection_ty(proj_ty.clone())
444 }) 442 }
443 _ => ty,
444 },
445 DebruijnIndex::INNERMOST,
446 )
445 } 447 }
446 448
447 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 449 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
@@ -470,55 +472,32 @@ impl<'a> InferenceContext<'a> {
470 TypeNs::AdtId(AdtId::StructId(strukt)) => { 472 TypeNs::AdtId(AdtId::StructId(strukt)) => {
471 let substs = ctx.substs_from_path(path, strukt.into(), true); 473 let substs = ctx.substs_from_path(path, strukt.into(), true);
472 let ty = self.db.ty(strukt.into()); 474 let ty = self.db.ty(strukt.into());
473 let ty = self.insert_type_vars(ty.subst(&substs)); 475 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
474 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 476 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
475 } 477 }
476 TypeNs::AdtId(AdtId::UnionId(u)) => { 478 TypeNs::AdtId(AdtId::UnionId(u)) => {
477 let substs = ctx.substs_from_path(path, u.into(), true); 479 let substs = ctx.substs_from_path(path, u.into(), true);
478 let ty = self.db.ty(u.into()); 480 let ty = self.db.ty(u.into());
479 let ty = self.insert_type_vars(ty.subst(&substs)); 481 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
480 forbid_unresolved_segments((ty, Some(u.into())), unresolved) 482 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
481 } 483 }
482 TypeNs::EnumVariantId(var) => { 484 TypeNs::EnumVariantId(var) => {
483 let substs = ctx.substs_from_path(path, var.into(), true); 485 let substs = ctx.substs_from_path(path, var.into(), true);
484 let ty = self.db.ty(var.parent.into()); 486 let ty = self.db.ty(var.parent.into());
485 let ty = self.insert_type_vars(ty.subst(&substs)); 487 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
486 forbid_unresolved_segments((ty, Some(var.into())), unresolved) 488 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
487 } 489 }
488 TypeNs::SelfType(impl_id) => { 490 TypeNs::SelfType(impl_id) => {
489 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 491 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
490 let substs = generics.type_params_subst(self.db); 492 let substs = generics.type_params_subst(self.db);
491 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 493 let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs);
492 match unresolved { 494 self.resolve_variant_on_alias(ty, unresolved, path)
493 None => {
494 let variant = ty_variant(&ty);
495 (ty, variant)
496 }
497 Some(1) => {
498 let segment = path.mod_path().segments().last().unwrap();
499 // this could be an enum variant or associated type
500 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
501 let enum_data = self.db.enum_data(enum_id);
502 if let Some(local_id) = enum_data.variant(segment) {
503 let variant = EnumVariantId { parent: enum_id, local_id };
504 return (ty, Some(variant.into()));
505 }
506 }
507 // FIXME potentially resolve assoc type
508 (self.err_ty(), None)
509 }
510 Some(_) => {
511 // FIXME diagnostic
512 (self.err_ty(), None)
513 }
514 }
515 } 495 }
516 TypeNs::TypeAliasId(it) => { 496 TypeNs::TypeAliasId(it) => {
517 let ty = TyBuilder::def_ty(self.db, it.into()) 497 let ty = TyBuilder::def_ty(self.db, it.into())
518 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 498 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
519 .build(); 499 .build();
520 let variant = ty_variant(&ty); 500 self.resolve_variant_on_alias(ty, unresolved, path)
521 forbid_unresolved_segments((ty, variant), unresolved)
522 } 501 }
523 TypeNs::AdtSelfType(_) => { 502 TypeNs::AdtSelfType(_) => {
524 // FIXME this could happen in array size expressions, once we're checking them 503 // FIXME this could happen in array size expressions, once we're checking them
@@ -542,19 +521,46 @@ impl<'a> InferenceContext<'a> {
542 result 521 result
543 } else { 522 } else {
544 // FIXME diagnostic 523 // FIXME diagnostic
545 (TyKind::Unknown.intern(&Interner), None) 524 (TyKind::Error.intern(&Interner), None)
546 } 525 }
547 } 526 }
527 }
548 528
549 fn ty_variant(ty: &Ty) -> Option<VariantId> { 529 fn resolve_variant_on_alias(
550 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 530 &mut self,
551 AdtId::StructId(s) => Some(VariantId::StructId(s)), 531 ty: Ty,
552 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 532 unresolved: Option<usize>,
553 AdtId::EnumId(_) => { 533 path: &Path,
554 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` 534 ) -> (Ty, Option<VariantId>) {
555 None 535 match unresolved {
536 None => {
537 let variant = ty.as_adt().and_then(|(adt_id, _)| match adt_id {
538 AdtId::StructId(s) => Some(VariantId::StructId(s)),
539 AdtId::UnionId(u) => Some(VariantId::UnionId(u)),
540 AdtId::EnumId(_) => {
541 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo`
542 None
543 }
544 });
545 (ty, variant)
546 }
547 Some(1) => {
548 let segment = path.mod_path().segments().last().unwrap();
549 // this could be an enum variant or associated type
550 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
551 let enum_data = self.db.enum_data(enum_id);
552 if let Some(local_id) = enum_data.variant(segment) {
553 let variant = EnumVariantId { parent: enum_id, local_id };
554 return (ty, Some(variant.into()));
555 }
556 } 556 }
557 }) 557 // FIXME potentially resolve assoc type
558 (self.err_ty(), None)
559 }
560 Some(_) => {
561 // FIXME diagnostic
562 (self.err_ty(), None)
563 }
558 } 564 }
559 } 565 }
560 566
@@ -692,25 +698,6 @@ impl<'a> InferenceContext<'a> {
692 } 698 }
693} 699}
694 700
695/// The kinds of placeholders we need during type inference. There's separate
696/// values for general types, and for integer and float variables. The latter
697/// two are used for inference of literal values (e.g. `100` could be one of
698/// several integer types).
699#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
700pub struct InferenceVar {
701 index: u32,
702}
703
704impl InferenceVar {
705 fn to_inner(self) -> unify::TypeVarId {
706 unify::TypeVarId(self.index)
707 }
708
709 fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self {
710 InferenceVar { index }
711 }
712}
713
714/// When inferring an expression, we propagate downward whatever type hint we 701/// When inferring an expression, we propagate downward whatever type hint we
715/// are able in the form of an `Expectation`. 702/// are able in the form of an `Expectation`.
716#[derive(Clone, PartialEq, Eq, Debug)] 703#[derive(Clone, PartialEq, Eq, Debug)]
@@ -755,7 +742,7 @@ impl Expectation {
755 fn none() -> Self { 742 fn none() -> Self {
756 Expectation { 743 Expectation {
757 // FIXME 744 // FIXME
758 ty: TyKind::Unknown.intern(&Interner), 745 ty: TyKind::Error.intern(&Interner),
759 rvalue_hint: false, 746 rvalue_hint: false,
760 } 747 }
761 } 748 }
@@ -763,7 +750,7 @@ impl Expectation {
763 fn coercion_target(&self) -> Ty { 750 fn coercion_target(&self) -> Ty {
764 if self.rvalue_hint { 751 if self.rvalue_hint {
765 // FIXME 752 // FIXME
766 TyKind::Unknown.intern(&Interner) 753 TyKind::Error.intern(&Interner)
767 } else { 754 } else {
768 self.ty.clone() 755 self.ty.clone()
769 } 756 }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 028a4d568..1f463a425 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -7,7 +7,7 @@
7use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 7use chalk_ir::{cast::Cast, Mutability, TyVariableKind};
8use hir_def::lang_item::LangItemTarget; 8use hir_def::lang_item::LangItemTarget;
9 9
10use crate::{autoderef, traits::Solution, Interner, Ty, TyBuilder, TyKind}; 10use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
11 11
12use super::{InEnvironment, InferenceContext}; 12use super::{InEnvironment, InferenceContext};
13 13
@@ -71,17 +71,19 @@ impl<'a> InferenceContext<'a> {
71 } 71 }
72 72
73 // Pointer weakening and function to pointer 73 // Pointer weakening and function to pointer
74 match (from_ty.interned_mut(), to_ty.kind(&Interner)) { 74 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
75 // `*mut T` -> `*const T` 75 // `*mut T` -> `*const T`
76 (TyKind::Raw(_, inner), TyKind::Raw(m2 @ Mutability::Not, ..)) => {
77 from_ty = TyKind::Raw(*m2, inner.clone()).intern(&Interner);
78 }
76 // `&mut T` -> `&T` 79 // `&mut T` -> `&T`
77 (TyKind::Raw(m1, ..), TyKind::Raw(m2 @ Mutability::Not, ..)) 80 (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
78 | (TyKind::Ref(m1, ..), TyKind::Ref(m2 @ Mutability::Not, ..)) => { 81 from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner);
79 *m1 = *m2;
80 } 82 }
81 // `&T` -> `*const T` 83 // `&T` -> `*const T`
82 // `&mut T` -> `*mut T`/`*const T` 84 // `&mut T` -> `*mut T`/`*const T`
83 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..)) 85 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..))
84 | (TyKind::Ref(Mutability::Mut, substs), &TyKind::Raw(m2, ..)) => { 86 | (TyKind::Ref(Mutability::Mut, _, substs), &TyKind::Raw(m2, ..)) => {
85 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner); 87 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner);
86 } 88 }
87 89
@@ -111,7 +113,9 @@ impl<'a> InferenceContext<'a> {
111 // Auto Deref if cannot coerce 113 // Auto Deref if cannot coerce
112 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) { 114 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
113 // FIXME: DerefMut 115 // FIXME: DerefMut
114 (TyKind::Ref(_, st1), TyKind::Ref(_, st2)) => self.unify_autoderef_behind_ref(st1, st2), 116 (TyKind::Ref(.., st1), TyKind::Ref(.., st2)) => {
117 self.unify_autoderef_behind_ref(st1, st2)
118 }
115 119
116 // Otherwise, normal unify 120 // Otherwise, normal unify
117 _ => self.unify(&from_ty, to_ty), 121 _ => self.unify(&from_ty, to_ty),
@@ -137,7 +141,7 @@ impl<'a> InferenceContext<'a> {
137 b.push(from_ty.clone()).push(to_ty.clone()).build() 141 b.push(from_ty.clone()).push(to_ty.clone()).build()
138 }; 142 };
139 143
140 let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner)); 144 let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
141 145
142 let canonicalizer = self.canonicalizer(); 146 let canonicalizer = self.canonicalizer();
143 let canonicalized = canonicalizer.canonicalize_obligation(goal); 147 let canonicalized = canonicalizer.canonicalize_obligation(goal);
@@ -146,7 +150,14 @@ impl<'a> InferenceContext<'a> {
146 150
147 match solution { 151 match solution {
148 Solution::Unique(v) => { 152 Solution::Unique(v) => {
149 canonicalized.apply_solution(self, v.0); 153 canonicalized.apply_solution(
154 self,
155 Canonical {
156 binders: v.binders,
157 // FIXME handle constraints
158 value: v.value.subst,
159 },
160 );
150 } 161 }
151 _ => return None, 162 _ => return None,
152 }; 163 };
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index c584a2c08..50497eecb 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -3,7 +3,7 @@
3use std::iter::{repeat, repeat_with}; 3use std::iter::{repeat, repeat_with};
4use std::{mem, sync::Arc}; 4use std::{mem, sync::Arc};
5 5
6use chalk_ir::{cast::Cast, Mutability, TyVariableKind}; 6use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
7use hir_def::{ 7use hir_def::{
8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, 8 expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
9 path::{GenericArg, GenericArgs}, 9 path::{GenericArg, GenericArgs},
@@ -15,15 +15,16 @@ use stdx::always;
15use syntax::ast::RangeOp; 15use syntax::ast::RangeOp;
16 16
17use crate::{ 17use crate::{
18 autoderef, 18 autoderef, dummy_usize_const,
19 lower::lower_to_chalk_mutability, 19 lower::lower_to_chalk_mutability,
20 mapping::from_chalk,
20 method_resolution, op, 21 method_resolution, op,
21 primitive::{self, UintTy}, 22 primitive::{self, UintTy},
22 to_chalk_trait_id, 23 static_lifetime, to_chalk_trait_id,
23 traits::{chalk::from_chalk, FnTrait, InEnvironment}, 24 traits::FnTrait,
24 utils::{generics, variant_data, Generics}, 25 utils::{generics, Generics},
25 AdtId, Binders, CallableDefId, FnPointer, FnSig, Interner, Rawness, Scalar, Substitution, 26 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 TraitRef, Ty, TyBuilder, TyKind, 27 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27}; 28};
28 29
29use super::{ 30use super::{
@@ -180,7 +181,8 @@ impl<'a> InferenceContext<'a> {
180 let inner_ty = self.infer_expr(*body, &Expectation::none()); 181 let inner_ty = self.infer_expr(*body, &Expectation::none());
181 let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body); 182 let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
182 let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); 183 let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
183 TyKind::OpaqueType(opaque_ty_id, Substitution::single(inner_ty)).intern(&Interner) 184 TyKind::OpaqueType(opaque_ty_id, Substitution::from1(&Interner, inner_ty))
185 .intern(&Interner)
184 } 186 }
185 Expr::Loop { body, label } => { 187 Expr::Loop { body, label } => {
186 self.breakables.push(BreakableContext { 188 self.breakables.push(BreakableContext {
@@ -259,14 +261,17 @@ impl<'a> InferenceContext<'a> {
259 }; 261 };
260 sig_tys.push(ret_ty.clone()); 262 sig_tys.push(ret_ty.clone());
261 let sig_ty = TyKind::Function(FnPointer { 263 let sig_ty = TyKind::Function(FnPointer {
262 num_args: sig_tys.len() - 1, 264 num_binders: 0,
263 sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, 265 sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
264 substs: Substitution::from_iter(&Interner, sig_tys.clone()), 266 substitution: FnSubst(
267 Substitution::from_iter(&Interner, sig_tys.clone()).shifted_in(&Interner),
268 ),
265 }) 269 })
266 .intern(&Interner); 270 .intern(&Interner);
267 let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into(); 271 let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
268 let closure_ty = 272 let closure_ty =
269 TyKind::Closure(closure_id, Substitution::single(sig_ty)).intern(&Interner); 273 TyKind::Closure(closure_id, Substitution::from1(&Interner, sig_ty))
274 .intern(&Interner);
270 275
271 // Eagerly try to relate the closure type with the expected 276 // Eagerly try to relate the closure type with the expected
272 // type, otherwise we often won't have enough information to 277 // type, otherwise we often won't have enough information to
@@ -313,7 +318,13 @@ impl<'a> InferenceContext<'a> {
313 self.normalize_associated_types_in(ret_ty) 318 self.normalize_associated_types_in(ret_ty)
314 } 319 }
315 Expr::MethodCall { receiver, args, method_name, generic_args } => self 320 Expr::MethodCall { receiver, args, method_name, generic_args } => self
316 .infer_method_call(tgt_expr, *receiver, &args, &method_name, generic_args.as_ref()), 321 .infer_method_call(
322 tgt_expr,
323 *receiver,
324 &args,
325 &method_name,
326 generic_args.as_deref(),
327 ),
317 Expr::Match { expr, arms } => { 328 Expr::Match { expr, arms } => {
318 let input_ty = self.infer_expr(*expr, &Expectation::none()); 329 let input_ty = self.infer_expr(*expr, &Expectation::none());
319 330
@@ -394,16 +405,19 @@ impl<'a> InferenceContext<'a> {
394 TyKind::Never.intern(&Interner) 405 TyKind::Never.intern(&Interner)
395 } 406 }
396 Expr::RecordLit { path, fields, spread } => { 407 Expr::RecordLit { path, fields, spread } => {
397 let (ty, def_id) = self.resolve_variant(path.as_ref()); 408 let (ty, def_id) = self.resolve_variant(path.as_deref());
398 if let Some(variant) = def_id { 409 if let Some(variant) = def_id {
399 self.write_variant_resolution(tgt_expr.into(), variant); 410 self.write_variant_resolution(tgt_expr.into(), variant);
400 } 411 }
401 412
402 self.unify(&ty, &expected.ty); 413 self.unify(&ty, &expected.ty);
403 414
404 let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); 415 let substs = ty
416 .as_adt()
417 .map(|(_, s)| s.clone())
418 .unwrap_or_else(|| Substitution::empty(&Interner));
405 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default(); 419 let field_types = def_id.map(|it| self.db.field_types(it)).unwrap_or_default();
406 let variant_data = def_id.map(|it| variant_data(self.db.upcast(), it)); 420 let variant_data = def_id.map(|it| it.variant_data(self.db.upcast()));
407 for field in fields.iter() { 421 for field in fields.iter() {
408 let field_def = 422 let field_def =
409 variant_data.as_ref().and_then(|it| match it.field(&field.name) { 423 variant_data.as_ref().and_then(|it| match it.field(&field.name) {
@@ -415,11 +429,8 @@ impl<'a> InferenceContext<'a> {
415 None 429 None
416 } 430 }
417 }); 431 });
418 if let Some(field_def) = field_def {
419 self.result.record_field_resolutions.insert(field.expr, field_def);
420 }
421 let field_ty = field_def.map_or(self.err_ty(), |it| { 432 let field_ty = field_def.map_or(self.err_ty(), |it| {
422 field_types[it.local_id].clone().subst(&substs) 433 field_types[it.local_id].clone().substitute(&Interner, &substs)
423 }); 434 });
424 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 435 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
425 } 436 }
@@ -453,7 +464,7 @@ impl<'a> InferenceContext<'a> {
453 match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) { 464 match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
454 TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| { 465 TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
455 substs 466 substs
456 .interned(&Interner) 467 .as_slice(&Interner)
457 .get(idx) 468 .get(idx)
458 .map(|a| a.assert_ty_ref(&Interner)) 469 .map(|a| a.assert_ty_ref(&Interner))
459 .cloned() 470 .cloned()
@@ -466,7 +477,7 @@ impl<'a> InferenceContext<'a> {
466 Some( 477 Some(
467 self.db.field_types((*s).into())[field.local_id] 478 self.db.field_types((*s).into())[field.local_id]
468 .clone() 479 .clone()
469 .subst(&parameters), 480 .substitute(&Interner, &parameters),
470 ) 481 )
471 } else { 482 } else {
472 None 483 None
@@ -480,7 +491,7 @@ impl<'a> InferenceContext<'a> {
480 Some( 491 Some(
481 self.db.field_types((*u).into())[field.local_id] 492 self.db.field_types((*u).into())[field.local_id]
482 .clone() 493 .clone()
483 .subst(&parameters), 494 .substitute(&Interner, &parameters),
484 ) 495 )
485 } else { 496 } else {
486 None 497 None
@@ -527,7 +538,7 @@ impl<'a> InferenceContext<'a> {
527 let inner_ty = self.infer_expr_inner(*expr, &expectation); 538 let inner_ty = self.infer_expr_inner(*expr, &expectation);
528 match rawness { 539 match rawness {
529 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty), 540 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
530 Rawness::Ref => TyKind::Ref(mutability, inner_ty), 541 Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
531 } 542 }
532 .intern(&Interner) 543 .intern(&Interner)
533 } 544 }
@@ -702,7 +713,7 @@ impl<'a> InferenceContext<'a> {
702 } 713 }
703 Expr::Array(array) => { 714 Expr::Array(array) => {
704 let elem_ty = match expected.ty.kind(&Interner) { 715 let elem_ty = match expected.ty.kind(&Interner) {
705 TyKind::Array(st) | TyKind::Slice(st) => st.clone(), 716 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
706 _ => self.table.new_type_var(), 717 _ => self.table.new_type_var(),
707 }; 718 };
708 719
@@ -726,17 +737,19 @@ impl<'a> InferenceContext<'a> {
726 } 737 }
727 } 738 }
728 739
729 TyKind::Array(elem_ty).intern(&Interner) 740 TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner)
730 } 741 }
731 Expr::Literal(lit) => match lit { 742 Expr::Literal(lit) => match lit {
732 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 743 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
733 Literal::String(..) => { 744 Literal::String(..) => {
734 TyKind::Ref(Mutability::Not, TyKind::Str.intern(&Interner)).intern(&Interner) 745 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
746 .intern(&Interner)
735 } 747 }
736 Literal::ByteString(..) => { 748 Literal::ByteString(..) => {
737 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 749 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
738 let array_type = TyKind::Array(byte_type).intern(&Interner); 750 let array_type =
739 TyKind::Ref(Mutability::Not, array_type).intern(&Interner) 751 TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
752 TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
740 } 753 }
741 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner), 754 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
742 Literal::Int(_v, ty) => match ty { 755 Literal::Int(_v, ty) => match ty {
@@ -853,10 +866,10 @@ impl<'a> InferenceContext<'a> {
853 self.write_method_resolution(tgt_expr, func); 866 self.write_method_resolution(tgt_expr, func);
854 (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into()))) 867 (ty, self.db.value_ty(func.into()), Some(generics(self.db.upcast(), func.into())))
855 } 868 }
856 None => (receiver_ty, Binders::new(0, self.err_ty()), None), 869 None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None),
857 }; 870 };
858 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty); 871 let substs = self.substs_for_method_call(def_generics, generic_args, &derefed_receiver_ty);
859 let method_ty = method_ty.subst(&substs); 872 let method_ty = method_ty.substitute(&Interner, &substs);
860 let method_ty = self.insert_type_vars(method_ty); 873 let method_ty = self.insert_type_vars(method_ty);
861 self.register_obligations_for_call(&method_ty); 874 self.register_obligations_for_call(&method_ty);
862 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) { 875 let (expected_receiver_ty, param_tys, ret_ty) = match method_ty.callable_sig(self.db) {
@@ -872,7 +885,9 @@ impl<'a> InferenceContext<'a> {
872 // Apply autoref so the below unification works correctly 885 // Apply autoref so the below unification works correctly
873 // FIXME: return correct autorefs from lookup_method 886 // FIXME: return correct autorefs from lookup_method
874 let actual_receiver_ty = match expected_receiver_ty.as_reference() { 887 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
875 Some((_, mutability)) => TyKind::Ref(mutability, derefed_receiver_ty).intern(&Interner), 888 Some((_, lifetime, mutability)) => {
889 TyKind::Ref(mutability, lifetime, derefed_receiver_ty).intern(&Interner)
890 }
876 _ => derefed_receiver_ty, 891 _ => derefed_receiver_ty,
877 }; 892 };
878 self.unify(&expected_receiver_ty, &actual_receiver_ty); 893 self.unify(&expected_receiver_ty, &actual_receiver_ty);
@@ -953,9 +968,11 @@ impl<'a> InferenceContext<'a> {
953 let def: CallableDefId = from_chalk(self.db, *fn_def); 968 let def: CallableDefId = from_chalk(self.db, *fn_def);
954 let generic_predicates = self.db.generic_predicates(def.into()); 969 let generic_predicates = self.db.generic_predicates(def.into());
955 for predicate in generic_predicates.iter() { 970 for predicate in generic_predicates.iter() {
956 let (predicate, binders) = 971 let (predicate, binders) = predicate
957 predicate.clone().subst(parameters).into_value_and_skipped_binders(); 972 .clone()
958 always!(binders == 0); // quantified where clauses not yet handled 973 .substitute(&Interner, parameters)
974 .into_value_and_skipped_binders();
975 always!(binders.len(&Interner) == 0); // quantified where clauses not yet handled
959 self.push_obligation(predicate.cast(&Interner)); 976 self.push_obligation(predicate.cast(&Interner));
960 } 977 }
961 // add obligation for trait implementation, if this is a trait method 978 // add obligation for trait implementation, if this is a trait method
@@ -964,8 +981,10 @@ impl<'a> InferenceContext<'a> {
964 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container 981 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
965 { 982 {
966 // construct a TraitRef 983 // construct a TraitRef
967 let substs = 984 let substs = crate::subst_prefix(
968 parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); 985 &*parameters,
986 generics(self.db.upcast(), trait_.into()).len(),
987 );
969 self.push_obligation( 988 self.push_obligation(
970 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } 989 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
971 .cast(&Interner), 990 .cast(&Interner),
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 5b70d5e5a..aea354cde 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -7,14 +7,13 @@ use chalk_ir::Mutability;
7use hir_def::{ 7use hir_def::{
8 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat}, 8 expr::{BindingAnnotation, Expr, Literal, Pat, PatId, RecordFieldPat},
9 path::Path, 9 path::Path,
10 FieldId,
11}; 10};
12use hir_expand::name::Name; 11use hir_expand::name::Name;
13 12
14use super::{BindingMode, Expectation, InferenceContext}; 13use super::{BindingMode, Expectation, InferenceContext};
15use crate::{ 14use crate::{
16 lower::lower_to_chalk_mutability, utils::variant_data, Interner, Substitution, Ty, TyBuilder, 15 lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
17 TyKind, 16 TyExt, TyKind,
18}; 17};
19 18
20impl<'a> InferenceContext<'a> { 19impl<'a> InferenceContext<'a> {
@@ -28,13 +27,14 @@ impl<'a> InferenceContext<'a> {
28 ellipsis: Option<usize>, 27 ellipsis: Option<usize>,
29 ) -> Ty { 28 ) -> Ty {
30 let (ty, def) = self.resolve_variant(path); 29 let (ty, def) = self.resolve_variant(path);
31 let var_data = def.map(|it| variant_data(self.db.upcast(), it)); 30 let var_data = def.map(|it| it.variant_data(self.db.upcast()));
32 if let Some(variant) = def { 31 if let Some(variant) = def {
33 self.write_variant_resolution(id.into(), variant); 32 self.write_variant_resolution(id.into(), variant);
34 } 33 }
35 self.unify(&ty, expected); 34 self.unify(&ty, expected);
36 35
37 let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); 36 let substs =
37 ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
38 38
39 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 39 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
40 let (pre, post) = match ellipsis { 40 let (pre, post) = match ellipsis {
@@ -49,7 +49,9 @@ impl<'a> InferenceContext<'a> {
49 let expected_ty = var_data 49 let expected_ty = var_data
50 .as_ref() 50 .as_ref()
51 .and_then(|d| d.field(&Name::new_tuple_field(i))) 51 .and_then(|d| d.field(&Name::new_tuple_field(i)))
52 .map_or(self.err_ty(), |field| field_tys[field].clone().subst(&substs)); 52 .map_or(self.err_ty(), |field| {
53 field_tys[field].clone().substitute(&Interner, &substs)
54 });
53 let expected_ty = self.normalize_associated_types_in(expected_ty); 55 let expected_ty = self.normalize_associated_types_in(expected_ty);
54 self.infer_pat(subpat, &expected_ty, default_bm); 56 self.infer_pat(subpat, &expected_ty, default_bm);
55 } 57 }
@@ -66,25 +68,22 @@ impl<'a> InferenceContext<'a> {
66 id: PatId, 68 id: PatId,
67 ) -> Ty { 69 ) -> Ty {
68 let (ty, def) = self.resolve_variant(path); 70 let (ty, def) = self.resolve_variant(path);
69 let var_data = def.map(|it| variant_data(self.db.upcast(), it)); 71 let var_data = def.map(|it| it.variant_data(self.db.upcast()));
70 if let Some(variant) = def { 72 if let Some(variant) = def {
71 self.write_variant_resolution(id.into(), variant); 73 self.write_variant_resolution(id.into(), variant);
72 } 74 }
73 75
74 self.unify(&ty, expected); 76 self.unify(&ty, expected);
75 77
76 let substs = ty.substs().cloned().unwrap_or_else(|| Substitution::empty(&Interner)); 78 let substs =
79 ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
77 80
78 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default(); 81 let field_tys = def.map(|it| self.db.field_types(it)).unwrap_or_default();
79 for subpat in subpats { 82 for subpat in subpats {
80 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name)); 83 let matching_field = var_data.as_ref().and_then(|it| it.field(&subpat.name));
81 if let Some(local_id) = matching_field { 84 let expected_ty = matching_field.map_or(self.err_ty(), |field| {
82 let field_def = FieldId { parent: def.unwrap(), local_id }; 85 field_tys[field].clone().substitute(&Interner, &substs)
83 self.result.record_pat_field_resolutions.insert(subpat.pat, field_def); 86 });
84 }
85
86 let expected_ty = matching_field
87 .map_or(self.err_ty(), |field| field_tys[field].clone().subst(&substs));
88 let expected_ty = self.normalize_associated_types_in(expected_ty); 87 let expected_ty = self.normalize_associated_types_in(expected_ty);
89 self.infer_pat(subpat.pat, &expected_ty, default_bm); 88 self.infer_pat(subpat.pat, &expected_ty, default_bm);
90 } 89 }
@@ -101,7 +100,7 @@ impl<'a> InferenceContext<'a> {
101 let body = Arc::clone(&self.body); // avoid borrow checker problem 100 let body = Arc::clone(&self.body); // avoid borrow checker problem
102 101
103 if is_non_ref_pat(&body, pat) { 102 if is_non_ref_pat(&body, pat) {
104 while let Some((inner, mutability)) = expected.as_reference() { 103 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
105 expected = inner; 104 expected = inner;
106 default_bm = match default_bm { 105 default_bm = match default_bm {
107 BindingMode::Move => BindingMode::Ref(mutability), 106 BindingMode::Move => BindingMode::Ref(mutability),
@@ -123,7 +122,7 @@ impl<'a> InferenceContext<'a> {
123 let ty = match &body[pat] { 122 let ty = match &body[pat] {
124 &Pat::Tuple { ref args, ellipsis } => { 123 &Pat::Tuple { ref args, ellipsis } => {
125 let expectations = match expected.as_tuple() { 124 let expectations = match expected.as_tuple() {
126 Some(parameters) => &*parameters.0, 125 Some(parameters) => &*parameters.as_slice(&Interner),
127 _ => &[], 126 _ => &[],
128 }; 127 };
129 128
@@ -159,7 +158,7 @@ impl<'a> InferenceContext<'a> {
159 Pat::Ref { pat, mutability } => { 158 Pat::Ref { pat, mutability } => {
160 let mutability = lower_to_chalk_mutability(*mutability); 159 let mutability = lower_to_chalk_mutability(*mutability);
161 let expectation = match expected.as_reference() { 160 let expectation = match expected.as_reference() {
162 Some((inner_ty, exp_mut)) => { 161 Some((inner_ty, _lifetime, exp_mut)) => {
163 if mutability != exp_mut { 162 if mutability != exp_mut {
164 // FIXME: emit type error? 163 // FIXME: emit type error?
165 } 164 }
@@ -168,10 +167,10 @@ impl<'a> InferenceContext<'a> {
168 _ => self.result.standard_types.unknown.clone(), 167 _ => self.result.standard_types.unknown.clone(),
169 }; 168 };
170 let subty = self.infer_pat(*pat, &expectation, default_bm); 169 let subty = self.infer_pat(*pat, &expectation, default_bm);
171 TyKind::Ref(mutability, subty).intern(&Interner) 170 TyKind::Ref(mutability, static_lifetime(), subty).intern(&Interner)
172 } 171 }
173 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat( 172 Pat::TupleStruct { path: p, args: subpats, ellipsis } => self.infer_tuple_struct_pat(
174 p.as_ref(), 173 p.as_deref(),
175 subpats, 174 subpats,
176 expected, 175 expected,
177 default_bm, 176 default_bm,
@@ -179,7 +178,7 @@ impl<'a> InferenceContext<'a> {
179 *ellipsis, 178 *ellipsis,
180 ), 179 ),
181 Pat::Record { path: p, args: fields, ellipsis: _ } => { 180 Pat::Record { path: p, args: fields, ellipsis: _ } => {
182 self.infer_record_pat(p.as_ref(), fields, expected, default_bm, pat) 181 self.infer_record_pat(p.as_deref(), fields, expected, default_bm, pat)
183 } 182 }
184 Pat::Path(path) => { 183 Pat::Path(path) => {
185 // FIXME use correct resolver for the surrounding expression 184 // FIXME use correct resolver for the surrounding expression
@@ -201,7 +200,8 @@ impl<'a> InferenceContext<'a> {
201 200
202 let bound_ty = match mode { 201 let bound_ty = match mode {
203 BindingMode::Ref(mutability) => { 202 BindingMode::Ref(mutability) => {
204 TyKind::Ref(mutability, inner_ty.clone()).intern(&Interner) 203 TyKind::Ref(mutability, static_lifetime(), inner_ty.clone())
204 .intern(&Interner)
205 } 205 }
206 BindingMode::Move => inner_ty.clone(), 206 BindingMode::Move => inner_ty.clone(),
207 }; 207 };
@@ -210,17 +210,20 @@ impl<'a> InferenceContext<'a> {
210 return inner_ty; 210 return inner_ty;
211 } 211 }
212 Pat::Slice { prefix, slice, suffix } => { 212 Pat::Slice { prefix, slice, suffix } => {
213 let (container_ty, elem_ty): (fn(_) -> _, _) = match expected.kind(&Interner) { 213 let elem_ty = match expected.kind(&Interner) {
214 TyKind::Array(st) => (TyKind::Array, st.clone()), 214 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
215 TyKind::Slice(st) => (TyKind::Slice, st.clone()), 215 _ => self.err_ty(),
216 _ => (TyKind::Slice, self.err_ty()),
217 }; 216 };
218 217
219 for pat_id in prefix.iter().chain(suffix) { 218 for pat_id in prefix.iter().chain(suffix) {
220 self.infer_pat(*pat_id, &elem_ty, default_bm); 219 self.infer_pat(*pat_id, &elem_ty, default_bm);
221 } 220 }
222 221
223 let pat_ty = container_ty(elem_ty).intern(&Interner); 222 let pat_ty = match expected.kind(&Interner) {
223 TyKind::Array(_, const_) => TyKind::Array(elem_ty, const_.clone()),
224 _ => TyKind::Slice(elem_ty),
225 }
226 .intern(&Interner);
224 if let Some(slice_pat_id) = slice { 227 if let Some(slice_pat_id) = slice {
225 self.infer_pat(*slice_pat_id, &pat_ty, default_bm); 228 self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
226 } 229 }
@@ -239,7 +242,7 @@ impl<'a> InferenceContext<'a> {
239 let (inner_ty, alloc_ty) = match expected.as_adt() { 242 let (inner_ty, alloc_ty) = match expected.as_adt() {
240 Some((adt, subst)) if adt == box_adt => ( 243 Some((adt, subst)) if adt == box_adt => (
241 subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(), 244 subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
242 subst.interned(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()), 245 subst.as_slice(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
243 ), 246 ),
244 _ => (self.result.standard_types.unknown.clone(), None), 247 _ => (self.result.standard_types.unknown.clone(), None),
245 }; 248 };
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 671ea355f..495282eba 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -10,7 +10,10 @@ use hir_def::{
10}; 10};
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{method_resolution, Interner, Substitution, Ty, TyBuilder, TyKind, ValueTyDefId}; 13use crate::{
14 method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
15 ValueTyDefId,
16};
14 17
15use super::{ExprOrPatId, InferenceContext, TraitRef}; 18use super::{ExprOrPatId, InferenceContext, TraitRef};
16 19
@@ -81,9 +84,9 @@ impl<'a> InferenceContext<'a> {
81 ValueNs::ImplSelf(impl_id) => { 84 ValueNs::ImplSelf(impl_id) => {
82 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 85 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
83 let substs = generics.type_params_subst(self.db); 86 let substs = generics.type_params_subst(self.db);
84 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 87 let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs);
85 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { 88 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
86 let ty = self.db.value_ty(struct_id.into()).subst(&substs); 89 let ty = self.db.value_ty(struct_id.into()).substitute(&Interner, &substs);
87 return Some(ty); 90 return Some(ty);
88 } else { 91 } else {
89 // FIXME: diagnostic, invalid Self reference 92 // FIXME: diagnostic, invalid Self reference
@@ -98,7 +101,7 @@ impl<'a> InferenceContext<'a> {
98 let substs = ctx.substs_from_path(path, typable, true); 101 let substs = ctx.substs_from_path(path, typable, true);
99 let ty = TyBuilder::value_ty(self.db, typable) 102 let ty = TyBuilder::value_ty(self.db, typable)
100 .use_parent_substs(&parent_substs) 103 .use_parent_substs(&parent_substs)
101 .fill(substs.interned(&Interner)[parent_substs.len(&Interner)..].iter().cloned()) 104 .fill(substs.as_slice(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
102 .build(); 105 .build();
103 Some(ty) 106 Some(ty)
104 } 107 }
@@ -142,7 +145,7 @@ impl<'a> InferenceContext<'a> {
142 remaining_segments_for_ty, 145 remaining_segments_for_ty,
143 true, 146 true,
144 ); 147 );
145 if let TyKind::Unknown = ty.kind(&Interner) { 148 if let TyKind::Error = ty.kind(&Interner) {
146 return None; 149 return None;
147 } 150 }
148 151
@@ -207,7 +210,7 @@ impl<'a> InferenceContext<'a> {
207 name: &Name, 210 name: &Name,
208 id: ExprOrPatId, 211 id: ExprOrPatId,
209 ) -> Option<(ValueNs, Option<Substitution>)> { 212 ) -> Option<(ValueNs, Option<Substitution>)> {
210 if let TyKind::Unknown = ty.kind(&Interner) { 213 if let TyKind::Error = ty.kind(&Interner) {
211 return None; 214 return None;
212 } 215 }
213 216
@@ -243,7 +246,8 @@ impl<'a> InferenceContext<'a> {
243 let impl_substs = TyBuilder::subst_for_def(self.db, impl_id) 246 let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
244 .fill(iter::repeat_with(|| self.table.new_type_var())) 247 .fill(iter::repeat_with(|| self.table.new_type_var()))
245 .build(); 248 .build();
246 let impl_self_ty = self.db.impl_self_ty(impl_id).subst(&impl_substs); 249 let impl_self_ty =
250 self.db.impl_self_ty(impl_id).substitute(&Interner, &impl_substs);
247 self.unify(&impl_self_ty, &ty); 251 self.unify(&impl_self_ty, &ty);
248 Some(impl_substs) 252 Some(impl_substs)
249 } 253 }
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index a04b935ef..a887e20b0 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -2,13 +2,17 @@
2 2
3use std::borrow::Cow; 3use std::borrow::Cow;
4 4
5use chalk_ir::{FloatTy, IntTy, TyVariableKind, UniverseIndex, VariableKind}; 5use chalk_ir::{
6 cast::Cast, fold::Fold, interner::HasInterner, FloatTy, IntTy, TyVariableKind, UniverseIndex,
7 VariableKind,
8};
6use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue}; 9use ena::unify::{InPlaceUnificationTable, NoError, UnifyKey, UnifyValue};
7 10
8use super::{DomainGoal, InferenceContext}; 11use super::{DomainGoal, InferenceContext};
9use crate::{ 12use crate::{
10 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, 13 fold_tys, static_lifetime, AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds,
11 InEnvironment, InferenceVar, Interner, Scalar, Substitution, Ty, TyKind, TypeWalk, WhereClause, 14 DebruijnIndex, FnPointer, FnSubst, InEnvironment, InferenceVar, Interner, Scalar, Substitution,
15 Ty, TyExt, TyKind, WhereClause,
12}; 16};
13 17
14impl<'a> InferenceContext<'a> { 18impl<'a> InferenceContext<'a> {
@@ -33,7 +37,10 @@ where
33} 37}
34 38
35#[derive(Debug)] 39#[derive(Debug)]
36pub(super) struct Canonicalized<T> { 40pub(super) struct Canonicalized<T>
41where
42 T: HasInterner<Interner = Interner>,
43{
37 pub(super) value: Canonical<T>, 44 pub(super) value: Canonical<T>,
38 free_vars: Vec<(InferenceVar, TyVariableKind)>, 45 free_vars: Vec<(InferenceVar, TyVariableKind)>,
39} 46}
@@ -47,11 +54,16 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
47 }) 54 })
48 } 55 }
49 56
50 fn do_canonicalize<T: TypeWalk>(&mut self, t: T, binders: DebruijnIndex) -> T { 57 fn do_canonicalize<T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>>(
51 t.fold_binders( 58 &mut self,
52 &mut |ty, binders| match ty.kind(&Interner) { 59 t: T,
60 binders: DebruijnIndex,
61 ) -> T {
62 fold_tys(
63 t,
64 |ty, binders| match ty.kind(&Interner) {
53 &TyKind::InferenceVar(var, kind) => { 65 &TyKind::InferenceVar(var, kind) => {
54 let inner = var.to_inner(); 66 let inner = from_inference_var(var);
55 if self.var_stack.contains(&inner) { 67 if self.var_stack.contains(&inner) {
56 // recursive type 68 // recursive type
57 return self.ctx.table.type_variable_table.fallback_value(var, kind); 69 return self.ctx.table.type_variable_table.fallback_value(var, kind);
@@ -65,7 +77,7 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
65 result 77 result
66 } else { 78 } else {
67 let root = self.ctx.table.var_unification_table.find(inner); 79 let root = self.ctx.table.var_unification_table.find(inner);
68 let position = self.add(InferenceVar::from_inner(root), kind); 80 let position = self.add(to_inference_var(root), kind);
69 TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner) 81 TyKind::BoundVar(BoundVar::new(binders, position)).intern(&Interner)
70 } 82 }
71 } 83 }
@@ -75,7 +87,10 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
75 ) 87 )
76 } 88 }
77 89
78 fn into_canonicalized<T>(self, result: T) -> Canonicalized<T> { 90 fn into_canonicalized<T: HasInterner<Interner = Interner>>(
91 self,
92 result: T,
93 ) -> Canonicalized<T> {
79 let kinds = self 94 let kinds = self
80 .free_vars 95 .free_vars
81 .iter() 96 .iter()
@@ -102,25 +117,18 @@ impl<'a, 'b> Canonicalizer<'a, 'b> {
102 DomainGoal::Holds(wc) => { 117 DomainGoal::Holds(wc) => {
103 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST)) 118 DomainGoal::Holds(self.do_canonicalize(wc, DebruijnIndex::INNERMOST))
104 } 119 }
120 _ => unimplemented!(),
105 }; 121 };
106 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment }) 122 self.into_canonicalized(InEnvironment { goal: result, environment: obligation.environment })
107 } 123 }
108} 124}
109 125
110impl<T> Canonicalized<T> { 126impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
111 pub(super) fn decanonicalize_ty(&self, mut ty: Ty) -> Ty { 127 pub(super) fn decanonicalize_ty(&self, ty: Ty) -> Ty {
112 ty.walk_mut_binders( 128 crate::fold_free_vars(ty, |bound, _binders| {
113 &mut |ty, binders| { 129 let (v, k) = self.free_vars[bound.index];
114 if let &mut TyKind::BoundVar(bound) = ty.interned_mut() { 130 TyKind::InferenceVar(v, k).intern(&Interner)
115 if bound.debruijn >= binders { 131 })
116 let (v, k) = self.free_vars[bound.index];
117 *ty = TyKind::InferenceVar(v, k).intern(&Interner);
118 }
119 }
120 },
121 DebruijnIndex::INNERMOST,
122 );
123 ty
124 } 132 }
125 133
126 pub(super) fn apply_solution( 134 pub(super) fn apply_solution(
@@ -132,15 +140,17 @@ impl<T> Canonicalized<T> {
132 let new_vars = Substitution::from_iter( 140 let new_vars = Substitution::from_iter(
133 &Interner, 141 &Interner,
134 solution.binders.iter(&Interner).map(|k| match k.kind { 142 solution.binders.iter(&Interner).map(|k| match k.kind {
135 VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), 143 VariableKind::Ty(TyVariableKind::General) => {
136 VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), 144 ctx.table.new_type_var().cast(&Interner)
137 VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), 145 }
138 // HACK: Chalk can sometimes return new lifetime variables. We 146 VariableKind::Ty(TyVariableKind::Integer) => {
139 // want to just skip them, but to not mess up the indices of 147 ctx.table.new_integer_var().cast(&Interner)
140 // other variables, we'll just create a new type variable in 148 }
141 // their place instead. This should not matter (we never see the 149 VariableKind::Ty(TyVariableKind::Float) => {
142 // actual *uses* of the lifetime variable). 150 ctx.table.new_float_var().cast(&Interner)
143 VariableKind::Lifetime => ctx.table.new_type_var(), 151 }
152 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
153 VariableKind::Lifetime => static_lifetime().cast(&Interner),
144 _ => panic!("const variable in solution"), 154 _ => panic!("const variable in solution"),
145 }), 155 }),
146 ); 156 );
@@ -149,7 +159,7 @@ impl<T> Canonicalized<T> {
149 // eagerly replace projections in the type; we may be getting types 159 // eagerly replace projections in the type; we may be getting types
150 // e.g. from where clauses where this hasn't happened yet 160 // e.g. from where clauses where this hasn't happened yet
151 let ty = ctx.normalize_associated_types_in( 161 let ty = ctx.normalize_associated_types_in(
152 ty.assert_ty_ref(&Interner).clone().subst_bound_vars(&new_vars), 162 new_vars.apply(ty.assert_ty_ref(&Interner).clone(), &Interner),
153 ); 163 );
154 ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty); 164 ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty);
155 } 165 }
@@ -170,8 +180,8 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
170 // fallback to Unknown in the end (kind of hacky, as below) 180 // fallback to Unknown in the end (kind of hacky, as below)
171 .map(|_| table.new_type_var()), 181 .map(|_| table.new_type_var()),
172 ); 182 );
173 let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); 183 let ty1_with_vars = vars.apply(tys.value.0.clone(), &Interner);
174 let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); 184 let ty2_with_vars = vars.apply(tys.value.1.clone(), &Interner);
175 if !table.unify(&ty1_with_vars, &ty2_with_vars) { 185 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
176 return None; 186 return None;
177 } 187 }
@@ -204,17 +214,17 @@ impl TypeVariableTable {
204 } 214 }
205 215
206 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) { 216 pub(super) fn set_diverging(&mut self, iv: InferenceVar, diverging: bool) {
207 self.inner[iv.to_inner().0 as usize].diverging = diverging; 217 self.inner[from_inference_var(iv).0 as usize].diverging = diverging;
208 } 218 }
209 219
210 fn is_diverging(&mut self, iv: InferenceVar) -> bool { 220 fn is_diverging(&mut self, iv: InferenceVar) -> bool {
211 self.inner[iv.to_inner().0 as usize].diverging 221 self.inner[from_inference_var(iv).0 as usize].diverging
212 } 222 }
213 223
214 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty { 224 fn fallback_value(&self, iv: InferenceVar, kind: TyVariableKind) -> Ty {
215 match kind { 225 match kind {
216 _ if self.inner[iv.to_inner().0 as usize].diverging => TyKind::Never, 226 _ if self.inner[from_inference_var(iv).0 as usize].diverging => TyKind::Never,
217 TyVariableKind::General => TyKind::Unknown, 227 TyVariableKind::General => TyKind::Error,
218 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)), 228 TyVariableKind::Integer => TyKind::Scalar(Scalar::Int(IntTy::I32)),
219 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)), 229 TyVariableKind::Float => TyKind::Scalar(Scalar::Float(FloatTy::F64)),
220 } 230 }
@@ -247,7 +257,7 @@ impl InferenceTable {
247 self.type_variable_table.push(TypeVariableData { diverging }); 257 self.type_variable_table.push(TypeVariableData { diverging });
248 let key = self.var_unification_table.new_key(TypeVarValue::Unknown); 258 let key = self.var_unification_table.new_key(TypeVarValue::Unknown);
249 assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1); 259 assert_eq!(key.0 as usize, self.type_variable_table.inner.len() - 1);
250 TyKind::InferenceVar(InferenceVar::from_inner(key), kind).intern(&Interner) 260 TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner)
251 } 261 }
252 262
253 pub(crate) fn new_type_var(&mut self) -> Ty { 263 pub(crate) fn new_type_var(&mut self) -> Ty {
@@ -284,7 +294,7 @@ impl InferenceTable {
284 substs2: &Substitution, 294 substs2: &Substitution,
285 depth: usize, 295 depth: usize,
286 ) -> bool { 296 ) -> bool {
287 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| { 297 substs1.iter(&Interner).zip(substs2.iter(&Interner)).all(|(t1, t2)| {
288 self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth) 298 self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth)
289 }) 299 })
290 } 300 }
@@ -305,8 +315,8 @@ impl InferenceTable {
305 (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2)) 315 (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2))
306 | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2)) 316 | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2))
307 | ( 317 | (
308 TyKind::Function(FnPointer { substs: substs1, .. }), 318 TyKind::Function(FnPointer { substitution: FnSubst(substs1), .. }),
309 TyKind::Function(FnPointer { substs: substs2, .. }), 319 TyKind::Function(FnPointer { substitution: FnSubst(substs2), .. }),
310 ) 320 )
311 | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2)) 321 | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2))
312 | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2)) 322 | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2))
@@ -314,9 +324,11 @@ impl InferenceTable {
314 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => { 324 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => {
315 self.unify_substs(substs1, substs2, depth + 1) 325 self.unify_substs(substs1, substs2, depth + 1)
316 } 326 }
317 (TyKind::Ref(_, ty1), TyKind::Ref(_, ty2)) 327 (TyKind::Array(ty1, c1), TyKind::Array(ty2, c2)) if c1 == c2 => {
328 self.unify_inner(ty1, ty2, depth + 1)
329 }
330 (TyKind::Ref(_, _, ty1), TyKind::Ref(_, _, ty2))
318 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2)) 331 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
319 | (TyKind::Array(ty1), TyKind::Array(ty2))
320 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1), 332 | (TyKind::Slice(ty1), TyKind::Slice(ty2)) => self.unify_inner(ty1, ty2, depth + 1),
321 _ => true, /* we checked equals_ctor already */ 333 _ => true, /* we checked equals_ctor already */
322 } 334 }
@@ -327,7 +339,7 @@ impl InferenceTable {
327 339
328 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 340 pub(super) fn unify_inner_trivial(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
329 match (ty1.kind(&Interner), ty2.kind(&Interner)) { 341 match (ty1.kind(&Interner), ty2.kind(&Interner)) {
330 (TyKind::Unknown, _) | (_, TyKind::Unknown) => true, 342 (TyKind::Error, _) | (_, TyKind::Error) => true,
331 343
332 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, 344 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true,
333 345
@@ -364,8 +376,12 @@ impl InferenceTable {
364 == self.type_variable_table.is_diverging(*tv2) => 376 == self.type_variable_table.is_diverging(*tv2) =>
365 { 377 {
366 // both type vars are unknown since we tried to resolve them 378 // both type vars are unknown since we tried to resolve them
367 if !self.var_unification_table.unioned(tv1.to_inner(), tv2.to_inner()) { 379 if !self
368 self.var_unification_table.union(tv1.to_inner(), tv2.to_inner()); 380 .var_unification_table
381 .unioned(from_inference_var(*tv1), from_inference_var(*tv2))
382 {
383 self.var_unification_table
384 .union(from_inference_var(*tv1), from_inference_var(*tv2));
369 self.revision += 1; 385 self.revision += 1;
370 } 386 }
371 true 387 true
@@ -402,7 +418,7 @@ impl InferenceTable {
402 ) => { 418 ) => {
403 // the type var is unknown since we tried to resolve it 419 // the type var is unknown since we tried to resolve it
404 self.var_unification_table.union_value( 420 self.var_unification_table.union_value(
405 tv.to_inner(), 421 from_inference_var(*tv),
406 TypeVarValue::Known(other.clone().intern(&Interner)), 422 TypeVarValue::Known(other.clone().intern(&Interner)),
407 ); 423 );
408 self.revision += 1; 424 self.revision += 1;
@@ -457,7 +473,7 @@ impl InferenceTable {
457 } 473 }
458 match ty.kind(&Interner) { 474 match ty.kind(&Interner) {
459 TyKind::InferenceVar(tv, _) => { 475 TyKind::InferenceVar(tv, _) => {
460 let inner = tv.to_inner(); 476 let inner = from_inference_var(*tv);
461 match self.var_unification_table.inlined_probe_value(inner).known() { 477 match self.var_unification_table.inlined_probe_value(inner).known() {
462 Some(known_ty) => { 478 Some(known_ty) => {
463 // The known_ty can't be a type var itself 479 // The known_ty can't be a type var itself
@@ -478,55 +494,63 @@ impl InferenceTable {
478 /// be resolved as far as possible, i.e. contain no type variables with 494 /// be resolved as far as possible, i.e. contain no type variables with
479 /// known type. 495 /// known type.
480 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 496 fn resolve_ty_as_possible_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
481 ty.fold(&mut |ty| match ty.kind(&Interner) { 497 fold_tys(
482 &TyKind::InferenceVar(tv, kind) => { 498 ty,
483 let inner = tv.to_inner(); 499 |ty, _| match ty.kind(&Interner) {
484 if tv_stack.contains(&inner) { 500 &TyKind::InferenceVar(tv, kind) => {
485 cov_mark::hit!(type_var_cycles_resolve_as_possible); 501 let inner = from_inference_var(tv);
486 // recursive type 502 if tv_stack.contains(&inner) {
487 return self.type_variable_table.fallback_value(tv, kind); 503 cov_mark::hit!(type_var_cycles_resolve_as_possible);
488 } 504 // recursive type
489 if let Some(known_ty) = 505 return self.type_variable_table.fallback_value(tv, kind);
490 self.var_unification_table.inlined_probe_value(inner).known() 506 }
491 { 507 if let Some(known_ty) =
492 // known_ty may contain other variables that are known by now 508 self.var_unification_table.inlined_probe_value(inner).known()
493 tv_stack.push(inner); 509 {
494 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone()); 510 // known_ty may contain other variables that are known by now
495 tv_stack.pop(); 511 tv_stack.push(inner);
496 result 512 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
497 } else { 513 tv_stack.pop();
498 ty 514 result
515 } else {
516 ty
517 }
499 } 518 }
500 } 519 _ => ty,
501 _ => ty, 520 },
502 }) 521 DebruijnIndex::INNERMOST,
522 )
503 } 523 }
504 524
505 /// Resolves the type completely; type variables without known type are 525 /// Resolves the type completely; type variables without known type are
506 /// replaced by TyKind::Unknown. 526 /// replaced by TyKind::Unknown.
507 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty { 527 fn resolve_ty_completely_inner(&mut self, tv_stack: &mut Vec<TypeVarId>, ty: Ty) -> Ty {
508 ty.fold(&mut |ty| match ty.kind(&Interner) { 528 fold_tys(
509 &TyKind::InferenceVar(tv, kind) => { 529 ty,
510 let inner = tv.to_inner(); 530 |ty, _| match ty.kind(&Interner) {
511 if tv_stack.contains(&inner) { 531 &TyKind::InferenceVar(tv, kind) => {
512 cov_mark::hit!(type_var_cycles_resolve_completely); 532 let inner = from_inference_var(tv);
513 // recursive type 533 if tv_stack.contains(&inner) {
514 return self.type_variable_table.fallback_value(tv, kind); 534 cov_mark::hit!(type_var_cycles_resolve_completely);
515 } 535 // recursive type
516 if let Some(known_ty) = 536 return self.type_variable_table.fallback_value(tv, kind);
517 self.var_unification_table.inlined_probe_value(inner).known() 537 }
518 { 538 if let Some(known_ty) =
519 // known_ty may contain other variables that are known by now 539 self.var_unification_table.inlined_probe_value(inner).known()
520 tv_stack.push(inner); 540 {
521 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); 541 // known_ty may contain other variables that are known by now
522 tv_stack.pop(); 542 tv_stack.push(inner);
523 result 543 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
524 } else { 544 tv_stack.pop();
525 self.type_variable_table.fallback_value(tv, kind) 545 result
546 } else {
547 self.type_variable_table.fallback_value(tv, kind)
548 }
526 } 549 }
527 } 550 _ => ty,
528 _ => ty, 551 },
529 }) 552 DebruijnIndex::INNERMOST,
553 )
530 } 554 }
531} 555}
532 556
@@ -550,6 +574,14 @@ impl UnifyKey for TypeVarId {
550 } 574 }
551} 575}
552 576
577fn from_inference_var(var: InferenceVar) -> TypeVarId {
578 TypeVarId(var.index())
579}
580
581fn to_inference_var(TypeVarId(index): TypeVarId) -> InferenceVar {
582 index.into()
583}
584
553/// The value of a type variable: either we already know the type, or we don't 585/// The value of a type variable: either we already know the type, or we don't
554/// know it yet. 586/// know it yet.
555#[derive(Clone, PartialEq, Eq, Debug)] 587#[derive(Clone, PartialEq, Eq, Debug)]
diff --git a/crates/hir_ty/src/traits/chalk/interner.rs b/crates/hir_ty/src/interner.rs
index 94e94a26d..a1656115d 100644
--- a/crates/hir_ty/src/traits/chalk/interner.rs
+++ b/crates/hir_ty/src/interner.rs
@@ -1,61 +1,83 @@
1//! Implementation of the Chalk `Interner` trait, which allows customizing the 1//! Implementation of the Chalk `Interner` trait, which allows customizing the
2//! representation of the various objects Chalk deals with (types, goals etc.). 2//! representation of the various objects Chalk deals with (types, goals etc.).
3 3
4use super::tls; 4use crate::{chalk_db, tls, GenericArg};
5use base_db::salsa::InternId; 5use base_db::salsa::InternId;
6use chalk_ir::{GenericArg, Goal, GoalData}; 6use chalk_ir::{Goal, GoalData};
7use hir_def::TypeAliasId; 7use hir_def::{
8 intern::{impl_internable, InternStorage, Internable, Interned},
9 TypeAliasId,
10};
8use smallvec::SmallVec; 11use smallvec::SmallVec;
9use std::{fmt, sync::Arc}; 12use std::{fmt, sync::Arc};
10 13
11#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)] 14#[derive(Debug, Copy, Clone, Hash, PartialOrd, Ord, PartialEq, Eq)]
12pub struct Interner; 15pub struct Interner;
13 16
14pub(crate) type AssocTypeId = chalk_ir::AssocTypeId<Interner>; 17#[derive(PartialEq, Eq, Hash, Debug)]
15pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; 18pub struct InternedWrapper<T>(T);
16pub(crate) type TraitId = chalk_ir::TraitId<Interner>; 19
17pub(crate) type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; 20impl<T> std::ops::Deref for InternedWrapper<T> {
18pub(crate) type AdtId = chalk_ir::AdtId<Interner>; 21 type Target = T;
19pub(crate) type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; 22
20pub(crate) type ImplId = chalk_ir::ImplId<Interner>; 23 fn deref(&self) -> &Self::Target {
21pub(crate) type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; 24 &self.0
22pub(crate) type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>; 25 }
23pub(crate) type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; 26}
24pub(crate) type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; 27
25pub(crate) type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 28impl_internable!(
26pub(crate) type OpaqueTyDatum = chalk_solve::rust_ir::OpaqueTyDatum<Interner>; 29 InternedWrapper<Vec<chalk_ir::VariableKind<Interner>>>,
27pub(crate) type Variances = chalk_ir::Variances<Interner>; 30 InternedWrapper<SmallVec<[GenericArg; 2]>>,
31 InternedWrapper<chalk_ir::TyData<Interner>>,
32 InternedWrapper<chalk_ir::LifetimeData<Interner>>,
33 InternedWrapper<chalk_ir::ConstData<Interner>>,
34 InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>,
35 InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>,
36 InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>,
37 InternedWrapper<Vec<chalk_ir::Variance>>,
38);
28 39
29impl chalk_ir::interner::Interner for Interner { 40impl chalk_ir::interner::Interner for Interner {
30 type InternedType = Arc<chalk_ir::TyData<Self>>; 41 type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
31 type InternedLifetime = chalk_ir::LifetimeData<Self>; 42 type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
32 type InternedConst = Arc<chalk_ir::ConstData<Self>>; 43 type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
33 type InternedConcreteConst = (); 44 type InternedConcreteConst = ();
34 type InternedGenericArg = chalk_ir::GenericArgData<Self>; 45 type InternedGenericArg = chalk_ir::GenericArgData<Self>;
35 type InternedGoal = Arc<GoalData<Self>>; 46 type InternedGoal = Arc<GoalData<Self>>;
36 type InternedGoals = Vec<Goal<Self>>; 47 type InternedGoals = Vec<Goal<Self>>;
37 type InternedSubstitution = SmallVec<[GenericArg<Self>; 2]>; 48 type InternedSubstitution = Interned<InternedWrapper<SmallVec<[GenericArg; 2]>>>;
38 type InternedProgramClause = Arc<chalk_ir::ProgramClauseData<Self>>; 49 type InternedProgramClause = chalk_ir::ProgramClauseData<Self>;
39 type InternedProgramClauses = Arc<[chalk_ir::ProgramClause<Self>]>; 50 type InternedProgramClauses = Interned<InternedWrapper<Vec<chalk_ir::ProgramClause<Self>>>>;
40 type InternedQuantifiedWhereClauses = Vec<chalk_ir::QuantifiedWhereClause<Self>>; 51 type InternedQuantifiedWhereClauses =
41 type InternedVariableKinds = Vec<chalk_ir::VariableKind<Self>>; 52 Interned<InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Self>>>>;
42 type InternedCanonicalVarKinds = Vec<chalk_ir::CanonicalVarKind<Self>>; 53 type InternedVariableKinds = Interned<InternedWrapper<Vec<chalk_ir::VariableKind<Interner>>>>;
54 type InternedCanonicalVarKinds =
55 Interned<InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Self>>>>;
43 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>; 56 type InternedConstraints = Vec<chalk_ir::InEnvironment<chalk_ir::Constraint<Self>>>;
44 type InternedVariances = Arc<[chalk_ir::Variance]>; 57 type InternedVariances = Interned<InternedWrapper<Vec<chalk_ir::Variance>>>;
45 type DefId = InternId; 58 type DefId = InternId;
46 type InternedAdtId = hir_def::AdtId; 59 type InternedAdtId = hir_def::AdtId;
47 type Identifier = TypeAliasId; 60 type Identifier = TypeAliasId;
48 type FnAbi = (); 61 type FnAbi = ();
49 62
50 fn debug_adt_id(type_kind_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 63 fn debug_adt_id(
64 type_kind_id: chalk_db::AdtId,
65 fmt: &mut fmt::Formatter<'_>,
66 ) -> Option<fmt::Result> {
51 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt))) 67 tls::with_current_program(|prog| Some(prog?.debug_struct_id(type_kind_id, fmt)))
52 } 68 }
53 69
54 fn debug_trait_id(type_kind_id: TraitId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 70 fn debug_trait_id(
71 type_kind_id: chalk_db::TraitId,
72 fmt: &mut fmt::Formatter<'_>,
73 ) -> Option<fmt::Result> {
55 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt))) 74 tls::with_current_program(|prog| Some(prog?.debug_trait_id(type_kind_id, fmt)))
56 } 75 }
57 76
58 fn debug_assoc_type_id(id: AssocTypeId, fmt: &mut fmt::Formatter<'_>) -> Option<fmt::Result> { 77 fn debug_assoc_type_id(
78 id: chalk_db::AssocTypeId,
79 fmt: &mut fmt::Formatter<'_>,
80 ) -> Option<fmt::Result> {
59 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt))) 81 tls::with_current_program(|prog| Some(prog?.debug_assoc_type_id(id, fmt)))
60 } 82 }
61 83
@@ -99,7 +121,7 @@ impl chalk_ir::interner::Interner for Interner {
99 } 121 }
100 122
101 fn debug_generic_arg( 123 fn debug_generic_arg(
102 parameter: &GenericArg<Interner>, 124 parameter: &GenericArg,
103 fmt: &mut fmt::Formatter<'_>, 125 fmt: &mut fmt::Formatter<'_>,
104 ) -> Option<fmt::Result> { 126 ) -> Option<fmt::Result> {
105 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt))) 127 tls::with_current_program(|prog| Some(prog?.debug_generic_arg(parameter, fmt)))
@@ -192,59 +214,58 @@ impl chalk_ir::interner::Interner for Interner {
192 tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt))) 214 tls::with_current_program(|prog| Some(prog?.debug_quantified_where_clauses(clauses, fmt)))
193 } 215 }
194 216
195 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Arc<chalk_ir::TyData<Self>> { 217 fn intern_ty(&self, kind: chalk_ir::TyKind<Self>) -> Self::InternedType {
196 let flags = kind.compute_flags(self); 218 let flags = kind.compute_flags(self);
197 Arc::new(chalk_ir::TyData { kind, flags }) 219 Interned::new(InternedWrapper(chalk_ir::TyData { kind, flags }))
198 } 220 }
199 221
200 fn ty_data<'a>(&self, ty: &'a Arc<chalk_ir::TyData<Self>>) -> &'a chalk_ir::TyData<Self> { 222 fn ty_data<'a>(&self, ty: &'a Self::InternedType) -> &'a chalk_ir::TyData<Self> {
201 ty 223 &ty.0
202 } 224 }
203 225
204 fn intern_lifetime( 226 fn intern_lifetime(&self, lifetime: chalk_ir::LifetimeData<Self>) -> Self::InternedLifetime {
205 &self, 227 Interned::new(InternedWrapper(lifetime))
206 lifetime: chalk_ir::LifetimeData<Self>,
207 ) -> chalk_ir::LifetimeData<Self> {
208 lifetime
209 } 228 }
210 229
211 fn lifetime_data<'a>( 230 fn lifetime_data<'a>(
212 &self, 231 &self,
213 lifetime: &'a chalk_ir::LifetimeData<Self>, 232 lifetime: &'a Self::InternedLifetime,
214 ) -> &'a chalk_ir::LifetimeData<Self> { 233 ) -> &'a chalk_ir::LifetimeData<Self> {
215 lifetime 234 &lifetime.0
216 } 235 }
217 236
218 fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Arc<chalk_ir::ConstData<Self>> { 237 fn intern_const(&self, constant: chalk_ir::ConstData<Self>) -> Self::InternedConst {
219 Arc::new(constant) 238 Interned::new(InternedWrapper(constant))
220 } 239 }
221 240
222 fn const_data<'a>( 241 fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a chalk_ir::ConstData<Self> {
223 &self, 242 &constant.0
224 constant: &'a Arc<chalk_ir::ConstData<Self>>,
225 ) -> &'a chalk_ir::ConstData<Self> {
226 constant
227 } 243 }
228 244
229 fn const_eq(&self, _ty: &Arc<chalk_ir::TyData<Self>>, _c1: &(), _c2: &()) -> bool { 245 fn const_eq(
246 &self,
247 _ty: &Self::InternedType,
248 _c1: &Self::InternedConcreteConst,
249 _c2: &Self::InternedConcreteConst,
250 ) -> bool {
230 true 251 true
231 } 252 }
232 253
233 fn intern_generic_arg( 254 fn intern_generic_arg(
234 &self, 255 &self,
235 parameter: chalk_ir::GenericArgData<Self>, 256 parameter: chalk_ir::GenericArgData<Self>,
236 ) -> chalk_ir::GenericArgData<Self> { 257 ) -> Self::InternedGenericArg {
237 parameter 258 parameter
238 } 259 }
239 260
240 fn generic_arg_data<'a>( 261 fn generic_arg_data<'a>(
241 &self, 262 &self,
242 parameter: &'a chalk_ir::GenericArgData<Self>, 263 parameter: &'a Self::InternedGenericArg,
243 ) -> &'a chalk_ir::GenericArgData<Self> { 264 ) -> &'a chalk_ir::GenericArgData<Self> {
244 parameter 265 parameter
245 } 266 }
246 267
247 fn intern_goal(&self, goal: GoalData<Self>) -> Arc<GoalData<Self>> { 268 fn intern_goal(&self, goal: GoalData<Self>) -> Self::InternedGoal {
248 Arc::new(goal) 269 Arc::new(goal)
249 } 270 }
250 271
@@ -255,38 +276,38 @@ impl chalk_ir::interner::Interner for Interner {
255 data.into_iter().collect() 276 data.into_iter().collect()
256 } 277 }
257 278
258 fn goal_data<'a>(&self, goal: &'a Arc<GoalData<Self>>) -> &'a GoalData<Self> { 279 fn goal_data<'a>(&self, goal: &'a Self::InternedGoal) -> &'a GoalData<Self> {
259 goal 280 goal
260 } 281 }
261 282
262 fn goals_data<'a>(&self, goals: &'a Vec<Goal<Interner>>) -> &'a [Goal<Interner>] { 283 fn goals_data<'a>(&self, goals: &'a Self::InternedGoals) -> &'a [Goal<Interner>] {
263 goals 284 goals
264 } 285 }
265 286
266 fn intern_substitution<E>( 287 fn intern_substitution<E>(
267 &self, 288 &self,
268 data: impl IntoIterator<Item = Result<GenericArg<Self>, E>>, 289 data: impl IntoIterator<Item = Result<GenericArg, E>>,
269 ) -> Result<Self::InternedSubstitution, E> { 290 ) -> Result<Self::InternedSubstitution, E> {
270 data.into_iter().collect() 291 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
271 } 292 }
272 293
273 fn substitution_data<'a>( 294 fn substitution_data<'a>(
274 &self, 295 &self,
275 substitution: &'a Self::InternedSubstitution, 296 substitution: &'a Self::InternedSubstitution,
276 ) -> &'a [GenericArg<Self>] { 297 ) -> &'a [GenericArg] {
277 substitution 298 &substitution.as_ref().0
278 } 299 }
279 300
280 fn intern_program_clause( 301 fn intern_program_clause(
281 &self, 302 &self,
282 data: chalk_ir::ProgramClauseData<Self>, 303 data: chalk_ir::ProgramClauseData<Self>,
283 ) -> Arc<chalk_ir::ProgramClauseData<Self>> { 304 ) -> Self::InternedProgramClause {
284 Arc::new(data) 305 data
285 } 306 }
286 307
287 fn program_clause_data<'a>( 308 fn program_clause_data<'a>(
288 &self, 309 &self,
289 clause: &'a Arc<chalk_ir::ProgramClauseData<Self>>, 310 clause: &'a Self::InternedProgramClause,
290 ) -> &'a chalk_ir::ProgramClauseData<Self> { 311 ) -> &'a chalk_ir::ProgramClauseData<Self> {
291 clause 312 clause
292 } 313 }
@@ -294,13 +315,13 @@ impl chalk_ir::interner::Interner for Interner {
294 fn intern_program_clauses<E>( 315 fn intern_program_clauses<E>(
295 &self, 316 &self,
296 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>, 317 data: impl IntoIterator<Item = Result<chalk_ir::ProgramClause<Self>, E>>,
297 ) -> Result<Arc<[chalk_ir::ProgramClause<Self>]>, E> { 318 ) -> Result<Self::InternedProgramClauses, E> {
298 data.into_iter().collect() 319 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
299 } 320 }
300 321
301 fn program_clauses_data<'a>( 322 fn program_clauses_data<'a>(
302 &self, 323 &self,
303 clauses: &'a Arc<[chalk_ir::ProgramClause<Self>]>, 324 clauses: &'a Self::InternedProgramClauses,
304 ) -> &'a [chalk_ir::ProgramClause<Self>] { 325 ) -> &'a [chalk_ir::ProgramClause<Self>] {
305 &clauses 326 &clauses
306 } 327 }
@@ -309,7 +330,7 @@ impl chalk_ir::interner::Interner for Interner {
309 &self, 330 &self,
310 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>, 331 data: impl IntoIterator<Item = Result<chalk_ir::QuantifiedWhereClause<Self>, E>>,
311 ) -> Result<Self::InternedQuantifiedWhereClauses, E> { 332 ) -> Result<Self::InternedQuantifiedWhereClauses, E> {
312 data.into_iter().collect() 333 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
313 } 334 }
314 335
315 fn quantified_where_clauses_data<'a>( 336 fn quantified_where_clauses_data<'a>(
@@ -323,21 +344,21 @@ impl chalk_ir::interner::Interner for Interner {
323 &self, 344 &self,
324 data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>, 345 data: impl IntoIterator<Item = Result<chalk_ir::VariableKind<Self>, E>>,
325 ) -> Result<Self::InternedVariableKinds, E> { 346 ) -> Result<Self::InternedVariableKinds, E> {
326 data.into_iter().collect() 347 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
327 } 348 }
328 349
329 fn variable_kinds_data<'a>( 350 fn variable_kinds_data<'a>(
330 &self, 351 &self,
331 parameter_kinds: &'a Self::InternedVariableKinds, 352 parameter_kinds: &'a Self::InternedVariableKinds,
332 ) -> &'a [chalk_ir::VariableKind<Self>] { 353 ) -> &'a [chalk_ir::VariableKind<Self>] {
333 &parameter_kinds 354 &parameter_kinds.as_ref().0
334 } 355 }
335 356
336 fn intern_canonical_var_kinds<E>( 357 fn intern_canonical_var_kinds<E>(
337 &self, 358 &self,
338 data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>, 359 data: impl IntoIterator<Item = Result<chalk_ir::CanonicalVarKind<Self>, E>>,
339 ) -> Result<Self::InternedCanonicalVarKinds, E> { 360 ) -> Result<Self::InternedCanonicalVarKinds, E> {
340 data.into_iter().collect() 361 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
341 } 362 }
342 363
343 fn canonical_var_kinds_data<'a>( 364 fn canonical_var_kinds_data<'a>(
@@ -377,7 +398,7 @@ impl chalk_ir::interner::Interner for Interner {
377 &self, 398 &self,
378 data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>, 399 data: impl IntoIterator<Item = Result<chalk_ir::Variance, E>>,
379 ) -> Result<Self::InternedVariances, E> { 400 ) -> Result<Self::InternedVariances, E> {
380 data.into_iter().collect() 401 Ok(Interned::new(InternedWrapper(data.into_iter().collect::<Result<_, _>>()?)))
381 } 402 }
382 403
383 fn variances_data<'a>( 404 fn variances_data<'a>(
@@ -391,3 +412,12 @@ impl chalk_ir::interner::Interner for Interner {
391impl chalk_ir::interner::HasInterner for Interner { 412impl chalk_ir::interner::HasInterner for Interner {
392 type Interner = Self; 413 type Interner = Self;
393} 414}
415
416#[macro_export]
417macro_rules! has_interner {
418 ($t:ty) => {
419 impl HasInterner for $t {
420 type Interner = crate::Interner;
421 }
422 };
423}
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index a8c87eadf..0505fa4ae 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -1,65 +1,68 @@
1//! The type system. We currently use this to infer types for completion, hover 1//! The type system. We currently use this to infer types for completion, hover
2//! information and various assists. 2//! information and various assists.
3
3#[allow(unused)] 4#[allow(unused)]
4macro_rules! eprintln { 5macro_rules! eprintln {
5 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) }; 6 ($($tt:tt)*) => { stdx::eprintln!($($tt)*) };
6} 7}
7 8
8mod autoderef; 9mod autoderef;
9pub mod primitive;
10pub mod traits;
11pub mod method_resolution;
12mod op;
13mod lower;
14pub(crate) mod infer;
15pub(crate) mod utils;
16mod chalk_cast;
17mod chalk_ext;
18mod builder; 10mod builder;
19 11mod chalk_db;
20pub mod display; 12mod chalk_ext;
13mod infer;
14mod interner;
15mod lower;
16mod mapping;
17mod op;
18mod tls;
19mod utils;
20mod walk;
21pub mod db; 21pub mod db;
22pub mod diagnostics; 22pub mod diagnostics;
23pub mod display;
24pub mod method_resolution;
25pub mod primitive;
26pub mod traits;
23 27
24#[cfg(test)] 28#[cfg(test)]
25mod tests; 29mod tests;
26#[cfg(test)] 30#[cfg(test)]
27mod test_db; 31mod test_db;
28 32
29use std::{mem, sync::Arc}; 33use std::sync::Arc;
30
31use chalk_ir::cast::{CastTo, Caster};
32use itertools::Itertools;
33use smallvec::SmallVec;
34 34
35use base_db::salsa; 35use chalk_ir::{
36use hir_def::{ 36 fold::{Fold, Shift},
37 expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, GenericDefId, HasModule, 37 interner::HasInterner,
38 LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, 38 UintTy,
39}; 39};
40use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};
40 41
41use crate::{ 42use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
42 db::HirDatabase,
43 display::HirDisplay,
44 utils::{generics, make_mut_slice},
45};
46 43
47pub use autoderef::autoderef; 44pub use autoderef::autoderef;
48pub use builder::TyBuilder; 45pub use builder::TyBuilder;
49pub use chalk_ext::TyExt; 46pub use chalk_ext::*;
50pub use infer::{could_unify, InferenceResult, InferenceVar}; 47pub use infer::{could_unify, InferenceResult};
48pub use interner::Interner;
51pub use lower::{ 49pub use lower::{
52 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 50 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
53 TyDefId, TyLoweringContext, ValueTyDefId, 51 TyDefId, TyLoweringContext, ValueTyDefId,
54}; 52};
55pub use traits::{AliasEq, DomainGoal, InEnvironment, TraitEnvironment}; 53pub use mapping::{
54 const_from_placeholder_idx, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
55 from_placeholder_idx, lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
56 to_foreign_def_id, to_placeholder_idx,
57};
58pub use traits::TraitEnvironment;
59pub use utils::all_super_traits;
60pub use walk::TypeWalk;
56 61
57pub use chalk_ir::{ 62pub use chalk_ir::{
58 cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, 63 cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
59}; 64};
60 65
61pub use crate::traits::chalk::Interner;
62
63pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>; 66pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
64pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; 67pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
65pub type FnDefId = chalk_ir::FnDefId<Interner>; 68pub type FnDefId = chalk_ir::FnDefId<Interner>;
@@ -67,401 +70,56 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
67pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 70pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
68pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; 71pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
69 72
73pub type VariableKind = chalk_ir::VariableKind<Interner>;
74pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
70pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>; 75pub type CanonicalVarKinds = chalk_ir::CanonicalVarKinds<Interner>;
76pub type Binders<T> = chalk_ir::Binders<T>;
77pub type Substitution = chalk_ir::Substitution<Interner>;
78pub type GenericArg = chalk_ir::GenericArg<Interner>;
79pub type GenericArgData = chalk_ir::GenericArgData<Interner>;
80
81pub type Ty = chalk_ir::Ty<Interner>;
82pub type TyKind = chalk_ir::TyKind<Interner>;
83pub type DynTy = chalk_ir::DynTy<Interner>;
84pub type FnPointer = chalk_ir::FnPointer<Interner>;
85// pub type FnSubst = chalk_ir::FnSubst<Interner>;
86pub use chalk_ir::FnSubst;
87pub type ProjectionTy = chalk_ir::ProjectionTy<Interner>;
88pub type AliasTy = chalk_ir::AliasTy<Interner>;
89pub type OpaqueTy = chalk_ir::OpaqueTy<Interner>;
90pub type InferenceVar = chalk_ir::InferenceVar;
91
92pub type Lifetime = chalk_ir::Lifetime<Interner>;
93pub type LifetimeData = chalk_ir::LifetimeData<Interner>;
94pub type LifetimeOutlives = chalk_ir::LifetimeOutlives<Interner>;
95
96pub type Const = chalk_ir::Const<Interner>;
97pub type ConstData = chalk_ir::ConstData<Interner>;
98pub type ConstValue = chalk_ir::ConstValue<Interner>;
99pub type ConcreteConst = chalk_ir::ConcreteConst<Interner>;
71 100
72pub type ChalkTraitId = chalk_ir::TraitId<Interner>; 101pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
73 102pub type TraitRef = chalk_ir::TraitRef<Interner>;
74#[derive(Clone, PartialEq, Eq, Debug, Hash)] 103pub type QuantifiedWhereClause = Binders<WhereClause>;
75pub enum Lifetime { 104pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
76 Parameter(LifetimeParamId), 105pub type Canonical<T> = chalk_ir::Canonical<T>;
77 Static,
78}
79
80#[derive(Clone, PartialEq, Eq, Debug, Hash)]
81pub struct OpaqueTy {
82 pub opaque_ty_id: OpaqueTyId,
83 pub substitution: Substitution,
84}
85
86impl TypeWalk for OpaqueTy {
87 fn walk(&self, f: &mut impl FnMut(&Ty)) {
88 self.substitution.walk(f);
89 }
90
91 fn walk_mut_binders(
92 &mut self,
93 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
94 binders: DebruijnIndex,
95 ) {
96 self.substitution.walk_mut_binders(f, binders);
97 }
98}
99
100/// A "projection" type corresponds to an (unnormalized)
101/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
102/// trait and all its parameters are fully known.
103#[derive(Clone, PartialEq, Eq, Debug, Hash)]
104pub struct ProjectionTy {
105 pub associated_ty_id: AssocTypeId,
106 pub substitution: Substitution,
107}
108
109impl ProjectionTy {
110 pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
111 TraitRef {
112 trait_id: to_chalk_trait_id(self.trait_(db)),
113 substitution: self.substitution.clone(),
114 }
115 }
116
117 pub fn self_type_parameter(&self) -> &Ty {
118 &self.substitution.interned(&Interner)[0].assert_ty_ref(&Interner)
119 }
120
121 fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
122 match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
123 AssocContainerId::TraitId(it) => it,
124 _ => panic!("projection ty without parent trait"),
125 }
126 }
127}
128
129impl TypeWalk for ProjectionTy {
130 fn walk(&self, f: &mut impl FnMut(&Ty)) {
131 self.substitution.walk(f);
132 }
133
134 fn walk_mut_binders(
135 &mut self,
136 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
137 binders: DebruijnIndex,
138 ) {
139 self.substitution.walk_mut_binders(f, binders);
140 }
141}
142
143#[derive(Clone, PartialEq, Eq, Debug, Hash)]
144pub struct DynTy {
145 /// The unknown self type.
146 pub bounds: Binders<QuantifiedWhereClauses>,
147}
148 106
149pub type FnSig = chalk_ir::FnSig<Interner>; 107pub type FnSig = chalk_ir::FnSig<Interner>;
150 108
151#[derive(Clone, PartialEq, Eq, Debug, Hash)] 109pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
152pub struct FnPointer { 110pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
153 pub num_args: usize, 111pub type AliasEq = chalk_ir::AliasEq<Interner>;
154 pub sig: FnSig, 112pub type Solution = chalk_solve::Solution<Interner>;
155 pub substs: Substitution, 113pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
156} 114pub type Guidance = chalk_solve::Guidance<Interner>;
157 115pub type WhereClause = chalk_ir::WhereClause<Interner>;
158#[derive(Clone, PartialEq, Eq, Debug, Hash)]
159pub enum AliasTy {
160 /// A "projection" type corresponds to an (unnormalized)
161 /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
162 /// trait and all its parameters are fully known.
163 Projection(ProjectionTy),
164 /// An opaque type (`impl Trait`).
165 ///
166 /// This is currently only used for return type impl trait; each instance of
167 /// `impl Trait` in a return type gets its own ID.
168 Opaque(OpaqueTy),
169}
170
171impl TypeWalk for AliasTy {
172 fn walk(&self, f: &mut impl FnMut(&Ty)) {
173 match self {
174 AliasTy::Projection(it) => it.walk(f),
175 AliasTy::Opaque(it) => it.walk(f),
176 }
177 }
178 116
179 fn walk_mut_binders( 117// FIXME: get rid of this
180 &mut self, 118pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
181 f: &mut impl FnMut(&mut Ty, DebruijnIndex), 119 Substitution::from_iter(
182 binders: DebruijnIndex, 120 &Interner,
183 ) { 121 s.as_slice(&Interner)[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
184 match self { 122 )
185 AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
186 AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
187 }
188 }
189}
190/// A type.
191///
192/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
193/// the same thing (but in a different way).
194///
195/// This should be cheap to clone.
196#[derive(Clone, PartialEq, Eq, Debug, Hash)]
197pub enum TyKind {
198 /// Structures, enumerations and unions.
199 Adt(AdtId<Interner>, Substitution),
200
201 /// Represents an associated item like `Iterator::Item`. This is used
202 /// when we have tried to normalize a projection like `T::Item` but
203 /// couldn't find a better representation. In that case, we generate
204 /// an **application type** like `(Iterator::Item)<T>`.
205 AssociatedType(AssocTypeId, Substitution),
206
207 /// a scalar type like `bool` or `u32`
208 Scalar(Scalar),
209
210 /// A tuple type. For example, `(i32, bool)`.
211 Tuple(usize, Substitution),
212
213 /// An array with the given length. Written as `[T; n]`.
214 Array(Ty),
215
216 /// The pointee of an array slice. Written as `[T]`.
217 Slice(Ty),
218
219 /// A raw pointer. Written as `*mut T` or `*const T`
220 Raw(Mutability, Ty),
221
222 /// A reference; a pointer with an associated lifetime. Written as
223 /// `&'a mut T` or `&'a T`.
224 Ref(Mutability, Ty),
225
226 /// This represents a placeholder for an opaque type in situations where we
227 /// don't know the hidden type (i.e. currently almost always). This is
228 /// analogous to the `AssociatedType` type constructor.
229 /// It is also used as the type of async block, with one type parameter
230 /// representing the Future::Output type.
231 OpaqueType(OpaqueTyId, Substitution),
232
233 /// The anonymous type of a function declaration/definition. Each
234 /// function has a unique type, which is output (for a function
235 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
236 ///
237 /// This includes tuple struct / enum variant constructors as well.
238 ///
239 /// For example the type of `bar` here:
240 ///
241 /// ```
242 /// fn foo() -> i32 { 1 }
243 /// let bar = foo; // bar: fn() -> i32 {foo}
244 /// ```
245 FnDef(FnDefId, Substitution),
246
247 /// The pointee of a string slice. Written as `str`.
248 Str,
249
250 /// The never type `!`.
251 Never,
252
253 /// The type of a specific closure.
254 ///
255 /// The closure signature is stored in a `FnPtr` type in the first type
256 /// parameter.
257 Closure(ClosureId, Substitution),
258
259 /// Represents a foreign type declared in external blocks.
260 ForeignType(ForeignDefId),
261
262 /// A pointer to a function. Written as `fn() -> i32`.
263 ///
264 /// For example the type of `bar` here:
265 ///
266 /// ```
267 /// fn foo() -> i32 { 1 }
268 /// let bar: fn() -> i32 = foo;
269 /// ```
270 Function(FnPointer),
271
272 /// An "alias" type represents some form of type alias, such as:
273 /// - An associated type projection like `<T as Iterator>::Item`
274 /// - `impl Trait` types
275 /// - Named type aliases like `type Foo<X> = Vec<X>`
276 Alias(AliasTy),
277
278 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
279 /// {}` when we're type-checking the body of that function. In this
280 /// situation, we know this stands for *some* type, but don't know the exact
281 /// type.
282 Placeholder(PlaceholderIndex),
283
284 /// A bound type variable. This is used in various places: when representing
285 /// some polymorphic type like the type of function `fn f<T>`, the type
286 /// parameters get turned into variables; during trait resolution, inference
287 /// variables get turned into bound variables and back; and in `Dyn` the
288 /// `Self` type is represented with a bound variable as well.
289 BoundVar(BoundVar),
290
291 /// A type variable used during type checking.
292 InferenceVar(InferenceVar, TyVariableKind),
293
294 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
295 ///
296 /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
297 /// represents the `Self` type inside the bounds. This is currently
298 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
299 /// didn't seem worth the overhead yet.
300 Dyn(DynTy),
301
302 /// A placeholder for a type which could not be computed; this is propagated
303 /// to avoid useless error messages. Doubles as a placeholder where type
304 /// variables are inserted before type checking, since we want to try to
305 /// infer a better type here anyway -- for the IDE use case, we want to try
306 /// to infer as much as possible even in the presence of type errors.
307 Unknown,
308}
309
310#[derive(Clone, PartialEq, Eq, Debug, Hash)]
311pub struct Ty(Arc<TyKind>);
312
313impl TyKind {
314 pub fn intern(self, _interner: &Interner) -> Ty {
315 Ty(Arc::new(self))
316 }
317}
318
319impl Ty {
320 pub fn kind(&self, _interner: &Interner) -> &TyKind {
321 &self.0
322 }
323
324 pub fn interned_mut(&mut self) -> &mut TyKind {
325 Arc::make_mut(&mut self.0)
326 }
327
328 pub fn into_inner(self) -> TyKind {
329 Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
330 }
331}
332
333#[derive(Clone, PartialEq, Eq, Debug, Hash)]
334pub struct GenericArg {
335 interned: GenericArgData,
336}
337
338#[derive(Clone, PartialEq, Eq, Debug, Hash)]
339pub enum GenericArgData {
340 Ty(Ty),
341}
342
343impl GenericArg {
344 /// Constructs a generic argument using `GenericArgData`.
345 pub fn new(_interner: &Interner, data: GenericArgData) -> Self {
346 GenericArg { interned: data }
347 }
348
349 /// Gets the interned value.
350 pub fn interned(&self) -> &GenericArgData {
351 &self.interned
352 }
353
354 /// Asserts that this is a type argument.
355 pub fn assert_ty_ref(&self, interner: &Interner) -> &Ty {
356 self.ty(interner).unwrap()
357 }
358
359 /// Checks whether the generic argument is a type.
360 pub fn is_ty(&self, _interner: &Interner) -> bool {
361 match self.interned() {
362 GenericArgData::Ty(_) => true,
363 }
364 }
365
366 /// Returns the type if it is one, `None` otherwise.
367 pub fn ty(&self, _interner: &Interner) -> Option<&Ty> {
368 match self.interned() {
369 GenericArgData::Ty(t) => Some(t),
370 }
371 }
372}
373
374impl TypeWalk for GenericArg {
375 fn walk(&self, f: &mut impl FnMut(&Ty)) {
376 match &self.interned {
377 GenericArgData::Ty(ty) => {
378 ty.walk(f);
379 }
380 }
381 }
382
383 fn walk_mut_binders(
384 &mut self,
385 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
386 binders: DebruijnIndex,
387 ) {
388 match &mut self.interned {
389 GenericArgData::Ty(ty) => {
390 ty.walk_mut_binders(f, binders);
391 }
392 }
393 }
394}
395
396/// A list of substitutions for generic parameters.
397#[derive(Clone, PartialEq, Eq, Debug, Hash)]
398pub struct Substitution(SmallVec<[GenericArg; 2]>);
399
400impl TypeWalk for Substitution {
401 fn walk(&self, f: &mut impl FnMut(&Ty)) {
402 for t in self.0.iter() {
403 t.walk(f);
404 }
405 }
406
407 fn walk_mut_binders(
408 &mut self,
409 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
410 binders: DebruijnIndex,
411 ) {
412 for t in &mut self.0 {
413 t.walk_mut_binders(f, binders);
414 }
415 }
416}
417
418impl Substitution {
419 pub fn interned(&self, _: &Interner) -> &[GenericArg] {
420 &self.0
421 }
422
423 pub fn len(&self, _: &Interner) -> usize {
424 self.0.len()
425 }
426
427 pub fn is_empty(&self, _: &Interner) -> bool {
428 self.0.is_empty()
429 }
430
431 pub fn at(&self, _: &Interner, i: usize) -> &GenericArg {
432 &self.0[i]
433 }
434
435 pub fn empty(_: &Interner) -> Substitution {
436 Substitution(SmallVec::new())
437 }
438
439 pub fn iter(&self, _: &Interner) -> std::slice::Iter<'_, GenericArg> {
440 self.0.iter()
441 }
442
443 pub fn single(ty: Ty) -> Substitution {
444 Substitution({
445 let mut v = SmallVec::new();
446 v.push(ty.cast(&Interner));
447 v
448 })
449 }
450
451 pub fn prefix(&self, n: usize) -> Substitution {
452 Substitution(self.0[..std::cmp::min(self.0.len(), n)].into())
453 }
454
455 pub fn suffix(&self, n: usize) -> Substitution {
456 Substitution(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into())
457 }
458
459 pub fn from_iter(
460 interner: &Interner,
461 elements: impl IntoIterator<Item = impl CastTo<GenericArg>>,
462 ) -> Self {
463 Substitution(elements.into_iter().casted(interner).collect())
464 }
465} 123}
466 124
467/// Return an index of a parameter in the generic type parameter list by it's id. 125/// Return an index of a parameter in the generic type parameter list by it's id.
@@ -469,190 +127,39 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
469 generics(db.upcast(), id.parent).param_idx(id) 127 generics(db.upcast(), id.parent).param_idx(id)
470} 128}
471 129
472#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] 130pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
473pub struct Binders<T> { 131where
474 pub num_binders: usize, 132 T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>,
475 pub value: T, 133{
476} 134 Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE))
477 135}
478impl<T> Binders<T> { 136
479 pub fn new(num_binders: usize, value: T) -> Self { 137pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
480 Self { num_binders, value } 138 num_vars: usize,
481 } 139 value: T,
482 140) -> Binders<T> {
483 pub fn wrap_empty(value: T) -> Self 141 Binders::new(
484 where 142 VariableKinds::from_iter(
485 T: TypeWalk, 143 &Interner,
486 { 144 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
487 Self { num_binders: 0, value: value.shift_bound_vars(DebruijnIndex::ONE) } 145 .take(num_vars),
488 } 146 ),
489 147 value,
490 pub fn as_ref(&self) -> Binders<&T> { 148 )
491 Binders { num_binders: self.num_binders, value: &self.value } 149}
492 } 150
493 151// FIXME: get rid of this
494 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> { 152pub fn make_canonical<T: HasInterner<Interner = Interner>>(
495 Binders { num_binders: self.num_binders, value: f(self.value) } 153 value: T,
496 } 154 kinds: impl IntoIterator<Item = TyVariableKind>,
497 155) -> Canonical<T> {
498 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> { 156 let kinds = kinds.into_iter().map(|tk| {
499 Some(Binders { num_binders: self.num_binders, value: f(self.value)? }) 157 chalk_ir::CanonicalVarKind::new(
500 } 158 chalk_ir::VariableKind::Ty(tk),
501 159 chalk_ir::UniverseIndex::ROOT,
502 pub fn skip_binders(&self) -> &T { 160 )
503 &self.value 161 });
504 } 162 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
505
506 pub fn into_value_and_skipped_binders(self) -> (T, usize) {
507 (self.value, self.num_binders)
508 }
509}
510
511impl<T: Clone> Binders<&T> {
512 pub fn cloned(&self) -> Binders<T> {
513 Binders { num_binders: self.num_binders, value: self.value.clone() }
514 }
515}
516
517impl<T: TypeWalk> Binders<T> {
518 /// Substitutes all variables.
519 pub fn subst(self, subst: &Substitution) -> T {
520 assert_eq!(subst.len(&Interner), self.num_binders);
521 self.value.subst_bound_vars(subst)
522 }
523}
524
525impl<T: TypeWalk> TypeWalk for Binders<T> {
526 fn walk(&self, f: &mut impl FnMut(&Ty)) {
527 self.value.walk(f);
528 }
529
530 fn walk_mut_binders(
531 &mut self,
532 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
533 binders: DebruijnIndex,
534 ) {
535 self.value.walk_mut_binders(f, binders.shifted_in())
536 }
537}
538
539/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
540#[derive(Clone, PartialEq, Eq, Debug, Hash)]
541pub struct TraitRef {
542 pub trait_id: ChalkTraitId,
543 pub substitution: Substitution,
544}
545
546impl TraitRef {
547 pub fn self_type_parameter(&self) -> &Ty {
548 &self.substitution.at(&Interner, 0).assert_ty_ref(&Interner)
549 }
550
551 pub fn hir_trait_id(&self) -> TraitId {
552 from_chalk_trait_id(self.trait_id)
553 }
554}
555
556impl TypeWalk for TraitRef {
557 fn walk(&self, f: &mut impl FnMut(&Ty)) {
558 self.substitution.walk(f);
559 }
560
561 fn walk_mut_binders(
562 &mut self,
563 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
564 binders: DebruijnIndex,
565 ) {
566 self.substitution.walk_mut_binders(f, binders);
567 }
568}
569
570/// Like `generics::WherePredicate`, but with resolved types: A condition on the
571/// parameters of a generic item.
572#[derive(Debug, Clone, PartialEq, Eq, Hash)]
573pub enum WhereClause {
574 /// The given trait needs to be implemented for its type parameters.
575 Implemented(TraitRef),
576 /// An associated type bindings like in `Iterator<Item = T>`.
577 AliasEq(AliasEq),
578}
579
580impl WhereClause {
581 pub fn is_implemented(&self) -> bool {
582 matches!(self, WhereClause::Implemented(_))
583 }
584
585 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
586 match self {
587 WhereClause::Implemented(tr) => Some(tr.clone()),
588 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
589 Some(proj.trait_ref(db))
590 }
591 WhereClause::AliasEq(_) => None,
592 }
593 }
594}
595
596impl TypeWalk for WhereClause {
597 fn walk(&self, f: &mut impl FnMut(&Ty)) {
598 match self {
599 WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
600 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
601 }
602 }
603
604 fn walk_mut_binders(
605 &mut self,
606 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
607 binders: DebruijnIndex,
608 ) {
609 match self {
610 WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
611 WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
612 }
613 }
614}
615
616pub type QuantifiedWhereClause = Binders<WhereClause>;
617
618#[derive(Debug, Clone, PartialEq, Eq, Hash)]
619pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
620
621impl QuantifiedWhereClauses {
622 pub fn from_iter(
623 _interner: &Interner,
624 elements: impl IntoIterator<Item = QuantifiedWhereClause>,
625 ) -> Self {
626 QuantifiedWhereClauses(elements.into_iter().collect())
627 }
628
629 pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
630 &self.0
631 }
632}
633
634/// Basically a claim (currently not validated / checked) that the contained
635/// type / trait ref contains no inference variables; any inference variables it
636/// contained have been replaced by bound variables, and `kinds` tells us how
637/// many there are and whether they were normal or float/int variables. This is
638/// used to erase irrelevant differences between types before using them in
639/// queries.
640#[derive(Debug, Clone, PartialEq, Eq, Hash)]
641pub struct Canonical<T> {
642 pub value: T,
643 pub binders: CanonicalVarKinds,
644}
645
646impl<T> Canonical<T> {
647 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
648 let kinds = kinds.into_iter().map(|tk| {
649 chalk_ir::CanonicalVarKind::new(
650 chalk_ir::VariableKind::Ty(tk),
651 chalk_ir::UniverseIndex::ROOT,
652 )
653 });
654 Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
655 }
656} 163}
657 164
658/// A function signature as seen by type inference: Several parameter types and 165/// A function signature as seen by type inference: Several parameter types and
@@ -663,6 +170,8 @@ pub struct CallableSig {
663 is_varargs: bool, 170 is_varargs: bool,
664} 171}
665 172
173has_interner!(CallableSig);
174
666/// A polymorphic function signature. 175/// A polymorphic function signature.
667pub type PolyFnSig = Binders<CallableSig>; 176pub type PolyFnSig = Binders<CallableSig>;
668 177
@@ -676,10 +185,12 @@ impl CallableSig {
676 CallableSig { 185 CallableSig {
677 // FIXME: what to do about lifetime params? -> return PolyFnSig 186 // FIXME: what to do about lifetime params? -> return PolyFnSig
678 params_and_return: fn_ptr 187 params_and_return: fn_ptr
679 .substs 188 .substitution
680 .clone() 189 .clone()
681 .shift_bound_vars_out(DebruijnIndex::ONE) 190 .shifted_out_to(&Interner, DebruijnIndex::ONE)
682 .interned(&Interner) 191 .expect("unexpected lifetime vars in fn ptr")
192 .0
193 .as_slice(&Interner)
683 .iter() 194 .iter()
684 .map(|arg| arg.assert_ty_ref(&Interner).clone()) 195 .map(|arg| arg.assert_ty_ref(&Interner).clone())
685 .collect(), 196 .collect(),
@@ -696,485 +207,20 @@ impl CallableSig {
696 } 207 }
697} 208}
698 209
699impl TypeWalk for CallableSig { 210impl Fold<Interner> for CallableSig {
700 fn walk(&self, f: &mut impl FnMut(&Ty)) { 211 type Result = CallableSig;
701 for t in self.params_and_return.iter() {
702 t.walk(f);
703 }
704 }
705
706 fn walk_mut_binders(
707 &mut self,
708 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
709 binders: DebruijnIndex,
710 ) {
711 for t in make_mut_slice(&mut self.params_and_return) {
712 t.walk_mut_binders(f, binders);
713 }
714 }
715}
716
717impl Ty {
718 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
719 match self.kind(&Interner) {
720 TyKind::Ref(mutability, ty) => Some((ty, *mutability)),
721 _ => None,
722 }
723 }
724
725 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
726 match self.kind(&Interner) {
727 TyKind::Ref(mutability, ty) => Some((ty, Rawness::Ref, *mutability)),
728 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
729 _ => None,
730 }
731 }
732
733 pub fn strip_references(&self) -> &Ty {
734 let mut t: &Ty = self;
735
736 while let TyKind::Ref(_mutability, ty) = t.kind(&Interner) {
737 t = ty;
738 }
739
740 t
741 }
742
743 pub fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
744 match self.kind(&Interner) {
745 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
746 _ => None,
747 }
748 }
749
750 pub fn as_tuple(&self) -> Option<&Substitution> {
751 match self.kind(&Interner) {
752 TyKind::Tuple(_, substs) => Some(substs),
753 _ => None,
754 }
755 }
756
757 pub fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> {
758 match *self.kind(&Interner) {
759 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()),
760 TyKind::FnDef(callable, ..) => {
761 Some(db.lookup_intern_callable_def(callable.into()).into())
762 }
763 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
764 TyKind::ForeignType(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
765 _ => None,
766 }
767 }
768
769 pub fn is_never(&self) -> bool {
770 matches!(self.kind(&Interner), TyKind::Never)
771 }
772
773 pub fn is_unknown(&self) -> bool {
774 matches!(self.kind(&Interner), TyKind::Unknown)
775 }
776
777 pub fn equals_ctor(&self, other: &Ty) -> bool {
778 match (self.kind(&Interner), other.kind(&Interner)) {
779 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
780 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_), TyKind::Array(_)) => true,
781 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
782 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
783 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
784 ty_id == ty_id2
785 }
786 (TyKind::ForeignType(ty_id, ..), TyKind::ForeignType(ty_id2, ..)) => ty_id == ty_id2,
787 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
788 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
789 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
790 mutability == mutability2
791 }
792 (
793 TyKind::Function(FnPointer { num_args, sig, .. }),
794 TyKind::Function(FnPointer { num_args: num_args2, sig: sig2, .. }),
795 ) => num_args == num_args2 && sig == sig2,
796 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
797 cardinality == cardinality2
798 }
799 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
800 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
801 _ => false,
802 }
803 }
804
805 /// If this is a `dyn Trait` type, this returns the `Trait` part.
806 fn dyn_trait_ref(&self) -> Option<&TraitRef> {
807 match self.kind(&Interner) {
808 TyKind::Dyn(dyn_ty) => {
809 dyn_ty.bounds.value.interned().get(0).and_then(|b| match b.skip_binders() {
810 WhereClause::Implemented(trait_ref) => Some(trait_ref),
811 _ => None,
812 })
813 }
814 _ => None,
815 }
816 }
817
818 /// If this is a `dyn Trait`, returns that trait.
819 pub fn dyn_trait(&self) -> Option<TraitId> {
820 self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
821 }
822
823 fn builtin_deref(&self) -> Option<Ty> {
824 match self.kind(&Interner) {
825 TyKind::Ref(.., ty) => Some(ty.clone()),
826 TyKind::Raw(.., ty) => Some(ty.clone()),
827 _ => None,
828 }
829 }
830
831 pub fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
832 match self.kind(&Interner) {
833 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
834 _ => None,
835 }
836 }
837
838 pub fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
839 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
840 Some(func)
841 } else {
842 None
843 }
844 }
845
846 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
847 match self.kind(&Interner) {
848 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
849 TyKind::FnDef(def, parameters) => {
850 let callable_def = db.lookup_intern_callable_def((*def).into());
851 let sig = db.callable_item_signature(callable_def);
852 Some(sig.subst(&parameters))
853 }
854 TyKind::Closure(.., substs) => {
855 let sig_param = substs.at(&Interner, 0).assert_ty_ref(&Interner);
856 sig_param.callable_sig(db)
857 }
858 _ => None,
859 }
860 }
861
862 /// Returns the type parameters of this type if it has some (i.e. is an ADT
863 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
864 pub fn substs(&self) -> Option<&Substitution> {
865 match self.kind(&Interner) {
866 TyKind::Adt(_, substs)
867 | TyKind::FnDef(_, substs)
868 | TyKind::Function(FnPointer { substs, .. })
869 | TyKind::Tuple(_, substs)
870 | TyKind::OpaqueType(_, substs)
871 | TyKind::AssociatedType(_, substs)
872 | TyKind::Closure(.., substs) => Some(substs),
873 _ => None,
874 }
875 }
876
877 fn substs_mut(&mut self) -> Option<&mut Substitution> {
878 match self.interned_mut() {
879 TyKind::Adt(_, substs)
880 | TyKind::FnDef(_, substs)
881 | TyKind::Function(FnPointer { substs, .. })
882 | TyKind::Tuple(_, substs)
883 | TyKind::OpaqueType(_, substs)
884 | TyKind::AssociatedType(_, substs)
885 | TyKind::Closure(.., substs) => Some(substs),
886 _ => None,
887 }
888 }
889
890 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
891 match self.kind(&Interner) {
892 TyKind::OpaqueType(opaque_ty_id, ..) => {
893 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
894 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
895 let krate = def.module(db.upcast()).krate();
896 if let Some(future_trait) = db
897 .lang_item(krate, "future_trait".into())
898 .and_then(|item| item.as_trait())
899 {
900 // This is only used by type walking.
901 // Parameters will be walked outside, and projection predicate is not used.
902 // So just provide the Future trait.
903 let impl_bound = Binders::new(
904 0,
905 WhereClause::Implemented(TraitRef {
906 trait_id: to_chalk_trait_id(future_trait),
907 substitution: Substitution::empty(&Interner),
908 }),
909 );
910 Some(vec![impl_bound])
911 } else {
912 None
913 }
914 }
915 ImplTraitId::ReturnTypeImplTrait(..) => None,
916 }
917 }
918 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
919 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
920 {
921 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
922 db.return_type_impl_traits(func).map(|it| {
923 let data = (*it)
924 .as_ref()
925 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
926 data.subst(&opaque_ty.substitution)
927 })
928 }
929 // It always has an parameter for Future::Output type.
930 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
931 };
932
933 predicates.map(|it| it.value)
934 }
935 TyKind::Placeholder(idx) => {
936 let id = from_placeholder_idx(db, *idx);
937 let generic_params = db.generic_params(id.parent);
938 let param_data = &generic_params.types[id.local_id];
939 match param_data.provenance {
940 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
941 let substs = TyBuilder::type_params_subst(db, id.parent);
942 let predicates = db
943 .generic_predicates(id.parent)
944 .into_iter()
945 .map(|pred| pred.clone().subst(&substs))
946 .filter(|wc| match &wc.skip_binders() {
947 WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
948 WhereClause::AliasEq(AliasEq {
949 alias: AliasTy::Projection(proj),
950 ty: _,
951 }) => proj.self_type_parameter() == self,
952 _ => false,
953 })
954 .collect_vec();
955
956 Some(predicates)
957 }
958 _ => None,
959 }
960 }
961 _ => None,
962 }
963 }
964
965 pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
966 match self.kind(&Interner) {
967 TyKind::AssociatedType(id, ..) => {
968 match from_assoc_type_id(*id).lookup(db.upcast()).container {
969 AssocContainerId::TraitId(trait_id) => Some(trait_id),
970 _ => None,
971 }
972 }
973 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
974 match from_assoc_type_id(projection_ty.associated_ty_id)
975 .lookup(db.upcast())
976 .container
977 {
978 AssocContainerId::TraitId(trait_id) => Some(trait_id),
979 _ => None,
980 }
981 }
982 _ => None,
983 }
984 }
985}
986
987/// This allows walking structures that contain types to do something with those
988/// types, similar to Chalk's `Fold` trait.
989pub trait TypeWalk {
990 fn walk(&self, f: &mut impl FnMut(&Ty));
991 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
992 self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
993 }
994 /// Walk the type, counting entered binders.
995 ///
996 /// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
997 /// to the innermost binder, 1 to the next, etc.. So when we want to
998 /// substitute a certain bound variable, we can't just walk the whole type
999 /// and blindly replace each instance of a certain index; when we 'enter'
1000 /// things that introduce new bound variables, we have to keep track of
1001 /// that. Currently, the only thing that introduces bound variables on our
1002 /// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
1003 /// variable for the self type.
1004 fn walk_mut_binders(
1005 &mut self,
1006 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1007 binders: DebruijnIndex,
1008 );
1009
1010 fn fold_binders(
1011 mut self,
1012 f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
1013 binders: DebruijnIndex,
1014 ) -> Self
1015 where
1016 Self: Sized,
1017 {
1018 self.walk_mut_binders(
1019 &mut |ty_mut, binders| {
1020 let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
1021 *ty_mut = f(ty, binders);
1022 },
1023 binders,
1024 );
1025 self
1026 }
1027
1028 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
1029 where
1030 Self: Sized,
1031 {
1032 self.walk_mut(&mut |ty_mut| {
1033 let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
1034 *ty_mut = f(ty);
1035 });
1036 self
1037 }
1038 212
1039 /// Substitutes `TyKind::Bound` vars with the given substitution. 213 fn fold_with<'i>(
1040 fn subst_bound_vars(self, substs: &Substitution) -> Self 214 self,
215 folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>,
216 outer_binder: DebruijnIndex,
217 ) -> chalk_ir::Fallible<Self::Result>
1041 where 218 where
1042 Self: Sized, 219 Interner: 'i,
1043 { 220 {
1044 self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST) 221 let vec = self.params_and_return.to_vec();
1045 } 222 let folded = vec.fold_with(folder, outer_binder)?;
1046 223 Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
1047 /// Substitutes `TyKind::Bound` vars with the given substitution.
1048 fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
1049 where
1050 Self: Sized,
1051 {
1052 self.walk_mut_binders(
1053 &mut |ty, binders| {
1054 if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
1055 if bound.debruijn >= binders {
1056 *ty = substs.0[bound.index]
1057 .assert_ty_ref(&Interner)
1058 .clone()
1059 .shift_bound_vars(binders);
1060 }
1061 }
1062 },
1063 depth,
1064 );
1065 self
1066 }
1067
1068 /// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
1069 fn shift_bound_vars(self, n: DebruijnIndex) -> Self
1070 where
1071 Self: Sized,
1072 {
1073 self.fold_binders(
1074 &mut |ty, binders| match ty.kind(&Interner) {
1075 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
1076 TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
1077 }
1078 _ => ty,
1079 },
1080 DebruijnIndex::INNERMOST,
1081 )
1082 }
1083
1084 /// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
1085 fn shift_bound_vars_out(self, n: DebruijnIndex) -> Self
1086 where
1087 Self: Sized + std::fmt::Debug,
1088 {
1089 self.fold_binders(
1090 &mut |ty, binders| match ty.kind(&Interner) {
1091 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
1092 TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
1093 .intern(&Interner)
1094 }
1095 _ => ty,
1096 },
1097 DebruijnIndex::INNERMOST,
1098 )
1099 }
1100}
1101
1102impl TypeWalk for Ty {
1103 fn walk(&self, f: &mut impl FnMut(&Ty)) {
1104 match self.kind(&Interner) {
1105 TyKind::Alias(AliasTy::Projection(p_ty)) => {
1106 for t in p_ty.substitution.iter(&Interner) {
1107 t.walk(f);
1108 }
1109 }
1110 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
1111 for t in o_ty.substitution.iter(&Interner) {
1112 t.walk(f);
1113 }
1114 }
1115 TyKind::Dyn(dyn_ty) => {
1116 for p in dyn_ty.bounds.value.interned().iter() {
1117 p.walk(f);
1118 }
1119 }
1120 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
1121 ty.walk(f);
1122 }
1123 _ => {
1124 if let Some(substs) = self.substs() {
1125 for t in substs.iter(&Interner) {
1126 t.walk(f);
1127 }
1128 }
1129 }
1130 }
1131 f(self);
1132 }
1133
1134 fn walk_mut_binders(
1135 &mut self,
1136 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1137 binders: DebruijnIndex,
1138 ) {
1139 match self.interned_mut() {
1140 TyKind::Alias(AliasTy::Projection(p_ty)) => {
1141 p_ty.substitution.walk_mut_binders(f, binders);
1142 }
1143 TyKind::Dyn(dyn_ty) => {
1144 for p in make_mut_slice(&mut dyn_ty.bounds.value.0) {
1145 p.walk_mut_binders(f, binders.shifted_in());
1146 }
1147 }
1148 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
1149 o_ty.substitution.walk_mut_binders(f, binders);
1150 }
1151 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
1152 ty.walk_mut_binders(f, binders);
1153 }
1154 _ => {
1155 if let Some(substs) = self.substs_mut() {
1156 substs.walk_mut_binders(f, binders);
1157 }
1158 }
1159 }
1160 f(self, binders);
1161 }
1162}
1163
1164impl<T: TypeWalk> TypeWalk for Vec<T> {
1165 fn walk(&self, f: &mut impl FnMut(&Ty)) {
1166 for t in self {
1167 t.walk(f);
1168 }
1169 }
1170 fn walk_mut_binders(
1171 &mut self,
1172 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1173 binders: DebruijnIndex,
1174 ) {
1175 for t in self {
1176 t.walk_mut_binders(f, binders);
1177 }
1178 } 224 }
1179} 225}
1180 226
@@ -1189,45 +235,75 @@ pub struct ReturnTypeImplTraits {
1189 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, 235 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
1190} 236}
1191 237
238has_interner!(ReturnTypeImplTraits);
239
1192#[derive(Clone, PartialEq, Eq, Debug, Hash)] 240#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1193pub(crate) struct ReturnTypeImplTrait { 241pub(crate) struct ReturnTypeImplTrait {
1194 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>, 242 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
1195} 243}
1196 244
1197pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { 245pub fn static_lifetime() -> Lifetime {
1198 chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id)) 246 LifetimeData::Static.intern(&Interner)
1199}
1200
1201pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
1202 salsa::InternKey::from_intern_id(id.0)
1203} 247}
1204 248
1205pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId { 249pub fn dummy_usize_const() -> Const {
1206 chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id)) 250 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
251 chalk_ir::ConstData {
252 ty: usize_ty,
253 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
254 }
255 .intern(&Interner)
1207} 256}
1208 257
1209pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId { 258pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
1210 salsa::InternKey::from_intern_id(id.0) 259 t: T,
1211} 260 f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
261) -> T::Result {
262 use chalk_ir::{fold::Folder, Fallible};
263 struct FreeVarFolder<F>(F);
264 impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for FreeVarFolder<F> {
265 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
266 self
267 }
1212 268
1213pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId { 269 fn interner(&self) -> &'i Interner {
1214 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); 270 &Interner
1215 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); 271 }
1216 db.lookup_intern_type_param_id(interned_id)
1217}
1218 272
1219pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex { 273 fn fold_free_var_ty(
1220 let interned_id = db.intern_type_param_id(id); 274 &mut self,
1221 PlaceholderIndex { 275 bound_var: BoundVar,
1222 ui: chalk_ir::UniverseIndex::ROOT, 276 outer_binder: DebruijnIndex,
1223 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(), 277 ) -> Fallible<Ty> {
278 Ok(self.0(bound_var, outer_binder))
279 }
1224 } 280 }
281 t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
1225} 282}
1226 283
1227pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { 284pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
1228 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id)) 285 t: T,
1229} 286 f: impl FnMut(Ty, DebruijnIndex) -> Ty,
287 binders: DebruijnIndex,
288) -> T::Result {
289 use chalk_ir::{
290 fold::{Folder, SuperFold},
291 Fallible,
292 };
293 struct TyFolder<F>(F);
294 impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<'i, Interner> for TyFolder<F> {
295 fn as_dyn(&mut self) -> &mut dyn Folder<'i, Interner> {
296 self
297 }
298
299 fn interner(&self) -> &'i Interner {
300 &Interner
301 }
1230 302
1231pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { 303 fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
1232 salsa::InternKey::from_intern_id(id.0) 304 let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
305 Ok(self.0(ty, outer_binder))
306 }
307 }
308 t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
1233} 309}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 214655807..7fd46becd 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -5,12 +5,14 @@
5//! - Building the type for an item: This happens through the `type_for_def` query. 5//! - Building the type for an item: This happens through the `type_for_def` query.
6//! 6//!
7//! This usually involves resolving names, collecting generic arguments etc. 7//! This usually involves resolving names, collecting generic arguments etc.
8use std::cell::{Cell, RefCell};
8use std::{iter, sync::Arc}; 9use std::{iter, sync::Arc};
9 10
10use base_db::CrateId; 11use base_db::CrateId;
11use chalk_ir::{cast::Cast, Mutability, Safety}; 12use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
12use hir_def::{ 13use hir_def::{
13 adt::StructKind, 14 adt::StructKind,
15 body::{Expander, LowerCtx},
14 builtin_type::BuiltinType, 16 builtin_type::BuiltinType,
15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, 17 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
16 path::{GenericArg, Path, PathSegment, PathSegments}, 18 path::{GenericArg, Path, PathSegment, PathSegments},
@@ -20,23 +22,24 @@ use hir_def::{
20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, 22 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
21 TypeAliasId, TypeParamId, UnionId, VariantId, 23 TypeAliasId, TypeParamId, UnionId, VariantId,
22}; 24};
23use hir_expand::name::Name; 25use hir_expand::{name::Name, ExpandResult};
24use la_arena::ArenaMap; 26use la_arena::ArenaMap;
25use smallvec::SmallVec; 27use smallvec::SmallVec;
26use stdx::impl_from; 28use stdx::impl_from;
29use syntax::ast;
27 30
28use crate::{ 31use crate::{
29 db::HirDatabase, 32 db::HirDatabase,
30 to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, 33 dummy_usize_const,
31 traits::chalk::{Interner, ToChalk}, 34 mapping::ToChalk,
35 static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
32 utils::{ 36 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 37 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
34 variant_data,
35 }, 38 },
36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 39 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, 40 FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
38 ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, 41 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
39 TyBuilder, TyKind, TypeWalk, WhereClause, 42 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
40}; 43};
41 44
42#[derive(Debug)] 45#[derive(Debug)]
@@ -50,7 +53,7 @@ pub struct TyLoweringContext<'a> {
50 /// possible currently, so this should be fine for now. 53 /// possible currently, so this should be fine for now.
51 pub type_param_mode: TypeParamLoweringMode, 54 pub type_param_mode: TypeParamLoweringMode,
52 pub impl_trait_mode: ImplTraitLoweringMode, 55 pub impl_trait_mode: ImplTraitLoweringMode,
53 impl_trait_counter: std::cell::Cell<u16>, 56 impl_trait_counter: Cell<u16>,
54 /// When turning `impl Trait` into opaque types, we have to collect the 57 /// When turning `impl Trait` into opaque types, we have to collect the
55 /// bounds at the same time to get the IDs correct (without becoming too 58 /// bounds at the same time to get the IDs correct (without becoming too
56 /// complicated). I don't like using interior mutability (as for the 59 /// complicated). I don't like using interior mutability (as for the
@@ -59,16 +62,17 @@ pub struct TyLoweringContext<'a> {
59 /// we're grouping the mutable data (the counter and this field) together 62 /// we're grouping the mutable data (the counter and this field) together
60 /// with the immutable context (the references to the DB and resolver). 63 /// with the immutable context (the references to the DB and resolver).
61 /// Splitting this up would be a possible fix. 64 /// Splitting this up would be a possible fix.
62 opaque_type_data: std::cell::RefCell<Vec<ReturnTypeImplTrait>>, 65 opaque_type_data: RefCell<Vec<ReturnTypeImplTrait>>,
66 expander: RefCell<Option<Expander>>,
63} 67}
64 68
65impl<'a> TyLoweringContext<'a> { 69impl<'a> TyLoweringContext<'a> {
66 pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self { 70 pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
67 let impl_trait_counter = std::cell::Cell::new(0); 71 let impl_trait_counter = Cell::new(0);
68 let impl_trait_mode = ImplTraitLoweringMode::Disallowed; 72 let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
69 let type_param_mode = TypeParamLoweringMode::Placeholder; 73 let type_param_mode = TypeParamLoweringMode::Placeholder;
70 let in_binders = DebruijnIndex::INNERMOST; 74 let in_binders = DebruijnIndex::INNERMOST;
71 let opaque_type_data = std::cell::RefCell::new(Vec::new()); 75 let opaque_type_data = RefCell::new(Vec::new());
72 Self { 76 Self {
73 db, 77 db,
74 resolver, 78 resolver,
@@ -77,6 +81,7 @@ impl<'a> TyLoweringContext<'a> {
77 impl_trait_counter, 81 impl_trait_counter,
78 type_param_mode, 82 type_param_mode,
79 opaque_type_data, 83 opaque_type_data,
84 expander: RefCell::new(None),
80 } 85 }
81 } 86 }
82 87
@@ -86,15 +91,18 @@ impl<'a> TyLoweringContext<'a> {
86 f: impl FnOnce(&TyLoweringContext) -> T, 91 f: impl FnOnce(&TyLoweringContext) -> T,
87 ) -> T { 92 ) -> T {
88 let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new()); 93 let opaque_ty_data_vec = self.opaque_type_data.replace(Vec::new());
94 let expander = self.expander.replace(None);
89 let new_ctx = Self { 95 let new_ctx = Self {
90 in_binders: debruijn, 96 in_binders: debruijn,
91 impl_trait_counter: std::cell::Cell::new(self.impl_trait_counter.get()), 97 impl_trait_counter: Cell::new(self.impl_trait_counter.get()),
92 opaque_type_data: std::cell::RefCell::new(opaque_ty_data_vec), 98 opaque_type_data: RefCell::new(opaque_ty_data_vec),
99 expander: RefCell::new(expander),
93 ..*self 100 ..*self
94 }; 101 };
95 let result = f(&new_ctx); 102 let result = f(&new_ctx);
96 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get()); 103 self.impl_trait_counter.set(new_ctx.impl_trait_counter.get());
97 self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner()); 104 self.opaque_type_data.replace(new_ctx.opaque_type_data.into_inner());
105 self.expander.replace(new_ctx.expander.into_inner());
98 result 106 result
99 } 107 }
100 108
@@ -166,7 +174,7 @@ impl<'a> TyLoweringContext<'a> {
166 } 174 }
167 TypeRef::Array(inner) => { 175 TypeRef::Array(inner) => {
168 let inner_ty = self.lower_ty(inner); 176 let inner_ty = self.lower_ty(inner);
169 TyKind::Array(inner_ty).intern(&Interner) 177 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
170 } 178 }
171 TypeRef::Slice(inner) => { 179 TypeRef::Slice(inner) => {
172 let inner_ty = self.lower_ty(inner); 180 let inner_ty = self.lower_ty(inner);
@@ -174,16 +182,19 @@ impl<'a> TyLoweringContext<'a> {
174 } 182 }
175 TypeRef::Reference(inner, _, mutability) => { 183 TypeRef::Reference(inner, _, mutability) => {
176 let inner_ty = self.lower_ty(inner); 184 let inner_ty = self.lower_ty(inner);
177 TyKind::Ref(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner) 185 let lifetime = static_lifetime();
186 TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
187 .intern(&Interner)
178 } 188 }
179 TypeRef::Placeholder => TyKind::Unknown.intern(&Interner), 189 TypeRef::Placeholder => TyKind::Error.intern(&Interner),
180 TypeRef::Fn(params, is_varargs) => { 190 TypeRef::Fn(params, is_varargs) => {
181 let substs = 191 let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
182 Substitution::from_iter(&Interner, params.iter().map(|tr| self.lower_ty(tr))); 192 Substitution::from_iter(&Interner, params.iter().map(|tr| ctx.lower_ty(tr)))
193 });
183 TyKind::Function(FnPointer { 194 TyKind::Function(FnPointer {
184 num_args: substs.len(&Interner) - 1, 195 num_binders: 0, // FIXME lower `for<'a> fn()` correctly
185 sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs }, 196 sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
186 substs, 197 substitution: FnSubst(substs),
187 }) 198 })
188 .intern(&Interner) 199 .intern(&Interner)
189 } 200 }
@@ -196,8 +207,8 @@ impl<'a> TyLoweringContext<'a> {
196 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), 207 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
197 ) 208 )
198 }); 209 });
199 let bounds = Binders::new(1, bounds); 210 let bounds = crate::make_only_type_binders(1, bounds);
200 TyKind::Dyn(DynTy { bounds }).intern(&Interner) 211 TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(&Interner)
201 } 212 }
202 TypeRef::ImplTrait(bounds) => { 213 TypeRef::ImplTrait(bounds) => {
203 match self.impl_trait_mode { 214 match self.impl_trait_mode {
@@ -209,9 +220,9 @@ impl<'a> TyLoweringContext<'a> {
209 // this dance is to make sure the data is in the right 220 // this dance is to make sure the data is in the right
210 // place even if we encounter more opaque types while 221 // place even if we encounter more opaque types while
211 // lowering the bounds 222 // lowering the bounds
212 self.opaque_type_data 223 self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
213 .borrow_mut() 224 bounds: crate::make_only_type_binders(1, Vec::new()),
214 .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); 225 });
215 // We don't want to lower the bounds inside the binders 226 // We don't want to lower the bounds inside the binders
216 // we're currently in, because they don't end up inside 227 // we're currently in, because they don't end up inside
217 // those binders. E.g. when we have `impl Trait<impl 228 // those binders. E.g. when we have `impl Trait<impl
@@ -253,12 +264,12 @@ impl<'a> TyLoweringContext<'a> {
253 data.provenance == TypeParamProvenance::ArgumentImplTrait 264 data.provenance == TypeParamProvenance::ArgumentImplTrait
254 }) 265 })
255 .nth(idx as usize) 266 .nth(idx as usize)
256 .map_or(TyKind::Unknown, |(id, _)| { 267 .map_or(TyKind::Error, |(id, _)| {
257 TyKind::Placeholder(to_placeholder_idx(self.db, id)) 268 TyKind::Placeholder(to_placeholder_idx(self.db, id))
258 }); 269 });
259 param.intern(&Interner) 270 param.intern(&Interner)
260 } else { 271 } else {
261 TyKind::Unknown.intern(&Interner) 272 TyKind::Error.intern(&Interner)
262 } 273 }
263 } 274 }
264 ImplTraitLoweringMode::Variable => { 275 ImplTraitLoweringMode::Variable => {
@@ -280,11 +291,58 @@ impl<'a> TyLoweringContext<'a> {
280 } 291 }
281 ImplTraitLoweringMode::Disallowed => { 292 ImplTraitLoweringMode::Disallowed => {
282 // FIXME: report error 293 // FIXME: report error
283 TyKind::Unknown.intern(&Interner) 294 TyKind::Error.intern(&Interner)
295 }
296 }
297 }
298 TypeRef::Macro(macro_call) => {
299 let (expander, recursion_start) = {
300 let mut expander = self.expander.borrow_mut();
301 if expander.is_some() {
302 (Some(expander), false)
303 } else {
304 if let Some(module_id) = self.resolver.module() {
305 *expander = Some(Expander::new(
306 self.db.upcast(),
307 macro_call.file_id,
308 module_id,
309 ));
310 (Some(expander), true)
311 } else {
312 (None, false)
313 }
284 } 314 }
315 };
316 let ty = if let Some(mut expander) = expander {
317 let expander_mut = expander.as_mut().unwrap();
318 let macro_call = macro_call.to_node(self.db.upcast());
319 match expander_mut.enter_expand::<ast::Type>(self.db.upcast(), macro_call) {
320 Ok(ExpandResult { value: Some((mark, expanded)), .. }) => {
321 let ctx =
322 LowerCtx::new(self.db.upcast(), expander_mut.current_file_id());
323 let type_ref = TypeRef::from_ast(&ctx, expanded);
324
325 drop(expander);
326 let ty = self.lower_ty(&type_ref);
327
328 self.expander
329 .borrow_mut()
330 .as_mut()
331 .unwrap()
332 .exit(self.db.upcast(), mark);
333 Some(ty)
334 }
335 _ => None,
336 }
337 } else {
338 None
339 };
340 if recursion_start {
341 *self.expander.borrow_mut() = None;
285 } 342 }
343 ty.unwrap_or_else(|| TyKind::Error.intern(&Interner))
286 } 344 }
287 TypeRef::Error => TyKind::Unknown.intern(&Interner), 345 TypeRef::Error => TyKind::Error.intern(&Interner),
288 }; 346 };
289 (ty, res) 347 (ty, res)
290 } 348 }
@@ -328,7 +386,7 @@ impl<'a> TyLoweringContext<'a> {
328 (self.select_associated_type(res, segment), None) 386 (self.select_associated_type(res, segment), None)
329 } else if remaining_segments.len() > 1 { 387 } else if remaining_segments.len() > 1 {
330 // FIXME report error (ambiguous associated type) 388 // FIXME report error (ambiguous associated type)
331 (TyKind::Unknown.intern(&Interner), None) 389 (TyKind::Error.intern(&Interner), None)
332 } else { 390 } else {
333 (ty, res) 391 (ty, res)
334 } 392 }
@@ -372,21 +430,24 @@ impl<'a> TyLoweringContext<'a> {
372 } 430 }
373 None => { 431 None => {
374 // FIXME: report error (associated type not found) 432 // FIXME: report error (associated type not found)
375 TyKind::Unknown.intern(&Interner) 433 TyKind::Error.intern(&Interner)
376 } 434 }
377 } 435 }
378 } else if remaining_segments.len() > 1 { 436 } else if remaining_segments.len() > 1 {
379 // FIXME report error (ambiguous associated type) 437 // FIXME report error (ambiguous associated type)
380 TyKind::Unknown.intern(&Interner) 438 TyKind::Error.intern(&Interner)
381 } else { 439 } else {
382 let dyn_ty = DynTy { 440 let dyn_ty = DynTy {
383 bounds: Binders::new( 441 bounds: crate::make_only_type_binders(
384 1, 442 1,
385 QuantifiedWhereClauses::from_iter( 443 QuantifiedWhereClauses::from_iter(
386 &Interner, 444 &Interner,
387 Some(Binders::wrap_empty(WhereClause::Implemented(trait_ref))), 445 Some(crate::wrap_empty_binders(WhereClause::Implemented(
446 trait_ref,
447 ))),
388 ), 448 ),
389 ), 449 ),
450 lifetime: static_lifetime(),
390 }; 451 };
391 TyKind::Dyn(dyn_ty).intern(&Interner) 452 TyKind::Dyn(dyn_ty).intern(&Interner)
392 }; 453 };
@@ -414,7 +475,7 @@ impl<'a> TyLoweringContext<'a> {
414 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), 475 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
415 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), 476 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
416 }; 477 };
417 self.db.impl_self_ty(impl_id).subst(&substs) 478 self.db.impl_self_ty(impl_id).substitute(&Interner, &substs)
418 } 479 }
419 TypeNs::AdtSelfType(adt) => { 480 TypeNs::AdtSelfType(adt) => {
420 let generics = generics(self.db.upcast(), adt.into()); 481 let generics = generics(self.db.upcast(), adt.into());
@@ -422,7 +483,7 @@ impl<'a> TyLoweringContext<'a> {
422 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db), 483 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
423 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders), 484 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
424 }; 485 };
425 self.db.ty(adt.into()).subst(&substs) 486 self.db.ty(adt.into()).substitute(&Interner, &substs)
426 } 487 }
427 488
428 TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), 489 TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
@@ -433,7 +494,7 @@ impl<'a> TyLoweringContext<'a> {
433 self.lower_path_inner(resolved_segment, it.into(), infer_args) 494 self.lower_path_inner(resolved_segment, it.into(), infer_args)
434 } 495 }
435 // FIXME: report error 496 // FIXME: report error
436 TypeNs::EnumVariantId(_) => return (TyKind::Unknown.intern(&Interner), None), 497 TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(&Interner), None),
437 }; 498 };
438 self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) 499 self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
439 } 500 }
@@ -447,7 +508,7 @@ impl<'a> TyLoweringContext<'a> {
447 let (resolution, remaining_index) = 508 let (resolution, remaining_index) =
448 match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { 509 match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
449 Some(it) => it, 510 Some(it) => it,
450 None => return (TyKind::Unknown.intern(&Interner), None), 511 None => return (TyKind::Error.intern(&Interner), None),
451 }; 512 };
452 let (resolved_segment, remaining_segments) = match remaining_index { 513 let (resolved_segment, remaining_segments) = match remaining_index {
453 None => ( 514 None => (
@@ -477,13 +538,13 @@ impl<'a> TyLoweringContext<'a> {
477 ), 538 ),
478 ); 539 );
479 let s = generics.type_params_subst(self.db); 540 let s = generics.type_params_subst(self.db);
480 t.substitution.clone().subst_bound_vars(&s) 541 s.apply(t.substitution.clone(), &Interner)
481 } 542 }
482 TypeParamLoweringMode::Variable => t.substitution.clone(), 543 TypeParamLoweringMode::Variable => t.substitution.clone(),
483 }; 544 };
484 // We need to shift in the bound vars, since 545 // We need to shift in the bound vars, since
485 // associated_type_shorthand_candidates does not do that 546 // associated_type_shorthand_candidates does not do that
486 let substs = substs.shift_bound_vars(self.in_binders); 547 let substs = substs.shifted_in_from(&Interner, self.in_binders);
487 // FIXME handle type parameters on the segment 548 // FIXME handle type parameters on the segment
488 return Some( 549 return Some(
489 TyKind::Alias(AliasTy::Projection(ProjectionTy { 550 TyKind::Alias(AliasTy::Projection(ProjectionTy {
@@ -498,9 +559,9 @@ impl<'a> TyLoweringContext<'a> {
498 }, 559 },
499 ); 560 );
500 561
501 ty.unwrap_or(TyKind::Unknown.intern(&Interner)) 562 ty.unwrap_or(TyKind::Error.intern(&Interner))
502 } else { 563 } else {
503 TyKind::Unknown.intern(&Interner) 564 TyKind::Error.intern(&Interner)
504 } 565 }
505 } 566 }
506 567
@@ -516,7 +577,7 @@ impl<'a> TyLoweringContext<'a> {
516 TyDefId::TypeAliasId(it) => Some(it.into()), 577 TyDefId::TypeAliasId(it) => Some(it.into()),
517 }; 578 };
518 let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None); 579 let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
519 self.db.ty(typeable).subst(&substs) 580 self.db.ty(typeable).substitute(&Interner, &substs)
520 } 581 }
521 582
522 /// Collect generic arguments from a path into a `Substs`. See also 583 /// Collect generic arguments from a path into a `Substs`. See also
@@ -569,13 +630,13 @@ impl<'a> TyLoweringContext<'a> {
569 def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); 630 def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
570 let total_len = parent_params + self_params + type_params + impl_trait_params; 631 let total_len = parent_params + self_params + type_params + impl_trait_params;
571 632
572 substs.extend(iter::repeat(TyKind::Unknown.intern(&Interner)).take(parent_params)); 633 substs.extend(iter::repeat(TyKind::Error.intern(&Interner)).take(parent_params));
573 634
574 let fill_self_params = || { 635 let fill_self_params = || {
575 substs.extend( 636 substs.extend(
576 explicit_self_ty 637 explicit_self_ty
577 .into_iter() 638 .into_iter()
578 .chain(iter::repeat(TyKind::Unknown.intern(&Interner))) 639 .chain(iter::repeat(TyKind::Error.intern(&Interner)))
579 .take(self_params), 640 .take(self_params),
580 ) 641 )
581 }; 642 };
@@ -620,7 +681,7 @@ impl<'a> TyLoweringContext<'a> {
620 for default_ty in defaults.iter().skip(substs.len()) { 681 for default_ty in defaults.iter().skip(substs.len()) {
621 // each default can depend on the previous parameters 682 // each default can depend on the previous parameters
622 let substs_so_far = Substitution::from_iter(&Interner, substs.clone()); 683 let substs_so_far = Substitution::from_iter(&Interner, substs.clone());
623 substs.push(default_ty.clone().subst(&substs_so_far)); 684 substs.push(default_ty.clone().substitute(&Interner, &substs_so_far));
624 } 685 }
625 } 686 }
626 } 687 }
@@ -628,7 +689,7 @@ impl<'a> TyLoweringContext<'a> {
628 // add placeholders for args that were not provided 689 // add placeholders for args that were not provided
629 // FIXME: emit diagnostics in contexts where this is not allowed 690 // FIXME: emit diagnostics in contexts where this is not allowed
630 for _ in substs.len()..total_len { 691 for _ in substs.len()..total_len {
631 substs.push(TyKind::Unknown.intern(&Interner)); 692 substs.push(TyKind::Error.intern(&Interner));
632 } 693 }
633 assert_eq!(substs.len(), total_len); 694 assert_eq!(substs.len(), total_len);
634 695
@@ -720,7 +781,7 @@ impl<'a> TyLoweringContext<'a> {
720 let trait_ref = match bound { 781 let trait_ref = match bound {
721 TypeBound::Path(path) => { 782 TypeBound::Path(path) => {
722 bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); 783 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
723 bindings.clone().map(WhereClause::Implemented).map(|b| Binders::wrap_empty(b)) 784 bindings.clone().map(WhereClause::Implemented).map(|b| crate::wrap_empty_binders(b))
724 } 785 }
725 TypeBound::Lifetime(_) => None, 786 TypeBound::Lifetime(_) => None,
726 TypeBound::Error => None, 787 TypeBound::Error => None,
@@ -767,7 +828,7 @@ impl<'a> TyLoweringContext<'a> {
767 let ty = self.lower_ty(type_ref); 828 let ty = self.lower_ty(type_ref);
768 let alias_eq = 829 let alias_eq =
769 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; 830 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
770 preds.push(Binders::wrap_empty(WhereClause::AliasEq(alias_eq))); 831 preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
771 } 832 }
772 for bound in &binding.bounds { 833 for bound in &binding.bounds {
773 preds.extend(self.lower_type_bound( 834 preds.extend(self.lower_type_bound(
@@ -787,7 +848,7 @@ impl<'a> TyLoweringContext<'a> {
787 let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { 848 let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
788 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect() 849 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
789 }); 850 });
790 ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } 851 ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
791 } 852 }
792} 853}
793 854
@@ -831,17 +892,20 @@ pub fn associated_type_shorthand_candidates<R>(
831 }; 892 };
832 893
833 match res { 894 match res {
834 // FIXME: how to correctly handle higher-ranked bounds here? 895 TypeNs::SelfType(impl_id) => search(
835 TypeNs::SelfType(impl_id) => { 896 // we're _in_ the impl -- the binders get added back later. Correct,
836 search(db.impl_trait(impl_id)?.value.shift_bound_vars_out(DebruijnIndex::ONE)) 897 // but it would be nice to make this more explicit
837 } 898 db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
899 ),
838 TypeNs::GenericParam(param_id) => { 900 TypeNs::GenericParam(param_id) => {
839 let predicates = db.generic_predicates_for_param(param_id); 901 let predicates = db.generic_predicates_for_param(param_id);
840 let res = predicates.iter().find_map(|pred| match &pred.value.value { 902 let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
841 // FIXME: how to correctly handle higher-ranked bounds here? 903 // FIXME: how to correctly handle higher-ranked bounds here?
842 WhereClause::Implemented(tr) => { 904 WhereClause::Implemented(tr) => search(
843 search(tr.clone().shift_bound_vars_out(DebruijnIndex::ONE)) 905 tr.clone()
844 } 906 .shifted_out_to(&Interner, DebruijnIndex::ONE)
907 .expect("FIXME unexpected higher-ranked trait bound"),
908 ),
845 _ => None, 909 _ => None,
846 }); 910 });
847 if let res @ Some(_) = res { 911 if let res @ Some(_) = res {
@@ -870,7 +934,7 @@ pub(crate) fn field_types_query(
870 db: &dyn HirDatabase, 934 db: &dyn HirDatabase,
871 variant_id: VariantId, 935 variant_id: VariantId,
872) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { 936) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
873 let var_data = variant_data(db.upcast(), variant_id); 937 let var_data = variant_id.variant_data(db.upcast());
874 let (resolver, def): (_, GenericDefId) = match variant_id { 938 let (resolver, def): (_, GenericDefId) = match variant_id {
875 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), 939 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
876 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), 940 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
@@ -881,7 +945,7 @@ pub(crate) fn field_types_query(
881 let ctx = 945 let ctx =
882 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 946 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
883 for (field_id, field_data) in var_data.fields().iter() { 947 for (field_id, field_data) in var_data.fields().iter() {
884 res.insert(field_id, Binders::new(generics.len(), ctx.lower_ty(&field_data.type_ref))) 948 res.insert(field_id, make_binders(&generics, ctx.lower_ty(&field_data.type_ref)))
885 } 949 }
886 Arc::new(res) 950 Arc::new(res)
887} 951}
@@ -915,9 +979,7 @@ pub(crate) fn generic_predicates_for_param_query(
915 }, 979 },
916 WherePredicate::Lifetime { .. } => false, 980 WherePredicate::Lifetime { .. } => false,
917 }) 981 })
918 .flat_map(|pred| { 982 .flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
919 ctx.lower_where_predicate(pred, true).map(|p| Binders::new(generics.len(), p))
920 })
921 .collect() 983 .collect()
922} 984}
923 985
@@ -941,10 +1003,10 @@ pub(crate) fn trait_environment_query(
941 for pred in resolver.where_predicates_in_scope() { 1003 for pred in resolver.where_predicates_in_scope() {
942 for pred in ctx.lower_where_predicate(pred, false) { 1004 for pred in ctx.lower_where_predicate(pred, false) {
943 if let WhereClause::Implemented(tr) = &pred.skip_binders() { 1005 if let WhereClause::Implemented(tr) = &pred.skip_binders() {
944 traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); 1006 traits_in_scope
1007 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
945 } 1008 }
946 let program_clause: chalk_ir::ProgramClause<Interner> = 1009 let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
947 pred.clone().to_chalk(db).cast(&Interner);
948 clauses.push(program_clause.into_from_env_clause(&Interner)); 1010 clauses.push(program_clause.into_from_env_clause(&Interner));
949 } 1011 }
950 } 1012 }
@@ -967,7 +1029,7 @@ pub(crate) fn trait_environment_query(
967 let substs = TyBuilder::type_params_subst(db, trait_id); 1029 let substs = TyBuilder::type_params_subst(db, trait_id);
968 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; 1030 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
969 let pred = WhereClause::Implemented(trait_ref); 1031 let pred = WhereClause::Implemented(trait_ref);
970 let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); 1032 let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
971 clauses.push(program_clause.into_from_env_clause(&Interner)); 1033 clauses.push(program_clause.into_from_env_clause(&Interner));
972 } 1034 }
973 1035
@@ -987,9 +1049,7 @@ pub(crate) fn generic_predicates_query(
987 let generics = generics(db.upcast(), def); 1049 let generics = generics(db.upcast(), def);
988 resolver 1050 resolver
989 .where_predicates_in_scope() 1051 .where_predicates_in_scope()
990 .flat_map(|pred| { 1052 .flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
991 ctx.lower_where_predicate(pred, false).map(|p| Binders::new(generics.len(), p))
992 })
993 .collect() 1053 .collect()
994} 1054}
995 1055
@@ -1008,25 +1068,21 @@ pub(crate) fn generic_defaults_query(
1008 .enumerate() 1068 .enumerate()
1009 .map(|(idx, (_, p))| { 1069 .map(|(idx, (_, p))| {
1010 let mut ty = 1070 let mut ty =
1011 p.default.as_ref().map_or(TyKind::Unknown.intern(&Interner), |t| ctx.lower_ty(t)); 1071 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
1012 1072
1013 // Each default can only refer to previous parameters. 1073 // Each default can only refer to previous parameters.
1014 ty.walk_mut_binders( 1074 ty = crate::fold_free_vars(ty, |bound, binders| {
1015 &mut |ty, binders| match ty.interned_mut() { 1075 if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
1016 TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => { 1076 // type variable default referring to parameter coming
1017 if *index >= idx { 1077 // after it. This is forbidden (FIXME: report
1018 // type variable default referring to parameter coming 1078 // diagnostic)
1019 // after it. This is forbidden (FIXME: report 1079 TyKind::Error.intern(&Interner)
1020 // diagnostic) 1080 } else {
1021 *ty = TyKind::Unknown.intern(&Interner); 1081 bound.shifted_in_from(binders).to_ty(&Interner)
1022 } 1082 }
1023 } 1083 });
1024 _ => {}
1025 },
1026 DebruijnIndex::INNERMOST,
1027 );
1028 1084
1029 Binders::new(idx, ty) 1085 crate::make_only_type_binders(idx, ty)
1030 }) 1086 })
1031 .collect(); 1087 .collect();
1032 1088
@@ -1039,14 +1095,13 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
1039 let ctx_params = TyLoweringContext::new(db, &resolver) 1095 let ctx_params = TyLoweringContext::new(db, &resolver)
1040 .with_impl_trait_mode(ImplTraitLoweringMode::Variable) 1096 .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
1041 .with_type_param_mode(TypeParamLoweringMode::Variable); 1097 .with_type_param_mode(TypeParamLoweringMode::Variable);
1042 let params = data.params.iter().map(|tr| (&ctx_params).lower_ty(tr)).collect::<Vec<_>>(); 1098 let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
1043 let ctx_ret = TyLoweringContext::new(db, &resolver) 1099 let ctx_ret = TyLoweringContext::new(db, &resolver)
1044 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) 1100 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
1045 .with_type_param_mode(TypeParamLoweringMode::Variable); 1101 .with_type_param_mode(TypeParamLoweringMode::Variable);
1046 let ret = (&ctx_ret).lower_ty(&data.ret_type); 1102 let ret = ctx_ret.lower_ty(&data.ret_type);
1047 let generics = generics(db.upcast(), def.into()); 1103 let generics = generics(db.upcast(), def.into());
1048 let num_binders = generics.len(); 1104 make_binders(&generics, CallableSig::from_params_and_return(params, ret, data.is_varargs()))
1049 Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs()))
1050} 1105}
1051 1106
1052/// Build the declared type of a function. This should not need to look at the 1107/// Build the declared type of a function. This should not need to look at the
@@ -1054,8 +1109,8 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
1054fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { 1109fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
1055 let generics = generics(db.upcast(), def.into()); 1110 let generics = generics(db.upcast(), def.into());
1056 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); 1111 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1057 Binders::new( 1112 make_binders(
1058 substs.len(&Interner), 1113 &generics,
1059 TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner), 1114 TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner),
1060 ) 1115 )
1061} 1116}
@@ -1068,7 +1123,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
1068 let ctx = 1123 let ctx =
1069 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1124 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1070 1125
1071 Binders::new(generics.len(), ctx.lower_ty(&data.type_ref)) 1126 make_binders(&generics, ctx.lower_ty(&data.type_ref))
1072} 1127}
1073 1128
1074/// Build the declared type of a static. 1129/// Build the declared type of a static.
@@ -1077,7 +1132,7 @@ fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
1077 let resolver = def.resolver(db.upcast()); 1132 let resolver = def.resolver(db.upcast());
1078 let ctx = TyLoweringContext::new(db, &resolver); 1133 let ctx = TyLoweringContext::new(db, &resolver);
1079 1134
1080 Binders::new(0, ctx.lower_ty(&data.type_ref)) 1135 Binders::empty(&Interner, ctx.lower_ty(&data.type_ref))
1081} 1136}
1082 1137
1083fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { 1138fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
@@ -1087,8 +1142,8 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
1087 let ctx = 1142 let ctx =
1088 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1143 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1089 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); 1144 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
1090 let ret = type_for_adt(db, def.into()); 1145 let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
1091 Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false)) 1146 Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
1092} 1147}
1093 1148
1094/// Build the type of a tuple struct constructor. 1149/// Build the type of a tuple struct constructor.
@@ -1099,8 +1154,8 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
1099 } 1154 }
1100 let generics = generics(db.upcast(), def.into()); 1155 let generics = generics(db.upcast(), def.into());
1101 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); 1156 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1102 Binders::new( 1157 make_binders(
1103 substs.len(&Interner), 1158 &generics,
1104 TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner), 1159 TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner),
1105 ) 1160 )
1106} 1161}
@@ -1113,8 +1168,8 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
1113 let ctx = 1168 let ctx =
1114 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1169 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1115 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); 1170 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
1116 let ret = type_for_adt(db, def.parent.into()); 1171 let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
1117 Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false)) 1172 Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
1118} 1173}
1119 1174
1120/// Build the type of a tuple enum variant constructor. 1175/// Build the type of a tuple enum variant constructor.
@@ -1126,17 +1181,17 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
1126 } 1181 }
1127 let generics = generics(db.upcast(), def.parent.into()); 1182 let generics = generics(db.upcast(), def.parent.into());
1128 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST); 1183 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1129 Binders::new( 1184 make_binders(
1130 substs.len(&Interner), 1185 &generics,
1131 TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner), 1186 TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner),
1132 ) 1187 )
1133} 1188}
1134 1189
1135fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { 1190fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
1191 let generics = generics(db.upcast(), adt.into());
1136 let b = TyBuilder::adt(db, adt); 1192 let b = TyBuilder::adt(db, adt);
1137 let num_binders = b.remaining();
1138 let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build(); 1193 let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
1139 Binders::new(num_binders, ty) 1194 make_binders(&generics, ty)
1140} 1195}
1141 1196
1142fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { 1197fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
@@ -1145,11 +1200,11 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
1145 let ctx = 1200 let ctx =
1146 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1201 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1147 if db.type_alias_data(t).is_extern { 1202 if db.type_alias_data(t).is_extern {
1148 Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) 1203 Binders::empty(&Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(&Interner))
1149 } else { 1204 } else {
1150 let type_ref = &db.type_alias_data(t).type_ref; 1205 let type_ref = &db.type_alias_data(t).type_ref;
1151 let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error)); 1206 let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
1152 Binders::new(generics.len(), inner) 1207 make_binders(&generics, inner)
1153 } 1208 }
1154} 1209}
1155 1210
@@ -1208,19 +1263,21 @@ impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for V
1208/// namespace. 1263/// namespace.
1209pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { 1264pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
1210 match def { 1265 match def {
1211 TyDefId::BuiltinType(it) => Binders::new(0, TyBuilder::builtin(it)), 1266 TyDefId::BuiltinType(it) => Binders::empty(&Interner, TyBuilder::builtin(it)),
1212 TyDefId::AdtId(it) => type_for_adt(db, it), 1267 TyDefId::AdtId(it) => type_for_adt(db, it),
1213 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), 1268 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
1214 } 1269 }
1215} 1270}
1216 1271
1217pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> { 1272pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> {
1218 let num_binders = match *def { 1273 let generics = match *def {
1219 TyDefId::BuiltinType(_) => 0, 1274 TyDefId::BuiltinType(_) => {
1220 TyDefId::AdtId(it) => generics(db.upcast(), it.into()).len(), 1275 return Binders::empty(&Interner, TyKind::Error.intern(&Interner))
1221 TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()).len(), 1276 }
1277 TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
1278 TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
1222 }; 1279 };
1223 Binders::new(num_binders, TyKind::Unknown.intern(&Interner)) 1280 make_binders(&generics, TyKind::Error.intern(&Interner))
1224} 1281}
1225 1282
1226pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> { 1283pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
@@ -1240,7 +1297,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
1240 let generics = generics(db.upcast(), impl_id.into()); 1297 let generics = generics(db.upcast(), impl_id.into());
1241 let ctx = 1298 let ctx =
1242 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1299 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1243 Binders::new(generics.len(), ctx.lower_ty(&impl_data.self_ty)) 1300 make_binders(&generics, ctx.lower_ty(&impl_data.self_ty))
1244} 1301}
1245 1302
1246pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { 1303pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
@@ -1258,7 +1315,7 @@ pub(crate) fn impl_self_ty_recover(
1258 impl_id: &ImplId, 1315 impl_id: &ImplId,
1259) -> Binders<Ty> { 1316) -> Binders<Ty> {
1260 let generics = generics(db.upcast(), (*impl_id).into()); 1317 let generics = generics(db.upcast(), (*impl_id).into());
1261 Binders::new(generics.len(), TyKind::Unknown.intern(&Interner)) 1318 make_binders(&generics, TyKind::Error.intern(&Interner))
1262} 1319}
1263 1320
1264pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { 1321pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
@@ -1266,9 +1323,9 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
1266 let resolver = impl_id.resolver(db.upcast()); 1323 let resolver = impl_id.resolver(db.upcast());
1267 let ctx = 1324 let ctx =
1268 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1325 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1269 let self_ty = db.impl_self_ty(impl_id); 1326 let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
1270 let target_trait = impl_data.target_trait.as_ref()?; 1327 let target_trait = impl_data.target_trait.as_ref()?;
1271 Some(Binders::new(self_ty.num_binders, ctx.lower_trait_ref(target_trait, Some(self_ty.value))?)) 1328 Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
1272} 1329}
1273 1330
1274pub(crate) fn return_type_impl_traits( 1331pub(crate) fn return_type_impl_traits(
@@ -1283,13 +1340,12 @@ pub(crate) fn return_type_impl_traits(
1283 .with_type_param_mode(TypeParamLoweringMode::Variable); 1340 .with_type_param_mode(TypeParamLoweringMode::Variable);
1284 let _ret = (&ctx_ret).lower_ty(&data.ret_type); 1341 let _ret = (&ctx_ret).lower_ty(&data.ret_type);
1285 let generics = generics(db.upcast(), def.into()); 1342 let generics = generics(db.upcast(), def.into());
1286 let num_binders = generics.len();
1287 let return_type_impl_traits = 1343 let return_type_impl_traits =
1288 ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; 1344 ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
1289 if return_type_impl_traits.impl_traits.is_empty() { 1345 if return_type_impl_traits.impl_traits.is_empty() {
1290 None 1346 None
1291 } else { 1347 } else {
1292 Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) 1348 Some(Arc::new(make_binders(&generics, return_type_impl_traits)))
1293 } 1349 }
1294} 1350}
1295 1351
@@ -1299,3 +1355,7 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
1299 hir_def::type_ref::Mutability::Mut => Mutability::Mut, 1355 hir_def::type_ref::Mutability::Mut => Mutability::Mut,
1300 } 1356 }
1301} 1357}
1358
1359fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
1360 crate::make_only_type_binders(generics.len(), value)
1361}
diff --git a/crates/hir_ty/src/mapping.rs b/crates/hir_ty/src/mapping.rs
new file mode 100644
index 000000000..5e86fafe5
--- /dev/null
+++ b/crates/hir_ty/src/mapping.rs
@@ -0,0 +1,154 @@
1//! This module contains the implementations of the `ToChalk` trait, which
2//! handles conversion between our data types and their corresponding types in
3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions.
5
6use chalk_solve::rust_ir;
7
8use base_db::salsa::{self, InternKey};
9use hir_def::{ConstParamId, LifetimeParamId, TraitId, TypeAliasId, TypeParamId};
10
11use crate::{
12 chalk_db, db::HirDatabase, AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId,
13 Interner, OpaqueTyId, PlaceholderIndex,
14};
15
16pub(crate) trait ToChalk {
17 type Chalk;
18 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk;
19 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self;
20}
21
22pub(crate) fn from_chalk<T, ChalkT>(db: &dyn HirDatabase, chalk: ChalkT) -> T
23where
24 T: ToChalk<Chalk = ChalkT>,
25{
26 T::from_chalk(db, chalk)
27}
28
29impl ToChalk for hir_def::ImplId {
30 type Chalk = chalk_db::ImplId;
31
32 fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::ImplId {
33 chalk_ir::ImplId(self.as_intern_id())
34 }
35
36 fn from_chalk(_db: &dyn HirDatabase, impl_id: chalk_db::ImplId) -> hir_def::ImplId {
37 InternKey::from_intern_id(impl_id.0)
38 }
39}
40
41impl ToChalk for CallableDefId {
42 type Chalk = FnDefId;
43
44 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
45 db.intern_callable_def(self).into()
46 }
47
48 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
49 db.lookup_intern_callable_def(fn_def_id.into())
50 }
51}
52
53pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId);
54
55impl ToChalk for TypeAliasAsValue {
56 type Chalk = chalk_db::AssociatedTyValueId;
57
58 fn to_chalk(self, _db: &dyn HirDatabase) -> chalk_db::AssociatedTyValueId {
59 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
60 }
61
62 fn from_chalk(
63 _db: &dyn HirDatabase,
64 assoc_ty_value_id: chalk_db::AssociatedTyValueId,
65 ) -> TypeAliasAsValue {
66 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
67 }
68}
69
70impl From<FnDefId> for crate::db::InternedCallableDefId {
71 fn from(fn_def_id: FnDefId) -> Self {
72 InternKey::from_intern_id(fn_def_id.0)
73 }
74}
75
76impl From<crate::db::InternedCallableDefId> for FnDefId {
77 fn from(callable_def_id: crate::db::InternedCallableDefId) -> Self {
78 chalk_ir::FnDefId(callable_def_id.as_intern_id())
79 }
80}
81
82impl From<OpaqueTyId> for crate::db::InternedOpaqueTyId {
83 fn from(id: OpaqueTyId) -> Self {
84 InternKey::from_intern_id(id.0)
85 }
86}
87
88impl From<crate::db::InternedOpaqueTyId> for OpaqueTyId {
89 fn from(id: crate::db::InternedOpaqueTyId) -> Self {
90 chalk_ir::OpaqueTyId(id.as_intern_id())
91 }
92}
93
94impl From<chalk_ir::ClosureId<Interner>> for crate::db::InternedClosureId {
95 fn from(id: chalk_ir::ClosureId<Interner>) -> Self {
96 Self::from_intern_id(id.0)
97 }
98}
99
100impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
101 fn from(id: crate::db::InternedClosureId) -> Self {
102 chalk_ir::ClosureId(id.as_intern_id())
103 }
104}
105
106pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
107 chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
108}
109
110pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId {
111 salsa::InternKey::from_intern_id(id.0)
112}
113
114pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId {
115 chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id))
116}
117
118pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
119 salsa::InternKey::from_intern_id(id.0)
120}
121
122pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId {
123 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
124 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
125 db.lookup_intern_type_param_id(interned_id)
126}
127
128pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex {
129 let interned_id = db.intern_type_param_id(id);
130 PlaceholderIndex {
131 ui: chalk_ir::UniverseIndex::ROOT,
132 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
133 }
134}
135
136pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> LifetimeParamId {
137 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
138 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
139 db.lookup_intern_lifetime_param_id(interned_id)
140}
141
142pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId {
143 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
144 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
145 db.lookup_intern_const_param_id(interned_id)
146}
147
148pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
149 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
150}
151
152pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId {
153 salsa::InternKey::from_intern_id(id.0)
154}
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index a76586f0c..48bbcfd9f 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -8,8 +8,8 @@ use arrayvec::ArrayVec;
8use base_db::CrateId; 8use base_db::CrateId;
9use chalk_ir::{cast::Cast, Mutability, UniverseIndex}; 9use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
10use hir_def::{ 10use hir_def::{
11 lang_item::LangItemTarget, AssocContainerId, AssocItemId, FunctionId, GenericDefId, HasModule, 11 lang_item::LangItemTarget, nameres::DefMap, AssocContainerId, AssocItemId, FunctionId,
12 ImplId, Lookup, ModuleId, TraitId, 12 GenericDefId, HasModule, ImplId, Lookup, ModuleId, TraitId,
13}; 13};
14use hir_expand::name::Name; 14use hir_expand::name::Name;
15use rustc_hash::{FxHashMap, FxHashSet}; 15use rustc_hash::{FxHashMap, FxHashSet};
@@ -19,51 +19,91 @@ use crate::{
19 db::HirDatabase, 19 db::HirDatabase,
20 from_foreign_def_id, 20 from_foreign_def_id,
21 primitive::{self, FloatTy, IntTy, UintTy}, 21 primitive::{self, FloatTy, IntTy, UintTy},
22 static_lifetime,
22 utils::all_super_traits, 23 utils::all_super_traits,
23 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
24 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, Ty, TyBuilder, TyKind, 25 Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
25 TypeWalk,
26}; 26};
27 27
28/// This is used as a key for indexing impls. 28/// This is used as a key for indexing impls.
29#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 29#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
30pub enum TyFingerprint { 30pub enum TyFingerprint {
31 // These are lang item impls:
31 Str, 32 Str,
32 Slice, 33 Slice,
33 Array, 34 Array,
34 Never, 35 Never,
35 RawPtr(Mutability), 36 RawPtr(Mutability),
36 Scalar(Scalar), 37 Scalar(Scalar),
38 // These can have user-defined impls:
37 Adt(hir_def::AdtId), 39 Adt(hir_def::AdtId),
38 Dyn(TraitId), 40 Dyn(TraitId),
39 Tuple(usize),
40 ForeignType(ForeignDefId), 41 ForeignType(ForeignDefId),
41 FnPtr(usize, FnSig), 42 // These only exist for trait impls
43 Unit,
44 Unnameable,
45 Function(u32),
42} 46}
43 47
44impl TyFingerprint { 48impl TyFingerprint {
45 /// Creates a TyFingerprint for looking up an impl. Only certain types can 49 /// Creates a TyFingerprint for looking up an inherent impl. Only certain
46 /// have impls: if we have some `struct S`, we can have an `impl S`, but not 50 /// types can have inherent impls: if we have some `struct S`, we can have
47 /// `impl &S`. Hence, this will return `None` for reference types and such. 51 /// an `impl S`, but not `impl &S`. Hence, this will return `None` for
48 pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { 52 /// reference types and such.
49 let fp = match *ty.kind(&Interner) { 53 pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
54 let fp = match ty.kind(&Interner) {
50 TyKind::Str => TyFingerprint::Str, 55 TyKind::Str => TyFingerprint::Str,
51 TyKind::Never => TyFingerprint::Never, 56 TyKind::Never => TyFingerprint::Never,
52 TyKind::Slice(..) => TyFingerprint::Slice, 57 TyKind::Slice(..) => TyFingerprint::Slice,
53 TyKind::Array(..) => TyFingerprint::Array, 58 TyKind::Array(..) => TyFingerprint::Array,
54 TyKind::Scalar(scalar) => TyFingerprint::Scalar(scalar), 59 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
55 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(adt), 60 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
56 TyKind::Tuple(cardinality, _) => TyFingerprint::Tuple(cardinality), 61 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
57 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(mutability), 62 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
58 TyKind::ForeignType(alias_id, ..) => TyFingerprint::ForeignType(alias_id),
59 TyKind::Function(FnPointer { num_args, sig, .. }) => {
60 TyFingerprint::FnPtr(num_args, sig)
61 }
62 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, 63 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
63 _ => return None, 64 _ => return None,
64 }; 65 };
65 Some(fp) 66 Some(fp)
66 } 67 }
68
69 /// Creates a TyFingerprint for looking up a trait impl.
70 pub fn for_trait_impl(ty: &Ty) -> Option<TyFingerprint> {
71 let fp = match ty.kind(&Interner) {
72 TyKind::Str => TyFingerprint::Str,
73 TyKind::Never => TyFingerprint::Never,
74 TyKind::Slice(..) => TyFingerprint::Slice,
75 TyKind::Array(..) => TyFingerprint::Array,
76 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
77 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
78 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
79 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
80 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
81 TyKind::Ref(_, _, ty) => return TyFingerprint::for_trait_impl(ty),
82 TyKind::Tuple(_, subst) => {
83 let first_ty = subst.interned().get(0).map(|arg| arg.assert_ty_ref(&Interner));
84 if let Some(ty) = first_ty {
85 return TyFingerprint::for_trait_impl(ty);
86 } else {
87 TyFingerprint::Unit
88 }
89 }
90 TyKind::AssociatedType(_, _)
91 | TyKind::OpaqueType(_, _)
92 | TyKind::FnDef(_, _)
93 | TyKind::Closure(_, _)
94 | TyKind::Generator(..)
95 | TyKind::GeneratorWitness(..) => TyFingerprint::Unnameable,
96 TyKind::Function(fn_ptr) => {
97 TyFingerprint::Function(fn_ptr.substitution.0.len(&Interner) as u32)
98 }
99 TyKind::Alias(_)
100 | TyKind::Placeholder(_)
101 | TyKind::BoundVar(_)
102 | TyKind::InferenceVar(_, _)
103 | TyKind::Error => return None,
104 };
105 Some(fp)
106 }
67} 107}
68 108
69pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ 109pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@@ -99,25 +139,38 @@ impl TraitImpls {
99 let mut impls = Self { map: FxHashMap::default() }; 139 let mut impls = Self { map: FxHashMap::default() };
100 140
101 let crate_def_map = db.crate_def_map(krate); 141 let crate_def_map = db.crate_def_map(krate);
102 for (_module_id, module_data) in crate_def_map.modules() { 142 collect_def_map(db, &crate_def_map, &mut impls);
103 for impl_id in module_data.scope.impls() { 143
104 let target_trait = match db.impl_trait(impl_id) { 144 return Arc::new(impls);
105 Some(tr) => tr.value.hir_trait_id(), 145
106 None => continue, 146 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) {
107 }; 147 for (_module_id, module_data) in def_map.modules() {
108 let self_ty = db.impl_self_ty(impl_id); 148 for impl_id in module_data.scope.impls() {
109 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); 149 let target_trait = match db.impl_trait(impl_id) {
110 impls 150 Some(tr) => tr.skip_binders().hir_trait_id(),
111 .map 151 None => continue,
112 .entry(target_trait) 152 };
113 .or_default() 153 let self_ty = db.impl_self_ty(impl_id);
114 .entry(self_ty_fp) 154 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
115 .or_default() 155 impls
116 .push(impl_id); 156 .map
157 .entry(target_trait)
158 .or_default()
159 .entry(self_ty_fp)
160 .or_default()
161 .push(impl_id);
162 }
163
164 // To better support custom derives, collect impls in all unnamed const items.
165 // const _: () = { ... };
166 for konst in module_data.scope.unnamed_consts() {
167 let body = db.body(konst.into());
168 for (_, block_def_map) in body.blocks(db.upcast()) {
169 collect_def_map(db, &block_def_map, impls);
170 }
171 }
117 } 172 }
118 } 173 }
119
120 Arc::new(impls)
121 } 174 }
122 175
123 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { 176 pub(crate) fn trait_impls_in_deps_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
@@ -143,10 +196,13 @@ impl TraitImpls {
143 } 196 }
144 197
145 /// Queries all trait impls for the given type. 198 /// Queries all trait impls for the given type.
146 pub fn for_self_ty(&self, fp: TyFingerprint) -> impl Iterator<Item = ImplId> + '_ { 199 pub fn for_self_ty_without_blanket_impls(
200 &self,
201 fp: TyFingerprint,
202 ) -> impl Iterator<Item = ImplId> + '_ {
147 self.map 203 self.map
148 .values() 204 .values()
149 .flat_map(move |impls| impls.get(&None).into_iter().chain(impls.get(&Some(fp)))) 205 .flat_map(move |impls| impls.get(&Some(fp)).into_iter())
150 .flat_map(|it| it.iter().copied()) 206 .flat_map(|it| it.iter().copied())
151 } 207 }
152 208
@@ -190,28 +246,43 @@ pub struct InherentImpls {
190 246
191impl InherentImpls { 247impl InherentImpls {
192 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> { 248 pub(crate) fn inherent_impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<Self> {
193 let mut map: FxHashMap<_, Vec<_>> = FxHashMap::default(); 249 let mut impls = Self { map: FxHashMap::default() };
194 250
195 let crate_def_map = db.crate_def_map(krate); 251 let crate_def_map = db.crate_def_map(krate);
196 for (_module_id, module_data) in crate_def_map.modules() { 252 collect_def_map(db, &crate_def_map, &mut impls);
197 for impl_id in module_data.scope.impls() { 253
198 let data = db.impl_data(impl_id); 254 return Arc::new(impls);
199 if data.target_trait.is_some() { 255
200 continue; 256 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut InherentImpls) {
257 for (_module_id, module_data) in def_map.modules() {
258 for impl_id in module_data.scope.impls() {
259 let data = db.impl_data(impl_id);
260 if data.target_trait.is_some() {
261 continue;
262 }
263
264 let self_ty = db.impl_self_ty(impl_id);
265 let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
266 if let Some(fp) = fp {
267 impls.map.entry(fp).or_default().push(impl_id);
268 }
269 // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
201 } 270 }
202 271
203 let self_ty = db.impl_self_ty(impl_id); 272 // To better support custom derives, collect impls in all unnamed const items.
204 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) { 273 // const _: () = { ... };
205 map.entry(fp).or_default().push(impl_id); 274 for konst in module_data.scope.unnamed_consts() {
275 let body = db.body(konst.into());
276 for (_, block_def_map) in body.blocks(db.upcast()) {
277 collect_def_map(db, &block_def_map, impls);
278 }
206 } 279 }
207 } 280 }
208 } 281 }
209
210 Arc::new(Self { map })
211 } 282 }
212 283
213 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { 284 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
214 match TyFingerprint::for_impl(self_ty) { 285 match TyFingerprint::for_inherent_impl(self_ty) {
215 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), 286 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
216 None => &[], 287 None => &[],
217 } 288 }
@@ -222,15 +293,14 @@ impl InherentImpls {
222 } 293 }
223} 294}
224 295
225impl Ty { 296pub fn def_crates(
226 pub fn def_crates( 297 db: &dyn HirDatabase,
227 &self, 298 ty: &Ty,
228 db: &dyn HirDatabase, 299 cur_crate: CrateId,
229 cur_crate: CrateId, 300) -> Option<ArrayVec<CrateId, 2>> {
230 ) -> Option<ArrayVec<CrateId, 2>> { 301 // Types like slice can have inherent impls in several crates, (core and alloc).
231 // Types like slice can have inherent impls in several crates, (core and alloc). 302 // The corresponding impls are marked with lang items, so we can use them to find the required crates.
232 // The corresponding impls are marked with lang items, so we can use them to find the required crates. 303 macro_rules! lang_item_crate {
233 macro_rules! lang_item_crate {
234 ($($name:expr),+ $(,)?) => {{ 304 ($($name:expr),+ $(,)?) => {{
235 let mut v = ArrayVec::<LangItemTarget, 2>::new(); 305 let mut v = ArrayVec::<LangItemTarget, 2>::new();
236 $( 306 $(
@@ -240,51 +310,50 @@ impl Ty {
240 }}; 310 }};
241 } 311 }
242 312
243 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect()); 313 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect());
244 314
245 let lang_item_targets = match self.kind(&Interner) { 315 let lang_item_targets = match ty.kind(&Interner) {
246 TyKind::Adt(AdtId(def_id), _) => { 316 TyKind::Adt(AdtId(def_id), _) => {
247 return mod_to_crate_ids(def_id.module(db.upcast())); 317 return mod_to_crate_ids(def_id.module(db.upcast()));
248 } 318 }
249 TyKind::ForeignType(id) => { 319 TyKind::Foreign(id) => {
250 return mod_to_crate_ids( 320 return mod_to_crate_ids(
251 from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()), 321 from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()),
252 ); 322 );
253 } 323 }
254 TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"), 324 TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"),
255 TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"), 325 TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"),
256 TyKind::Scalar(Scalar::Float(f)) => match f { 326 TyKind::Scalar(Scalar::Float(f)) => match f {
257 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 327 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
258 FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"), 328 FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"),
259 FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"), 329 FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"),
260 }, 330 },
261 &TyKind::Scalar(Scalar::Int(t)) => { 331 &TyKind::Scalar(Scalar::Int(t)) => {
262 lang_item_crate!(primitive::int_ty_to_string(t)) 332 lang_item_crate!(primitive::int_ty_to_string(t))
263 } 333 }
264 &TyKind::Scalar(Scalar::Uint(t)) => { 334 &TyKind::Scalar(Scalar::Uint(t)) => {
265 lang_item_crate!(primitive::uint_ty_to_string(t)) 335 lang_item_crate!(primitive::uint_ty_to_string(t))
266 } 336 }
267 TyKind::Str => lang_item_crate!("str_alloc", "str"), 337 TyKind::Str => lang_item_crate!("str_alloc", "str"),
268 TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"), 338 TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"),
269 TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"), 339 TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"),
270 TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"), 340 TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"),
271 TyKind::Dyn(_) => { 341 TyKind::Dyn(_) => {
272 return self.dyn_trait().and_then(|trait_| { 342 return ty.dyn_trait().and_then(|trait_| {
273 mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast())) 343 mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))
274 }); 344 });
275 } 345 }
276 _ => return None, 346 _ => return None,
277 }; 347 };
278 let res = lang_item_targets 348 let res = lang_item_targets
279 .into_iter() 349 .into_iter()
280 .filter_map(|it| match it { 350 .filter_map(|it| match it {
281 LangItemTarget::ImplDefId(it) => Some(it), 351 LangItemTarget::ImplDefId(it) => Some(it),
282 _ => None, 352 _ => None,
283 }) 353 })
284 .map(|it| it.lookup(db.upcast()).container.krate()) 354 .map(|it| it.lookup(db.upcast()).container.krate())
285 .collect(); 355 .collect();
286 Some(res) 356 Some(res)
287 }
288} 357}
289 358
290/// Look up the method with the given name, returning the actual autoderefed 359/// Look up the method with the given name, returning the actual autoderefed
@@ -453,7 +522,8 @@ fn iterate_method_candidates_with_autoref(
453 } 522 }
454 let refed = Canonical { 523 let refed = Canonical {
455 binders: deref_chain[0].binders.clone(), 524 binders: deref_chain[0].binders.clone(),
456 value: TyKind::Ref(Mutability::Not, deref_chain[0].value.clone()).intern(&Interner), 525 value: TyKind::Ref(Mutability::Not, static_lifetime(), deref_chain[0].value.clone())
526 .intern(&Interner),
457 }; 527 };
458 if iterate_method_candidates_by_receiver( 528 if iterate_method_candidates_by_receiver(
459 &refed, 529 &refed,
@@ -470,7 +540,8 @@ fn iterate_method_candidates_with_autoref(
470 } 540 }
471 let ref_muted = Canonical { 541 let ref_muted = Canonical {
472 binders: deref_chain[0].binders.clone(), 542 binders: deref_chain[0].binders.clone(),
473 value: TyKind::Ref(Mutability::Mut, deref_chain[0].value.clone()).intern(&Interner), 543 value: TyKind::Ref(Mutability::Mut, static_lifetime(), deref_chain[0].value.clone())
544 .intern(&Interner),
474 }; 545 };
475 if iterate_method_candidates_by_receiver( 546 if iterate_method_candidates_by_receiver(
476 &ref_muted, 547 &ref_muted,
@@ -592,6 +663,7 @@ fn iterate_trait_method_candidates(
592 } 663 }
593 } 664 }
594 known_implemented = true; 665 known_implemented = true;
666 // FIXME: we shouldn't be ignoring the binders here
595 if callback(&self_ty.value, *item) { 667 if callback(&self_ty.value, *item) {
596 return true; 668 return true;
597 } 669 }
@@ -609,7 +681,7 @@ fn iterate_inherent_methods(
609 visible_from_module: Option<ModuleId>, 681 visible_from_module: Option<ModuleId>,
610 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 682 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
611) -> bool { 683) -> bool {
612 let def_crates = match self_ty.value.def_crates(db, krate) { 684 let def_crates = match def_crates(db, &self_ty.value, krate) {
613 Some(k) => k, 685 Some(k) => k,
614 None => return false, 686 None => return false,
615 }; 687 };
@@ -709,10 +781,11 @@ pub(crate) fn inherent_impl_substs(
709) -> Option<Substitution> { 781) -> Option<Substitution> {
710 // we create a var for each type parameter of the impl; we need to keep in 782 // we create a var for each type parameter of the impl; we need to keep in
711 // mind here that `self_ty` might have vars of its own 783 // mind here that `self_ty` might have vars of its own
784 let self_ty_vars = self_ty.binders.len(&Interner);
712 let vars = TyBuilder::subst_for_def(db, impl_id) 785 let vars = TyBuilder::subst_for_def(db, impl_id)
713 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.binders.len(&Interner)) 786 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty_vars)
714 .build(); 787 .build();
715 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 788 let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(&Interner, &vars);
716 let mut kinds = self_ty.binders.interned().to_vec(); 789 let mut kinds = self_ty.binders.interned().to_vec();
717 kinds.extend( 790 kinds.extend(
718 iter::repeat(chalk_ir::WithKind::new( 791 iter::repeat(chalk_ir::WithKind::new(
@@ -725,33 +798,27 @@ pub(crate) fn inherent_impl_substs(
725 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 798 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
726 value: (self_ty_with_vars, self_ty.value.clone()), 799 value: (self_ty_with_vars, self_ty.value.clone()),
727 }; 800 };
728 let substs = super::infer::unify(&tys); 801 let substs = super::infer::unify(&tys)?;
729 // We only want the substs for the vars we added, not the ones from self_ty. 802 // We only want the substs for the vars we added, not the ones from self_ty.
730 // Also, if any of the vars we added are still in there, we replace them by 803 // Also, if any of the vars we added are still in there, we replace them by
731 // Unknown. I think this can only really happen if self_ty contained 804 // Unknown. I think this can only really happen if self_ty contained
732 // Unknown, and in that case we want the result to contain Unknown in those 805 // Unknown, and in that case we want the result to contain Unknown in those
733 // places again. 806 // places again.
734 substs 807 let suffix =
735 .map(|s| fallback_bound_vars(s.suffix(vars.len(&Interner)), self_ty.binders.len(&Interner))) 808 Substitution::from_iter(&Interner, substs.iter(&Interner).cloned().skip(self_ty_vars));
809 Some(fallback_bound_vars(suffix, self_ty_vars))
736} 810}
737 811
738/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 812/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
739/// num_vars_to_keep) by `TyKind::Unknown`. 813/// num_vars_to_keep) by `TyKind::Unknown`.
740fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution { 814fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
741 s.fold_binders( 815 crate::fold_free_vars(s, |bound, binders| {
742 &mut |ty, binders| { 816 if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
743 if let TyKind::BoundVar(bound) = ty.kind(&Interner) { 817 TyKind::Error.intern(&Interner)
744 if bound.index >= num_vars_to_keep && bound.debruijn >= binders { 818 } else {
745 TyKind::Unknown.intern(&Interner) 819 bound.shifted_in_from(binders).to_ty(&Interner)
746 } else { 820 }
747 ty 821 })
748 }
749 } else {
750 ty
751 }
752 },
753 DebruijnIndex::INNERMOST,
754 )
755} 822}
756 823
757fn transform_receiver_ty( 824fn transform_receiver_ty(
@@ -774,7 +841,7 @@ fn transform_receiver_ty(
774 AssocContainerId::ModuleId(_) => unreachable!(), 841 AssocContainerId::ModuleId(_) => unreachable!(),
775 }; 842 };
776 let sig = db.callable_item_signature(function_id.into()); 843 let sig = db.callable_item_signature(function_id.into());
777 Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) 844 Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))
778} 845}
779 846
780pub fn implements_trait( 847pub fn implements_trait(
@@ -800,7 +867,7 @@ pub fn implements_trait_unique(
800 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 867 let goal = generic_implements_goal(db, env, trait_, ty.clone());
801 let solution = db.trait_solve(krate, goal); 868 let solution = db.trait_solve(krate, goal);
802 869
803 matches!(solution, Some(crate::traits::Solution::Unique(_))) 870 matches!(solution, Some(crate::Solution::Unique(_)))
804} 871}
805 872
806/// This creates Substs for a trait with the given Self type and type variables 873/// This creates Substs for a trait with the given Self type and type variables
@@ -826,7 +893,7 @@ fn generic_implements_goal(
826 let obligation = trait_ref.cast(&Interner); 893 let obligation = trait_ref.cast(&Interner);
827 Canonical { 894 Canonical {
828 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 895 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
829 value: InEnvironment::new(env.env.clone(), obligation), 896 value: InEnvironment::new(&env.env, obligation),
830 } 897 }
831} 898}
832 899
@@ -837,7 +904,9 @@ fn autoderef_method_receiver(
837) -> Vec<Canonical<Ty>> { 904) -> Vec<Canonical<Ty>> {
838 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); 905 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
839 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) 906 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
840 if let Some(TyKind::Array(parameters)) = deref_chain.last().map(|ty| ty.value.kind(&Interner)) { 907 if let Some(TyKind::Array(parameters, _)) =
908 deref_chain.last().map(|ty| ty.value.kind(&Interner))
909 {
841 let kinds = deref_chain.last().unwrap().binders.clone(); 910 let kinds = deref_chain.last().unwrap().binders.clone();
842 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner); 911 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner);
843 deref_chain.push(Canonical { value: unsized_ty, binders: kinds }) 912 deref_chain.push(Canonical { value: unsized_ty, binders: kinds })
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs
index 90dd31a35..0222de2bc 100644
--- a/crates/hir_ty/src/op.rs
+++ b/crates/hir_ty/src/op.rs
@@ -9,22 +9,56 @@ pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 9 BinaryOp::LogicOp(_) | BinaryOp::CmpOp(_) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
10 BinaryOp::Assignment { .. } => TyBuilder::unit(), 10 BinaryOp::Assignment { .. } => TyBuilder::unit(),
11 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { 11 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => {
12 match lhs_ty.kind(&Interner) { 12 // all integer combinations are valid here
13 if matches!(
14 lhs_ty.kind(&Interner),
13 TyKind::Scalar(Scalar::Int(_)) 15 TyKind::Scalar(Scalar::Int(_))
14 | TyKind::Scalar(Scalar::Uint(_)) 16 | TyKind::Scalar(Scalar::Uint(_))
15 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty, 17 | TyKind::InferenceVar(_, TyVariableKind::Integer)
16 TyKind::InferenceVar(_, TyVariableKind::Integer) 18 ) && matches!(
17 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, 19 rhs_ty.kind(&Interner),
18 _ => TyKind::Unknown.intern(&Interner), 20 TyKind::Scalar(Scalar::Int(_))
21 | TyKind::Scalar(Scalar::Uint(_))
22 | TyKind::InferenceVar(_, TyVariableKind::Integer)
23 ) {
24 lhs_ty
25 } else {
26 TyKind::Error.intern(&Interner)
19 } 27 }
20 } 28 }
21 BinaryOp::ArithOp(_) => match rhs_ty.kind(&Interner) { 29 BinaryOp::ArithOp(_) => match (lhs_ty.kind(&Interner), rhs_ty.kind(&Interner)) {
22 TyKind::Scalar(Scalar::Int(_)) 30 // (int, int) | (uint, uint) | (float, float)
23 | TyKind::Scalar(Scalar::Uint(_)) 31 (TyKind::Scalar(Scalar::Int(_)), TyKind::Scalar(Scalar::Int(_)))
24 | TyKind::Scalar(Scalar::Float(_)) => rhs_ty, 32 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::Scalar(Scalar::Uint(_)))
25 TyKind::InferenceVar(_, TyVariableKind::Integer) 33 | (TyKind::Scalar(Scalar::Float(_)), TyKind::Scalar(Scalar::Float(_))) => rhs_ty,
26 | TyKind::InferenceVar(_, TyVariableKind::Float) => rhs_ty, 34 // ({int}, int) | ({int}, uint)
27 _ => TyKind::Unknown.intern(&Interner), 35 (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Int(_)))
36 | (TyKind::InferenceVar(_, TyVariableKind::Integer), TyKind::Scalar(Scalar::Uint(_))) => {
37 rhs_ty
38 }
39 // (int, {int}) | (uint, {int})
40 (TyKind::Scalar(Scalar::Int(_)), TyKind::InferenceVar(_, TyVariableKind::Integer))
41 | (TyKind::Scalar(Scalar::Uint(_)), TyKind::InferenceVar(_, TyVariableKind::Integer)) => {
42 lhs_ty
43 }
44 // ({float} | float)
45 (TyKind::InferenceVar(_, TyVariableKind::Float), TyKind::Scalar(Scalar::Float(_))) => {
46 rhs_ty
47 }
48 // (float, {float})
49 (TyKind::Scalar(Scalar::Float(_)), TyKind::InferenceVar(_, TyVariableKind::Float)) => {
50 lhs_ty
51 }
52 // ({int}, {int}) | ({float}, {float})
53 (
54 TyKind::InferenceVar(_, TyVariableKind::Integer),
55 TyKind::InferenceVar(_, TyVariableKind::Integer),
56 )
57 | (
58 TyKind::InferenceVar(_, TyVariableKind::Float),
59 TyKind::InferenceVar(_, TyVariableKind::Float),
60 ) => rhs_ty,
61 _ => TyKind::Error.intern(&Interner),
28 }, 62 },
29 } 63 }
30} 64}
@@ -37,10 +71,10 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
37 TyKind::Scalar(_) | TyKind::Str => lhs_ty, 71 TyKind::Scalar(_) | TyKind::Str => lhs_ty,
38 TyKind::InferenceVar(_, TyVariableKind::Integer) 72 TyKind::InferenceVar(_, TyVariableKind::Integer)
39 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, 73 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
40 _ => TyKind::Unknown.intern(&Interner), 74 _ => TyKind::Error.intern(&Interner),
41 }, 75 },
42 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => { 76 BinaryOp::ArithOp(ArithOp::Shl) | BinaryOp::ArithOp(ArithOp::Shr) => {
43 TyKind::Unknown.intern(&Interner) 77 TyKind::Error.intern(&Interner)
44 } 78 }
45 BinaryOp::CmpOp(CmpOp::Ord { .. }) 79 BinaryOp::CmpOp(CmpOp::Ord { .. })
46 | BinaryOp::Assignment { op: Some(_) } 80 | BinaryOp::Assignment { op: Some(_) }
@@ -50,7 +84,7 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
50 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty, 84 | TyKind::Scalar(Scalar::Float(_)) => lhs_ty,
51 TyKind::InferenceVar(_, TyVariableKind::Integer) 85 TyKind::InferenceVar(_, TyVariableKind::Integer)
52 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty, 86 | TyKind::InferenceVar(_, TyVariableKind::Float) => lhs_ty,
53 _ => TyKind::Unknown.intern(&Interner), 87 _ => TyKind::Error.intern(&Interner),
54 }, 88 },
55 } 89 }
56} 90}
diff --git a/crates/hir_ty/src/primitive.rs b/crates/hir_ty/src/primitive.rs
index 2449addfb..d7f48c69a 100644
--- a/crates/hir_ty/src/primitive.rs
+++ b/crates/hir_ty/src/primitive.rs
@@ -1,7 +1,4 @@
1//! Defines primitive types, which have a couple of peculiarities: 1//! A few helper functions for dealing with primitives.
2//!
3//! * during type inference, they can be uncertain (ie, `let x = 92;`)
4//! * they don't belong to any particular crate.
5 2
6pub use chalk_ir::{FloatTy, IntTy, UintTy}; 3pub use chalk_ir::{FloatTy, IntTy, UintTy};
7pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint}; 4pub use hir_def::builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint};
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 86e3d8b86..6588aa46c 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -1065,12 +1065,211 @@ fn macro_in_arm() {
1065 } 1065 }
1066 "#, 1066 "#,
1067 expect![[r#" 1067 expect![[r#"
1068 !0..2 '()': ()
1068 51..110 '{ ... }; }': () 1069 51..110 '{ ... }; }': ()
1069 61..62 'x': u32 1070 61..62 'x': u32
1070 65..107 'match ... }': u32 1071 65..107 'match ... }': u32
1071 71..73 '()': () 1072 71..73 '()': ()
1072 84..91 'unit!()': ()
1073 95..100 '92u32': u32 1073 95..100 '92u32': u32
1074 "#]], 1074 "#]],
1075 ); 1075 );
1076} 1076}
1077
1078#[test]
1079fn macro_in_type_alias_position() {
1080 check_infer(
1081 r#"
1082 macro_rules! U32 {
1083 () => { u32 };
1084 }
1085
1086 trait Foo {
1087 type Ty;
1088 }
1089
1090 impl<T> Foo for T {
1091 type Ty = U32!();
1092 }
1093
1094 type TayTo = U32!();
1095
1096 fn testy() {
1097 let a: <() as Foo>::Ty;
1098 let b: TayTo;
1099 }
1100 "#,
1101 expect![[r#"
1102 147..196 '{ ...yTo; }': ()
1103 157..158 'a': u32
1104 185..186 'b': u32
1105 "#]],
1106 );
1107}
1108
1109#[test]
1110fn nested_macro_in_type_alias_position() {
1111 check_infer(
1112 r#"
1113 macro_rules! U32Inner2 {
1114 () => { u32 };
1115 }
1116
1117 macro_rules! U32Inner1 {
1118 () => { U32Inner2!() };
1119 }
1120
1121 macro_rules! U32 {
1122 () => { U32Inner1!() };
1123 }
1124
1125 trait Foo {
1126 type Ty;
1127 }
1128
1129 impl<T> Foo for T {
1130 type Ty = U32!();
1131 }
1132
1133 type TayTo = U32!();
1134
1135 fn testy() {
1136 let a: <() as Foo>::Ty;
1137 let b: TayTo;
1138 }
1139 "#,
1140 expect![[r#"
1141 259..308 '{ ...yTo; }': ()
1142 269..270 'a': u32
1143 297..298 'b': u32
1144 "#]],
1145 );
1146}
1147
1148#[test]
1149fn macros_in_type_alias_position_generics() {
1150 check_infer(
1151 r#"
1152 struct Foo<A, B>(A, B);
1153
1154 macro_rules! U32 {
1155 () => { u32 };
1156 }
1157
1158 macro_rules! Bar {
1159 () => { Foo<U32!(), U32!()> };
1160 }
1161
1162 trait Moo {
1163 type Ty;
1164 }
1165
1166 impl<T> Moo for T {
1167 type Ty = Bar!();
1168 }
1169
1170 type TayTo = Bar!();
1171
1172 fn main() {
1173 let a: <() as Moo>::Ty;
1174 let b: TayTo;
1175 }
1176 "#,
1177 expect![[r#"
1178 228..277 '{ ...yTo; }': ()
1179 238..239 'a': Foo<u32, u32>
1180 266..267 'b': Foo<u32, u32>
1181 "#]],
1182 );
1183}
1184
1185#[test]
1186fn macros_in_type_position() {
1187 check_infer(
1188 r#"
1189 struct Foo<A, B>(A, B);
1190
1191 macro_rules! U32 {
1192 () => { u32 };
1193 }
1194
1195 macro_rules! Bar {
1196 () => { Foo<U32!(), U32!()> };
1197 }
1198
1199 fn main() {
1200 let a: Bar!();
1201 }
1202 "#,
1203 expect![[r#"
1204 133..155 '{ ...!(); }': ()
1205 143..144 'a': Foo<u32, u32>
1206 "#]],
1207 );
1208}
1209
1210#[test]
1211fn macros_in_type_generics() {
1212 check_infer(
1213 r#"
1214 struct Foo<A, B>(A, B);
1215
1216 macro_rules! U32 {
1217 () => { u32 };
1218 }
1219
1220 macro_rules! Bar {
1221 () => { Foo<U32!(), U32!()> };
1222 }
1223
1224 trait Moo {
1225 type Ty;
1226 }
1227
1228 impl<T> Moo for T {
1229 type Ty = Foo<Bar!(), Bar!()>;
1230 }
1231
1232 type TayTo = Foo<Bar!(), U32!()>;
1233
1234 fn main() {
1235 let a: <() as Moo>::Ty;
1236 let b: TayTo;
1237 }
1238 "#,
1239 expect![[r#"
1240 254..303 '{ ...yTo; }': ()
1241 264..265 'a': Foo<Foo<u32, u32>, Foo<u32, u32>>
1242 292..293 'b': Foo<Foo<u32, u32>, u32>
1243 "#]],
1244 );
1245}
1246
1247#[test]
1248fn infinitely_recursive_macro_type() {
1249 check_infer(
1250 r#"
1251 struct Bar<T, X>(T, X);
1252
1253 macro_rules! Foo {
1254 () => { Foo!() }
1255 }
1256
1257 macro_rules! U32 {
1258 () => { u32 }
1259 }
1260
1261 type A = Foo!();
1262 type B = Bar<Foo!(), U32!()>;
1263
1264 fn main() {
1265 let a: A;
1266 let b: B;
1267 }
1268 "#,
1269 expect![[r#"
1270 166..197 '{ ...: B; }': ()
1271 176..177 'a': {unknown}
1272 190..191 'b': Bar<{unknown}, u32>
1273 "#]],
1274 );
1275}
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 61f18b0d2..a4c132bc5 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1292,3 +1292,60 @@ mod b {
1292 "#]], 1292 "#]],
1293 ) 1293 )
1294} 1294}
1295
1296#[test]
1297fn trait_impl_in_unnamed_const() {
1298 check_types(
1299 r#"
1300struct S;
1301
1302trait Tr {
1303 fn method(&self) -> u16;
1304}
1305
1306const _: () = {
1307 impl Tr for S {}
1308};
1309
1310fn f() {
1311 S.method();
1312 //^^^^^^^^^^ u16
1313}
1314 "#,
1315 );
1316}
1317
1318#[test]
1319fn inherent_impl_in_unnamed_const() {
1320 check_types(
1321 r#"
1322struct S;
1323
1324const _: () = {
1325 impl S {
1326 fn method(&self) -> u16 { 0 }
1327
1328 pub(super) fn super_method(&self) -> u16 { 0 }
1329
1330 pub(crate) fn crate_method(&self) -> u16 { 0 }
1331
1332 pub fn pub_method(&self) -> u16 { 0 }
1333 }
1334};
1335
1336fn f() {
1337 S.method();
1338 //^^^^^^^^^^ u16
1339
1340 S.super_method();
1341 //^^^^^^^^^^^^^^^^ u16
1342
1343 S.crate_method();
1344 //^^^^^^^^^^^^^^^^ u16
1345
1346 S.pub_method();
1347 //^^^^^^^^^^^^^^ u16
1348}
1349 "#,
1350 );
1351}
diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs
index 85a28e76b..f514b3efe 100644
--- a/crates/hir_ty/src/tests/patterns.rs
+++ b/crates/hir_ty/src/tests/patterns.rs
@@ -1,6 +1,6 @@
1use expect_test::expect; 1use expect_test::expect;
2 2
3use super::{check_infer, check_infer_with_mismatches}; 3use super::{check_infer, check_infer_with_mismatches, check_types};
4 4
5#[test] 5#[test]
6fn infer_pattern() { 6fn infer_pattern() {
@@ -825,3 +825,29 @@ fn foo(foo: Foo) {
825 "#]], 825 "#]],
826 ); 826 );
827} 827}
828
829#[test]
830fn macro_pat() {
831 check_types(
832 r#"
833macro_rules! pat {
834 ($name:ident) => { Enum::Variant1($name) }
835}
836
837enum Enum {
838 Variant1(u8),
839 Variant2,
840}
841
842fn f(e: Enum) {
843 match e {
844 pat!(bind) => {
845 bind;
846 //^^^^ u8
847 }
848 Enum::Variant2 => {}
849 }
850}
851 "#,
852 )
853}
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index b69f86050..9cd9f473d 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -974,3 +974,41 @@ fn param_overrides_fn() {
974 "#, 974 "#,
975 ) 975 )
976} 976}
977
978#[test]
979fn lifetime_from_chalk_during_deref() {
980 check_types(
981 r#"
982 #[lang = "deref"]
983 pub trait Deref {
984 type Target;
985 }
986
987 struct Box<T: ?Sized> {}
988 impl<T> Deref for Box<T> {
989 type Target = T;
990
991 fn deref(&self) -> &Self::Target {
992 loop {}
993 }
994 }
995
996 trait Iterator {
997 type Item;
998 }
999
1000 pub struct Iter<'a, T: 'a> {
1001 inner: Box<dyn IterTrait<'a, T, Item = &'a T> + 'a>,
1002 }
1003
1004 trait IterTrait<'a, T: 'a>: Iterator<Item = &'a T> {
1005 fn clone_box(&self);
1006 }
1007
1008 fn clone_iter<T>(s: Iter<T>) {
1009 s.inner.clone_box();
1010 //^^^^^^^^^^^^^^^^^^^ ()
1011 }
1012 "#,
1013 )
1014}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 361cd6302..5948d0bc2 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1765,6 +1765,24 @@ fn main() {
1765} 1765}
1766 1766
1767#[test] 1767#[test]
1768fn shadowing_primitive_with_inner_items() {
1769 check_types(
1770 r#"
1771struct i32;
1772struct Foo;
1773
1774impl i32 { fn foo(&self) -> Foo { Foo } }
1775
1776fn main() {
1777 fn inner() {}
1778 let x: i32 = i32;
1779 x.foo();
1780 //^ Foo
1781}"#,
1782 );
1783}
1784
1785#[test]
1768fn not_shadowing_primitive_by_module() { 1786fn not_shadowing_primitive_by_module() {
1769 check_types( 1787 check_types(
1770 r#" 1788 r#"
@@ -2564,3 +2582,36 @@ fn f() {
2564 "#, 2582 "#,
2565 ) 2583 )
2566} 2584}
2585
2586#[test]
2587fn infer_type_alias_variant() {
2588 check_infer(
2589 r#"
2590type Qux = Foo;
2591enum Foo {
2592 Bar(i32),
2593 Baz { baz: f32 }
2594}
2595
2596fn f() {
2597 match Foo::Bar(3) {
2598 Qux::Bar(bar) => (),
2599 Qux::Baz { baz } => (),
2600 }
2601}
2602 "#,
2603 expect![[r#"
2604 72..166 '{ ... } }': ()
2605 78..164 'match ... }': ()
2606 84..92 'Foo::Bar': Bar(i32) -> Foo
2607 84..95 'Foo::Bar(3)': Foo
2608 93..94 '3': i32
2609 106..119 'Qux::Bar(bar)': Foo
2610 115..118 'bar': i32
2611 123..125 '()': ()
2612 135..151 'Qux::B... baz }': Foo
2613 146..149 'baz': f32
2614 155..157 '()': ()
2615 "#]],
2616 )
2617}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 65b71fdfa..ffc7c8ef4 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -263,15 +263,14 @@ mod ops {
263fn infer_from_bound_1() { 263fn infer_from_bound_1() {
264 check_infer( 264 check_infer(
265 r#" 265 r#"
266 trait Trait<T> {} 266trait Trait<T> {}
267 struct S<T>(T); 267struct S<T>(T);
268 impl<U> Trait<U> for S<U> {} 268impl<U> Trait<U> for S<U> {}
269 fn foo<T: Trait<u32>>(t: T) {} 269fn foo<T: Trait<u32>>(t: T) {}
270 fn test() { 270fn test() {
271 let s = S(unknown); 271 let s = S(unknown);
272 foo(s); 272 foo(s);
273 } 273}"#,
274 "#,
275 expect![[r#" 274 expect![[r#"
276 85..86 't': T 275 85..86 't': T
277 91..93 '{}': () 276 91..93 '{}': ()
@@ -291,15 +290,14 @@ fn infer_from_bound_1() {
291fn infer_from_bound_2() { 290fn infer_from_bound_2() {
292 check_infer( 291 check_infer(
293 r#" 292 r#"
294 trait Trait<T> {} 293trait Trait<T> {}
295 struct S<T>(T); 294struct S<T>(T);
296 impl<U> Trait<U> for S<U> {} 295impl<U> Trait<U> for S<U> {}
297 fn foo<U, T: Trait<U>>(t: T) -> U {} 296fn foo<U, T: Trait<U>>(t: T) -> U {}
298 fn test() { 297fn test() {
299 let s = S(unknown); 298 let s = S(unknown);
300 let x: u32 = foo(s); 299 let x: u32 = foo(s);
301 } 300}"#,
302 "#,
303 expect![[r#" 301 expect![[r#"
304 86..87 't': T 302 86..87 't': T
305 97..99 '{}': () 303 97..99 '{}': ()
@@ -321,13 +319,12 @@ fn trait_default_method_self_bound_implements_trait() {
321 cov_mark::check!(trait_self_implements_self); 319 cov_mark::check!(trait_self_implements_self);
322 check_infer( 320 check_infer(
323 r#" 321 r#"
324 trait Trait { 322trait Trait {
325 fn foo(&self) -> i64; 323 fn foo(&self) -> i64;
326 fn bar(&self) -> { 324 fn bar(&self) -> {
327 let x = self.foo(); 325 let x = self.foo();
328 } 326 }
329 } 327}"#,
330 "#,
331 expect![[r#" 328 expect![[r#"
332 26..30 'self': &Self 329 26..30 'self': &Self
333 52..56 'self': &Self 330 52..56 'self': &Self
@@ -343,15 +340,14 @@ fn trait_default_method_self_bound_implements_trait() {
343fn trait_default_method_self_bound_implements_super_trait() { 340fn trait_default_method_self_bound_implements_super_trait() {
344 check_infer( 341 check_infer(
345 r#" 342 r#"
346 trait SuperTrait { 343trait SuperTrait {
347 fn foo(&self) -> i64; 344 fn foo(&self) -> i64;
348 } 345}
349 trait Trait: SuperTrait { 346trait Trait: SuperTrait {
350 fn bar(&self) -> { 347 fn bar(&self) -> {
351 let x = self.foo(); 348 let x = self.foo();
352 } 349 }
353 } 350}"#,
354 "#,
355 expect![[r#" 351 expect![[r#"
356 31..35 'self': &Self 352 31..35 'self': &Self
357 85..89 'self': &Self 353 85..89 'self': &Self
@@ -367,18 +363,17 @@ fn trait_default_method_self_bound_implements_super_trait() {
367fn infer_project_associated_type() { 363fn infer_project_associated_type() {
368 check_infer( 364 check_infer(
369 r#" 365 r#"
370 trait Iterable { 366trait Iterable {
371 type Item; 367 type Item;
372 } 368}
373 struct S; 369struct S;
374 impl Iterable for S { type Item = u32; } 370impl Iterable for S { type Item = u32; }
375 fn test<T: Iterable>() { 371fn test<T: Iterable>() {
376 let x: <S as Iterable>::Item = 1; 372 let x: <S as Iterable>::Item = 1;
377 let y: <T as Iterable>::Item = no_matter; 373 let y: <T as Iterable>::Item = no_matter;
378 let z: T::Item = no_matter; 374 let z: T::Item = no_matter;
379 let a: <T>::Item = no_matter; 375 let a: <T>::Item = no_matter;
380 } 376}"#,
381 "#,
382 expect![[r#" 377 expect![[r#"
383 108..261 '{ ...ter; }': () 378 108..261 '{ ...ter; }': ()
384 118..119 'x': u32 379 118..119 'x': u32
@@ -397,20 +392,19 @@ fn infer_project_associated_type() {
397fn infer_return_associated_type() { 392fn infer_return_associated_type() {
398 check_infer( 393 check_infer(
399 r#" 394 r#"
400 trait Iterable { 395trait Iterable {
401 type Item; 396 type Item;
402 } 397}
403 struct S; 398struct S;
404 impl Iterable for S { type Item = u32; } 399impl Iterable for S { type Item = u32; }
405 fn foo1<T: Iterable>(t: T) -> T::Item {} 400fn foo1<T: Iterable>(t: T) -> T::Item {}
406 fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {} 401fn foo2<T: Iterable>(t: T) -> <T as Iterable>::Item {}
407 fn foo3<T: Iterable>(t: T) -> <T>::Item {} 402fn foo3<T: Iterable>(t: T) -> <T>::Item {}
408 fn test() { 403fn test() {
409 let x = foo1(S); 404 let x = foo1(S);
410 let y = foo2(S); 405 let y = foo2(S);
411 let z = foo3(S); 406 let z = foo3(S);
412 } 407}"#,
413 "#,
414 expect![[r#" 408 expect![[r#"
415 106..107 't': T 409 106..107 't': T
416 123..125 '{}': () 410 123..125 '{}': ()
@@ -439,13 +433,12 @@ fn infer_return_associated_type() {
439fn infer_associated_type_bound() { 433fn infer_associated_type_bound() {
440 check_infer( 434 check_infer(
441 r#" 435 r#"
442 trait Iterable { 436trait Iterable {
443 type Item; 437 type Item;
444 } 438}
445 fn test<T: Iterable<Item=u32>>() { 439fn test<T: Iterable<Item=u32>>() {
446 let y: T::Item = unknown; 440 let y: T::Item = unknown;
447 } 441}"#,
448 "#,
449 expect![[r#" 442 expect![[r#"
450 67..100 '{ ...own; }': () 443 67..100 '{ ...own; }': ()
451 77..78 'y': u32 444 77..78 'y': u32
@@ -458,9 +451,8 @@ fn infer_associated_type_bound() {
458fn infer_const_body() { 451fn infer_const_body() {
459 check_infer( 452 check_infer(
460 r#" 453 r#"
461 const A: u32 = 1 + 1; 454const A: u32 = 1 + 1;
462 static B: u64 = { let x = 1; x }; 455static B: u64 = { let x = 1; x };"#,
463 "#,
464 expect![[r#" 456 expect![[r#"
465 15..16 '1': u32 457 15..16 '1': u32
466 15..20 '1 + 1': u32 458 15..20 '1 + 1': u32
@@ -477,13 +469,12 @@ fn infer_const_body() {
477fn tuple_struct_fields() { 469fn tuple_struct_fields() {
478 check_infer( 470 check_infer(
479 r#" 471 r#"
480 struct S(i32, u64); 472struct S(i32, u64);
481 fn test() -> u64 { 473fn test() -> u64 {
482 let a = S(4, 6); 474 let a = S(4, 6);
483 let b = a.0; 475 let b = a.0;
484 a.1 476 a.1
485 } 477}"#,
486 "#,
487 expect![[r#" 478 expect![[r#"
488 37..86 '{ ... a.1 }': u64 479 37..86 '{ ... a.1 }': u64
489 47..48 'a': S 480 47..48 'a': S
@@ -504,13 +495,12 @@ fn tuple_struct_fields() {
504fn tuple_struct_with_fn() { 495fn tuple_struct_with_fn() {
505 check_infer( 496 check_infer(
506 r#" 497 r#"
507 struct S(fn(u32) -> u64); 498struct S(fn(u32) -> u64);
508 fn test() -> u64 { 499fn test() -> u64 {
509 let a = S(|i| 2*i); 500 let a = S(|i| 2*i);
510 let b = a.0(4); 501 let b = a.0(4);
511 a.0(2) 502 a.0(2)
512 } 503}"#,
513 "#,
514 expect![[r#" 504 expect![[r#"
515 43..101 '{ ...0(2) }': u64 505 43..101 '{ ...0(2) }': u64
516 53..54 'a': S 506 53..54 'a': S
@@ -949,27 +939,26 @@ fn test<T: ApplyL>(t: T) {
949fn argument_impl_trait() { 939fn argument_impl_trait() {
950 check_infer_with_mismatches( 940 check_infer_with_mismatches(
951 r#" 941 r#"
952 trait Trait<T> { 942trait Trait<T> {
953 fn foo(&self) -> T; 943 fn foo(&self) -> T;
954 fn foo2(&self) -> i64; 944 fn foo2(&self) -> i64;
955 } 945}
956 fn bar(x: impl Trait<u16>) {} 946fn bar(x: impl Trait<u16>) {}
957 struct S<T>(T); 947struct S<T>(T);
958 impl<T> Trait<T> for S<T> {} 948impl<T> Trait<T> for S<T> {}
959 949
960 fn test(x: impl Trait<u64>, y: &impl Trait<u32>) { 950fn test(x: impl Trait<u64>, y: &impl Trait<u32>) {
961 x; 951 x;
962 y; 952 y;
963 let z = S(1); 953 let z = S(1);
964 bar(z); 954 bar(z);
965 x.foo(); 955 x.foo();
966 y.foo(); 956 y.foo();
967 z.foo(); 957 z.foo();
968 x.foo2(); 958 x.foo2();
969 y.foo2(); 959 y.foo2();
970 z.foo2(); 960 z.foo2();
971 } 961}"#,
972 "#,
973 expect![[r#" 962 expect![[r#"
974 29..33 'self': &Self 963 29..33 'self': &Self
975 54..58 'self': &Self 964 54..58 'self': &Self
@@ -1007,30 +996,29 @@ fn argument_impl_trait() {
1007fn argument_impl_trait_type_args_1() { 996fn argument_impl_trait_type_args_1() {
1008 check_infer_with_mismatches( 997 check_infer_with_mismatches(
1009 r#" 998 r#"
1010 trait Trait {} 999trait Trait {}
1011 trait Foo { 1000trait Foo {
1012 // this function has an implicit Self param, an explicit type param, 1001 // this function has an implicit Self param, an explicit type param,
1013 // and an implicit impl Trait param! 1002 // and an implicit impl Trait param!
1014 fn bar<T>(x: impl Trait) -> T { loop {} } 1003 fn bar<T>(x: impl Trait) -> T { loop {} }
1015 } 1004}
1016 fn foo<T>(x: impl Trait) -> T { loop {} } 1005fn foo<T>(x: impl Trait) -> T { loop {} }
1017 struct S; 1006struct S;
1018 impl Trait for S {} 1007impl Trait for S {}
1019 struct F; 1008struct F;
1020 impl Foo for F {} 1009impl Foo for F {}
1021 1010
1022 fn test() { 1011fn test() {
1023 Foo::bar(S); 1012 Foo::bar(S);
1024 <F as Foo>::bar(S); 1013 <F as Foo>::bar(S);
1025 F::bar(S); 1014 F::bar(S);
1026 Foo::bar::<u32>(S); 1015 Foo::bar::<u32>(S);
1027 <F as Foo>::bar::<u32>(S); 1016 <F as Foo>::bar::<u32>(S);
1028 1017
1029 foo(S); 1018 foo(S);
1030 foo::<u32>(S); 1019 foo::<u32>(S);
1031 foo::<u32, i32>(S); // we should ignore the extraneous i32 1020 foo::<u32, i32>(S); // we should ignore the extraneous i32
1032 } 1021}"#,
1033 "#,
1034 expect![[r#" 1022 expect![[r#"
1035 155..156 'x': impl Trait 1023 155..156 'x': impl Trait
1036 175..186 '{ loop {} }': T 1024 175..186 '{ loop {} }': T
@@ -1073,21 +1061,20 @@ fn argument_impl_trait_type_args_1() {
1073fn argument_impl_trait_type_args_2() { 1061fn argument_impl_trait_type_args_2() {
1074 check_infer_with_mismatches( 1062 check_infer_with_mismatches(
1075 r#" 1063 r#"
1076 trait Trait {} 1064trait Trait {}
1077 struct S; 1065struct S;
1078 impl Trait for S {} 1066impl Trait for S {}
1079 struct F<T>; 1067struct F<T>;
1080 impl<T> F<T> { 1068impl<T> F<T> {
1081 fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} } 1069 fn foo<U>(self, x: impl Trait) -> (T, U) { loop {} }
1082 } 1070}
1083 1071
1084 fn test() { 1072fn test() {
1085 F.foo(S); 1073 F.foo(S);
1086 F::<u32>.foo(S); 1074 F::<u32>.foo(S);
1087 F::<u32>.foo::<i32>(S); 1075 F::<u32>.foo::<i32>(S);
1088 F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored 1076 F::<u32>.foo::<i32, u32>(S); // extraneous argument should be ignored
1089 } 1077}"#,
1090 "#,
1091 expect![[r#" 1078 expect![[r#"
1092 87..91 'self': F<T> 1079 87..91 'self': F<T>
1093 93..94 'x': impl Trait 1080 93..94 'x': impl Trait
@@ -1115,15 +1102,14 @@ fn argument_impl_trait_type_args_2() {
1115fn argument_impl_trait_to_fn_pointer() { 1102fn argument_impl_trait_to_fn_pointer() {
1116 check_infer_with_mismatches( 1103 check_infer_with_mismatches(
1117 r#" 1104 r#"
1118 trait Trait {} 1105trait Trait {}
1119 fn foo(x: impl Trait) { loop {} } 1106fn foo(x: impl Trait) { loop {} }
1120 struct S; 1107struct S;
1121 impl Trait for S {} 1108impl Trait for S {}
1122 1109
1123 fn test() { 1110fn test() {
1124 let f: fn(S) -> () = foo; 1111 let f: fn(S) -> () = foo;
1125 } 1112}"#,
1126 "#,
1127 expect![[r#" 1113 expect![[r#"
1128 22..23 'x': impl Trait 1114 22..23 'x': impl Trait
1129 37..48 '{ loop {} }': () 1115 37..48 '{ loop {} }': ()
@@ -1140,24 +1126,23 @@ fn argument_impl_trait_to_fn_pointer() {
1140fn impl_trait() { 1126fn impl_trait() {
1141 check_infer( 1127 check_infer(
1142 r#" 1128 r#"
1143 trait Trait<T> { 1129trait Trait<T> {
1144 fn foo(&self) -> T; 1130 fn foo(&self) -> T;
1145 fn foo2(&self) -> i64; 1131 fn foo2(&self) -> i64;
1146 } 1132}
1147 fn bar() -> impl Trait<u64> {} 1133fn bar() -> impl Trait<u64> {}
1148 1134
1149 fn test(x: impl Trait<u64>, y: &impl Trait<u64>) { 1135fn test(x: impl Trait<u64>, y: &impl Trait<u64>) {
1150 x; 1136 x;
1151 y; 1137 y;
1152 let z = bar(); 1138 let z = bar();
1153 x.foo(); 1139 x.foo();
1154 y.foo(); 1140 y.foo();
1155 z.foo(); 1141 z.foo();
1156 x.foo2(); 1142 x.foo2();
1157 y.foo2(); 1143 y.foo2();
1158 z.foo2(); 1144 z.foo2();
1159 } 1145}"#,
1160 "#,
1161 expect![[r#" 1146 expect![[r#"
1162 29..33 'self': &Self 1147 29..33 'self': &Self
1163 54..58 'self': &Self 1148 54..58 'self': &Self
@@ -1191,16 +1176,15 @@ fn simple_return_pos_impl_trait() {
1191 cov_mark::check!(lower_rpit); 1176 cov_mark::check!(lower_rpit);
1192 check_infer( 1177 check_infer(
1193 r#" 1178 r#"
1194 trait Trait<T> { 1179trait Trait<T> {
1195 fn foo(&self) -> T; 1180 fn foo(&self) -> T;
1196 } 1181}
1197 fn bar() -> impl Trait<u64> { loop {} } 1182fn bar() -> impl Trait<u64> { loop {} }
1198 1183
1199 fn test() { 1184fn test() {
1200 let a = bar(); 1185 let a = bar();
1201 a.foo(); 1186 a.foo();
1202 } 1187}"#,
1203 "#,
1204 expect![[r#" 1188 expect![[r#"
1205 29..33 'self': &Self 1189 29..33 'self': &Self
1206 71..82 '{ loop {} }': ! 1190 71..82 '{ loop {} }': !
@@ -1220,25 +1204,24 @@ fn simple_return_pos_impl_trait() {
1220fn more_return_pos_impl_trait() { 1204fn more_return_pos_impl_trait() {
1221 check_infer( 1205 check_infer(
1222 r#" 1206 r#"
1223 trait Iterator { 1207trait Iterator {
1224 type Item; 1208 type Item;
1225 fn next(&mut self) -> Self::Item; 1209 fn next(&mut self) -> Self::Item;
1226 } 1210}
1227 trait Trait<T> { 1211trait Trait<T> {
1228 fn foo(&self) -> T; 1212 fn foo(&self) -> T;
1229 } 1213}
1230 fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} } 1214fn bar() -> (impl Iterator<Item = impl Trait<u32>>, impl Trait<u64>) { loop {} }
1231 fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} } 1215fn baz<T>(t: T) -> (impl Iterator<Item = impl Trait<T>>, impl Trait<T>) { loop {} }
1232 1216
1233 fn test() { 1217fn test() {
1234 let (a, b) = bar(); 1218 let (a, b) = bar();
1235 a.next().foo(); 1219 a.next().foo();
1236 b.foo(); 1220 b.foo();
1237 let (c, d) = baz(1u128); 1221 let (c, d) = baz(1u128);
1238 c.next().foo(); 1222 c.next().foo();
1239 d.foo(); 1223 d.foo();
1240 } 1224}"#,
1241 "#,
1242 expect![[r#" 1225 expect![[r#"
1243 49..53 'self': &mut Self 1226 49..53 'self': &mut Self
1244 101..105 'self': &Self 1227 101..105 'self': &Self
@@ -1279,24 +1262,23 @@ fn more_return_pos_impl_trait() {
1279fn dyn_trait() { 1262fn dyn_trait() {
1280 check_infer( 1263 check_infer(
1281 r#" 1264 r#"
1282 trait Trait<T> { 1265trait Trait<T> {
1283 fn foo(&self) -> T; 1266 fn foo(&self) -> T;
1284 fn foo2(&self) -> i64; 1267 fn foo2(&self) -> i64;
1285 } 1268}
1286 fn bar() -> dyn Trait<u64> {} 1269fn bar() -> dyn Trait<u64> {}
1287 1270
1288 fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) { 1271fn test(x: dyn Trait<u64>, y: &dyn Trait<u64>) {
1289 x; 1272 x;
1290 y; 1273 y;
1291 let z = bar(); 1274 let z = bar();
1292 x.foo(); 1275 x.foo();
1293 y.foo(); 1276 y.foo();
1294 z.foo(); 1277 z.foo();
1295 x.foo2(); 1278 x.foo2();
1296 y.foo2(); 1279 y.foo2();
1297 z.foo2(); 1280 z.foo2();
1298 } 1281}"#,
1299 "#,
1300 expect![[r#" 1282 expect![[r#"
1301 29..33 'self': &Self 1283 29..33 'self': &Self
1302 54..58 'self': &Self 1284 54..58 'self': &Self
@@ -1329,22 +1311,21 @@ fn dyn_trait() {
1329fn dyn_trait_in_impl() { 1311fn dyn_trait_in_impl() {
1330 check_infer( 1312 check_infer(
1331 r#" 1313 r#"
1332 trait Trait<T, U> { 1314trait Trait<T, U> {
1333 fn foo(&self) -> (T, U); 1315 fn foo(&self) -> (T, U);
1334 } 1316}
1335 struct S<T, U> {} 1317struct S<T, U> {}
1336 impl<T, U> S<T, U> { 1318impl<T, U> S<T, U> {
1337 fn bar(&self) -> &dyn Trait<T, U> { loop {} } 1319 fn bar(&self) -> &dyn Trait<T, U> { loop {} }
1338 } 1320}
1339 trait Trait2<T, U> { 1321trait Trait2<T, U> {
1340 fn baz(&self) -> (T, U); 1322 fn baz(&self) -> (T, U);
1341 } 1323}
1342 impl<T, U> Trait2<T, U> for dyn Trait<T, U> { } 1324impl<T, U> Trait2<T, U> for dyn Trait<T, U> { }
1343 1325
1344 fn test(s: S<u32, i32>) { 1326fn test(s: S<u32, i32>) {
1345 s.bar().baz(); 1327 s.bar().baz();
1346 } 1328}"#,
1347 "#,
1348 expect![[r#" 1329 expect![[r#"
1349 32..36 'self': &Self 1330 32..36 'self': &Self
1350 102..106 'self': &S<T, U> 1331 102..106 'self': &S<T, U>
@@ -1365,20 +1346,19 @@ fn dyn_trait_in_impl() {
1365fn dyn_trait_bare() { 1346fn dyn_trait_bare() {
1366 check_infer( 1347 check_infer(
1367 r#" 1348 r#"
1368 trait Trait { 1349trait Trait {
1369 fn foo(&self) -> u64; 1350 fn foo(&self) -> u64;
1370 } 1351}
1371 fn bar() -> Trait {} 1352fn bar() -> Trait {}
1372 1353
1373 fn test(x: Trait, y: &Trait) -> u64 { 1354fn test(x: Trait, y: &Trait) -> u64 {
1374 x; 1355 x;
1375 y; 1356 y;
1376 let z = bar(); 1357 let z = bar();
1377 x.foo(); 1358 x.foo();
1378 y.foo(); 1359 y.foo();
1379 z.foo(); 1360 z.foo();
1380 } 1361}"#,
1381 "#,
1382 expect![[r#" 1362 expect![[r#"
1383 26..30 'self': &Self 1363 26..30 'self': &Self
1384 60..62 '{}': () 1364 60..62 '{}': ()
@@ -1404,17 +1384,24 @@ fn dyn_trait_bare() {
1404fn weird_bounds() { 1384fn weird_bounds() {
1405 check_infer( 1385 check_infer(
1406 r#" 1386 r#"
1407 trait Trait {} 1387trait Trait {}
1408 fn test(a: impl Trait + 'lifetime, b: impl 'lifetime, c: impl (Trait), d: impl ('lifetime), e: impl ?Sized, f: impl Trait + ?Sized) {} 1388fn test(
1409 "#, 1389 a: impl Trait + 'lifetime,
1390 b: impl 'lifetime,
1391 c: impl (Trait),
1392 d: impl ('lifetime),
1393 e: impl ?Sized,
1394 f: impl Trait + ?Sized
1395) {}
1396"#,
1410 expect![[r#" 1397 expect![[r#"
1411 23..24 'a': impl Trait 1398 28..29 'a': impl Trait
1412 50..51 'b': impl 1399 59..60 'b': impl
1413 69..70 'c': impl Trait 1400 82..83 'c': impl Trait
1414 86..87 'd': impl 1401 103..104 'd': impl
1415 107..108 'e': impl 1402 128..129 'e': impl
1416 123..124 'f': impl Trait 1403 148..149 'f': impl Trait
1417 147..149 '{}': () 1404 173..175 '{}': ()
1418 "#]], 1405 "#]],
1419 ); 1406 );
1420} 1407}
@@ -1439,27 +1426,26 @@ fn test(x: (impl Trait + UnknownTrait)) {
1439fn assoc_type_bindings() { 1426fn assoc_type_bindings() {
1440 check_infer( 1427 check_infer(
1441 r#" 1428 r#"
1442 trait Trait { 1429trait Trait {
1443 type Type; 1430 type Type;
1444 } 1431}
1445 1432
1446 fn get<T: Trait>(t: T) -> <T as Trait>::Type {} 1433fn get<T: Trait>(t: T) -> <T as Trait>::Type {}
1447 fn get2<U, T: Trait<Type = U>>(t: T) -> U {} 1434fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1448 fn set<T: Trait<Type = u64>>(t: T) -> T {t} 1435fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1449 1436
1450 struct S<T>; 1437struct S<T>;
1451 impl<T> Trait for S<T> { type Type = T; } 1438impl<T> Trait for S<T> { type Type = T; }
1452 1439
1453 fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) { 1440fn test<T: Trait<Type = u32>>(x: T, y: impl Trait<Type = i64>) {
1454 get(x); 1441 get(x);
1455 get2(x); 1442 get2(x);
1456 get(y); 1443 get(y);
1457 get2(y); 1444 get2(y);
1458 get(set(S)); 1445 get(set(S));
1459 get2(set(S)); 1446 get2(set(S));
1460 get2(S::<str>); 1447 get2(S::<str>);
1461 } 1448}"#,
1462 "#,
1463 expect![[r#" 1449 expect![[r#"
1464 49..50 't': T 1450 49..50 't': T
1465 77..79 '{}': () 1451 77..79 '{}': ()
@@ -1546,18 +1532,17 @@ mod iter {
1546fn projection_eq_within_chalk() { 1532fn projection_eq_within_chalk() {
1547 check_infer( 1533 check_infer(
1548 r#" 1534 r#"
1549 trait Trait1 { 1535trait Trait1 {
1550 type Type; 1536 type Type;
1551 } 1537}
1552 trait Trait2<T> { 1538trait Trait2<T> {
1553 fn foo(self) -> T; 1539 fn foo(self) -> T;
1554 } 1540}
1555 impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {} 1541impl<T, U> Trait2<T> for U where U: Trait1<Type = T> {}
1556 1542
1557 fn test<T: Trait1<Type = u32>>(x: T) { 1543fn test<T: Trait1<Type = u32>>(x: T) {
1558 x.foo(); 1544 x.foo();
1559 } 1545}"#,
1560 "#,
1561 expect![[r#" 1546 expect![[r#"
1562 61..65 'self': Self 1547 61..65 'self': Self
1563 163..164 'x': T 1548 163..164 'x': T
@@ -1589,19 +1574,18 @@ fn test<T: foo::Trait>(x: T) {
1589fn super_trait_method_resolution() { 1574fn super_trait_method_resolution() {
1590 check_infer( 1575 check_infer(
1591 r#" 1576 r#"
1592 mod foo { 1577mod foo {
1593 trait SuperTrait { 1578 trait SuperTrait {
1594 fn foo(&self) -> u32 {} 1579 fn foo(&self) -> u32 {}
1595 } 1580 }
1596 } 1581}
1597 trait Trait1: foo::SuperTrait {} 1582trait Trait1: foo::SuperTrait {}
1598 trait Trait2 where Self: foo::SuperTrait {} 1583trait Trait2 where Self: foo::SuperTrait {}
1599 1584
1600 fn test<T: Trait1, U: Trait2>(x: T, y: U) { 1585fn test<T: Trait1, U: Trait2>(x: T, y: U) {
1601 x.foo(); 1586 x.foo();
1602 y.foo(); 1587 y.foo();
1603 } 1588}"#,
1604 "#,
1605 expect![[r#" 1589 expect![[r#"
1606 49..53 'self': &Self 1590 49..53 'self': &Self
1607 62..64 '{}': () 1591 62..64 '{}': ()
@@ -1620,17 +1604,16 @@ fn super_trait_method_resolution() {
1620fn super_trait_impl_trait_method_resolution() { 1604fn super_trait_impl_trait_method_resolution() {
1621 check_infer( 1605 check_infer(
1622 r#" 1606 r#"
1623 mod foo { 1607mod foo {
1624 trait SuperTrait { 1608 trait SuperTrait {
1625 fn foo(&self) -> u32 {} 1609 fn foo(&self) -> u32 {}
1626 } 1610 }
1627 } 1611}
1628 trait Trait1: foo::SuperTrait {} 1612trait Trait1: foo::SuperTrait {}
1629 1613
1630 fn test(x: &impl Trait1) { 1614fn test(x: &impl Trait1) {
1631 x.foo(); 1615 x.foo();
1632 } 1616}"#,
1633 "#,
1634 expect![[r#" 1617 expect![[r#"
1635 49..53 'self': &Self 1618 49..53 'self': &Self
1636 62..64 '{}': () 1619 62..64 '{}': ()
@@ -1667,20 +1650,19 @@ fn super_trait_cycle() {
1667fn super_trait_assoc_type_bounds() { 1650fn super_trait_assoc_type_bounds() {
1668 check_infer( 1651 check_infer(
1669 r#" 1652 r#"
1670 trait SuperTrait { type Type; } 1653trait SuperTrait { type Type; }
1671 trait Trait where Self: SuperTrait {} 1654trait Trait where Self: SuperTrait {}
1672 1655
1673 fn get2<U, T: Trait<Type = U>>(t: T) -> U {} 1656fn get2<U, T: Trait<Type = U>>(t: T) -> U {}
1674 fn set<T: Trait<Type = u64>>(t: T) -> T {t} 1657fn set<T: Trait<Type = u64>>(t: T) -> T {t}
1675 1658
1676 struct S<T>; 1659struct S<T>;
1677 impl<T> SuperTrait for S<T> { type Type = T; } 1660impl<T> SuperTrait for S<T> { type Type = T; }
1678 impl<T> Trait for S<T> {} 1661impl<T> Trait for S<T> {}
1679 1662
1680 fn test() { 1663fn test() {
1681 get2(set(S)); 1664 get2(set(S));
1682 } 1665}"#,
1683 "#,
1684 expect![[r#" 1666 expect![[r#"
1685 102..103 't': T 1667 102..103 't': T
1686 113..115 '{}': () 1668 113..115 '{}': ()
@@ -1701,16 +1683,15 @@ fn super_trait_assoc_type_bounds() {
1701fn fn_trait() { 1683fn fn_trait() {
1702 check_infer_with_mismatches( 1684 check_infer_with_mismatches(
1703 r#" 1685 r#"
1704 trait FnOnce<Args> { 1686trait FnOnce<Args> {
1705 type Output; 1687 type Output;
1706 1688
1707 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output; 1689 fn call_once(self, args: Args) -> <Self as FnOnce<Args>>::Output;
1708 } 1690}
1709 1691
1710 fn test<F: FnOnce(u32, u64) -> u128>(f: F) { 1692fn test<F: FnOnce(u32, u64) -> u128>(f: F) {
1711 f.call_once((1, 2)); 1693 f.call_once((1, 2));
1712 } 1694}"#,
1713 "#,
1714 expect![[r#" 1695 expect![[r#"
1715 56..60 'self': Self 1696 56..60 'self': Self
1716 62..66 'args': Args 1697 62..66 'args': Args
@@ -1729,37 +1710,36 @@ fn fn_trait() {
1729fn fn_ptr_and_item() { 1710fn fn_ptr_and_item() {
1730 check_infer_with_mismatches( 1711 check_infer_with_mismatches(
1731 r#" 1712 r#"
1732 #[lang="fn_once"] 1713#[lang="fn_once"]
1733 trait FnOnce<Args> { 1714trait FnOnce<Args> {
1734 type Output; 1715 type Output;
1735 1716
1736 fn call_once(self, args: Args) -> Self::Output; 1717 fn call_once(self, args: Args) -> Self::Output;
1737 } 1718}
1738 1719
1739 trait Foo<T> { 1720trait Foo<T> {
1740 fn foo(&self) -> T; 1721 fn foo(&self) -> T;
1741 } 1722}
1742 1723
1743 struct Bar<T>(T); 1724struct Bar<T>(T);
1744 1725
1745 impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> { 1726impl<A1, R, F: FnOnce(A1) -> R> Foo<(A1, R)> for Bar<F> {
1746 fn foo(&self) -> (A1, R) { loop {} } 1727 fn foo(&self) -> (A1, R) { loop {} }
1747 } 1728}
1748 1729
1749 enum Opt<T> { None, Some(T) } 1730enum Opt<T> { None, Some(T) }
1750 impl<T> Opt<T> { 1731impl<T> Opt<T> {
1751 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} } 1732 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Opt<U> { loop {} }
1752 } 1733}
1753 1734
1754 fn test() { 1735fn test() {
1755 let bar: Bar<fn(u8) -> u32>; 1736 let bar: Bar<fn(u8) -> u32>;
1756 bar.foo(); 1737 bar.foo();
1757 1738
1758 let opt: Opt<u8>; 1739 let opt: Opt<u8>;
1759 let f: fn(u8) -> u32; 1740 let f: fn(u8) -> u32;
1760 opt.map(f); 1741 opt.map(f);
1761 } 1742}"#,
1762 "#,
1763 expect![[r#" 1743 expect![[r#"
1764 74..78 'self': Self 1744 74..78 'self': Self
1765 80..84 'args': Args 1745 80..84 'args': Args
@@ -1790,46 +1770,45 @@ fn fn_ptr_and_item() {
1790fn fn_trait_deref_with_ty_default() { 1770fn fn_trait_deref_with_ty_default() {
1791 check_infer( 1771 check_infer(
1792 r#" 1772 r#"
1793 #[lang = "deref"] 1773#[lang = "deref"]
1794 trait Deref { 1774trait Deref {
1795 type Target; 1775 type Target;
1796 1776
1797 fn deref(&self) -> &Self::Target; 1777 fn deref(&self) -> &Self::Target;
1798 } 1778}
1799 1779
1800 #[lang="fn_once"] 1780#[lang="fn_once"]
1801 trait FnOnce<Args> { 1781trait FnOnce<Args> {
1802 type Output; 1782 type Output;
1803 1783
1804 fn call_once(self, args: Args) -> Self::Output; 1784 fn call_once(self, args: Args) -> Self::Output;
1805 } 1785}
1806 1786
1807 struct Foo; 1787struct Foo;
1808 1788
1809 impl Foo { 1789impl Foo {
1810 fn foo(&self) -> usize {} 1790 fn foo(&self) -> usize {}
1811 } 1791}
1812 1792
1813 struct Lazy<T, F = fn() -> T>(F); 1793struct Lazy<T, F = fn() -> T>(F);
1814 1794
1815 impl<T, F> Lazy<T, F> { 1795impl<T, F> Lazy<T, F> {
1816 pub fn new(f: F) -> Lazy<T, F> {} 1796 pub fn new(f: F) -> Lazy<T, F> {}
1817 } 1797}
1818 1798
1819 impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> { 1799impl<T, F: FnOnce() -> T> Deref for Lazy<T, F> {
1820 type Target = T; 1800 type Target = T;
1821 } 1801}
1822 1802
1823 fn test() { 1803fn test() {
1824 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo); 1804 let lazy1: Lazy<Foo, _> = Lazy::new(|| Foo);
1825 let r1 = lazy1.foo(); 1805 let r1 = lazy1.foo();
1826 1806
1827 fn make_foo_fn() -> Foo {} 1807 fn make_foo_fn() -> Foo {}
1828 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn; 1808 let make_foo_fn_ptr: fn() -> Foo = make_foo_fn;
1829 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr); 1809 let lazy2: Lazy<Foo, _> = Lazy::new(make_foo_fn_ptr);
1830 let r2 = lazy2.foo(); 1810 let r2 = lazy2.foo();
1831 } 1811}"#,
1832 "#,
1833 expect![[r#" 1812 expect![[r#"
1834 64..68 'self': &Self 1813 64..68 'self': &Self
1835 165..169 'self': Self 1814 165..169 'self': Self
@@ -1865,23 +1844,22 @@ fn fn_trait_deref_with_ty_default() {
1865fn closure_1() { 1844fn closure_1() {
1866 check_infer_with_mismatches( 1845 check_infer_with_mismatches(
1867 r#" 1846 r#"
1868 #[lang = "fn_once"] 1847#[lang = "fn_once"]
1869 trait FnOnce<Args> { 1848trait FnOnce<Args> {
1870 type Output; 1849 type Output;
1871 } 1850}
1872 1851
1873 enum Option<T> { Some(T), None } 1852enum Option<T> { Some(T), None }
1874 impl<T> Option<T> { 1853impl<T> Option<T> {
1875 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} } 1854 fn map<U, F: FnOnce(T) -> U>(self, f: F) -> Option<U> { loop {} }
1876 } 1855}
1877 1856
1878 fn test() { 1857fn test() {
1879 let x = Option::Some(1u32); 1858 let x = Option::Some(1u32);
1880 x.map(|v| v + 1); 1859 x.map(|v| v + 1);
1881 x.map(|_v| 1u64); 1860 x.map(|_v| 1u64);
1882 let y: Option<i64> = x.map(|_v| 1); 1861 let y: Option<i64> = x.map(|_v| 1);
1883 } 1862}"#,
1884 "#,
1885 expect![[r#" 1863 expect![[r#"
1886 147..151 'self': Option<T> 1864 147..151 'self': Option<T>
1887 153..154 'f': F 1865 153..154 'f': F
@@ -1919,38 +1897,63 @@ fn closure_1() {
1919fn closure_2() { 1897fn closure_2() {
1920 check_infer_with_mismatches( 1898 check_infer_with_mismatches(
1921 r#" 1899 r#"
1922 trait FnOnce<Args> { 1900#[lang = "add"]
1923 type Output; 1901pub trait Add<Rhs = Self> {
1924 } 1902 type Output;
1903 fn add(self, rhs: Rhs) -> Self::Output;
1904}
1925 1905
1926 fn test<F: FnOnce(u32) -> u64>(f: F) { 1906trait FnOnce<Args> {
1927 f(1); 1907 type Output;
1928 let g = |v| v + 1; 1908}
1929 g(1u64); 1909
1930 let h = |v| 1u128 + v; 1910impl Add for u64 {
1931 } 1911 type Output = Self;
1932 "#, 1912 fn add(self, rhs: u64) -> Self::Output {0}
1913}
1914
1915impl Add for u128 {
1916 type Output = Self;
1917 fn add(self, rhs: u128) -> Self::Output {0}
1918}
1919
1920fn test<F: FnOnce(u32) -> u64>(f: F) {
1921 f(1);
1922 let g = |v| v + 1;
1923 g(1u64);
1924 let h = |v| 1u128 + v;
1925}"#,
1933 expect![[r#" 1926 expect![[r#"
1934 72..73 'f': F 1927 72..76 'self': Self
1935 78..154 '{ ...+ v; }': () 1928 78..81 'rhs': Rhs
1936 84..85 'f': F 1929 203..207 'self': u64
1937 84..88 'f(1)': {unknown} 1930 209..212 'rhs': u64
1938 86..87 '1': i32 1931 235..238 '{0}': u64
1939 98..99 'g': |u64| -> i32 1932 236..237 '0': u64
1940 102..111 '|v| v + 1': |u64| -> i32 1933 297..301 'self': u128
1941 103..104 'v': u64 1934 303..306 'rhs': u128
1942 106..107 'v': u64 1935 330..333 '{0}': u128
1943 106..111 'v + 1': i32 1936 331..332 '0': u128
1944 110..111 '1': i32 1937 368..369 'f': F
1945 117..118 'g': |u64| -> i32 1938 374..450 '{ ...+ v; }': ()
1946 117..124 'g(1u64)': i32 1939 380..381 'f': F
1947 119..123 '1u64': u64 1940 380..384 'f(1)': {unknown}
1948 134..135 'h': |u128| -> u128 1941 382..383 '1': i32
1949 138..151 '|v| 1u128 + v': |u128| -> u128 1942 394..395 'g': |u64| -> u64
1950 139..140 'v': u128 1943 398..407 '|v| v + 1': |u64| -> u64
1951 142..147 '1u128': u128 1944 399..400 'v': u64
1952 142..151 '1u128 + v': u128 1945 402..403 'v': u64
1953 150..151 'v': u128 1946 402..407 'v + 1': u64
1947 406..407 '1': u64
1948 413..414 'g': |u64| -> u64
1949 413..420 'g(1u64)': u64
1950 415..419 '1u64': u64
1951 430..431 'h': |u128| -> u128
1952 434..447 '|v| 1u128 + v': |u128| -> u128
1953 435..436 'v': u128
1954 438..443 '1u128': u128
1955 438..447 '1u128 + v': u128
1956 446..447 'v': u128
1954 "#]], 1957 "#]],
1955 ); 1958 );
1956} 1959}
@@ -1959,29 +1962,28 @@ fn closure_2() {
1959fn closure_as_argument_inference_order() { 1962fn closure_as_argument_inference_order() {
1960 check_infer_with_mismatches( 1963 check_infer_with_mismatches(
1961 r#" 1964 r#"
1962 #[lang = "fn_once"] 1965#[lang = "fn_once"]
1963 trait FnOnce<Args> { 1966trait FnOnce<Args> {
1964 type Output; 1967 type Output;
1965 } 1968}
1966 1969
1967 fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} } 1970fn foo1<T, U, F: FnOnce(T) -> U>(x: T, f: F) -> U { loop {} }
1968 fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} } 1971fn foo2<T, U, F: FnOnce(T) -> U>(f: F, x: T) -> U { loop {} }
1969 1972
1970 struct S; 1973struct S;
1971 impl S { 1974impl S {
1972 fn method(self) -> u64; 1975 fn method(self) -> u64;
1973 1976
1974 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} } 1977 fn foo1<T, U, F: FnOnce(T) -> U>(self, x: T, f: F) -> U { loop {} }
1975 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} } 1978 fn foo2<T, U, F: FnOnce(T) -> U>(self, f: F, x: T) -> U { loop {} }
1976 } 1979}
1977 1980
1978 fn test() { 1981fn test() {
1979 let x1 = foo1(S, |s| s.method()); 1982 let x1 = foo1(S, |s| s.method());
1980 let x2 = foo2(|s| s.method(), S); 1983 let x2 = foo2(|s| s.method(), S);
1981 let x3 = S.foo1(S, |s| s.method()); 1984 let x3 = S.foo1(S, |s| s.method());
1982 let x4 = S.foo2(|s| s.method(), S); 1985 let x4 = S.foo2(|s| s.method(), S);
1983 } 1986}"#,
1984 "#,
1985 expect![[r#" 1987 expect![[r#"
1986 94..95 'x': T 1988 94..95 'x': T
1987 100..101 'f': F 1989 100..101 'f': F
@@ -2110,27 +2112,26 @@ fn test<T, U>() where T::Item: Trait2, T: Trait<U::Item>, U: Trait<()> {
2110fn unselected_projection_on_impl_self() { 2112fn unselected_projection_on_impl_self() {
2111 check_infer( 2113 check_infer(
2112 r#" 2114 r#"
2113 //- /main.rs 2115//- /main.rs
2114 trait Trait { 2116trait Trait {
2115 type Item; 2117 type Item;
2116 2118
2117 fn f(&self, x: Self::Item); 2119 fn f(&self, x: Self::Item);
2118 } 2120}
2119 2121
2120 struct S; 2122struct S;
2121 2123
2122 impl Trait for S { 2124impl Trait for S {
2123 type Item = u32; 2125 type Item = u32;
2124 fn f(&self, x: Self::Item) { let y = x; } 2126 fn f(&self, x: Self::Item) { let y = x; }
2125 } 2127}
2126 2128
2127 struct S2; 2129struct S2;
2128 2130
2129 impl Trait for S2 { 2131impl Trait for S2 {
2130 type Item = i32; 2132 type Item = i32;
2131 fn f(&self, x: <Self>::Item) { let y = x; } 2133 fn f(&self, x: <Self>::Item) { let y = x; }
2132 } 2134}"#,
2133 "#,
2134 expect![[r#" 2135 expect![[r#"
2135 40..44 'self': &Self 2136 40..44 'self': &Self
2136 46..47 'x': Trait::Item<Self> 2137 46..47 'x': Trait::Item<Self>
@@ -2366,58 +2367,57 @@ fn test<I: Iterator<Item: Iterator<Item = u32>>>() {
2366fn proc_macro_server_types() { 2367fn proc_macro_server_types() {
2367 check_infer( 2368 check_infer(
2368 r#" 2369 r#"
2369 macro_rules! with_api { 2370macro_rules! with_api {
2370 ($S:ident, $self:ident, $m:ident) => { 2371 ($S:ident, $self:ident, $m:ident) => {
2371 $m! { 2372 $m! {
2372 TokenStream { 2373 TokenStream {
2373 fn new() -> $S::TokenStream; 2374 fn new() -> $S::TokenStream;
2374 }, 2375 },
2375 Group { 2376 Group {
2376 }, 2377 },
2377 }
2378 };
2379 } 2378 }
2380 macro_rules! associated_item { 2379 };
2381 (type TokenStream) => 2380}
2382 (type TokenStream: 'static;); 2381macro_rules! associated_item {
2383 (type Group) => 2382 (type TokenStream) =>
2384 (type Group: 'static;); 2383 (type TokenStream: 'static;);
2385 ($($item:tt)*) => ($($item)*;) 2384 (type Group) =>
2386 } 2385 (type Group: 'static;);
2387 macro_rules! declare_server_traits { 2386 ($($item:tt)*) => ($($item)*;)
2388 ($($name:ident { 2387}
2389 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)* 2388macro_rules! declare_server_traits {
2390 }),* $(,)?) => { 2389 ($($name:ident {
2391 pub trait Types { 2390 $(fn $method:ident($($arg:ident: $arg_ty:ty),* $(,)?) $(-> $ret_ty:ty)?;)*
2392 $(associated_item!(type $name);)* 2391 }),* $(,)?) => {
2393 } 2392 pub trait Types {
2394 2393 $(associated_item!(type $name);)*
2395 $(pub trait $name: Types {
2396 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2397 })*
2398
2399 pub trait Server: Types $(+ $name)* {}
2400 impl<S: Types $(+ $name)*> Server for S {}
2401 }
2402 } 2394 }
2403 2395
2404 with_api!(Self, self_, declare_server_traits); 2396 $(pub trait $name: Types {
2405 struct G {} 2397 $(associated_item!(fn $method($($arg: $arg_ty),*) $(-> $ret_ty)?);)*
2406 struct T {} 2398 })*
2407 struct Rustc;
2408 impl Types for Rustc {
2409 type TokenStream = T;
2410 type Group = G;
2411 }
2412 2399
2413 fn make<T>() -> T { loop {} } 2400 pub trait Server: Types $(+ $name)* {}
2414 impl TokenStream for Rustc { 2401 impl<S: Types $(+ $name)*> Server for S {}
2415 fn new() -> Self::TokenStream { 2402 }
2416 let group: Self::Group = make(); 2403}
2417 make() 2404
2418 } 2405with_api!(Self, self_, declare_server_traits);
2419 } 2406struct G {}
2420 "#, 2407struct T {}
2408struct Rustc;
2409impl Types for Rustc {
2410 type TokenStream = T;
2411 type Group = G;
2412}
2413
2414fn make<T>() -> T { loop {} }
2415impl TokenStream for Rustc {
2416 fn new() -> Self::TokenStream {
2417 let group: Self::Group = make();
2418 make()
2419 }
2420}"#,
2421 expect![[r#" 2421 expect![[r#"
2422 1061..1072 '{ loop {} }': T 2422 1061..1072 '{ loop {} }': T
2423 1063..1070 'loop {}': ! 2423 1063..1070 'loop {}': !
@@ -2436,23 +2436,22 @@ fn proc_macro_server_types() {
2436fn unify_impl_trait() { 2436fn unify_impl_trait() {
2437 check_infer_with_mismatches( 2437 check_infer_with_mismatches(
2438 r#" 2438 r#"
2439 trait Trait<T> {} 2439trait Trait<T> {}
2440 2440
2441 fn foo(x: impl Trait<u32>) { loop {} } 2441fn foo(x: impl Trait<u32>) { loop {} }
2442 fn bar<T>(x: impl Trait<T>) -> T { loop {} } 2442fn bar<T>(x: impl Trait<T>) -> T { loop {} }
2443 2443
2444 struct S<T>(T); 2444struct S<T>(T);
2445 impl<T> Trait<T> for S<T> {} 2445impl<T> Trait<T> for S<T> {}
2446 2446
2447 fn default<T>() -> T { loop {} } 2447fn default<T>() -> T { loop {} }
2448 2448
2449 fn test() -> impl Trait<i32> { 2449fn test() -> impl Trait<i32> {
2450 let s1 = S(default()); 2450 let s1 = S(default());
2451 foo(s1); 2451 foo(s1);
2452 let x: i32 = bar(S(default())); 2452 let x: i32 = bar(S(default()));
2453 S(default()) 2453 S(default())
2454 } 2454}"#,
2455 "#,
2456 expect![[r#" 2455 expect![[r#"
2457 26..27 'x': impl Trait<u32> 2456 26..27 'x': impl Trait<u32>
2458 46..57 '{ loop {} }': () 2457 46..57 '{ loop {} }': ()
@@ -2493,30 +2492,29 @@ fn unify_impl_trait() {
2493fn assoc_types_from_bounds() { 2492fn assoc_types_from_bounds() {
2494 check_infer( 2493 check_infer(
2495 r#" 2494 r#"
2496 //- /main.rs 2495//- /main.rs
2497 #[lang = "fn_once"] 2496#[lang = "fn_once"]
2498 trait FnOnce<Args> { 2497trait FnOnce<Args> {
2499 type Output; 2498 type Output;
2500 } 2499}
2501 2500
2502 trait T { 2501trait T {
2503 type O; 2502 type O;
2504 } 2503}
2505 2504
2506 impl T for () { 2505impl T for () {
2507 type O = (); 2506 type O = ();
2508 } 2507}
2509 2508
2510 fn f<X, F>(_v: F) 2509fn f<X, F>(_v: F)
2511 where 2510where
2512 X: T, 2511 X: T,
2513 F: FnOnce(&X::O), 2512 F: FnOnce(&X::O),
2514 { } 2513{ }
2515 2514
2516 fn main() { 2515fn main() {
2517 f::<(), _>(|z| { z; }); 2516 f::<(), _>(|z| { z; });
2518 } 2517}"#,
2519 "#,
2520 expect![[r#" 2518 expect![[r#"
2521 133..135 '_v': F 2519 133..135 '_v': F
2522 178..181 '{ }': () 2520 178..181 '{ }': ()
@@ -2602,76 +2600,75 @@ fn test() {
2602fn iterator_chain() { 2600fn iterator_chain() {
2603 check_infer_with_mismatches( 2601 check_infer_with_mismatches(
2604 r#" 2602 r#"
2605 //- /main.rs 2603//- /main.rs
2606 #[lang = "fn_once"] 2604#[lang = "fn_once"]
2607 trait FnOnce<Args> { 2605trait FnOnce<Args> {
2608 type Output; 2606 type Output;
2609 } 2607}
2610 #[lang = "fn_mut"] 2608#[lang = "fn_mut"]
2611 trait FnMut<Args>: FnOnce<Args> { } 2609trait FnMut<Args>: FnOnce<Args> { }
2612 2610
2613 enum Option<T> { Some(T), None } 2611enum Option<T> { Some(T), None }
2614 use Option::*; 2612use Option::*;
2615 2613
2616 pub trait Iterator { 2614pub trait Iterator {
2617 type Item; 2615 type Item;
2618 2616
2619 fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F> 2617 fn filter_map<B, F>(self, f: F) -> FilterMap<Self, F>
2620 where 2618 where
2621 F: FnMut(Self::Item) -> Option<B>, 2619 F: FnMut(Self::Item) -> Option<B>,
2622 { loop {} } 2620 { loop {} }
2623 2621
2624 fn for_each<F>(self, f: F) 2622 fn for_each<F>(self, f: F)
2625 where 2623 where
2626 F: FnMut(Self::Item), 2624 F: FnMut(Self::Item),
2627 { loop {} } 2625 { loop {} }
2628 } 2626}
2629 2627
2630 pub trait IntoIterator { 2628pub trait IntoIterator {
2631 type Item; 2629 type Item;
2632 type IntoIter: Iterator<Item = Self::Item>; 2630 type IntoIter: Iterator<Item = Self::Item>;
2633 fn into_iter(self) -> Self::IntoIter; 2631 fn into_iter(self) -> Self::IntoIter;
2634 } 2632}
2635 2633
2636 pub struct FilterMap<I, F> { } 2634pub struct FilterMap<I, F> { }
2637 impl<B, I: Iterator, F> Iterator for FilterMap<I, F> 2635impl<B, I: Iterator, F> Iterator for FilterMap<I, F>
2638 where 2636where
2639 F: FnMut(I::Item) -> Option<B>, 2637 F: FnMut(I::Item) -> Option<B>,
2640 { 2638{
2641 type Item = B; 2639 type Item = B;
2642 } 2640}
2643 2641
2644 #[stable(feature = "rust1", since = "1.0.0")] 2642#[stable(feature = "rust1", since = "1.0.0")]
2645 impl<I: Iterator> IntoIterator for I { 2643impl<I: Iterator> IntoIterator for I {
2646 type Item = I::Item; 2644 type Item = I::Item;
2647 type IntoIter = I; 2645 type IntoIter = I;
2648 2646
2649 fn into_iter(self) -> I { 2647 fn into_iter(self) -> I {
2650 self 2648 self
2651 } 2649 }
2652 } 2650}
2653 2651
2654 struct Vec<T> {} 2652struct Vec<T> {}
2655 impl<T> Vec<T> { 2653impl<T> Vec<T> {
2656 fn new() -> Self { loop {} } 2654 fn new() -> Self { loop {} }
2657 } 2655}
2658 2656
2659 impl<T> IntoIterator for Vec<T> { 2657impl<T> IntoIterator for Vec<T> {
2660 type Item = T; 2658 type Item = T;
2661 type IntoIter = IntoIter<T>; 2659 type IntoIter = IntoIter<T>;
2662 } 2660}
2663 2661
2664 pub struct IntoIter<T> { } 2662pub struct IntoIter<T> { }
2665 impl<T> Iterator for IntoIter<T> { 2663impl<T> Iterator for IntoIter<T> {
2666 type Item = T; 2664 type Item = T;
2667 } 2665}
2668 2666
2669 fn main() { 2667fn main() {
2670 Vec::<i32>::new().into_iter() 2668 Vec::<i32>::new().into_iter()
2671 .filter_map(|x| if x > 0 { Some(x as u32) } else { None }) 2669 .filter_map(|x| if x > 0 { Some(x as u32) } else { None })
2672 .for_each(|y| { y; }); 2670 .for_each(|y| { y; });
2673 } 2671}"#,
2674 "#,
2675 expect![[r#" 2672 expect![[r#"
2676 226..230 'self': Self 2673 226..230 'self': Self
2677 232..233 'f': F 2674 232..233 'f': F
@@ -2753,14 +2750,13 @@ fn main() {
2753fn trait_object_no_coercion() { 2750fn trait_object_no_coercion() {
2754 check_infer_with_mismatches( 2751 check_infer_with_mismatches(
2755 r#" 2752 r#"
2756 trait Foo {} 2753trait Foo {}
2757 2754
2758 fn foo(x: &dyn Foo) {} 2755fn foo(x: &dyn Foo) {}
2759 2756
2760 fn test(x: &dyn Foo) { 2757fn test(x: &dyn Foo) {
2761 foo(x); 2758 foo(x);
2762 } 2759}"#,
2763 "#,
2764 expect![[r#" 2760 expect![[r#"
2765 21..22 'x': &dyn Foo 2761 21..22 'x': &dyn Foo
2766 34..36 '{}': () 2762 34..36 '{}': ()
@@ -2777,23 +2773,22 @@ fn trait_object_no_coercion() {
2777fn builtin_copy() { 2773fn builtin_copy() {
2778 check_infer_with_mismatches( 2774 check_infer_with_mismatches(
2779 r#" 2775 r#"
2780 #[lang = "copy"] 2776#[lang = "copy"]
2781 trait Copy {} 2777trait Copy {}
2782 2778
2783 struct IsCopy; 2779struct IsCopy;
2784 impl Copy for IsCopy {} 2780impl Copy for IsCopy {}
2785 struct NotCopy; 2781struct NotCopy;
2786 2782
2787 trait Test { fn test(&self) -> bool; } 2783trait Test { fn test(&self) -> bool; }
2788 impl<T: Copy> Test for T {} 2784impl<T: Copy> Test for T {}
2789 2785
2790 fn test() { 2786fn test() {
2791 IsCopy.test(); 2787 IsCopy.test();
2792 NotCopy.test(); 2788 NotCopy.test();
2793 (IsCopy, IsCopy).test(); 2789 (IsCopy, IsCopy).test();
2794 (IsCopy, NotCopy).test(); 2790 (IsCopy, NotCopy).test();
2795 } 2791}"#,
2796 "#,
2797 expect![[r#" 2792 expect![[r#"
2798 110..114 'self': &Self 2793 110..114 'self': &Self
2799 166..267 '{ ...t(); }': () 2794 166..267 '{ ...t(); }': ()
@@ -2817,24 +2812,23 @@ fn builtin_copy() {
2817fn builtin_fn_def_copy() { 2812fn builtin_fn_def_copy() {
2818 check_infer_with_mismatches( 2813 check_infer_with_mismatches(
2819 r#" 2814 r#"
2820 #[lang = "copy"] 2815#[lang = "copy"]
2821 trait Copy {} 2816trait Copy {}
2822 2817
2823 fn foo() {} 2818fn foo() {}
2824 fn bar<T: Copy>(T) -> T {} 2819fn bar<T: Copy>(T) -> T {}
2825 struct Struct(usize); 2820struct Struct(usize);
2826 enum Enum { Variant(usize) } 2821enum Enum { Variant(usize) }
2827 2822
2828 trait Test { fn test(&self) -> bool; } 2823trait Test { fn test(&self) -> bool; }
2829 impl<T: Copy> Test for T {} 2824impl<T: Copy> Test for T {}
2830 2825
2831 fn test() { 2826fn test() {
2832 foo.test(); 2827 foo.test();
2833 bar.test(); 2828 bar.test();
2834 Struct.test(); 2829 Struct.test();
2835 Enum::Variant.test(); 2830 Enum::Variant.test();
2836 } 2831}"#,
2837 "#,
2838 expect![[r#" 2832 expect![[r#"
2839 41..43 '{}': () 2833 41..43 '{}': ()
2840 60..61 'T': {unknown} 2834 60..61 'T': {unknown}
@@ -2858,18 +2852,17 @@ fn builtin_fn_def_copy() {
2858fn builtin_fn_ptr_copy() { 2852fn builtin_fn_ptr_copy() {
2859 check_infer_with_mismatches( 2853 check_infer_with_mismatches(
2860 r#" 2854 r#"
2861 #[lang = "copy"] 2855#[lang = "copy"]
2862 trait Copy {} 2856trait Copy {}
2863 2857
2864 trait Test { fn test(&self) -> bool; } 2858trait Test { fn test(&self) -> bool; }
2865 impl<T: Copy> Test for T {} 2859impl<T: Copy> Test for T {}
2866 2860
2867 fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { 2861fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) {
2868 f1.test(); 2862 f1.test();
2869 f2.test(); 2863 f2.test();
2870 f3.test(); 2864 f3.test();
2871 } 2865}"#,
2872 "#,
2873 expect![[r#" 2866 expect![[r#"
2874 54..58 'self': &Self 2867 54..58 'self': &Self
2875 108..110 'f1': fn() 2868 108..110 'f1': fn()
@@ -2890,19 +2883,18 @@ fn builtin_fn_ptr_copy() {
2890fn builtin_sized() { 2883fn builtin_sized() {
2891 check_infer_with_mismatches( 2884 check_infer_with_mismatches(
2892 r#" 2885 r#"
2893 #[lang = "sized"] 2886#[lang = "sized"]
2894 trait Sized {} 2887trait Sized {}
2895 2888
2896 trait Test { fn test(&self) -> bool; } 2889trait Test { fn test(&self) -> bool; }
2897 impl<T: Sized> Test for T {} 2890impl<T: Sized> Test for T {}
2898 2891
2899 fn test() { 2892fn test() {
2900 1u8.test(); 2893 1u8.test();
2901 (*"foo").test(); // not Sized 2894 (*"foo").test(); // not Sized
2902 (1u8, 1u8).test(); 2895 (1u8, 1u8).test();
2903 (1u8, *"foo").test(); // not Sized 2896 (1u8, *"foo").test(); // not Sized
2904 } 2897}"#,
2905 "#,
2906 expect![[r#" 2898 expect![[r#"
2907 56..60 'self': &Self 2899 56..60 'self': &Self
2908 113..228 '{ ...ized }': () 2900 113..228 '{ ...ized }': ()
@@ -2972,19 +2964,18 @@ impl<A: Step> iter::Iterator for ops::Range<A> {
2972fn infer_closure_arg() { 2964fn infer_closure_arg() {
2973 check_infer( 2965 check_infer(
2974 r#" 2966 r#"
2975 //- /lib.rs 2967//- /lib.rs
2976 2968
2977 enum Option<T> { 2969enum Option<T> {
2978 None, 2970 None,
2979 Some(T) 2971 Some(T)
2980 } 2972}
2981 2973
2982 fn foo() { 2974fn foo() {
2983 let s = Option::None; 2975 let s = Option::None;
2984 let f = |x: Option<i32>| {}; 2976 let f = |x: Option<i32>| {};
2985 (&f)(s) 2977 (&f)(s)
2986 } 2978}"#,
2987 "#,
2988 expect![[r#" 2979 expect![[r#"
2989 52..126 '{ ...)(s) }': () 2980 52..126 '{ ...)(s) }': ()
2990 62..63 's': Option<i32> 2981 62..63 's': Option<i32>
@@ -3053,46 +3044,45 @@ fn infer_box_fn_arg() {
3053 // The type mismatch is a bug 3044 // The type mismatch is a bug
3054 check_infer_with_mismatches( 3045 check_infer_with_mismatches(
3055 r#" 3046 r#"
3056 //- /lib.rs deps:std 3047//- /lib.rs deps:std
3057 3048
3058 #[lang = "fn_once"] 3049#[lang = "fn_once"]
3059 pub trait FnOnce<Args> { 3050pub trait FnOnce<Args> {
3060 type Output; 3051 type Output;
3061 3052
3062 extern "rust-call" fn call_once(self, args: Args) -> Self::Output; 3053 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
3063 } 3054}
3064 3055
3065 #[lang = "deref"] 3056#[lang = "deref"]
3066 pub trait Deref { 3057pub trait Deref {
3067 type Target: ?Sized; 3058 type Target: ?Sized;
3068 3059
3069 fn deref(&self) -> &Self::Target; 3060 fn deref(&self) -> &Self::Target;
3070 } 3061}
3071 3062
3072 #[lang = "owned_box"] 3063#[lang = "owned_box"]
3073 pub struct Box<T: ?Sized> { 3064pub struct Box<T: ?Sized> {
3074 inner: *mut T, 3065 inner: *mut T,
3075 } 3066}
3076 3067
3077 impl<T: ?Sized> Deref for Box<T> { 3068impl<T: ?Sized> Deref for Box<T> {
3078 type Target = T; 3069 type Target = T;
3079 3070
3080 fn deref(&self) -> &T { 3071 fn deref(&self) -> &T {
3081 &self.inner 3072 &self.inner
3082 } 3073 }
3083 } 3074}
3084 3075
3085 enum Option<T> { 3076enum Option<T> {
3086 None, 3077 None,
3087 Some(T) 3078 Some(T)
3088 } 3079}
3089 3080
3090 fn foo() { 3081fn foo() {
3091 let s = Option::None; 3082 let s = Option::None;
3092 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); 3083 let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {});
3093 f(&s); 3084 f(&s);
3094 } 3085}"#,
3095 "#,
3096 expect![[r#" 3086 expect![[r#"
3097 100..104 'self': Self 3087 100..104 'self': Self
3098 106..110 'args': Args 3088 106..110 'args': Args
@@ -3258,8 +3248,7 @@ fn f() {
3258 ().method(); 3248 ().method();
3259 //^^^^^^^^^^^ u8 3249 //^^^^^^^^^^^ u8
3260 } 3250 }
3261} 3251}"#,
3262 "#,
3263 expect![[r#" 3252 expect![[r#"
3264 46..50 'self': &Self 3253 46..50 'self': &Self
3265 58..63 '{ 0 }': u8 3254 58..63 '{ 0 }': u8
@@ -3313,8 +3302,7 @@ fn f() {
3313 fn inner() -> S { 3302 fn inner() -> S {
3314 let s = inner(); 3303 let s = inner();
3315 } 3304 }
3316} 3305}"#,
3317 "#,
3318 expect![[r#" 3306 expect![[r#"
3319 17..73 '{ ... } }': () 3307 17..73 '{ ... } }': ()
3320 39..71 '{ ... }': () 3308 39..71 '{ ... }': ()
@@ -3349,8 +3337,7 @@ fn test() {
3349 let x = A; 3337 let x = A;
3350 let y = A; 3338 let y = A;
3351 let r = x.do_op(y); 3339 let r = x.do_op(y);
3352} 3340}"#,
3353 "#,
3354 expect![[r#" 3341 expect![[r#"
3355 63..67 'self': Self 3342 63..67 'self': Self
3356 69..72 'rhs': RHS 3343 69..72 'rhs': RHS
@@ -3399,9 +3386,7 @@ impl foo::Bar for F {
3399fn foo() { 3386fn foo() {
3400 use foo::Bar; 3387 use foo::Bar;
3401 let x = <F as Bar>::boo(); 3388 let x = <F as Bar>::boo();
3402} 3389}"#,
3403
3404 "#,
3405 expect![[r#" 3390 expect![[r#"
3406 132..163 '{ ... }': Bar::Output<Self> 3391 132..163 '{ ... }': Bar::Output<Self>
3407 146..153 'loop {}': ! 3392 146..153 'loop {}': !
@@ -3413,3 +3398,79 @@ fn foo() {
3413 "#]], 3398 "#]],
3414 ); 3399 );
3415} 3400}
3401
3402#[test]
3403fn renamed_extern_crate_in_block() {
3404 check_types(
3405 r#"
3406//- /lib.rs crate:lib deps:serde
3407use serde::Deserialize;
3408
3409struct Foo {}
3410
3411const _ : () = {
3412 extern crate serde as _serde;
3413 impl _serde::Deserialize for Foo {
3414 fn deserialize() -> u8 { 0 }
3415 }
3416};
3417
3418fn foo() {
3419 Foo::deserialize();
3420 //^^^^^^^^^^^^^^^^^^ u8
3421}
3422
3423//- /serde.rs crate:serde
3424
3425pub trait Deserialize {
3426 fn deserialize() -> u8;
3427}"#,
3428 );
3429}
3430
3431#[test]
3432fn bin_op_adt_with_rhs_primitive() {
3433 check_infer_with_mismatches(
3434 r#"
3435#[lang = "add"]
3436pub trait Add<Rhs = Self> {
3437 type Output;
3438 fn add(self, rhs: Rhs) -> Self::Output;
3439}
3440
3441struct Wrapper(u32);
3442impl Add<u32> for Wrapper {
3443 type Output = Self;
3444 fn add(self, rhs: u32) -> Wrapper {
3445 Wrapper(rhs)
3446 }
3447}
3448fn main(){
3449 let wrapped = Wrapper(10);
3450 let num: u32 = 2;
3451 let res = wrapped + num;
3452
3453}"#,
3454 expect![[r#"
3455 72..76 'self': Self
3456 78..81 'rhs': Rhs
3457 192..196 'self': Wrapper
3458 198..201 'rhs': u32
3459 219..247 '{ ... }': Wrapper
3460 229..236 'Wrapper': Wrapper(u32) -> Wrapper
3461 229..241 'Wrapper(rhs)': Wrapper
3462 237..240 'rhs': u32
3463 259..345 '{ ...um; }': ()
3464 269..276 'wrapped': Wrapper
3465 279..286 'Wrapper': Wrapper(u32) -> Wrapper
3466 279..290 'Wrapper(10)': Wrapper
3467 287..289 '10': u32
3468 300..303 'num': u32
3469 311..312 '2': u32
3470 322..325 'res': Wrapper
3471 328..335 'wrapped': Wrapper
3472 328..341 'wrapped + num': Wrapper
3473 338..341 'num': u32
3474 "#]],
3475 )
3476}
diff --git a/crates/hir_ty/src/traits/chalk/tls.rs b/crates/hir_ty/src/tls.rs
index 8892a63a9..87c671a42 100644
--- a/crates/hir_ty/src/traits/chalk/tls.rs
+++ b/crates/hir_ty/src/tls.rs
@@ -4,8 +4,10 @@ use std::fmt;
4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication}; 4use chalk_ir::{AliasTy, GenericArg, Goal, Goals, Lifetime, ProgramClauseImplication};
5use itertools::Itertools; 5use itertools::Itertools;
6 6
7use super::{from_chalk, Interner}; 7use crate::{
8use crate::{db::HirDatabase, from_assoc_type_id, CallableDefId}; 8 chalk_db, db::HirDatabase, from_assoc_type_id, from_chalk_trait_id, mapping::from_chalk,
9 CallableDefId, Interner,
10};
9use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId}; 11use hir_def::{AdtId, AssocContainerId, Lookup, TypeAliasId};
10 12
11pub(crate) use unsafe_tls::{set_current_program, with_current_program}; 13pub(crate) use unsafe_tls::{set_current_program, with_current_program};
@@ -15,7 +17,7 @@ pub(crate) struct DebugContext<'a>(&'a dyn HirDatabase);
15impl DebugContext<'_> { 17impl DebugContext<'_> {
16 pub(crate) fn debug_struct_id( 18 pub(crate) fn debug_struct_id(
17 &self, 19 &self,
18 id: super::AdtId, 20 id: chalk_db::AdtId,
19 f: &mut fmt::Formatter<'_>, 21 f: &mut fmt::Formatter<'_>,
20 ) -> Result<(), fmt::Error> { 22 ) -> Result<(), fmt::Error> {
21 let name = match id.0 { 23 let name = match id.0 {
@@ -28,17 +30,17 @@ impl DebugContext<'_> {
28 30
29 pub(crate) fn debug_trait_id( 31 pub(crate) fn debug_trait_id(
30 &self, 32 &self,
31 id: super::TraitId, 33 id: chalk_db::TraitId,
32 fmt: &mut fmt::Formatter<'_>, 34 fmt: &mut fmt::Formatter<'_>,
33 ) -> Result<(), fmt::Error> { 35 ) -> Result<(), fmt::Error> {
34 let trait_: hir_def::TraitId = from_chalk(self.0, id); 36 let trait_: hir_def::TraitId = from_chalk_trait_id(id);
35 let trait_data = self.0.trait_data(trait_); 37 let trait_data = self.0.trait_data(trait_);
36 write!(fmt, "{}", trait_data.name) 38 write!(fmt, "{}", trait_data.name)
37 } 39 }
38 40
39 pub(crate) fn debug_assoc_type_id( 41 pub(crate) fn debug_assoc_type_id(
40 &self, 42 &self,
41 id: super::AssocTypeId, 43 id: chalk_db::AssocTypeId,
42 fmt: &mut fmt::Formatter<'_>, 44 fmt: &mut fmt::Formatter<'_>,
43 ) -> Result<(), fmt::Error> { 45 ) -> Result<(), fmt::Error> {
44 let type_alias: TypeAliasId = from_assoc_type_id(id); 46 let type_alias: TypeAliasId = from_assoc_type_id(id);
diff --git a/crates/hir_ty/src/traits.rs b/crates/hir_ty/src/traits.rs
index e5e8cff33..9936d0803 100644
--- a/crates/hir_ty/src/traits.rs
+++ b/crates/hir_ty/src/traits.rs
@@ -1,28 +1,26 @@
1//! Trait solving using Chalk. 1//! Trait solving using Chalk.
2
2use std::env::var; 3use std::env::var;
3 4
4use base_db::CrateId;
5use chalk_ir::cast::Cast; 5use chalk_ir::cast::Cast;
6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver}; 6use chalk_solve::{logging_db::LoggingRustIrDatabase, Solver};
7
8use base_db::CrateId;
7use hir_def::{lang_item::LangItemTarget, TraitId}; 9use hir_def::{lang_item::LangItemTarget, TraitId};
8use stdx::panic_context; 10use stdx::panic_context;
9 11
10use crate::{ 12use crate::{
11 db::HirDatabase, AliasTy, Canonical, DebruijnIndex, HirDisplay, Substitution, Ty, TyKind, 13 db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Guidance, HirDisplay, InEnvironment,
12 TypeWalk, WhereClause, 14 Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
13}; 15};
14 16
15use self::chalk::{from_chalk, Interner, ToChalk};
16
17pub(crate) mod chalk;
18
19/// This controls how much 'time' we give the Chalk solver before giving up. 17/// This controls how much 'time' we give the Chalk solver before giving up.
20const CHALK_SOLVER_FUEL: i32 = 100; 18const CHALK_SOLVER_FUEL: i32 = 100;
21 19
22#[derive(Debug, Copy, Clone)] 20#[derive(Debug, Copy, Clone)]
23struct ChalkContext<'a> { 21pub(crate) struct ChalkContext<'a> {
24 db: &'a dyn HirDatabase, 22 pub(crate) db: &'a dyn HirDatabase,
25 krate: CrateId, 23 pub(crate) krate: CrateId,
26} 24}
27 25
28fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> { 26fn create_chalk_solver() -> chalk_recursive::RecursiveSolver<Interner> {
@@ -70,55 +68,6 @@ impl Default for TraitEnvironment {
70 } 68 }
71} 69}
72 70
73/// Something (usually a goal), along with an environment.
74#[derive(Clone, Debug, PartialEq, Eq, Hash)]
75pub struct InEnvironment<T> {
76 pub environment: chalk_ir::Environment<Interner>,
77 pub goal: T,
78}
79
80impl<T> InEnvironment<T> {
81 pub fn new(environment: chalk_ir::Environment<Interner>, value: T) -> InEnvironment<T> {
82 InEnvironment { environment, goal: value }
83 }
84}
85
86/// Something that needs to be proven (by Chalk) during type checking, e.g. that
87/// a certain type implements a certain trait. Proving the Obligation might
88/// result in additional information about inference variables.
89#[derive(Clone, Debug, PartialEq, Eq, Hash)]
90pub enum DomainGoal {
91 Holds(WhereClause),
92}
93
94#[derive(Clone, Debug, PartialEq, Eq, Hash)]
95pub struct AliasEq {
96 pub alias: AliasTy,
97 pub ty: Ty,
98}
99
100impl TypeWalk for AliasEq {
101 fn walk(&self, f: &mut impl FnMut(&Ty)) {
102 self.ty.walk(f);
103 match &self.alias {
104 AliasTy::Projection(projection_ty) => projection_ty.walk(f),
105 AliasTy::Opaque(opaque) => opaque.walk(f),
106 }
107 }
108
109 fn walk_mut_binders(
110 &mut self,
111 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
112 binders: DebruijnIndex,
113 ) {
114 self.ty.walk_mut_binders(f, binders);
115 match &mut self.alias {
116 AliasTy::Projection(projection_ty) => projection_ty.walk_mut_binders(f, binders),
117 AliasTy::Opaque(opaque) => opaque.walk_mut_binders(f, binders),
118 }
119 }
120}
121
122/// Solve a trait goal using Chalk. 71/// Solve a trait goal using Chalk.
123pub(crate) fn trait_solve_query( 72pub(crate) fn trait_solve_query(
124 db: &dyn HirDatabase, 73 db: &dyn HirDatabase,
@@ -130,6 +79,7 @@ pub(crate) fn trait_solve_query(
130 db.trait_data(it.hir_trait_id()).name.to_string() 79 db.trait_data(it.hir_trait_id()).name.to_string()
131 } 80 }
132 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(), 81 DomainGoal::Holds(WhereClause::AliasEq(_)) => "alias_eq".to_string(),
82 _ => "??".to_string(),
133 }); 83 });
134 log::info!("trait_solve_query({})", goal.value.goal.display(db)); 84 log::info!("trait_solve_query({})", goal.value.goal.display(db));
135 85
@@ -138,19 +88,18 @@ pub(crate) fn trait_solve_query(
138 .. 88 ..
139 })) = &goal.value.goal 89 })) = &goal.value.goal
140 { 90 {
141 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter().kind(&Interner) { 91 if let TyKind::BoundVar(_) = projection_ty.self_type_parameter(&Interner).kind(&Interner) {
142 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible 92 // Hack: don't ask Chalk to normalize with an unknown self type, it'll say that's impossible
143 return Some(Solution::Ambig(Guidance::Unknown)); 93 return Some(Solution::Ambig(Guidance::Unknown));
144 } 94 }
145 } 95 }
146 96
147 let canonical = goal.to_chalk(db).cast(&Interner); 97 let canonical = goal.cast(&Interner);
148 98
149 // We currently don't deal with universes (I think / hope they're not yet 99 // We currently don't deal with universes (I think / hope they're not yet
150 // relevant for our use cases?) 100 // relevant for our use cases?)
151 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 }; 101 let u_canonical = chalk_ir::UCanonical { canonical, universes: 1 };
152 let solution = solve(db, krate, &u_canonical); 102 solve(db, krate, &u_canonical)
153 solution.map(|solution| solution_from_chalk(db, solution))
154} 103}
155 104
156fn solve( 105fn solve(
@@ -197,7 +146,7 @@ fn solve(
197 // don't set the TLS for Chalk unless Chalk debugging is active, to make 146 // don't set the TLS for Chalk unless Chalk debugging is active, to make
198 // extra sure we only use it for debugging 147 // extra sure we only use it for debugging
199 let solution = 148 let solution =
200 if is_chalk_debug() { chalk::tls::set_current_program(db, solve) } else { solve() }; 149 if is_chalk_debug() { crate::tls::set_current_program(db, solve) } else { solve() };
201 150
202 solution 151 solution
203} 152}
@@ -218,69 +167,6 @@ fn is_chalk_print() -> bool {
218 std::env::var("CHALK_PRINT").is_ok() 167 std::env::var("CHALK_PRINT").is_ok()
219} 168}
220 169
221fn solution_from_chalk(
222 db: &dyn HirDatabase,
223 solution: chalk_solve::Solution<Interner>,
224) -> Solution {
225 let convert_subst = |subst: chalk_ir::Canonical<chalk_ir::Substitution<Interner>>| {
226 let result = from_chalk(db, subst);
227 SolutionVariables(result)
228 };
229 match solution {
230 chalk_solve::Solution::Unique(constr_subst) => {
231 let subst = chalk_ir::Canonical {
232 value: constr_subst.value.subst,
233 binders: constr_subst.binders,
234 };
235 Solution::Unique(convert_subst(subst))
236 }
237 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Definite(subst)) => {
238 Solution::Ambig(Guidance::Definite(convert_subst(subst)))
239 }
240 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Suggested(subst)) => {
241 Solution::Ambig(Guidance::Suggested(convert_subst(subst)))
242 }
243 chalk_solve::Solution::Ambig(chalk_solve::Guidance::Unknown) => {
244 Solution::Ambig(Guidance::Unknown)
245 }
246 }
247}
248
249#[derive(Clone, Debug, PartialEq, Eq)]
250pub struct SolutionVariables(pub Canonical<Substitution>);
251
252#[derive(Clone, Debug, PartialEq, Eq)]
253/// A (possible) solution for a proposed goal.
254pub enum Solution {
255 /// The goal indeed holds, and there is a unique value for all existential
256 /// variables.
257 Unique(SolutionVariables),
258
259 /// The goal may be provable in multiple ways, but regardless we may have some guidance
260 /// for type inference. In this case, we don't return any lifetime
261 /// constraints, since we have not "committed" to any particular solution
262 /// yet.
263 Ambig(Guidance),
264}
265
266#[derive(Clone, Debug, PartialEq, Eq)]
267/// When a goal holds ambiguously (e.g., because there are multiple possible
268/// solutions), we issue a set of *guidance* back to type inference.
269pub enum Guidance {
270 /// The existential variables *must* have the given values if the goal is
271 /// ever to hold, but that alone isn't enough to guarantee the goal will
272 /// actually hold.
273 Definite(SolutionVariables),
274
275 /// There are multiple plausible values for the existentials, but the ones
276 /// here are suggested as the preferred choice heuristically. These should
277 /// be used for inference fallback only.
278 Suggested(SolutionVariables),
279
280 /// There's no useful information to feed back to type inference
281 Unknown,
282}
283
284#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 170#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
285pub enum FnTrait { 171pub enum FnTrait {
286 FnOnce, 172 FnOnce,
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
deleted file mode 100644
index 452b357e8..000000000
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ /dev/null
@@ -1,575 +0,0 @@
1//! This module contains the implementations of the `ToChalk` trait, which
2//! handles conversion between our data types and their corresponding types in
3//! Chalk (in both directions); plus some helper functions for more specialized
4//! conversions.
5
6use chalk_ir::{cast::Cast, fold::shift::Shift, interner::HasInterner, LifetimeData};
7use chalk_solve::rust_ir;
8
9use base_db::salsa::InternKey;
10use hir_def::{GenericDefId, TypeAliasId};
11
12use crate::{
13 db::HirDatabase,
14 primitive::UintTy,
15 traits::{Canonical, DomainGoal},
16 AliasTy, CallableDefId, FnPointer, GenericArg, InEnvironment, OpaqueTy, ProjectionTy,
17 QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
18};
19
20use super::interner::*;
21use super::*;
22
23impl ToChalk for Ty {
24 type Chalk = chalk_ir::Ty<Interner>;
25 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
26 match self.into_inner() {
27 TyKind::Ref(m, ty) => ref_to_chalk(db, m, ty),
28 TyKind::Array(ty) => array_to_chalk(db, ty),
29 TyKind::Function(FnPointer { sig, substs, .. }) => {
30 let substitution = chalk_ir::FnSubst(substs.to_chalk(db).shifted_in(&Interner));
31 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
32 num_binders: 0,
33 sig,
34 substitution,
35 })
36 .intern(&Interner)
37 }
38 TyKind::AssociatedType(assoc_type_id, substs) => {
39 let substitution = substs.to_chalk(db);
40 chalk_ir::TyKind::AssociatedType(assoc_type_id, substitution).intern(&Interner)
41 }
42
43 TyKind::OpaqueType(id, substs) => {
44 let substitution = substs.to_chalk(db);
45 chalk_ir::TyKind::OpaqueType(id, substitution).intern(&Interner)
46 }
47
48 TyKind::ForeignType(id) => chalk_ir::TyKind::Foreign(id).intern(&Interner),
49
50 TyKind::Scalar(scalar) => chalk_ir::TyKind::Scalar(scalar).intern(&Interner),
51
52 TyKind::Tuple(cardinality, substs) => {
53 let substitution = substs.to_chalk(db);
54 chalk_ir::TyKind::Tuple(cardinality, substitution).intern(&Interner)
55 }
56 TyKind::Raw(mutability, ty) => {
57 let ty = ty.to_chalk(db);
58 chalk_ir::TyKind::Raw(mutability, ty).intern(&Interner)
59 }
60 TyKind::Slice(ty) => chalk_ir::TyKind::Slice(ty.to_chalk(db)).intern(&Interner),
61 TyKind::Str => chalk_ir::TyKind::Str.intern(&Interner),
62 TyKind::FnDef(id, substs) => {
63 let substitution = substs.to_chalk(db);
64 chalk_ir::TyKind::FnDef(id, substitution).intern(&Interner)
65 }
66 TyKind::Never => chalk_ir::TyKind::Never.intern(&Interner),
67
68 TyKind::Closure(closure_id, substs) => {
69 let substitution = substs.to_chalk(db);
70 chalk_ir::TyKind::Closure(closure_id, substitution).intern(&Interner)
71 }
72
73 TyKind::Adt(adt_id, substs) => {
74 let substitution = substs.to_chalk(db);
75 chalk_ir::TyKind::Adt(adt_id, substitution).intern(&Interner)
76 }
77 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
78 let associated_ty_id = proj_ty.associated_ty_id;
79 let substitution = proj_ty.substitution.to_chalk(db);
80 chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
81 associated_ty_id,
82 substitution,
83 })
84 .cast(&Interner)
85 .intern(&Interner)
86 }
87 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
88 let opaque_ty_id = opaque_ty.opaque_ty_id;
89 let substitution = opaque_ty.substitution.to_chalk(db);
90 chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy { opaque_ty_id, substitution })
91 .cast(&Interner)
92 .intern(&Interner)
93 }
94 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
95 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
96 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
97 TyKind::Dyn(dyn_ty) => {
98 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
99 &Interner,
100 dyn_ty.bounds.value.interned().iter().cloned().map(|p| p.to_chalk(db)),
101 );
102 let bounded_ty = chalk_ir::DynTy {
103 bounds: make_binders(where_clauses, 1),
104 lifetime: LifetimeData::Static.intern(&Interner),
105 };
106 chalk_ir::TyKind::Dyn(bounded_ty).intern(&Interner)
107 }
108 TyKind::Unknown => chalk_ir::TyKind::Error.intern(&Interner),
109 }
110 }
111 fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
112 match chalk.data(&Interner).kind.clone() {
113 chalk_ir::TyKind::Error => TyKind::Unknown,
114 chalk_ir::TyKind::Array(ty, _size) => TyKind::Array(from_chalk(db, ty)),
115 chalk_ir::TyKind::Placeholder(idx) => TyKind::Placeholder(idx),
116 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(proj)) => {
117 let associated_ty = proj.associated_ty_id;
118 let parameters = from_chalk(db, proj.substitution);
119 TyKind::Alias(AliasTy::Projection(ProjectionTy {
120 associated_ty_id: associated_ty,
121 substitution: parameters,
122 }))
123 }
124 chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(opaque_ty)) => {
125 let opaque_ty_id = opaque_ty.opaque_ty_id;
126 let parameters = from_chalk(db, opaque_ty.substitution);
127 TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, substitution: parameters }))
128 }
129 chalk_ir::TyKind::Function(chalk_ir::FnPointer {
130 num_binders,
131 sig,
132 substitution,
133 ..
134 }) => {
135 assert_eq!(num_binders, 0);
136 let substs: Substitution = from_chalk(
137 db,
138 substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
139 );
140 TyKind::Function(FnPointer { num_args: (substs.len(&Interner) - 1), sig, substs })
141 }
142 chalk_ir::TyKind::BoundVar(idx) => TyKind::BoundVar(idx),
143 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown,
144 chalk_ir::TyKind::Dyn(where_clauses) => {
145 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
146 let bounds = where_clauses
147 .bounds
148 .skip_binders()
149 .iter(&Interner)
150 .map(|c| from_chalk(db, c.clone()));
151 TyKind::Dyn(crate::DynTy {
152 bounds: crate::Binders::new(
153 1,
154 crate::QuantifiedWhereClauses::from_iter(&Interner, bounds),
155 ),
156 })
157 }
158
159 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
160 chalk_ir::TyKind::AssociatedType(type_id, subst) => {
161 TyKind::AssociatedType(type_id, from_chalk(db, subst))
162 }
163
164 chalk_ir::TyKind::OpaqueType(opaque_type_id, subst) => {
165 TyKind::OpaqueType(opaque_type_id, from_chalk(db, subst))
166 }
167
168 chalk_ir::TyKind::Scalar(scalar) => TyKind::Scalar(scalar),
169 chalk_ir::TyKind::Tuple(cardinality, subst) => {
170 TyKind::Tuple(cardinality, from_chalk(db, subst))
171 }
172 chalk_ir::TyKind::Raw(mutability, ty) => TyKind::Raw(mutability, from_chalk(db, ty)),
173 chalk_ir::TyKind::Slice(ty) => TyKind::Slice(from_chalk(db, ty)),
174 chalk_ir::TyKind::Ref(mutability, _lifetime, ty) => {
175 TyKind::Ref(mutability, from_chalk(db, ty))
176 }
177 chalk_ir::TyKind::Str => TyKind::Str,
178 chalk_ir::TyKind::Never => TyKind::Never,
179
180 chalk_ir::TyKind::FnDef(fn_def_id, subst) => {
181 TyKind::FnDef(fn_def_id, from_chalk(db, subst))
182 }
183
184 chalk_ir::TyKind::Closure(id, subst) => TyKind::Closure(id, from_chalk(db, subst)),
185
186 chalk_ir::TyKind::Foreign(foreign_def_id) => TyKind::ForeignType(foreign_def_id),
187 chalk_ir::TyKind::Generator(_, _) => unimplemented!(), // FIXME
188 chalk_ir::TyKind::GeneratorWitness(_, _) => unimplemented!(), // FIXME
189 }
190 .intern(&Interner)
191 }
192}
193
194/// We currently don't model lifetimes, but Chalk does. So, we have to insert a
195/// fake lifetime here, because Chalks built-in logic may expect it to be there.
196fn ref_to_chalk(
197 db: &dyn HirDatabase,
198 mutability: chalk_ir::Mutability,
199 ty: Ty,
200) -> chalk_ir::Ty<Interner> {
201 let arg = ty.to_chalk(db);
202 let lifetime = LifetimeData::Static.intern(&Interner);
203 chalk_ir::TyKind::Ref(mutability, lifetime, arg).intern(&Interner)
204}
205
206/// We currently don't model constants, but Chalk does. So, we have to insert a
207/// fake constant here, because Chalks built-in logic may expect it to be there.
208fn array_to_chalk(db: &dyn HirDatabase, ty: Ty) -> chalk_ir::Ty<Interner> {
209 let arg = ty.to_chalk(db);
210 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
211 let const_ = chalk_ir::ConstData {
212 ty: usize_ty,
213 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
214 }
215 .intern(&Interner);
216 chalk_ir::TyKind::Array(arg, const_).intern(&Interner)
217}
218
219impl ToChalk for GenericArg {
220 type Chalk = chalk_ir::GenericArg<Interner>;
221
222 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
223 match self.interned {
224 crate::GenericArgData::Ty(ty) => ty.to_chalk(db).cast(&Interner),
225 }
226 }
227
228 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
229 match chalk.interned() {
230 chalk_ir::GenericArgData::Ty(ty) => Ty::from_chalk(db, ty.clone()).cast(&Interner),
231 chalk_ir::GenericArgData::Lifetime(_) => unimplemented!(),
232 chalk_ir::GenericArgData::Const(_) => unimplemented!(),
233 }
234 }
235}
236
237impl ToChalk for Substitution {
238 type Chalk = chalk_ir::Substitution<Interner>;
239
240 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
241 chalk_ir::Substitution::from_iter(
242 &Interner,
243 self.iter(&Interner).map(|ty| ty.clone().to_chalk(db)),
244 )
245 }
246
247 fn from_chalk(
248 db: &dyn HirDatabase,
249 parameters: chalk_ir::Substitution<Interner>,
250 ) -> Substitution {
251 let tys = parameters.iter(&Interner).map(|p| from_chalk(db, p.clone())).collect();
252 Substitution(tys)
253 }
254}
255
256impl ToChalk for TraitRef {
257 type Chalk = chalk_ir::TraitRef<Interner>;
258
259 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
260 let trait_id = self.trait_id;
261 let substitution = self.substitution.to_chalk(db);
262 chalk_ir::TraitRef { trait_id, substitution }
263 }
264
265 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
266 let trait_id = trait_ref.trait_id;
267 let substs = from_chalk(db, trait_ref.substitution);
268 TraitRef { trait_id, substitution: substs }
269 }
270}
271
272impl ToChalk for hir_def::TraitId {
273 type Chalk = TraitId;
274
275 fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId {
276 chalk_ir::TraitId(self.as_intern_id())
277 }
278
279 fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
280 InternKey::from_intern_id(trait_id.0)
281 }
282}
283
284impl ToChalk for hir_def::ImplId {
285 type Chalk = ImplId;
286
287 fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId {
288 chalk_ir::ImplId(self.as_intern_id())
289 }
290
291 fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId {
292 InternKey::from_intern_id(impl_id.0)
293 }
294}
295
296impl ToChalk for CallableDefId {
297 type Chalk = FnDefId;
298
299 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
300 db.intern_callable_def(self).into()
301 }
302
303 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
304 db.lookup_intern_callable_def(fn_def_id.into())
305 }
306}
307
308pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId);
309
310impl ToChalk for TypeAliasAsValue {
311 type Chalk = AssociatedTyValueId;
312
313 fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId {
314 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
315 }
316
317 fn from_chalk(
318 _db: &dyn HirDatabase,
319 assoc_ty_value_id: AssociatedTyValueId,
320 ) -> TypeAliasAsValue {
321 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
322 }
323}
324
325impl ToChalk for WhereClause {
326 type Chalk = chalk_ir::WhereClause<Interner>;
327
328 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
329 match self {
330 WhereClause::Implemented(trait_ref) => {
331 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
332 }
333 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
334 }
335 }
336
337 fn from_chalk(
338 db: &dyn HirDatabase,
339 where_clause: chalk_ir::WhereClause<Interner>,
340 ) -> WhereClause {
341 match where_clause {
342 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
343 chalk_ir::WhereClause::AliasEq(alias_eq) => {
344 WhereClause::AliasEq(from_chalk(db, alias_eq))
345 }
346
347 chalk_ir::WhereClause::LifetimeOutlives(_) => {
348 // we shouldn't get these from Chalk
349 panic!("encountered LifetimeOutlives from Chalk")
350 }
351
352 chalk_ir::WhereClause::TypeOutlives(_) => {
353 // we shouldn't get these from Chalk
354 panic!("encountered TypeOutlives from Chalk")
355 }
356 }
357 }
358}
359
360impl ToChalk for ProjectionTy {
361 type Chalk = chalk_ir::ProjectionTy<Interner>;
362
363 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
364 chalk_ir::ProjectionTy {
365 associated_ty_id: self.associated_ty_id,
366 substitution: self.substitution.to_chalk(db),
367 }
368 }
369
370 fn from_chalk(
371 db: &dyn HirDatabase,
372 projection_ty: chalk_ir::ProjectionTy<Interner>,
373 ) -> ProjectionTy {
374 ProjectionTy {
375 associated_ty_id: projection_ty.associated_ty_id,
376 substitution: from_chalk(db, projection_ty.substitution),
377 }
378 }
379}
380impl ToChalk for OpaqueTy {
381 type Chalk = chalk_ir::OpaqueTy<Interner>;
382
383 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
384 chalk_ir::OpaqueTy {
385 opaque_ty_id: self.opaque_ty_id,
386 substitution: self.substitution.to_chalk(db),
387 }
388 }
389
390 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
391 OpaqueTy {
392 opaque_ty_id: chalk.opaque_ty_id,
393 substitution: from_chalk(db, chalk.substitution),
394 }
395 }
396}
397
398impl ToChalk for AliasTy {
399 type Chalk = chalk_ir::AliasTy<Interner>;
400
401 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
402 match self {
403 AliasTy::Projection(projection_ty) => {
404 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
405 }
406 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
407 }
408 }
409
410 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
411 match chalk {
412 chalk_ir::AliasTy::Projection(projection_ty) => {
413 AliasTy::Projection(from_chalk(db, projection_ty))
414 }
415 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
416 }
417 }
418}
419
420impl ToChalk for AliasEq {
421 type Chalk = chalk_ir::AliasEq<Interner>;
422
423 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
424 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
425 }
426
427 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
428 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
429 }
430}
431
432impl ToChalk for DomainGoal {
433 type Chalk = chalk_ir::DomainGoal<Interner>;
434
435 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
436 match self {
437 DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
438 DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
439 alias_eq.to_chalk(db).cast(&Interner)
440 }
441 }
442 }
443
444 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
445 unimplemented!()
446 }
447}
448
449impl<T> ToChalk for Canonical<T>
450where
451 T: ToChalk,
452 T::Chalk: HasInterner<Interner = Interner>,
453{
454 type Chalk = chalk_ir::Canonical<T::Chalk>;
455
456 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
457 let value = self.value.to_chalk(db);
458 chalk_ir::Canonical { value, binders: self.binders }
459 }
460
461 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
462 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
463 }
464}
465
466impl<T: ToChalk> ToChalk for InEnvironment<T>
467where
468 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
469{
470 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
471
472 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
473 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
474 }
475
476 fn from_chalk(
477 _db: &dyn HirDatabase,
478 _in_env: chalk_ir::InEnvironment<T::Chalk>,
479 ) -> InEnvironment<T> {
480 unimplemented!()
481 }
482}
483
484impl<T: ToChalk> ToChalk for crate::Binders<T>
485where
486 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
487{
488 type Chalk = chalk_ir::Binders<T::Chalk>;
489
490 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
491 chalk_ir::Binders::new(
492 chalk_ir::VariableKinds::from_iter(
493 &Interner,
494 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
495 .take(self.num_binders),
496 ),
497 self.value.to_chalk(db),
498 )
499 }
500
501 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
502 let (v, b) = binders.into_value_and_skipped_binders();
503 crate::Binders::new(b.len(&Interner), from_chalk(db, v))
504 }
505}
506
507pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
508where
509 T: HasInterner<Interner = Interner>,
510{
511 chalk_ir::Binders::new(
512 chalk_ir::VariableKinds::from_iter(
513 &Interner,
514 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
515 .take(num_vars),
516 ),
517 value,
518 )
519}
520
521pub(super) fn convert_where_clauses(
522 db: &dyn HirDatabase,
523 def: GenericDefId,
524 substs: &Substitution,
525) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
526 let generic_predicates = db.generic_predicates(def);
527 let mut result = Vec::with_capacity(generic_predicates.len());
528 for pred in generic_predicates.iter() {
529 result.push(pred.clone().subst(substs).to_chalk(db));
530 }
531 result
532}
533
534pub(super) fn generic_predicate_to_inline_bound(
535 db: &dyn HirDatabase,
536 pred: &QuantifiedWhereClause,
537 self_ty: &Ty,
538) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
539 // An InlineBound is like a GenericPredicate, except the self type is left out.
540 // We don't have a special type for this, but Chalk does.
541 let self_ty_shifted_in = self_ty.clone().shift_bound_vars(DebruijnIndex::ONE);
542 match &pred.value {
543 WhereClause::Implemented(trait_ref) => {
544 if trait_ref.self_type_parameter() != &self_ty_shifted_in {
545 // we can only convert predicates back to type bounds if they
546 // have the expected self type
547 return None;
548 }
549 let args_no_self = trait_ref.substitution.interned(&Interner)[1..]
550 .iter()
551 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
552 .collect();
553 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
554 Some(make_binders(rust_ir::InlineBound::TraitBound(trait_bound), pred.num_binders))
555 }
556 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
557 if projection_ty.self_type_parameter() != &self_ty_shifted_in {
558 return None;
559 }
560 let trait_ = projection_ty.trait_(db);
561 let args_no_self = projection_ty.substitution.interned(&Interner)[1..]
562 .iter()
563 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
564 .collect();
565 let alias_eq_bound = rust_ir::AliasEqBound {
566 value: ty.clone().to_chalk(db),
567 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
568 associated_ty_id: projection_ty.associated_ty_id,
569 parameters: Vec::new(), // FIXME we don't support generic associated types yet
570 };
571 Some(make_binders(rust_ir::InlineBound::AliasEqBound(alias_eq_bound), pred.num_binders))
572 }
573 _ => None,
574 }
575}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index b23e91b1b..2f04ee57a 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -1,22 +1,21 @@
1//! Helper functions for working with def, which don't need to be a separate 1//! Helper functions for working with def, which don't need to be a separate
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3use std::sync::Arc;
4 3
5use chalk_ir::{BoundVar, DebruijnIndex}; 4use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
6use hir_def::{ 5use hir_def::{
7 adt::VariantData,
8 db::DefDatabase, 6 db::DefDatabase,
9 generics::{ 7 generics::{
10 GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget, 8 GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
11 }, 9 },
10 intern::Interned,
12 path::Path, 11 path::Path,
13 resolver::{HasResolver, TypeNs}, 12 resolver::{HasResolver, TypeNs},
14 type_ref::TypeRef, 13 type_ref::TypeRef,
15 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId, VariantId, 14 AssocContainerId, GenericDefId, Lookup, TraitId, TypeAliasId, TypeParamId,
16}; 15};
17use hir_expand::name::{name, Name}; 16use hir_expand::name::{name, Name};
18 17
19use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TyKind, TypeWalk, WhereClause}; 18use crate::{db::HirDatabase, Interner, Substitution, TraitRef, TraitRefExt, TyKind, WhereClause};
20 19
21fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 20fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
22 let resolver = trait_.resolver(db); 21 let resolver = trait_.resolver(db);
@@ -32,11 +31,10 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
32 .filter_map(|pred| match pred { 31 .filter_map(|pred| match pred {
33 WherePredicate::ForLifetime { target, bound, .. } 32 WherePredicate::ForLifetime { target, bound, .. }
34 | WherePredicate::TypeBound { target, bound } => match target { 33 | WherePredicate::TypeBound { target, bound } => match target {
35 WherePredicateTypeTarget::TypeRef(TypeRef::Path(p)) 34 WherePredicateTypeTarget::TypeRef(type_ref) => match &**type_ref {
36 if p == &Path::from(name![Self]) => 35 TypeRef::Path(p) if p == &Path::from(name![Self]) => bound.as_path(),
37 { 36 _ => None,
38 bound.as_path() 37 },
39 }
40 WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => { 38 WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => {
41 bound.as_path() 39 bound.as_path()
42 } 40 }
@@ -66,19 +64,21 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
66 .filter_map(|pred| { 64 .filter_map(|pred| {
67 pred.as_ref().filter_map(|pred| match pred.skip_binders() { 65 pred.as_ref().filter_map(|pred| match pred.skip_binders() {
68 // FIXME: how to correctly handle higher-ranked bounds here? 66 // FIXME: how to correctly handle higher-ranked bounds here?
69 WhereClause::Implemented(tr) => { 67 WhereClause::Implemented(tr) => Some(
70 Some(tr.clone().shift_bound_vars_out(DebruijnIndex::ONE)) 68 tr.clone()
71 } 69 .shifted_out_to(&Interner, DebruijnIndex::ONE)
70 .expect("FIXME unexpected higher-ranked trait bound"),
71 ),
72 _ => None, 72 _ => None,
73 }) 73 })
74 }) 74 })
75 .map(|pred| pred.subst(&trait_ref.substitution)) 75 .map(|pred| pred.substitute(&Interner, &trait_ref.substitution))
76 .collect() 76 .collect()
77} 77}
78 78
79/// Returns an iterator over the whole super trait hierarchy (including the 79/// Returns an iterator over the whole super trait hierarchy (including the
80/// trait itself). 80/// trait itself).
81pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> { 81pub fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<TraitId> {
82 // we need to take care a bit here to avoid infinite loops in case of cycles 82 // we need to take care a bit here to avoid infinite loops in case of cycles
83 // (i.e. if we have `trait A: B; trait B: A;`) 83 // (i.e. if we have `trait A: B; trait B: A;`)
84 let mut result = vec![trait_]; 84 let mut result = vec![trait_];
@@ -103,6 +103,8 @@ pub(super) fn all_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> Vec<Tra
103/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get 103/// we have `Self: Trait<u32, i32>` and `Trait<T, U>: OtherTrait<U>` we'll get
104/// `Self: OtherTrait<i32>`. 104/// `Self: OtherTrait<i32>`.
105pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> { 105pub(super) fn all_super_trait_refs(db: &dyn HirDatabase, trait_ref: TraitRef) -> Vec<TraitRef> {
106 // FIXME: replace by Chalk's `super_traits`, maybe make this a query
107
106 // we need to take care a bit here to avoid infinite loops in case of cycles 108 // we need to take care a bit here to avoid infinite loops in case of cycles
107 // (i.e. if we have `trait A: B; trait B: A;`) 109 // (i.e. if we have `trait A: B; trait B: A;`)
108 let mut result = vec![trait_ref]; 110 let mut result = vec![trait_ref];
@@ -132,25 +134,6 @@ pub(super) fn associated_type_by_name_including_super_traits(
132 }) 134 })
133} 135}
134 136
135pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> {
136 match var {
137 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
138 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
139 VariantId::EnumVariantId(it) => {
140 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
141 }
142 }
143}
144
145/// Helper for mutating `Arc<[T]>` (i.e. `Arc::make_mut` for Arc slices).
146/// The underlying values are cloned if there are other strong references.
147pub(crate) fn make_mut_slice<T: Clone>(a: &mut Arc<[T]>) -> &mut [T] {
148 if Arc::get_mut(a).is_none() {
149 *a = a.iter().cloned().collect();
150 }
151 Arc::get_mut(a).unwrap()
152}
153
154pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { 137pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
155 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def))); 138 let parent_generics = parent_generic_def(db, def).map(|def| Box::new(generics(db, def)));
156 Generics { def, params: db.generic_params(def), parent_generics } 139 Generics { def, params: db.generic_params(def), parent_generics }
@@ -159,7 +142,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics {
159#[derive(Debug)] 142#[derive(Debug)]
160pub(crate) struct Generics { 143pub(crate) struct Generics {
161 def: GenericDefId, 144 def: GenericDefId,
162 pub(crate) params: Arc<GenericParams>, 145 pub(crate) params: Interned<GenericParams>,
163 parent_generics: Option<Box<Generics>>, 146 parent_generics: Option<Box<Generics>>,
164} 147}
165 148
diff --git a/crates/hir_ty/src/walk.rs b/crates/hir_ty/src/walk.rs
new file mode 100644
index 000000000..6ef1d5336
--- /dev/null
+++ b/crates/hir_ty/src/walk.rs
@@ -0,0 +1,150 @@
1//! The `TypeWalk` trait (probably to be replaced by Chalk's `Fold` and
2//! `Visit`).
3
4use chalk_ir::interner::HasInterner;
5
6use crate::{
7 AliasEq, AliasTy, Binders, CallableSig, FnSubst, GenericArg, GenericArgData, Interner,
8 OpaqueTy, ProjectionTy, Substitution, TraitRef, Ty, TyKind, WhereClause,
9};
10
11/// This allows walking structures that contain types to do something with those
12/// types, similar to Chalk's `Fold` trait.
13pub trait TypeWalk {
14 fn walk(&self, f: &mut impl FnMut(&Ty));
15}
16
17impl TypeWalk for Ty {
18 fn walk(&self, f: &mut impl FnMut(&Ty)) {
19 match self.kind(&Interner) {
20 TyKind::Alias(AliasTy::Projection(p_ty)) => {
21 for t in p_ty.substitution.iter(&Interner) {
22 t.walk(f);
23 }
24 }
25 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
26 for t in o_ty.substitution.iter(&Interner) {
27 t.walk(f);
28 }
29 }
30 TyKind::Dyn(dyn_ty) => {
31 for p in dyn_ty.bounds.skip_binders().interned().iter() {
32 p.walk(f);
33 }
34 }
35 TyKind::Slice(ty)
36 | TyKind::Array(ty, _)
37 | TyKind::Ref(_, _, ty)
38 | TyKind::Raw(_, ty) => {
39 ty.walk(f);
40 }
41 TyKind::Function(fn_pointer) => {
42 fn_pointer.substitution.0.walk(f);
43 }
44 TyKind::Adt(_, substs)
45 | TyKind::FnDef(_, substs)
46 | TyKind::Tuple(_, substs)
47 | TyKind::OpaqueType(_, substs)
48 | TyKind::AssociatedType(_, substs)
49 | TyKind::Closure(.., substs) => {
50 substs.walk(f);
51 }
52 _ => {}
53 }
54 f(self);
55 }
56}
57
58impl<T: TypeWalk> TypeWalk for Vec<T> {
59 fn walk(&self, f: &mut impl FnMut(&Ty)) {
60 for t in self {
61 t.walk(f);
62 }
63 }
64}
65
66impl TypeWalk for OpaqueTy {
67 fn walk(&self, f: &mut impl FnMut(&Ty)) {
68 self.substitution.walk(f);
69 }
70}
71
72impl TypeWalk for ProjectionTy {
73 fn walk(&self, f: &mut impl FnMut(&Ty)) {
74 self.substitution.walk(f);
75 }
76}
77
78impl TypeWalk for AliasTy {
79 fn walk(&self, f: &mut impl FnMut(&Ty)) {
80 match self {
81 AliasTy::Projection(it) => it.walk(f),
82 AliasTy::Opaque(it) => it.walk(f),
83 }
84 }
85}
86
87impl TypeWalk for GenericArg {
88 fn walk(&self, f: &mut impl FnMut(&Ty)) {
89 match &self.interned() {
90 GenericArgData::Ty(ty) => {
91 ty.walk(f);
92 }
93 _ => {}
94 }
95 }
96}
97
98impl TypeWalk for Substitution {
99 fn walk(&self, f: &mut impl FnMut(&Ty)) {
100 for t in self.iter(&Interner) {
101 t.walk(f);
102 }
103 }
104}
105
106impl<T: TypeWalk + HasInterner<Interner = Interner>> TypeWalk for Binders<T> {
107 fn walk(&self, f: &mut impl FnMut(&Ty)) {
108 self.skip_binders().walk(f);
109 }
110}
111
112impl TypeWalk for TraitRef {
113 fn walk(&self, f: &mut impl FnMut(&Ty)) {
114 self.substitution.walk(f);
115 }
116}
117
118impl TypeWalk for WhereClause {
119 fn walk(&self, f: &mut impl FnMut(&Ty)) {
120 match self {
121 WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
122 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
123 _ => {}
124 }
125 }
126}
127
128impl TypeWalk for CallableSig {
129 fn walk(&self, f: &mut impl FnMut(&Ty)) {
130 for t in self.params_and_return.iter() {
131 t.walk(f);
132 }
133 }
134}
135
136impl TypeWalk for AliasEq {
137 fn walk(&self, f: &mut impl FnMut(&Ty)) {
138 self.ty.walk(f);
139 match &self.alias {
140 AliasTy::Projection(projection_ty) => projection_ty.walk(f),
141 AliasTy::Opaque(opaque) => opaque.walk(f),
142 }
143 }
144}
145
146impl TypeWalk for FnSubst<Interner> {
147 fn walk(&self, f: &mut impl FnMut(&Ty)) {
148 self.0.walk(f)
149 }
150}
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index dd42116a7..1c911a8b2 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -20,12 +20,12 @@ use itertools::Itertools;
20use rustc_hash::FxHashSet; 20use rustc_hash::FxHashSet;
21use syntax::{ 21use syntax::{
22 ast::{self, AstNode}, 22 ast::{self, AstNode},
23 SyntaxNode, SyntaxNodePtr, TextRange, 23 SyntaxNode, SyntaxNodePtr, TextRange, TextSize,
24}; 24};
25use text_edit::TextEdit; 25use text_edit::TextEdit;
26use unlinked_file::UnlinkedFile; 26use unlinked_file::UnlinkedFile;
27 27
28use crate::{FileId, Label, SourceChange}; 28use crate::{Assist, AssistId, AssistKind, FileId, Label, SourceChange};
29 29
30use self::fixes::DiagnosticWithFix; 30use self::fixes::DiagnosticWithFix;
31 31
@@ -35,7 +35,7 @@ pub struct Diagnostic {
35 pub message: String, 35 pub message: String,
36 pub range: TextRange, 36 pub range: TextRange,
37 pub severity: Severity, 37 pub severity: Severity,
38 pub fix: Option<Fix>, 38 pub fix: Option<Assist>,
39 pub unused: bool, 39 pub unused: bool,
40 pub code: Option<DiagnosticCode>, 40 pub code: Option<DiagnosticCode>,
41} 41}
@@ -56,7 +56,7 @@ impl Diagnostic {
56 } 56 }
57 } 57 }
58 58
59 fn with_fix(self, fix: Option<Fix>) -> Self { 59 fn with_fix(self, fix: Option<Assist>) -> Self {
60 Self { fix, ..self } 60 Self { fix, ..self }
61 } 61 }
62 62
@@ -69,21 +69,6 @@ impl Diagnostic {
69 } 69 }
70} 70}
71 71
72#[derive(Debug)]
73pub struct Fix {
74 pub label: Label,
75 pub source_change: SourceChange,
76 /// Allows to trigger the fix only when the caret is in the range given
77 pub fix_trigger_range: TextRange,
78}
79
80impl Fix {
81 fn new(label: &str, source_change: SourceChange, fix_trigger_range: TextRange) -> Self {
82 let label = Label::new(label);
83 Self { label, source_change, fix_trigger_range }
84 }
85}
86
87#[derive(Debug, Copy, Clone)] 72#[derive(Debug, Copy, Clone)]
88pub enum Severity { 73pub enum Severity {
89 Error, 74 Error,
@@ -99,6 +84,7 @@ pub struct DiagnosticsConfig {
99pub(crate) fn diagnostics( 84pub(crate) fn diagnostics(
100 db: &RootDatabase, 85 db: &RootDatabase,
101 config: &DiagnosticsConfig, 86 config: &DiagnosticsConfig,
87 resolve: bool,
102 file_id: FileId, 88 file_id: FileId,
103) -> Vec<Diagnostic> { 89) -> Vec<Diagnostic> {
104 let _p = profile::span("diagnostics"); 90 let _p = profile::span("diagnostics");
@@ -122,25 +108,25 @@ pub(crate) fn diagnostics(
122 let res = RefCell::new(res); 108 let res = RefCell::new(res);
123 let sink_builder = DiagnosticSinkBuilder::new() 109 let sink_builder = DiagnosticSinkBuilder::new()
124 .on::<hir::diagnostics::UnresolvedModule, _>(|d| { 110 .on::<hir::diagnostics::UnresolvedModule, _>(|d| {
125 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 111 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
126 }) 112 })
127 .on::<hir::diagnostics::MissingFields, _>(|d| { 113 .on::<hir::diagnostics::MissingFields, _>(|d| {
128 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 114 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
129 }) 115 })
130 .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| { 116 .on::<hir::diagnostics::MissingOkOrSomeInTailExpr, _>(|d| {
131 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 117 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
132 }) 118 })
133 .on::<hir::diagnostics::NoSuchField, _>(|d| { 119 .on::<hir::diagnostics::NoSuchField, _>(|d| {
134 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 120 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
135 }) 121 })
136 .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| { 122 .on::<hir::diagnostics::RemoveThisSemicolon, _>(|d| {
137 res.borrow_mut().push(diagnostic_with_fix(d, &sema)); 123 res.borrow_mut().push(diagnostic_with_fix(d, &sema, resolve));
138 }) 124 })
139 .on::<hir::diagnostics::IncorrectCase, _>(|d| { 125 .on::<hir::diagnostics::IncorrectCase, _>(|d| {
140 res.borrow_mut().push(warning_with_fix(d, &sema)); 126 res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
141 }) 127 })
142 .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| { 128 .on::<hir::diagnostics::ReplaceFilterMapNextWithFindMap, _>(|d| {
143 res.borrow_mut().push(warning_with_fix(d, &sema)); 129 res.borrow_mut().push(warning_with_fix(d, &sema, resolve));
144 }) 130 })
145 .on::<hir::diagnostics::InactiveCode, _>(|d| { 131 .on::<hir::diagnostics::InactiveCode, _>(|d| {
146 // If there's inactive code somewhere in a macro, don't propagate to the call-site. 132 // If there's inactive code somewhere in a macro, don't propagate to the call-site.
@@ -159,14 +145,16 @@ pub(crate) fn diagnostics(
159 ); 145 );
160 }) 146 })
161 .on::<UnlinkedFile, _>(|d| { 147 .on::<UnlinkedFile, _>(|d| {
148 // Limit diagnostic to the first few characters in the file. This matches how VS Code
149 // renders it with the full span, but on other editors, and is less invasive.
150 let range = sema.diagnostics_display_range(d.display_source()).range;
151 let range = range.intersect(TextRange::up_to(TextSize::of("..."))).unwrap_or(range);
152
162 // Override severity and mark as unused. 153 // Override severity and mark as unused.
163 res.borrow_mut().push( 154 res.borrow_mut().push(
164 Diagnostic::hint( 155 Diagnostic::hint(range, d.message())
165 sema.diagnostics_display_range(d.display_source()).range, 156 .with_fix(d.fix(&sema, resolve))
166 d.message(), 157 .with_code(Some(d.code())),
167 )
168 .with_fix(d.fix(&sema))
169 .with_code(Some(d.code())),
170 ); 158 );
171 }) 159 })
172 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { 160 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
@@ -221,15 +209,23 @@ pub(crate) fn diagnostics(
221 res.into_inner() 209 res.into_inner()
222} 210}
223 211
224fn diagnostic_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 212fn diagnostic_with_fix<D: DiagnosticWithFix>(
213 d: &D,
214 sema: &Semantics<RootDatabase>,
215 resolve: bool,
216) -> Diagnostic {
225 Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message()) 217 Diagnostic::error(sema.diagnostics_display_range(d.display_source()).range, d.message())
226 .with_fix(d.fix(&sema)) 218 .with_fix(d.fix(&sema, resolve))
227 .with_code(Some(d.code())) 219 .with_code(Some(d.code()))
228} 220}
229 221
230fn warning_with_fix<D: DiagnosticWithFix>(d: &D, sema: &Semantics<RootDatabase>) -> Diagnostic { 222fn warning_with_fix<D: DiagnosticWithFix>(
223 d: &D,
224 sema: &Semantics<RootDatabase>,
225 resolve: bool,
226) -> Diagnostic {
231 Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message()) 227 Diagnostic::hint(sema.diagnostics_display_range(d.display_source()).range, d.message())
232 .with_fix(d.fix(&sema)) 228 .with_fix(d.fix(&sema, resolve))
233 .with_code(Some(d.code())) 229 .with_code(Some(d.code()))
234} 230}
235 231
@@ -259,7 +255,8 @@ fn check_unnecessary_braces_in_use_statement(
259 255
260 acc.push( 256 acc.push(
261 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) 257 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
262 .with_fix(Some(Fix::new( 258 .with_fix(Some(fix(
259 "remove_braces",
263 "Remove unnecessary braces", 260 "Remove unnecessary braces",
264 SourceChange::from_text_edit(file_id, edit), 261 SourceChange::from_text_edit(file_id, edit),
265 use_range, 262 use_range,
@@ -282,6 +279,23 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
282 None 279 None
283} 280}
284 281
282fn fix(id: &'static str, label: &str, source_change: SourceChange, target: TextRange) -> Assist {
283 let mut res = unresolved_fix(id, label, target);
284 res.source_change = Some(source_change);
285 res
286}
287
288fn unresolved_fix(id: &'static str, label: &str, target: TextRange) -> Assist {
289 assert!(!id.contains(' '));
290 Assist {
291 id: AssistId(id, AssistKind::QuickFix),
292 label: Label::new(label),
293 group: None,
294 target,
295 source_change: None,
296 }
297}
298
285#[cfg(test)] 299#[cfg(test)]
286mod tests { 300mod tests {
287 use expect_test::{expect, Expect}; 301 use expect_test::{expect, Expect};
@@ -300,16 +314,17 @@ mod tests {
300 314
301 let (analysis, file_position) = fixture::position(ra_fixture_before); 315 let (analysis, file_position) = fixture::position(ra_fixture_before);
302 let diagnostic = analysis 316 let diagnostic = analysis
303 .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) 317 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
304 .unwrap() 318 .unwrap()
305 .pop() 319 .pop()
306 .unwrap(); 320 .unwrap();
307 let fix = diagnostic.fix.unwrap(); 321 let fix = diagnostic.fix.unwrap();
308 let actual = { 322 let actual = {
309 let file_id = *fix.source_change.source_file_edits.keys().next().unwrap(); 323 let source_change = fix.source_change.unwrap();
324 let file_id = *source_change.source_file_edits.keys().next().unwrap();
310 let mut actual = analysis.file_text(file_id).unwrap().to_string(); 325 let mut actual = analysis.file_text(file_id).unwrap().to_string();
311 326
312 for edit in fix.source_change.source_file_edits.values() { 327 for edit in source_change.source_file_edits.values() {
313 edit.apply(&mut actual); 328 edit.apply(&mut actual);
314 } 329 }
315 actual 330 actual
@@ -317,9 +332,9 @@ mod tests {
317 332
318 assert_eq_text!(&after, &actual); 333 assert_eq_text!(&after, &actual);
319 assert!( 334 assert!(
320 fix.fix_trigger_range.contains_inclusive(file_position.offset), 335 fix.target.contains_inclusive(file_position.offset),
321 "diagnostic fix range {:?} does not touch cursor position {:?}", 336 "diagnostic fix range {:?} does not touch cursor position {:?}",
322 fix.fix_trigger_range, 337 fix.target,
323 file_position.offset 338 file_position.offset
324 ); 339 );
325 } 340 }
@@ -328,7 +343,7 @@ mod tests {
328 fn check_no_fix(ra_fixture: &str) { 343 fn check_no_fix(ra_fixture: &str) {
329 let (analysis, file_position) = fixture::position(ra_fixture); 344 let (analysis, file_position) = fixture::position(ra_fixture);
330 let diagnostic = analysis 345 let diagnostic = analysis
331 .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) 346 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
332 .unwrap() 347 .unwrap()
333 .pop() 348 .pop()
334 .unwrap(); 349 .unwrap();
@@ -342,7 +357,7 @@ mod tests {
342 let diagnostics = files 357 let diagnostics = files
343 .into_iter() 358 .into_iter()
344 .flat_map(|file_id| { 359 .flat_map(|file_id| {
345 analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() 360 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap()
346 }) 361 })
347 .collect::<Vec<_>>(); 362 .collect::<Vec<_>>();
348 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); 363 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
@@ -350,7 +365,8 @@ mod tests {
350 365
351 fn check_expect(ra_fixture: &str, expect: Expect) { 366 fn check_expect(ra_fixture: &str, expect: Expect) {
352 let (analysis, file_id) = fixture::file(ra_fixture); 367 let (analysis, file_id) = fixture::file(ra_fixture);
353 let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); 368 let diagnostics =
369 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap();
354 expect.assert_debug_eq(&diagnostics) 370 expect.assert_debug_eq(&diagnostics)
355 } 371 }
356 372
@@ -663,24 +679,31 @@ fn test_fn() {
663 range: 0..8, 679 range: 0..8,
664 severity: Error, 680 severity: Error,
665 fix: Some( 681 fix: Some(
666 Fix { 682 Assist {
683 id: AssistId(
684 "create_module",
685 QuickFix,
686 ),
667 label: "Create module", 687 label: "Create module",
668 source_change: SourceChange { 688 group: None,
669 source_file_edits: {}, 689 target: 0..8,
670 file_system_edits: [ 690 source_change: Some(
671 CreateFile { 691 SourceChange {
672 dst: AnchoredPathBuf { 692 source_file_edits: {},
673 anchor: FileId( 693 file_system_edits: [
674 0, 694 CreateFile {
675 ), 695 dst: AnchoredPathBuf {
676 path: "foo.rs", 696 anchor: FileId(
697 0,
698 ),
699 path: "foo.rs",
700 },
701 initial_contents: "",
677 }, 702 },
678 initial_contents: "", 703 ],
679 }, 704 is_snippet: false,
680 ], 705 },
681 is_snippet: false, 706 ),
682 },
683 fix_trigger_range: 0..8,
684 }, 707 },
685 ), 708 ),
686 unused: false, 709 unused: false,
@@ -702,7 +725,7 @@ fn test_fn() {
702 expect![[r#" 725 expect![[r#"
703 [ 726 [
704 Diagnostic { 727 Diagnostic {
705 message: "unresolved macro call", 728 message: "unresolved macro `foo::bar!`",
706 range: 5..8, 729 range: 5..8,
707 severity: Error, 730 severity: Error,
708 fix: None, 731 fix: None,
@@ -888,10 +911,11 @@ struct Foo {
888 911
889 let (analysis, file_id) = fixture::file(r#"mod foo;"#); 912 let (analysis, file_id) = fixture::file(r#"mod foo;"#);
890 913
891 let diagnostics = analysis.diagnostics(&config, file_id).unwrap(); 914 let diagnostics = analysis.diagnostics(&config, true, file_id).unwrap();
892 assert!(diagnostics.is_empty()); 915 assert!(diagnostics.is_empty());
893 916
894 let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); 917 let diagnostics =
918 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap();
895 assert!(!diagnostics.is_empty()); 919 assert!(!diagnostics.is_empty());
896 } 920 }
897 921
@@ -997,8 +1021,9 @@ impl TestStruct {
997 let expected = r#"fn foo() {}"#; 1021 let expected = r#"fn foo() {}"#;
998 1022
999 let (analysis, file_position) = fixture::position(input); 1023 let (analysis, file_position) = fixture::position(input);
1000 let diagnostics = 1024 let diagnostics = analysis
1001 analysis.diagnostics(&DiagnosticsConfig::default(), file_position.file_id).unwrap(); 1025 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
1026 .unwrap();
1002 assert_eq!(diagnostics.len(), 1); 1027 assert_eq!(diagnostics.len(), 1);
1003 1028
1004 check_fix(input, expected); 1029 check_fix(input, expected);
diff --git a/crates/ide/src/diagnostics/field_shorthand.rs b/crates/ide/src/diagnostics/field_shorthand.rs
index 5c89e2170..2b1787f9b 100644
--- a/crates/ide/src/diagnostics/field_shorthand.rs
+++ b/crates/ide/src/diagnostics/field_shorthand.rs
@@ -5,7 +5,7 @@ use ide_db::{base_db::FileId, source_change::SourceChange};
5use syntax::{ast, match_ast, AstNode, SyntaxNode}; 5use syntax::{ast, match_ast, AstNode, SyntaxNode};
6use text_edit::TextEdit; 6use text_edit::TextEdit;
7 7
8use crate::{Diagnostic, Fix}; 8use crate::{diagnostics::fix, Diagnostic};
9 9
10pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) { 10pub(super) fn check(acc: &mut Vec<Diagnostic>, file_id: FileId, node: &SyntaxNode) {
11 match_ast! { 11 match_ast! {
@@ -47,7 +47,8 @@ fn check_expr_field_shorthand(
47 let field_range = record_field.syntax().text_range(); 47 let field_range = record_field.syntax().text_range();
48 acc.push( 48 acc.push(
49 Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix( 49 Diagnostic::hint(field_range, "Shorthand struct initialization".to_string()).with_fix(
50 Some(Fix::new( 50 Some(fix(
51 "use_expr_field_shorthand",
51 "Use struct shorthand initialization", 52 "Use struct shorthand initialization",
52 SourceChange::from_text_edit(file_id, edit), 53 SourceChange::from_text_edit(file_id, edit),
53 field_range, 54 field_range,
@@ -86,7 +87,8 @@ fn check_pat_field_shorthand(
86 87
87 let field_range = record_pat_field.syntax().text_range(); 88 let field_range = record_pat_field.syntax().text_range();
88 acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix( 89 acc.push(Diagnostic::hint(field_range, "Shorthand struct pattern".to_string()).with_fix(
89 Some(Fix::new( 90 Some(fix(
91 "use_pat_field_shorthand",
90 "Use struct field shorthand", 92 "Use struct field shorthand",
91 SourceChange::from_text_edit(file_id, edit), 93 SourceChange::from_text_edit(file_id, edit),
92 field_range, 94 field_range,
diff --git a/crates/ide/src/diagnostics/fixes.rs b/crates/ide/src/diagnostics/fixes.rs
index 5fb3e2d91..7be8b3459 100644
--- a/crates/ide/src/diagnostics/fixes.rs
+++ b/crates/ide/src/diagnostics/fixes.rs
@@ -20,20 +20,30 @@ use syntax::{
20}; 20};
21use text_edit::TextEdit; 21use text_edit::TextEdit;
22 22
23use crate::{diagnostics::Fix, references::rename::rename_with_semantics, FilePosition}; 23use crate::{
24 diagnostics::{fix, unresolved_fix},
25 references::rename::rename_with_semantics,
26 Assist, FilePosition,
27};
24 28
25/// A [Diagnostic] that potentially has a fix available. 29/// A [Diagnostic] that potentially has a fix available.
26/// 30///
27/// [Diagnostic]: hir::diagnostics::Diagnostic 31/// [Diagnostic]: hir::diagnostics::Diagnostic
28pub(crate) trait DiagnosticWithFix: Diagnostic { 32pub(crate) trait DiagnosticWithFix: Diagnostic {
29 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix>; 33 /// `resolve` determines if the diagnostic should fill in the `edit` field
34 /// of the assist.
35 ///
36 /// If `resolve` is false, the edit will be computed later, on demand, and
37 /// can be omitted.
38 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist>;
30} 39}
31 40
32impl DiagnosticWithFix for UnresolvedModule { 41impl DiagnosticWithFix for UnresolvedModule {
33 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 42 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
34 let root = sema.db.parse_or_expand(self.file)?; 43 let root = sema.db.parse_or_expand(self.file)?;
35 let unresolved_module = self.decl.to_node(&root); 44 let unresolved_module = self.decl.to_node(&root);
36 Some(Fix::new( 45 Some(fix(
46 "create_module",
37 "Create module", 47 "Create module",
38 FileSystemEdit::CreateFile { 48 FileSystemEdit::CreateFile {
39 dst: AnchoredPathBuf { 49 dst: AnchoredPathBuf {
@@ -49,7 +59,7 @@ impl DiagnosticWithFix for UnresolvedModule {
49} 59}
50 60
51impl DiagnosticWithFix for NoSuchField { 61impl DiagnosticWithFix for NoSuchField {
52 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 62 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
53 let root = sema.db.parse_or_expand(self.file)?; 63 let root = sema.db.parse_or_expand(self.file)?;
54 missing_record_expr_field_fix( 64 missing_record_expr_field_fix(
55 &sema, 65 &sema,
@@ -60,7 +70,7 @@ impl DiagnosticWithFix for NoSuchField {
60} 70}
61 71
62impl DiagnosticWithFix for MissingFields { 72impl DiagnosticWithFix for MissingFields {
63 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 73 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
64 // Note that although we could add a diagnostics to 74 // Note that although we could add a diagnostics to
65 // fill the missing tuple field, e.g : 75 // fill the missing tuple field, e.g :
66 // `struct A(usize);` 76 // `struct A(usize);`
@@ -86,7 +96,8 @@ impl DiagnosticWithFix for MissingFields {
86 .into_text_edit(&mut builder); 96 .into_text_edit(&mut builder);
87 builder.finish() 97 builder.finish()
88 }; 98 };
89 Some(Fix::new( 99 Some(fix(
100 "fill_missing_fields",
90 "Fill struct fields", 101 "Fill struct fields",
91 SourceChange::from_text_edit(self.file.original_file(sema.db), edit), 102 SourceChange::from_text_edit(self.file.original_file(sema.db), edit),
92 sema.original_range(&field_list_parent.syntax()).range, 103 sema.original_range(&field_list_parent.syntax()).range,
@@ -95,7 +106,7 @@ impl DiagnosticWithFix for MissingFields {
95} 106}
96 107
97impl DiagnosticWithFix for MissingOkOrSomeInTailExpr { 108impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
98 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 109 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
99 let root = sema.db.parse_or_expand(self.file)?; 110 let root = sema.db.parse_or_expand(self.file)?;
100 let tail_expr = self.expr.to_node(&root); 111 let tail_expr = self.expr.to_node(&root);
101 let tail_expr_range = tail_expr.syntax().text_range(); 112 let tail_expr_range = tail_expr.syntax().text_range();
@@ -103,12 +114,12 @@ impl DiagnosticWithFix for MissingOkOrSomeInTailExpr {
103 let edit = TextEdit::replace(tail_expr_range, replacement); 114 let edit = TextEdit::replace(tail_expr_range, replacement);
104 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); 115 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
105 let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" }; 116 let name = if self.required == "Ok" { "Wrap with Ok" } else { "Wrap with Some" };
106 Some(Fix::new(name, source_change, tail_expr_range)) 117 Some(fix("wrap_tail_expr", name, source_change, tail_expr_range))
107 } 118 }
108} 119}
109 120
110impl DiagnosticWithFix for RemoveThisSemicolon { 121impl DiagnosticWithFix for RemoveThisSemicolon {
111 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 122 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
112 let root = sema.db.parse_or_expand(self.file)?; 123 let root = sema.db.parse_or_expand(self.file)?;
113 124
114 let semicolon = self 125 let semicolon = self
@@ -123,12 +134,12 @@ impl DiagnosticWithFix for RemoveThisSemicolon {
123 let edit = TextEdit::delete(semicolon); 134 let edit = TextEdit::delete(semicolon);
124 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); 135 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
125 136
126 Some(Fix::new("Remove this semicolon", source_change, semicolon)) 137 Some(fix("remove_semicolon", "Remove this semicolon", source_change, semicolon))
127 } 138 }
128} 139}
129 140
130impl DiagnosticWithFix for IncorrectCase { 141impl DiagnosticWithFix for IncorrectCase {
131 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 142 fn fix(&self, sema: &Semantics<RootDatabase>, resolve: bool) -> Option<Assist> {
132 let root = sema.db.parse_or_expand(self.file)?; 143 let root = sema.db.parse_or_expand(self.file)?;
133 let name_node = self.ident.to_node(&root); 144 let name_node = self.ident.to_node(&root);
134 145
@@ -136,16 +147,19 @@ impl DiagnosticWithFix for IncorrectCase {
136 let frange = name_node.original_file_range(sema.db); 147 let frange = name_node.original_file_range(sema.db);
137 let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() }; 148 let file_position = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
138 149
139 let rename_changes =
140 rename_with_semantics(sema, file_position, &self.suggested_text).ok()?;
141
142 let label = format!("Rename to {}", self.suggested_text); 150 let label = format!("Rename to {}", self.suggested_text);
143 Some(Fix::new(&label, rename_changes, frange.range)) 151 let mut res = unresolved_fix("change_case", &label, frange.range);
152 if resolve {
153 let source_change = rename_with_semantics(sema, file_position, &self.suggested_text);
154 res.source_change = Some(source_change.ok().unwrap_or_default());
155 }
156
157 Some(res)
144 } 158 }
145} 159}
146 160
147impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap { 161impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
148 fn fix(&self, sema: &Semantics<RootDatabase>) -> Option<Fix> { 162 fn fix(&self, sema: &Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
149 let root = sema.db.parse_or_expand(self.file)?; 163 let root = sema.db.parse_or_expand(self.file)?;
150 let next_expr = self.next_expr.to_node(&root); 164 let next_expr = self.next_expr.to_node(&root);
151 let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?; 165 let next_call = ast::MethodCallExpr::cast(next_expr.syntax().clone())?;
@@ -163,7 +177,8 @@ impl DiagnosticWithFix for ReplaceFilterMapNextWithFindMap {
163 177
164 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit); 178 let source_change = SourceChange::from_text_edit(self.file.original_file(sema.db), edit);
165 179
166 Some(Fix::new( 180 Some(fix(
181 "replace_with_find_map",
167 "Replace filter_map(..).next() with find_map()", 182 "Replace filter_map(..).next() with find_map()",
168 source_change, 183 source_change,
169 trigger_range, 184 trigger_range,
@@ -175,7 +190,7 @@ fn missing_record_expr_field_fix(
175 sema: &Semantics<RootDatabase>, 190 sema: &Semantics<RootDatabase>,
176 usage_file_id: FileId, 191 usage_file_id: FileId,
177 record_expr_field: &ast::RecordExprField, 192 record_expr_field: &ast::RecordExprField,
178) -> Option<Fix> { 193) -> Option<Assist> {
179 let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?; 194 let record_lit = ast::RecordExpr::cast(record_expr_field.syntax().parent()?.parent()?)?;
180 let def_id = sema.resolve_variant(record_lit)?; 195 let def_id = sema.resolve_variant(record_lit)?;
181 let module; 196 let module;
@@ -233,7 +248,12 @@ fn missing_record_expr_field_fix(
233 def_file_id, 248 def_file_id,
234 TextEdit::insert(last_field_syntax.text_range().end(), new_field), 249 TextEdit::insert(last_field_syntax.text_range().end(), new_field),
235 ); 250 );
236 return Some(Fix::new("Create field", source_change, record_expr_field.syntax().text_range())); 251 return Some(fix(
252 "create_field",
253 "Create field",
254 source_change,
255 record_expr_field.syntax().text_range(),
256 ));
237 257
238 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> { 258 fn record_field_list(field_def_list: ast::FieldList) -> Option<ast::RecordFieldList> {
239 match field_def_list { 259 match field_def_list {
diff --git a/crates/ide/src/diagnostics/unlinked_file.rs b/crates/ide/src/diagnostics/unlinked_file.rs
index e174fb767..7d39f4fbe 100644
--- a/crates/ide/src/diagnostics/unlinked_file.rs
+++ b/crates/ide/src/diagnostics/unlinked_file.rs
@@ -16,9 +16,10 @@ use syntax::{
16}; 16};
17use text_edit::TextEdit; 17use text_edit::TextEdit;
18 18
19use crate::Fix; 19use crate::{
20 20 diagnostics::{fix, fixes::DiagnosticWithFix},
21use super::fixes::DiagnosticWithFix; 21 Assist,
22};
22 23
23// Diagnostic: unlinked-file 24// Diagnostic: unlinked-file
24// 25//
@@ -49,7 +50,7 @@ impl Diagnostic for UnlinkedFile {
49} 50}
50 51
51impl DiagnosticWithFix for UnlinkedFile { 52impl DiagnosticWithFix for UnlinkedFile {
52 fn fix(&self, sema: &hir::Semantics<RootDatabase>) -> Option<Fix> { 53 fn fix(&self, sema: &hir::Semantics<RootDatabase>, _resolve: bool) -> Option<Assist> {
53 // If there's an existing module that could add a `mod` item to include the unlinked file, 54 // If there's an existing module that could add a `mod` item to include the unlinked file,
54 // suggest that as a fix. 55 // suggest that as a fix.
55 56
@@ -100,7 +101,7 @@ fn make_fix(
100 parent_file_id: FileId, 101 parent_file_id: FileId,
101 new_mod_name: &str, 102 new_mod_name: &str,
102 added_file_id: FileId, 103 added_file_id: FileId,
103) -> Option<Fix> { 104) -> Option<Assist> {
104 fn is_outline_mod(item: &ast::Item) -> bool { 105 fn is_outline_mod(item: &ast::Item) -> bool {
105 matches!(item, ast::Item::Module(m) if m.item_list().is_none()) 106 matches!(item, ast::Item::Module(m) if m.item_list().is_none())
106 } 107 }
@@ -152,7 +153,8 @@ fn make_fix(
152 153
153 let edit = builder.finish(); 154 let edit = builder.finish();
154 let trigger_range = db.parse(added_file_id).tree().syntax().text_range(); 155 let trigger_range = db.parse(added_file_id).tree().syntax().text_range();
155 Some(Fix::new( 156 Some(fix(
157 "add_mod_declaration",
156 &format!("Insert `{}`", mod_decl), 158 &format!("Insert `{}`", mod_decl),
157 SourceChange::from_text_edit(parent_file_id, edit), 159 SourceChange::from_text_edit(parent_file_id, edit),
158 trigger_range, 160 trigger_range,
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index 67e2e5a1c..cb5a8e19a 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -1,6 +1,9 @@
1//! Extracts, resolves and rewrites links and intra-doc links in markdown documentation. 1//! Extracts, resolves and rewrites links and intra-doc links in markdown documentation.
2 2
3use std::{convert::TryFrom, iter::once, ops::Range}; 3use std::{
4 convert::{TryFrom, TryInto},
5 iter::once,
6};
4 7
5use itertools::Itertools; 8use itertools::Itertools;
6use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag}; 9use pulldown_cmark::{BrokenLink, CowStr, Event, InlineStr, LinkType, Options, Parser, Tag};
@@ -16,8 +19,7 @@ use ide_db::{
16 RootDatabase, 19 RootDatabase,
17}; 20};
18use syntax::{ 21use syntax::{
19 ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TextSize, 22 ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode, SyntaxToken, TextRange, TokenAtOffset, T,
20 TokenAtOffset, T,
21}; 23};
22 24
23use crate::{FilePosition, Semantics}; 25use crate::{FilePosition, Semantics};
@@ -26,12 +28,7 @@ pub(crate) type DocumentationLink = String;
26 28
27/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs) 29/// Rewrite documentation links in markdown to point to an online host (e.g. docs.rs)
28pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String { 30pub(crate) fn rewrite_links(db: &RootDatabase, markdown: &str, definition: &Definition) -> String {
29 let mut cb = |link: BrokenLink| { 31 let mut cb = broken_link_clone_cb;
30 Some((
31 /*url*/ link.reference.to_owned().into(),
32 /*title*/ link.reference.to_owned().into(),
33 ))
34 };
35 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb)); 32 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
36 33
37 let doc = map_links(doc, |target, title: &str| { 34 let doc = map_links(doc, |target, title: &str| {
@@ -111,86 +108,39 @@ pub(crate) fn external_docs(
111 let node = token.parent()?; 108 let node = token.parent()?;
112 let definition = match_ast! { 109 let definition = match_ast! {
113 match node { 110 match node {
114 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)), 111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db))?,
115 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)), 112 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db))?,
116 _ => None, 113 _ => return None,
117 } 114 }
118 }; 115 };
119 116
120 get_doc_link(db, definition?) 117 get_doc_link(db, definition)
121} 118}
122 119
123/// Extracts all links from a given markdown text. 120/// Extracts all links from a given markdown text.
124pub(crate) fn extract_definitions_from_markdown( 121pub(crate) fn extract_definitions_from_markdown(
125 markdown: &str, 122 markdown: &str,
126) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { 123) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
127 let mut res = vec![]; 124 Parser::new_with_broken_link_callback(
128 let mut cb = |link: BrokenLink| { 125 markdown,
129 // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong 126 Options::empty(),
130 // this is fixed in the repo but not on the crates.io release yet 127 Some(&mut broken_link_clone_cb),
131 Some(( 128 )
132 /*url*/ link.reference.to_owned().into(), 129 .into_offset_iter()
133 /*title*/ link.reference.to_owned().into(), 130 .filter_map(|(event, range)| {
134 ))
135 };
136 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
137 for (event, range) in doc.into_offset_iter() {
138 if let Event::Start(Tag::Link(_, target, title)) = event { 131 if let Event::Start(Tag::Link(_, target, title)) = event {
139 let link = if target.is_empty() { title } else { target }; 132 let link = if target.is_empty() { title } else { target };
140 let (link, ns) = parse_intra_doc_link(&link); 133 let (link, ns) = parse_intra_doc_link(&link);
141 res.push((range, link.to_string(), ns)); 134 Some((
142 } 135 TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?),
143 } 136 link.to_string(),
144 res 137 ns,
145} 138 ))
146 139 } else {
147/// Extracts a link from a comment at the given position returning the spanning range, link and 140 None
148/// optionally it's namespace.
149pub(crate) fn extract_positioned_link_from_comment(
150 position: TextSize,
151 comment: &ast::Comment,
152) -> Option<(TextRange, String, Option<hir::Namespace>)> {
153 let doc_comment = comment.doc_comment()?;
154 let comment_start =
155 comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32);
156 let def_links = extract_definitions_from_markdown(doc_comment);
157 let (range, def_link, ns) =
158 def_links.into_iter().find_map(|(Range { start, end }, def_link, ns)| {
159 let range = TextRange::at(
160 comment_start + TextSize::from(start as u32),
161 TextSize::from((end - start) as u32),
162 );
163 range.contains(position).then(|| (range, def_link, ns))
164 })?;
165 Some((range, def_link, ns))
166}
167
168/// Turns a syntax node into it's [`Definition`] if it can hold docs.
169pub(crate) fn doc_owner_to_def(
170 sema: &Semantics<RootDatabase>,
171 item: &SyntaxNode,
172) -> Option<Definition> {
173 let res: hir::ModuleDef = match_ast! {
174 match item {
175 ast::SourceFile(_it) => sema.scope(item).module()?.into(),
176 ast::Fn(it) => sema.to_def(&it)?.into(),
177 ast::Struct(it) => sema.to_def(&it)?.into(),
178 ast::Enum(it) => sema.to_def(&it)?.into(),
179 ast::Union(it) => sema.to_def(&it)?.into(),
180 ast::Trait(it) => sema.to_def(&it)?.into(),
181 ast::Const(it) => sema.to_def(&it)?.into(),
182 ast::Static(it) => sema.to_def(&it)?.into(),
183 ast::TypeAlias(it) => sema.to_def(&it)?.into(),
184 ast::Variant(it) => sema.to_def(&it)?.into(),
185 ast::Trait(it) => sema.to_def(&it)?.into(),
186 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType),
187 ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro),
188 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field),
189 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field),
190 _ => return None,
191 } 141 }
192 }; 142 })
193 Some(Definition::ModuleDef(res)) 143 .collect()
194} 144}
195 145
196pub(crate) fn resolve_doc_path_for_def( 146pub(crate) fn resolve_doc_path_for_def(
@@ -220,6 +170,42 @@ pub(crate) fn resolve_doc_path_for_def(
220 } 170 }
221} 171}
222 172
173pub(crate) fn doc_attributes(
174 sema: &Semantics<RootDatabase>,
175 node: &SyntaxNode,
176) -> Option<(hir::AttrsWithOwner, Definition)> {
177 match_ast! {
178 match node {
179 ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
180 ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
181 ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))),
182 ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))),
183 ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))),
184 ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))),
185 ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))),
186 ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))),
187 ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))),
188 ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))),
189 ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))),
190 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
191 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
192 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
193 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
194 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
195 _ => return None
196 }
197 }
198}
199
200fn broken_link_clone_cb<'a, 'b>(link: BrokenLink<'a>) -> Option<(CowStr<'b>, CowStr<'b>)> {
201 // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong
202 // this is fixed in the repo but not on the crates.io release yet
203 Some((
204 /*url*/ link.reference.to_owned().into(),
205 /*title*/ link.reference.to_owned().into(),
206 ))
207}
208
223// FIXME: 209// FIXME:
224// BUG: For Option::Some 210// BUG: For Option::Some
225// Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some 211// Returns https://doc.rust-lang.org/nightly/core/prelude/v1/enum.Option.html#variant.Some
@@ -228,20 +214,20 @@ pub(crate) fn resolve_doc_path_for_def(
228// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented 214// This should cease to be a problem if RFC2988 (Stable Rustdoc URLs) is implemented
229// https://github.com/rust-lang/rfcs/pull/2988 215// https://github.com/rust-lang/rfcs/pull/2988
230fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> { 216fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
231 // Get the outermost definition for the moduledef. This is used to resolve the public path to the type, 217 // Get the outermost definition for the module def. This is used to resolve the public path to the type,
232 // then we can join the method, field, etc onto it if required. 218 // then we can join the method, field, etc onto it if required.
233 let target_def: ModuleDef = match definition { 219 let target_def: ModuleDef = match definition {
234 Definition::ModuleDef(moddef) => match moddef { 220 Definition::ModuleDef(def) => match def {
235 ModuleDef::Function(f) => f 221 ModuleDef::Function(f) => f
236 .as_assoc_item(db) 222 .as_assoc_item(db)
237 .and_then(|assoc| match assoc.container(db) { 223 .and_then(|assoc| match assoc.container(db) {
238 AssocItemContainer::Trait(t) => Some(t.into()), 224 AssocItemContainer::Trait(t) => Some(t.into()),
239 AssocItemContainer::Impl(impld) => { 225 AssocItemContainer::Impl(impl_) => {
240 impld.self_ty(db).as_adt().map(|adt| adt.into()) 226 impl_.self_ty(db).as_adt().map(|adt| adt.into())
241 } 227 }
242 }) 228 })
243 .unwrap_or_else(|| f.clone().into()), 229 .unwrap_or_else(|| def),
244 moddef => moddef, 230 def => def,
245 }, 231 },
246 Definition::Field(f) => f.parent_def(db).into(), 232 Definition::Field(f) => f.parent_def(db).into(),
247 // FIXME: Handle macros 233 // FIXME: Handle macros
@@ -250,17 +236,28 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
250 236
251 let ns = ItemInNs::from(target_def); 237 let ns = ItemInNs::from(target_def);
252 238
253 let module = definition.module(db)?; 239 let krate = match definition {
254 let krate = module.krate(); 240 // Definition::module gives back the parent module, we don't want that as it fails for root modules
241 Definition::ModuleDef(ModuleDef::Module(module)) => module.krate(),
242 _ => definition.module(db)?.krate(),
243 };
255 let import_map = db.import_map(krate.into()); 244 let import_map = db.import_map(krate.into());
256 let base = once(krate.display_name(db)?.to_string()) 245
257 .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string())) 246 let mut base = krate.display_name(db)?.to_string();
258 .join("/") 247 let is_root_module = matches!(
259 + "/"; 248 definition,
249 Definition::ModuleDef(ModuleDef::Module(module)) if krate.root_module(db) == module
250 );
251 if !is_root_module {
252 base = once(base)
253 .chain(import_map.path_of(ns)?.segments.iter().map(|name| name.to_string()))
254 .join("/");
255 }
256 base += "/";
260 257
261 let filename = get_symbol_filename(db, &target_def); 258 let filename = get_symbol_filename(db, &target_def);
262 let fragment = match definition { 259 let fragment = match definition {
263 Definition::ModuleDef(moddef) => match moddef { 260 Definition::ModuleDef(def) => match def {
264 ModuleDef::Function(f) => { 261 ModuleDef::Function(f) => {
265 get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f))) 262 get_symbol_fragment(db, &FieldOrAssocItem::AssocItem(AssocItem::Function(f)))
266 } 263 }
@@ -547,6 +544,19 @@ mod tests {
547 } 544 }
548 545
549 #[test] 546 #[test]
547 fn test_doc_url_crate() {
548 check(
549 r#"
550//- /main.rs crate:main deps:test
551use test$0::Foo;
552//- /lib.rs crate:test
553pub struct Foo;
554"#,
555 expect![[r#"https://docs.rs/test/*/test/index.html"#]],
556 );
557 }
558
559 #[test]
550 fn test_doc_url_struct() { 560 fn test_doc_url_struct() {
551 check( 561 check(
552 r#" 562 r#"
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index 9eeabbeda..eebae5ebe 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -1,9 +1,9 @@
1use std::iter;
2
1use hir::Semantics; 3use hir::Semantics;
2use ide_db::RootDatabase; 4use ide_db::RootDatabase;
3use syntax::{ 5use syntax::{
4 algo::{find_node_at_offset, SyntaxRewriter}, 6 algo::find_node_at_offset, ast, ted, AstNode, NodeOrToken, SyntaxKind, SyntaxKind::*,
5 ast, AstNode, NodeOrToken, SyntaxKind,
6 SyntaxKind::*,
7 SyntaxNode, WalkEvent, T, 7 SyntaxNode, WalkEvent, T,
8}; 8};
9 9
@@ -44,26 +44,23 @@ fn expand_macro_recur(
44 sema: &Semantics<RootDatabase>, 44 sema: &Semantics<RootDatabase>,
45 macro_call: &ast::MacroCall, 45 macro_call: &ast::MacroCall,
46) -> Option<SyntaxNode> { 46) -> Option<SyntaxNode> {
47 let mut expanded = sema.expand(macro_call)?; 47 let expanded = sema.expand(macro_call)?.clone_for_update();
48 48
49 let children = expanded.descendants().filter_map(ast::MacroCall::cast); 49 let children = expanded.descendants().filter_map(ast::MacroCall::cast);
50 let mut rewriter = SyntaxRewriter::default(); 50 let mut replacements = Vec::new();
51 51
52 for child in children.into_iter() { 52 for child in children {
53 if let Some(new_node) = expand_macro_recur(sema, &child) { 53 if let Some(new_node) = expand_macro_recur(sema, &child) {
54 // Replace the whole node if it is root 54 // check if the whole original syntax is replaced
55 // `replace_descendants` will not replace the parent node
56 // but `SyntaxNode::descendants include itself
57 if expanded == *child.syntax() { 55 if expanded == *child.syntax() {
58 expanded = new_node; 56 return Some(new_node);
59 } else {
60 rewriter.replace(child.syntax(), &new_node)
61 } 57 }
58 replacements.push((child, new_node));
62 } 59 }
63 } 60 }
64 61
65 let res = rewriter.rewrite(&expanded); 62 replacements.into_iter().rev().for_each(|(old, new)| ted::replace(old.syntax(), new));
66 Some(res) 63 Some(expanded)
67} 64}
68 65
69// FIXME: It would also be cool to share logic here and in the mbe tests, 66// FIXME: It would also be cool to share logic here and in the mbe tests,
@@ -91,24 +88,42 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
91 let is_last = 88 let is_last =
92 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) }; 89 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
93 90
94 res += &match token.kind() { 91 match token.kind() {
95 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ", 92 k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
93 res.push_str(token.text());
94 res.push(' ');
95 }
96 L_CURLY if is_next(|it| it != R_CURLY, true) => { 96 L_CURLY if is_next(|it| it != R_CURLY, true) => {
97 indent += 1; 97 indent += 1;
98 let leading_space = if is_last(is_text, false) { " " } else { "" }; 98 if is_last(is_text, false) {
99 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 99 res.push(' ');
100 }
101 res.push_str("{\n");
102 res.extend(iter::repeat(" ").take(2 * indent));
100 } 103 }
101 R_CURLY if is_last(|it| it != L_CURLY, true) => { 104 R_CURLY if is_last(|it| it != L_CURLY, true) => {
102 indent = indent.saturating_sub(1); 105 indent = indent.saturating_sub(1);
103 format!("\n{}}}", " ".repeat(indent)) 106 res.push('\n');
107 res.extend(iter::repeat(" ").take(2 * indent));
108 res.push_str("}");
104 } 109 }
105 R_CURLY => format!("}}\n{}", " ".repeat(indent)), 110 R_CURLY => {
106 T![;] => format!(";\n{}", " ".repeat(indent)), 111 res.push_str("}\n");
107 T![->] => " -> ".to_string(), 112 res.extend(iter::repeat(" ").take(2 * indent));
108 T![=] => " = ".to_string(), 113 }
109 T![=>] => " => ".to_string(), 114 LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
110 _ => token.text().to_string(), 115 res.push_str(token.text());
111 }; 116 res.push(' ');
117 }
118 T![;] => {
119 res.push_str(";\n");
120 res.extend(iter::repeat(" ").take(2 * indent));
121 }
122 T![->] => res.push_str(" -> "),
123 T![=] => res.push_str(" = "),
124 T![=>] => res.push_str(" => "),
125 _ => res.push_str(token.text()),
126 }
112 127
113 last = Some(token.kind()); 128 last = Some(token.kind());
114 } 129 }
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 153726ce8..2b9ed123c 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -19,6 +19,7 @@ pub enum FoldKind {
19 Region, 19 Region,
20 Consts, 20 Consts,
21 Statics, 21 Statics,
22 Array,
22} 23}
23 24
24#[derive(Debug)] 25#[derive(Debug)]
@@ -119,6 +120,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
119 match kind { 120 match kind {
120 COMMENT => Some(FoldKind::Comment), 121 COMMENT => Some(FoldKind::Comment),
121 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), 122 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
123 ARRAY_EXPR => Some(FoldKind::Array),
122 ASSOC_ITEM_LIST 124 ASSOC_ITEM_LIST
123 | RECORD_FIELD_LIST 125 | RECORD_FIELD_LIST
124 | RECORD_PAT_FIELD_LIST 126 | RECORD_PAT_FIELD_LIST
@@ -269,6 +271,7 @@ mod tests {
269 FoldKind::Region => "region", 271 FoldKind::Region => "region",
270 FoldKind::Consts => "consts", 272 FoldKind::Consts => "consts",
271 FoldKind::Statics => "statics", 273 FoldKind::Statics => "statics",
274 FoldKind::Array => "array",
272 }; 275 };
273 assert_eq!(kind, &attr.unwrap()); 276 assert_eq!(kind, &attr.unwrap());
274 } 277 }
@@ -465,6 +468,20 @@ fn foo<fold arglist>(
465 } 468 }
466 469
467 #[test] 470 #[test]
471 fn fold_multiline_array() {
472 check(
473 r#"
474const FOO: [usize; 4] = <fold array>[
475 1,
476 2,
477 3,
478 4,
479]</fold>;
480"#,
481 )
482 }
483
484 #[test]
468 fn fold_region() { 485 fn fold_region() {
469 check( 486 check(
470 r#" 487 r#"
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index 8574d1e3f..a04333e63 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1,5 +1,5 @@
1use either::Either; 1use either::Either;
2use hir::Semantics; 2use hir::{InFile, Semantics};
3use ide_db::{ 3use ide_db::{
4 defs::{NameClass, NameRefClass}, 4 defs::{NameClass, NameRefClass},
5 RootDatabase, 5 RootDatabase,
@@ -8,7 +8,7 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke
8 8
9use crate::{ 9use crate::{
10 display::TryToNav, 10 display::TryToNav,
11 doc_links::{doc_owner_to_def, extract_positioned_link_from_comment, resolve_doc_path_for_def}, 11 doc_links::{doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def},
12 FilePosition, NavigationTarget, RangeInfo, 12 FilePosition, NavigationTarget, RangeInfo,
13}; 13};
14 14
@@ -32,9 +32,16 @@ pub(crate) fn goto_definition(
32 let original_token = pick_best(file.token_at_offset(position.offset))?; 32 let original_token = pick_best(file.token_at_offset(position.offset))?;
33 let token = sema.descend_into_macros(original_token.clone()); 33 let token = sema.descend_into_macros(original_token.clone());
34 let parent = token.parent()?; 34 let parent = token.parent()?;
35 if let Some(comment) = ast::Comment::cast(token) { 35 if let Some(_) = ast::Comment::cast(token) {
36 let (_, link, ns) = extract_positioned_link_from_comment(position.offset, &comment)?; 36 let (attributes, def) = doc_attributes(&sema, &parent)?;
37 let def = doc_owner_to_def(&sema, &parent)?; 37
38 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
39 let (_, link, ns) =
40 extract_definitions_from_markdown(docs.as_str()).into_iter().find(|(range, ..)| {
41 doc_mapping.map(range.clone()).map_or(false, |InFile { file_id, value: range }| {
42 file_id == position.file_id.into() && range.contains(position.offset)
43 })
44 })?;
38 let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?; 45 let nav = resolve_doc_path_for_def(db, def, &link, ns)?.try_to_nav(db)?;
39 return Some(RangeInfo::new(original_token.text_range(), vec![nav])); 46 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
40 } 47 }
@@ -103,6 +110,13 @@ mod tests {
103 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() }); 110 assert_eq!(expected, FileRange { file_id: nav.file_id, range: nav.focus_or_full_range() });
104 } 111 }
105 112
113 fn check_unresolved(ra_fixture: &str) {
114 let (analysis, position) = fixture::position(ra_fixture);
115 let navs = analysis.goto_definition(position).unwrap().expect("no definition found").info;
116
117 assert!(navs.is_empty(), "didn't expect this to resolve anywhere: {:?}", navs)
118 }
119
106 #[test] 120 #[test]
107 fn goto_def_for_extern_crate() { 121 fn goto_def_for_extern_crate() {
108 check( 122 check(
@@ -920,17 +934,12 @@ fn f() -> impl Iterator<Item$0 = u8> {}
920 } 934 }
921 935
922 #[test] 936 #[test]
923 #[should_panic = "unresolved reference"]
924 fn unknown_assoc_ty() { 937 fn unknown_assoc_ty() {
925 check( 938 check_unresolved(
926 r#" 939 r#"
927trait Iterator { 940trait Iterator { type Item; }
928 type Item;
929 //^^^^
930}
931
932fn f() -> impl Iterator<Invalid$0 = u8> {} 941fn f() -> impl Iterator<Invalid$0 = u8> {}
933 "#, 942"#,
934 ) 943 )
935 } 944 }
936 945
@@ -1160,4 +1169,51 @@ fn fn_macro() {}
1160 "#, 1169 "#,
1161 ) 1170 )
1162 } 1171 }
1172
1173 #[test]
1174 fn goto_intra_doc_links() {
1175 check(
1176 r#"
1177
1178pub mod theitem {
1179 /// This is the item. Cool!
1180 pub struct TheItem;
1181 //^^^^^^^
1182}
1183
1184/// Gives you a [`TheItem$0`].
1185///
1186/// [`TheItem`]: theitem::TheItem
1187pub fn gimme() -> theitem::TheItem {
1188 theitem::TheItem
1189}
1190"#,
1191 );
1192 }
1193
1194 #[test]
1195 fn goto_ident_from_pat_macro() {
1196 check(
1197 r#"
1198macro_rules! pat {
1199 ($name:ident) => { Enum::Variant1($name) }
1200}
1201
1202enum Enum {
1203 Variant1(u8),
1204 Variant2,
1205}
1206
1207fn f(e: Enum) {
1208 match e {
1209 pat!(bind) => {
1210 //^^^^
1211 bind$0
1212 }
1213 Enum::Variant2 => {}
1214 }
1215}
1216"#,
1217 );
1218 }
1163} 1219}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 614433417..9de653739 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -1,6 +1,6 @@
1use either::Either; 1use either::Either;
2use hir::{ 2use hir::{
3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, Module, 3 AsAssocItem, AssocItemContainer, GenericParam, HasAttrs, HasSource, HirDisplay, InFile, Module,
4 ModuleDef, Semantics, 4 ModuleDef, Semantics,
5}; 5};
6use ide_db::{ 6use ide_db::{
@@ -16,8 +16,8 @@ use syntax::{ast, match_ast, AstNode, AstToken, SyntaxKind::*, SyntaxToken, Toke
16use crate::{ 16use crate::{
17 display::{macro_label, TryToNav}, 17 display::{macro_label, TryToNav},
18 doc_links::{ 18 doc_links::{
19 doc_owner_to_def, extract_positioned_link_from_comment, remove_links, 19 doc_attributes, extract_definitions_from_markdown, remove_links, resolve_doc_path_for_def,
20 resolve_doc_path_for_def, rewrite_links, 20 rewrite_links,
21 }, 21 },
22 markdown_remove::remove_markdown, 22 markdown_remove::remove_markdown,
23 markup::Markup, 23 markup::Markup,
@@ -116,11 +116,19 @@ pub(crate) fn hover(
116 ), 116 ),
117 117
118 _ => ast::Comment::cast(token.clone()) 118 _ => ast::Comment::cast(token.clone())
119 .and_then(|comment| { 119 .and_then(|_| {
120 let (attributes, def) = doc_attributes(&sema, &node)?;
121 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
120 let (idl_range, link, ns) = 122 let (idl_range, link, ns) =
121 extract_positioned_link_from_comment(position.offset, &comment)?; 123 extract_definitions_from_markdown(docs.as_str()).into_iter().find_map(|(range, link, ns)| {
124 let InFile { file_id, value: range } = doc_mapping.map(range.clone())?;
125 if file_id == position.file_id.into() && range.contains(position.offset) {
126 Some((range, link, ns))
127 } else {
128 None
129 }
130 })?;
122 range = Some(idl_range); 131 range = Some(idl_range);
123 let def = doc_owner_to_def(&sema, &node)?;
124 resolve_doc_path_for_def(db, def, &link, ns) 132 resolve_doc_path_for_def(db, def, &link, ns)
125 }) 133 })
126 .map(Definition::ModuleDef), 134 .map(Definition::ModuleDef),
@@ -3814,23 +3822,33 @@ fn main() {
3814 fn hover_intra_doc_links() { 3822 fn hover_intra_doc_links() {
3815 check( 3823 check(
3816 r#" 3824 r#"
3817/// This is the [`foo`](foo$0) function. 3825
3818fn foo() {} 3826pub mod theitem {
3827 /// This is the item. Cool!
3828 pub struct TheItem;
3829}
3830
3831/// Gives you a [`TheItem$0`].
3832///
3833/// [`TheItem`]: theitem::TheItem
3834pub fn gimme() -> theitem::TheItem {
3835 theitem::TheItem
3836}
3819"#, 3837"#,
3820 expect![[r#" 3838 expect![[r#"
3821 *[`foo`](foo)* 3839 *[`TheItem`]*
3822 3840
3823 ```rust 3841 ```rust
3824 test 3842 test::theitem
3825 ``` 3843 ```
3826 3844
3827 ```rust 3845 ```rust
3828 fn foo() 3846 pub struct TheItem
3829 ``` 3847 ```
3830 3848
3831 --- 3849 ---
3832 3850
3833 This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. 3851 This is the item. Cool!
3834 "#]], 3852 "#]],
3835 ); 3853 );
3836 } 3854 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 3f73c0632..99e45633e 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -69,7 +69,7 @@ use crate::display::ToNav;
69pub use crate::{ 69pub use crate::{
70 annotations::{Annotation, AnnotationConfig, AnnotationKind}, 70 annotations::{Annotation, AnnotationConfig, AnnotationKind},
71 call_hierarchy::CallItem, 71 call_hierarchy::CallItem,
72 diagnostics::{Diagnostic, DiagnosticsConfig, Fix, Severity}, 72 diagnostics::{Diagnostic, DiagnosticsConfig, Severity},
73 display::navigation_target::NavigationTarget, 73 display::navigation_target::NavigationTarget,
74 expand_macro::ExpandedMacro, 74 expand_macro::ExpandedMacro,
75 file_structure::{StructureNode, StructureNodeKind}, 75 file_structure::{StructureNode, StructureNodeKind},
@@ -82,7 +82,7 @@ pub use crate::{
82 references::{rename::RenameError, ReferenceSearchResult}, 82 references::{rename::RenameError, ReferenceSearchResult},
83 runnables::{Runnable, RunnableKind, TestId}, 83 runnables::{Runnable, RunnableKind, TestId},
84 syntax_highlighting::{ 84 syntax_highlighting::{
85 tags::{Highlight, HlMod, HlMods, HlPunct, HlTag}, 85 tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
86 HlRange, 86 HlRange,
87 }, 87 },
88}; 88};
@@ -244,6 +244,12 @@ impl Analysis {
244 self.with_db(|db| db.parse(file_id).tree()) 244 self.with_db(|db| db.parse(file_id).tree())
245 } 245 }
246 246
247 /// Returns true if this file belongs to an immutable library.
248 pub fn is_library_file(&self, file_id: FileId) -> Cancelable<bool> {
249 use ide_db::base_db::SourceDatabaseExt;
250 self.with_db(|db| db.source_root(db.file_source_root(file_id)).is_library)
251 }
252
247 /// Gets the file's `LineIndex`: data structure to convert between absolute 253 /// Gets the file's `LineIndex`: data structure to convert between absolute
248 /// offsets and line/column representation. 254 /// offsets and line/column representation.
249 pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> { 255 pub fn file_line_index(&self, file_id: FileId) -> Cancelable<Arc<LineIndex>> {
@@ -526,9 +532,39 @@ impl Analysis {
526 pub fn diagnostics( 532 pub fn diagnostics(
527 &self, 533 &self,
528 config: &DiagnosticsConfig, 534 config: &DiagnosticsConfig,
535 resolve: bool,
529 file_id: FileId, 536 file_id: FileId,
530 ) -> Cancelable<Vec<Diagnostic>> { 537 ) -> Cancelable<Vec<Diagnostic>> {
531 self.with_db(|db| diagnostics::diagnostics(db, config, file_id)) 538 self.with_db(|db| diagnostics::diagnostics(db, config, resolve, file_id))
539 }
540
541 /// Convenience function to return assists + quick fixes for diagnostics
542 pub fn assists_with_fixes(
543 &self,
544 assist_config: &AssistConfig,
545 diagnostics_config: &DiagnosticsConfig,
546 resolve: bool,
547 frange: FileRange,
548 ) -> Cancelable<Vec<Assist>> {
549 let include_fixes = match &assist_config.allowed {
550 Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
551 None => true,
552 };
553
554 self.with_db(|db| {
555 let mut res = Assist::get(db, assist_config, resolve, frange);
556 ssr::add_ssr_assist(db, &mut res, resolve, frange);
557
558 if include_fixes {
559 res.extend(
560 diagnostics::diagnostics(db, diagnostics_config, resolve, frange.file_id)
561 .into_iter()
562 .filter_map(|it| it.fix)
563 .filter(|it| it.target.intersect(frange.range).is_some()),
564 );
565 }
566 res
567 })
532 } 568 }
533 569
534 /// Returns the edit required to rename reference at the position to the new 570 /// Returns the edit required to rename reference at the position to the new
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs
index 8d37f4f92..246f10a0a 100644
--- a/crates/ide/src/move_item.rs
+++ b/crates/ide/src/move_item.rs
@@ -1,4 +1,4 @@
1use std::iter::once; 1use std::{iter::once, mem};
2 2
3use hir::Semantics; 3use hir::Semantics;
4use ide_db::{base_db::FileRange, RootDatabase}; 4use ide_db::{base_db::FileRange, RootDatabase};
@@ -102,7 +102,7 @@ fn move_in_direction(
102 ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction), 102 ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction),
103 ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction), 103 ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction),
104 ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction), 104 ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction),
105 _ => Some(replace_nodes(node, &match direction { 105 _ => Some(replace_nodes(range, node, &match direction {
106 Direction::Up => node.prev_sibling(), 106 Direction::Up => node.prev_sibling(),
107 Direction::Down => node.next_sibling(), 107 Direction::Down => node.next_sibling(),
108 }?)) 108 }?))
@@ -125,7 +125,7 @@ fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
125 .next(); 125 .next();
126 126
127 if let Some((l, r)) = list_lookup { 127 if let Some((l, r)) = list_lookup {
128 Some(replace_nodes(l.syntax(), r.syntax())) 128 Some(replace_nodes(range, l.syntax(), r.syntax()))
129 } else { 129 } else {
130 // Cursor is beyond any movable list item (for example, on curly brace in enum). 130 // Cursor is beyond any movable list item (for example, on curly brace in enum).
131 // It's not necessary, that parent of list is movable (arg list's parent is not, for example), 131 // It's not necessary, that parent of list is movable (arg list's parent is not, for example),
@@ -134,11 +134,38 @@ fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
134 } 134 }
135} 135}
136 136
137fn replace_nodes(first: &SyntaxNode, second: &SyntaxNode) -> TextEdit { 137fn replace_nodes<'a>(
138 range: TextRange,
139 mut first: &'a SyntaxNode,
140 mut second: &'a SyntaxNode,
141) -> TextEdit {
142 let cursor_offset = if range.is_empty() {
143 // FIXME: `applySnippetTextEdits` does not support non-empty selection ranges
144 if first.text_range().contains_range(range) {
145 Some(range.start() - first.text_range().start())
146 } else if second.text_range().contains_range(range) {
147 mem::swap(&mut first, &mut second);
148 Some(range.start() - first.text_range().start())
149 } else {
150 None
151 }
152 } else {
153 None
154 };
155
156 let first_with_cursor = match cursor_offset {
157 Some(offset) => {
158 let mut item_text = first.text().to_string();
159 item_text.insert_str(offset.into(), "$0");
160 item_text
161 }
162 None => first.text().to_string(),
163 };
164
138 let mut edit = TextEditBuilder::default(); 165 let mut edit = TextEditBuilder::default();
139 166
140 algo::diff(first, second).into_text_edit(&mut edit); 167 algo::diff(first, second).into_text_edit(&mut edit);
141 algo::diff(second, first).into_text_edit(&mut edit); 168 edit.replace(second.text_range(), first_with_cursor);
142 169
143 edit.finish() 170 edit.finish()
144} 171}
@@ -188,7 +215,7 @@ fn main() {
188 expect![[r#" 215 expect![[r#"
189fn main() { 216fn main() {
190 match true { 217 match true {
191 false => { 218 false =>$0 {
192 println!("Test"); 219 println!("Test");
193 }, 220 },
194 true => { 221 true => {
@@ -222,7 +249,7 @@ fn main() {
222 false => { 249 false => {
223 println!("Test"); 250 println!("Test");
224 }, 251 },
225 true => { 252 true =>$0 {
226 println!("Hello, world"); 253 println!("Hello, world");
227 } 254 }
228 }; 255 };
@@ -274,7 +301,7 @@ fn main() {
274 "#, 301 "#,
275 expect![[r#" 302 expect![[r#"
276fn main() { 303fn main() {
277 let test2 = 456; 304 let test2$0 = 456;
278 let test = 123; 305 let test = 123;
279} 306}
280 "#]], 307 "#]],
@@ -293,7 +320,7 @@ fn main() {
293 "#, 320 "#,
294 expect![[r#" 321 expect![[r#"
295fn main() { 322fn main() {
296 println!("All I want to say is..."); 323 println!("All I want to say is...");$0
297 println!("Hello, world"); 324 println!("Hello, world");
298} 325}
299 "#]], 326 "#]],
@@ -313,7 +340,7 @@ fn main() {
313fn main() { 340fn main() {
314 if true { 341 if true {
315 println!("Test"); 342 println!("Test");
316 } 343 }$0
317 344
318 println!("Hello, world"); 345 println!("Hello, world");
319} 346}
@@ -334,7 +361,7 @@ fn main() {
334fn main() { 361fn main() {
335 for i in 0..10 { 362 for i in 0..10 {
336 println!("Test"); 363 println!("Test");
337 } 364 }$0
338 365
339 println!("Hello, world"); 366 println!("Hello, world");
340} 367}
@@ -355,7 +382,7 @@ fn main() {
355fn main() { 382fn main() {
356 loop { 383 loop {
357 println!("Test"); 384 println!("Test");
358 } 385 }$0
359 386
360 println!("Hello, world"); 387 println!("Hello, world");
361} 388}
@@ -376,7 +403,7 @@ fn main() {
376fn main() { 403fn main() {
377 while true { 404 while true {
378 println!("Test"); 405 println!("Test");
379 } 406 }$0
380 407
381 println!("Hello, world"); 408 println!("Hello, world");
382} 409}
@@ -393,7 +420,7 @@ fn main() {
393 "#, 420 "#,
394 expect![[r#" 421 expect![[r#"
395fn main() { 422fn main() {
396 return 123; 423 return 123;$0
397 424
398 println!("Hello, world"); 425 println!("Hello, world");
399} 426}
@@ -430,7 +457,7 @@ fn main() {}
430fn foo() {}$0$0 457fn foo() {}$0$0
431 "#, 458 "#,
432 expect![[r#" 459 expect![[r#"
433fn foo() {} 460fn foo() {}$0
434 461
435fn main() {} 462fn main() {}
436 "#]], 463 "#]],
@@ -451,7 +478,7 @@ impl Wow for Yay $0$0{}
451 expect![[r#" 478 expect![[r#"
452struct Yay; 479struct Yay;
453 480
454impl Wow for Yay {} 481impl Wow for Yay $0{}
455 482
456trait Wow {} 483trait Wow {}
457 "#]], 484 "#]],
@@ -467,7 +494,7 @@ use std::vec::Vec;
467use std::collections::HashMap$0$0; 494use std::collections::HashMap$0$0;
468 "#, 495 "#,
469 expect![[r#" 496 expect![[r#"
470use std::collections::HashMap; 497use std::collections::HashMap$0;
471use std::vec::Vec; 498use std::vec::Vec;
472 "#]], 499 "#]],
473 Direction::Up, 500 Direction::Up,
@@ -502,7 +529,7 @@ fn main() {
502 } 529 }
503 530
504 #[test] 531 #[test]
505 fn test_moves_param_up() { 532 fn test_moves_param() {
506 check( 533 check(
507 r#" 534 r#"
508fn test(one: i32, two$0$0: u32) {} 535fn test(one: i32, two$0$0: u32) {}
@@ -512,7 +539,7 @@ fn main() {
512} 539}
513 "#, 540 "#,
514 expect![[r#" 541 expect![[r#"
515fn test(two: u32, one: i32) {} 542fn test(two$0: u32, one: i32) {}
516 543
517fn main() { 544fn main() {
518 test(123, 456); 545 test(123, 456);
@@ -520,6 +547,15 @@ fn main() {
520 "#]], 547 "#]],
521 Direction::Up, 548 Direction::Up,
522 ); 549 );
550 check(
551 r#"
552fn f($0$0arg: u8, arg2: u16) {}
553 "#,
554 expect![[r#"
555fn f(arg2: u16, $0arg: u8) {}
556 "#]],
557 Direction::Down,
558 );
523 } 559 }
524 560
525 #[test] 561 #[test]
@@ -536,7 +572,7 @@ fn main() {
536fn test(one: i32, two: u32) {} 572fn test(one: i32, two: u32) {}
537 573
538fn main() { 574fn main() {
539 test(456, 123); 575 test(456$0, 123);
540} 576}
541 "#]], 577 "#]],
542 Direction::Up, 578 Direction::Up,
@@ -557,7 +593,7 @@ fn main() {
557fn test(one: i32, two: u32) {} 593fn test(one: i32, two: u32) {}
558 594
559fn main() { 595fn main() {
560 test(456, 123); 596 test(456, 123$0);
561} 597}
562 "#]], 598 "#]],
563 Direction::Down, 599 Direction::Down,
@@ -594,7 +630,7 @@ struct Test<A, B$0$0>(A, B);
594fn main() {} 630fn main() {}
595 "#, 631 "#,
596 expect![[r#" 632 expect![[r#"
597struct Test<B, A>(A, B); 633struct Test<B$0, A>(A, B);
598 634
599fn main() {} 635fn main() {}
600 "#]], 636 "#]],
@@ -616,7 +652,7 @@ fn main() {
616struct Test<A, B>(A, B); 652struct Test<A, B>(A, B);
617 653
618fn main() { 654fn main() {
619 let t = Test::<&str, i32>(123, "yay"); 655 let t = Test::<&str$0, i32>(123, "yay");
620} 656}
621 "#]], 657 "#]],
622 Direction::Up, 658 Direction::Up,
@@ -636,7 +672,7 @@ fn main() {}
636 "#, 672 "#,
637 expect![[r#" 673 expect![[r#"
638enum Hello { 674enum Hello {
639 Two, 675 Two$0,
640 One 676 One
641} 677}
642 678
@@ -663,7 +699,7 @@ trait One {}
663 699
664trait Two {} 700trait Two {}
665 701
666fn test<T: Two + One>(t: T) {} 702fn test<T: Two$0 + One>(t: T) {}
667 703
668fn main() {} 704fn main() {}
669 "#]], 705 "#]],
@@ -709,7 +745,7 @@ trait Yay {
709impl Yay for Test { 745impl Yay for Test {
710 type One = i32; 746 type One = i32;
711 747
712 fn inner() { 748 fn inner() {$0
713 println!("Mmmm"); 749 println!("Mmmm");
714 } 750 }
715 751
@@ -736,7 +772,7 @@ fn test() {
736 "#, 772 "#,
737 expect![[r#" 773 expect![[r#"
738fn test() { 774fn test() {
739 mod hi { 775 mod hi {$0
740 fn inner() {} 776 fn inner() {}
741 } 777 }
742 778
@@ -764,7 +800,7 @@ fn main() {}
764 expect![[r#" 800 expect![[r#"
765fn main() {} 801fn main() {}
766 802
767#[derive(Debug)] 803$0#[derive(Debug)]
768enum FooBar { 804enum FooBar {
769 Foo, 805 Foo,
770 Bar, 806 Bar,
@@ -784,7 +820,7 @@ fn main() {}
784 expect![[r#" 820 expect![[r#"
785fn main() {} 821fn main() {}
786 822
787enum FooBar { 823$0enum FooBar {
788 Foo, 824 Foo,
789 Bar, 825 Bar,
790} 826}
@@ -804,7 +840,7 @@ fn main() {}
804 expect![[r#" 840 expect![[r#"
805struct Test; 841struct Test;
806 842
807impl SomeTrait for Test {} 843$0impl SomeTrait for Test {}
808 844
809trait SomeTrait {} 845trait SomeTrait {}
810 846
@@ -831,7 +867,7 @@ fn main() {}
831enum FooBar { 867enum FooBar {
832 Foo, 868 Foo,
833 Bar, 869 Bar,
834} 870}$0
835 "#]], 871 "#]],
836 Direction::Down, 872 Direction::Down,
837 ); 873 );
@@ -848,7 +884,7 @@ fn main() {}
848 expect![[r#" 884 expect![[r#"
849struct Test; 885struct Test;
850 886
851impl SomeTrait for Test {} 887impl SomeTrait for Test {}$0
852 888
853trait SomeTrait {} 889trait SomeTrait {}
854 890
diff --git a/crates/ide/src/prime_caches.rs b/crates/ide/src/prime_caches.rs
index ea0acfaa0..03597f507 100644
--- a/crates/ide/src/prime_caches.rs
+++ b/crates/ide/src/prime_caches.rs
@@ -27,6 +27,7 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress)
27 let topo = &graph.crates_in_topological_order(); 27 let topo = &graph.crates_in_topological_order();
28 28
29 cb(PrimeCachesProgress::Started); 29 cb(PrimeCachesProgress::Started);
30 let _d = stdx::defer(|| cb(PrimeCachesProgress::Finished));
30 31
31 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that. 32 // FIXME: This would be easy to parallelize, since it's in the ideal ordering for that.
32 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks 33 // Unfortunately rayon prevents panics from propagation out of a `scope`, which breaks
@@ -41,6 +42,4 @@ pub(crate) fn prime_caches(db: &RootDatabase, cb: &(dyn Fn(PrimeCachesProgress)
41 }); 42 });
42 db.crate_def_map(*krate); 43 db.crate_def_map(*krate);
43 } 44 }
44
45 cb(PrimeCachesProgress::Finished);
46} 45}
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index 5ccb84714..18552459b 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -12,7 +12,10 @@ use syntax::{
12 SyntaxNode, SyntaxToken, T, 12 SyntaxNode, SyntaxToken, T,
13}; 13};
14 14
15use crate::{syntax_highlighting::tags::HlPunct, Highlight, HlMod, HlTag}; 15use crate::{
16 syntax_highlighting::tags::{HlOperator, HlPunct},
17 Highlight, HlMod, HlTag,
18};
16 19
17pub(super) fn element( 20pub(super) fn element(
18 sema: &Semantics<RootDatabase>, 21 sema: &Semantics<RootDatabase>,
@@ -132,7 +135,7 @@ pub(super) fn element(
132 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(), 135 INT_NUMBER | FLOAT_NUMBER => HlTag::NumericLiteral.into(),
133 BYTE => HlTag::ByteLiteral.into(), 136 BYTE => HlTag::ByteLiteral.into(),
134 CHAR => HlTag::CharLiteral.into(), 137 CHAR => HlTag::CharLiteral.into(),
135 QUESTION => Highlight::new(HlTag::Operator) | HlMod::ControlFlow, 138 QUESTION => Highlight::new(HlTag::Operator(HlOperator::Other)) | HlMod::ControlFlow,
136 LIFETIME => { 139 LIFETIME => {
137 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap(); 140 let lifetime = element.into_node().and_then(ast::Lifetime::cast).unwrap();
138 141
@@ -146,8 +149,11 @@ pub(super) fn element(
146 } 149 }
147 } 150 }
148 p if p.is_punct() => match p { 151 p if p.is_punct() => match p {
152 T![&] if element.parent().and_then(ast::BinExpr::cast).is_some() => {
153 HlTag::Operator(HlOperator::Bitwise).into()
154 }
149 T![&] => { 155 T![&] => {
150 let h = HlTag::Operator.into(); 156 let h = HlTag::Operator(HlOperator::Other).into();
151 let is_unsafe = element 157 let is_unsafe = element
152 .parent() 158 .parent()
153 .and_then(ast::RefExpr::cast) 159 .and_then(ast::RefExpr::cast)
@@ -159,13 +165,18 @@ pub(super) fn element(
159 h 165 h
160 } 166 }
161 } 167 }
162 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => HlTag::Operator.into(), 168 T![::] | T![->] | T![=>] | T![..] | T![=] | T![@] | T![.] => {
169 HlTag::Operator(HlOperator::Other).into()
170 }
163 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => { 171 T![!] if element.parent().and_then(ast::MacroCall::cast).is_some() => {
164 HlTag::Symbol(SymbolKind::Macro).into() 172 HlTag::Symbol(SymbolKind::Macro).into()
165 } 173 }
166 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => { 174 T![!] if element.parent().and_then(ast::NeverType::cast).is_some() => {
167 HlTag::BuiltinType.into() 175 HlTag::BuiltinType.into()
168 } 176 }
177 T![!] if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
178 HlTag::Operator(HlOperator::Logical).into()
179 }
169 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => { 180 T![*] if element.parent().and_then(ast::PtrType::cast).is_some() => {
170 HlTag::Keyword.into() 181 HlTag::Keyword.into()
171 } 182 }
@@ -175,9 +186,9 @@ pub(super) fn element(
175 let expr = prefix_expr.expr()?; 186 let expr = prefix_expr.expr()?;
176 let ty = sema.type_of_expr(&expr)?; 187 let ty = sema.type_of_expr(&expr)?;
177 if ty.is_raw_ptr() { 188 if ty.is_raw_ptr() {
178 HlTag::Operator | HlMod::Unsafe 189 HlTag::Operator(HlOperator::Other) | HlMod::Unsafe
179 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() { 190 } else if let Some(ast::PrefixOp::Deref) = prefix_expr.op_kind() {
180 HlTag::Operator.into() 191 HlTag::Operator(HlOperator::Other).into()
181 } else { 192 } else {
182 HlTag::Punctuation(HlPunct::Other).into() 193 HlTag::Punctuation(HlPunct::Other).into()
183 } 194 }
@@ -188,19 +199,43 @@ pub(super) fn element(
188 let expr = prefix_expr.expr()?; 199 let expr = prefix_expr.expr()?;
189 match expr { 200 match expr {
190 ast::Expr::Literal(_) => HlTag::NumericLiteral, 201 ast::Expr::Literal(_) => HlTag::NumericLiteral,
191 _ => HlTag::Operator, 202 _ => HlTag::Operator(HlOperator::Other),
192 } 203 }
193 .into() 204 .into()
194 } 205 }
195 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => { 206 _ if element.parent().and_then(ast::PrefixExpr::cast).is_some() => {
196 HlTag::Operator.into() 207 HlTag::Operator(HlOperator::Other).into()
208 }
209 T![+] | T![-] | T![*] | T![/] | T![+=] | T![-=] | T![*=] | T![/=]
210 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
211 {
212 HlTag::Operator(HlOperator::Arithmetic).into()
213 }
214 T![|] | T![&] | T![!] | T![^] | T![|=] | T![&=] | T![^=]
215 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
216 {
217 HlTag::Operator(HlOperator::Bitwise).into()
218 }
219 T![&&] | T![||] if element.parent().and_then(ast::BinExpr::cast).is_some() => {
220 HlTag::Operator(HlOperator::Logical).into()
221 }
222 T![>] | T![<] | T![==] | T![>=] | T![<=] | T![!=]
223 if element.parent().and_then(ast::BinExpr::cast).is_some() =>
224 {
225 HlTag::Operator(HlOperator::Comparison).into()
226 }
227 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => {
228 HlTag::Operator(HlOperator::Other).into()
197 } 229 }
198 _ if element.parent().and_then(ast::BinExpr::cast).is_some() => HlTag::Operator.into(),
199 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => { 230 _ if element.parent().and_then(ast::RangeExpr::cast).is_some() => {
200 HlTag::Operator.into() 231 HlTag::Operator(HlOperator::Other).into()
232 }
233 _ if element.parent().and_then(ast::RangePat::cast).is_some() => {
234 HlTag::Operator(HlOperator::Other).into()
235 }
236 _ if element.parent().and_then(ast::RestPat::cast).is_some() => {
237 HlTag::Operator(HlOperator::Other).into()
201 } 238 }
202 _ if element.parent().and_then(ast::RangePat::cast).is_some() => HlTag::Operator.into(),
203 _ if element.parent().and_then(ast::RestPat::cast).is_some() => HlTag::Operator.into(),
204 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(), 239 _ if element.parent().and_then(ast::Attr::cast).is_some() => HlTag::Attribute.into(),
205 kind => HlTag::Punctuation(match kind { 240 kind => HlTag::Punctuation(match kind {
206 T!['['] | T![']'] => HlPunct::Bracket, 241 T!['['] | T![']'] => HlPunct::Bracket,
@@ -323,8 +358,18 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
323 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), 358 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
324 hir::ModuleDef::TypeAlias(type_) => { 359 hir::ModuleDef::TypeAlias(type_) => {
325 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 360 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
326 if type_.as_assoc_item(db).is_some() { 361 if let Some(item) = type_.as_assoc_item(db) {
327 h |= HlMod::Associated 362 h |= HlMod::Associated;
363 match item.container(db) {
364 AssocItemContainer::Impl(i) => {
365 if i.trait_(db).is_some() {
366 h |= HlMod::Trait;
367 }
368 }
369 AssocItemContainer::Trait(_t) => {
370 h |= HlMod::Trait;
371 }
372 }
328 } 373 }
329 return h; 374 return h;
330 } 375 }
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index b62d43256..bc221d599 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -1,17 +1,17 @@
1//! "Recursive" Syntax highlighting for code in doctests and fixtures. 1//! "Recursive" Syntax highlighting for code in doctests and fixtures.
2 2
3use std::{mem, ops::Range}; 3use std::mem;
4 4
5use either::Either; 5use either::Either;
6use hir::{HasAttrs, InFile, Semantics}; 6use hir::{InFile, Semantics};
7use ide_db::{call_info::ActiveParameter, defs::Definition, SymbolKind}; 7use ide_db::{call_info::ActiveParameter, helpers::rust_doc::is_rust_fence, SymbolKind};
8use syntax::{ 8use syntax::{
9 ast::{self, AstNode}, 9 ast::{self, AstNode},
10 match_ast, AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize, 10 AstToken, NodeOrToken, SyntaxNode, SyntaxToken, TextRange, TextSize,
11}; 11};
12 12
13use crate::{ 13use crate::{
14 doc_links::{extract_definitions_from_markdown, resolve_doc_path_for_def}, 14 doc_links::{doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def},
15 Analysis, HlMod, HlRange, HlTag, RootDatabase, 15 Analysis, HlMod, HlRange, HlTag, RootDatabase,
16}; 16};
17 17
@@ -78,44 +78,6 @@ pub(super) fn ra_fixture(
78} 78}
79 79
80const RUSTDOC_FENCE: &'static str = "```"; 80const RUSTDOC_FENCE: &'static str = "```";
81const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
82 "",
83 "rust",
84 "should_panic",
85 "ignore",
86 "no_run",
87 "compile_fail",
88 "edition2015",
89 "edition2018",
90 "edition2021",
91];
92
93fn doc_attributes<'node>(
94 sema: &Semantics<RootDatabase>,
95 node: &'node SyntaxNode,
96) -> Option<(hir::AttrsWithOwner, Definition)> {
97 match_ast! {
98 match node {
99 ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
100 ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
101 ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))),
102 ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))),
103 ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))),
104 ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))),
105 ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))),
106 ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))),
107 ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))),
108 ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))),
109 ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))),
110 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
111 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
112 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
113 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
114 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
115 _ => return None
116 }
117 }
118}
119 81
120/// Injection of syntax highlighting of doctests. 82/// Injection of syntax highlighting of doctests.
121pub(super) fn doc_comment( 83pub(super) fn doc_comment(
@@ -139,8 +101,28 @@ pub(super) fn doc_comment(
139 // Replace the original, line-spanning comment ranges by new, only comment-prefix 101 // Replace the original, line-spanning comment ranges by new, only comment-prefix
140 // spanning comment ranges. 102 // spanning comment ranges.
141 let mut new_comments = Vec::new(); 103 let mut new_comments = Vec::new();
142 let mut intra_doc_links = Vec::new();
143 let mut string; 104 let mut string;
105
106 if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
107 extract_definitions_from_markdown(docs.as_str())
108 .into_iter()
109 .filter_map(|(range, link, ns)| {
110 let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
111 let InFile { file_id, value: range } = doc_mapping.map(range)?;
112 (file_id == node.file_id).then(|| (range, def))
113 })
114 .for_each(|(range, def)| {
115 hl.add(HlRange {
116 range,
117 highlight: module_def_to_hl_tag(def)
118 | HlMod::Documentation
119 | HlMod::Injected
120 | HlMod::IntraDocLink,
121 binding_hash: None,
122 })
123 });
124 }
125
144 for attr in attributes.by_key("doc").attrs() { 126 for attr in attributes.by_key("doc").attrs() {
145 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr); 127 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
146 if file_id != node.file_id { 128 if file_id != node.file_id {
@@ -181,30 +163,11 @@ pub(super) fn doc_comment(
181 is_codeblock = !is_codeblock; 163 is_codeblock = !is_codeblock;
182 // Check whether code is rust by inspecting fence guards 164 // Check whether code is rust by inspecting fence guards
183 let guards = &line[idx + RUSTDOC_FENCE.len()..]; 165 let guards = &line[idx + RUSTDOC_FENCE.len()..];
184 let is_rust = 166 let is_rust = is_rust_fence(guards);
185 guards.split(',').all(|sub| RUSTDOC_FENCE_TOKENS.contains(&sub.trim()));
186 is_doctest = is_codeblock && is_rust; 167 is_doctest = is_codeblock && is_rust;
187 continue; 168 continue;
188 } 169 }
189 None if !is_doctest => { 170 None if !is_doctest => continue,
190 intra_doc_links.extend(
191 extract_definitions_from_markdown(line)
192 .into_iter()
193 .filter_map(|(range, link, ns)| {
194 Some(range).zip(resolve_doc_path_for_def(sema.db, def, &link, ns))
195 })
196 .map(|(Range { start, end }, def)| {
197 (
198 def,
199 TextRange::at(
200 prev_range_start + TextSize::from(start as u32),
201 TextSize::from((end - start) as u32),
202 ),
203 )
204 }),
205 );
206 continue;
207 }
208 None => (), 171 None => (),
209 } 172 }
210 173
@@ -223,17 +186,6 @@ pub(super) fn doc_comment(
223 } 186 }
224 } 187 }
225 188
226 for (def, range) in intra_doc_links {
227 hl.add(HlRange {
228 range,
229 highlight: module_def_to_hl_tag(def)
230 | HlMod::Documentation
231 | HlMod::Injected
232 | HlMod::IntraDocLink,
233 binding_hash: None,
234 });
235 }
236
237 if new_comments.is_empty() { 189 if new_comments.is_empty() {
238 return; // no need to run an analysis on an empty file 190 return; // no need to run an analysis on an empty file
239 } 191 }
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 1cec991aa..e58392d67 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -28,7 +28,7 @@ pub enum HlTag {
28 FormatSpecifier, 28 FormatSpecifier,
29 Keyword, 29 Keyword,
30 NumericLiteral, 30 NumericLiteral,
31 Operator, 31 Operator(HlOperator),
32 Punctuation(HlPunct), 32 Punctuation(HlPunct),
33 StringLiteral, 33 StringLiteral,
34 UnresolvedReference, 34 UnresolvedReference,
@@ -87,6 +87,20 @@ pub enum HlPunct {
87 Other, 87 Other,
88} 88}
89 89
90#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
91pub enum HlOperator {
92 /// |, &, !, ^, |=, &=, ^=
93 Bitwise,
94 /// +, -, *, /, +=, -=, *=, /=
95 Arithmetic,
96 /// &&, ||, !
97 Logical,
98 /// >, <, ==, >=, <=, !=
99 Comparison,
100 ///
101 Other,
102}
103
90impl HlTag { 104impl HlTag {
91 fn as_str(self) -> &'static str { 105 fn as_str(self) -> &'static str {
92 match self { 106 match self {
@@ -133,7 +147,13 @@ impl HlTag {
133 HlPunct::Other => "punctuation", 147 HlPunct::Other => "punctuation",
134 }, 148 },
135 HlTag::NumericLiteral => "numeric_literal", 149 HlTag::NumericLiteral => "numeric_literal",
136 HlTag::Operator => "operator", 150 HlTag::Operator(op) => match op {
151 HlOperator::Bitwise => "bitwise",
152 HlOperator::Arithmetic => "arithmetic",
153 HlOperator::Logical => "logical",
154 HlOperator::Comparison => "comparison",
155 HlOperator::Other => "operator",
156 },
137 HlTag::StringLiteral => "string_literal", 157 HlTag::StringLiteral => "string_literal",
138 HlTag::UnresolvedReference => "unresolved_reference", 158 HlTag::UnresolvedReference => "unresolved_reference",
139 HlTag::None => "none", 159 HlTag::None => "none",
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 045162eb8..6ee6d85fb 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -76,7 +76,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
76 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span> 76 <span class="comment documentation">/// </span><span class="comment injected">// calls bar on foo</span>
77 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> 77 <span class="comment documentation">/// </span><span class="macro injected">assert!</span><span class="parenthesis injected">(</span><span class="none injected">foo</span><span class="operator injected">.</span><span class="none injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
78 <span class="comment documentation">///</span> 78 <span class="comment documentation">///</span>
79 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="operator injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span> 79 <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">bar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="variable injected">foo</span><span class="operator injected">.</span><span class="field injected">bar</span><span class="none injected"> </span><span class="logical injected">||</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="constant injected">bar</span><span class="semicolon injected">;</span>
80 <span class="comment documentation">///</span> 80 <span class="comment documentation">///</span>
81 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span> 81 <span class="comment documentation">/// </span><span class="comment injected">/* multi-line</span>
82 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span> 82 <span class="comment documentation">/// </span><span class="comment injected"> comment */</span>
@@ -100,10 +100,18 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
100<span class="brace">}</span> 100<span class="brace">}</span>
101 101
102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span> 102<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Foo`](Foo)</span><span class="comment documentation"> is a struct</span>
103<span class="comment documentation">/// </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> is this function</span> 103<span class="comment documentation">/// This function is &gt; </span><span class="function documentation intra_doc_link injected">[`all_the_links`](all_the_links)</span><span class="comment documentation"> &lt;</span>
104<span class="comment documentation">/// [`noop`](noop) is a macro below</span> 104<span class="comment documentation">/// [`noop`](noop) is a macro below</span>
105<span class="comment documentation">/// </span><span class="struct documentation intra_doc_link injected">[`Item`]</span><span class="comment documentation"> is a struct in the module </span><span class="module documentation intra_doc_link injected">[`module`]</span>
106<span class="comment documentation">///</span>
107<span class="comment documentation">/// [`Item`]: module::Item</span>
108<span class="comment documentation">/// [mix_and_match]: ThisShouldntResolve</span>
105<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 109<span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration">all_the_links</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
106 110
111<span class="keyword">pub</span> <span class="keyword">mod</span> <span class="module declaration">module</span> <span class="brace">{</span>
112 <span class="keyword">pub</span> <span class="keyword">struct</span> <span class="struct declaration">Item</span><span class="semicolon">;</span>
113<span class="brace">}</span>
114
107<span class="comment documentation">/// ```</span> 115<span class="comment documentation">/// ```</span>
108<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span> 116<span class="comment documentation">/// </span><span class="macro injected">noop!</span><span class="parenthesis injected">(</span><span class="numeric_literal injected">1</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
109<span class="comment documentation">/// ```</span> 117<span class="comment documentation">/// ```</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 973173254..c43bcb691 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -213,7 +213,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span> 213 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="numeric_literal">-</span><span class="numeric_literal">42</span><span class="semicolon">;</span>
214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span> 214 <span class="keyword">let</span> <span class="variable declaration">baz</span> <span class="operator">=</span> <span class="operator">-</span><span class="variable">baz</span><span class="semicolon">;</span>
215 215
216 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="operator">!</span><span class="bool_literal">true</span><span class="semicolon">;</span> 216 <span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="logical">!</span><span class="bool_literal">true</span><span class="semicolon">;</span>
217 217
218 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span> 218 <span class="label declaration">'foo</span><span class="colon">:</span> <span class="keyword control">loop</span> <span class="brace">{</span>
219 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span> 219 <span class="keyword control">break</span> <span class="label">'foo</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 369ae0972..17cc6334b 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -1,6 +1,8 @@
1use std::time::Instant;
2
1use expect_test::{expect_file, ExpectFile}; 3use expect_test::{expect_file, ExpectFile};
2use ide_db::SymbolKind; 4use ide_db::SymbolKind;
3use test_utils::{bench, bench_fixture, skip_slow_tests}; 5use test_utils::{bench, bench_fixture, skip_slow_tests, AssertLinear};
4 6
5use crate::{fixture, FileRange, HlTag, TextRange}; 7use crate::{fixture, FileRange, HlTag, TextRange};
6 8
@@ -258,6 +260,36 @@ fn benchmark_syntax_highlighting_long_struct() {
258} 260}
259 261
260#[test] 262#[test]
263fn syntax_highlighting_not_quadratic() {
264 if skip_slow_tests() {
265 return;
266 }
267
268 let mut al = AssertLinear::default();
269 while al.next_round() {
270 for i in 6..=10 {
271 let n = 1 << i;
272
273 let fixture = bench_fixture::big_struct_n(n);
274 let (analysis, file_id) = fixture::file(&fixture);
275
276 let time = Instant::now();
277
278 let hash = analysis
279 .highlight(file_id)
280 .unwrap()
281 .iter()
282 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Struct))
283 .count();
284 assert!(hash > n as usize);
285
286 let elapsed = time.elapsed();
287 al.sample(n as f64, elapsed.as_millis() as f64);
288 }
289 }
290}
291
292#[test]
261fn benchmark_syntax_highlighting_parser() { 293fn benchmark_syntax_highlighting_parser() {
262 if skip_slow_tests() { 294 if skip_slow_tests() {
263 return; 295 return;
@@ -275,7 +307,7 @@ fn benchmark_syntax_highlighting_parser() {
275 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function)) 307 .filter(|it| it.highlight.tag == HlTag::Symbol(SymbolKind::Function))
276 .count() 308 .count()
277 }; 309 };
278 assert_eq!(hash, 1629); 310 assert_eq!(hash, 1632);
279} 311}
280 312
281#[test] 313#[test]
@@ -544,10 +576,18 @@ impl Foo {
544} 576}
545 577
546/// [`Foo`](Foo) is a struct 578/// [`Foo`](Foo) is a struct
547/// [`all_the_links`](all_the_links) is this function 579/// This function is > [`all_the_links`](all_the_links) <
548/// [`noop`](noop) is a macro below 580/// [`noop`](noop) is a macro below
581/// [`Item`] is a struct in the module [`module`]
582///
583/// [`Item`]: module::Item
584/// [mix_and_match]: ThisShouldntResolve
549pub fn all_the_links() {} 585pub fn all_the_links() {}
550 586
587pub mod module {
588 pub struct Item;
589}
590
551/// ``` 591/// ```
552/// noop!(1); 592/// noop!(1);
553/// ``` 593/// ```
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 11408d445..82c732390 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -22,18 +22,19 @@ use ide_db::{
22use syntax::{ 22use syntax::{
23 algo::find_node_at_offset, 23 algo::find_node_at_offset,
24 ast::{self, edit::IndentLevel, AstToken}, 24 ast::{self, edit::IndentLevel, AstToken},
25 AstNode, SourceFile, 25 AstNode, Parse, SourceFile,
26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR}, 26 SyntaxKind::{FIELD_EXPR, METHOD_CALL_EXPR},
27 TextRange, TextSize, 27 TextRange, TextSize,
28}; 28};
29 29
30use text_edit::TextEdit; 30use text_edit::{Indel, TextEdit};
31 31
32use crate::SourceChange; 32use crate::SourceChange;
33 33
34pub(crate) use on_enter::on_enter; 34pub(crate) use on_enter::on_enter;
35 35
36pub(crate) const TRIGGER_CHARS: &str = ".=>"; 36// Don't forget to add new trigger characters to `server_capabilities` in `caps.rs`.
37pub(crate) const TRIGGER_CHARS: &str = ".=>{";
37 38
38// Feature: On Typing Assists 39// Feature: On Typing Assists
39// 40//
@@ -41,6 +42,7 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
41// 42//
42// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression 43// - typing `let =` tries to smartly add `;` if `=` is followed by an existing expression
43// - typing `.` in a chain method call auto-indents 44// - typing `.` in a chain method call auto-indents
45// - typing `{` in front of an expression inserts a closing `}` after the expression
44// 46//
45// VS Code:: 47// VS Code::
46// 48//
@@ -57,28 +59,79 @@ pub(crate) fn on_char_typed(
57 position: FilePosition, 59 position: FilePosition,
58 char_typed: char, 60 char_typed: char,
59) -> Option<SourceChange> { 61) -> Option<SourceChange> {
60 assert!(TRIGGER_CHARS.contains(char_typed)); 62 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
61 let file = &db.parse(position.file_id).tree(); 63 return None;
62 assert_eq!(file.syntax().text().char_at(position.offset), Some(char_typed)); 64 }
65 let file = &db.parse(position.file_id);
66 if !stdx::always!(file.tree().syntax().text().char_at(position.offset) == Some(char_typed)) {
67 return None;
68 }
63 let edit = on_char_typed_inner(file, position.offset, char_typed)?; 69 let edit = on_char_typed_inner(file, position.offset, char_typed)?;
64 Some(SourceChange::from_text_edit(position.file_id, edit)) 70 Some(SourceChange::from_text_edit(position.file_id, edit))
65} 71}
66 72
67fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { 73fn on_char_typed_inner(
68 assert!(TRIGGER_CHARS.contains(char_typed)); 74 file: &Parse<SourceFile>,
75 offset: TextSize,
76 char_typed: char,
77) -> Option<TextEdit> {
78 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
79 return None;
80 }
69 match char_typed { 81 match char_typed {
70 '.' => on_dot_typed(file, offset), 82 '.' => on_dot_typed(&file.tree(), offset),
71 '=' => on_eq_typed(file, offset), 83 '=' => on_eq_typed(&file.tree(), offset),
72 '>' => on_arrow_typed(file, offset), 84 '>' => on_arrow_typed(&file.tree(), offset),
85 '{' => on_opening_brace_typed(file, offset),
73 _ => unreachable!(), 86 _ => unreachable!(),
74 } 87 }
75} 88}
76 89
90/// Inserts a closing `}` when the user types an opening `{`, wrapping an existing expression in a
91/// block.
92fn on_opening_brace_typed(file: &Parse<SourceFile>, offset: TextSize) -> Option<TextEdit> {
93 if !stdx::always!(file.tree().syntax().text().char_at(offset) == Some('{')) {
94 return None;
95 }
96
97 let brace_token = file.tree().syntax().token_at_offset(offset).right_biased()?;
98
99 // Remove the `{` to get a better parse tree, and reparse
100 let file = file.reparse(&Indel::delete(brace_token.text_range()));
101
102 let mut expr: ast::Expr = find_node_at_offset(file.tree().syntax(), offset)?;
103 if expr.syntax().text_range().start() != offset {
104 return None;
105 }
106
107 // Enclose the outermost expression starting at `offset`
108 while let Some(parent) = expr.syntax().parent() {
109 if parent.text_range().start() != expr.syntax().text_range().start() {
110 break;
111 }
112
113 match ast::Expr::cast(parent) {
114 Some(parent) => expr = parent,
115 None => break,
116 }
117 }
118
119 // If it's a statement in a block, we don't know how many statements should be included
120 if ast::ExprStmt::can_cast(expr.syntax().parent()?.kind()) {
121 return None;
122 }
123
124 // Insert `}` right after the expression.
125 Some(TextEdit::insert(expr.syntax().text_range().end() + TextSize::of("{"), "}".to_string()))
126}
127
77/// Returns an edit which should be applied after `=` was typed. Primarily, 128/// Returns an edit which should be applied after `=` was typed. Primarily,
78/// this works when adding `let =`. 129/// this works when adding `let =`.
79// FIXME: use a snippet completion instead of this hack here. 130// FIXME: use a snippet completion instead of this hack here.
80fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 131fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
81 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 132 if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
133 return None;
134 }
82 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?; 135 let let_stmt: ast::LetStmt = find_node_at_offset(file.syntax(), offset)?;
83 if let_stmt.semicolon_token().is_some() { 136 if let_stmt.semicolon_token().is_some() {
84 return None; 137 return None;
@@ -100,7 +153,9 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
100 153
101/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately. 154/// Returns an edit which should be applied when a dot ('.') is typed on a blank line, indenting the line appropriately.
102fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 155fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
103 assert_eq!(file.syntax().text().char_at(offset), Some('.')); 156 if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
157 return None;
158 }
104 let whitespace = 159 let whitespace =
105 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?; 160 file.syntax().token_at_offset(offset).left_biased().and_then(ast::Whitespace::cast)?;
106 161
@@ -129,7 +184,9 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
129/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }` 184/// Adds a space after an arrow when `fn foo() { ... }` is turned into `fn foo() -> { ... }`
130fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 185fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
131 let file_text = file.syntax().text(); 186 let file_text = file.syntax().text();
132 assert_eq!(file_text.char_at(offset), Some('>')); 187 if !stdx::always!(file_text.char_at(offset) == Some('>')) {
188 return None;
189 }
133 let after_arrow = offset + TextSize::of('>'); 190 let after_arrow = offset + TextSize::of('>');
134 if file_text.char_at(after_arrow) != Some('{') { 191 if file_text.char_at(after_arrow) != Some('{') {
135 return None; 192 return None;
@@ -152,7 +209,7 @@ mod tests {
152 let edit = TextEdit::insert(offset, char_typed.to_string()); 209 let edit = TextEdit::insert(offset, char_typed.to_string());
153 edit.apply(&mut before); 210 edit.apply(&mut before);
154 let parse = SourceFile::parse(&before); 211 let parse = SourceFile::parse(&before);
155 on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { 212 on_char_typed_inner(&parse, offset, char_typed).map(|it| {
156 it.apply(&mut before); 213 it.apply(&mut before);
157 before.to_string() 214 before.to_string()
158 }) 215 })
@@ -165,8 +222,8 @@ mod tests {
165 assert_eq_text!(ra_fixture_after, &actual); 222 assert_eq_text!(ra_fixture_after, &actual);
166 } 223 }
167 224
168 fn type_char_noop(char_typed: char, before: &str) { 225 fn type_char_noop(char_typed: char, ra_fixture_before: &str) {
169 let file_change = do_type_char(char_typed, before); 226 let file_change = do_type_char(char_typed, ra_fixture_before);
170 assert!(file_change.is_none()) 227 assert!(file_change.is_none())
171 } 228 }
172 229
@@ -183,16 +240,16 @@ mod tests {
183 // "); 240 // ");
184 type_char( 241 type_char(
185 '=', 242 '=',
186 r" 243 r#"
187fn foo() { 244fn foo() {
188 let foo $0 1 + 1 245 let foo $0 1 + 1
189} 246}
190", 247"#,
191 r" 248 r#"
192fn foo() { 249fn foo() {
193 let foo = 1 + 1; 250 let foo = 1 + 1;
194} 251}
195", 252"#,
196 ); 253 );
197 // do_check(r" 254 // do_check(r"
198 // fn foo() { 255 // fn foo() {
@@ -211,27 +268,27 @@ fn foo() {
211 fn indents_new_chain_call() { 268 fn indents_new_chain_call() {
212 type_char( 269 type_char(
213 '.', 270 '.',
214 r" 271 r#"
215 fn main() { 272fn main() {
216 xs.foo() 273 xs.foo()
217 $0 274 $0
218 } 275}
219 ", 276 "#,
220 r" 277 r#"
221 fn main() { 278fn main() {
222 xs.foo() 279 xs.foo()
223 . 280 .
224 } 281}
225 ", 282 "#,
226 ); 283 );
227 type_char_noop( 284 type_char_noop(
228 '.', 285 '.',
229 r" 286 r#"
230 fn main() { 287fn main() {
231 xs.foo() 288 xs.foo()
232 $0 289 $0
233 } 290}
234 ", 291 "#,
235 ) 292 )
236 } 293 }
237 294
@@ -240,26 +297,26 @@ fn foo() {
240 type_char( 297 type_char(
241 '.', 298 '.',
242 r" 299 r"
243 fn main() { 300fn main() {
244 xs.foo() 301 xs.foo()
245 $0; 302 $0;
246 } 303}
247 ",
248 r"
249 fn main() {
250 xs.foo()
251 .;
252 }
253 ", 304 ",
305 r#"
306fn main() {
307 xs.foo()
308 .;
309}
310 "#,
254 ); 311 );
255 type_char_noop( 312 type_char_noop(
256 '.', 313 '.',
257 r" 314 r#"
258 fn main() { 315fn main() {
259 xs.foo() 316 xs.foo()
260 $0; 317 $0;
261 } 318}
262 ", 319 "#,
263 ) 320 )
264 } 321 }
265 322
@@ -288,30 +345,30 @@ fn main() {
288 fn indents_continued_chain_call() { 345 fn indents_continued_chain_call() {
289 type_char( 346 type_char(
290 '.', 347 '.',
291 r" 348 r#"
292 fn main() { 349fn main() {
293 xs.foo() 350 xs.foo()
294 .first() 351 .first()
295 $0 352 $0
296 } 353}
297 ", 354 "#,
298 r" 355 r#"
299 fn main() { 356fn main() {
300 xs.foo() 357 xs.foo()
301 .first() 358 .first()
302 . 359 .
303 } 360}
304 ", 361 "#,
305 ); 362 );
306 type_char_noop( 363 type_char_noop(
307 '.', 364 '.',
308 r" 365 r#"
309 fn main() { 366fn main() {
310 xs.foo() 367 xs.foo()
311 .first() 368 .first()
312 $0 369 $0
313 } 370}
314 ", 371 "#,
315 ); 372 );
316 } 373 }
317 374
@@ -319,33 +376,33 @@ fn main() {
319 fn indents_middle_of_chain_call() { 376 fn indents_middle_of_chain_call() {
320 type_char( 377 type_char(
321 '.', 378 '.',
322 r" 379 r#"
323 fn source_impl() { 380fn source_impl() {
324 let var = enum_defvariant_list().unwrap() 381 let var = enum_defvariant_list().unwrap()
325 $0 382 $0
326 .nth(92) 383 .nth(92)
327 .unwrap(); 384 .unwrap();
328 } 385}
329 ", 386 "#,
330 r" 387 r#"
331 fn source_impl() { 388fn source_impl() {
332 let var = enum_defvariant_list().unwrap() 389 let var = enum_defvariant_list().unwrap()
333 . 390 .
334 .nth(92) 391 .nth(92)
335 .unwrap(); 392 .unwrap();
336 } 393}
337 ", 394 "#,
338 ); 395 );
339 type_char_noop( 396 type_char_noop(
340 '.', 397 '.',
341 r" 398 r#"
342 fn source_impl() { 399fn source_impl() {
343 let var = enum_defvariant_list().unwrap() 400 let var = enum_defvariant_list().unwrap()
344 $0 401 $0
345 .nth(92) 402 .nth(92)
346 .unwrap(); 403 .unwrap();
347 } 404}
348 ", 405 "#,
349 ); 406 );
350 } 407 }
351 408
@@ -353,24 +410,113 @@ fn main() {
353 fn dont_indent_freestanding_dot() { 410 fn dont_indent_freestanding_dot() {
354 type_char_noop( 411 type_char_noop(
355 '.', 412 '.',
356 r" 413 r#"
357 fn main() { 414fn main() {
358 $0 415 $0
359 } 416}
360 ", 417 "#,
361 ); 418 );
362 type_char_noop( 419 type_char_noop(
363 '.', 420 '.',
364 r" 421 r#"
365 fn main() { 422fn main() {
366 $0 423$0
367 } 424}
368 ", 425 "#,
369 ); 426 );
370 } 427 }
371 428
372 #[test] 429 #[test]
373 fn adds_space_after_return_type() { 430 fn adds_space_after_return_type() {
374 type_char('>', "fn foo() -$0{ 92 }", "fn foo() -> { 92 }") 431 type_char(
432 '>',
433 r#"
434fn foo() -$0{ 92 }
435"#,
436 r#"
437fn foo() -> { 92 }
438"#,
439 );
440 }
441
442 #[test]
443 fn adds_closing_brace() {
444 type_char(
445 '{',
446 r#"
447fn f() { match () { _ => $0() } }
448 "#,
449 r#"
450fn f() { match () { _ => {()} } }
451 "#,
452 );
453 type_char(
454 '{',
455 r#"
456fn f() { $0() }
457 "#,
458 r#"
459fn f() { {()} }
460 "#,
461 );
462 type_char(
463 '{',
464 r#"
465fn f() { let x = $0(); }
466 "#,
467 r#"
468fn f() { let x = {()}; }
469 "#,
470 );
471 type_char(
472 '{',
473 r#"
474fn f() { let x = $0a.b(); }
475 "#,
476 r#"
477fn f() { let x = {a.b()}; }
478 "#,
479 );
480 type_char(
481 '{',
482 r#"
483const S: () = $0();
484fn f() {}
485 "#,
486 r#"
487const S: () = {()};
488fn f() {}
489 "#,
490 );
491 type_char(
492 '{',
493 r#"
494const S: () = $0a.b();
495fn f() {}
496 "#,
497 r#"
498const S: () = {a.b()};
499fn f() {}
500 "#,
501 );
502 type_char(
503 '{',
504 r#"
505fn f() {
506 match x {
507 0 => $0(),
508 1 => (),
509 }
510}
511 "#,
512 r#"
513fn f() {
514 match x {
515 0 => {()},
516 1 => (),
517 }
518}
519 "#,
520 );
375 } 521 }
376} 522}
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 9144681bf..7d2db201a 100644
--- a/crates/ide/src/typing/on_enter.rs
+++ b/crates/ide/src/typing/on_enter.rs
@@ -4,10 +4,11 @@
4use ide_db::base_db::{FilePosition, SourceDatabase}; 4use ide_db::base_db::{FilePosition, SourceDatabase};
5use ide_db::RootDatabase; 5use ide_db::RootDatabase;
6use syntax::{ 6use syntax::{
7 ast::{self, AstToken}, 7 algo::find_node_at_offset,
8 ast::{self, edit::IndentLevel, AstToken},
8 AstNode, SmolStr, SourceFile, 9 AstNode, SmolStr, SourceFile,
9 SyntaxKind::*, 10 SyntaxKind::*,
10 SyntaxToken, TextRange, TextSize, TokenAtOffset, 11 SyntaxNode, SyntaxToken, TextRange, TextSize, TokenAtOffset,
11}; 12};
12 13
13use text_edit::TextEdit; 14use text_edit::TextEdit;
@@ -18,6 +19,8 @@ use text_edit::TextEdit;
18// 19//
19// - kbd:[Enter] inside triple-slash comments automatically inserts `///` 20// - kbd:[Enter] inside triple-slash comments automatically inserts `///`
20// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//` 21// - kbd:[Enter] in the middle or after a trailing space in `//` inserts `//`
22// - kbd:[Enter] inside `//!` doc comments automatically inserts `//!`
23// - kbd:[Enter] after `{` indents contents and closing `}` of single-line block
21// 24//
22// This action needs to be assigned to shortcut explicitly. 25// This action needs to be assigned to shortcut explicitly.
23// 26//
@@ -37,25 +40,43 @@ use text_edit::TextEdit;
37pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 40pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
38 let parse = db.parse(position.file_id); 41 let parse = db.parse(position.file_id);
39 let file = parse.tree(); 42 let file = parse.tree();
40 let comment = file 43 let token = file.syntax().token_at_offset(position.offset).left_biased()?;
41 .syntax()
42 .token_at_offset(position.offset)
43 .left_biased()
44 .and_then(ast::Comment::cast)?;
45 44
45 if let Some(comment) = ast::Comment::cast(token.clone()) {
46 return on_enter_in_comment(&comment, &file, position.offset);
47 }
48
49 if token.kind() == L_CURLY {
50 // Typing enter after the `{` of a block expression, where the `}` is on the same line
51 if let Some(edit) = find_node_at_offset(file.syntax(), position.offset - TextSize::of('{'))
52 .and_then(|block| on_enter_in_block(block, position))
53 {
54 cov_mark::hit!(indent_block_contents);
55 return Some(edit);
56 }
57 }
58
59 None
60}
61
62fn on_enter_in_comment(
63 comment: &ast::Comment,
64 file: &ast::SourceFile,
65 offset: TextSize,
66) -> Option<TextEdit> {
46 if comment.kind().shape.is_block() { 67 if comment.kind().shape.is_block() {
47 return None; 68 return None;
48 } 69 }
49 70
50 let prefix = comment.prefix(); 71 let prefix = comment.prefix();
51 let comment_range = comment.syntax().text_range(); 72 let comment_range = comment.syntax().text_range();
52 if position.offset < comment_range.start() + TextSize::of(prefix) { 73 if offset < comment_range.start() + TextSize::of(prefix) {
53 return None; 74 return None;
54 } 75 }
55 76
56 let mut remove_trailing_whitespace = false; 77 let mut remove_trailing_whitespace = false;
57 // Continuing single-line non-doc comments (like this one :) ) is annoying 78 // Continuing single-line non-doc comments (like this one :) ) is annoying
58 if prefix == "//" && comment_range.end() == position.offset { 79 if prefix == "//" && comment_range.end() == offset {
59 if comment.text().ends_with(' ') { 80 if comment.text().ends_with(' ') {
60 cov_mark::hit!(continues_end_of_line_comment_with_space); 81 cov_mark::hit!(continues_end_of_line_comment_with_space);
61 remove_trailing_whitespace = true; 82 remove_trailing_whitespace = true;
@@ -69,14 +90,42 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
69 let delete = if remove_trailing_whitespace { 90 let delete = if remove_trailing_whitespace {
70 let trimmed_len = comment.text().trim_end().len() as u32; 91 let trimmed_len = comment.text().trim_end().len() as u32;
71 let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len; 92 let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len;
72 TextRange::new(position.offset - TextSize::from(trailing_whitespace_len), position.offset) 93 TextRange::new(offset - TextSize::from(trailing_whitespace_len), offset)
73 } else { 94 } else {
74 TextRange::empty(position.offset) 95 TextRange::empty(offset)
75 }; 96 };
76 let edit = TextEdit::replace(delete, inserted); 97 let edit = TextEdit::replace(delete, inserted);
77 Some(edit) 98 Some(edit)
78} 99}
79 100
101fn on_enter_in_block(block: ast::BlockExpr, position: FilePosition) -> Option<TextEdit> {
102 let contents = block_contents(&block)?;
103
104 if block.syntax().text().contains_char('\n') {
105 return None;
106 }
107
108 let indent = IndentLevel::from_node(block.syntax());
109 let mut edit = TextEdit::insert(position.offset, format!("\n{}$0", indent + 1));
110 edit.union(TextEdit::insert(contents.text_range().end(), format!("\n{}", indent))).ok()?;
111 Some(edit)
112}
113
114fn block_contents(block: &ast::BlockExpr) -> Option<SyntaxNode> {
115 let mut node = block.tail_expr().map(|e| e.syntax().clone());
116
117 for stmt in block.statements() {
118 if node.is_some() {
119 // More than 1 node in the block
120 return None;
121 }
122
123 node = Some(stmt.syntax().clone());
124 }
125
126 node
127}
128
80fn followed_by_comment(comment: &ast::Comment) -> bool { 129fn followed_by_comment(comment: &ast::Comment) -> bool {
81 let ws = match comment.syntax().next_token().and_then(ast::Whitespace::cast) { 130 let ws = match comment.syntax().next_token().and_then(ast::Whitespace::cast) {
82 Some(it) => it, 131 Some(it) => it,
@@ -187,6 +236,25 @@ fn foo() {
187 } 236 }
188 237
189 #[test] 238 #[test]
239 fn continues_another_doc_comment() {
240 do_check(
241 r#"
242fn main() {
243 //! Documentation for$0 on enter
244 let x = 1 + 1;
245}
246"#,
247 r#"
248fn main() {
249 //! Documentation for
250 //! $0 on enter
251 let x = 1 + 1;
252}
253"#,
254 );
255 }
256
257 #[test]
190 fn continues_code_comment_in_the_middle_of_line() { 258 fn continues_code_comment_in_the_middle_of_line() {
191 do_check( 259 do_check(
192 r" 260 r"
@@ -276,4 +344,144 @@ fn main() {
276", 344",
277 ); 345 );
278 } 346 }
347
348 #[test]
349 fn indents_fn_body_block() {
350 cov_mark::check!(indent_block_contents);
351 do_check(
352 r#"
353fn f() {$0()}
354 "#,
355 r#"
356fn f() {
357 $0()
358}
359 "#,
360 );
361 }
362
363 #[test]
364 fn indents_block_expr() {
365 do_check(
366 r#"
367fn f() {
368 let x = {$0()};
369}
370 "#,
371 r#"
372fn f() {
373 let x = {
374 $0()
375 };
376}
377 "#,
378 );
379 }
380
381 #[test]
382 fn indents_match_arm() {
383 do_check(
384 r#"
385fn f() {
386 match 6 {
387 1 => {$0f()},
388 _ => (),
389 }
390}
391 "#,
392 r#"
393fn f() {
394 match 6 {
395 1 => {
396 $0f()
397 },
398 _ => (),
399 }
400}
401 "#,
402 );
403 }
404
405 #[test]
406 fn indents_block_with_statement() {
407 do_check(
408 r#"
409fn f() {$0a = b}
410 "#,
411 r#"
412fn f() {
413 $0a = b
414}
415 "#,
416 );
417 do_check(
418 r#"
419fn f() {$0fn f() {}}
420 "#,
421 r#"
422fn f() {
423 $0fn f() {}
424}
425 "#,
426 );
427 }
428
429 #[test]
430 fn indents_nested_blocks() {
431 do_check(
432 r#"
433fn f() {$0{}}
434 "#,
435 r#"
436fn f() {
437 $0{}
438}
439 "#,
440 );
441 }
442
443 #[test]
444 fn does_not_indent_empty_block() {
445 do_check_noop(
446 r#"
447fn f() {$0}
448 "#,
449 );
450 do_check_noop(
451 r#"
452fn f() {{$0}}
453 "#,
454 );
455 }
456
457 #[test]
458 fn does_not_indent_block_with_too_much_content() {
459 do_check_noop(
460 r#"
461fn f() {$0 a = b; ()}
462 "#,
463 );
464 do_check_noop(
465 r#"
466fn f() {$0 a = b; a = b; }
467 "#,
468 );
469 }
470
471 #[test]
472 fn does_not_indent_multiline_block() {
473 do_check_noop(
474 r#"
475fn f() {$0
476}
477 "#,
478 );
479 do_check_noop(
480 r#"
481fn f() {$0
482
483}
484 "#,
485 );
486 }
279} 487}
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 5ccd7f7a2..49aa70f74 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -934,4 +934,37 @@ fn main() {
934", 934",
935 ); 935 );
936 } 936 }
937
938 #[test]
939 fn inner_items() {
940 check_assist(
941 auto_import,
942 r#"
943mod baz {
944 pub struct Foo {}
945}
946
947mod bar {
948 fn bar() {
949 Foo$0;
950 println!("Hallo");
951 }
952}
953"#,
954 r#"
955mod baz {
956 pub struct Foo {}
957}
958
959mod bar {
960 use crate::baz::Foo;
961
962 fn bar() {
963 Foo;
964 println!("Hallo");
965 }
966}
967"#,
968 );
969 }
937} 970}
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 5fdc8bf38..5f80a40c8 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -75,7 +75,8 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext) -> Option
75 let insert_after = scope_for_fn_insertion(&body, anchor)?; 75 let insert_after = scope_for_fn_insertion(&body, anchor)?;
76 let module = ctx.sema.scope(&insert_after).module()?; 76 let module = ctx.sema.scope(&insert_after).module()?;
77 77
78 let vars_defined_in_body_and_outlive = vars_defined_in_body_and_outlive(ctx, &body); 78 let vars_defined_in_body_and_outlive =
79 vars_defined_in_body_and_outlive(ctx, &body, &node.parent().as_ref().unwrap_or(&node));
79 let ret_ty = body_return_ty(ctx, &body)?; 80 let ret_ty = body_return_ty(ctx, &body)?;
80 81
81 // FIXME: we compute variables that outlive here just to check `never!` condition 82 // FIXME: we compute variables that outlive here just to check `never!` condition
@@ -257,7 +258,7 @@ struct Function {
257 control_flow: ControlFlow, 258 control_flow: ControlFlow,
258 ret_ty: RetType, 259 ret_ty: RetType,
259 body: FunctionBody, 260 body: FunctionBody,
260 vars_defined_in_body_and_outlive: Vec<Local>, 261 vars_defined_in_body_and_outlive: Vec<OutlivedLocal>,
261} 262}
262 263
263#[derive(Debug)] 264#[derive(Debug)]
@@ -296,9 +297,9 @@ impl Function {
296 RetType::Expr(ty) => FunType::Single(ty.clone()), 297 RetType::Expr(ty) => FunType::Single(ty.clone()),
297 RetType::Stmt => match self.vars_defined_in_body_and_outlive.as_slice() { 298 RetType::Stmt => match self.vars_defined_in_body_and_outlive.as_slice() {
298 [] => FunType::Unit, 299 [] => FunType::Unit,
299 [var] => FunType::Single(var.ty(ctx.db())), 300 [var] => FunType::Single(var.local.ty(ctx.db())),
300 vars => { 301 vars => {
301 let types = vars.iter().map(|v| v.ty(ctx.db())).collect(); 302 let types = vars.iter().map(|v| v.local.ty(ctx.db())).collect();
302 FunType::Tuple(types) 303 FunType::Tuple(types)
303 } 304 }
304 }, 305 },
@@ -562,6 +563,12 @@ impl HasTokenAtOffset for FunctionBody {
562 } 563 }
563} 564}
564 565
566#[derive(Debug)]
567struct OutlivedLocal {
568 local: Local,
569 mut_usage_outside_body: bool,
570}
571
565/// Try to guess what user wants to extract 572/// Try to guess what user wants to extract
566/// 573///
567/// We have basically have two cases: 574/// We have basically have two cases:
@@ -592,7 +599,12 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
592 // we have selected a few statements in a block 599 // we have selected a few statements in a block
593 // so covering_element returns the whole block 600 // so covering_element returns the whole block
594 if node.kind() == BLOCK_EXPR { 601 if node.kind() == BLOCK_EXPR {
595 let body = FunctionBody::from_range(node.clone(), selection_range); 602 // Extract the full statements.
603 let statements_range = node
604 .children()
605 .filter(|c| selection_range.intersect(c.text_range()).is_some())
606 .fold(selection_range, |acc, c| acc.cover(c.text_range()));
607 let body = FunctionBody::from_range(node.clone(), statements_range);
596 if body.is_some() { 608 if body.is_some() {
597 return body; 609 return body;
598 } 610 }
@@ -603,7 +615,8 @@ fn extraction_target(node: &SyntaxNode, selection_range: TextRange) -> Option<Fu
603 // so we try to expand covering_element to parent and repeat the previous 615 // so we try to expand covering_element to parent and repeat the previous
604 if let Some(parent) = node.parent() { 616 if let Some(parent) = node.parent() {
605 if parent.kind() == BLOCK_EXPR { 617 if parent.kind() == BLOCK_EXPR {
606 let body = FunctionBody::from_range(parent, selection_range); 618 // Extract the full statement.
619 let body = FunctionBody::from_range(parent, node.text_range());
607 if body.is_some() { 620 if body.is_some() {
608 return body; 621 return body;
609 } 622 }
@@ -707,10 +720,10 @@ fn has_exclusive_usages(ctx: &AssistContext, usages: &LocalUsages, body: &Functi
707 .any(|reference| reference_is_exclusive(reference, body, ctx)) 720 .any(|reference| reference_is_exclusive(reference, body, ctx))
708} 721}
709 722
710/// checks if this reference requires `&mut` access inside body 723/// checks if this reference requires `&mut` access inside node
711fn reference_is_exclusive( 724fn reference_is_exclusive(
712 reference: &FileReference, 725 reference: &FileReference,
713 body: &FunctionBody, 726 node: &dyn HasTokenAtOffset,
714 ctx: &AssistContext, 727 ctx: &AssistContext,
715) -> bool { 728) -> bool {
716 // we directly modify variable with set: `n = 0`, `n += 1` 729 // we directly modify variable with set: `n = 0`, `n += 1`
@@ -719,7 +732,7 @@ fn reference_is_exclusive(
719 } 732 }
720 733
721 // we take `&mut` reference to variable: `&mut v` 734 // we take `&mut` reference to variable: `&mut v`
722 let path = match path_element_of_reference(body, reference) { 735 let path = match path_element_of_reference(node, reference) {
723 Some(path) => path, 736 Some(path) => path,
724 None => return false, 737 None => return false,
725 }; 738 };
@@ -729,6 +742,14 @@ fn reference_is_exclusive(
729 742
730/// checks if this expr requires `&mut` access, recurses on field access 743/// checks if this expr requires `&mut` access, recurses on field access
731fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> { 744fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> {
745 match expr {
746 ast::Expr::MacroCall(_) => {
747 // FIXME: expand macro and check output for mutable usages of the variable?
748 return None;
749 }
750 _ => (),
751 }
752
732 let parent = expr.syntax().parent()?; 753 let parent = expr.syntax().parent()?;
733 754
734 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) { 755 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
@@ -787,7 +808,7 @@ impl HasTokenAtOffset for SyntaxNode {
787 } 808 }
788} 809}
789 810
790/// find relevant `ast::PathExpr` for reference 811/// find relevant `ast::Expr` for reference
791/// 812///
792/// # Preconditions 813/// # Preconditions
793/// 814///
@@ -804,7 +825,11 @@ fn path_element_of_reference(
804 stdx::never!(false, "cannot find path parent of variable usage: {:?}", token); 825 stdx::never!(false, "cannot find path parent of variable usage: {:?}", token);
805 None 826 None
806 })?; 827 })?;
807 stdx::always!(matches!(path, ast::Expr::PathExpr(_))); 828 stdx::always!(
829 matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroCall(_)),
830 "unexpected expression type for variable usage: {:?}",
831 path
832 );
808 Some(path) 833 Some(path)
809} 834}
810 835
@@ -820,10 +845,16 @@ fn vars_defined_in_body(body: &FunctionBody, ctx: &AssistContext) -> Vec<Local>
820} 845}
821 846
822/// list local variables defined inside `body` that should be returned from extracted function 847/// list local variables defined inside `body` that should be returned from extracted function
823fn vars_defined_in_body_and_outlive(ctx: &AssistContext, body: &FunctionBody) -> Vec<Local> { 848fn vars_defined_in_body_and_outlive(
824 let mut vars_defined_in_body = vars_defined_in_body(&body, ctx); 849 ctx: &AssistContext,
825 vars_defined_in_body.retain(|var| var_outlives_body(ctx, body, var)); 850 body: &FunctionBody,
851 parent: &SyntaxNode,
852) -> Vec<OutlivedLocal> {
853 let vars_defined_in_body = vars_defined_in_body(&body, ctx);
826 vars_defined_in_body 854 vars_defined_in_body
855 .into_iter()
856 .filter_map(|var| var_outlives_body(ctx, body, var, parent))
857 .collect()
827} 858}
828 859
829/// checks if the relevant local was defined before(outside of) body 860/// checks if the relevant local was defined before(outside of) body
@@ -843,11 +874,23 @@ fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode {
843 } 874 }
844} 875}
845 876
846/// checks if local variable is used after(outside of) body 877/// returns usage details if local variable is used after(outside of) body
847fn var_outlives_body(ctx: &AssistContext, body: &FunctionBody, var: &Local) -> bool { 878fn var_outlives_body(
848 let usages = LocalUsages::find(ctx, *var); 879 ctx: &AssistContext,
880 body: &FunctionBody,
881 var: Local,
882 parent: &SyntaxNode,
883) -> Option<OutlivedLocal> {
884 let usages = LocalUsages::find(ctx, var);
849 let has_usages = usages.iter().any(|reference| body.preceedes_range(reference.range)); 885 let has_usages = usages.iter().any(|reference| body.preceedes_range(reference.range));
850 has_usages 886 if !has_usages {
887 return None;
888 }
889 let has_mut_usages = usages
890 .iter()
891 .filter(|reference| body.preceedes_range(reference.range))
892 .any(|reference| reference_is_exclusive(reference, parent, ctx));
893 Some(OutlivedLocal { local: var, mut_usage_outside_body: has_mut_usages })
851} 894}
852 895
853fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option<RetType> { 896fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option<RetType> {
@@ -927,16 +970,25 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel)
927 let mut buf = String::new(); 970 let mut buf = String::new();
928 match fun.vars_defined_in_body_and_outlive.as_slice() { 971 match fun.vars_defined_in_body_and_outlive.as_slice() {
929 [] => {} 972 [] => {}
930 [var] => format_to!(buf, "let {} = ", var.name(ctx.db()).unwrap()), 973 [var] => {
974 format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()).unwrap())
975 }
931 [v0, vs @ ..] => { 976 [v0, vs @ ..] => {
932 buf.push_str("let ("); 977 buf.push_str("let (");
933 format_to!(buf, "{}", v0.name(ctx.db()).unwrap()); 978 format_to!(buf, "{}{}", mut_modifier(v0), v0.local.name(ctx.db()).unwrap());
934 for var in vs { 979 for var in vs {
935 format_to!(buf, ", {}", var.name(ctx.db()).unwrap()); 980 format_to!(buf, ", {}{}", mut_modifier(var), var.local.name(ctx.db()).unwrap());
936 } 981 }
937 buf.push_str(") = "); 982 buf.push_str(") = ");
938 } 983 }
939 } 984 }
985 fn mut_modifier(var: &OutlivedLocal) -> &'static str {
986 if var.mut_usage_outside_body {
987 "mut "
988 } else {
989 ""
990 }
991 }
940 format_to!(buf, "{}", expr); 992 format_to!(buf, "{}", expr);
941 if fun.ret_ty.is_unit() 993 if fun.ret_ty.is_unit()
942 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) 994 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like())
@@ -1175,9 +1227,19 @@ fn make_body(
1175 FunctionBody::Expr(expr) => { 1227 FunctionBody::Expr(expr) => {
1176 let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax()); 1228 let expr = rewrite_body_segment(ctx, &fun.params, &handler, expr.syntax());
1177 let expr = ast::Expr::cast(expr).unwrap(); 1229 let expr = ast::Expr::cast(expr).unwrap();
1178 let expr = expr.dedent(old_indent).indent(IndentLevel(1)); 1230 match expr {
1231 ast::Expr::BlockExpr(block) => {
1232 // If the extracted expression is itself a block, there is no need to wrap it inside another block.
1233 let block = block.dedent(old_indent);
1234 // Recreate the block for formatting consistency with other extracted functions.
1235 make::block_expr(block.statements(), block.tail_expr())
1236 }
1237 _ => {
1238 let expr = expr.dedent(old_indent).indent(IndentLevel(1));
1179 1239
1180 make::block_expr(Vec::new(), Some(expr)) 1240 make::block_expr(Vec::new(), Some(expr))
1241 }
1242 }
1181 } 1243 }
1182 FunctionBody::Span { parent, text_range } => { 1244 FunctionBody::Span { parent, text_range } => {
1183 let mut elements: Vec<_> = parent 1245 let mut elements: Vec<_> = parent
@@ -1199,10 +1261,10 @@ fn make_body(
1199 match fun.vars_defined_in_body_and_outlive.as_slice() { 1261 match fun.vars_defined_in_body_and_outlive.as_slice() {
1200 [] => {} 1262 [] => {}
1201 [var] => { 1263 [var] => {
1202 tail_expr = Some(path_expr_from_local(ctx, *var)); 1264 tail_expr = Some(path_expr_from_local(ctx, var.local));
1203 } 1265 }
1204 vars => { 1266 vars => {
1205 let exprs = vars.iter().map(|var| path_expr_from_local(ctx, *var)); 1267 let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local));
1206 let expr = make::expr_tuple(exprs); 1268 let expr = make::expr_tuple(exprs);
1207 tail_expr = Some(expr); 1269 tail_expr = Some(expr);
1208 } 1270 }
@@ -1492,7 +1554,7 @@ fn foo() {
1492} 1554}
1493 1555
1494fn $0fun_name() -> i32 { 1556fn $0fun_name() -> i32 {
1495 { 1 + 1 } 1557 1 + 1
1496}"#, 1558}"#,
1497 ); 1559 );
1498 } 1560 }
@@ -1739,6 +1801,60 @@ fn $0fun_name() -> i32 {
1739 } 1801 }
1740 1802
1741 #[test] 1803 #[test]
1804 fn extract_partial_block_single_line() {
1805 check_assist(
1806 extract_function,
1807 r#"
1808fn foo() {
1809 let n = 1;
1810 let mut v = $0n * n;$0
1811 v += 1;
1812}"#,
1813 r#"
1814fn foo() {
1815 let n = 1;
1816 let mut v = fun_name(n);
1817 v += 1;
1818}
1819
1820fn $0fun_name(n: i32) -> i32 {
1821 let mut v = n * n;
1822 v
1823}"#,
1824 );
1825 }
1826
1827 #[test]
1828 fn extract_partial_block() {
1829 check_assist(
1830 extract_function,
1831 r#"
1832fn foo() {
1833 let m = 2;
1834 let n = 1;
1835 let mut v = m $0* n;
1836 let mut w = 3;$0
1837 v += 1;
1838 w += 1;
1839}"#,
1840 r#"
1841fn foo() {
1842 let m = 2;
1843 let n = 1;
1844 let (mut v, mut w) = fun_name(m, n);
1845 v += 1;
1846 w += 1;
1847}
1848
1849fn $0fun_name(m: i32, n: i32) -> (i32, i32) {
1850 let mut v = m * n;
1851 let mut w = 3;
1852 (v, w)
1853}"#,
1854 );
1855 }
1856
1857 #[test]
1742 fn argument_form_expr() { 1858 fn argument_form_expr() {
1743 check_assist( 1859 check_assist(
1744 extract_function, 1860 extract_function,
@@ -2111,6 +2227,30 @@ fn $0fun_name(n: i32) -> i32 {
2111 } 2227 }
2112 2228
2113 #[test] 2229 #[test]
2230 fn variable_defined_inside_and_used_after_mutably_no_ret() {
2231 check_assist(
2232 extract_function,
2233 r"
2234fn foo() {
2235 let n = 1;
2236 $0let mut k = n * n;$0
2237 k += 1;
2238}",
2239 r"
2240fn foo() {
2241 let n = 1;
2242 let mut k = fun_name(n);
2243 k += 1;
2244}
2245
2246fn $0fun_name(n: i32) -> i32 {
2247 let mut k = n * n;
2248 k
2249}",
2250 );
2251 }
2252
2253 #[test]
2114 fn two_variables_defined_inside_and_used_after_no_ret() { 2254 fn two_variables_defined_inside_and_used_after_no_ret() {
2115 check_assist( 2255 check_assist(
2116 extract_function, 2256 extract_function,
@@ -2137,6 +2277,38 @@ fn $0fun_name(n: i32) -> (i32, i32) {
2137 } 2277 }
2138 2278
2139 #[test] 2279 #[test]
2280 fn multi_variables_defined_inside_and_used_after_mutably_no_ret() {
2281 check_assist(
2282 extract_function,
2283 r"
2284fn foo() {
2285 let n = 1;
2286 $0let mut k = n * n;
2287 let mut m = k + 2;
2288 let mut o = m + 3;
2289 o += 1;$0
2290 k += o;
2291 m = 1;
2292}",
2293 r"
2294fn foo() {
2295 let n = 1;
2296 let (mut k, mut m, o) = fun_name(n);
2297 k += o;
2298 m = 1;
2299}
2300
2301fn $0fun_name(n: i32) -> (i32, i32, i32) {
2302 let mut k = n * n;
2303 let mut m = k + 2;
2304 let mut o = m + 3;
2305 o += 1;
2306 (k, m, o)
2307}",
2308 );
2309 }
2310
2311 #[test]
2140 fn nontrivial_patterns_define_variables() { 2312 fn nontrivial_patterns_define_variables() {
2141 check_assist( 2313 check_assist(
2142 extract_function, 2314 extract_function,
@@ -2364,17 +2536,15 @@ fn foo() {
2364} 2536}
2365 2537
2366fn $0fun_name(n: &mut i32) { 2538fn $0fun_name(n: &mut i32) {
2367 { 2539 *n += *n;
2368 *n += *n; 2540 bar(*n);
2369 bar(*n); 2541 bar(*n+1);
2370 bar(*n+1); 2542 bar(*n**n);
2371 bar(*n**n); 2543 bar(&*n);
2372 bar(&*n); 2544 n.inc();
2373 n.inc(); 2545 let v = n;
2374 let v = n; 2546 *v = v.succ();
2375 *v = v.succ(); 2547 n.succ();
2376 n.succ();
2377 }
2378}", 2548}",
2379 ); 2549 );
2380 } 2550 }
@@ -3372,4 +3542,36 @@ fn foo() -> Result<(), i64> {
3372}"##, 3542}"##,
3373 ); 3543 );
3374 } 3544 }
3545
3546 #[test]
3547 fn param_usage_in_macro() {
3548 check_assist(
3549 extract_function,
3550 r"
3551macro_rules! m {
3552 ($val:expr) => { $val };
3553}
3554
3555fn foo() {
3556 let n = 1;
3557 $0let k = n * m!(n);$0
3558 let m = k + 1;
3559}",
3560 r"
3561macro_rules! m {
3562 ($val:expr) => { $val };
3563}
3564
3565fn foo() {
3566 let n = 1;
3567 let k = fun_name(n);
3568 let m = k + 1;
3569}
3570
3571fn $0fun_name(n: i32) -> i32 {
3572 let k = n * m!(n);
3573 k
3574}",
3575 );
3576 }
3375} 3577}
diff --git a/crates/ide_assists/src/handlers/extract_variable.rs b/crates/ide_assists/src/handlers/extract_variable.rs
index 7a32483dc..136b9a55b 100644
--- a/crates/ide_assists/src/handlers/extract_variable.rs
+++ b/crates/ide_assists/src/handlers/extract_variable.rs
@@ -2,7 +2,8 @@ use stdx::format_to;
2use syntax::{ 2use syntax::{
3 ast::{self, AstNode}, 3 ast::{self, AstNode},
4 SyntaxKind::{ 4 SyntaxKind::{
5 BLOCK_EXPR, BREAK_EXPR, CLOSURE_EXPR, COMMENT, LOOP_EXPR, MATCH_ARM, PATH_EXPR, RETURN_EXPR, 5 BLOCK_EXPR, BREAK_EXPR, CLOSURE_EXPR, COMMENT, LOOP_EXPR, MATCH_ARM, MATCH_GUARD,
6 PATH_EXPR, RETURN_EXPR,
6 }, 7 },
7 SyntaxNode, 8 SyntaxNode,
8}; 9};
@@ -147,9 +148,18 @@ impl Anchor {
147 } 148 }
148 149
149 if let Some(parent) = node.parent() { 150 if let Some(parent) = node.parent() {
150 if parent.kind() == MATCH_ARM || parent.kind() == CLOSURE_EXPR { 151 if parent.kind() == CLOSURE_EXPR {
152 cov_mark::hit!(test_extract_var_in_closure_no_block);
151 return Some(Anchor::WrapInBlock(node)); 153 return Some(Anchor::WrapInBlock(node));
152 } 154 }
155 if parent.kind() == MATCH_ARM {
156 if node.kind() == MATCH_GUARD {
157 cov_mark::hit!(test_extract_var_in_match_guard);
158 } else {
159 cov_mark::hit!(test_extract_var_in_match_arm_no_block);
160 return Some(Anchor::WrapInBlock(node));
161 }
162 }
153 } 163 }
154 164
155 if let Some(stmt) = ast::Stmt::cast(node.clone()) { 165 if let Some(stmt) = ast::Stmt::cast(node.clone()) {
@@ -280,9 +290,10 @@ fn foo() {
280 290
281 #[test] 291 #[test]
282 fn test_extract_var_in_match_arm_no_block() { 292 fn test_extract_var_in_match_arm_no_block() {
293 cov_mark::check!(test_extract_var_in_match_arm_no_block);
283 check_assist( 294 check_assist(
284 extract_variable, 295 extract_variable,
285 " 296 r#"
286fn main() { 297fn main() {
287 let x = true; 298 let x = true;
288 let tuple = match x { 299 let tuple = match x {
@@ -290,8 +301,8 @@ fn main() {
290 _ => (0, false) 301 _ => (0, false)
291 }; 302 };
292} 303}
293", 304"#,
294 " 305 r#"
295fn main() { 306fn main() {
296 let x = true; 307 let x = true;
297 let tuple = match x { 308 let tuple = match x {
@@ -299,7 +310,7 @@ fn main() {
299 _ => (0, false) 310 _ => (0, false)
300 }; 311 };
301} 312}
302", 313"#,
303 ); 314 );
304 } 315 }
305 316
@@ -307,7 +318,7 @@ fn main() {
307 fn test_extract_var_in_match_arm_with_block() { 318 fn test_extract_var_in_match_arm_with_block() {
308 check_assist( 319 check_assist(
309 extract_variable, 320 extract_variable,
310 " 321 r#"
311fn main() { 322fn main() {
312 let x = true; 323 let x = true;
313 let tuple = match x { 324 let tuple = match x {
@@ -318,8 +329,8 @@ fn main() {
318 _ => (0, false) 329 _ => (0, false)
319 }; 330 };
320} 331}
321", 332"#,
322 " 333 r#"
323fn main() { 334fn main() {
324 let x = true; 335 let x = true;
325 let tuple = match x { 336 let tuple = match x {
@@ -331,24 +342,50 @@ fn main() {
331 _ => (0, false) 342 _ => (0, false)
332 }; 343 };
333} 344}
334", 345"#,
346 );
347 }
348
349 #[test]
350 fn test_extract_var_in_match_guard() {
351 cov_mark::check!(test_extract_var_in_match_guard);
352 check_assist(
353 extract_variable,
354 r#"
355fn main() {
356 match () {
357 () if $010 > 0$0 => 1
358 _ => 2
359 };
360}
361"#,
362 r#"
363fn main() {
364 let $0var_name = 10 > 0;
365 match () {
366 () if var_name => 1
367 _ => 2
368 };
369}
370"#,
335 ); 371 );
336 } 372 }
337 373
338 #[test] 374 #[test]
339 fn test_extract_var_in_closure_no_block() { 375 fn test_extract_var_in_closure_no_block() {
376 cov_mark::check!(test_extract_var_in_closure_no_block);
340 check_assist( 377 check_assist(
341 extract_variable, 378 extract_variable,
342 " 379 r#"
343fn main() { 380fn main() {
344 let lambda = |x: u32| $0x * 2$0; 381 let lambda = |x: u32| $0x * 2$0;
345} 382}
346", 383"#,
347 " 384 r#"
348fn main() { 385fn main() {
349 let lambda = |x: u32| { let $0var_name = x * 2; var_name }; 386 let lambda = |x: u32| { let $0var_name = x * 2; var_name };
350} 387}
351", 388"#,
352 ); 389 );
353 } 390 }
354 391
@@ -356,16 +393,16 @@ fn main() {
356 fn test_extract_var_in_closure_with_block() { 393 fn test_extract_var_in_closure_with_block() {
357 check_assist( 394 check_assist(
358 extract_variable, 395 extract_variable,
359 " 396 r#"
360fn main() { 397fn main() {
361 let lambda = |x: u32| { $0x * 2$0 }; 398 let lambda = |x: u32| { $0x * 2$0 };
362} 399}
363", 400"#,
364 " 401 r#"
365fn main() { 402fn main() {
366 let lambda = |x: u32| { let $0var_name = x * 2; var_name }; 403 let lambda = |x: u32| { let $0var_name = x * 2; var_name };
367} 404}
368", 405"#,
369 ); 406 );
370 } 407 }
371 408
diff --git a/crates/ide_assists/src/handlers/fill_match_arms.rs b/crates/ide_assists/src/handlers/fill_match_arms.rs
index 878b3a3fa..be927cc1c 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -1,5 +1,6 @@
1use std::iter; 1use std::iter;
2 2
3use either::Either;
3use hir::{Adt, HasSource, ModuleDef, Semantics}; 4use hir::{Adt, HasSource, ModuleDef, Semantics};
4use ide_db::helpers::{mod_path_to_ast, FamousDefs}; 5use ide_db::helpers::{mod_path_to_ast, FamousDefs};
5use ide_db::RootDatabase; 6use ide_db::RootDatabase;
@@ -7,7 +8,7 @@ use itertools::Itertools;
7use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat}; 8use syntax::ast::{self, make, AstNode, MatchArm, NameOwner, Pat};
8 9
9use crate::{ 10use crate::{
10 utils::{does_pat_match_variant, render_snippet, Cursor}, 11 utils::{self, render_snippet, Cursor},
11 AssistContext, AssistId, AssistKind, Assists, 12 AssistContext, AssistId, AssistKind, Assists,
12}; 13};
13 14
@@ -48,6 +49,18 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
48 } 49 }
49 } 50 }
50 51
52 let top_lvl_pats: Vec<_> = arms
53 .iter()
54 .filter_map(ast::MatchArm::pat)
55 .flat_map(|pat| match pat {
56 // Special case OrPat as separate top-level pats
57 Pat::OrPat(or_pat) => Either::Left(or_pat.pats()),
58 _ => Either::Right(iter::once(pat)),
59 })
60 // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
61 .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
62 .collect();
63
51 let module = ctx.sema.scope(expr.syntax()).module()?; 64 let module = ctx.sema.scope(expr.syntax()).module()?;
52 65
53 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) { 66 let missing_arms: Vec<MatchArm> = if let Some(enum_def) = resolve_enum_def(&ctx.sema, &expr) {
@@ -56,27 +69,20 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
56 let mut variants = variants 69 let mut variants = variants
57 .into_iter() 70 .into_iter()
58 .filter_map(|variant| build_pat(ctx.db(), module, variant)) 71 .filter_map(|variant| build_pat(ctx.db(), module, variant))
59 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 72 .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat))
60 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 73 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
61 .collect::<Vec<_>>(); 74 .collect::<Vec<_>>();
62 if Some(enum_def) == FamousDefs(&ctx.sema, Some(module.krate())).core_option_Option() { 75 if Some(enum_def)
76 == FamousDefs(&ctx.sema, Some(module.krate()))
77 .core_option_Option()
78 .map(|x| lift_enum(x))
79 {
63 // Match `Some` variant first. 80 // Match `Some` variant first.
64 cov_mark::hit!(option_order); 81 cov_mark::hit!(option_order);
65 variants.reverse() 82 variants.reverse()
66 } 83 }
67 variants 84 variants
68 } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) { 85 } else if let Some(enum_defs) = resolve_tuple_of_enum_def(&ctx.sema, &expr) {
69 // Partial fill not currently supported for tuple of enums.
70 if !arms.is_empty() {
71 return None;
72 }
73
74 // We do not currently support filling match arms for a tuple
75 // containing a single enum.
76 if enum_defs.len() < 2 {
77 return None;
78 }
79
80 // When calculating the match arms for a tuple of enums, we want 86 // When calculating the match arms for a tuple of enums, we want
81 // to create a match arm for each possible combination of enum 87 // to create a match arm for each possible combination of enum
82 // values. The `multi_cartesian_product` method transforms 88 // values. The `multi_cartesian_product` method transforms
@@ -91,7 +97,7 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
91 variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant)); 97 variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
92 ast::Pat::from(make::tuple_pat(patterns)) 98 ast::Pat::from(make::tuple_pat(patterns))
93 }) 99 })
94 .filter(|variant_pat| is_variant_missing(&mut arms, variant_pat)) 100 .filter(|variant_pat| is_variant_missing(&top_lvl_pats, variant_pat))
95 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block())) 101 .map(|pat| make::match_arm(iter::once(pat), make::expr_empty_block()))
96 .collect() 102 .collect()
97 } else { 103 } else {
@@ -134,61 +140,114 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
134 ) 140 )
135} 141}
136 142
137fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { 143fn is_variant_missing(existing_pats: &[Pat], var: &Pat) -> bool {
138 existing_arms.iter().filter_map(|arm| arm.pat()).all(|pat| { 144 !existing_pats.iter().any(|pat| does_pat_match_variant(pat, var))
139 // Special casee OrPat as separate top-level pats 145}
140 let top_level_pats: Vec<Pat> = match pat {
141 Pat::OrPat(pats) => pats.pats().collect::<Vec<_>>(),
142 _ => vec![pat],
143 };
144 146
145 !top_level_pats.iter().any(|pat| does_pat_match_variant(pat, var)) 147// Fixme: this is still somewhat limited, use hir_ty::diagnostics::match_check?
146 }) 148fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool {
149 match (pat, var) {
150 (Pat::WildcardPat(_), _) => true,
151 (Pat::TuplePat(tpat), Pat::TuplePat(tvar)) => {
152 tpat.fields().zip(tvar.fields()).all(|(p, v)| does_pat_match_variant(&p, &v))
153 }
154 _ => utils::does_pat_match_variant(pat, var),
155 }
156}
157
158#[derive(Eq, PartialEq, Clone)]
159enum ExtendedEnum {
160 Bool,
161 Enum(hir::Enum),
162}
163
164#[derive(Eq, PartialEq, Clone)]
165enum ExtendedVariant {
166 True,
167 False,
168 Variant(hir::Variant),
169}
170
171fn lift_enum(e: hir::Enum) -> ExtendedEnum {
172 ExtendedEnum::Enum(e)
173}
174
175impl ExtendedEnum {
176 fn variants(&self, db: &RootDatabase) -> Vec<ExtendedVariant> {
177 match self {
178 ExtendedEnum::Enum(e) => {
179 e.variants(db).into_iter().map(|x| ExtendedVariant::Variant(x)).collect::<Vec<_>>()
180 }
181 ExtendedEnum::Bool => {
182 Vec::<ExtendedVariant>::from([ExtendedVariant::True, ExtendedVariant::False])
183 }
184 }
185 }
147} 186}
148 187
149fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<hir::Enum> { 188fn resolve_enum_def(sema: &Semantics<RootDatabase>, expr: &ast::Expr) -> Option<ExtendedEnum> {
150 sema.type_of_expr(&expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() { 189 sema.type_of_expr(&expr)?.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
151 Some(Adt::Enum(e)) => Some(e), 190 Some(Adt::Enum(e)) => Some(ExtendedEnum::Enum(e)),
152 _ => None, 191 _ => {
192 if ty.is_bool() {
193 Some(ExtendedEnum::Bool)
194 } else {
195 None
196 }
197 }
153 }) 198 })
154} 199}
155 200
156fn resolve_tuple_of_enum_def( 201fn resolve_tuple_of_enum_def(
157 sema: &Semantics<RootDatabase>, 202 sema: &Semantics<RootDatabase>,
158 expr: &ast::Expr, 203 expr: &ast::Expr,
159) -> Option<Vec<hir::Enum>> { 204) -> Option<Vec<ExtendedEnum>> {
160 sema.type_of_expr(&expr)? 205 sema.type_of_expr(&expr)?
161 .tuple_fields(sema.db) 206 .tuple_fields(sema.db)
162 .iter() 207 .iter()
163 .map(|ty| { 208 .map(|ty| {
164 ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() { 209 ty.autoderef(sema.db).find_map(|ty| match ty.as_adt() {
165 Some(Adt::Enum(e)) => Some(e), 210 Some(Adt::Enum(e)) => Some(lift_enum(e)),
166 // For now we only handle expansion for a tuple of enums. Here 211 // For now we only handle expansion for a tuple of enums. Here
167 // we map non-enum items to None and rely on `collect` to 212 // we map non-enum items to None and rely on `collect` to
168 // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>. 213 // convert Vec<Option<hir::Enum>> into Option<Vec<hir::Enum>>.
169 _ => None, 214 _ => {
215 if ty.is_bool() {
216 Some(ExtendedEnum::Bool)
217 } else {
218 None
219 }
220 }
170 }) 221 })
171 }) 222 })
172 .collect() 223 .collect()
173} 224}
174 225
175fn build_pat(db: &RootDatabase, module: hir::Module, var: hir::Variant) -> Option<ast::Pat> { 226fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option<ast::Pat> {
176 let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?); 227 match var {
228 ExtendedVariant::Variant(var) => {
229 let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
230
231 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
232 let pat: ast::Pat = match var.source(db)?.value.kind() {
233 ast::StructKind::Tuple(field_list) => {
234 let pats =
235 iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
236 make::tuple_struct_pat(path, pats).into()
237 }
238 ast::StructKind::Record(field_list) => {
239 let pats =
240 field_list.fields().map(|f| make::ident_pat(f.name().unwrap()).into());
241 make::record_pat(path, pats).into()
242 }
243 ast::StructKind::Unit => make::path_pat(path),
244 };
177 245
178 // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though 246 Some(pat)
179 let pat: ast::Pat = match var.source(db)?.value.kind() {
180 ast::StructKind::Tuple(field_list) => {
181 let pats = iter::repeat(make::wildcard_pat().into()).take(field_list.fields().count());
182 make::tuple_struct_pat(path, pats).into()
183 }
184 ast::StructKind::Record(field_list) => {
185 let pats = field_list.fields().map(|f| make::ident_pat(f.name().unwrap()).into());
186 make::record_pat(path, pats).into()
187 } 247 }
188 ast::StructKind::Unit => make::path_pat(path), 248 ExtendedVariant::True => Some(ast::Pat::from(make::literal_pat("true"))),
189 }; 249 ExtendedVariant::False => Some(ast::Pat::from(make::literal_pat("false"))),
190 250 }
191 Some(pat)
192} 251}
193 252
194#[cfg(test)] 253#[cfg(test)]
@@ -221,6 +280,21 @@ mod tests {
221 } 280 }
222 281
223 #[test] 282 #[test]
283 fn all_boolean_match_arms_provided() {
284 check_assist_not_applicable(
285 fill_match_arms,
286 r#"
287 fn foo(a: bool) {
288 match a$0 {
289 true => {}
290 false => {}
291 }
292 }
293 "#,
294 )
295 }
296
297 #[test]
224 fn tuple_of_non_enum() { 298 fn tuple_of_non_enum() {
225 // for now this case is not handled, although it potentially could be 299 // for now this case is not handled, although it potentially could be
226 // in the future 300 // in the future
@@ -236,6 +310,113 @@ mod tests {
236 } 310 }
237 311
238 #[test] 312 #[test]
313 fn fill_match_arms_boolean() {
314 check_assist(
315 fill_match_arms,
316 r#"
317 fn foo(a: bool) {
318 match a$0 {
319 }
320 }
321 "#,
322 r#"
323 fn foo(a: bool) {
324 match a {
325 $0true => {}
326 false => {}
327 }
328 }
329 "#,
330 )
331 }
332
333 #[test]
334 fn partial_fill_boolean() {
335 check_assist(
336 fill_match_arms,
337 r#"
338 fn foo(a: bool) {
339 match a$0 {
340 true => {}
341 }
342 }
343 "#,
344 r#"
345 fn foo(a: bool) {
346 match a {
347 true => {}
348 $0false => {}
349 }
350 }
351 "#,
352 )
353 }
354
355 #[test]
356 fn all_boolean_tuple_arms_provided() {
357 check_assist_not_applicable(
358 fill_match_arms,
359 r#"
360 fn foo(a: bool) {
361 match (a, a)$0 {
362 (true, true) => {}
363 (true, false) => {}
364 (false, true) => {}
365 (false, false) => {}
366 }
367 }
368 "#,
369 )
370 }
371
372 #[test]
373 fn fill_boolean_tuple() {
374 check_assist(
375 fill_match_arms,
376 r#"
377 fn foo(a: bool) {
378 match (a, a)$0 {
379 }
380 }
381 "#,
382 r#"
383 fn foo(a: bool) {
384 match (a, a) {
385 $0(true, true) => {}
386 (true, false) => {}
387 (false, true) => {}
388 (false, false) => {}
389 }
390 }
391 "#,
392 )
393 }
394
395 #[test]
396 fn partial_fill_boolean_tuple() {
397 check_assist(
398 fill_match_arms,
399 r#"
400 fn foo(a: bool) {
401 match (a, a)$0 {
402 (false, true) => {}
403 }
404 }
405 "#,
406 r#"
407 fn foo(a: bool) {
408 match (a, a) {
409 (false, true) => {}
410 $0(true, true) => {}
411 (true, false) => {}
412 (false, false) => {}
413 }
414 }
415 "#,
416 )
417 }
418
419 #[test]
239 fn partial_fill_record_tuple() { 420 fn partial_fill_record_tuple() {
240 check_assist( 421 check_assist(
241 fill_match_arms, 422 fill_match_arms,
@@ -473,20 +654,81 @@ fn main() {
473 654
474 #[test] 655 #[test]
475 fn fill_match_arms_tuple_of_enum_partial() { 656 fn fill_match_arms_tuple_of_enum_partial() {
476 check_assist_not_applicable( 657 check_assist(
477 fill_match_arms, 658 fill_match_arms,
478 r#" 659 r#"
479 enum A { One, Two } 660enum A { One, Two }
480 enum B { One, Two } 661enum B { One, Two }
481 662
482 fn main() { 663fn main() {
483 let a = A::One; 664 let a = A::One;
484 let b = B::One; 665 let b = B::One;
485 match (a$0, b) { 666 match (a$0, b) {
486 (A::Two, B::One) => {} 667 (A::Two, B::One) => {}
487 } 668 }
488 } 669}
489 "#, 670"#,
671 r#"
672enum A { One, Two }
673enum B { One, Two }
674
675fn main() {
676 let a = A::One;
677 let b = B::One;
678 match (a, b) {
679 (A::Two, B::One) => {}
680 $0(A::One, B::One) => {}
681 (A::One, B::Two) => {}
682 (A::Two, B::Two) => {}
683 }
684}
685"#,
686 );
687 }
688
689 #[test]
690 fn fill_match_arms_tuple_of_enum_partial_with_wildcards() {
691 let ra_fixture = r#"
692fn main() {
693 let a = Some(1);
694 let b = Some(());
695 match (a$0, b) {
696 (Some(_), _) => {}
697 (None, Some(_)) => {}
698 }
699}
700"#;
701 check_assist(
702 fill_match_arms,
703 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
704 r#"
705fn main() {
706 let a = Some(1);
707 let b = Some(());
708 match (a, b) {
709 (Some(_), _) => {}
710 (None, Some(_)) => {}
711 $0(None, None) => {}
712 }
713}
714"#,
715 );
716 }
717
718 #[test]
719 fn fill_match_arms_partial_with_deep_pattern() {
720 // Fixme: cannot handle deep patterns
721 let ra_fixture = r#"
722fn main() {
723 match $0Some(true) {
724 Some(true) => {}
725 None => {}
726 }
727}
728"#;
729 check_assist_not_applicable(
730 fill_match_arms,
731 &format!("//- /main.rs crate:main deps:core{}{}", ra_fixture, FamousDefs::FIXTURE),
490 ); 732 );
491 } 733 }
492 734
@@ -514,10 +756,7 @@ fn main() {
514 756
515 #[test] 757 #[test]
516 fn fill_match_arms_single_element_tuple_of_enum() { 758 fn fill_match_arms_single_element_tuple_of_enum() {
517 // For now we don't hande the case of a single element tuple, but 759 check_assist(
518 // we could handle this in the future if `make::tuple_pat` allowed
519 // creating a tuple with a single pattern.
520 check_assist_not_applicable(
521 fill_match_arms, 760 fill_match_arms,
522 r#" 761 r#"
523 enum A { One, Two } 762 enum A { One, Two }
@@ -528,6 +767,17 @@ fn main() {
528 } 767 }
529 } 768 }
530 "#, 769 "#,
770 r#"
771 enum A { One, Two }
772
773 fn main() {
774 let a = A::One;
775 match (a, ) {
776 $0(A::One,) => {}
777 (A::Two,) => {}
778 }
779 }
780 "#,
531 ); 781 );
532 } 782 }
533 783
diff --git a/crates/ide_assists/src/handlers/flip_comma.rs b/crates/ide_assists/src/handlers/flip_comma.rs
index 7f5e75d34..99be5e090 100644
--- a/crates/ide_assists/src/handlers/flip_comma.rs
+++ b/crates/ide_assists/src/handlers/flip_comma.rs
@@ -66,26 +66,12 @@ mod tests {
66 } 66 }
67 67
68 #[test] 68 #[test]
69 #[should_panic]
70 fn flip_comma_before_punct() { 69 fn flip_comma_before_punct() {
71 // See https://github.com/rust-analyzer/rust-analyzer/issues/1619 70 // See https://github.com/rust-analyzer/rust-analyzer/issues/1619
72 // "Flip comma" assist shouldn't be applicable to the last comma in enum or struct 71 // "Flip comma" assist shouldn't be applicable to the last comma in enum or struct
73 // declaration body. 72 // declaration body.
74 check_assist_target( 73 check_assist_not_applicable(flip_comma, "pub enum Test { A,$0 }");
75 flip_comma, 74 check_assist_not_applicable(flip_comma, "pub struct Test { foo: usize,$0 }");
76 "pub enum Test { \
77 A,$0 \
78 }",
79 ",",
80 );
81
82 check_assist_target(
83 flip_comma,
84 "pub struct Test { \
85 foo: usize,$0 \
86 }",
87 ",",
88 );
89 } 75 }
90 76
91 #[test] 77 #[test]
diff --git a/crates/ide_assists/src/handlers/generate_deref.rs b/crates/ide_assists/src/handlers/generate_deref.rs
new file mode 100644
index 000000000..4998ff7a4
--- /dev/null
+++ b/crates/ide_assists/src/handlers/generate_deref.rs
@@ -0,0 +1,227 @@
1use std::fmt::Display;
2
3use ide_db::{helpers::FamousDefs, RootDatabase};
4use syntax::{
5 ast::{self, NameOwner},
6 AstNode, SyntaxNode,
7};
8
9use crate::{
10 assist_context::{AssistBuilder, AssistContext, Assists},
11 utils::generate_trait_impl_text,
12 AssistId, AssistKind,
13};
14
15// Assist: generate_deref
16//
17// Generate `Deref` impl using the given struct field.
18//
19// ```
20// struct A;
21// struct B {
22// $0a: A
23// }
24// ```
25// ->
26// ```
27// struct A;
28// struct B {
29// a: A
30// }
31//
32// impl std::ops::Deref for B {
33// type Target = A;
34//
35// fn deref(&self) -> &Self::Target {
36// &self.a
37// }
38// }
39// ```
40pub(crate) fn generate_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
41 generate_record_deref(acc, ctx).or_else(|| generate_tuple_deref(acc, ctx))
42}
43
44fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
45 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
46 let field = ctx.find_node_at_offset::<ast::RecordField>()?;
47
48 if existing_deref_impl(&ctx.sema, &strukt).is_some() {
49 cov_mark::hit!(test_add_record_deref_impl_already_exists);
50 return None;
51 }
52
53 let field_type = field.ty()?;
54 let field_name = field.name()?;
55 let target = field.syntax().text_range();
56 acc.add(
57 AssistId("generate_deref", AssistKind::Generate),
58 format!("Generate `Deref` impl using `{}`", field_name),
59 target,
60 |edit| generate_edit(edit, strukt, field_type.syntax(), field_name.syntax()),
61 )
62}
63
64fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
65 let strukt = ctx.find_node_at_offset::<ast::Struct>()?;
66 let field = ctx.find_node_at_offset::<ast::TupleField>()?;
67 let field_list = ctx.find_node_at_offset::<ast::TupleFieldList>()?;
68 let field_list_index =
69 field_list.syntax().children().into_iter().position(|s| &s == field.syntax())?;
70
71 if existing_deref_impl(&ctx.sema, &strukt).is_some() {
72 cov_mark::hit!(test_add_field_deref_impl_already_exists);
73 return None;
74 }
75
76 let field_type = field.ty()?;
77 let target = field.syntax().text_range();
78 acc.add(
79 AssistId("generate_deref", AssistKind::Generate),
80 format!("Generate `Deref` impl using `{}`", field.syntax()),
81 target,
82 |edit| generate_edit(edit, strukt, field_type.syntax(), field_list_index),
83 )
84}
85
86fn generate_edit(
87 edit: &mut AssistBuilder,
88 strukt: ast::Struct,
89 field_type_syntax: &SyntaxNode,
90 field_name: impl Display,
91) {
92 let start_offset = strukt.syntax().text_range().end();
93 let impl_code = format!(
94 r#" type Target = {0};
95
96 fn deref(&self) -> &Self::Target {{
97 &self.{1}
98 }}"#,
99 field_type_syntax, field_name
100 );
101 let strukt_adt = ast::Adt::Struct(strukt);
102 let deref_impl = generate_trait_impl_text(&strukt_adt, "std::ops::Deref", &impl_code);
103 edit.insert(start_offset, deref_impl);
104}
105
106fn existing_deref_impl(
107 sema: &'_ hir::Semantics<'_, RootDatabase>,
108 strukt: &ast::Struct,
109) -> Option<()> {
110 let strukt = sema.to_def(strukt)?;
111 let krate = strukt.module(sema.db).krate();
112
113 let deref_trait = FamousDefs(sema, Some(krate)).core_ops_Deref()?;
114 let strukt_type = strukt.ty(sema.db);
115
116 if strukt_type.impls_trait(sema.db, deref_trait, &[]) {
117 Some(())
118 } else {
119 None
120 }
121}
122
123#[cfg(test)]
124mod tests {
125 use crate::tests::{check_assist, check_assist_not_applicable};
126
127 use super::*;
128
129 #[test]
130 fn test_generate_record_deref() {
131 check_assist(
132 generate_deref,
133 r#"struct A { }
134struct B { $0a: A }"#,
135 r#"struct A { }
136struct B { a: A }
137
138impl std::ops::Deref for B {
139 type Target = A;
140
141 fn deref(&self) -> &Self::Target {
142 &self.a
143 }
144}"#,
145 );
146 }
147
148 #[test]
149 fn test_generate_field_deref_idx_0() {
150 check_assist(
151 generate_deref,
152 r#"struct A { }
153struct B($0A);"#,
154 r#"struct A { }
155struct B(A);
156
157impl std::ops::Deref for B {
158 type Target = A;
159
160 fn deref(&self) -> &Self::Target {
161 &self.0
162 }
163}"#,
164 );
165 }
166 #[test]
167 fn test_generate_field_deref_idx_1() {
168 check_assist(
169 generate_deref,
170 r#"struct A { }
171struct B(u8, $0A);"#,
172 r#"struct A { }
173struct B(u8, A);
174
175impl std::ops::Deref for B {
176 type Target = A;
177
178 fn deref(&self) -> &Self::Target {
179 &self.1
180 }
181}"#,
182 );
183 }
184
185 fn check_not_applicable(ra_fixture: &str) {
186 let fixture = format!(
187 "//- /main.rs crate:main deps:core,std\n{}\n{}",
188 ra_fixture,
189 FamousDefs::FIXTURE
190 );
191 check_assist_not_applicable(generate_deref, &fixture)
192 }
193
194 #[test]
195 fn test_generate_record_deref_not_applicable_if_already_impl() {
196 cov_mark::check!(test_add_record_deref_impl_already_exists);
197 check_not_applicable(
198 r#"struct A { }
199struct B { $0a: A }
200
201impl std::ops::Deref for B {
202 type Target = A;
203
204 fn deref(&self) -> &Self::Target {
205 &self.a
206 }
207}"#,
208 )
209 }
210
211 #[test]
212 fn test_generate_field_deref_not_applicable_if_already_impl() {
213 cov_mark::check!(test_add_field_deref_impl_already_exists);
214 check_not_applicable(
215 r#"struct A { }
216struct B($0A)
217
218impl std::ops::Deref for B {
219 type Target = A;
220
221 fn deref(&self) -> &Self::Target {
222 &self.0
223 }
224}"#,
225 )
226 }
227}
diff --git a/crates/ide_assists/src/handlers/inline_local_variable.rs b/crates/ide_assists/src/handlers/inline_local_variable.rs
index ea1466dc8..f5dafc8cb 100644
--- a/crates/ide_assists/src/handlers/inline_local_variable.rs
+++ b/crates/ide_assists/src/handlers/inline_local_variable.rs
@@ -1,7 +1,9 @@
1use ide_db::{defs::Definition, search::FileReference}; 1use either::Either;
2use hir::PathResolution;
3use ide_db::{base_db::FileId, defs::Definition, search::FileReference};
2use rustc_hash::FxHashMap; 4use rustc_hash::FxHashMap;
3use syntax::{ 5use syntax::{
4 ast::{self, AstNode, AstToken}, 6 ast::{self, AstNode, AstToken, NameOwner},
5 TextRange, 7 TextRange,
6}; 8};
7 9
@@ -27,44 +29,28 @@ use crate::{
27// } 29// }
28// ``` 30// ```
29pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 31pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
30 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?; 32 let InlineData { let_stmt, delete_let, replace_usages, target } =
31 let bind_pat = match let_stmt.pat()? { 33 inline_let(ctx).or_else(|| inline_usage(ctx))?;
32 ast::Pat::IdentPat(pat) => pat,
33 _ => return None,
34 };
35 if bind_pat.mut_token().is_some() {
36 cov_mark::hit!(test_not_inline_mut_variable);
37 return None;
38 }
39 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
40 cov_mark::hit!(not_applicable_outside_of_bind_pat);
41 return None;
42 }
43 let initializer_expr = let_stmt.initializer()?; 34 let initializer_expr = let_stmt.initializer()?;
44 35
45 let def = ctx.sema.to_def(&bind_pat)?; 36 let delete_range = if delete_let {
46 let def = Definition::Local(def); 37 if let Some(whitespace) = let_stmt
47 let usages = def.usages(&ctx.sema).all(); 38 .syntax()
48 if usages.is_empty() { 39 .next_sibling_or_token()
49 cov_mark::hit!(test_not_applicable_if_variable_unused); 40 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone()))
50 return None; 41 {
51 }; 42 Some(TextRange::new(
52 43 let_stmt.syntax().text_range().start(),
53 let delete_range = if let Some(whitespace) = let_stmt 44 whitespace.syntax().text_range().end(),
54 .syntax() 45 ))
55 .next_sibling_or_token() 46 } else {
56 .and_then(|it| ast::Whitespace::cast(it.as_token()?.clone())) 47 Some(let_stmt.syntax().text_range())
57 { 48 }
58 TextRange::new(
59 let_stmt.syntax().text_range().start(),
60 whitespace.syntax().text_range().end(),
61 )
62 } else { 49 } else {
63 let_stmt.syntax().text_range() 50 None
64 }; 51 };
65 52
66 let wrap_in_parens = usages 53 let wrap_in_parens = replace_usages
67 .references
68 .iter() 54 .iter()
69 .map(|(&file_id, refs)| { 55 .map(|(&file_id, refs)| {
70 refs.iter() 56 refs.iter()
@@ -114,14 +100,20 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
114 let init_str = initializer_expr.syntax().text().to_string(); 100 let init_str = initializer_expr.syntax().text().to_string();
115 let init_in_paren = format!("({})", &init_str); 101 let init_in_paren = format!("({})", &init_str);
116 102
117 let target = bind_pat.syntax().text_range(); 103 let target = match target {
104 ast::NameOrNameRef::Name(it) => it.syntax().text_range(),
105 ast::NameOrNameRef::NameRef(it) => it.syntax().text_range(),
106 };
107
118 acc.add( 108 acc.add(
119 AssistId("inline_local_variable", AssistKind::RefactorInline), 109 AssistId("inline_local_variable", AssistKind::RefactorInline),
120 "Inline variable", 110 "Inline variable",
121 target, 111 target,
122 move |builder| { 112 move |builder| {
123 builder.delete(delete_range); 113 if let Some(range) = delete_range {
124 for (file_id, references) in usages.references { 114 builder.delete(range);
115 }
116 for (file_id, references) in replace_usages {
125 for (&should_wrap, reference) in wrap_in_parens[&file_id].iter().zip(references) { 117 for (&should_wrap, reference) in wrap_in_parens[&file_id].iter().zip(references) {
126 let replacement = 118 let replacement =
127 if should_wrap { init_in_paren.clone() } else { init_str.clone() }; 119 if should_wrap { init_in_paren.clone() } else { init_str.clone() };
@@ -140,6 +132,81 @@ pub(crate) fn inline_local_variable(acc: &mut Assists, ctx: &AssistContext) -> O
140 ) 132 )
141} 133}
142 134
135struct InlineData {
136 let_stmt: ast::LetStmt,
137 delete_let: bool,
138 target: ast::NameOrNameRef,
139 replace_usages: FxHashMap<FileId, Vec<FileReference>>,
140}
141
142fn inline_let(ctx: &AssistContext) -> Option<InlineData> {
143 let let_stmt = ctx.find_node_at_offset::<ast::LetStmt>()?;
144 let bind_pat = match let_stmt.pat()? {
145 ast::Pat::IdentPat(pat) => pat,
146 _ => return None,
147 };
148 if bind_pat.mut_token().is_some() {
149 cov_mark::hit!(test_not_inline_mut_variable);
150 return None;
151 }
152 if !bind_pat.syntax().text_range().contains_inclusive(ctx.offset()) {
153 cov_mark::hit!(not_applicable_outside_of_bind_pat);
154 return None;
155 }
156
157 let def = ctx.sema.to_def(&bind_pat)?;
158 let def = Definition::Local(def);
159 let usages = def.usages(&ctx.sema).all();
160 if usages.is_empty() {
161 cov_mark::hit!(test_not_applicable_if_variable_unused);
162 return None;
163 };
164
165 Some(InlineData {
166 let_stmt,
167 delete_let: true,
168 target: ast::NameOrNameRef::Name(bind_pat.name()?),
169 replace_usages: usages.references,
170 })
171}
172
173fn inline_usage(ctx: &AssistContext) -> Option<InlineData> {
174 let path_expr = ctx.find_node_at_offset::<ast::PathExpr>()?;
175 let path = path_expr.path()?;
176 let name = match path.as_single_segment()?.kind()? {
177 ast::PathSegmentKind::Name(name) => name,
178 _ => return None,
179 };
180
181 let local = match ctx.sema.resolve_path(&path)? {
182 PathResolution::Local(local) => local,
183 _ => return None,
184 };
185
186 let bind_pat = match local.source(ctx.db()).value {
187 Either::Left(ident) => ident,
188 _ => return None,
189 };
190
191 let let_stmt = ast::LetStmt::cast(bind_pat.syntax().parent()?)?;
192
193 let def = Definition::Local(local);
194 let mut usages = def.usages(&ctx.sema).all();
195
196 let delete_let = usages.references.values().map(|v| v.len()).sum::<usize>() == 1;
197
198 for references in usages.references.values_mut() {
199 references.retain(|reference| reference.name.as_name_ref() == Some(&name));
200 }
201
202 Some(InlineData {
203 let_stmt,
204 delete_let,
205 target: ast::NameOrNameRef::NameRef(name),
206 replace_usages: usages.references,
207 })
208}
209
143#[cfg(test)] 210#[cfg(test)]
144mod tests { 211mod tests {
145 use crate::tests::{check_assist, check_assist_not_applicable}; 212 use crate::tests::{check_assist, check_assist_not_applicable};
@@ -726,4 +793,84 @@ fn main() {
726", 793",
727 ) 794 )
728 } 795 }
796
797 #[test]
798 fn works_on_local_usage() {
799 check_assist(
800 inline_local_variable,
801 r#"
802fn f() {
803 let xyz = 0;
804 xyz$0;
805}
806"#,
807 r#"
808fn f() {
809 0;
810}
811"#,
812 );
813 }
814
815 #[test]
816 fn does_not_remove_let_when_multiple_usages() {
817 check_assist(
818 inline_local_variable,
819 r#"
820fn f() {
821 let xyz = 0;
822 xyz$0;
823 xyz;
824}
825"#,
826 r#"
827fn f() {
828 let xyz = 0;
829 0;
830 xyz;
831}
832"#,
833 );
834 }
835
836 #[test]
837 fn not_applicable_with_non_ident_pattern() {
838 check_assist_not_applicable(
839 inline_local_variable,
840 r#"
841fn main() {
842 let (x, y) = (0, 1);
843 x$0;
844}
845"#,
846 );
847 }
848
849 #[test]
850 fn not_applicable_on_local_usage_in_macro() {
851 check_assist_not_applicable(
852 inline_local_variable,
853 r#"
854macro_rules! m {
855 ($i:ident) => { $i }
856}
857fn f() {
858 let xyz = 0;
859 m!(xyz$0); // replacing it would break the macro
860}
861"#,
862 );
863 check_assist_not_applicable(
864 inline_local_variable,
865 r#"
866macro_rules! m {
867 ($i:ident) => { $i }
868}
869fn f() {
870 let xyz$0 = 0;
871 m!(xyz); // replacing it would break the macro
872}
873"#,
874 );
875 }
729} 876}
diff --git a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
index 02782eb6d..9f4f71d6c 100644
--- a/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ide_assists/src/handlers/introduce_named_lifetime.rs
@@ -1,7 +1,8 @@
1use rustc_hash::FxHashSet; 1use rustc_hash::FxHashSet;
2use syntax::{ 2use syntax::{
3 ast::{self, GenericParamsOwner, NameOwner}, 3 ast::{self, edit_in_place::GenericParamsOwnerEdit, make, GenericParamsOwner},
4 AstNode, TextRange, TextSize, 4 ted::{self, Position},
5 AstNode, TextRange,
5}; 6};
6 7
7use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists}; 8use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
@@ -37,10 +38,12 @@ static ASSIST_LABEL: &str = "Introduce named lifetime";
37pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 38pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
38 let lifetime = 39 let lifetime =
39 ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?; 40 ctx.find_node_at_offset::<ast::Lifetime>().filter(|lifetime| lifetime.text() == "'_")?;
41 let lifetime_loc = lifetime.lifetime_ident_token()?.text_range();
42
40 if let Some(fn_def) = lifetime.syntax().ancestors().find_map(ast::Fn::cast) { 43 if let Some(fn_def) = lifetime.syntax().ancestors().find_map(ast::Fn::cast) {
41 generate_fn_def_assist(acc, &fn_def, lifetime.lifetime_ident_token()?.text_range()) 44 generate_fn_def_assist(acc, fn_def, lifetime_loc, lifetime)
42 } else if let Some(impl_def) = lifetime.syntax().ancestors().find_map(ast::Impl::cast) { 45 } else if let Some(impl_def) = lifetime.syntax().ancestors().find_map(ast::Impl::cast) {
43 generate_impl_def_assist(acc, &impl_def, lifetime.lifetime_ident_token()?.text_range()) 46 generate_impl_def_assist(acc, impl_def, lifetime_loc, lifetime)
44 } else { 47 } else {
45 None 48 None
46 } 49 }
@@ -49,26 +52,26 @@ pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -
49/// Generate the assist for the fn def case 52/// Generate the assist for the fn def case
50fn generate_fn_def_assist( 53fn generate_fn_def_assist(
51 acc: &mut Assists, 54 acc: &mut Assists,
52 fn_def: &ast::Fn, 55 fn_def: ast::Fn,
53 lifetime_loc: TextRange, 56 lifetime_loc: TextRange,
57 lifetime: ast::Lifetime,
54) -> Option<()> { 58) -> Option<()> {
55 let param_list: ast::ParamList = fn_def.param_list()?; 59 let param_list: ast::ParamList = fn_def.param_list()?;
56 let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.generic_param_list())?; 60 let new_lifetime_param = generate_unique_lifetime_param_name(fn_def.generic_param_list())?;
57 let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end();
58 let self_param = 61 let self_param =
59 // use the self if it's a reference and has no explicit lifetime 62 // use the self if it's a reference and has no explicit lifetime
60 param_list.self_param().filter(|p| p.lifetime().is_none() && p.amp_token().is_some()); 63 param_list.self_param().filter(|p| p.lifetime().is_none() && p.amp_token().is_some());
61 // compute the location which implicitly has the same lifetime as the anonymous lifetime 64 // compute the location which implicitly has the same lifetime as the anonymous lifetime
62 let loc_needing_lifetime = if let Some(self_param) = self_param { 65 let loc_needing_lifetime = if let Some(self_param) = self_param {
63 // if we have a self reference, use that 66 // if we have a self reference, use that
64 Some(self_param.name()?.syntax().text_range().start()) 67 Some(NeedsLifetime::SelfParam(self_param))
65 } else { 68 } else {
66 // otherwise, if there's a single reference parameter without a named liftime, use that 69 // otherwise, if there's a single reference parameter without a named liftime, use that
67 let fn_params_without_lifetime: Vec<_> = param_list 70 let fn_params_without_lifetime: Vec<_> = param_list
68 .params() 71 .params()
69 .filter_map(|param| match param.ty() { 72 .filter_map(|param| match param.ty() {
70 Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime().is_none() => { 73 Some(ast::Type::RefType(ascribed_type)) if ascribed_type.lifetime().is_none() => {
71 Some(ascribed_type.amp_token()?.text_range().end()) 74 Some(NeedsLifetime::RefType(ascribed_type))
72 } 75 }
73 _ => None, 76 _ => None,
74 }) 77 })
@@ -81,30 +84,46 @@ fn generate_fn_def_assist(
81 } 84 }
82 }; 85 };
83 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { 86 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
84 add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); 87 let fn_def = builder.make_ast_mut(fn_def);
85 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); 88 let lifetime = builder.make_ast_mut(lifetime);
86 loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); 89 let loc_needing_lifetime =
90 loc_needing_lifetime.and_then(|it| it.make_mut(builder).to_position());
91
92 add_lifetime_param(fn_def.get_or_create_generic_param_list(), new_lifetime_param);
93 ted::replace(
94 lifetime.syntax(),
95 make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(),
96 );
97 loc_needing_lifetime.map(|position| {
98 ted::insert(position, make_ast_lifetime(new_lifetime_param).clone_for_update().syntax())
99 });
87 }) 100 })
88} 101}
89 102
90/// Generate the assist for the impl def case 103/// Generate the assist for the impl def case
91fn generate_impl_def_assist( 104fn generate_impl_def_assist(
92 acc: &mut Assists, 105 acc: &mut Assists,
93 impl_def: &ast::Impl, 106 impl_def: ast::Impl,
94 lifetime_loc: TextRange, 107 lifetime_loc: TextRange,
108 lifetime: ast::Lifetime,
95) -> Option<()> { 109) -> Option<()> {
96 let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.generic_param_list())?; 110 let new_lifetime_param = generate_unique_lifetime_param_name(impl_def.generic_param_list())?;
97 let end_of_impl_kw = impl_def.impl_token()?.text_range().end();
98 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| { 111 acc.add(AssistId(ASSIST_NAME, AssistKind::Refactor), ASSIST_LABEL, lifetime_loc, |builder| {
99 add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); 112 let impl_def = builder.make_ast_mut(impl_def);
100 builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); 113 let lifetime = builder.make_ast_mut(lifetime);
114
115 add_lifetime_param(impl_def.get_or_create_generic_param_list(), new_lifetime_param);
116 ted::replace(
117 lifetime.syntax(),
118 make_ast_lifetime(new_lifetime_param).clone_for_update().syntax(),
119 );
101 }) 120 })
102} 121}
103 122
104/// Given a type parameter list, generate a unique lifetime parameter name 123/// Given a type parameter list, generate a unique lifetime parameter name
105/// which is not in the list 124/// which is not in the list
106fn generate_unique_lifetime_param_name( 125fn generate_unique_lifetime_param_name(
107 existing_type_param_list: &Option<ast::GenericParamList>, 126 existing_type_param_list: Option<ast::GenericParamList>,
108) -> Option<char> { 127) -> Option<char> {
109 match existing_type_param_list { 128 match existing_type_param_list {
110 Some(type_params) => { 129 Some(type_params) => {
@@ -118,25 +137,37 @@ fn generate_unique_lifetime_param_name(
118 } 137 }
119} 138}
120 139
121/// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise 140fn add_lifetime_param(type_params: ast::GenericParamList, new_lifetime_param: char) {
122/// add new type params brackets with the lifetime parameter at `new_type_params_loc`. 141 let generic_param =
123fn add_lifetime_param<TypeParamsOwner: ast::GenericParamsOwner>( 142 make::generic_param(format!("'{}", new_lifetime_param), None).clone_for_update();
124 type_params_owner: &TypeParamsOwner, 143 type_params.add_generic_param(generic_param);
125 builder: &mut AssistBuilder, 144}
126 new_type_params_loc: TextSize, 145
127 new_lifetime_param: char, 146fn make_ast_lifetime(new_lifetime_param: char) -> ast::Lifetime {
128) { 147 make::generic_param(format!("'{}", new_lifetime_param), None)
129 match type_params_owner.generic_param_list() { 148 .syntax()
130 // add the new lifetime parameter to an existing type param list 149 .descendants()
131 Some(type_params) => { 150 .find_map(ast::Lifetime::cast)
132 builder.insert( 151 .unwrap()
133 (u32::from(type_params.syntax().text_range().end()) - 1).into(), 152}
134 format!(", '{}", new_lifetime_param), 153
135 ); 154enum NeedsLifetime {
155 SelfParam(ast::SelfParam),
156 RefType(ast::RefType),
157}
158
159impl NeedsLifetime {
160 fn make_mut(self, builder: &mut AssistBuilder) -> Self {
161 match self {
162 Self::SelfParam(it) => Self::SelfParam(builder.make_ast_mut(it)),
163 Self::RefType(it) => Self::RefType(builder.make_ast_mut(it)),
136 } 164 }
137 // create a new type param list containing only the new lifetime parameter 165 }
138 None => { 166
139 builder.insert(new_type_params_loc, format!("<'{}>", new_lifetime_param)); 167 fn to_position(self) -> Option<Position> {
168 match self {
169 Self::SelfParam(it) => Some(Position::after(it.amp_token()?)),
170 Self::RefType(it) => Some(Position::after(it.amp_token()?)),
140 } 171 }
141 } 172 }
142} 173}
@@ -312,4 +343,13 @@ mod tests {
312 r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, 343 r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#,
313 ); 344 );
314 } 345 }
346
347 #[test]
348 fn test_function_add_lifetime_to_self_ref_mut() {
349 check_assist(
350 introduce_named_lifetime,
351 r#"fn foo(&mut self) -> &'_$0 ()"#,
352 r#"fn foo<'a>(&'a mut self) -> &'a ()"#,
353 );
354 }
315} 355}
diff --git a/crates/ide_assists/src/handlers/remove_dbg.rs b/crates/ide_assists/src/handlers/remove_dbg.rs
index 6114091f2..c8226550f 100644
--- a/crates/ide_assists/src/handlers/remove_dbg.rs
+++ b/crates/ide_assists/src/handlers/remove_dbg.rs
@@ -1,5 +1,5 @@
1use syntax::{ 1use syntax::{
2 ast::{self, AstNode}, 2 ast::{self, AstNode, AstToken},
3 match_ast, SyntaxElement, TextRange, TextSize, T, 3 match_ast, SyntaxElement, TextRange, TextSize, T,
4}; 4};
5 5
@@ -24,7 +24,39 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?; 24 let macro_call = ctx.find_node_at_offset::<ast::MacroCall>()?;
25 let new_contents = adjusted_macro_contents(&macro_call)?; 25 let new_contents = adjusted_macro_contents(&macro_call)?;
26 26
27 let macro_text_range = macro_call.syntax().text_range(); 27 let parent = macro_call.syntax().parent();
28
29 let macro_text_range = if let Some(it) = parent.as_ref() {
30 if new_contents.is_empty() {
31 match_ast! {
32 match it {
33 ast::BlockExpr(_it) => {
34 macro_call.syntax()
35 .prev_sibling_or_token()
36 .and_then(whitespace_start)
37 .map(|start| TextRange::new(start, macro_call.syntax().text_range().end()))
38 .unwrap_or(macro_call.syntax().text_range())
39 },
40 ast::ExprStmt(it) => {
41 let start = it
42 .syntax()
43 .prev_sibling_or_token()
44 .and_then(whitespace_start)
45 .unwrap_or(it.syntax().text_range().start());
46 let end = it.syntax().text_range().end();
47
48 TextRange::new(start, end)
49 },
50 _ => macro_call.syntax().text_range()
51 }
52 }
53 } else {
54 macro_call.syntax().text_range()
55 }
56 } else {
57 macro_call.syntax().text_range()
58 };
59
28 let macro_end = if macro_call.semicolon_token().is_some() { 60 let macro_end = if macro_call.semicolon_token().is_some() {
29 macro_text_range.end() - TextSize::of(';') 61 macro_text_range.end() - TextSize::of(';')
30 } else { 62 } else {
@@ -36,11 +68,22 @@ pub(crate) fn remove_dbg(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
36 "Remove dbg!()", 68 "Remove dbg!()",
37 macro_text_range, 69 macro_text_range,
38 |builder| { 70 |builder| {
39 builder.replace(TextRange::new(macro_text_range.start(), macro_end), new_contents); 71 builder.replace(
72 TextRange::new(macro_text_range.start(), macro_end),
73 if new_contents.is_empty() && parent.and_then(ast::LetStmt::cast).is_some() {
74 ast::make::expr_unit().to_string()
75 } else {
76 new_contents
77 },
78 );
40 }, 79 },
41 ) 80 )
42} 81}
43 82
83fn whitespace_start(it: SyntaxElement) -> Option<TextSize> {
84 Some(it.into_token().and_then(ast::Whitespace::cast)?.syntax().text_range().start())
85}
86
44fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> { 87fn adjusted_macro_contents(macro_call: &ast::MacroCall) -> Option<String> {
45 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?; 88 let contents = get_valid_macrocall_contents(&macro_call, "dbg")?;
46 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text(); 89 let macro_text_with_brackets = macro_call.token_tree()?.syntax().text();
@@ -94,15 +137,11 @@ fn get_valid_macrocall_contents(
94 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>(); 137 let mut contents_between_brackets = children_with_tokens.collect::<Vec<_>>();
95 let last_child = contents_between_brackets.pop()?; 138 let last_child = contents_between_brackets.pop()?;
96 139
97 if contents_between_brackets.is_empty() { 140 match (first_child.kind(), last_child.kind()) {
98 None 141 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
99 } else { 142 Some(contents_between_brackets)
100 match (first_child.kind(), last_child.kind()) {
101 (T!['('], T![')']) | (T!['['], T![']']) | (T!['{'], T!['}']) => {
102 Some(contents_between_brackets)
103 }
104 _ => None,
105 } 143 }
144 _ => None,
106 } 145 }
107} 146}
108 147
@@ -418,4 +457,48 @@ fn main() {
418}"#, 457}"#,
419 ); 458 );
420 } 459 }
460
461 #[test]
462 fn test_remove_empty_dbg() {
463 check_assist(remove_dbg, r#"fn foo() { $0dbg!(); }"#, r#"fn foo() { }"#);
464 check_assist(
465 remove_dbg,
466 r#"
467fn foo() {
468 $0dbg!();
469}
470"#,
471 r#"
472fn foo() {
473}
474"#,
475 );
476 check_assist(
477 remove_dbg,
478 r#"
479fn foo() {
480 let test = $0dbg!();
481}"#,
482 r#"
483fn foo() {
484 let test = ();
485}"#,
486 );
487 check_assist(
488 remove_dbg,
489 r#"
490fn foo() {
491 let t = {
492 println!("Hello, world");
493 $0dbg!()
494 };
495}"#,
496 r#"
497fn foo() {
498 let t = {
499 println!("Hello, world");
500 };
501}"#,
502 );
503 }
421} 504}
diff --git a/crates/ide_assists/src/handlers/reorder_fields.rs b/crates/ide_assists/src/handlers/reorder_fields.rs
index 383ca6c47..1a95135ca 100644
--- a/crates/ide_assists/src/handlers/reorder_fields.rs
+++ b/crates/ide_assists/src/handlers/reorder_fields.rs
@@ -1,6 +1,8 @@
1use either::Either;
2use itertools::Itertools;
1use rustc_hash::FxHashMap; 3use rustc_hash::FxHashMap;
2 4
3use syntax::{algo, ast, match_ast, AstNode, SyntaxKind::*, SyntaxNode}; 5use syntax::{ast, ted, AstNode};
4 6
5use crate::{AssistContext, AssistId, AssistKind, Assists}; 7use crate::{AssistContext, AssistId, AssistKind, Assists};
6 8
@@ -22,60 +24,70 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
22pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { 24pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
23 let record = ctx 25 let record = ctx
24 .find_node_at_offset::<ast::RecordExpr>() 26 .find_node_at_offset::<ast::RecordExpr>()
25 .map(|it| it.syntax().clone()) 27 .map(Either::Left)
26 .or_else(|| ctx.find_node_at_offset::<ast::RecordPat>().map(|it| it.syntax().clone()))?; 28 .or_else(|| ctx.find_node_at_offset::<ast::RecordPat>().map(Either::Right))?;
27
28 let path = record.children().find_map(ast::Path::cast)?;
29 29
30 let path = record.as_ref().either(|it| it.path(), |it| it.path())?;
30 let ranks = compute_fields_ranks(&path, &ctx)?; 31 let ranks = compute_fields_ranks(&path, &ctx)?;
32 let get_rank_of_field =
33 |of: Option<_>| *ranks.get(&of.unwrap_or_default()).unwrap_or(&usize::MAX);
31 34
32 let fields: Vec<SyntaxNode> = { 35 let field_list = match &record {
33 let field_kind = match record.kind() { 36 Either::Left(it) => Either::Left(it.record_expr_field_list()?),
34 RECORD_EXPR => RECORD_EXPR_FIELD, 37 Either::Right(it) => Either::Right(it.record_pat_field_list()?),
35 RECORD_PAT => RECORD_PAT_FIELD,
36 _ => {
37 stdx::never!();
38 return None;
39 }
40 };
41 record.children().flat_map(|n| n.children()).filter(|n| n.kind() == field_kind).collect()
42 }; 38 };
43 39 let fields = match field_list {
44 let sorted_fields = { 40 Either::Left(it) => Either::Left((
45 let mut fields = fields.clone(); 41 it.fields()
46 fields.sort_by_key(|node| *ranks.get(&get_field_name(node)).unwrap_or(&usize::max_value())); 42 .sorted_unstable_by_key(|field| {
47 fields 43 get_rank_of_field(field.field_name().map(|it| it.to_string()))
44 })
45 .collect::<Vec<_>>(),
46 it,
47 )),
48 Either::Right(it) => Either::Right((
49 it.fields()
50 .sorted_unstable_by_key(|field| {
51 get_rank_of_field(field.field_name().map(|it| it.to_string()))
52 })
53 .collect::<Vec<_>>(),
54 it,
55 )),
48 }; 56 };
49 57
50 if sorted_fields == fields { 58 let is_sorted = fields.as_ref().either(
59 |(sorted, field_list)| field_list.fields().zip(sorted).all(|(a, b)| a == *b),
60 |(sorted, field_list)| field_list.fields().zip(sorted).all(|(a, b)| a == *b),
61 );
62 if is_sorted {
51 cov_mark::hit!(reorder_sorted_fields); 63 cov_mark::hit!(reorder_sorted_fields);
52 return None; 64 return None;
53 } 65 }
54 66 let target = record.as_ref().either(AstNode::syntax, AstNode::syntax).text_range();
55 let target = record.text_range();
56 acc.add( 67 acc.add(
57 AssistId("reorder_fields", AssistKind::RefactorRewrite), 68 AssistId("reorder_fields", AssistKind::RefactorRewrite),
58 "Reorder record fields", 69 "Reorder record fields",
59 target, 70 target,
60 |edit| { 71 |builder| match fields {
61 let mut rewriter = algo::SyntaxRewriter::default(); 72 Either::Left((sorted, field_list)) => {
62 for (old, new) in fields.iter().zip(&sorted_fields) { 73 replace(builder.make_ast_mut(field_list).fields(), sorted)
63 rewriter.replace(old, new); 74 }
75 Either::Right((sorted, field_list)) => {
76 replace(builder.make_ast_mut(field_list).fields(), sorted)
64 } 77 }
65 edit.rewrite(rewriter);
66 }, 78 },
67 ) 79 )
68} 80}
69 81
70fn get_field_name(node: &SyntaxNode) -> String { 82fn replace<T: AstNode + PartialEq>(
71 let res = match_ast! { 83 fields: impl Iterator<Item = T>,
72 match node { 84 sorted_fields: impl IntoIterator<Item = T>,
73 ast::RecordExprField(field) => field.field_name().map(|it| it.to_string()), 85) {
74 ast::RecordPatField(field) => field.field_name().map(|it| it.to_string()), 86 fields.zip(sorted_fields).filter(|(field, sorted)| field != sorted).for_each(
75 _ => None, 87 |(field, sorted_field)| {
76 } 88 ted::replace(field.syntax(), sorted_field.syntax().clone_for_update());
77 }; 89 },
78 res.unwrap_or_default() 90 );
79} 91}
80 92
81fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> { 93fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashMap<String, usize>> {
@@ -86,7 +98,7 @@ fn compute_fields_ranks(path: &ast::Path, ctx: &AssistContext) -> Option<FxHashM
86 98
87 let res = strukt 99 let res = strukt
88 .fields(ctx.db()) 100 .fields(ctx.db())
89 .iter() 101 .into_iter()
90 .enumerate() 102 .enumerate()
91 .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx)) 103 .map(|(idx, field)| (field.name(ctx.db()).to_string(), idx))
92 .collect(); 104 .collect();
@@ -137,7 +149,6 @@ const test: Foo = Foo { foo: 1, bar: 0 };
137"#, 149"#,
138 ) 150 )
139 } 151 }
140
141 #[test] 152 #[test]
142 fn reorder_struct_pattern() { 153 fn reorder_struct_pattern() {
143 check_assist( 154 check_assist(
diff --git a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
index f872d20c8..694d897d1 100644
--- a/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide_assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -5,7 +5,6 @@ use itertools::Itertools;
5use syntax::{ 5use syntax::{
6 ast::{self, make, AstNode, NameOwner}, 6 ast::{self, make, AstNode, NameOwner},
7 SyntaxKind::{IDENT, WHITESPACE}, 7 SyntaxKind::{IDENT, WHITESPACE},
8 TextSize,
9}; 8};
10 9
11use crate::{ 10use crate::{
@@ -43,32 +42,28 @@ pub(crate) fn replace_derive_with_manual_impl(
43 ctx: &AssistContext, 42 ctx: &AssistContext,
44) -> Option<()> { 43) -> Option<()> {
45 let attr = ctx.find_node_at_offset::<ast::Attr>()?; 44 let attr = ctx.find_node_at_offset::<ast::Attr>()?;
45 let (name, args) = attr.as_simple_call()?;
46 if name != "derive" {
47 return None;
48 }
46 49
47 let has_derive = attr 50 if !args.syntax().text_range().contains(ctx.offset()) {
48 .syntax() 51 cov_mark::hit!(outside_of_attr_args);
49 .descendants_with_tokens()
50 .filter(|t| t.kind() == IDENT)
51 .find_map(syntax::NodeOrToken::into_token)
52 .filter(|t| t.text() == "derive")
53 .is_some();
54 if !has_derive {
55 return None; 52 return None;
56 } 53 }
57 54
58 let trait_token = ctx.token_at_offset().find(|t| t.kind() == IDENT && t.text() != "derive")?; 55 let trait_token = args.syntax().token_at_offset(ctx.offset()).find(|t| t.kind() == IDENT)?;
59 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_token.text()))); 56 let trait_name = trait_token.text();
60 57
61 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?; 58 let adt = attr.syntax().parent().and_then(ast::Adt::cast)?;
62 let annotated_name = adt.name()?;
63 let insert_pos = adt.syntax().text_range().end();
64 59
65 let current_module = ctx.sema.scope(annotated_name.syntax()).module()?; 60 let current_module = ctx.sema.scope(adt.syntax()).module()?;
66 let current_crate = current_module.krate(); 61 let current_crate = current_module.krate();
67 62
68 let found_traits = items_locator::items_with_name( 63 let found_traits = items_locator::items_with_name(
69 &ctx.sema, 64 &ctx.sema,
70 current_crate, 65 current_crate,
71 NameToImport::Exact(trait_token.text().to_string()), 66 NameToImport::Exact(trait_name.to_string()),
72 items_locator::AssocItemSearch::Exclude, 67 items_locator::AssocItemSearch::Exclude,
73 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT), 68 Some(items_locator::DEFAULT_QUERY_SEARCH_LIMIT),
74 ) 69 )
@@ -86,10 +81,11 @@ pub(crate) fn replace_derive_with_manual_impl(
86 81
87 let mut no_traits_found = true; 82 let mut no_traits_found = true;
88 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) { 83 for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
89 add_assist(acc, ctx, &attr, &trait_path, Some(trait_), &adt, &annotated_name, insert_pos)?; 84 add_assist(acc, ctx, &attr, &args, &trait_path, Some(trait_), &adt)?;
90 } 85 }
91 if no_traits_found { 86 if no_traits_found {
92 add_assist(acc, ctx, &attr, &trait_path, None, &adt, &annotated_name, insert_pos)?; 87 let trait_path = make::path_unqualified(make::path_segment(make::name_ref(trait_name)));
88 add_assist(acc, ctx, &attr, &args, &trait_path, None, &adt)?;
93 } 89 }
94 Some(()) 90 Some(())
95} 91}
@@ -98,15 +94,14 @@ fn add_assist(
98 acc: &mut Assists, 94 acc: &mut Assists,
99 ctx: &AssistContext, 95 ctx: &AssistContext,
100 attr: &ast::Attr, 96 attr: &ast::Attr,
97 input: &ast::TokenTree,
101 trait_path: &ast::Path, 98 trait_path: &ast::Path,
102 trait_: Option<hir::Trait>, 99 trait_: Option<hir::Trait>,
103 adt: &ast::Adt, 100 adt: &ast::Adt,
104 annotated_name: &ast::Name,
105 insert_pos: TextSize,
106) -> Option<()> { 101) -> Option<()> {
107 let target = attr.syntax().text_range(); 102 let target = attr.syntax().text_range();
108 let input = attr.token_tree()?; 103 let annotated_name = adt.name()?;
109 let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name); 104 let label = format!("Convert to manual `impl {} for {}`", trait_path, annotated_name);
110 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?; 105 let trait_name = trait_path.segment().and_then(|seg| seg.name_ref())?;
111 106
112 acc.add( 107 acc.add(
@@ -114,8 +109,9 @@ fn add_assist(
114 label, 109 label,
115 target, 110 target,
116 |builder| { 111 |builder| {
112 let insert_pos = adt.syntax().text_range().end();
117 let impl_def_with_items = 113 let impl_def_with_items =
118 impl_def_from_trait(&ctx.sema, annotated_name, trait_, trait_path); 114 impl_def_from_trait(&ctx.sema, &annotated_name, trait_, trait_path);
119 update_attribute(builder, &input, &trait_name, &attr); 115 update_attribute(builder, &input, &trait_name, &attr);
120 let trait_path = format!("{}", trait_path); 116 let trait_path = format!("{}", trait_path);
121 match (ctx.config.snippet_cap, impl_def_with_items) { 117 match (ctx.config.snippet_cap, impl_def_with_items) {
@@ -216,7 +212,7 @@ mod tests {
216 fn add_custom_impl_debug() { 212 fn add_custom_impl_debug() {
217 check_assist( 213 check_assist(
218 replace_derive_with_manual_impl, 214 replace_derive_with_manual_impl,
219 " 215 r#"
220mod fmt { 216mod fmt {
221 pub struct Error; 217 pub struct Error;
222 pub type Result = Result<(), Error>; 218 pub type Result = Result<(), Error>;
@@ -230,8 +226,8 @@ mod fmt {
230struct Foo { 226struct Foo {
231 bar: String, 227 bar: String,
232} 228}
233", 229"#,
234 " 230 r#"
235mod fmt { 231mod fmt {
236 pub struct Error; 232 pub struct Error;
237 pub type Result = Result<(), Error>; 233 pub type Result = Result<(), Error>;
@@ -250,14 +246,14 @@ impl fmt::Debug for Foo {
250 ${0:todo!()} 246 ${0:todo!()}
251 } 247 }
252} 248}
253", 249"#,
254 ) 250 )
255 } 251 }
256 #[test] 252 #[test]
257 fn add_custom_impl_all() { 253 fn add_custom_impl_all() {
258 check_assist( 254 check_assist(
259 replace_derive_with_manual_impl, 255 replace_derive_with_manual_impl,
260 " 256 r#"
261mod foo { 257mod foo {
262 pub trait Bar { 258 pub trait Bar {
263 type Qux; 259 type Qux;
@@ -272,8 +268,8 @@ mod foo {
272struct Foo { 268struct Foo {
273 bar: String, 269 bar: String,
274} 270}
275", 271"#,
276 " 272 r#"
277mod foo { 273mod foo {
278 pub trait Bar { 274 pub trait Bar {
279 type Qux; 275 type Qux;
@@ -299,20 +295,20 @@ impl foo::Bar for Foo {
299 todo!() 295 todo!()
300 } 296 }
301} 297}
302", 298"#,
303 ) 299 )
304 } 300 }
305 #[test] 301 #[test]
306 fn add_custom_impl_for_unique_input() { 302 fn add_custom_impl_for_unique_input() {
307 check_assist( 303 check_assist(
308 replace_derive_with_manual_impl, 304 replace_derive_with_manual_impl,
309 " 305 r#"
310#[derive(Debu$0g)] 306#[derive(Debu$0g)]
311struct Foo { 307struct Foo {
312 bar: String, 308 bar: String,
313} 309}
314 ", 310 "#,
315 " 311 r#"
316struct Foo { 312struct Foo {
317 bar: String, 313 bar: String,
318} 314}
@@ -320,7 +316,7 @@ struct Foo {
320impl Debug for Foo { 316impl Debug for Foo {
321 $0 317 $0
322} 318}
323 ", 319 "#,
324 ) 320 )
325 } 321 }
326 322
@@ -328,13 +324,13 @@ impl Debug for Foo {
328 fn add_custom_impl_for_with_visibility_modifier() { 324 fn add_custom_impl_for_with_visibility_modifier() {
329 check_assist( 325 check_assist(
330 replace_derive_with_manual_impl, 326 replace_derive_with_manual_impl,
331 " 327 r#"
332#[derive(Debug$0)] 328#[derive(Debug$0)]
333pub struct Foo { 329pub struct Foo {
334 bar: String, 330 bar: String,
335} 331}
336 ", 332 "#,
337 " 333 r#"
338pub struct Foo { 334pub struct Foo {
339 bar: String, 335 bar: String,
340} 336}
@@ -342,7 +338,7 @@ pub struct Foo {
342impl Debug for Foo { 338impl Debug for Foo {
343 $0 339 $0
344} 340}
345 ", 341 "#,
346 ) 342 )
347 } 343 }
348 344
@@ -350,18 +346,18 @@ impl Debug for Foo {
350 fn add_custom_impl_when_multiple_inputs() { 346 fn add_custom_impl_when_multiple_inputs() {
351 check_assist( 347 check_assist(
352 replace_derive_with_manual_impl, 348 replace_derive_with_manual_impl,
353 " 349 r#"
354#[derive(Display, Debug$0, Serialize)] 350#[derive(Display, Debug$0, Serialize)]
355struct Foo {} 351struct Foo {}
356 ", 352 "#,
357 " 353 r#"
358#[derive(Display, Serialize)] 354#[derive(Display, Serialize)]
359struct Foo {} 355struct Foo {}
360 356
361impl Debug for Foo { 357impl Debug for Foo {
362 $0 358 $0
363} 359}
364 ", 360 "#,
365 ) 361 )
366 } 362 }
367 363
@@ -369,10 +365,10 @@ impl Debug for Foo {
369 fn test_ignore_derive_macro_without_input() { 365 fn test_ignore_derive_macro_without_input() {
370 check_assist_not_applicable( 366 check_assist_not_applicable(
371 replace_derive_with_manual_impl, 367 replace_derive_with_manual_impl,
372 " 368 r#"
373#[derive($0)] 369#[derive($0)]
374struct Foo {} 370struct Foo {}
375 ", 371 "#,
376 ) 372 )
377 } 373 }
378 374
@@ -380,18 +376,18 @@ struct Foo {}
380 fn test_ignore_if_cursor_on_param() { 376 fn test_ignore_if_cursor_on_param() {
381 check_assist_not_applicable( 377 check_assist_not_applicable(
382 replace_derive_with_manual_impl, 378 replace_derive_with_manual_impl,
383 " 379 r#"
384#[derive$0(Debug)] 380#[derive$0(Debug)]
385struct Foo {} 381struct Foo {}
386 ", 382 "#,
387 ); 383 );
388 384
389 check_assist_not_applicable( 385 check_assist_not_applicable(
390 replace_derive_with_manual_impl, 386 replace_derive_with_manual_impl,
391 " 387 r#"
392#[derive(Debug)$0] 388#[derive(Debug)$0]
393struct Foo {} 389struct Foo {}
394 ", 390 "#,
395 ) 391 )
396 } 392 }
397 393
@@ -399,10 +395,22 @@ struct Foo {}
399 fn test_ignore_if_not_derive() { 395 fn test_ignore_if_not_derive() {
400 check_assist_not_applicable( 396 check_assist_not_applicable(
401 replace_derive_with_manual_impl, 397 replace_derive_with_manual_impl,
402 " 398 r#"
403#[allow(non_camel_$0case_types)] 399#[allow(non_camel_$0case_types)]
404struct Foo {} 400struct Foo {}
405 ", 401 "#,
406 ) 402 )
407 } 403 }
404
405 #[test]
406 fn works_at_start_of_file() {
407 cov_mark::check!(outside_of_attr_args);
408 check_assist_not_applicable(
409 replace_derive_with_manual_impl,
410 r#"
411$0#[derive(Debug)]
412struct S;
413 "#,
414 );
415 }
408} 416}
diff --git a/crates/ide_assists/src/lib.rs b/crates/ide_assists/src/lib.rs
index 1c55b9fbf..88ae5c9a9 100644
--- a/crates/ide_assists/src/lib.rs
+++ b/crates/ide_assists/src/lib.rs
@@ -28,7 +28,9 @@ pub use assist_config::AssistConfig;
28 28
29#[derive(Debug, Clone, Copy, PartialEq, Eq)] 29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub enum AssistKind { 30pub enum AssistKind {
31 // FIXME: does the None variant make sense? Probably not.
31 None, 32 None,
33
32 QuickFix, 34 QuickFix,
33 Generate, 35 Generate,
34 Refactor, 36 Refactor,
@@ -133,6 +135,7 @@ mod handlers {
133 mod generate_default_from_enum_variant; 135 mod generate_default_from_enum_variant;
134 mod generate_default_from_new; 136 mod generate_default_from_new;
135 mod generate_is_empty_from_len; 137 mod generate_is_empty_from_len;
138 mod generate_deref;
136 mod generate_derive; 139 mod generate_derive;
137 mod generate_enum_is_method; 140 mod generate_enum_is_method;
138 mod generate_enum_projection_method; 141 mod generate_enum_projection_method;
@@ -201,6 +204,7 @@ mod handlers {
201 generate_default_from_enum_variant::generate_default_from_enum_variant, 204 generate_default_from_enum_variant::generate_default_from_enum_variant,
202 generate_default_from_new::generate_default_from_new, 205 generate_default_from_new::generate_default_from_new,
203 generate_is_empty_from_len::generate_is_empty_from_len, 206 generate_is_empty_from_len::generate_is_empty_from_len,
207 generate_deref::generate_deref,
204 generate_derive::generate_derive, 208 generate_derive::generate_derive,
205 generate_enum_is_method::generate_enum_is_method, 209 generate_enum_is_method::generate_enum_is_method,
206 generate_enum_projection_method::generate_enum_as_method, 210 generate_enum_projection_method::generate_enum_as_method,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index a7a923beb..49533e7d2 100644
--- a/crates/ide_assists/src/tests.rs
+++ b/crates/ide_assists/src/tests.rs
@@ -84,7 +84,8 @@ fn check_doc_test(assist_id: &str, before: &str, after: &str) {
84 }); 84 });
85 85
86 let actual = { 86 let actual = {
87 let source_change = assist.source_change.unwrap(); 87 let source_change =
88 assist.source_change.expect("Assist did not contain any source changes");
88 let mut actual = before; 89 let mut actual = before;
89 if let Some(source_file_edit) = source_change.get_source_edit(file_id) { 90 if let Some(source_file_edit) = source_change.get_source_edit(file_id) {
90 source_file_edit.apply(&mut actual); 91 source_file_edit.apply(&mut actual);
@@ -121,7 +122,8 @@ fn check(handler: Handler, before: &str, expected: ExpectedResult, assist_label:
121 122
122 match (assist, expected) { 123 match (assist, expected) {
123 (Some(assist), ExpectedResult::After(after)) => { 124 (Some(assist), ExpectedResult::After(after)) => {
124 let source_change = assist.source_change.unwrap(); 125 let source_change =
126 assist.source_change.expect("Assist did not contain any source changes");
125 assert!(!source_change.source_file_edits.is_empty()); 127 assert!(!source_change.source_file_edits.is_empty());
126 let skip_header = source_change.source_file_edits.len() == 1 128 let skip_header = source_change.source_file_edits.len() == 1
127 && source_change.file_system_edits.len() == 0; 129 && source_change.file_system_edits.len() == 0;
@@ -191,6 +193,7 @@ fn assist_order_field_struct() {
191 let mut assists = assists.iter(); 193 let mut assists = assists.iter();
192 194
193 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)"); 195 assert_eq!(assists.next().expect("expected assist").label, "Change visibility to pub(crate)");
196 assert_eq!(assists.next().expect("expected assist").label, "Generate `Deref` impl using `bar`");
194 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method"); 197 assert_eq!(assists.next().expect("expected assist").label, "Generate a mut getter method");
195 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method"); 198 assert_eq!(assists.next().expect("expected assist").label, "Generate a getter method");
196 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method"); 199 assert_eq!(assists.next().expect("expected assist").label, "Generate a setter method");
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index f4a4749c8..59bcef8fb 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -593,6 +593,33 @@ impl Default for Example {
593} 593}
594 594
595#[test] 595#[test]
596fn doctest_generate_deref() {
597 check_doc_test(
598 "generate_deref",
599 r#####"
600struct A;
601struct B {
602 $0a: A
603}
604"#####,
605 r#####"
606struct A;
607struct B {
608 a: A
609}
610
611impl std::ops::Deref for B {
612 type Target = A;
613
614 fn deref(&self) -> &Self::Target {
615 &self.a
616 }
617}
618"#####,
619 )
620}
621
622#[test]
596fn doctest_generate_derive() { 623fn doctest_generate_derive() {
597 check_doc_test( 624 check_doc_test(
598 "generate_derive", 625 "generate_derive",
diff --git a/crates/ide_completion/src/completions/flyimport.rs b/crates/ide_completion/src/completions/flyimport.rs
index 1ad017198..8e211ae1e 100644
--- a/crates/ide_completion/src/completions/flyimport.rs
+++ b/crates/ide_completion/src/completions/flyimport.rs
@@ -113,6 +113,9 @@ pub(crate) fn import_on_the_fly(acc: &mut Completions, ctx: &CompletionContext)
113 if ctx.use_item_syntax.is_some() 113 if ctx.use_item_syntax.is_some()
114 || ctx.attribute_under_caret.is_some() 114 || ctx.attribute_under_caret.is_some()
115 || ctx.mod_declaration_under_caret.is_some() 115 || ctx.mod_declaration_under_caret.is_some()
116 || ctx.record_lit_syntax.is_some()
117 || ctx.has_trait_parent
118 || ctx.has_impl_parent
116 { 119 {
117 return None; 120 return None;
118 } 121 }
@@ -1034,4 +1037,117 @@ fn main() {
1034 expect![[]], 1037 expect![[]],
1035 ); 1038 );
1036 } 1039 }
1040
1041 #[test]
1042 fn no_fuzzy_during_fields_of_record_lit_syntax() {
1043 check(
1044 r#"
1045mod m {
1046 pub fn some_fn() -> i32 {
1047 42
1048 }
1049}
1050struct Foo {
1051 some_field: i32,
1052}
1053fn main() {
1054 let _ = Foo { so$0 };
1055}
1056"#,
1057 expect![[]],
1058 );
1059 }
1060
1061 #[test]
1062 fn fuzzy_after_fields_of_record_lit_syntax() {
1063 check(
1064 r#"
1065mod m {
1066 pub fn some_fn() -> i32 {
1067 42
1068 }
1069}
1070struct Foo {
1071 some_field: i32,
1072}
1073fn main() {
1074 let _ = Foo { some_field: so$0 };
1075}
1076"#,
1077 expect![[r#"
1078 fn some_fn() (m::some_fn) fn() -> i32
1079 "#]],
1080 );
1081 }
1082
1083 #[test]
1084 fn no_flyimports_in_traits_and_impl_declarations() {
1085 check(
1086 r#"
1087mod m {
1088 pub fn some_fn() -> i32 {
1089 42
1090 }
1091}
1092trait Foo {
1093 som$0
1094}
1095"#,
1096 expect![[r#""#]],
1097 );
1098
1099 check(
1100 r#"
1101mod m {
1102 pub fn some_fn() -> i32 {
1103 42
1104 }
1105}
1106struct Foo;
1107impl Foo {
1108 som$0
1109}
1110"#,
1111 expect![[r#""#]],
1112 );
1113
1114 check(
1115 r#"
1116mod m {
1117 pub fn some_fn() -> i32 {
1118 42
1119 }
1120}
1121struct Foo;
1122trait Bar {}
1123impl Bar for Foo {
1124 som$0
1125}
1126"#,
1127 expect![[r#""#]],
1128 );
1129 }
1130
1131 #[test]
1132 fn no_inherent_candidates_proposed() {
1133 check(
1134 r#"
1135mod baz {
1136 pub trait DefDatabase {
1137 fn method1(&self);
1138 }
1139 pub trait HirDatabase: DefDatabase {
1140 fn method2(&self);
1141 }
1142}
1143
1144mod bar {
1145 fn test(db: &dyn crate::baz::HirDatabase) {
1146 db.metho$0
1147 }
1148}
1149 "#,
1150 expect![[r#""#]],
1151 );
1152 }
1037} 1153}
diff --git a/crates/ide_completion/src/item.rs b/crates/ide_completion/src/item.rs
index cc4ac9ea2..16991b688 100644
--- a/crates/ide_completion/src/item.rs
+++ b/crates/ide_completion/src/item.rs
@@ -29,7 +29,7 @@ pub struct CompletionItem {
29 /// Range of identifier that is being completed. 29 /// Range of identifier that is being completed.
30 /// 30 ///
31 /// It should be used primarily for UI, but we also use this to convert 31 /// It should be used primarily for UI, but we also use this to convert
32 /// genetic TextEdit into LSP's completion edit (see conv.rs). 32 /// generic TextEdit into LSP's completion edit (see conv.rs).
33 /// 33 ///
34 /// `source_range` must contain the completion offset. `insert_text` should 34 /// `source_range` must contain the completion offset. `insert_text` should
35 /// start with what `source_range` points to, or VSCode will filter out the 35 /// start with what `source_range` points to, or VSCode will filter out the
diff --git a/crates/ide_completion/src/lib.rs b/crates/ide_completion/src/lib.rs
index 831d543bb..6f3d5c5c5 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -106,6 +106,34 @@ pub use crate::{
106/// `foo` *should* be present among the completion variants. Filtering by 106/// `foo` *should* be present among the completion variants. Filtering by
107/// identifier prefix/fuzzy match should be done higher in the stack, together 107/// identifier prefix/fuzzy match should be done higher in the stack, together
108/// with ordering of completions (currently this is done by the client). 108/// with ordering of completions (currently this is done by the client).
109///
110/// # Hypothetical Completion Problem
111///
112/// There's a curious unsolved problem in the current implementation. Often, you
113/// want to compute completions on a *slightly different* text document.
114///
115/// In the simplest case, when the code looks like `let x = `, you want to
116/// insert a fake identifier to get a better syntax tree: `let x = complete_me`.
117///
118/// We do this in `CompletionContext`, and it works OK-enough for *syntax*
119/// analysis. However, we might want to, eg, ask for the type of `complete_me`
120/// variable, and that's where our current infrastructure breaks down. salsa
121/// doesn't allow such "phantom" inputs.
122///
123/// Another case where this would be instrumental is macro expansion. We want to
124/// insert a fake ident and re-expand code. There's `expand_hypothetical` as a
125/// work-around for this.
126///
127/// A different use-case is completion of injection (examples and links in doc
128/// comments). When computing completion for a path in a doc-comment, you want
129/// to inject a fake path expression into the item being documented and complete
130/// that.
131///
132/// IntelliJ has CodeFragment/Context infrastructure for that. You can create a
133/// temporary PSI node, and say that the context ("parent") of this node is some
134/// existing node. Asking for, eg, type of this `CodeFragment` node works
135/// correctly, as the underlying infrastructure makes use of contexts to do
136/// analysis.
109pub fn completions( 137pub fn completions(
110 db: &RootDatabase, 138 db: &RootDatabase,
111 config: &CompletionConfig, 139 config: &CompletionConfig,
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index 111e9325a..eac5ef6b9 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -152,6 +152,10 @@ impl RootDatabase {
152 hir::db::FileItemTreeQuery 152 hir::db::FileItemTreeQuery
153 hir::db::BlockDefMapQuery 153 hir::db::BlockDefMapQuery
154 hir::db::CrateDefMapQueryQuery 154 hir::db::CrateDefMapQueryQuery
155 hir::db::FieldsAttrsQuery
156 hir::db::VariantsAttrsQuery
157 hir::db::FieldsAttrsSourceMapQuery
158 hir::db::VariantsAttrsSourceMapQuery
155 hir::db::StructDataQuery 159 hir::db::StructDataQuery
156 hir::db::UnionDataQuery 160 hir::db::UnionDataQuery
157 hir::db::EnumDataQuery 161 hir::db::EnumDataQuery
@@ -197,7 +201,7 @@ impl RootDatabase {
197 hir::db::InternImplTraitIdQuery 201 hir::db::InternImplTraitIdQuery
198 hir::db::InternClosureQuery 202 hir::db::InternClosureQuery
199 hir::db::AssociatedTyValueQuery 203 hir::db::AssociatedTyValueQuery
200 hir::db::TraitSolveQuery 204 hir::db::TraitSolveQueryQuery
201 205
202 // SymbolsDatabase 206 // SymbolsDatabase
203 crate::symbol_index::FileSymbolsQuery 207 crate::symbol_index::FileSymbolsQuery
diff --git a/crates/ide_db/src/call_info.rs b/crates/ide_db/src/call_info.rs
index e583a52f4..bad277a95 100644
--- a/crates/ide_db/src/call_info.rs
+++ b/crates/ide_db/src/call_info.rs
@@ -4,8 +4,9 @@ use either::Either;
4use hir::{HasAttrs, HirDisplay, Semantics, Type}; 4use hir::{HasAttrs, HirDisplay, Semantics, Type};
5use stdx::format_to; 5use stdx::format_to;
6use syntax::{ 6use syntax::{
7 algo,
7 ast::{self, ArgListOwner, NameOwner}, 8 ast::{self, ArgListOwner, NameOwner},
8 match_ast, AstNode, SyntaxNode, SyntaxToken, TextRange, TextSize, 9 match_ast, AstNode, Direction, SyntaxNode, SyntaxToken, TextRange, TextSize,
9}; 10};
10 11
11use crate::RootDatabase; 12use crate::RootDatabase;
@@ -43,7 +44,12 @@ pub fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo>
43 let sema = Semantics::new(db); 44 let sema = Semantics::new(db);
44 let file = sema.parse(position.file_id); 45 let file = sema.parse(position.file_id);
45 let file = file.syntax(); 46 let file = file.syntax();
46 let token = file.token_at_offset(position.offset).next()?; 47 let token = file
48 .token_at_offset(position.offset)
49 .left_biased()
50 // if the cursor is sandwiched between two space tokens and the call is unclosed
51 // this prevents us from leaving the CallExpression
52 .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
47 let token = sema.descend_into_macros(token); 53 let token = sema.descend_into_macros(token);
48 54
49 let (callable, active_parameter) = call_info_impl(&sema, token)?; 55 let (callable, active_parameter) = call_info_impl(&sema, token)?;
diff --git a/crates/ide_db/src/call_info/tests.rs b/crates/ide_db/src/call_info/tests.rs
index 281a081a3..be1cc12de 100644
--- a/crates/ide_db/src/call_info/tests.rs
+++ b/crates/ide_db/src/call_info/tests.rs
@@ -522,3 +522,30 @@ fn main(f: fn(i32, f64) -> char) {
522 "#]], 522 "#]],
523 ) 523 )
524} 524}
525
526#[test]
527fn call_info_for_unclosed_call() {
528 check(
529 r#"
530fn foo(foo: u32, bar: u32) {}
531fn main() {
532 foo($0
533}"#,
534 expect![[r#"
535 fn foo(foo: u32, bar: u32)
536 (<foo: u32>, bar: u32)
537 "#]],
538 );
539 // check with surrounding space
540 check(
541 r#"
542fn foo(foo: u32, bar: u32) {}
543fn main() {
544 foo( $0
545}"#,
546 expect![[r#"
547 fn foo(foo: u32, bar: u32)
548 (<foo: u32>, bar: u32)
549 "#]],
550 )
551}
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 66798ea3a..720de0d1f 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -1,6 +1,7 @@
1//! A module with ide helpers for high-level ide features. 1//! A module with ide helpers for high-level ide features.
2pub mod insert_use; 2pub mod insert_use;
3pub mod import_assets; 3pub mod import_assets;
4pub mod rust_doc;
4 5
5use std::collections::VecDeque; 6use std::collections::VecDeque;
6 7
@@ -113,6 +114,10 @@ impl FamousDefs<'_, '_> {
113 self.find_module("core:iter") 114 self.find_module("core:iter")
114 } 115 }
115 116
117 pub fn core_ops_Deref(&self) -> Option<Trait> {
118 self.find_trait("core:ops:Deref")
119 }
120
116 fn find_trait(&self, path: &str) -> Option<Trait> { 121 fn find_trait(&self, path: &str) -> Option<Trait> {
117 match self.find_def(path)? { 122 match self.find_def(path)? {
118 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), 123 hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it),
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
index 4d79e064e..29ae12dcf 100644
--- a/crates/ide_db/src/helpers/famous_defs_fixture.rs
+++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs
@@ -112,6 +112,12 @@ pub mod ops {
112 type Output; 112 type Output;
113 extern "rust-call" fn call_once(self, args: Args) -> Self::Output; 113 extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
114 } 114 }
115
116 #[lang = "deref"]
117 pub trait Deref {
118 type Target: ?Sized;
119 fn deref(&self) -> &Self::Target;
120 }
115} 121}
116 122
117pub mod option { 123pub mod option {
@@ -141,3 +147,5 @@ mod return_keyword {}
141 147
142/// Docs for prim_str 148/// Docs for prim_str
143mod prim_str {} 149mod prim_str {}
150
151pub use core::ops; \ No newline at end of file
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 8ce648367..91d6a4665 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -436,6 +436,8 @@ fn trait_applicable_items(
436 }) 436 })
437 .collect(); 437 .collect();
438 438
439 let related_dyn_traits =
440 trait_candidate.receiver_ty.applicable_inherent_traits(db).collect::<FxHashSet<_>>();
439 let mut located_imports = FxHashSet::default(); 441 let mut located_imports = FxHashSet::default();
440 442
441 if trait_assoc_item { 443 if trait_assoc_item {
@@ -451,12 +453,16 @@ fn trait_applicable_items(
451 return None; 453 return None;
452 } 454 }
453 } 455 }
456 let located_trait = assoc.containing_trait(db)?;
457 if related_dyn_traits.contains(&located_trait) {
458 return None;
459 }
454 460
455 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); 461 let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
456 let original_item = assoc_to_item(assoc); 462 let original_item = assoc_to_item(assoc);
457 located_imports.insert(LocatedImport::new( 463 located_imports.insert(LocatedImport::new(
458 mod_path(item)?, 464 mod_path(trait_item)?,
459 item, 465 trait_item,
460 original_item, 466 original_item,
461 mod_path(original_item), 467 mod_path(original_item),
462 )); 468 ));
@@ -473,11 +479,15 @@ fn trait_applicable_items(
473 |_, function| { 479 |_, function| {
474 let assoc = function.as_assoc_item(db)?; 480 let assoc = function.as_assoc_item(db)?;
475 if required_assoc_items.contains(&assoc) { 481 if required_assoc_items.contains(&assoc) {
476 let item = ItemInNs::from(ModuleDef::from(assoc.containing_trait(db)?)); 482 let located_trait = assoc.containing_trait(db)?;
483 if related_dyn_traits.contains(&located_trait) {
484 return None;
485 }
486 let trait_item = ItemInNs::from(ModuleDef::from(located_trait));
477 let original_item = assoc_to_item(assoc); 487 let original_item = assoc_to_item(assoc);
478 located_imports.insert(LocatedImport::new( 488 located_imports.insert(LocatedImport::new(
479 mod_path(item)?, 489 mod_path(trait_item)?,
480 item, 490 trait_item,
481 original_item, 491 original_item,
482 mod_path(original_item), 492 mod_path(original_item),
483 )); 493 ));
diff --git a/crates/ide_db/src/helpers/rust_doc.rs b/crates/ide_db/src/helpers/rust_doc.rs
new file mode 100644
index 000000000..e27e23867
--- /dev/null
+++ b/crates/ide_db/src/helpers/rust_doc.rs
@@ -0,0 +1,34 @@
1//! Rustdoc specific doc comment handling
2
3// stripped down version of https://github.com/rust-lang/rust/blob/392ba2ba1a7d6c542d2459fb8133bebf62a4a423/src/librustdoc/html/markdown.rs#L810-L933
4pub fn is_rust_fence(s: &str) -> bool {
5 let mut seen_rust_tags = false;
6 let mut seen_other_tags = false;
7
8 let tokens = s
9 .trim()
10 .split(|c| c == ',' || c == ' ' || c == '\t')
11 .map(str::trim)
12 .filter(|t| !t.is_empty());
13
14 for token in tokens {
15 match token {
16 "should_panic" | "no_run" | "ignore" | "allow_fail" => {
17 seen_rust_tags = !seen_other_tags
18 }
19 "rust" => seen_rust_tags = true,
20 "test_harness" | "compile_fail" => seen_rust_tags = !seen_other_tags || seen_rust_tags,
21 x if x.starts_with("edition") => {}
22 x if x.starts_with('E') && x.len() == 5 => {
23 if x[1..].parse::<u32>().is_ok() {
24 seen_rust_tags = !seen_other_tags || seen_rust_tags;
25 } else {
26 seen_other_tags = true;
27 }
28 }
29 _ => seen_other_tags = true,
30 }
31 }
32
33 !seen_other_tags || seen_rust_tags
34}
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 9ba98f7fb..a7c8c13c6 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -213,7 +213,7 @@ fn doc_comment_text(comment: &ast::Comment) -> SmolStr {
213 213
214 // Quote the string 214 // Quote the string
215 // Note that `tt::Literal` expect an escaped string 215 // Note that `tt::Literal` expect an escaped string
216 let text = format!("{:?}", text.escape_debug().to_string()); 216 let text = format!("\"{}\"", text.escape_debug());
217 text.into() 217 text.into()
218} 218}
219 219
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index e02d038b6..3a1d840ea 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -936,7 +936,25 @@ fn test_meta_doc_comments() {
936 MultiLines Doc 936 MultiLines Doc
937 */ 937 */
938 }"#, 938 }"#,
939 "# [doc = \" Single Line Doc 1\"] # [doc = \"\\\\n MultiLines Doc\\\\n \"] fn bar () {}", 939 "# [doc = \" Single Line Doc 1\"] # [doc = \"\\n MultiLines Doc\\n \"] fn bar () {}",
940 );
941}
942
943#[test]
944fn test_meta_extended_key_value_attributes() {
945 parse_macro(
946 r#"
947macro_rules! foo {
948 (#[$i:meta]) => (
949 #[$ i]
950 fn bar() {}
951 )
952}
953"#,
954 )
955 .assert_expand_items(
956 r#"foo! { #[doc = concat!("The `", "bla", "` lang item.")] }"#,
957 r#"# [doc = concat ! ("The `" , "bla" , "` lang item.")] fn bar () {}"#,
940 ); 958 );
941} 959}
942 960
@@ -959,7 +977,27 @@ fn test_meta_doc_comments_non_latin() {
959 莊生曉夢迷蝴蝶,望帝春心託杜鵑。 977 莊生曉夢迷蝴蝶,望帝春心託杜鵑。
960 */ 978 */
961 }"#, 979 }"#,
962 "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\\\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\\\n \"] fn bar () {}", 980 "# [doc = \" 錦瑟無端五十弦,一弦一柱思華年。\"] # [doc = \"\\n 莊生曉夢迷蝴蝶,望帝春心託杜鵑。\\n \"] fn bar () {}",
981 );
982}
983
984#[test]
985fn test_meta_doc_comments_escaped_characters() {
986 parse_macro(
987 r#"
988 macro_rules! foo {
989 ($(#[$ i:meta])+) => (
990 $(#[$ i])+
991 fn bar() {}
992 )
993 }
994"#,
995 )
996 .assert_expand_items(
997 r#"foo! {
998 /// \ " '
999 }"#,
1000 r#"# [doc = " \\ \" \'"] fn bar () {}"#,
963 ); 1001 );
964} 1002}
965 1003
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index cebb8f400..9bdf0b5fa 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -76,42 +76,7 @@ pub(crate) mod fragments {
76 76
77 // Parse a meta item , which excluded [], e.g : #[ MetaItem ] 77 // Parse a meta item , which excluded [], e.g : #[ MetaItem ]
78 pub(crate) fn meta_item(p: &mut Parser) { 78 pub(crate) fn meta_item(p: &mut Parser) {
79 fn is_delimiter(p: &mut Parser) -> bool { 79 attributes::meta(p);
80 matches!(p.current(), T!['{'] | T!['('] | T!['['])
81 }
82
83 if is_delimiter(p) {
84 items::token_tree(p);
85 return;
86 }
87
88 let m = p.start();
89 while !p.at(EOF) {
90 if is_delimiter(p) {
91 items::token_tree(p);
92 break;
93 } else {
94 // https://doc.rust-lang.org/reference/attributes.html
95 // https://doc.rust-lang.org/reference/paths.html#simple-paths
96 // The start of an meta must be a simple path
97 match p.current() {
98 IDENT | T![super] | T![self] | T![crate] => p.bump_any(),
99 T![=] => {
100 p.bump_any();
101 match p.current() {
102 c if c.is_literal() => p.bump_any(),
103 T![true] | T![false] => p.bump_any(),
104 _ => {}
105 }
106 break;
107 }
108 _ if p.at(T![::]) => p.bump(T![::]),
109 _ => break,
110 }
111 }
112 }
113
114 m.complete(p, TOKEN_TREE);
115 } 80 }
116 81
117 pub(crate) fn item(p: &mut Parser) { 82 pub(crate) fn item(p: &mut Parser) {
diff --git a/crates/parser/src/grammar/attributes.rs b/crates/parser/src/grammar/attributes.rs
index 96791ffc2..124a10eb2 100644
--- a/crates/parser/src/grammar/attributes.rs
+++ b/crates/parser/src/grammar/attributes.rs
@@ -14,6 +14,21 @@ pub(super) fn outer_attrs(p: &mut Parser) {
14 } 14 }
15} 15}
16 16
17pub(super) fn meta(p: &mut Parser) {
18 paths::use_path(p);
19
20 match p.current() {
21 T![=] => {
22 p.bump(T![=]);
23 if expressions::expr(p).0.is_none() {
24 p.error("expected expression");
25 }
26 }
27 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
28 _ => {}
29 }
30}
31
17fn attr(p: &mut Parser, inner: bool) { 32fn attr(p: &mut Parser, inner: bool) {
18 let attr = p.start(); 33 let attr = p.start();
19 assert!(p.at(T![#])); 34 assert!(p.at(T![#]));
@@ -25,18 +40,7 @@ fn attr(p: &mut Parser, inner: bool) {
25 } 40 }
26 41
27 if p.eat(T!['[']) { 42 if p.eat(T!['[']) {
28 paths::use_path(p); 43 meta(p);
29
30 match p.current() {
31 T![=] => {
32 p.bump(T![=]);
33 if expressions::expr(p).0.is_none() {
34 p.error("expected expression");
35 }
36 }
37 T!['('] | T!['['] | T!['{'] => items::token_tree(p),
38 _ => {}
39 }
40 44
41 if !p.eat(T![']']) { 45 if !p.eat(T![']']) {
42 p.error("expected `]`"); 46 p.error("expected `]`");
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
index da71498a8..3ab347834 100644
--- a/crates/parser/src/grammar/patterns.rs
+++ b/crates/parser/src/grammar/patterns.rs
@@ -206,13 +206,15 @@ fn record_pat_field_list(p: &mut Parser) {
206 T![.] if p.at(T![..]) => p.bump(T![..]), 206 T![.] if p.at(T![..]) => p.bump(T![..]),
207 T!['{'] => error_block(p, "expected ident"), 207 T!['{'] => error_block(p, "expected ident"),
208 208
209 c => { 209 _ => {
210 let m = p.start(); 210 let m = p.start();
211 match c { 211 attributes::outer_attrs(p);
212 match p.current() {
212 // test record_pat_field 213 // test record_pat_field
213 // fn foo() { 214 // fn foo() {
214 // let S { 0: 1 } = (); 215 // let S { 0: 1 } = ();
215 // let S { x: 1 } = (); 216 // let S { x: 1 } = ();
217 // let S { #[cfg(any())] x: 1 } = ();
216 // } 218 // }
217 IDENT | INT_NUMBER if p.nth(1) == T![:] => { 219 IDENT | INT_NUMBER if p.nth(1) == T![:] => {
218 name_ref_or_index(p); 220 name_ref_or_index(p);
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index 94cbf7d85..6ae3e734f 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -283,17 +283,21 @@ pub(super) fn path_type(p: &mut Parser) {
283// type B = crate::foo!(); 283// type B = crate::foo!();
284fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) { 284fn path_or_macro_type_(p: &mut Parser, allow_bounds: bool) {
285 assert!(paths::is_path_start(p)); 285 assert!(paths::is_path_start(p));
286 let r = p.start();
286 let m = p.start(); 287 let m = p.start();
288
287 paths::type_path(p); 289 paths::type_path(p);
288 290
289 let kind = if p.at(T![!]) && !p.at(T![!=]) { 291 let kind = if p.at(T![!]) && !p.at(T![!=]) {
290 items::macro_call_after_excl(p); 292 items::macro_call_after_excl(p);
291 MACRO_CALL 293 m.complete(p, MACRO_CALL);
294 MACRO_TYPE
292 } else { 295 } else {
296 m.abandon(p);
293 PATH_TYPE 297 PATH_TYPE
294 }; 298 };
295 299
296 let path = m.complete(p, kind); 300 let path = r.complete(p, kind);
297 301
298 if allow_bounds { 302 if allow_bounds {
299 opt_type_bounds_as_dyn_trait_type(p, path); 303 opt_type_bounds_as_dyn_trait_type(p, path);
@@ -319,7 +323,7 @@ pub(super) fn path_type_(p: &mut Parser, allow_bounds: bool) {
319fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) { 323fn opt_type_bounds_as_dyn_trait_type(p: &mut Parser, type_marker: CompletedMarker) {
320 assert!(matches!( 324 assert!(matches!(
321 type_marker.kind(), 325 type_marker.kind(),
322 SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_CALL 326 SyntaxKind::PATH_TYPE | SyntaxKind::FOR_TYPE | SyntaxKind::MACRO_TYPE
323 )); 327 ));
324 if !p.at(T![+]) { 328 if !p.at(T![+]) {
325 return; 329 return;
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs
index 22011cb33..f09ad37e3 100644
--- a/crates/paths/src/lib.rs
+++ b/crates/paths/src/lib.rs
@@ -1,6 +1,7 @@
1//! Thin wrappers around `std::path`, distinguishing between absolute and 1//! Thin wrappers around `std::path`, distinguishing between absolute and
2//! relative paths. 2//! relative paths.
3use std::{ 3use std::{
4 borrow::Borrow,
4 convert::{TryFrom, TryInto}, 5 convert::{TryFrom, TryInto},
5 ops, 6 ops,
6 path::{Component, Path, PathBuf}, 7 path::{Component, Path, PathBuf},
@@ -35,6 +36,12 @@ impl AsRef<AbsPath> for AbsPathBuf {
35 } 36 }
36} 37}
37 38
39impl Borrow<AbsPath> for AbsPathBuf {
40 fn borrow(&self) -> &AbsPath {
41 self.as_path()
42 }
43}
44
38impl TryFrom<PathBuf> for AbsPathBuf { 45impl TryFrom<PathBuf> for AbsPathBuf {
39 type Error = PathBuf; 46 type Error = PathBuf;
40 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { 47 fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> {
diff --git a/crates/proc_macro_api/Cargo.toml b/crates/proc_macro_api/Cargo.toml
index 16fd56c7e..1ba1e4abd 100644
--- a/crates/proc_macro_api/Cargo.toml
+++ b/crates/proc_macro_api/Cargo.toml
@@ -15,10 +15,11 @@ serde_json = { version = "1.0", features = ["unbounded_depth"] }
15log = "0.4.8" 15log = "0.4.8"
16crossbeam-channel = "0.5.0" 16crossbeam-channel = "0.5.0"
17jod-thread = "0.1.1" 17jod-thread = "0.1.1"
18memmap = "0.7.0"
19object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] }
20snap = "1.0"
18 21
19tt = { path = "../tt", version = "0.0.0" } 22tt = { path = "../tt", version = "0.0.0" }
20base_db = { path = "../base_db", version = "0.0.0" } 23base_db = { path = "../base_db", version = "0.0.0" }
21stdx = { path = "../stdx", version = "0.0.0" } 24stdx = { path = "../stdx", version = "0.0.0" }
22snap = "1" 25profile = { path = "../profile", version = "0.0.0" }
23object = { version = "0.23.0", default-features = false, features = ["std", "read_core", "elf", "macho", "pe", "unaligned"] }
24memmap = "0.7.0"
diff --git a/crates/proc_macro_api/src/lib.rs b/crates/proc_macro_api/src/lib.rs
index 2dd2a8541..654bd9943 100644
--- a/crates/proc_macro_api/src/lib.rs
+++ b/crates/proc_macro_api/src/lib.rs
@@ -77,6 +77,7 @@ impl ProcMacroClient {
77 } 77 }
78 78
79 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> { 79 pub fn by_dylib_path(&self, dylib_path: &Path) -> Vec<ProcMacro> {
80 let _p = profile::span("ProcMacroClient::by_dylib_path");
80 match version::read_dylib_info(dylib_path) { 81 match version::read_dylib_info(dylib_path) {
81 Ok(info) => { 82 Ok(info) => {
82 if info.version.0 < 1 || info.version.1 < 47 { 83 if info.version.0 < 1 || info.version.1 < 47 {
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index f7050be4e..faca336de 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -1,7 +1,6 @@
1//! Handles build script specific information 1//! Handles build script specific information
2 2
3use std::{ 3use std::{
4 io::BufReader,
5 path::PathBuf, 4 path::PathBuf,
6 process::{Command, Stdio}, 5 process::{Command, Stdio},
7 sync::Arc, 6 sync::Arc,
@@ -13,12 +12,13 @@ use cargo_metadata::{BuildScript, Message};
13use itertools::Itertools; 12use itertools::Itertools;
14use paths::{AbsPath, AbsPathBuf}; 13use paths::{AbsPath, AbsPathBuf};
15use rustc_hash::FxHashMap; 14use rustc_hash::FxHashMap;
16use stdx::JodChild; 15use serde::Deserialize;
16use stdx::format_to;
17 17
18use crate::{cfg_flag::CfgFlag, CargoConfig}; 18use crate::{cfg_flag::CfgFlag, CargoConfig};
19 19
20#[derive(Debug, Clone, Default, PartialEq, Eq)] 20#[derive(Debug, Clone, Default, PartialEq, Eq)]
21pub(crate) struct BuildData { 21pub(crate) struct PackageBuildData {
22 /// List of config flags defined by this package's build script 22 /// List of config flags defined by this package's build script
23 pub(crate) cfgs: Vec<CfgFlag>, 23 pub(crate) cfgs: Vec<CfgFlag>,
24 /// List of cargo-related environment variables with their value 24 /// List of cargo-related environment variables with their value
@@ -32,6 +32,17 @@ pub(crate) struct BuildData {
32 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>, 32 pub(crate) proc_macro_dylib_path: Option<AbsPathBuf>,
33} 33}
34 34
35#[derive(Debug, Default, PartialEq, Eq, Clone)]
36pub(crate) struct WorkspaceBuildData {
37 per_package: FxHashMap<String, PackageBuildData>,
38 error: Option<String>,
39}
40
41#[derive(Debug, Default, PartialEq, Eq, Clone)]
42pub struct BuildDataResult {
43 per_workspace: FxHashMap<AbsPathBuf, WorkspaceBuildData>,
44}
45
35#[derive(Clone, Debug)] 46#[derive(Clone, Debug)]
36pub(crate) struct BuildDataConfig { 47pub(crate) struct BuildDataConfig {
37 cargo_toml: AbsPathBuf, 48 cargo_toml: AbsPathBuf,
@@ -47,19 +58,17 @@ impl PartialEq for BuildDataConfig {
47 58
48impl Eq for BuildDataConfig {} 59impl Eq for BuildDataConfig {}
49 60
50#[derive(Debug, Default)] 61#[derive(Debug)]
51pub struct BuildDataCollector { 62pub struct BuildDataCollector {
63 wrap_rustc: bool,
52 configs: FxHashMap<AbsPathBuf, BuildDataConfig>, 64 configs: FxHashMap<AbsPathBuf, BuildDataConfig>,
53} 65}
54 66
55#[derive(Debug, Default, PartialEq, Eq)]
56pub struct BuildDataResult {
57 data: FxHashMap<AbsPathBuf, BuildDataMap>,
58}
59
60pub(crate) type BuildDataMap = FxHashMap<String, BuildData>;
61
62impl BuildDataCollector { 67impl BuildDataCollector {
68 pub fn new(wrap_rustc: bool) -> Self {
69 Self { wrap_rustc, configs: FxHashMap::default() }
70 }
71
63 pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) { 72 pub(crate) fn add_config(&mut self, workspace_root: &AbsPath, config: BuildDataConfig) {
64 self.configs.insert(workspace_root.to_path_buf(), config); 73 self.configs.insert(workspace_root.to_path_buf(), config);
65 } 74 }
@@ -67,23 +76,41 @@ impl BuildDataCollector {
67 pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> { 76 pub fn collect(&mut self, progress: &dyn Fn(String)) -> Result<BuildDataResult> {
68 let mut res = BuildDataResult::default(); 77 let mut res = BuildDataResult::default();
69 for (path, config) in self.configs.iter() { 78 for (path, config) in self.configs.iter() {
70 res.data.insert( 79 let workspace_build_data = WorkspaceBuildData::collect(
71 path.clone(), 80 &config.cargo_toml,
72 collect_from_workspace( 81 &config.cargo_features,
73 &config.cargo_toml, 82 &config.packages,
74 &config.cargo_features, 83 self.wrap_rustc,
75 &config.packages, 84 progress,
76 progress, 85 )?;
77 )?, 86 res.per_workspace.insert(path.clone(), workspace_build_data);
78 );
79 } 87 }
80 Ok(res) 88 Ok(res)
81 } 89 }
82} 90}
83 91
92impl WorkspaceBuildData {
93 pub(crate) fn get(&self, package_id: &str) -> Option<&PackageBuildData> {
94 self.per_package.get(package_id)
95 }
96}
97
84impl BuildDataResult { 98impl BuildDataResult {
85 pub(crate) fn get(&self, root: &AbsPath) -> Option<&BuildDataMap> { 99 pub(crate) fn get(&self, workspace_root: &AbsPath) -> Option<&WorkspaceBuildData> {
86 self.data.get(&root.to_path_buf()) 100 self.per_workspace.get(workspace_root)
101 }
102 pub fn error(&self) -> Option<String> {
103 let mut buf = String::new();
104 for (_workspace_root, build_data) in &self.per_workspace {
105 if let Some(err) = &build_data.error {
106 format_to!(buf, "cargo check failed:\n{}", err);
107 }
108 }
109 if buf.is_empty() {
110 return None;
111 }
112
113 Some(buf)
87 } 114 }
88} 115}
89 116
@@ -97,108 +124,155 @@ impl BuildDataConfig {
97 } 124 }
98} 125}
99 126
100fn collect_from_workspace( 127impl WorkspaceBuildData {
101 cargo_toml: &AbsPath, 128 fn collect(
102 cargo_features: &CargoConfig, 129 cargo_toml: &AbsPath,
103 packages: &Vec<cargo_metadata::Package>, 130 cargo_features: &CargoConfig,
104 progress: &dyn Fn(String), 131 packages: &Vec<cargo_metadata::Package>,
105) -> Result<BuildDataMap> { 132 wrap_rustc: bool,
106 let mut cmd = Command::new(toolchain::cargo()); 133 progress: &dyn Fn(String),
107 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"]) 134 ) -> Result<WorkspaceBuildData> {
108 .arg(cargo_toml.as_ref()); 135 let mut cmd = Command::new(toolchain::cargo());
109 136
110 // --all-targets includes tests, benches and examples in addition to the 137 if wrap_rustc {
111 // default lib and bins. This is an independent concept from the --targets 138 // Setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself. We use
112 // flag below. 139 // that to compile only proc macros and build scripts during the initial
113 cmd.arg("--all-targets"); 140 // `cargo check`.
114 141 let myself = std::env::current_exe()?;
115 if let Some(target) = &cargo_features.target { 142 cmd.env("RUSTC_WRAPPER", myself);
116 cmd.args(&["--target", target]); 143 cmd.env("RA_RUSTC_WRAPPER", "1");
117 } 144 }
118 145
119 if cargo_features.all_features { 146 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"])
120 cmd.arg("--all-features"); 147 .arg(cargo_toml.as_ref());
121 } else { 148
122 if cargo_features.no_default_features { 149 // --all-targets includes tests, benches and examples in addition to the
123 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 150 // default lib and bins. This is an independent concept from the --targets
124 // https://github.com/oli-obk/cargo_metadata/issues/79 151 // flag below.
125 cmd.arg("--no-default-features"); 152 cmd.arg("--all-targets");
153
154 if let Some(target) = &cargo_features.target {
155 cmd.args(&["--target", target]);
126 } 156 }
127 if !cargo_features.features.is_empty() { 157
128 cmd.arg("--features"); 158 if cargo_features.all_features {
129 cmd.arg(cargo_features.features.join(" ")); 159 cmd.arg("--all-features");
160 } else {
161 if cargo_features.no_default_features {
162 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures`
163 // https://github.com/oli-obk/cargo_metadata/issues/79
164 cmd.arg("--no-default-features");
165 }
166 if !cargo_features.features.is_empty() {
167 cmd.arg("--features");
168 cmd.arg(cargo_features.features.join(" "));
169 }
130 } 170 }
131 }
132 171
133 cmd.stdout(Stdio::piped()).stderr(Stdio::null()).stdin(Stdio::null()); 172 cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
134 173
135 let mut child = cmd.spawn().map(JodChild)?; 174 let mut res = WorkspaceBuildData::default();
136 let child_stdout = child.stdout.take().unwrap(); 175
137 let stdout = BufReader::new(child_stdout); 176 let mut callback_err = None;
138 177 let output = stdx::process::streaming_output(
139 let mut res = BuildDataMap::default(); 178 cmd,
140 for message in cargo_metadata::Message::parse_stream(stdout).flatten() { 179 &mut |line| {
141 match message { 180 if callback_err.is_some() {
142 Message::BuildScriptExecuted(BuildScript { 181 return;
143 package_id, out_dir, cfgs, env, .. 182 }
144 }) => { 183
145 let cfgs = { 184 // Copy-pasted from existing cargo_metadata. It seems like we
146 let mut acc = Vec::new(); 185 // should be using sered_stacker here?
147 for cfg in cfgs { 186 let mut deserializer = serde_json::Deserializer::from_str(&line);
148 match cfg.parse::<CfgFlag>() { 187 deserializer.disable_recursion_limit();
149 Ok(it) => acc.push(it), 188 let message = Message::deserialize(&mut deserializer)
150 Err(err) => { 189 .unwrap_or(Message::TextLine(line.to_string()));
151 anyhow::bail!("invalid cfg from cargo-metadata: {}", err) 190
191 match message {
192 Message::BuildScriptExecuted(BuildScript {
193 package_id,
194 out_dir,
195 cfgs,
196 env,
197 ..
198 }) => {
199 let cfgs = {
200 let mut acc = Vec::new();
201 for cfg in cfgs {
202 match cfg.parse::<CfgFlag>() {
203 Ok(it) => acc.push(it),
204 Err(err) => {
205 callback_err = Some(anyhow::format_err!(
206 "invalid cfg from cargo-metadata: {}",
207 err
208 ));
209 return;
210 }
211 };
152 } 212 }
213 acc
153 }; 214 };
215 let package_build_data =
216 res.per_package.entry(package_id.repr.clone()).or_default();
217 // cargo_metadata crate returns default (empty) path for
218 // older cargos, which is not absolute, so work around that.
219 if !out_dir.as_str().is_empty() {
220 let out_dir =
221 AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string()));
222 package_build_data.out_dir = Some(out_dir);
223 package_build_data.cfgs = cfgs;
224 }
225
226 package_build_data.envs = env;
154 } 227 }
155 acc 228 Message::CompilerArtifact(message) => {
156 }; 229 progress(format!("metadata {}", message.target.name));
157 let res = res.entry(package_id.repr.clone()).or_default(); 230
158 // cargo_metadata crate returns default (empty) path for 231 if message.target.kind.contains(&"proc-macro".to_string()) {
159 // older cargos, which is not absolute, so work around that. 232 let package_id = message.package_id;
160 if !out_dir.as_str().is_empty() { 233 // Skip rmeta file
161 let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string())); 234 if let Some(filename) =
162 res.out_dir = Some(out_dir); 235 message.filenames.iter().find(|name| is_dylib(name))
163 res.cfgs = cfgs; 236 {
164 } 237 let filename = AbsPathBuf::assert(PathBuf::from(&filename));
165 238 let package_build_data =
166 res.envs = env; 239 res.per_package.entry(package_id.repr.clone()).or_default();
167 } 240 package_build_data.proc_macro_dylib_path = Some(filename);
168 Message::CompilerArtifact(message) => { 241 }
169 progress(format!("metadata {}", message.target.name)); 242 }
170
171 if message.target.kind.contains(&"proc-macro".to_string()) {
172 let package_id = message.package_id;
173 // Skip rmeta file
174 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) {
175 let filename = AbsPathBuf::assert(PathBuf::from(&filename));
176 let res = res.entry(package_id.repr.clone()).or_default();
177 res.proc_macro_dylib_path = Some(filename);
178 } 243 }
244 Message::CompilerMessage(message) => {
245 progress(message.target.name.clone());
246 }
247 Message::BuildFinished(_) => {}
248 Message::TextLine(_) => {}
249 _ => {}
250 }
251 },
252 &mut |_| (),
253 )?;
254
255 for package in packages {
256 let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default();
257 inject_cargo_env(package, package_build_data);
258 if let Some(out_dir) = &package_build_data.out_dir {
259 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
260 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
261 package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
179 } 262 }
180 } 263 }
181 Message::CompilerMessage(message) => {
182 progress(message.target.name.clone());
183 }
184 Message::BuildFinished(_) => {}
185 Message::TextLine(_) => {}
186 _ => {}
187 } 264 }
188 }
189 265
190 for package in packages { 266 if !output.status.success() {
191 let build_data = res.entry(package.id.repr.clone()).or_default(); 267 let mut stderr = String::from_utf8(output.stderr).unwrap_or_default();
192 inject_cargo_env(package, build_data); 268 if stderr.is_empty() {
193 if let Some(out_dir) = &build_data.out_dir { 269 stderr = "cargo check failed".to_string();
194 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
195 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
196 build_data.envs.push(("OUT_DIR".to_string(), out_dir));
197 } 270 }
271 res.error = Some(stderr)
198 } 272 }
199 }
200 273
201 Ok(res) 274 Ok(res)
275 }
202} 276}
203 277
204// FIXME: File a better way to know if it is a dylib 278// FIXME: File a better way to know if it is a dylib
@@ -212,7 +286,7 @@ fn is_dylib(path: &Utf8Path) -> bool {
212/// Recreates the compile-time environment variables that Cargo sets. 286/// Recreates the compile-time environment variables that Cargo sets.
213/// 287///
214/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> 288/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates>
215fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut BuildData) { 289fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut PackageBuildData) {
216 let env = &mut build_data.envs; 290 let env = &mut build_data.envs;
217 291
218 // FIXME: Missing variables: 292 // FIXME: Missing variables:
diff --git a/crates/project_model/src/workspace.rs b/crates/project_model/src/workspace.rs
index 1b53fcc30..2fcd0f8fa 100644
--- a/crates/project_model/src/workspace.rs
+++ b/crates/project_model/src/workspace.rs
@@ -12,7 +12,7 @@ use proc_macro_api::ProcMacroClient;
12use rustc_hash::{FxHashMap, FxHashSet}; 12use rustc_hash::{FxHashMap, FxHashSet};
13 13
14use crate::{ 14use crate::{
15 build_data::{BuildData, BuildDataMap, BuildDataResult}, 15 build_data::{BuildDataResult, PackageBuildData, WorkspaceBuildData},
16 cargo_workspace, 16 cargo_workspace,
17 cfg_flag::CfgFlag, 17 cfg_flag::CfgFlag,
18 rustc_cfg, 18 rustc_cfg,
@@ -354,10 +354,10 @@ fn cargo_to_crate_graph(
354 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 354 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
355 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 355 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
356 cargo: &CargoWorkspace, 356 cargo: &CargoWorkspace,
357 build_data_map: Option<&BuildDataMap>, 357 build_data_map: Option<&WorkspaceBuildData>,
358 sysroot: &Sysroot, 358 sysroot: &Sysroot,
359 rustc: &Option<CargoWorkspace>, 359 rustc: &Option<CargoWorkspace>,
360 rustc_build_data_map: Option<&BuildDataMap>, 360 rustc_build_data_map: Option<&WorkspaceBuildData>,
361) -> CrateGraph { 361) -> CrateGraph {
362 let _p = profile::span("cargo_to_crate_graph"); 362 let _p = profile::span("cargo_to_crate_graph");
363 let mut crate_graph = CrateGraph::default(); 363 let mut crate_graph = CrateGraph::default();
@@ -464,7 +464,7 @@ fn handle_rustc_crates(
464 rustc_workspace: &CargoWorkspace, 464 rustc_workspace: &CargoWorkspace,
465 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>, 465 load: &mut dyn FnMut(&AbsPath) -> Option<FileId>,
466 crate_graph: &mut CrateGraph, 466 crate_graph: &mut CrateGraph,
467 rustc_build_data_map: Option<&FxHashMap<String, BuildData>>, 467 rustc_build_data_map: Option<&WorkspaceBuildData>,
468 cfg_options: &CfgOptions, 468 cfg_options: &CfgOptions,
469 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 469 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
470 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>, 470 pkg_to_lib_crate: &mut FxHashMap<la_arena::Idx<crate::PackageData>, CrateId>,
@@ -555,7 +555,7 @@ fn handle_rustc_crates(
555fn add_target_crate_root( 555fn add_target_crate_root(
556 crate_graph: &mut CrateGraph, 556 crate_graph: &mut CrateGraph,
557 pkg: &cargo_workspace::PackageData, 557 pkg: &cargo_workspace::PackageData,
558 build_data: Option<&BuildData>, 558 build_data: Option<&PackageBuildData>,
559 cfg_options: &CfgOptions, 559 cfg_options: &CfgOptions,
560 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>, 560 proc_macro_loader: &dyn Fn(&Path) -> Vec<ProcMacro>,
561 file_id: FileId, 561 file_id: FileId,
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 3130785cc..0571a912c 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -22,7 +22,7 @@ env_logger = { version = "0.8.1", default-features = false }
22itertools = "0.10.0" 22itertools = "0.10.0"
23jod-thread = "0.1.0" 23jod-thread = "0.1.0"
24log = "0.4.8" 24log = "0.4.8"
25lsp-types = { version = "0.88.0", features = ["proposed"] } 25lsp-types = { version = "0.89.0", features = ["proposed"] }
26parking_lot = "0.11.0" 26parking_lot = "0.11.0"
27xflags = "0.2.1" 27xflags = "0.2.1"
28oorandom = "11.1.2" 28oorandom = "11.1.2"
diff --git a/crates/rust-analyzer/build.rs b/crates/rust-analyzer/build.rs
index 999dc5928..13b903891 100644
--- a/crates/rust-analyzer/build.rs
+++ b/crates/rust-analyzer/build.rs
@@ -39,7 +39,8 @@ fn set_rerun() {
39} 39}
40 40
41fn rev() -> Option<String> { 41fn rev() -> Option<String> {
42 let output = Command::new("git").args(&["describe", "--tags"]).output().ok()?; 42 let output =
43 Command::new("git").args(&["describe", "--tags", "--exclude", "nightly"]).output().ok()?;
43 let stdout = String::from_utf8(output.stdout).ok()?; 44 let stdout = String::from_utf8(output.stdout).ok()?;
44 Some(stdout) 45 Some(stdout)
45} 46}
diff --git a/crates/rust-analyzer/src/benchmarks.rs b/crates/rust-analyzer/src/benchmarks.rs
index bf569b40b..bdd94b1c4 100644
--- a/crates/rust-analyzer/src/benchmarks.rs
+++ b/crates/rust-analyzer/src/benchmarks.rs
@@ -30,8 +30,11 @@ fn benchmark_integrated_highlighting() {
30 let file = "./crates/ide_db/src/apply_change.rs"; 30 let file = "./crates/ide_db/src/apply_change.rs";
31 31
32 let cargo_config = Default::default(); 32 let cargo_config = Default::default();
33 let load_cargo_config = 33 let load_cargo_config = LoadCargoConfig {
34 LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: false }; 34 load_out_dirs_from_check: true,
35 wrap_rustc: false,
36 with_proc_macro: false,
37 };
35 38
36 let (mut host, vfs, _proc_macro) = { 39 let (mut host, vfs, _proc_macro) = {
37 let _it = stdx::timeit("workspace loading"); 40 let _it = stdx::timeit("workspace loading");
diff --git a/crates/rust-analyzer/src/bin/flags.rs b/crates/rust-analyzer/src/bin/flags.rs
index b05fc00b9..63953098a 100644
--- a/crates/rust-analyzer/src/bin/flags.rs
+++ b/crates/rust-analyzer/src/bin/flags.rs
@@ -71,6 +71,8 @@ xflags::xflags! {
71 optional --load-output-dirs 71 optional --load-output-dirs
72 /// Use proc-macro-srv for proc-macro expanding. 72 /// Use proc-macro-srv for proc-macro expanding.
73 optional --with-proc-macro 73 optional --with-proc-macro
74 /// Only resolve names, don't run type inference.
75 optional --skip-inference
74 } 76 }
75 77
76 cmd diagnostics 78 cmd diagnostics
@@ -158,6 +160,7 @@ pub struct AnalysisStats {
158 pub no_sysroot: bool, 160 pub no_sysroot: bool,
159 pub load_output_dirs: bool, 161 pub load_output_dirs: bool,
160 pub with_proc_macro: bool, 162 pub with_proc_macro: bool,
163 pub skip_inference: bool,
161} 164}
162 165
163#[derive(Debug)] 166#[derive(Debug)]
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 3b9b9e8b4..f0abb5b15 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -3,6 +3,7 @@
3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis 3//! Based on cli flags, either spawns an LSP server, or runs a batch analysis
4mod flags; 4mod flags;
5mod logger; 5mod logger;
6mod rustc_wrapper;
6 7
7use std::{convert::TryFrom, env, fs, path::Path, process}; 8use std::{convert::TryFrom, env, fs, path::Path, process};
8 9
@@ -26,6 +27,20 @@ static ALLOC: mimalloc::MiMalloc = mimalloc::MiMalloc;
26static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; 27static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
27 28
28fn main() { 29fn main() {
30 if std::env::var("RA_RUSTC_WRAPPER").is_ok() {
31 let mut args = std::env::args_os();
32 let _me = args.next().unwrap();
33 let rustc = args.next().unwrap();
34 let code = match rustc_wrapper::run_rustc_skipping_cargo_checking(rustc, args.collect()) {
35 Ok(rustc_wrapper::ExitCode(code)) => code.unwrap_or(102),
36 Err(err) => {
37 eprintln!("{}", err);
38 101
39 }
40 };
41 process::exit(code);
42 }
43
29 if let Err(err) = try_main() { 44 if let Err(err) = try_main() {
30 log::error!("Unexpected error: {}", err); 45 log::error!("Unexpected error: {}", err);
31 eprintln!("{}", err); 46 eprintln!("{}", err);
@@ -78,6 +93,7 @@ fn try_main() -> Result<()> {
78 path: cmd.path, 93 path: cmd.path,
79 load_output_dirs: cmd.load_output_dirs, 94 load_output_dirs: cmd.load_output_dirs,
80 with_proc_macro: cmd.with_proc_macro, 95 with_proc_macro: cmd.with_proc_macro,
96 skip_inference: cmd.skip_inference,
81 } 97 }
82 .run(verbosity)?, 98 .run(verbosity)?,
83 99
diff --git a/crates/rust-analyzer/src/bin/rustc_wrapper.rs b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
new file mode 100644
index 000000000..2f6d4706d
--- /dev/null
+++ b/crates/rust-analyzer/src/bin/rustc_wrapper.rs
@@ -0,0 +1,46 @@
1//! We setup RUSTC_WRAPPER to point to `rust-analyzer` binary itself during the
2//! initial `cargo check`. That way, we avoid checking the actual project, and
3//! only build proc macros and build.rs.
4//!
5//! Code taken from IntelliJ :0)
6//! https://github.com/intellij-rust/intellij-rust/blob/master/native-helper/src/main.rs
7use std::{
8 ffi::OsString,
9 io,
10 process::{Command, Stdio},
11};
12
13/// ExitCode/ExitStatus are impossible to create :(.
14pub(crate) struct ExitCode(pub(crate) Option<i32>);
15
16pub(crate) fn run_rustc_skipping_cargo_checking(
17 rustc_executable: OsString,
18 args: Vec<OsString>,
19) -> io::Result<ExitCode> {
20 let is_cargo_check = args.iter().any(|arg| {
21 let arg = arg.to_string_lossy();
22 // `cargo check` invokes `rustc` with `--emit=metadata` argument.
23 //
24 // https://doc.rust-lang.org/rustc/command-line-arguments.html#--emit-specifies-the-types-of-output-files-to-generate
25 // link — Generates the crates specified by --crate-type. The default
26 // output filenames depend on the crate type and platform. This
27 // is the default if --emit is not specified.
28 // metadata — Generates a file containing metadata about the crate.
29 // The default output filename is CRATE_NAME.rmeta.
30 arg.starts_with("--emit=") && arg.contains("metadata") && !arg.contains("link")
31 });
32 if is_cargo_check {
33 return Ok(ExitCode(Some(0)));
34 }
35 run_rustc(rustc_executable, args)
36}
37
38fn run_rustc(rustc_executable: OsString, args: Vec<OsString>) -> io::Result<ExitCode> {
39 let mut child = Command::new(rustc_executable)
40 .args(args)
41 .stdin(Stdio::inherit())
42 .stdout(Stdio::inherit())
43 .stderr(Stdio::inherit())
44 .spawn()?;
45 Ok(ExitCode(child.wait()?.code()))
46}
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index 7a5bcb8c7..3c87782f2 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -57,7 +57,7 @@ pub fn server_capabilities(client_caps: &ClientCapabilities) -> ServerCapabiliti
57 document_range_formatting_provider: None, 57 document_range_formatting_provider: None,
58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions { 58 document_on_type_formatting_provider: Some(DocumentOnTypeFormattingOptions {
59 first_trigger_character: "=".to_string(), 59 first_trigger_character: "=".to_string(),
60 more_trigger_character: Some(vec![".".to_string(), ">".to_string()]), 60 more_trigger_character: Some(vec![".".to_string(), ">".to_string(), "{".to_string()]),
61 }), 61 }),
62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)), 62 selection_range_provider: Some(SelectionRangeProviderCapability::Simple(true)),
63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)), 63 folding_range_provider: Some(FoldingRangeProviderCapability::Simple(true)),
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index 9c59e7ee4..3f3134562 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -9,10 +9,11 @@ use std::{
9 9
10use hir::{ 10use hir::{
11 db::{AstDatabase, DefDatabase, HirDatabase}, 11 db::{AstDatabase, DefDatabase, HirDatabase},
12 AssocItem, Crate, HasSource, HirDisplay, ModuleDef, 12 AssocItem, Crate, Function, HasSource, HirDisplay, ModuleDef,
13}; 13};
14use hir_def::FunctionId; 14use hir_def::FunctionId;
15use hir_ty::TypeWalk; 15use hir_ty::{TyExt, TypeWalk};
16use ide::{AnalysisHost, RootDatabase};
16use ide_db::base_db::{ 17use ide_db::base_db::{
17 salsa::{self, ParallelDatabase}, 18 salsa::{self, ParallelDatabase},
18 SourceDatabaseExt, 19 SourceDatabaseExt,
@@ -24,6 +25,7 @@ use rayon::prelude::*;
24use rustc_hash::FxHashSet; 25use rustc_hash::FxHashSet;
25use stdx::format_to; 26use stdx::format_to;
26use syntax::AstNode; 27use syntax::AstNode;
28use vfs::Vfs;
27 29
28use crate::cli::{ 30use crate::cli::{
29 load_cargo::{load_workspace_at, LoadCargoConfig}, 31 load_cargo::{load_workspace_at, LoadCargoConfig},
@@ -51,6 +53,7 @@ pub struct AnalysisStatsCmd {
51 pub path: PathBuf, 53 pub path: PathBuf,
52 pub load_output_dirs: bool, 54 pub load_output_dirs: bool,
53 pub with_proc_macro: bool, 55 pub with_proc_macro: bool,
56 pub skip_inference: bool,
54} 57}
55 58
56impl AnalysisStatsCmd { 59impl AnalysisStatsCmd {
@@ -65,6 +68,7 @@ impl AnalysisStatsCmd {
65 cargo_config.no_sysroot = self.no_sysroot; 68 cargo_config.no_sysroot = self.no_sysroot;
66 let load_cargo_config = LoadCargoConfig { 69 let load_cargo_config = LoadCargoConfig {
67 load_out_dirs_from_check: self.load_output_dirs, 70 load_out_dirs_from_check: self.load_output_dirs,
71 wrap_rustc: false,
68 with_proc_macro: self.with_proc_macro, 72 with_proc_macro: self.with_proc_macro,
69 }; 73 };
70 let (host, vfs, _proc_macro) = 74 let (host, vfs, _proc_macro) =
@@ -128,6 +132,39 @@ impl AnalysisStatsCmd {
128 shuffle(&mut rng, &mut funcs); 132 shuffle(&mut rng, &mut funcs);
129 } 133 }
130 134
135 if !self.skip_inference {
136 self.run_inference(&host, db, &vfs, &funcs, verbosity);
137 }
138
139 let total_span = analysis_sw.elapsed();
140 eprintln!("{:<20} {}", "Total:", total_span);
141 report_metric("total time", total_span.time.as_millis() as u64, "ms");
142 if let Some(instructions) = total_span.instructions {
143 report_metric("total instructions", instructions, "#instr");
144 }
145 if let Some(memory) = total_span.memory {
146 report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
147 }
148
149 if env::var("RA_COUNT").is_ok() {
150 eprintln!("{}", profile::countme::get_all());
151 }
152
153 if self.memory_usage && verbosity.is_verbose() {
154 print_memory_usage(host, vfs);
155 }
156
157 Ok(())
158 }
159
160 fn run_inference(
161 &self,
162 host: &AnalysisHost,
163 db: &RootDatabase,
164 vfs: &Vfs,
165 funcs: &[Function],
166 verbosity: Verbosity,
167 ) {
131 let mut bar = match verbosity { 168 let mut bar = match verbosity {
132 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(), 169 Verbosity::Quiet | Verbosity::Spammy => ProgressReport::hidden(),
133 _ if self.parallel => ProgressReport::hidden(), 170 _ if self.parallel => ProgressReport::hidden(),
@@ -154,7 +191,7 @@ impl AnalysisStatsCmd {
154 let mut num_exprs_unknown = 0; 191 let mut num_exprs_unknown = 0;
155 let mut num_exprs_partially_unknown = 0; 192 let mut num_exprs_partially_unknown = 0;
156 let mut num_type_mismatches = 0; 193 let mut num_type_mismatches = 0;
157 for f in funcs { 194 for f in funcs.iter().copied() {
158 let name = f.name(db); 195 let name = f.name(db);
159 let full_name = f 196 let full_name = f
160 .module(db) 197 .module(db)
@@ -296,26 +333,6 @@ impl AnalysisStatsCmd {
296 report_metric("type mismatches", num_type_mismatches, "#"); 333 report_metric("type mismatches", num_type_mismatches, "#");
297 334
298 eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed()); 335 eprintln!("{:<20} {}", "Inference:", inference_sw.elapsed());
299
300 let total_span = analysis_sw.elapsed();
301 eprintln!("{:<20} {}", "Total:", total_span);
302 report_metric("total time", total_span.time.as_millis() as u64, "ms");
303 if let Some(instructions) = total_span.instructions {
304 report_metric("total instructions", instructions, "#instr");
305 }
306 if let Some(memory) = total_span.memory {
307 report_metric("total memory", memory.allocated.megabytes() as u64, "MB");
308 }
309
310 if env::var("RA_COUNT").is_ok() {
311 eprintln!("{}", profile::countme::get_all());
312 }
313
314 if self.memory_usage && verbosity.is_verbose() {
315 print_memory_usage(host, vfs);
316 }
317
318 Ok(())
319 } 336 }
320 337
321 fn stop_watch(&self) -> StopWatch { 338 fn stop_watch(&self) -> StopWatch {
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 8b985716b..74f784338 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -34,7 +34,8 @@ pub fn diagnostics(
34 with_proc_macro: bool, 34 with_proc_macro: bool,
35) -> Result<()> { 35) -> Result<()> {
36 let cargo_config = Default::default(); 36 let cargo_config = Default::default();
37 let load_cargo_config = LoadCargoConfig { load_out_dirs_from_check, with_proc_macro }; 37 let load_cargo_config =
38 LoadCargoConfig { load_out_dirs_from_check, with_proc_macro, wrap_rustc: false };
38 let (host, _vfs, _proc_macro) = 39 let (host, _vfs, _proc_macro) =
39 load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; 40 load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?;
40 let db = host.raw_database(); 41 let db = host.raw_database();
@@ -56,7 +57,8 @@ pub fn diagnostics(
56 let crate_name = 57 let crate_name =
57 module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string(); 58 module.krate().display_name(db).as_deref().unwrap_or("unknown").to_string();
58 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id)); 59 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id));
59 for diagnostic in analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() 60 for diagnostic in
61 analysis.diagnostics(&DiagnosticsConfig::default(), false, file_id).unwrap()
60 { 62 {
61 if matches!(diagnostic.severity, Severity::Error) { 63 if matches!(diagnostic.severity, Severity::Error) {
62 found_error = true; 64 found_error = true;
diff --git a/crates/rust-analyzer/src/cli/load_cargo.rs b/crates/rust-analyzer/src/cli/load_cargo.rs
index 310c36904..75bad1112 100644
--- a/crates/rust-analyzer/src/cli/load_cargo.rs
+++ b/crates/rust-analyzer/src/cli/load_cargo.rs
@@ -15,6 +15,7 @@ use crate::reload::{ProjectFolders, SourceRootConfig};
15 15
16pub struct LoadCargoConfig { 16pub struct LoadCargoConfig {
17 pub load_out_dirs_from_check: bool, 17 pub load_out_dirs_from_check: bool,
18 pub wrap_rustc: bool,
18 pub with_proc_macro: bool, 19 pub with_proc_macro: bool,
19} 20}
20 21
@@ -52,7 +53,7 @@ pub fn load_workspace(
52 }; 53 };
53 54
54 let build_data = if config.load_out_dirs_from_check { 55 let build_data = if config.load_out_dirs_from_check {
55 let mut collector = BuildDataCollector::default(); 56 let mut collector = BuildDataCollector::new(config.wrap_rustc);
56 ws.collect_build_data_configs(&mut collector); 57 ws.collect_build_data_configs(&mut collector);
57 Some(collector.collect(progress)?) 58 Some(collector.collect(progress)?)
58 } else { 59 } else {
@@ -136,8 +137,11 @@ mod tests {
136 fn test_loading_rust_analyzer() -> Result<()> { 137 fn test_loading_rust_analyzer() -> Result<()> {
137 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap(); 138 let path = Path::new(env!("CARGO_MANIFEST_DIR")).parent().unwrap().parent().unwrap();
138 let cargo_config = Default::default(); 139 let cargo_config = Default::default();
139 let load_cargo_config = 140 let load_cargo_config = LoadCargoConfig {
140 LoadCargoConfig { load_out_dirs_from_check: false, with_proc_macro: false }; 141 load_out_dirs_from_check: false,
142 wrap_rustc: false,
143 with_proc_macro: false,
144 };
141 let (host, _vfs, _proc_macro) = 145 let (host, _vfs, _proc_macro) =
142 load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?; 146 load_workspace_at(path, &cargo_config, &load_cargo_config, &|_| {})?;
143 147
diff --git a/crates/rust-analyzer/src/cli/ssr.rs b/crates/rust-analyzer/src/cli/ssr.rs
index 79f426fff..1fd9b5a9b 100644
--- a/crates/rust-analyzer/src/cli/ssr.rs
+++ b/crates/rust-analyzer/src/cli/ssr.rs
@@ -9,8 +9,11 @@ use ide_ssr::{MatchFinder, SsrPattern, SsrRule};
9pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> { 9pub fn apply_ssr_rules(rules: Vec<SsrRule>) -> Result<()> {
10 use ide_db::base_db::SourceDatabaseExt; 10 use ide_db::base_db::SourceDatabaseExt;
11 let cargo_config = Default::default(); 11 let cargo_config = Default::default();
12 let load_cargo_config = 12 let load_cargo_config = LoadCargoConfig {
13 LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: true }; 13 load_out_dirs_from_check: true,
14 wrap_rustc: false,
15 with_proc_macro: true,
16 };
14 let (host, vfs, _proc_macro) = 17 let (host, vfs, _proc_macro) =
15 load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; 18 load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?;
16 let db = host.raw_database(); 19 let db = host.raw_database();
@@ -37,7 +40,7 @@ pub fn search_for_patterns(patterns: Vec<SsrPattern>, debug_snippet: Option<Stri
37 use ide_db::symbol_index::SymbolsDatabase; 40 use ide_db::symbol_index::SymbolsDatabase;
38 let cargo_config = Default::default(); 41 let cargo_config = Default::default();
39 let load_cargo_config = 42 let load_cargo_config =
40 LoadCargoConfig { load_out_dirs_from_check: true, with_proc_macro: true }; 43 LoadCargoConfig { load_out_dirs_from_check: true, wrap_rustc: true, with_proc_macro: true };
41 let (host, _vfs, _proc_macro) = 44 let (host, _vfs, _proc_macro) =
42 load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?; 45 load_workspace_at(&std::env::current_dir()?, &cargo_config, &load_cargo_config, &|_| {})?;
43 let db = host.raw_database(); 46 let db = host.raw_database();
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index cda272fd4..1109d2daf 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -17,7 +17,7 @@ use ide_db::helpers::{
17}; 17};
18use lsp_types::{ClientCapabilities, MarkupKind}; 18use lsp_types::{ClientCapabilities, MarkupKind};
19use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource}; 19use project_model::{CargoConfig, ProjectJson, ProjectJsonData, ProjectManifest, RustcSource};
20use rustc_hash::FxHashSet; 20use rustc_hash::{FxHashMap, FxHashSet};
21use serde::{de::DeserializeOwned, Deserialize}; 21use serde::{de::DeserializeOwned, Deserialize};
22use vfs::AbsPathBuf; 22use vfs::AbsPathBuf;
23 23
@@ -48,6 +48,9 @@ config_data! {
48 /// Run build scripts (`build.rs`) for more precise code analysis. 48 /// Run build scripts (`build.rs`) for more precise code analysis.
49 cargo_runBuildScripts | 49 cargo_runBuildScripts |
50 cargo_loadOutDirsFromCheck: bool = "true", 50 cargo_loadOutDirsFromCheck: bool = "true",
51 /// Use `RUSTC_WRAPPER=rust-analyzer` when running build scripts to
52 /// avoid compiling unnecessary things.
53 cargo_useRustcWrapperForBuildScripts: bool = "true",
51 /// Do not activate the `default` feature. 54 /// Do not activate the `default` feature.
52 cargo_noDefaultFeatures: bool = "false", 55 cargo_noDefaultFeatures: bool = "false",
53 /// Compilation target (target triple). 56 /// Compilation target (target triple).
@@ -96,6 +99,9 @@ config_data! {
96 diagnostics_enableExperimental: bool = "true", 99 diagnostics_enableExperimental: bool = "true",
97 /// List of rust-analyzer diagnostics to disable. 100 /// List of rust-analyzer diagnostics to disable.
98 diagnostics_disabled: FxHashSet<String> = "[]", 101 diagnostics_disabled: FxHashSet<String> = "[]",
102 /// Map of prefixes to be substituted when parsing diagnostic file paths.
103 /// This should be the reverse mapping of what is passed to `rustc` as `--remap-path-prefix`.
104 diagnostics_remapPrefix: FxHashMap<String, String> = "{}",
99 /// List of warnings that should be displayed with info severity. 105 /// List of warnings that should be displayed with info severity.
100 /// 106 ///
101 /// The warnings will be indicated by a blue squiggly underline in code 107 /// The warnings will be indicated by a blue squiggly underline in code
@@ -397,6 +403,17 @@ impl Config {
397 pub fn will_rename(&self) -> bool { 403 pub fn will_rename(&self) -> bool {
398 try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false) 404 try_or!(self.caps.workspace.as_ref()?.file_operations.as_ref()?.will_rename?, false)
399 } 405 }
406 pub fn change_annotation_support(&self) -> bool {
407 try_!(self
408 .caps
409 .workspace
410 .as_ref()?
411 .workspace_edit
412 .as_ref()?
413 .change_annotation_support
414 .as_ref()?)
415 .is_some()
416 }
400 pub fn code_action_resolve(&self) -> bool { 417 pub fn code_action_resolve(&self) -> bool {
401 try_or!( 418 try_or!(
402 self.caps 419 self.caps
@@ -445,8 +462,8 @@ impl Config {
445 pub fn hover_actions(&self) -> bool { 462 pub fn hover_actions(&self) -> bool {
446 self.experimental("hoverActions") 463 self.experimental("hoverActions")
447 } 464 }
448 pub fn status_notification(&self) -> bool { 465 pub fn server_status_notification(&self) -> bool {
449 self.experimental("statusNotification") 466 self.experimental("serverStatusNotification")
450 } 467 }
451 468
452 pub fn publish_diagnostics(&self) -> bool { 469 pub fn publish_diagnostics(&self) -> bool {
@@ -460,6 +477,7 @@ impl Config {
460 } 477 }
461 pub fn diagnostics_map(&self) -> DiagnosticsMapConfig { 478 pub fn diagnostics_map(&self) -> DiagnosticsMapConfig {
462 DiagnosticsMapConfig { 479 DiagnosticsMapConfig {
480 remap_prefix: self.data.diagnostics_remapPrefix.clone(),
463 warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(), 481 warnings_as_info: self.data.diagnostics_warningsAsInfo.clone(),
464 warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(), 482 warnings_as_hint: self.data.diagnostics_warningsAsHint.clone(),
465 } 483 }
@@ -493,6 +511,9 @@ impl Config {
493 pub fn run_build_scripts(&self) -> bool { 511 pub fn run_build_scripts(&self) -> bool {
494 self.data.cargo_runBuildScripts || self.data.procMacro_enable 512 self.data.cargo_runBuildScripts || self.data.procMacro_enable
495 } 513 }
514 pub fn wrap_rustc(&self) -> bool {
515 self.data.cargo_useRustcWrapperForBuildScripts
516 }
496 pub fn cargo(&self) -> CargoConfig { 517 pub fn cargo(&self) -> CargoConfig {
497 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { 518 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| {
498 if rustc_src == "discover" { 519 if rustc_src == "discover" {
@@ -656,6 +677,19 @@ impl Config {
656 pub fn code_lens_refresh(&self) -> bool { 677 pub fn code_lens_refresh(&self) -> bool {
657 try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false) 678 try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false)
658 } 679 }
680 pub fn insert_replace_support(&self) -> bool {
681 try_or!(
682 self.caps
683 .text_document
684 .as_ref()?
685 .completion
686 .as_ref()?
687 .completion_item
688 .as_ref()?
689 .insert_replace_support?,
690 false
691 )
692 }
659} 693}
660 694
661#[derive(Deserialize, Debug, Clone)] 695#[derive(Deserialize, Debug, Clone)]
@@ -805,6 +839,9 @@ fn field_props(field: &str, ty: &str, doc: &[&str], default: &str) -> serde_json
805 "items": { "type": "string" }, 839 "items": { "type": "string" },
806 "uniqueItems": true, 840 "uniqueItems": true,
807 }, 841 },
842 "FxHashMap<String, String>" => set! {
843 "type": "object",
844 },
808 "Option<usize>" => set! { 845 "Option<usize>" => set! {
809 "type": ["null", "integer"], 846 "type": ["null", "integer"],
810 "minimum": 0, 847 "minimum": 0,
diff --git a/crates/rust-analyzer/src/diagnostics.rs b/crates/rust-analyzer/src/diagnostics.rs
index f01548c50..d4b9db362 100644
--- a/crates/rust-analyzer/src/diagnostics.rs
+++ b/crates/rust-analyzer/src/diagnostics.rs
@@ -12,6 +12,7 @@ pub(crate) type CheckFixes = Arc<FxHashMap<FileId, Vec<Fix>>>;
12 12
13#[derive(Debug, Default, Clone)] 13#[derive(Debug, Default, Clone)]
14pub struct DiagnosticsMapConfig { 14pub struct DiagnosticsMapConfig {
15 pub remap_prefix: FxHashMap<String, String>,
15 pub warnings_as_info: Vec<String>, 16 pub warnings_as_info: Vec<String>,
16 pub warnings_as_hint: Vec<String>, 17 pub warnings_as_hint: Vec<String>,
17} 18}
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
index 23ec2efba..227d96d51 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/clippy_pass_by_ref.txt
@@ -326,6 +326,7 @@
326 }, 326 },
327 ), 327 ),
328 document_changes: None, 328 document_changes: None,
329 change_annotations: None,
329 }, 330 },
330 ), 331 ),
331 is_preferred: Some( 332 is_preferred: Some(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
index b6acb5f42..f8adfad3b 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable.txt
@@ -179,6 +179,7 @@
179 }, 179 },
180 ), 180 ),
181 document_changes: None, 181 document_changes: None,
182 change_annotations: None,
182 }, 183 },
183 ), 184 ),
184 is_preferred: Some( 185 is_preferred: Some(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
index d765257c4..5a70d2ed7 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_hint.txt
@@ -179,6 +179,7 @@
179 }, 179 },
180 ), 180 ),
181 document_changes: None, 181 document_changes: None,
182 change_annotations: None,
182 }, 183 },
183 ), 184 ),
184 is_preferred: Some( 185 is_preferred: Some(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
index 6b0d94878..04ca0c9c2 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/rustc_unused_variable_as_info.txt
@@ -179,6 +179,7 @@
179 }, 179 },
180 ), 180 ),
181 document_changes: None, 181 document_changes: None,
182 change_annotations: None,
182 }, 183 },
183 ), 184 ),
184 is_preferred: Some( 185 is_preferred: Some(
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
index a0cfb8d33..57d2f1ae3 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/snap_multi_line_fix.txt
@@ -339,6 +339,7 @@
339 }, 339 },
340 ), 340 ),
341 document_changes: None, 341 document_changes: None,
342 change_annotations: None,
342 }, 343 },
343 ), 344 ),
344 is_preferred: Some( 345 is_preferred: Some(
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index e2f319f6b..82dd0da9a 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -1,6 +1,9 @@
1//! This module provides the functionality needed to convert diagnostics from 1//! This module provides the functionality needed to convert diagnostics from
2//! `cargo check` json format to the LSP diagnostic format. 2//! `cargo check` json format to the LSP diagnostic format.
3use std::{collections::HashMap, path::Path}; 3use std::{
4 collections::HashMap,
5 path::{Path, PathBuf},
6};
4 7
5use flycheck::{DiagnosticLevel, DiagnosticSpan}; 8use flycheck::{DiagnosticLevel, DiagnosticSpan};
6use stdx::format_to; 9use stdx::format_to;
@@ -41,8 +44,12 @@ fn is_dummy_macro_file(file_name: &str) -> bool {
41} 44}
42 45
43/// Converts a Rust span to a LSP location 46/// Converts a Rust span to a LSP location
44fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { 47fn location(
45 let file_name = workspace_root.join(&span.file_name); 48 config: &DiagnosticsMapConfig,
49 workspace_root: &Path,
50 span: &DiagnosticSpan,
51) -> lsp_types::Location {
52 let file_name = resolve_path(config, workspace_root, &span.file_name);
46 let uri = url_from_abs_path(&file_name); 53 let uri = url_from_abs_path(&file_name);
47 54
48 // FIXME: this doesn't handle UTF16 offsets correctly 55 // FIXME: this doesn't handle UTF16 offsets correctly
@@ -58,32 +65,50 @@ fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location
58/// 65///
59/// This takes locations pointing into the standard library, or generally outside the current 66/// This takes locations pointing into the standard library, or generally outside the current
60/// workspace into account and tries to avoid those, in case macros are involved. 67/// workspace into account and tries to avoid those, in case macros are involved.
61fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { 68fn primary_location(
69 config: &DiagnosticsMapConfig,
70 workspace_root: &Path,
71 span: &DiagnosticSpan,
72) -> lsp_types::Location {
62 let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span)); 73 let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span));
63 for span in span_stack.clone() { 74 for span in span_stack.clone() {
64 let abs_path = workspace_root.join(&span.file_name); 75 let abs_path = resolve_path(config, workspace_root, &span.file_name);
65 if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) { 76 if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) {
66 return location(workspace_root, span); 77 return location(config, workspace_root, span);
67 } 78 }
68 } 79 }
69 80
70 // Fall back to the outermost macro invocation if no suitable span comes up. 81 // Fall back to the outermost macro invocation if no suitable span comes up.
71 let last_span = span_stack.last().unwrap(); 82 let last_span = span_stack.last().unwrap();
72 location(workspace_root, last_span) 83 location(config, workspace_root, last_span)
73} 84}
74 85
75/// Converts a secondary Rust span to a LSP related information 86/// Converts a secondary Rust span to a LSP related information
76/// 87///
77/// If the span is unlabelled this will return `None`. 88/// If the span is unlabelled this will return `None`.
78fn diagnostic_related_information( 89fn diagnostic_related_information(
90 config: &DiagnosticsMapConfig,
79 workspace_root: &Path, 91 workspace_root: &Path,
80 span: &DiagnosticSpan, 92 span: &DiagnosticSpan,
81) -> Option<lsp_types::DiagnosticRelatedInformation> { 93) -> Option<lsp_types::DiagnosticRelatedInformation> {
82 let message = span.label.clone()?; 94 let message = span.label.clone()?;
83 let location = location(workspace_root, span); 95 let location = location(config, workspace_root, span);
84 Some(lsp_types::DiagnosticRelatedInformation { location, message }) 96 Some(lsp_types::DiagnosticRelatedInformation { location, message })
85} 97}
86 98
99/// Resolves paths applying any matching path prefix remappings, and then
100/// joining the path to the workspace root.
101fn resolve_path(config: &DiagnosticsMapConfig, workspace_root: &Path, file_name: &str) -> PathBuf {
102 match config
103 .remap_prefix
104 .iter()
105 .find_map(|(from, to)| file_name.strip_prefix(from).map(|file_name| (to, file_name)))
106 {
107 Some((to, file_name)) => workspace_root.join(format!("{}{}", to, file_name)),
108 None => workspace_root.join(file_name),
109 }
110}
111
87struct SubDiagnostic { 112struct SubDiagnostic {
88 related: lsp_types::DiagnosticRelatedInformation, 113 related: lsp_types::DiagnosticRelatedInformation,
89 suggested_fix: Option<lsp_ext::CodeAction>, 114 suggested_fix: Option<lsp_ext::CodeAction>,
@@ -95,6 +120,7 @@ enum MappedRustChildDiagnostic {
95} 120}
96 121
97fn map_rust_child_diagnostic( 122fn map_rust_child_diagnostic(
123 config: &DiagnosticsMapConfig,
98 workspace_root: &Path, 124 workspace_root: &Path,
99 rd: &flycheck::Diagnostic, 125 rd: &flycheck::Diagnostic,
100) -> MappedRustChildDiagnostic { 126) -> MappedRustChildDiagnostic {
@@ -108,7 +134,7 @@ fn map_rust_child_diagnostic(
108 let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new(); 134 let mut edit_map: HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>> = HashMap::new();
109 for &span in &spans { 135 for &span in &spans {
110 if let Some(suggested_replacement) = &span.suggested_replacement { 136 if let Some(suggested_replacement) = &span.suggested_replacement {
111 let location = location(workspace_root, span); 137 let location = location(config, workspace_root, span);
112 let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone()); 138 let edit = lsp_types::TextEdit::new(location.range, suggested_replacement.clone());
113 edit_map.entry(location.uri).or_default().push(edit); 139 edit_map.entry(location.uri).or_default().push(edit);
114 } 140 }
@@ -117,7 +143,7 @@ fn map_rust_child_diagnostic(
117 if edit_map.is_empty() { 143 if edit_map.is_empty() {
118 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { 144 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
119 related: lsp_types::DiagnosticRelatedInformation { 145 related: lsp_types::DiagnosticRelatedInformation {
120 location: location(workspace_root, spans[0]), 146 location: location(config, workspace_root, spans[0]),
121 message: rd.message.clone(), 147 message: rd.message.clone(),
122 }, 148 },
123 suggested_fix: None, 149 suggested_fix: None,
@@ -125,7 +151,7 @@ fn map_rust_child_diagnostic(
125 } else { 151 } else {
126 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic { 152 MappedRustChildDiagnostic::SubDiagnostic(SubDiagnostic {
127 related: lsp_types::DiagnosticRelatedInformation { 153 related: lsp_types::DiagnosticRelatedInformation {
128 location: location(workspace_root, spans[0]), 154 location: location(config, workspace_root, spans[0]),
129 message: rd.message.clone(), 155 message: rd.message.clone(),
130 }, 156 },
131 suggested_fix: Some(lsp_ext::CodeAction { 157 suggested_fix: Some(lsp_ext::CodeAction {
@@ -136,6 +162,7 @@ fn map_rust_child_diagnostic(
136 // FIXME: there's no good reason to use edit_map here.... 162 // FIXME: there's no good reason to use edit_map here....
137 changes: Some(edit_map), 163 changes: Some(edit_map),
138 document_changes: None, 164 document_changes: None,
165 change_annotations: None,
139 }), 166 }),
140 is_preferred: Some(true), 167 is_preferred: Some(true),
141 data: None, 168 data: None,
@@ -189,7 +216,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
189 let mut tags = Vec::new(); 216 let mut tags = Vec::new();
190 217
191 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) { 218 for secondary_span in rd.spans.iter().filter(|s| !s.is_primary) {
192 let related = diagnostic_related_information(workspace_root, secondary_span); 219 let related = diagnostic_related_information(config, workspace_root, secondary_span);
193 if let Some(related) = related { 220 if let Some(related) = related {
194 subdiagnostics.push(SubDiagnostic { related, suggested_fix: None }); 221 subdiagnostics.push(SubDiagnostic { related, suggested_fix: None });
195 } 222 }
@@ -197,7 +224,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
197 224
198 let mut message = rd.message.clone(); 225 let mut message = rd.message.clone();
199 for child in &rd.children { 226 for child in &rd.children {
200 let child = map_rust_child_diagnostic(workspace_root, &child); 227 let child = map_rust_child_diagnostic(config, workspace_root, &child);
201 match child { 228 match child {
202 MappedRustChildDiagnostic::SubDiagnostic(sub) => { 229 MappedRustChildDiagnostic::SubDiagnostic(sub) => {
203 subdiagnostics.push(sub); 230 subdiagnostics.push(sub);
@@ -241,7 +268,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
241 primary_spans 268 primary_spans
242 .iter() 269 .iter()
243 .flat_map(|primary_span| { 270 .flat_map(|primary_span| {
244 let primary_location = primary_location(workspace_root, &primary_span); 271 let primary_location = primary_location(config, workspace_root, &primary_span);
245 272
246 let mut message = message.clone(); 273 let mut message = message.clone();
247 if needs_primary_span_label { 274 if needs_primary_span_label {
@@ -271,7 +298,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
271 // generated that code. 298 // generated that code.
272 let is_in_macro_call = i != 0; 299 let is_in_macro_call = i != 0;
273 300
274 let secondary_location = location(workspace_root, &span); 301 let secondary_location = location(config, workspace_root, &span);
275 if secondary_location == primary_location { 302 if secondary_location == primary_location {
276 continue; 303 continue;
277 } 304 }
diff --git a/crates/rust-analyzer/src/from_proto.rs b/crates/rust-analyzer/src/from_proto.rs
index 5b02b2598..712d5a9c2 100644
--- a/crates/rust-analyzer/src/from_proto.rs
+++ b/crates/rust-analyzer/src/from_proto.rs
@@ -42,27 +42,27 @@ pub(crate) fn text_range(line_index: &LineIndex, range: lsp_types::Range) -> Tex
42 TextRange::new(start, end) 42 TextRange::new(start, end)
43} 43}
44 44
45pub(crate) fn file_id(world: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> { 45pub(crate) fn file_id(snap: &GlobalStateSnapshot, url: &lsp_types::Url) -> Result<FileId> {
46 world.url_to_file_id(url) 46 snap.url_to_file_id(url)
47} 47}
48 48
49pub(crate) fn file_position( 49pub(crate) fn file_position(
50 world: &GlobalStateSnapshot, 50 snap: &GlobalStateSnapshot,
51 tdpp: lsp_types::TextDocumentPositionParams, 51 tdpp: lsp_types::TextDocumentPositionParams,
52) -> Result<FilePosition> { 52) -> Result<FilePosition> {
53 let file_id = file_id(world, &tdpp.text_document.uri)?; 53 let file_id = file_id(snap, &tdpp.text_document.uri)?;
54 let line_index = world.file_line_index(file_id)?; 54 let line_index = snap.file_line_index(file_id)?;
55 let offset = offset(&line_index, tdpp.position); 55 let offset = offset(&line_index, tdpp.position);
56 Ok(FilePosition { file_id, offset }) 56 Ok(FilePosition { file_id, offset })
57} 57}
58 58
59pub(crate) fn file_range( 59pub(crate) fn file_range(
60 world: &GlobalStateSnapshot, 60 snap: &GlobalStateSnapshot,
61 text_document_identifier: lsp_types::TextDocumentIdentifier, 61 text_document_identifier: lsp_types::TextDocumentIdentifier,
62 range: lsp_types::Range, 62 range: lsp_types::Range,
63) -> Result<FileRange> { 63) -> Result<FileRange> {
64 let file_id = file_id(world, &text_document_identifier.uri)?; 64 let file_id = file_id(snap, &text_document_identifier.uri)?;
65 let line_index = world.file_line_index(file_id)?; 65 let line_index = snap.file_line_index(file_id)?;
66 let range = text_range(&line_index, range); 66 let range = text_range(&line_index, range);
67 Ok(FileRange { file_id, range }) 67 Ok(FileRange { file_id, range })
68} 68}
@@ -82,7 +82,7 @@ pub(crate) fn assist_kind(kind: lsp_types::CodeActionKind) -> Option<AssistKind>
82} 82}
83 83
84pub(crate) fn annotation( 84pub(crate) fn annotation(
85 world: &GlobalStateSnapshot, 85 snap: &GlobalStateSnapshot,
86 code_lens: lsp_types::CodeLens, 86 code_lens: lsp_types::CodeLens,
87) -> Result<Annotation> { 87) -> Result<Annotation> {
88 let data = code_lens.data.unwrap(); 88 let data = code_lens.data.unwrap();
@@ -91,25 +91,25 @@ pub(crate) fn annotation(
91 match resolve { 91 match resolve {
92 lsp_ext::CodeLensResolveData::Impls(params) => { 92 lsp_ext::CodeLensResolveData::Impls(params) => {
93 let file_id = 93 let file_id =
94 world.url_to_file_id(&params.text_document_position_params.text_document.uri)?; 94 snap.url_to_file_id(&params.text_document_position_params.text_document.uri)?;
95 let line_index = world.file_line_index(file_id)?; 95 let line_index = snap.file_line_index(file_id)?;
96 96
97 Ok(Annotation { 97 Ok(Annotation {
98 range: text_range(&line_index, code_lens.range), 98 range: text_range(&line_index, code_lens.range),
99 kind: AnnotationKind::HasImpls { 99 kind: AnnotationKind::HasImpls {
100 position: file_position(world, params.text_document_position_params)?, 100 position: file_position(snap, params.text_document_position_params)?,
101 data: None, 101 data: None,
102 }, 102 },
103 }) 103 })
104 } 104 }
105 lsp_ext::CodeLensResolveData::References(params) => { 105 lsp_ext::CodeLensResolveData::References(params) => {
106 let file_id = world.url_to_file_id(&params.text_document.uri)?; 106 let file_id = snap.url_to_file_id(&params.text_document.uri)?;
107 let line_index = world.file_line_index(file_id)?; 107 let line_index = snap.file_line_index(file_id)?;
108 108
109 Ok(Annotation { 109 Ok(Annotation {
110 range: text_range(&line_index, code_lens.range), 110 range: text_range(&line_index, code_lens.range),
111 kind: AnnotationKind::HasReferences { 111 kind: AnnotationKind::HasReferences {
112 position: file_position(world, params)?, 112 position: file_position(snap, params)?,
113 data: None, 113 data: None,
114 }, 114 },
115 }) 115 })
diff --git a/crates/rust-analyzer/src/global_state.rs b/crates/rust-analyzer/src/global_state.rs
index 52c249713..adeb7a97e 100644
--- a/crates/rust-analyzer/src/global_state.rs
+++ b/crates/rust-analyzer/src/global_state.rs
@@ -23,6 +23,7 @@ use crate::{
23 document::DocumentData, 23 document::DocumentData,
24 from_proto, 24 from_proto,
25 line_index::{LineEndings, LineIndex}, 25 line_index::{LineEndings, LineIndex},
26 lsp_ext,
26 main_loop::Task, 27 main_loop::Task,
27 op_queue::OpQueue, 28 op_queue::OpQueue,
28 reload::SourceRootConfig, 29 reload::SourceRootConfig,
@@ -32,20 +33,6 @@ use crate::{
32 Result, 33 Result,
33}; 34};
34 35
35#[derive(Eq, PartialEq, Copy, Clone)]
36pub(crate) enum Status {
37 Loading,
38 Ready { partial: bool },
39 Invalid,
40 NeedsReload,
41}
42
43impl Default for Status {
44 fn default() -> Self {
45 Status::Loading
46 }
47}
48
49// Enforces drop order 36// Enforces drop order
50pub(crate) struct Handle<H, C> { 37pub(crate) struct Handle<H, C> {
51 pub(crate) handle: H, 38 pub(crate) handle: H,
@@ -67,24 +54,37 @@ pub(crate) struct GlobalState {
67 req_queue: ReqQueue, 54 req_queue: ReqQueue,
68 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>, 55 pub(crate) task_pool: Handle<TaskPool<Task>, Receiver<Task>>,
69 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>, 56 pub(crate) loader: Handle<Box<dyn vfs::loader::Handle>, Receiver<vfs::loader::Message>>,
70 pub(crate) vfs_config_version: u32,
71 pub(crate) flycheck: Vec<FlycheckHandle>,
72 pub(crate) flycheck_sender: Sender<flycheck::Message>,
73 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
74 pub(crate) config: Arc<Config>, 57 pub(crate) config: Arc<Config>,
75 pub(crate) analysis_host: AnalysisHost, 58 pub(crate) analysis_host: AnalysisHost,
76 pub(crate) diagnostics: DiagnosticCollection, 59 pub(crate) diagnostics: DiagnosticCollection,
77 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>, 60 pub(crate) mem_docs: FxHashMap<VfsPath, DocumentData>,
78 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>, 61 pub(crate) semantic_tokens_cache: Arc<Mutex<FxHashMap<Url, SemanticTokens>>>,
79 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
80 pub(crate) shutdown_requested: bool, 62 pub(crate) shutdown_requested: bool,
81 pub(crate) status: Status, 63 pub(crate) last_reported_status: Option<lsp_ext::ServerStatusParams>,
82 pub(crate) source_root_config: SourceRootConfig, 64 pub(crate) source_root_config: SourceRootConfig,
83 pub(crate) proc_macro_client: Option<ProcMacroClient>, 65 pub(crate) proc_macro_client: Option<ProcMacroClient>,
66
67 pub(crate) flycheck: Vec<FlycheckHandle>,
68 pub(crate) flycheck_sender: Sender<flycheck::Message>,
69 pub(crate) flycheck_receiver: Receiver<flycheck::Message>,
70
71 pub(crate) vfs: Arc<RwLock<(vfs::Vfs, FxHashMap<FileId, LineEndings>)>>,
72 pub(crate) vfs_config_version: u32,
73 pub(crate) vfs_progress_config_version: u32,
74 pub(crate) vfs_progress_n_total: usize,
75 pub(crate) vfs_progress_n_done: usize,
76
77 /// For both `workspaces` and `workspace_build_data`, the field stores the
78 /// data we actually use, while the `OpQueue` stores the result of the last
79 /// fetch.
80 ///
81 /// If the fetch (partially) fails, we do not update the values.
84 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>, 82 pub(crate) workspaces: Arc<Vec<ProjectWorkspace>>,
85 pub(crate) fetch_workspaces_queue: OpQueue<()>, 83 pub(crate) fetch_workspaces_queue: OpQueue<(), Vec<anyhow::Result<ProjectWorkspace>>>,
86 pub(crate) workspace_build_data: Option<BuildDataResult>, 84 pub(crate) workspace_build_data: Option<BuildDataResult>,
87 pub(crate) fetch_build_data_queue: OpQueue<BuildDataCollector>, 85 pub(crate) fetch_build_data_queue:
86 OpQueue<BuildDataCollector, Option<anyhow::Result<BuildDataResult>>>,
87
88 latest_requests: Arc<RwLock<LatestRequests>>, 88 latest_requests: Arc<RwLock<LatestRequests>>,
89} 89}
90 90
@@ -121,25 +121,32 @@ impl GlobalState {
121 GlobalState { 121 GlobalState {
122 sender, 122 sender,
123 req_queue: ReqQueue::default(), 123 req_queue: ReqQueue::default(),
124 vfs_config_version: 0,
125 task_pool, 124 task_pool,
126 loader, 125 loader,
127 flycheck: Vec::new(),
128 flycheck_sender,
129 flycheck_receiver,
130 config: Arc::new(config), 126 config: Arc::new(config),
131 analysis_host, 127 analysis_host,
132 diagnostics: Default::default(), 128 diagnostics: Default::default(),
133 mem_docs: FxHashMap::default(), 129 mem_docs: FxHashMap::default(),
134 semantic_tokens_cache: Arc::new(Default::default()), 130 semantic_tokens_cache: Arc::new(Default::default()),
135 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
136 shutdown_requested: false, 131 shutdown_requested: false,
137 status: Status::default(), 132 last_reported_status: None,
138 source_root_config: SourceRootConfig::default(), 133 source_root_config: SourceRootConfig::default(),
139 proc_macro_client: None, 134 proc_macro_client: None,
135
136 flycheck: Vec::new(),
137 flycheck_sender,
138 flycheck_receiver,
139
140 vfs: Arc::new(RwLock::new((vfs::Vfs::default(), FxHashMap::default()))),
141 vfs_config_version: 0,
142 vfs_progress_config_version: 0,
143 vfs_progress_n_total: 0,
144 vfs_progress_n_done: 0,
145
140 workspaces: Arc::new(Vec::new()), 146 workspaces: Arc::new(Vec::new()),
141 fetch_workspaces_queue: OpQueue::default(), 147 fetch_workspaces_queue: OpQueue::default(),
142 workspace_build_data: None, 148 workspace_build_data: None,
149
143 fetch_build_data_queue: OpQueue::default(), 150 fetch_build_data_queue: OpQueue::default(),
144 latest_requests: Default::default(), 151 latest_requests: Default::default(),
145 } 152 }
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 53d29ddfc..1f59402e5 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -17,7 +17,7 @@ use lsp_server::ErrorCode;
17use lsp_types::{ 17use lsp_types::{
18 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem, 18 CallHierarchyIncomingCall, CallHierarchyIncomingCallsParams, CallHierarchyItem,
19 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams, 19 CallHierarchyOutgoingCall, CallHierarchyOutgoingCallsParams, CallHierarchyPrepareParams,
20 CodeActionKind, CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams, 20 CodeLens, CompletionItem, Diagnostic, DiagnosticTag, DocumentFormattingParams,
21 DocumentHighlight, FoldingRange, FoldingRangeParams, HoverContents, Location, NumberOrString, 21 DocumentHighlight, FoldingRange, FoldingRangeParams, HoverContents, Location, NumberOrString,
22 Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams, 22 Position, PrepareRenameResponse, Range, RenameParams, SemanticTokensDeltaParams,
23 SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams, 23 SemanticTokensFullDeltaResult, SemanticTokensParams, SemanticTokensRangeParams,
@@ -36,7 +36,7 @@ use crate::{
36 diff::diff, 36 diff::diff,
37 from_proto, 37 from_proto,
38 global_state::{GlobalState, GlobalStateSnapshot}, 38 global_state::{GlobalState, GlobalStateSnapshot},
39 line_index::{LineEndings, LineIndex}, 39 line_index::LineEndings,
40 lsp_ext::{self, InlayHint, InlayHintsParams}, 40 lsp_ext::{self, InlayHint, InlayHintsParams},
41 lsp_utils::all_edits_are_disjoint, 41 lsp_utils::all_edits_are_disjoint,
42 to_proto, LspError, Result, 42 to_proto, LspError, Result,
@@ -231,7 +231,6 @@ pub(crate) fn handle_on_enter(
231 Ok(Some(edit)) 231 Ok(Some(edit))
232} 232}
233 233
234// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
235pub(crate) fn handle_on_type_formatting( 234pub(crate) fn handle_on_type_formatting(
236 snap: GlobalStateSnapshot, 235 snap: GlobalStateSnapshot,
237 params: lsp_types::DocumentOnTypeFormattingParams, 236 params: lsp_types::DocumentOnTypeFormattingParams,
@@ -665,10 +664,13 @@ pub(crate) fn handle_completion(
665 }; 664 };
666 let line_index = snap.file_line_index(position.file_id)?; 665 let line_index = snap.file_line_index(position.file_id)?;
667 666
667 let insert_replace_support =
668 snap.config.insert_replace_support().then(|| text_document_position.position);
668 let items: Vec<CompletionItem> = items 669 let items: Vec<CompletionItem> = items
669 .into_iter() 670 .into_iter()
670 .flat_map(|item| { 671 .flat_map(|item| {
671 let mut new_completion_items = to_proto::completion_item(&line_index, item.clone()); 672 let mut new_completion_items =
673 to_proto::completion_item(insert_replace_support, &line_index, item.clone());
672 674
673 if completion_config.enable_imports_on_the_fly { 675 if completion_config.enable_imports_on_the_fly {
674 for new_item in &mut new_completion_items { 676 for new_item in &mut new_completion_items {
@@ -927,19 +929,22 @@ pub(crate) fn handle_formatting(
927 let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default(); 929 let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
928 930
929 if !output.status.success() { 931 if !output.status.success() {
930 match output.status.code() { 932 let rustfmt_not_installed =
931 Some(1) if !captured_stderr.contains("not installed") => { 933 captured_stderr.contains("not installed") || captured_stderr.contains("not available");
934
935 return match output.status.code() {
936 Some(1) if !rustfmt_not_installed => {
932 // While `rustfmt` doesn't have a specific exit code for parse errors this is the 937 // While `rustfmt` doesn't have a specific exit code for parse errors this is the
933 // likely cause exiting with 1. Most Language Servers swallow parse errors on 938 // likely cause exiting with 1. Most Language Servers swallow parse errors on
934 // formatting because otherwise an error is surfaced to the user on top of the 939 // formatting because otherwise an error is surfaced to the user on top of the
935 // syntax error diagnostics they're already receiving. This is especially jarring 940 // syntax error diagnostics they're already receiving. This is especially jarring
936 // if they have format on save enabled. 941 // if they have format on save enabled.
937 log::info!("rustfmt exited with status 1, assuming parse error and ignoring"); 942 log::info!("rustfmt exited with status 1, assuming parse error and ignoring");
938 return Ok(None); 943 Ok(None)
939 } 944 }
940 _ => { 945 _ => {
941 // Something else happened - e.g. `rustfmt` is missing or caught a signal 946 // Something else happened - e.g. `rustfmt` is missing or caught a signal
942 return Err(LspError::new( 947 Err(LspError::new(
943 -32900, 948 -32900,
944 format!( 949 format!(
945 r#"rustfmt exited with: 950 r#"rustfmt exited with:
@@ -949,9 +954,9 @@ pub(crate) fn handle_formatting(
949 output.status, captured_stdout, captured_stderr, 954 output.status, captured_stdout, captured_stderr,
950 ), 955 ),
951 ) 956 )
952 .into()); 957 .into())
953 } 958 }
954 } 959 };
955 } 960 }
956 961
957 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); 962 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
@@ -977,84 +982,52 @@ pub(crate) fn handle_code_action(
977 params: lsp_types::CodeActionParams, 982 params: lsp_types::CodeActionParams,
978) -> Result<Option<Vec<lsp_ext::CodeAction>>> { 983) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
979 let _p = profile::span("handle_code_action"); 984 let _p = profile::span("handle_code_action");
980 // We intentionally don't support command-based actions, as those either 985
981 // requires custom client-code anyway, or requires server-initiated edits.
982 // Server initiated edits break causality, so we avoid those as well.
983 if !snap.config.code_action_literals() { 986 if !snap.config.code_action_literals() {
987 // We intentionally don't support command-based actions, as those either
988 // require either custom client-code or server-initiated edits. Server
989 // initiated edits break causality, so we avoid those.
984 return Ok(None); 990 return Ok(None);
985 } 991 }
986 992
987 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 993 let line_index =
988 let line_index = snap.file_line_index(file_id)?; 994 snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
989 let range = from_proto::text_range(&line_index, params.range); 995 let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
990 let frange = FileRange { file_id, range };
991 996
992 let mut assists_config = snap.config.assist(); 997 let mut assists_config = snap.config.assist();
993 assists_config.allowed = params 998 assists_config.allowed = params
994 .clone()
995 .context 999 .context
996 .only 1000 .only
1001 .clone()
997 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); 1002 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
998 1003
999 let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); 1004 let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
1000 1005
1001 let include_quick_fixes = match &params.context.only { 1006 let code_action_resolve_cap = snap.config.code_action_resolve();
1002 Some(v) => v.iter().any(|it| { 1007 let assists = snap.analysis.assists_with_fixes(
1003 it == &lsp_types::CodeActionKind::EMPTY || it == &lsp_types::CodeActionKind::QUICKFIX 1008 &assists_config,
1004 }), 1009 &snap.config.diagnostics(),
1005 None => true, 1010 !code_action_resolve_cap,
1006 }; 1011 frange,
1007 if include_quick_fixes { 1012 )?;
1008 add_quick_fixes(&snap, frange, &line_index, &mut res)?; 1013 for (index, assist) in assists.into_iter().enumerate() {
1009 } 1014 let resolve_data =
1010 1015 if code_action_resolve_cap { Some((index, params.clone())) } else { None };
1011 if snap.config.code_action_resolve() { 1016 let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
1012 for (index, assist) in 1017 res.push(code_action)
1013 snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate()
1014 {
1015 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?);
1016 }
1017 } else {
1018 for assist in snap.analysis.assists(&assists_config, true, frange)?.into_iter() {
1019 res.push(to_proto::resolved_code_action(&snap, assist)?);
1020 }
1021 }
1022
1023 Ok(Some(res))
1024}
1025
1026fn add_quick_fixes(
1027 snap: &GlobalStateSnapshot,
1028 frange: FileRange,
1029 line_index: &LineIndex,
1030 acc: &mut Vec<lsp_ext::CodeAction>,
1031) -> Result<()> {
1032 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?;
1033
1034 for fix in diagnostics
1035 .into_iter()
1036 .filter_map(|d| d.fix)
1037 .filter(|fix| fix.fix_trigger_range.intersect(frange.range).is_some())
1038 {
1039 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
1040 let action = lsp_ext::CodeAction {
1041 title: fix.label.to_string(),
1042 group: None,
1043 kind: Some(CodeActionKind::QUICKFIX),
1044 edit: Some(edit),
1045 is_preferred: Some(false),
1046 data: None,
1047 };
1048 acc.push(action);
1049 } 1018 }
1050 1019
1020 // Fixes from `cargo check`.
1051 for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() { 1021 for fix in snap.check_fixes.get(&frange.file_id).into_iter().flatten() {
1022 // FIXME: this mapping is awkward and shouldn't exist. Refactor
1023 // `snap.check_fixes` to not convert to LSP prematurely.
1052 let fix_range = from_proto::text_range(&line_index, fix.range); 1024 let fix_range = from_proto::text_range(&line_index, fix.range);
1053 if fix_range.intersect(frange.range).is_some() { 1025 if fix_range.intersect(frange.range).is_some() {
1054 acc.push(fix.action.clone()); 1026 res.push(fix.action.clone());
1055 } 1027 }
1056 } 1028 }
1057 Ok(()) 1029
1030 Ok(Some(res))
1058} 1031}
1059 1032
1060pub(crate) fn handle_code_action_resolve( 1033pub(crate) fn handle_code_action_resolve(
@@ -1079,12 +1052,18 @@ pub(crate) fn handle_code_action_resolve(
1079 .only 1052 .only
1080 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect()); 1053 .map(|it| it.into_iter().filter_map(from_proto::assist_kind).collect());
1081 1054
1082 let assists = snap.analysis.assists(&assists_config, true, frange)?; 1055 let assists = snap.analysis.assists_with_fixes(
1056 &assists_config,
1057 &snap.config.diagnostics(),
1058 true,
1059 frange,
1060 )?;
1061
1083 let (id, index) = split_once(&params.id, ':').unwrap(); 1062 let (id, index) = split_once(&params.id, ':').unwrap();
1084 let index = index.parse::<usize>().unwrap(); 1063 let index = index.parse::<usize>().unwrap();
1085 let assist = &assists[index]; 1064 let assist = &assists[index];
1086 assert!(assist.id.0 == id); 1065 assert!(assist.id.0 == id);
1087 let edit = to_proto::resolved_code_action(&snap, assist.clone())?.edit; 1066 let edit = to_proto::code_action(&snap, assist.clone(), None)?.edit;
1088 code_action.edit = edit; 1067 code_action.edit = edit;
1089 Ok(code_action) 1068 Ok(code_action)
1090} 1069}
@@ -1203,7 +1182,7 @@ pub(crate) fn publish_diagnostics(
1203 1182
1204 let diagnostics: Vec<Diagnostic> = snap 1183 let diagnostics: Vec<Diagnostic> = snap
1205 .analysis 1184 .analysis
1206 .diagnostics(&snap.config.diagnostics(), file_id)? 1185 .diagnostics(&snap.config.diagnostics(), false, file_id)?
1207 .into_iter() 1186 .into_iter()
1208 .map(|d| Diagnostic { 1187 .map(|d| Diagnostic {
1209 range: to_proto::range(&line_index, d.range), 1188 range: to_proto::range(&line_index, d.range),
@@ -1431,7 +1410,7 @@ pub(crate) fn handle_open_cargo_toml(
1431pub(crate) fn handle_move_item( 1410pub(crate) fn handle_move_item(
1432 snap: GlobalStateSnapshot, 1411 snap: GlobalStateSnapshot,
1433 params: lsp_ext::MoveItemParams, 1412 params: lsp_ext::MoveItemParams,
1434) -> Result<Option<lsp_types::TextDocumentEdit>> { 1413) -> Result<Vec<lsp_ext::SnippetTextEdit>> {
1435 let _p = profile::span("handle_move_item"); 1414 let _p = profile::span("handle_move_item");
1436 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 1415 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?;
1437 let range = from_proto::file_range(&snap, params.text_document, params.range)?; 1416 let range = from_proto::file_range(&snap, params.text_document, params.range)?;
@@ -1442,8 +1421,11 @@ pub(crate) fn handle_move_item(
1442 }; 1421 };
1443 1422
1444 match snap.analysis.move_item(range, direction)? { 1423 match snap.analysis.move_item(range, direction)? {
1445 Some(text_edit) => Ok(Some(to_proto::text_document_edit(&snap, file_id, text_edit)?)), 1424 Some(text_edit) => {
1446 None => Ok(None), 1425 let line_index = snap.file_line_index(file_id)?;
1426 Ok(to_proto::snippet_text_edit_vec(&line_index, true, text_edit))
1427 }
1428 None => Ok(vec![]),
1447 } 1429 }
1448} 1430}
1449 1431
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e1fec209..b8835a534 100644
--- a/crates/rust-analyzer/src/lsp_ext.rs
+++ b/crates/rust-analyzer/src/lsp_ext.rs
@@ -241,26 +241,26 @@ pub struct SsrParams {
241 pub selections: Vec<lsp_types::Range>, 241 pub selections: Vec<lsp_types::Range>,
242} 242}
243 243
244pub enum StatusNotification {} 244pub enum ServerStatusNotification {}
245 245
246#[derive(Serialize, Deserialize)] 246impl Notification for ServerStatusNotification {
247#[serde(rename_all = "camelCase")] 247 type Params = ServerStatusParams;
248pub enum Status { 248 const METHOD: &'static str = "experimental/serverStatus";
249 Loading,
250 ReadyPartial,
251 Ready,
252 NeedsReload,
253 Invalid,
254} 249}
255 250
256#[derive(Deserialize, Serialize)] 251#[derive(Deserialize, Serialize, PartialEq, Eq, Clone)]
257pub struct StatusParams { 252pub struct ServerStatusParams {
258 pub status: Status, 253 pub health: Health,
254 pub quiescent: bool,
255 pub message: Option<String>,
259} 256}
260 257
261impl Notification for StatusNotification { 258#[derive(Serialize, Deserialize, Clone, Copy, PartialEq, Eq)]
262 type Params = StatusParams; 259#[serde(rename_all = "camelCase")]
263 const METHOD: &'static str = "rust-analyzer/status"; 260pub enum Health {
261 Ok,
262 Warning,
263 Error,
264} 264}
265 265
266pub enum CodeActionRequest {} 266pub enum CodeActionRequest {}
@@ -312,6 +312,9 @@ pub struct SnippetWorkspaceEdit {
312 pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>, 312 pub changes: Option<HashMap<lsp_types::Url, Vec<lsp_types::TextEdit>>>,
313 #[serde(skip_serializing_if = "Option::is_none")] 313 #[serde(skip_serializing_if = "Option::is_none")]
314 pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>, 314 pub document_changes: Option<Vec<SnippetDocumentChangeOperation>>,
315 #[serde(skip_serializing_if = "Option::is_none")]
316 pub change_annotations:
317 Option<HashMap<lsp_types::ChangeAnnotationIdentifier, lsp_types::ChangeAnnotation>>,
315} 318}
316 319
317#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] 320#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)]
@@ -335,6 +338,9 @@ pub struct SnippetTextEdit {
335 pub new_text: String, 338 pub new_text: String,
336 #[serde(skip_serializing_if = "Option::is_none")] 339 #[serde(skip_serializing_if = "Option::is_none")]
337 pub insert_text_format: Option<lsp_types::InsertTextFormat>, 340 pub insert_text_format: Option<lsp_types::InsertTextFormat>,
341 /// The annotation id if this is an annotated
342 #[serde(skip_serializing_if = "Option::is_none")]
343 pub annotation_id: Option<lsp_types::ChangeAnnotationIdentifier>,
338} 344}
339 345
340pub enum HoverRequest {} 346pub enum HoverRequest {}
@@ -407,7 +413,7 @@ pub enum MoveItem {}
407 413
408impl Request for MoveItem { 414impl Request for MoveItem {
409 type Params = MoveItemParams; 415 type Params = MoveItemParams;
410 type Result = Option<lsp_types::TextDocumentEdit>; 416 type Result = Vec<SnippetTextEdit>;
411 const METHOD: &'static str = "experimental/moveItem"; 417 const METHOD: &'static str = "experimental/moveItem";
412} 418}
413 419
diff --git a/crates/rust-analyzer/src/lsp_utils.rs b/crates/rust-analyzer/src/lsp_utils.rs
index 2ac487632..73c4193e8 100644
--- a/crates/rust-analyzer/src/lsp_utils.rs
+++ b/crates/rust-analyzer/src/lsp_utils.rs
@@ -150,8 +150,16 @@ pub(crate) fn all_edits_are_disjoint(
150 edit_ranges.push(edit.range); 150 edit_ranges.push(edit.range);
151 } 151 }
152 Some(lsp_types::CompletionTextEdit::InsertAndReplace(edit)) => { 152 Some(lsp_types::CompletionTextEdit::InsertAndReplace(edit)) => {
153 edit_ranges.push(edit.insert); 153 let replace = edit.replace;
154 edit_ranges.push(edit.replace); 154 let insert = edit.insert;
155 if replace.start != insert.start
156 || insert.start > insert.end
157 || insert.end > replace.end
158 {
159 // insert has to be a prefix of replace but it is not
160 return false;
161 }
162 edit_ranges.push(replace);
155 } 163 }
156 None => {} 164 None => {}
157 } 165 }
@@ -314,18 +322,6 @@ mod tests {
314 Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit { 322 Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
315 new_text: "new_text".to_string(), 323 new_text: "new_text".to_string(),
316 insert: disjoint_edit.range, 324 insert: disjoint_edit.range,
317 replace: joint_edit.range,
318 }));
319 completion_with_joint_edits.additional_text_edits = None;
320 assert!(
321 !all_edits_are_disjoint(&completion_with_joint_edits, &[]),
322 "Completion with disjoint edits fails the validation even with empty extra edits"
323 );
324
325 completion_with_joint_edits.text_edit =
326 Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
327 new_text: "new_text".to_string(),
328 insert: disjoint_edit.range,
329 replace: disjoint_edit_2.range, 325 replace: disjoint_edit_2.range,
330 })); 326 }));
331 completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]); 327 completion_with_joint_edits.additional_text_edits = Some(vec![joint_edit]);
diff --git a/crates/rust-analyzer/src/main_loop.rs b/crates/rust-analyzer/src/main_loop.rs
index e88f16cc1..6ea775d68 100644
--- a/crates/rust-analyzer/src/main_loop.rs
+++ b/crates/rust-analyzer/src/main_loop.rs
@@ -2,6 +2,7 @@
2//! requests/replies and notifications back to the client. 2//! requests/replies and notifications back to the client.
3use std::{ 3use std::{
4 env, fmt, 4 env, fmt,
5 sync::Arc,
5 time::{Duration, Instant}, 6 time::{Duration, Instant},
6}; 7};
7 8
@@ -12,6 +13,7 @@ use ide::{Canceled, FileId};
12use ide_db::base_db::VfsPath; 13use ide_db::base_db::VfsPath;
13use lsp_server::{Connection, Notification, Request, Response}; 14use lsp_server::{Connection, Notification, Request, Response};
14use lsp_types::notification::Notification as _; 15use lsp_types::notification::Notification as _;
16use project_model::BuildDataCollector;
15use vfs::ChangeKind; 17use vfs::ChangeKind;
16 18
17use crate::{ 19use crate::{
@@ -19,7 +21,7 @@ use crate::{
19 dispatch::{NotificationDispatcher, RequestDispatcher}, 21 dispatch::{NotificationDispatcher, RequestDispatcher},
20 document::DocumentData, 22 document::DocumentData,
21 from_proto, 23 from_proto,
22 global_state::{file_id_to_url, url_to_file_id, GlobalState, Status}, 24 global_state::{file_id_to_url, url_to_file_id, GlobalState},
23 handlers, lsp_ext, 25 handlers, lsp_ext,
24 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress}, 26 lsp_utils::{apply_document_changes, is_canceled, notification_is, Progress},
25 reload::{BuildDataProgress, ProjectWorkspaceProgress}, 27 reload::{BuildDataProgress, ProjectWorkspaceProgress},
@@ -187,7 +189,7 @@ impl GlobalState {
187 log::info!("task queue len: {}", task_queue_len); 189 log::info!("task queue len: {}", task_queue_len);
188 } 190 }
189 191
190 let mut new_status = self.status; 192 let was_quiescent = self.is_quiescent();
191 match event { 193 match event {
192 Event::Lsp(msg) => match msg { 194 Event::Lsp(msg) => match msg {
193 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?, 195 lsp_server::Message::Request(req) => self.on_request(loop_start, req)?,
@@ -227,12 +229,26 @@ impl GlobalState {
227 (Progress::Report, Some(msg)) 229 (Progress::Report, Some(msg))
228 } 230 }
229 ProjectWorkspaceProgress::End(workspaces) => { 231 ProjectWorkspaceProgress::End(workspaces) => {
230 self.fetch_workspaces_completed(); 232 self.fetch_workspaces_completed(workspaces);
231 self.switch_workspaces(workspaces, None); 233
234 let old = Arc::clone(&self.workspaces);
235 self.switch_workspaces();
236 let workspaces_updated = !Arc::ptr_eq(&old, &self.workspaces);
237
238 if self.config.run_build_scripts() && workspaces_updated {
239 let mut collector =
240 BuildDataCollector::new(self.config.wrap_rustc());
241 for ws in self.workspaces.iter() {
242 ws.collect_build_data_configs(&mut collector);
243 }
244 self.fetch_build_data_request(collector)
245 }
246
232 (Progress::End, None) 247 (Progress::End, None)
233 } 248 }
234 }; 249 };
235 self.report_progress("fetching", state, msg, None); 250
251 self.report_progress("Fetching", state, msg, None);
236 } 252 }
237 Task::FetchBuildData(progress) => { 253 Task::FetchBuildData(progress) => {
238 let (state, msg) = match progress { 254 let (state, msg) = match progress {
@@ -240,19 +256,21 @@ impl GlobalState {
240 BuildDataProgress::Report(msg) => { 256 BuildDataProgress::Report(msg) => {
241 (Some(Progress::Report), Some(msg)) 257 (Some(Progress::Report), Some(msg))
242 } 258 }
243 BuildDataProgress::End(collector) => { 259 BuildDataProgress::End(build_data_result) => {
244 self.fetch_build_data_completed(); 260 self.fetch_build_data_completed(build_data_result);
245 let workspaces = 261
246 (*self.workspaces).clone().into_iter().map(Ok).collect(); 262 self.switch_workspaces();
247 self.switch_workspaces(workspaces, Some(collector)); 263
248 (Some(Progress::End), None) 264 (Some(Progress::End), None)
249 } 265 }
250 }; 266 };
267
251 if let Some(state) = state { 268 if let Some(state) = state {
252 self.report_progress("loading", state, msg, None); 269 self.report_progress("Loading", state, msg, None);
253 } 270 }
254 } 271 }
255 } 272 }
273
256 // Coalesce multiple task events into one loop turn 274 // Coalesce multiple task events into one loop turn
257 task = match self.task_pool.receiver.try_recv() { 275 task = match self.task_pool.receiver.try_recv() {
258 Ok(task) => task, 276 Ok(task) => task,
@@ -280,7 +298,7 @@ impl GlobalState {
280 } 298 }
281 }; 299 };
282 300
283 self.report_progress("indexing", state, message, Some(fraction)); 301 self.report_progress("Indexing", state, message, Some(fraction));
284 } 302 }
285 } 303 }
286 Event::Vfs(mut task) => { 304 Event::Vfs(mut task) => {
@@ -298,30 +316,25 @@ impl GlobalState {
298 } 316 }
299 vfs::loader::Message::Progress { n_total, n_done, config_version } => { 317 vfs::loader::Message::Progress { n_total, n_done, config_version } => {
300 always!(config_version <= self.vfs_config_version); 318 always!(config_version <= self.vfs_config_version);
301 if n_total == 0 { 319
302 new_status = Status::Invalid; 320 self.vfs_progress_config_version = config_version;
321 self.vfs_progress_n_total = n_total;
322 self.vfs_progress_n_done = n_done;
323
324 let state = if n_done == 0 {
325 Progress::Begin
326 } else if n_done < n_total {
327 Progress::Report
303 } else { 328 } else {
304 let state = if n_done == 0 { 329 assert_eq!(n_done, n_total);
305 new_status = Status::Loading; 330 Progress::End
306 Progress::Begin 331 };
307 } else if n_done < n_total { 332 self.report_progress(
308 Progress::Report 333 "Roots Scanned",
309 } else { 334 state,
310 assert_eq!(n_done, n_total); 335 Some(format!("{}/{}", n_done, n_total)),
311 new_status = Status::Ready { 336 Some(Progress::fraction(n_done, n_total)),
312 partial: self.config.run_build_scripts() 337 )
313 && self.workspace_build_data.is_none()
314 || config_version < self.vfs_config_version,
315 };
316 Progress::End
317 };
318 self.report_progress(
319 "roots scanned",
320 state,
321 Some(format!("{}/{}", n_done, n_total)),
322 Some(Progress::fraction(n_done, n_total)),
323 )
324 }
325 } 338 }
326 } 339 }
327 // Coalesce many VFS event into a single loop turn 340 // Coalesce many VFS event into a single loop turn
@@ -397,18 +410,14 @@ impl GlobalState {
397 } 410 }
398 411
399 let state_changed = self.process_changes(); 412 let state_changed = self.process_changes();
400 let prev_status = self.status; 413
401 if prev_status != new_status { 414 if self.is_quiescent() && !was_quiescent {
402 self.transition(new_status);
403 }
404 let is_ready = matches!(self.status, Status::Ready { .. });
405 if prev_status == Status::Loading && is_ready {
406 for flycheck in &self.flycheck { 415 for flycheck in &self.flycheck {
407 flycheck.update(); 416 flycheck.update();
408 } 417 }
409 } 418 }
410 419
411 if is_ready && (state_changed || prev_status == Status::Loading) { 420 if self.is_quiescent() && (!was_quiescent || state_changed) {
412 self.update_file_notifications_on_threadpool(); 421 self.update_file_notifications_on_threadpool();
413 422
414 // Refresh semantic tokens if the client supports it. 423 // Refresh semantic tokens if the client supports it.
@@ -437,9 +446,13 @@ impl GlobalState {
437 } 446 }
438 } 447 }
439 448
440 self.fetch_workspaces_if_needed(); 449 if self.config.cargo_autoreload() {
450 self.fetch_workspaces_if_needed();
451 }
441 self.fetch_build_data_if_needed(); 452 self.fetch_build_data_if_needed();
442 453
454 self.report_new_status_if_needed();
455
443 let loop_duration = loop_start.elapsed(); 456 let loop_duration = loop_start.elapsed();
444 if loop_duration > Duration::from_millis(100) { 457 if loop_duration > Duration::from_millis(100) {
445 log::warn!("overly long loop turn: {:?}", loop_duration); 458 log::warn!("overly long loop turn: {:?}", loop_duration);
@@ -466,18 +479,23 @@ impl GlobalState {
466 return Ok(()); 479 return Ok(());
467 } 480 }
468 481
469 if self.status == Status::Loading && req.method != "shutdown" { 482 // Avoid flashing a bunch of unresolved references during initial load.
483 if self.workspaces.is_empty() && !self.is_quiescent() {
470 self.respond(lsp_server::Response::new_err( 484 self.respond(lsp_server::Response::new_err(
471 req.id, 485 req.id,
472 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion) 486 // FIXME: i32 should impl From<ErrorCode> (from() guarantees lossless conversion)
473 lsp_server::ErrorCode::ContentModified as i32, 487 lsp_server::ErrorCode::ContentModified as i32,
474 "Rust Analyzer is still loading...".to_owned(), 488 "waiting for cargo metadata or cargo check".to_owned(),
475 )); 489 ));
476 return Ok(()); 490 return Ok(());
477 } 491 }
478 492
479 RequestDispatcher { req: Some(req), global_state: self } 493 RequestDispatcher { req: Some(req), global_state: self }
480 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| Ok(s.fetch_workspaces_request()))? 494 .on_sync::<lsp_ext::ReloadWorkspace>(|s, ()| {
495 s.fetch_workspaces_request();
496 s.fetch_workspaces_if_needed();
497 Ok(())
498 })?
481 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))? 499 .on_sync::<lsp_ext::JoinLines>(|s, p| handlers::handle_join_lines(s.snapshot(), p))?
482 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))? 500 .on_sync::<lsp_ext::OnEnter>(|s, p| handlers::handle_on_enter(s.snapshot(), p))?
483 .on_sync::<lsp_types::request::Shutdown>(|s, ()| { 501 .on_sync::<lsp_types::request::Shutdown>(|s, ()| {
diff --git a/crates/rust-analyzer/src/markdown.rs b/crates/rust-analyzer/src/markdown.rs
index 865eaae9b..35eaffba8 100644
--- a/crates/rust-analyzer/src/markdown.rs
+++ b/crates/rust-analyzer/src/markdown.rs
@@ -1,17 +1,7 @@
1//! Transforms markdown 1//! Transforms markdown
2use ide_db::helpers::rust_doc::is_rust_fence;
2 3
3const RUSTDOC_FENCE: &str = "```"; 4const RUSTDOC_FENCE: &str = "```";
4const RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC: &[&str] = &[
5 "",
6 "rust",
7 "should_panic",
8 "ignore",
9 "no_run",
10 "compile_fail",
11 "edition2015",
12 "edition2018",
13 "edition2021",
14];
15 5
16pub(crate) fn format_docs(src: &str) -> String { 6pub(crate) fn format_docs(src: &str) -> String {
17 let mut processed_lines = Vec::new(); 7 let mut processed_lines = Vec::new();
@@ -27,9 +17,7 @@ pub(crate) fn format_docs(src: &str) -> String {
27 in_code_block ^= true; 17 in_code_block ^= true;
28 18
29 if in_code_block { 19 if in_code_block {
30 is_rust = header 20 is_rust = is_rust_fence(header);
31 .split(',')
32 .all(|sub| RUSTDOC_CODE_BLOCK_ATTRIBUTES_RUST_SPECIFIC.contains(&sub.trim()));
33 21
34 if is_rust { 22 if is_rust {
35 line = "```rust"; 23 line = "```rust";
@@ -82,6 +70,12 @@ mod tests {
82 } 70 }
83 71
84 #[test] 72 #[test]
73 fn test_format_docs_handles_error_codes() {
74 let comment = "```compile_fail,E0641\nlet b = 0 as *const _;\n```";
75 assert_eq!(format_docs(comment), "```rust\nlet b = 0 as *const _;\n```");
76 }
77
78 #[test]
85 fn test_format_docs_skips_comments_in_rust_block() { 79 fn test_format_docs_skips_comments_in_rust_block() {
86 let comment = 80 let comment =
87 "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n # \n #\tskip3\n\t#\t\n```"; 81 "```rust\n # skip1\n# skip2\n#stay1\nstay2\n#\n #\n # \n #\tskip3\n\t#\t\n```";
diff --git a/crates/rust-analyzer/src/op_queue.rs b/crates/rust-analyzer/src/op_queue.rs
index 761b9ad39..1d612a933 100644
--- a/crates/rust-analyzer/src/op_queue.rs
+++ b/crates/rust-analyzer/src/op_queue.rs
@@ -1,29 +1,43 @@
1//! Bookkeeping to make sure only one long-running operation is executed. 1//! Bookkeeping to make sure only one long-running operation is being executed
2//! at a time.
2 3
3pub(crate) struct OpQueue<D> { 4pub(crate) struct OpQueue<Args, Output> {
4 op_scheduled: Option<D>, 5 op_requested: Option<Args>,
5 op_in_progress: bool, 6 op_in_progress: bool,
7 last_op_result: Output,
6} 8}
7 9
8impl<D> Default for OpQueue<D> { 10impl<Args, Output: Default> Default for OpQueue<Args, Output> {
9 fn default() -> Self { 11 fn default() -> Self {
10 Self { op_scheduled: None, op_in_progress: false } 12 Self { op_requested: None, op_in_progress: false, last_op_result: Default::default() }
11 } 13 }
12} 14}
13 15
14impl<D> OpQueue<D> { 16impl<Args, Output> OpQueue<Args, Output> {
15 pub(crate) fn request_op(&mut self, data: D) { 17 pub(crate) fn request_op(&mut self, data: Args) {
16 self.op_scheduled = Some(data); 18 self.op_requested = Some(data);
17 } 19 }
18 pub(crate) fn should_start_op(&mut self) -> Option<D> { 20 pub(crate) fn should_start_op(&mut self) -> Option<Args> {
19 if self.op_in_progress { 21 if self.op_in_progress {
20 return None; 22 return None;
21 } 23 }
22 self.op_in_progress = self.op_scheduled.is_some(); 24 self.op_in_progress = self.op_requested.is_some();
23 self.op_scheduled.take() 25 self.op_requested.take()
24 } 26 }
25 pub(crate) fn op_completed(&mut self) { 27 pub(crate) fn op_completed(&mut self, result: Output) {
26 assert!(self.op_in_progress); 28 assert!(self.op_in_progress);
27 self.op_in_progress = false; 29 self.op_in_progress = false;
30 self.last_op_result = result;
31 }
32
33 #[allow(unused)]
34 pub(crate) fn last_op_result(&self) -> &Output {
35 &self.last_op_result
36 }
37 pub(crate) fn op_in_progress(&self) -> bool {
38 self.op_in_progress
39 }
40 pub(crate) fn op_requested(&self) -> bool {
41 self.op_requested.is_some()
28 } 42 }
29} 43}
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 76fdbcddd..0ae2758cc 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -9,11 +9,10 @@ use vfs::{file_set::FileSetConfig, AbsPath, AbsPathBuf, ChangeKind};
9 9
10use crate::{ 10use crate::{
11 config::{Config, FilesWatcher, LinkedProject}, 11 config::{Config, FilesWatcher, LinkedProject},
12 global_state::{GlobalState, Status}, 12 global_state::GlobalState,
13 lsp_ext, 13 lsp_ext,
14 main_loop::Task, 14 main_loop::Task,
15}; 15};
16use lsp_ext::StatusParams;
17 16
18#[derive(Debug)] 17#[derive(Debug)]
19pub(crate) enum ProjectWorkspaceProgress { 18pub(crate) enum ProjectWorkspaceProgress {
@@ -30,6 +29,13 @@ pub(crate) enum BuildDataProgress {
30} 29}
31 30
32impl GlobalState { 31impl GlobalState {
32 pub(crate) fn is_quiescent(&self) -> bool {
33 !(self.fetch_workspaces_queue.op_in_progress()
34 || self.fetch_build_data_queue.op_in_progress()
35 || self.vfs_progress_config_version < self.vfs_config_version
36 || self.vfs_progress_n_done < self.vfs_progress_n_total)
37 }
38
33 pub(crate) fn update_configuration(&mut self, config: Config) { 39 pub(crate) fn update_configuration(&mut self, config: Config) {
34 let _p = profile::span("GlobalState::update_configuration"); 40 let _p = profile::span("GlobalState::update_configuration");
35 let old_config = mem::replace(&mut self.config, Arc::new(config)); 41 let old_config = mem::replace(&mut self.config, Arc::new(config));
@@ -46,25 +52,17 @@ impl GlobalState {
46 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) { 52 if !changes.iter().any(|(path, kind)| is_interesting(path, *kind)) {
47 return; 53 return;
48 } 54 }
49 match self.status {
50 Status::Loading | Status::NeedsReload => return,
51 Status::Ready { .. } | Status::Invalid => (),
52 }
53 log::info!( 55 log::info!(
54 "Reloading workspace because of the following changes: {}", 56 "Requesting workspace reload because of the following changes: {}",
55 itertools::join( 57 itertools::join(
56 changes 58 changes
57 .iter() 59 .iter()
58 .filter(|(path, kind)| is_interesting(path, *kind)) 60 .filter(|(path, kind)| is_interesting(path, *kind))
59 .map(|(path, kind)| format!("{}/{:?}", path.display(), kind)), 61 .map(|(path, kind)| format!("{}: {:?}", path.display(), kind)),
60 ", " 62 ", "
61 ) 63 )
62 ); 64 );
63 if self.config.cargo_autoreload() { 65 self.fetch_workspaces_request();
64 self.fetch_workspaces_request();
65 } else {
66 self.transition(Status::NeedsReload);
67 }
68 66
69 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool { 67 fn is_interesting(path: &AbsPath, change_kind: ChangeKind) -> bool {
70 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"]; 68 const IMPLICIT_TARGET_FILES: &[&str] = &["build.rs", "src/main.rs", "src/lib.rs"];
@@ -101,46 +99,41 @@ impl GlobalState {
101 false 99 false
102 } 100 }
103 } 101 }
104 pub(crate) fn transition(&mut self, new_status: Status) { 102 pub(crate) fn report_new_status_if_needed(&mut self) {
105 self.status = new_status; 103 let mut status = lsp_ext::ServerStatusParams {
106 if self.config.status_notification() { 104 health: lsp_ext::Health::Ok,
107 let lsp_status = match new_status { 105 quiescent: self.is_quiescent(),
108 Status::Loading => lsp_ext::Status::Loading, 106 message: None,
109 Status::Ready { partial: true } => lsp_ext::Status::ReadyPartial, 107 };
110 Status::Ready { partial: false } => lsp_ext::Status::Ready, 108
111 Status::Invalid => lsp_ext::Status::Invalid, 109 if let Some(error) = self.build_data_error() {
112 Status::NeedsReload => lsp_ext::Status::NeedsReload, 110 status.health = lsp_ext::Health::Warning;
113 }; 111 status.message = Some(error)
114 self.send_notification::<lsp_ext::StatusNotification>(StatusParams { 112 }
115 status: lsp_status, 113 if !self.config.cargo_autoreload()
116 }); 114 && self.is_quiescent()
115 && self.fetch_workspaces_queue.op_requested()
116 {
117 status.health = lsp_ext::Health::Warning;
118 status.message = Some("Workspace reload required".to_string())
117 } 119 }
118 }
119 120
120 pub(crate) fn fetch_build_data_request(&mut self, build_data_collector: BuildDataCollector) { 121 if let Some(error) = self.fetch_workspace_error() {
121 self.fetch_build_data_queue.request_op(build_data_collector); 122 status.health = lsp_ext::Health::Error;
122 } 123 status.message = Some(error)
124 }
123 125
124 pub(crate) fn fetch_build_data_if_needed(&mut self) { 126 if self.last_reported_status.as_ref() != Some(&status) {
125 let mut build_data_collector = match self.fetch_build_data_queue.should_start_op() { 127 self.last_reported_status = Some(status.clone());
126 Some(it) => it,
127 None => return,
128 };
129 self.task_pool.handle.spawn_with_sender(move |sender| {
130 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
131 128
132 let progress = { 129 if let (lsp_ext::Health::Error, Some(message)) = (status.health, &status.message) {
133 let sender = sender.clone(); 130 self.show_message(lsp_types::MessageType::Error, message.clone());
134 move |msg| { 131 }
135 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap() 132
136 } 133 if self.config.server_status_notification() {
137 }; 134 self.send_notification::<lsp_ext::ServerStatusNotification>(status);
138 let res = build_data_collector.collect(&progress); 135 }
139 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap(); 136 }
140 });
141 }
142 pub(crate) fn fetch_build_data_completed(&mut self) {
143 self.fetch_build_data_queue.op_completed()
144 } 137 }
145 138
146 pub(crate) fn fetch_workspaces_request(&mut self) { 139 pub(crate) fn fetch_workspaces_request(&mut self) {
@@ -194,54 +187,69 @@ impl GlobalState {
194 } 187 }
195 }); 188 });
196 } 189 }
197 pub(crate) fn fetch_workspaces_completed(&mut self) { 190 pub(crate) fn fetch_workspaces_completed(
198 self.fetch_workspaces_queue.op_completed() 191 &mut self,
192 workspaces: Vec<anyhow::Result<ProjectWorkspace>>,
193 ) {
194 self.fetch_workspaces_queue.op_completed(workspaces)
195 }
196
197 pub(crate) fn fetch_build_data_request(&mut self, build_data_collector: BuildDataCollector) {
198 self.fetch_build_data_queue.request_op(build_data_collector);
199 } 199 }
200 pub(crate) fn fetch_build_data_if_needed(&mut self) {
201 let mut build_data_collector = match self.fetch_build_data_queue.should_start_op() {
202 Some(it) => it,
203 None => return,
204 };
205 self.task_pool.handle.spawn_with_sender(move |sender| {
206 sender.send(Task::FetchBuildData(BuildDataProgress::Begin)).unwrap();
200 207
201 pub(crate) fn switch_workspaces( 208 let progress = {
209 let sender = sender.clone();
210 move |msg| {
211 sender.send(Task::FetchBuildData(BuildDataProgress::Report(msg))).unwrap()
212 }
213 };
214 let res = build_data_collector.collect(&progress);
215 sender.send(Task::FetchBuildData(BuildDataProgress::End(res))).unwrap();
216 });
217 }
218 pub(crate) fn fetch_build_data_completed(
202 &mut self, 219 &mut self,
203 workspaces: Vec<anyhow::Result<ProjectWorkspace>>, 220 build_data: anyhow::Result<BuildDataResult>,
204 workspace_build_data: Option<anyhow::Result<BuildDataResult>>,
205 ) { 221 ) {
206 let _p = profile::span("GlobalState::switch_workspaces"); 222 self.fetch_build_data_queue.op_completed(Some(build_data))
207 log::info!("will switch workspaces: {:?}", workspaces); 223 }
208 224
209 let mut has_errors = false; 225 pub(crate) fn switch_workspaces(&mut self) {
210 let workspaces = workspaces 226 let _p = profile::span("GlobalState::switch_workspaces");
211 .into_iter() 227 log::info!("will switch workspaces");
212 .filter_map(|res| {
213 res.map_err(|err| {
214 has_errors = true;
215 log::error!("failed to load workspace: {:#}", err);
216 if self.workspaces.is_empty() {
217 self.show_message(
218 lsp_types::MessageType::Error,
219 format!("rust-analyzer failed to load workspace: {:#}", err),
220 );
221 }
222 })
223 .ok()
224 })
225 .collect::<Vec<_>>();
226 228
227 let workspace_build_data = match workspace_build_data { 229 if let Some(error_message) = self.fetch_workspace_error() {
228 Some(Ok(it)) => Some(it), 230 log::error!("failed to switch workspaces: {}", error_message);
229 Some(Err(err)) => { 231 if !self.workspaces.is_empty() {
230 log::error!("failed to fetch build data: {:#}", err);
231 self.show_message(
232 lsp_types::MessageType::Error,
233 format!("rust-analyzer failed to fetch build data: {:#}", err),
234 );
235 return; 232 return;
236 } 233 }
237 None => None, 234 }
238 };
239 235
240 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data { 236 if let Some(error_message) = self.build_data_error() {
241 return; 237 log::error!("failed to switch build data: {}", error_message);
242 } 238 }
243 239
244 if !self.workspaces.is_empty() && has_errors { 240 let workspaces = self
241 .fetch_workspaces_queue
242 .last_op_result()
243 .iter()
244 .filter_map(|res| res.as_ref().ok().cloned())
245 .collect::<Vec<_>>();
246
247 let workspace_build_data = match self.fetch_build_data_queue.last_op_result() {
248 Some(Ok(it)) => Some(it.clone()),
249 None | Some(Err(_)) => None,
250 };
251
252 if *self.workspaces == workspaces && self.workspace_build_data == workspace_build_data {
245 return; 253 return;
246 } 254 }
247 255
@@ -314,6 +322,7 @@ impl GlobalState {
314 let loader = &mut self.loader; 322 let loader = &mut self.loader;
315 let mem_docs = &self.mem_docs; 323 let mem_docs = &self.mem_docs;
316 let mut load = |path: &AbsPath| { 324 let mut load = |path: &AbsPath| {
325 let _p = profile::span("GlobalState::load");
317 let vfs_path = vfs::VfsPath::from(path.to_path_buf()); 326 let vfs_path = vfs::VfsPath::from(path.to_path_buf());
318 if !mem_docs.contains_key(&vfs_path) { 327 if !mem_docs.contains_key(&vfs_path) {
319 let contents = loader.handle.load_sync(path); 328 let contents = loader.handle.load_sync(path);
@@ -337,14 +346,6 @@ impl GlobalState {
337 }; 346 };
338 change.set_crate_graph(crate_graph); 347 change.set_crate_graph(crate_graph);
339 348
340 if self.config.run_build_scripts() && workspace_build_data.is_none() {
341 let mut collector = BuildDataCollector::default();
342 for ws in &workspaces {
343 ws.collect_build_data_configs(&mut collector);
344 }
345 self.fetch_build_data_request(collector)
346 }
347
348 self.source_root_config = project_folders.source_root_config; 349 self.source_root_config = project_folders.source_root_config;
349 self.workspaces = Arc::new(workspaces); 350 self.workspaces = Arc::new(workspaces);
350 self.workspace_build_data = workspace_build_data; 351 self.workspace_build_data = workspace_build_data;
@@ -355,6 +356,32 @@ impl GlobalState {
355 log::info!("did switch workspaces"); 356 log::info!("did switch workspaces");
356 } 357 }
357 358
359 fn fetch_workspace_error(&self) -> Option<String> {
360 let mut buf = String::new();
361
362 for ws in self.fetch_workspaces_queue.last_op_result() {
363 if let Err(err) = ws {
364 stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
365 }
366 }
367
368 if buf.is_empty() {
369 return None;
370 }
371
372 Some(buf)
373 }
374
375 fn build_data_error(&self) -> Option<String> {
376 match self.fetch_build_data_queue.last_op_result() {
377 Some(Err(err)) => {
378 Some(format!("rust-analyzer failed to fetch build data: {:#}\n", err))
379 }
380 Some(Ok(data)) => data.error(),
381 None => None,
382 }
383 }
384
358 fn reload_flycheck(&mut self) { 385 fn reload_flycheck(&mut self) {
359 let _p = profile::span("GlobalState::reload_flycheck"); 386 let _p = profile::span("GlobalState::reload_flycheck");
360 let config = match self.config.flycheck() { 387 let config = match self.config.flycheck() {
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index 2dc8a42f1..ecab89b2a 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -39,7 +39,9 @@ macro_rules! define_semantic_token_types {
39 39
40define_semantic_token_types![ 40define_semantic_token_types![
41 (ANGLE, "angle"), 41 (ANGLE, "angle"),
42 (ARITHMETIC, "arithmetic"),
42 (ATTRIBUTE, "attribute"), 43 (ATTRIBUTE, "attribute"),
44 (BITWISE, "bitwise"),
43 (BOOLEAN, "boolean"), 45 (BOOLEAN, "boolean"),
44 (BRACE, "brace"), 46 (BRACE, "brace"),
45 (BRACKET, "bracket"), 47 (BRACKET, "bracket"),
@@ -47,6 +49,7 @@ define_semantic_token_types![
47 (CHAR_LITERAL, "characterLiteral"), 49 (CHAR_LITERAL, "characterLiteral"),
48 (COLON, "colon"), 50 (COLON, "colon"),
49 (COMMA, "comma"), 51 (COMMA, "comma"),
52 (COMPARISON, "comparison"),
50 (CONST_PARAMETER, "constParameter"), 53 (CONST_PARAMETER, "constParameter"),
51 (DOT, "dot"), 54 (DOT, "dot"),
52 (ESCAPE_SEQUENCE, "escapeSequence"), 55 (ESCAPE_SEQUENCE, "escapeSequence"),
@@ -54,6 +57,8 @@ define_semantic_token_types![
54 (GENERIC, "generic"), 57 (GENERIC, "generic"),
55 (LABEL, "label"), 58 (LABEL, "label"),
56 (LIFETIME, "lifetime"), 59 (LIFETIME, "lifetime"),
60 (LOGICAL, "logical"),
61 (OPERATOR, "operator"),
57 (PARENTHESIS, "parenthesis"), 62 (PARENTHESIS, "parenthesis"),
58 (PUNCTUATION, "punctuation"), 63 (PUNCTUATION, "punctuation"),
59 (SELF_KEYWORD, "selfKeyword"), 64 (SELF_KEYWORD, "selfKeyword"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index c3820944b..c2361b32e 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -1,15 +1,16 @@
1//! Conversion of rust-analyzer specific types to lsp_types equivalents. 1//! Conversion of rust-analyzer specific types to lsp_types equivalents.
2use std::{ 2use std::{
3 iter::once,
3 path::{self, Path}, 4 path::{self, Path},
4 sync::atomic::{AtomicU32, Ordering}, 5 sync::atomic::{AtomicU32, Ordering},
5}; 6};
6 7
7use ide::{ 8use ide::{
8 Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, 9 Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancelable, CompletionItem,
9 CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, 10 CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
10 Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, 11 Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
11 Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, 12 InlayKind, InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable,
12 StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, 13 Severity, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
13}; 14};
14use itertools::Itertools; 15use itertools::Itertools;
15use serde_json::to_value; 16use serde_json::to_value;
@@ -145,6 +146,23 @@ pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::Text
145 lsp_types::TextEdit { range, new_text } 146 lsp_types::TextEdit { range, new_text }
146} 147}
147 148
149pub(crate) fn completion_text_edit(
150 line_index: &LineIndex,
151 insert_replace_support: Option<lsp_types::Position>,
152 indel: Indel,
153) -> lsp_types::CompletionTextEdit {
154 let text_edit = text_edit(line_index, indel);
155 match insert_replace_support {
156 Some(cursor_pos) => lsp_types::InsertReplaceEdit {
157 new_text: text_edit.new_text,
158 insert: lsp_types::Range { start: text_edit.range.start, end: cursor_pos },
159 replace: text_edit.range,
160 }
161 .into(),
162 None => text_edit.into(),
163 }
164}
165
148pub(crate) fn snippet_text_edit( 166pub(crate) fn snippet_text_edit(
149 line_index: &LineIndex, 167 line_index: &LineIndex,
150 is_snippet: bool, 168 is_snippet: bool,
@@ -157,6 +175,7 @@ pub(crate) fn snippet_text_edit(
157 range: text_edit.range, 175 range: text_edit.range,
158 new_text: text_edit.new_text, 176 new_text: text_edit.new_text,
159 insert_text_format, 177 insert_text_format,
178 annotation_id: None,
160 } 179 }
161} 180}
162 181
@@ -179,6 +198,7 @@ pub(crate) fn snippet_text_edit_vec(
179} 198}
180 199
181pub(crate) fn completion_item( 200pub(crate) fn completion_item(
201 insert_replace_support: Option<lsp_types::Position>,
182 line_index: &LineIndex, 202 line_index: &LineIndex,
183 item: CompletionItem, 203 item: CompletionItem,
184) -> Vec<lsp_types::CompletionItem> { 204) -> Vec<lsp_types::CompletionItem> {
@@ -190,7 +210,7 @@ pub(crate) fn completion_item(
190 for indel in item.text_edit().iter() { 210 for indel in item.text_edit().iter() {
191 if indel.delete.contains_range(source_range) { 211 if indel.delete.contains_range(source_range) {
192 text_edit = Some(if indel.delete == source_range { 212 text_edit = Some(if indel.delete == source_range {
193 self::text_edit(line_index, indel.clone()) 213 self::completion_text_edit(line_index, insert_replace_support, indel.clone())
194 } else { 214 } else {
195 assert!(source_range.end() == indel.delete.end()); 215 assert!(source_range.end() == indel.delete.end());
196 let range1 = TextRange::new(indel.delete.start(), source_range.start()); 216 let range1 = TextRange::new(indel.delete.start(), source_range.start());
@@ -198,7 +218,7 @@ pub(crate) fn completion_item(
198 let indel1 = Indel::replace(range1, String::new()); 218 let indel1 = Indel::replace(range1, String::new());
199 let indel2 = Indel::replace(range2, indel.insert.clone()); 219 let indel2 = Indel::replace(range2, indel.insert.clone());
200 additional_text_edits.push(self::text_edit(line_index, indel1)); 220 additional_text_edits.push(self::text_edit(line_index, indel1));
201 self::text_edit(line_index, indel2) 221 self::completion_text_edit(line_index, insert_replace_support, indel2)
202 }) 222 })
203 } else { 223 } else {
204 assert!(source_range.intersect(indel.delete).is_none()); 224 assert!(source_range.intersect(indel.delete).is_none());
@@ -213,7 +233,7 @@ pub(crate) fn completion_item(
213 detail: item.detail().map(|it| it.to_string()), 233 detail: item.detail().map(|it| it.to_string()),
214 filter_text: Some(item.lookup().to_string()), 234 filter_text: Some(item.lookup().to_string()),
215 kind: item.kind().map(completion_item_kind), 235 kind: item.kind().map(completion_item_kind),
216 text_edit: Some(text_edit.into()), 236 text_edit: Some(text_edit),
217 additional_text_edits: Some(additional_text_edits), 237 additional_text_edits: Some(additional_text_edits),
218 documentation: item.documentation().map(documentation), 238 documentation: item.documentation().map(documentation),
219 deprecated: Some(item.deprecated()), 239 deprecated: Some(item.deprecated()),
@@ -445,7 +465,13 @@ fn semantic_token_type_and_modifiers(
445 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 465 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
446 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, 466 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
447 HlTag::None => semantic_tokens::GENERIC, 467 HlTag::None => semantic_tokens::GENERIC,
448 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 468 HlTag::Operator(op) => match op {
469 HlOperator::Bitwise => semantic_tokens::BITWISE,
470 HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
471 HlOperator::Logical => semantic_tokens::LOGICAL,
472 HlOperator::Comparison => semantic_tokens::COMPARISON,
473 HlOperator::Other => semantic_tokens::OPERATOR,
474 },
449 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, 475 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
450 HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, 476 HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
451 HlTag::Punctuation(punct) => match punct { 477 HlTag::Punctuation(punct) => match punct {
@@ -497,7 +523,8 @@ pub(crate) fn folding_range(
497 | FoldKind::Block 523 | FoldKind::Block
498 | FoldKind::ArgList 524 | FoldKind::ArgList
499 | FoldKind::Consts 525 | FoldKind::Consts
500 | FoldKind::Statics => None, 526 | FoldKind::Statics
527 | FoldKind::Array => None,
501 }; 528 };
502 529
503 let range = range(line_index, fold.range); 530 let range = range(line_index, fold.range);
@@ -663,16 +690,8 @@ pub(crate) fn goto_definition_response(
663 } 690 }
664} 691}
665 692
666pub(crate) fn text_document_edit( 693fn outside_workspace_annotation_id() -> String {
667 snap: &GlobalStateSnapshot, 694 String::from("OutsideWorkspace")
668 file_id: FileId,
669 edit: TextEdit,
670) -> Result<lsp_types::TextDocumentEdit> {
671 let text_document = optional_versioned_text_document_identifier(snap, file_id);
672 let line_index = snap.file_line_index(file_id)?;
673 let edits =
674 edit.into_iter().map(|it| lsp_types::OneOf::Left(text_edit(&line_index, it))).collect();
675 Ok(lsp_types::TextDocumentEdit { text_document, edits })
676} 695}
677 696
678pub(crate) fn snippet_text_document_edit( 697pub(crate) fn snippet_text_document_edit(
@@ -683,14 +702,21 @@ pub(crate) fn snippet_text_document_edit(
683) -> Result<lsp_ext::SnippetTextDocumentEdit> { 702) -> Result<lsp_ext::SnippetTextDocumentEdit> {
684 let text_document = optional_versioned_text_document_identifier(snap, file_id); 703 let text_document = optional_versioned_text_document_identifier(snap, file_id);
685 let line_index = snap.file_line_index(file_id)?; 704 let line_index = snap.file_line_index(file_id)?;
686 let edits = edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect(); 705 let mut edits: Vec<_> =
706 edit.into_iter().map(|it| snippet_text_edit(&line_index, is_snippet, it)).collect();
707
708 if snap.analysis.is_library_file(file_id)? && snap.config.change_annotation_support() {
709 for edit in &mut edits {
710 edit.annotation_id = Some(outside_workspace_annotation_id())
711 }
712 }
687 Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits }) 713 Ok(lsp_ext::SnippetTextDocumentEdit { text_document, edits })
688} 714}
689 715
690pub(crate) fn snippet_text_document_ops( 716pub(crate) fn snippet_text_document_ops(
691 snap: &GlobalStateSnapshot, 717 snap: &GlobalStateSnapshot,
692 file_system_edit: FileSystemEdit, 718 file_system_edit: FileSystemEdit,
693) -> Vec<lsp_ext::SnippetDocumentChangeOperation> { 719) -> Cancelable<Vec<lsp_ext::SnippetDocumentChangeOperation>> {
694 let mut ops = Vec::new(); 720 let mut ops = Vec::new();
695 match file_system_edit { 721 match file_system_edit {
696 FileSystemEdit::CreateFile { dst, initial_contents } => { 722 FileSystemEdit::CreateFile { dst, initial_contents } => {
@@ -708,6 +734,7 @@ pub(crate) fn snippet_text_document_ops(
708 range: lsp_types::Range::default(), 734 range: lsp_types::Range::default(),
709 new_text: initial_contents, 735 new_text: initial_contents,
710 insert_text_format: Some(lsp_types::InsertTextFormat::PlainText), 736 insert_text_format: Some(lsp_types::InsertTextFormat::PlainText),
737 annotation_id: None,
711 }; 738 };
712 let edit_file = 739 let edit_file =
713 lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] }; 740 lsp_ext::SnippetTextDocumentEdit { text_document, edits: vec![text_edit] };
@@ -717,16 +744,19 @@ pub(crate) fn snippet_text_document_ops(
717 FileSystemEdit::MoveFile { src, dst } => { 744 FileSystemEdit::MoveFile { src, dst } => {
718 let old_uri = snap.file_id_to_url(src); 745 let old_uri = snap.file_id_to_url(src);
719 let new_uri = snap.anchored_path(&dst); 746 let new_uri = snap.anchored_path(&dst);
720 let rename_file = lsp_types::ResourceOp::Rename(lsp_types::RenameFile { 747 let mut rename_file =
721 old_uri, 748 lsp_types::RenameFile { old_uri, new_uri, options: None, annotation_id: None };
722 new_uri, 749 if snap.analysis.is_library_file(src) == Ok(true)
723 options: None, 750 && snap.config.change_annotation_support()
724 annotation_id: None, 751 {
725 }); 752 rename_file.annotation_id = Some(outside_workspace_annotation_id())
726 ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(rename_file)) 753 }
754 ops.push(lsp_ext::SnippetDocumentChangeOperation::Op(lsp_types::ResourceOp::Rename(
755 rename_file,
756 )))
727 } 757 }
728 } 758 }
729 ops 759 Ok(ops)
730} 760}
731 761
732pub(crate) fn snippet_workspace_edit( 762pub(crate) fn snippet_workspace_edit(
@@ -734,16 +764,35 @@ pub(crate) fn snippet_workspace_edit(
734 source_change: SourceChange, 764 source_change: SourceChange,
735) -> Result<lsp_ext::SnippetWorkspaceEdit> { 765) -> Result<lsp_ext::SnippetWorkspaceEdit> {
736 let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new(); 766 let mut document_changes: Vec<lsp_ext::SnippetDocumentChangeOperation> = Vec::new();
767
737 for op in source_change.file_system_edits { 768 for op in source_change.file_system_edits {
738 let ops = snippet_text_document_ops(snap, op); 769 let ops = snippet_text_document_ops(snap, op)?;
739 document_changes.extend_from_slice(&ops); 770 document_changes.extend_from_slice(&ops);
740 } 771 }
741 for (file_id, edit) in source_change.source_file_edits { 772 for (file_id, edit) in source_change.source_file_edits {
742 let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?; 773 let edit = snippet_text_document_edit(&snap, source_change.is_snippet, file_id, edit)?;
743 document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit)); 774 document_changes.push(lsp_ext::SnippetDocumentChangeOperation::Edit(edit));
744 } 775 }
745 let workspace_edit = 776 let mut workspace_edit = lsp_ext::SnippetWorkspaceEdit {
746 lsp_ext::SnippetWorkspaceEdit { changes: None, document_changes: Some(document_changes) }; 777 changes: None,
778 document_changes: Some(document_changes),
779 change_annotations: None,
780 };
781 if snap.config.change_annotation_support() {
782 workspace_edit.change_annotations = Some(
783 once((
784 outside_workspace_annotation_id(),
785 lsp_types::ChangeAnnotation {
786 label: String::from("Edit outside of the workspace"),
787 needs_confirmation: Some(true),
788 description: Some(String::from(
789 "This edit lies outside of the workspace and may affect dependencies",
790 )),
791 },
792 ))
793 .collect(),
794 )
795 }
747 Ok(workspace_edit) 796 Ok(workspace_edit)
748} 797}
749 798
@@ -771,16 +820,7 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
771 lsp_types::DocumentChangeOperation::Edit( 820 lsp_types::DocumentChangeOperation::Edit(
772 lsp_types::TextDocumentEdit { 821 lsp_types::TextDocumentEdit {
773 text_document: edit.text_document, 822 text_document: edit.text_document,
774 edits: edit 823 edits: edit.edits.into_iter().map(From::from).collect(),
775 .edits
776 .into_iter()
777 .map(|edit| {
778 lsp_types::OneOf::Left(lsp_types::TextEdit {
779 range: edit.range,
780 new_text: edit.new_text,
781 })
782 })
783 .collect(),
784 }, 824 },
785 ) 825 )
786 } 826 }
@@ -788,7 +828,23 @@ impl From<lsp_ext::SnippetWorkspaceEdit> for lsp_types::WorkspaceEdit {
788 .collect(), 828 .collect(),
789 ) 829 )
790 }), 830 }),
791 change_annotations: None, 831 change_annotations: snippet_workspace_edit.change_annotations,
832 }
833 }
834}
835
836impl From<lsp_ext::SnippetTextEdit>
837 for lsp_types::OneOf<lsp_types::TextEdit, lsp_types::AnnotatedTextEdit>
838{
839 fn from(
840 lsp_ext::SnippetTextEdit { annotation_id, insert_text_format:_, new_text, range }: lsp_ext::SnippetTextEdit,
841 ) -> Self {
842 match annotation_id {
843 Some(annotation_id) => lsp_types::OneOf::Right(lsp_types::AnnotatedTextEdit {
844 text_edit: lsp_types::TextEdit { range, new_text },
845 annotation_id,
846 }),
847 None => lsp_types::OneOf::Left(lsp_types::TextEdit { range, new_text }),
792 } 848 }
793 } 849 }
794} 850}
@@ -824,40 +880,31 @@ pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
824 } 880 }
825} 881}
826 882
827pub(crate) fn unresolved_code_action( 883pub(crate) fn code_action(
828 snap: &GlobalStateSnapshot, 884 snap: &GlobalStateSnapshot,
829 code_action_params: lsp_types::CodeActionParams,
830 assist: Assist, 885 assist: Assist,
831 index: usize, 886 resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
832) -> Result<lsp_ext::CodeAction> { 887) -> Result<lsp_ext::CodeAction> {
833 assert!(assist.source_change.is_none()); 888 let mut res = lsp_ext::CodeAction {
834 let res = lsp_ext::CodeAction {
835 title: assist.label.to_string(), 889 title: assist.label.to_string(),
836 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), 890 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
837 kind: Some(code_action_kind(assist.id.1)), 891 kind: Some(code_action_kind(assist.id.1)),
838 edit: None, 892 edit: None,
839 is_preferred: None, 893 is_preferred: None,
840 data: Some(lsp_ext::CodeActionData {
841 id: format!("{}:{}", assist.id.0, index.to_string()),
842 code_action_params,
843 }),
844 };
845 Ok(res)
846}
847
848pub(crate) fn resolved_code_action(
849 snap: &GlobalStateSnapshot,
850 assist: Assist,
851) -> Result<lsp_ext::CodeAction> {
852 let change = assist.source_change.unwrap();
853 let res = lsp_ext::CodeAction {
854 edit: Some(snippet_workspace_edit(snap, change)?),
855 title: assist.label.to_string(),
856 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
857 kind: Some(code_action_kind(assist.id.1)),
858 is_preferred: None,
859 data: None, 894 data: None,
860 }; 895 };
896 match (assist.source_change, resolve_data) {
897 (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
898 (None, Some((index, code_action_params))) => {
899 res.data = Some(lsp_ext::CodeActionData {
900 id: format!("{}:{}", assist.id.0, index.to_string()),
901 code_action_params,
902 });
903 }
904 (None, None) => {
905 stdx::never!("assist should always be resolved if client can't do lazy resolving")
906 }
907 };
861 Ok(res) 908 Ok(res)
862} 909}
863 910
@@ -1135,7 +1182,7 @@ mod tests {
1135 .unwrap() 1182 .unwrap()
1136 .into_iter() 1183 .into_iter()
1137 .filter(|c| c.label().ends_with("arg")) 1184 .filter(|c| c.label().ends_with("arg"))
1138 .map(|c| completion_item(&line_index, c)) 1185 .map(|c| completion_item(None, &line_index, c))
1139 .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) 1186 .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text)))
1140 .collect(); 1187 .collect();
1141 expect_test::expect![[r#" 1188 expect_test::expect![[r#"
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs
index 4442cbff6..9e89209ea 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/main.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs
@@ -340,7 +340,6 @@ fn main() {}
340 } 340 }
341 ] 341 ]
342 }, 342 },
343 "isPreferred": false,
344 "kind": "quickfix", 343 "kind": "quickfix",
345 "title": "Create module" 344 "title": "Create module"
346 }]), 345 }]),
@@ -411,7 +410,6 @@ fn main() {{}}
411 } 410 }
412 ] 411 ]
413 }, 412 },
414 "isPreferred": false,
415 "kind": "quickfix", 413 "kind": "quickfix",
416 "title": "Create module" 414 "title": "Create module"
417 }]), 415 }]),
diff --git a/crates/rust-analyzer/tests/rust-analyzer/support.rs b/crates/rust-analyzer/tests/rust-analyzer/support.rs
index 95bf26f01..75e677762 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/support.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/support.rs
@@ -32,8 +32,12 @@ impl<'a> Project<'a> {
32 tmp_dir: None, 32 tmp_dir: None,
33 roots: vec![], 33 roots: vec![],
34 config: serde_json::json!({ 34 config: serde_json::json!({
35 // Loading standard library is costly, let's ignore it by default 35 "cargo": {
36 "cargo": { "noSysroot": true } 36 // Loading standard library is costly, let's ignore it by default
37 "noSysroot": true,
38 // Can't use test binary as rustc wrapper.
39 "useRustcWrapperForBuildScripts": false,
40 }
37 }), 41 }),
38 } 42 }
39 } 43 }
@@ -49,7 +53,17 @@ impl<'a> Project<'a> {
49 } 53 }
50 54
51 pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> { 55 pub(crate) fn with_config(mut self, config: serde_json::Value) -> Project<'a> {
52 self.config = config; 56 fn merge(dst: &mut serde_json::Value, src: serde_json::Value) {
57 match (dst, src) {
58 (Value::Object(dst), Value::Object(src)) => {
59 for (k, v) in src {
60 merge(dst.entry(k).or_insert(v.clone()), v)
61 }
62 }
63 (dst, src) => *dst = src,
64 }
65 }
66 merge(&mut self.config, config);
53 self 67 self
54 } 68 }
55 69
@@ -103,7 +117,7 @@ impl<'a> Project<'a> {
103 ..Default::default() 117 ..Default::default()
104 }), 118 }),
105 experimental: Some(json!({ 119 experimental: Some(json!({
106 "statusNotification": true, 120 "serverStatusNotification": true,
107 })), 121 })),
108 ..Default::default() 122 ..Default::default()
109 }, 123 },
@@ -154,6 +168,7 @@ impl Server {
154 self.send_notification(r) 168 self.send_notification(r)
155 } 169 }
156 170
171 #[track_caller]
157 pub(crate) fn request<R>(&self, params: R::Params, expected_resp: Value) 172 pub(crate) fn request<R>(&self, params: R::Params, expected_resp: Value)
158 where 173 where
159 R: lsp_types::request::Request, 174 R: lsp_types::request::Request,
@@ -213,13 +228,12 @@ impl Server {
213 } 228 }
214 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server { 229 pub(crate) fn wait_until_workspace_is_loaded(self) -> Server {
215 self.wait_for_message_cond(1, &|msg: &Message| match msg { 230 self.wait_for_message_cond(1, &|msg: &Message| match msg {
216 Message::Notification(n) if n.method == "rust-analyzer/status" => { 231 Message::Notification(n) if n.method == "experimental/serverStatus" => {
217 let status = n 232 let status = n
218 .clone() 233 .clone()
219 .extract::<lsp_ext::StatusParams>("rust-analyzer/status") 234 .extract::<lsp_ext::ServerStatusParams>("experimental/serverStatus")
220 .unwrap() 235 .unwrap();
221 .status; 236 status.quiescent
222 matches!(status, lsp_ext::Status::Ready)
223 } 237 }
224 _ => false, 238 _ => false,
225 }) 239 })
diff --git a/crates/stdx/Cargo.toml b/crates/stdx/Cargo.toml
index d28b5e658..f78c5da7c 100644
--- a/crates/stdx/Cargo.toml
+++ b/crates/stdx/Cargo.toml
@@ -10,10 +10,15 @@ edition = "2018"
10doctest = false 10doctest = false
11 11
12[dependencies] 12[dependencies]
13libc = "0.2.93"
13backtrace = { version = "0.3.44", optional = true } 14backtrace = { version = "0.3.44", optional = true }
14always-assert = { version = "0.1.2", features = ["log"] } 15always-assert = { version = "0.1.2", features = ["log"] }
15# Think twice before adding anything here 16# Think twice before adding anything here
16 17
18[target.'cfg(windows)'.dependencies]
19miow = "0.3.6"
20winapi = "0.3.9"
21
17[features] 22[features]
18# Uncomment to enable for the whole crate graph 23# Uncomment to enable for the whole crate graph
19# default = [ "backtrace" ] 24# default = [ "backtrace" ]
diff --git a/crates/stdx/src/lib.rs b/crates/stdx/src/lib.rs
index d26be4853..857567a85 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -1,7 +1,8 @@
1//! Missing batteries for standard libraries. 1//! Missing batteries for standard libraries.
2use std::{cmp::Ordering, ops, process, time::Instant}; 2use std::{cmp::Ordering, ops, time::Instant};
3 3
4mod macros; 4mod macros;
5pub mod process;
5pub mod panic_context; 6pub mod panic_context;
6 7
7pub use always_assert::{always, never}; 8pub use always_assert::{always, never};
@@ -178,17 +179,30 @@ where
178 start..start + len 179 start..start + len
179} 180}
180 181
181pub struct JodChild(pub process::Child); 182pub fn defer<F: FnOnce()>(f: F) -> impl Drop {
183 struct D<F: FnOnce()>(Option<F>);
184 impl<F: FnOnce()> Drop for D<F> {
185 fn drop(&mut self) {
186 if let Some(f) = self.0.take() {
187 f()
188 }
189 }
190 }
191 D(Some(f))
192}
193
194#[repr(transparent)]
195pub struct JodChild(pub std::process::Child);
182 196
183impl ops::Deref for JodChild { 197impl ops::Deref for JodChild {
184 type Target = process::Child; 198 type Target = std::process::Child;
185 fn deref(&self) -> &process::Child { 199 fn deref(&self) -> &std::process::Child {
186 &self.0 200 &self.0
187 } 201 }
188} 202}
189 203
190impl ops::DerefMut for JodChild { 204impl ops::DerefMut for JodChild {
191 fn deref_mut(&mut self) -> &mut process::Child { 205 fn deref_mut(&mut self) -> &mut std::process::Child {
192 &mut self.0 206 &mut self.0
193 } 207 }
194} 208}
@@ -200,6 +214,13 @@ impl Drop for JodChild {
200 } 214 }
201} 215}
202 216
217impl JodChild {
218 pub fn into_inner(self) -> std::process::Child {
219 // SAFETY: repr transparent
220 unsafe { std::mem::transmute::<JodChild, std::process::Child>(self) }
221 }
222}
223
203#[cfg(test)] 224#[cfg(test)]
204mod tests { 225mod tests {
205 use super::*; 226 use super::*;
diff --git a/crates/stdx/src/process.rs b/crates/stdx/src/process.rs
new file mode 100644
index 000000000..b0fa12f76
--- /dev/null
+++ b/crates/stdx/src/process.rs
@@ -0,0 +1,238 @@
1//! Read both stdout and stderr of child without deadlocks.
2//!
3//! https://github.com/rust-lang/cargo/blob/905af549966f23a9288e9993a85d1249a5436556/crates/cargo-util/src/read2.rs
4//! https://github.com/rust-lang/cargo/blob/58a961314437258065e23cb6316dfc121d96fb71/crates/cargo-util/src/process_builder.rs#L231
5
6use std::{
7 io,
8 process::{Command, Output, Stdio},
9};
10
11pub fn streaming_output(
12 mut cmd: Command,
13 on_stdout_line: &mut dyn FnMut(&str),
14 on_stderr_line: &mut dyn FnMut(&str),
15) -> io::Result<Output> {
16 let mut stdout = Vec::new();
17 let mut stderr = Vec::new();
18
19 let cmd = cmd.stdout(Stdio::piped()).stderr(Stdio::piped()).stdin(Stdio::null());
20
21 let status = {
22 let mut child = cmd.spawn()?;
23 let out = child.stdout.take().unwrap();
24 let err = child.stderr.take().unwrap();
25 imp::read2(out, err, &mut |is_out, data, eof| {
26 let idx = if eof {
27 data.len()
28 } else {
29 match data.iter().rposition(|b| *b == b'\n') {
30 Some(i) => i + 1,
31 None => return,
32 }
33 };
34 {
35 // scope for new_lines
36 let new_lines = {
37 let dst = if is_out { &mut stdout } else { &mut stderr };
38 let start = dst.len();
39 let data = data.drain(..idx);
40 dst.extend(data);
41 &dst[start..]
42 };
43 for line in String::from_utf8_lossy(new_lines).lines() {
44 if is_out {
45 on_stdout_line(line)
46 } else {
47 on_stderr_line(line)
48 }
49 }
50 }
51 })?;
52 child.wait()?
53 };
54
55 Ok(Output { status, stdout, stderr })
56}
57
58#[cfg(unix)]
59mod imp {
60 use std::{
61 io::{self, prelude::*},
62 mem,
63 os::unix::prelude::*,
64 process::{ChildStderr, ChildStdout},
65 };
66
67 pub(crate) fn read2(
68 mut out_pipe: ChildStdout,
69 mut err_pipe: ChildStderr,
70 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
71 ) -> io::Result<()> {
72 unsafe {
73 libc::fcntl(out_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
74 libc::fcntl(err_pipe.as_raw_fd(), libc::F_SETFL, libc::O_NONBLOCK);
75 }
76
77 let mut out_done = false;
78 let mut err_done = false;
79 let mut out = Vec::new();
80 let mut err = Vec::new();
81
82 let mut fds: [libc::pollfd; 2] = unsafe { mem::zeroed() };
83 fds[0].fd = out_pipe.as_raw_fd();
84 fds[0].events = libc::POLLIN;
85 fds[1].fd = err_pipe.as_raw_fd();
86 fds[1].events = libc::POLLIN;
87 let mut nfds = 2;
88 let mut errfd = 1;
89
90 while nfds > 0 {
91 // wait for either pipe to become readable using `select`
92 let r = unsafe { libc::poll(fds.as_mut_ptr(), nfds, -1) };
93 if r == -1 {
94 let err = io::Error::last_os_error();
95 if err.kind() == io::ErrorKind::Interrupted {
96 continue;
97 }
98 return Err(err);
99 }
100
101 // Read as much as we can from each pipe, ignoring EWOULDBLOCK or
102 // EAGAIN. If we hit EOF, then this will happen because the underlying
103 // reader will return Ok(0), in which case we'll see `Ok` ourselves. In
104 // this case we flip the other fd back into blocking mode and read
105 // whatever's leftover on that file descriptor.
106 let handle = |res: io::Result<_>| match res {
107 Ok(_) => Ok(true),
108 Err(e) => {
109 if e.kind() == io::ErrorKind::WouldBlock {
110 Ok(false)
111 } else {
112 Err(e)
113 }
114 }
115 };
116 if !err_done && fds[errfd].revents != 0 && handle(err_pipe.read_to_end(&mut err))? {
117 err_done = true;
118 nfds -= 1;
119 }
120 data(false, &mut err, err_done);
121 if !out_done && fds[0].revents != 0 && handle(out_pipe.read_to_end(&mut out))? {
122 out_done = true;
123 fds[0].fd = err_pipe.as_raw_fd();
124 errfd = 0;
125 nfds -= 1;
126 }
127 data(true, &mut out, out_done);
128 }
129 Ok(())
130 }
131}
132
133#[cfg(windows)]
134mod imp {
135 use std::{
136 io,
137 os::windows::prelude::*,
138 process::{ChildStderr, ChildStdout},
139 slice,
140 };
141
142 use miow::{
143 iocp::{CompletionPort, CompletionStatus},
144 pipe::NamedPipe,
145 Overlapped,
146 };
147 use winapi::shared::winerror::ERROR_BROKEN_PIPE;
148
149 struct Pipe<'a> {
150 dst: &'a mut Vec<u8>,
151 overlapped: Overlapped,
152 pipe: NamedPipe,
153 done: bool,
154 }
155
156 pub(crate) fn read2(
157 out_pipe: ChildStdout,
158 err_pipe: ChildStderr,
159 data: &mut dyn FnMut(bool, &mut Vec<u8>, bool),
160 ) -> io::Result<()> {
161 let mut out = Vec::new();
162 let mut err = Vec::new();
163
164 let port = CompletionPort::new(1)?;
165 port.add_handle(0, &out_pipe)?;
166 port.add_handle(1, &err_pipe)?;
167
168 unsafe {
169 let mut out_pipe = Pipe::new(out_pipe, &mut out);
170 let mut err_pipe = Pipe::new(err_pipe, &mut err);
171
172 out_pipe.read()?;
173 err_pipe.read()?;
174
175 let mut status = [CompletionStatus::zero(), CompletionStatus::zero()];
176
177 while !out_pipe.done || !err_pipe.done {
178 for status in port.get_many(&mut status, None)? {
179 if status.token() == 0 {
180 out_pipe.complete(status);
181 data(true, out_pipe.dst, out_pipe.done);
182 out_pipe.read()?;
183 } else {
184 err_pipe.complete(status);
185 data(false, err_pipe.dst, err_pipe.done);
186 err_pipe.read()?;
187 }
188 }
189 }
190
191 Ok(())
192 }
193 }
194
195 impl<'a> Pipe<'a> {
196 unsafe fn new<P: IntoRawHandle>(p: P, dst: &'a mut Vec<u8>) -> Pipe<'a> {
197 Pipe {
198 dst,
199 pipe: NamedPipe::from_raw_handle(p.into_raw_handle()),
200 overlapped: Overlapped::zero(),
201 done: false,
202 }
203 }
204
205 unsafe fn read(&mut self) -> io::Result<()> {
206 let dst = slice_to_end(self.dst);
207 match self.pipe.read_overlapped(dst, self.overlapped.raw()) {
208 Ok(_) => Ok(()),
209 Err(e) => {
210 if e.raw_os_error() == Some(ERROR_BROKEN_PIPE as i32) {
211 self.done = true;
212 Ok(())
213 } else {
214 Err(e)
215 }
216 }
217 }
218 }
219
220 unsafe fn complete(&mut self, status: &CompletionStatus) {
221 let prev = self.dst.len();
222 self.dst.set_len(prev + status.bytes_transferred() as usize);
223 if status.bytes_transferred() == 0 {
224 self.done = true;
225 }
226 }
227 }
228
229 unsafe fn slice_to_end(v: &mut Vec<u8>) -> &mut [u8] {
230 if v.capacity() == 0 {
231 v.reserve(16);
232 }
233 if v.capacity() == v.len() {
234 v.reserve(1);
235 }
236 slice::from_raw_parts_mut(v.as_mut_ptr().add(v.len()), v.capacity() - v.len())
237 }
238}
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 9f01acc26..556f80882 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,10 +13,10 @@ doctest = false
13[dependencies] 13[dependencies]
14cov-mark = { version = "1.1", features = ["thread-local"] } 14cov-mark = { version = "1.1", features = ["thread-local"] }
15itertools = "0.10.0" 15itertools = "0.10.0"
16rowan = "0.13.0-pre.3" 16rowan = "=0.13.0-pre.3"
17rustc_lexer = { version = "710.0.0", package = "rustc-ap-rustc_lexer" } 17rustc_lexer = { version = "716.0.0", package = "rustc-ap-rustc_lexer" }
18rustc-hash = "1.1.0" 18rustc-hash = "1.1.0"
19arrayvec = "0.6" 19arrayvec = "0.7"
20once_cell = "1.3.1" 20once_cell = "1.3.1"
21indexmap = "1.4.0" 21indexmap = "1.4.0"
22smol_str = { version = "0.1.15", features = ["serde"] } 22smol_str = { version = "0.1.15", features = ["serde"] }
diff --git a/crates/syntax/src/ast/edit_in_place.rs b/crates/syntax/src/ast/edit_in_place.rs
index 529bd0eb1..04f97f368 100644
--- a/crates/syntax/src/ast/edit_in_place.rs
+++ b/crates/syntax/src/ast/edit_in_place.rs
@@ -14,10 +14,29 @@ use crate::{
14use super::NameOwner; 14use super::NameOwner;
15 15
16pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit { 16pub trait GenericParamsOwnerEdit: ast::GenericParamsOwner + AstNodeEdit {
17 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList;
17 fn get_or_create_where_clause(&self) -> ast::WhereClause; 18 fn get_or_create_where_clause(&self) -> ast::WhereClause;
18} 19}
19 20
20impl GenericParamsOwnerEdit for ast::Fn { 21impl GenericParamsOwnerEdit for ast::Fn {
22 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
23 match self.generic_param_list() {
24 Some(it) => it,
25 None => {
26 let position = if let Some(name) = self.name() {
27 Position::after(name.syntax)
28 } else if let Some(fn_token) = self.fn_token() {
29 Position::after(fn_token)
30 } else if let Some(param_list) = self.param_list() {
31 Position::before(param_list.syntax)
32 } else {
33 Position::last_child_of(self.syntax())
34 };
35 create_generic_param_list(position)
36 }
37 }
38 }
39
21 fn get_or_create_where_clause(&self) -> WhereClause { 40 fn get_or_create_where_clause(&self) -> WhereClause {
22 if self.where_clause().is_none() { 41 if self.where_clause().is_none() {
23 let position = if let Some(ty) = self.ret_type() { 42 let position = if let Some(ty) = self.ret_type() {
@@ -34,6 +53,20 @@ impl GenericParamsOwnerEdit for ast::Fn {
34} 53}
35 54
36impl GenericParamsOwnerEdit for ast::Impl { 55impl GenericParamsOwnerEdit for ast::Impl {
56 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
57 match self.generic_param_list() {
58 Some(it) => it,
59 None => {
60 let position = if let Some(imp_token) = self.impl_token() {
61 Position::after(imp_token)
62 } else {
63 Position::last_child_of(self.syntax())
64 };
65 create_generic_param_list(position)
66 }
67 }
68 }
69
37 fn get_or_create_where_clause(&self) -> WhereClause { 70 fn get_or_create_where_clause(&self) -> WhereClause {
38 if self.where_clause().is_none() { 71 if self.where_clause().is_none() {
39 let position = if let Some(items) = self.assoc_item_list() { 72 let position = if let Some(items) = self.assoc_item_list() {
@@ -48,6 +81,22 @@ impl GenericParamsOwnerEdit for ast::Impl {
48} 81}
49 82
50impl GenericParamsOwnerEdit for ast::Trait { 83impl GenericParamsOwnerEdit for ast::Trait {
84 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
85 match self.generic_param_list() {
86 Some(it) => it,
87 None => {
88 let position = if let Some(name) = self.name() {
89 Position::after(name.syntax)
90 } else if let Some(trait_token) = self.trait_token() {
91 Position::after(trait_token)
92 } else {
93 Position::last_child_of(self.syntax())
94 };
95 create_generic_param_list(position)
96 }
97 }
98 }
99
51 fn get_or_create_where_clause(&self) -> WhereClause { 100 fn get_or_create_where_clause(&self) -> WhereClause {
52 if self.where_clause().is_none() { 101 if self.where_clause().is_none() {
53 let position = if let Some(items) = self.assoc_item_list() { 102 let position = if let Some(items) = self.assoc_item_list() {
@@ -62,6 +111,22 @@ impl GenericParamsOwnerEdit for ast::Trait {
62} 111}
63 112
64impl GenericParamsOwnerEdit for ast::Struct { 113impl GenericParamsOwnerEdit for ast::Struct {
114 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
115 match self.generic_param_list() {
116 Some(it) => it,
117 None => {
118 let position = if let Some(name) = self.name() {
119 Position::after(name.syntax)
120 } else if let Some(struct_token) = self.struct_token() {
121 Position::after(struct_token)
122 } else {
123 Position::last_child_of(self.syntax())
124 };
125 create_generic_param_list(position)
126 }
127 }
128 }
129
65 fn get_or_create_where_clause(&self) -> WhereClause { 130 fn get_or_create_where_clause(&self) -> WhereClause {
66 if self.where_clause().is_none() { 131 if self.where_clause().is_none() {
67 let tfl = self.field_list().and_then(|fl| match fl { 132 let tfl = self.field_list().and_then(|fl| match fl {
@@ -84,6 +149,22 @@ impl GenericParamsOwnerEdit for ast::Struct {
84} 149}
85 150
86impl GenericParamsOwnerEdit for ast::Enum { 151impl GenericParamsOwnerEdit for ast::Enum {
152 fn get_or_create_generic_param_list(&self) -> ast::GenericParamList {
153 match self.generic_param_list() {
154 Some(it) => it,
155 None => {
156 let position = if let Some(name) = self.name() {
157 Position::after(name.syntax)
158 } else if let Some(enum_token) = self.enum_token() {
159 Position::after(enum_token)
160 } else {
161 Position::last_child_of(self.syntax())
162 };
163 create_generic_param_list(position)
164 }
165 }
166 }
167
87 fn get_or_create_where_clause(&self) -> WhereClause { 168 fn get_or_create_where_clause(&self) -> WhereClause {
88 if self.where_clause().is_none() { 169 if self.where_clause().is_none() {
89 let position = if let Some(gpl) = self.generic_param_list() { 170 let position = if let Some(gpl) = self.generic_param_list() {
@@ -104,6 +185,37 @@ fn create_where_clause(position: Position) {
104 ted::insert(position, where_clause.syntax()); 185 ted::insert(position, where_clause.syntax());
105} 186}
106 187
188fn create_generic_param_list(position: Position) -> ast::GenericParamList {
189 let gpl = make::generic_param_list(empty()).clone_for_update();
190 ted::insert_raw(position, gpl.syntax());
191 gpl
192}
193
194impl ast::GenericParamList {
195 pub fn add_generic_param(&self, generic_param: ast::GenericParam) {
196 match self.generic_params().last() {
197 Some(last_param) => {
198 let mut elems = Vec::new();
199 if !last_param
200 .syntax()
201 .siblings_with_tokens(Direction::Next)
202 .any(|it| it.kind() == T![,])
203 {
204 elems.push(make::token(T![,]).into());
205 elems.push(make::tokens::single_space().into());
206 };
207 elems.push(generic_param.syntax().clone().into());
208 let after_last_param = Position::after(last_param.syntax());
209 ted::insert_all(after_last_param, elems);
210 }
211 None => {
212 let after_l_angle = Position::after(self.l_angle_token().unwrap());
213 ted::insert(after_l_angle, generic_param.syntax())
214 }
215 }
216 }
217}
218
107impl ast::WhereClause { 219impl ast::WhereClause {
108 pub fn add_predicate(&self, predicate: ast::WherePred) { 220 pub fn add_predicate(&self, predicate: ast::WherePred) {
109 if let Some(pred) = self.predicates().last() { 221 if let Some(pred) = self.predicates().last() {
@@ -164,3 +276,44 @@ impl ast::Use {
164 ted::remove(self.syntax()) 276 ted::remove(self.syntax())
165 } 277 }
166} 278}
279
280#[cfg(test)]
281mod tests {
282 use std::fmt;
283
284 use crate::SourceFile;
285
286 use super::*;
287
288 fn ast_mut_from_text<N: AstNode>(text: &str) -> N {
289 let parse = SourceFile::parse(text);
290 parse.tree().syntax().descendants().find_map(N::cast).unwrap().clone_for_update()
291 }
292
293 #[test]
294 fn test_create_generic_param_list() {
295 fn check_create_gpl<N: GenericParamsOwnerEdit + fmt::Display>(before: &str, after: &str) {
296 let gpl_owner = ast_mut_from_text::<N>(before);
297 gpl_owner.get_or_create_generic_param_list();
298 assert_eq!(gpl_owner.to_string(), after);
299 }
300
301 check_create_gpl::<ast::Fn>("fn foo", "fn foo<>");
302 check_create_gpl::<ast::Fn>("fn foo() {}", "fn foo<>() {}");
303
304 check_create_gpl::<ast::Impl>("impl", "impl<>");
305 check_create_gpl::<ast::Impl>("impl Struct {}", "impl<> Struct {}");
306 check_create_gpl::<ast::Impl>("impl Trait for Struct {}", "impl<> Trait for Struct {}");
307
308 check_create_gpl::<ast::Trait>("trait Trait<>", "trait Trait<>");
309 check_create_gpl::<ast::Trait>("trait Trait<> {}", "trait Trait<> {}");
310
311 check_create_gpl::<ast::Struct>("struct A", "struct A<>");
312 check_create_gpl::<ast::Struct>("struct A;", "struct A<>;");
313 check_create_gpl::<ast::Struct>("struct A();", "struct A<>();");
314 check_create_gpl::<ast::Struct>("struct A {}", "struct A<> {}");
315
316 check_create_gpl::<ast::Enum>("enum E", "enum E<>");
317 check_create_gpl::<ast::Enum>("enum E {", "enum E<> {");
318 }
319}
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index 3a588e540..222b7e212 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -29,9 +29,13 @@ pub fn ty(text: &str) -> ast::Type {
29pub fn ty_unit() -> ast::Type { 29pub fn ty_unit() -> ast::Type {
30 ty("()") 30 ty("()")
31} 31}
32// FIXME: handle types of length == 1
33pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type { 32pub fn ty_tuple(types: impl IntoIterator<Item = ast::Type>) -> ast::Type {
34 let contents = types.into_iter().join(", "); 33 let mut count: usize = 0;
34 let mut contents = types.into_iter().inspect(|_| count += 1).join(", ");
35 if count == 1 {
36 contents.push(',');
37 }
38
35 ty(&format!("({})", contents)) 39 ty(&format!("({})", contents))
36} 40}
37// FIXME: handle path to type 41// FIXME: handle path to type
@@ -301,13 +305,23 @@ pub fn wildcard_pat() -> ast::WildcardPat {
301 } 305 }
302} 306}
303 307
308pub fn literal_pat(lit: &str) -> ast::LiteralPat {
309 return from_text(lit);
310
311 fn from_text(text: &str) -> ast::LiteralPat {
312 ast_from_text(&format!("fn f() {{ match x {{ {} => {{}} }} }}", text))
313 }
314}
315
304/// Creates a tuple of patterns from an iterator of patterns. 316/// Creates a tuple of patterns from an iterator of patterns.
305/// 317///
306/// Invariant: `pats` must be length > 1 318/// Invariant: `pats` must be length > 0
307///
308/// FIXME handle `pats` length == 1
309pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat { 319pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
310 let pats_str = pats.into_iter().map(|p| p.to_string()).join(", "); 320 let mut count: usize = 0;
321 let mut pats_str = pats.into_iter().inspect(|_| count += 1).join(", ");
322 if count == 1 {
323 pats_str.push(',');
324 }
311 return from_text(&format!("({})", pats_str)); 325 return from_text(&format!("({})", pats_str));
312 326
313 fn from_text(text: &str) -> ast::TuplePat { 327 fn from_text(text: &str) -> ast::TuplePat {
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index ae98dbd26..171099661 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -125,6 +125,18 @@ pub enum AttrKind {
125 Outer, 125 Outer,
126} 126}
127 127
128impl AttrKind {
129 /// Returns `true` if the attr_kind is [`Inner`].
130 pub fn is_inner(&self) -> bool {
131 matches!(self, Self::Inner)
132 }
133
134 /// Returns `true` if the attr_kind is [`Outer`].
135 pub fn is_outer(&self) -> bool {
136 matches!(self, Self::Outer)
137 }
138}
139
128impl ast::Attr { 140impl ast::Attr {
129 pub fn as_simple_atom(&self) -> Option<SmolStr> { 141 pub fn as_simple_atom(&self) -> Option<SmolStr> {
130 if self.eq_token().is_some() || self.token_tree().is_some() { 142 if self.eq_token().is_some() || self.token_tree().is_some() {
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index 177d4ff67..450f2e447 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -165,6 +165,13 @@ fn ws_between(left: &SyntaxElement, right: &SyntaxElement) -> Option<SyntaxToken
165 if right.kind() == T![;] || right.kind() == T![,] { 165 if right.kind() == T![;] || right.kind() == T![,] {
166 return None; 166 return None;
167 } 167 }
168 if left.kind() == T![<] || right.kind() == T![>] {
169 return None;
170 }
171 if left.kind() == T![&] && right.kind() == SyntaxKind::LIFETIME {
172 return None;
173 }
174
168 if right.kind() == SyntaxKind::USE { 175 if right.kind() == SyntaxKind::USE {
169 let indent = IndentLevel::from_element(left); 176 let indent = IndentLevel::from_element(left);
170 return Some(make::tokens::whitespace(&format!("\n{}", indent))); 177 return Some(make::tokens::whitespace(&format!("\n{}", indent)));
diff --git a/crates/syntax/src/validation/block.rs b/crates/syntax/src/validation/block.rs
index ad9901468..40170014f 100644
--- a/crates/syntax/src/validation/block.rs
+++ b/crates/syntax/src/validation/block.rs
@@ -13,7 +13,7 @@ pub(crate) fn validate_block_expr(block: ast::BlockExpr, errors: &mut Vec<Syntax
13 _ => {} 13 _ => {}
14 } 14 }
15 } 15 }
16 errors.extend(block.attrs().map(|attr| { 16 errors.extend(block.attrs().filter(|attr| attr.kind().is_inner()).map(|attr| {
17 SyntaxError::new( 17 SyntaxError::new(
18 "A block in this position cannot accept inner attributes", 18 "A block in this position cannot accept inner attributes",
19 attr.syntax().text_range(), 19 attr.syntax().text_range(),
diff --git a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
index 3016a6574..1ff3f7656 100644
--- a/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0117_macro_call_type.rast
@@ -7,15 +7,16 @@ [email protected]
7 [email protected] " " 7 [email protected] " "
8 [email protected] "=" 8 [email protected] "="
9 [email protected] " " 9 [email protected] " "
10 [email protected] 10 [email protected]
11 [email protected] 11 [email protected]
12 [email protected] 12 [email protected]
13 [email protected] 13 [email protected]
14 [email protected] "foo" 14 [email protected]
15 [email protected] "!" 15 [email protected] "foo"
16 [email protected] 16 [email protected] "!"
17 [email protected] "(" 17 [email protected]
18 [email protected] ")" 18 [email protected] "("
19 [email protected] ")"
19 [email protected] ";" 20 [email protected] ";"
20 [email protected] "\n" 21 [email protected] "\n"
21 [email protected] 22 [email protected]
@@ -26,19 +27,20 @@ [email protected]
26 [email protected] " " 27 [email protected] " "
27 [email protected] "=" 28 [email protected] "="
28 [email protected] " " 29 [email protected] " "
29 [email protected] 30 [email protected]
30 [email protected] 31 [email protected]
31 [email protected] 32 [email protected]
32 [email protected] 33 [email protected]
33 [email protected] 34 [email protected]
34 [email protected] "crate" 35 [email protected]
35 [email protected] "::" 36 [email protected] "crate"
36 [email protected] 37 [email protected] "::"
37 [email protected] 38 [email protected]
38 [email protected] "foo" 39 [email protected]
39 [email protected] "!" 40 [email protected] "foo"
40 [email protected] 41 [email protected] "!"
41 [email protected] "(" 42 [email protected]
42 [email protected] ")" 43 [email protected] "("
44 [email protected] ")"
43 [email protected] ";" 45 [email protected] ";"
44 [email protected] "\n" 46 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
index 925409bdf..e9202a612 100644
--- a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
+++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rast
@@ -1,5 +1,5 @@
1SOURCE_FILE@0..63 1SOURCE_FILE@0..102
2 FN@0..62 2 FN@0..101
3 [email protected] "fn" 3 [email protected] "fn"
4 [email protected] " " 4 [email protected] " "
5 [email protected] 5 [email protected]
@@ -8,7 +8,7 @@ [email protected]
8 [email protected] "(" 8 [email protected] "("
9 [email protected] ")" 9 [email protected] ")"
10 [email protected] " " 10 [email protected] " "
11 BLOCK_EXPR@9..62 11 BLOCK_EXPR@9..101
12 [email protected] "{" 12 [email protected] "{"
13 [email protected] "\n " 13 [email protected] "\n "
14 [email protected] 14 [email protected]
@@ -70,6 +70,52 @@ [email protected]
70 [email protected] "(" 70 [email protected] "("
71 [email protected] ")" 71 [email protected] ")"
72 [email protected] ";" 72 [email protected] ";"
73 [email protected] "\n" 73 [email protected] "\n "
74 [email protected] "}" 74 [email protected]
75 [email protected] "\n" 75 [email protected] "let"
76 [email protected] " "
77 [email protected]
78 [email protected]
79 [email protected]
80 [email protected]
81 [email protected] "S"
82 [email protected] " "
83 [email protected]
84 [email protected] "{"
85 [email protected] " "
86 [email protected]
87 [email protected]
88 [email protected] "#"
89 [email protected] "["
90 [email protected]
91 [email protected]
92 [email protected]
93 [email protected] "cfg"
94 [email protected]
95 [email protected] "("
96 [email protected] "any"
97 [email protected]
98 [email protected] "("
99 [email protected] ")"
100 [email protected] ")"
101 [email protected] "]"
102 [email protected] " "
103 [email protected]
104 [email protected] "x"
105 [email protected] ":"
106 [email protected] " "
107 [email protected]
108 [email protected]
109 [email protected] "1"
110 [email protected] " "
111 [email protected] "}"
112 [email protected] " "
113 [email protected] "="
114 [email protected] " "
115 [email protected]
116 [email protected] "("
117 [email protected] ")"
118 [email protected] ";"
119 [email protected] "\n"
120 [email protected] "}"
121 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs
index 26b1d5f89..53cfdc22d 100644
--- a/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs
+++ b/crates/syntax/test_data/parser/inline/ok/0145_record_pat_field.rs
@@ -1,4 +1,5 @@
1fn foo() { 1fn foo() {
2 let S { 0: 1 } = (); 2 let S { 0: 1 } = ();
3 let S { x: 1 } = (); 3 let S { x: 1 } = ();
4 let S { #[cfg(any())] x: 1 } = ();
4} 5}
diff --git a/crates/syntax/test_data/parser/ok/0045_block_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
new file mode 100644
index 000000000..50ab52d32
--- /dev/null
+++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rast
@@ -0,0 +1,218 @@
1[email protected]
2 [email protected]
3 [email protected] "fn"
4 [email protected] " "
5 [email protected]
6 [email protected] "inner"
7 [email protected]
8 [email protected] "("
9 [email protected] ")"
10 [email protected] " "
11 [email protected]
12 [email protected] "{"
13 [email protected] "\n "
14 [email protected]
15 [email protected] "#"
16 [email protected] "!"
17 [email protected] "["
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "doc"
22 [email protected]
23 [email protected] "("
24 [email protected] "\"Inner attributes all ..."
25 [email protected] ")"
26 [email protected] "]"
27 [email protected] "\n "
28 [email protected] "//! As are ModuleDoc ..."
29 [email protected] "\n "
30 [email protected]
31 [email protected]
32 [email protected] "{"
33 [email protected] "\n "
34 [email protected]
35 [email protected] "#"
36 [email protected] "!"
37 [email protected] "["
38 [email protected]
39 [email protected]
40 [email protected]
41 [email protected] "doc"
42 [email protected]
43 [email protected] "("
44 [email protected] "\"Inner attributes are ..."
45 [email protected] ")"
46 [email protected] "]"
47 [email protected] "\n "
48 [email protected]
49 [email protected] "#"
50 [email protected] "!"
51 [email protected] "["
52 [email protected]
53 [email protected]
54 [email protected]
55 [email protected] "doc"
56 [email protected]
57 [email protected] "("
58 [email protected] "\"Being validated is n ..."
59 [email protected] ")"
60 [email protected] "]"
61 [email protected] "\n "
62 [email protected] "//! As are ModuleDoc ..."
63 [email protected] "\n "
64 [email protected] "}"
65 [email protected] ";"
66 [email protected] "\n "
67 [email protected]
68 [email protected] "{"
69 [email protected] "\n "
70 [email protected]
71 [email protected] "#"
72 [email protected] "!"
73 [email protected] "["
74 [email protected]
75 [email protected]
76 [email protected]
77 [email protected] "doc"
78 [email protected]
79 [email protected] "("
80 [email protected] "\"Inner attributes are ..."
81 [email protected] ")"
82 [email protected] "]"
83 [email protected] "\n "
84 [email protected] "//! As are ModuleDoc ..."
85 [email protected] "\n "
86 [email protected] "}"
87 [email protected] "\n"
88 [email protected] "}"
89 [email protected] "\n\n"
90 [email protected]
91 [email protected] "fn"
92 [email protected] " "
93 [email protected]
94 [email protected] "outer"
95 [email protected]
96 [email protected] "("
97 [email protected] ")"
98 [email protected] " "
99 [email protected]
100 [email protected] "{"
101 [email protected] "\n "
102 [email protected]
103 [email protected] "let"
104 [email protected] " "
105 [email protected]
106 [email protected] "_"
107 [email protected] " "
108 [email protected] "="
109 [email protected] " "
110 [email protected]
111 [email protected]
112 [email protected] "#"
113 [email protected] "["
114 [email protected]
115 [email protected]
116 [email protected]
117 [email protected] "doc"
118 [email protected]
119 [email protected] "("
120 [email protected] "\"Outer attributes are ..."
121 [email protected] ")"
122 [email protected] "]"
123 [email protected] " "
124 [email protected] "{"
125 [email protected] "}"
126 [email protected] ";"
127 [email protected] "\n"
128 [email protected] "}"
129 [email protected] "\n\n"
130 [email protected] "// https://github.com ..."
131 [email protected] "\n"
132 [email protected]
133 [email protected] "impl"
134 [email protected] " "
135 [email protected]
136 [email protected]
137 [email protected]
138 [email protected]
139 [email protected] "Whatever"
140 [email protected] " "
141 [email protected]
142 [email protected] "{"
143 [email protected] "\n "
144 [email protected]
145 [email protected] "fn"
146 [email protected] " "
147 [email protected]
148 [email protected] "salsa_event"
149 [email protected]
150 [email protected] "("
151 [email protected]
152 [email protected] "&"
153 [email protected]
154 [email protected] "self"
155 [email protected] ","
156 [email protected] " "
157 [email protected]
158 [email protected]
159 [email protected]
160 [email protected] "event_fn"
161 [email protected] ":"
162 [email protected] " "
163 [email protected]
164 [email protected] "impl"
165 [email protected] " "
166 [email protected]
167 [email protected]
168 [email protected]
169 [email protected]
170 [email protected]
171 [email protected]
172 [email protected] "Fn"
173 [email protected]
174 [email protected] "("
175 [email protected] ")"
176 [email protected] " "
177 [email protected]
178 [email protected] "->"
179 [email protected] " "
180 [email protected]
181 [email protected]
182 [email protected]
183 [email protected]
184 [email protected] "Event"
185 [email protected]
186 [email protected] "<"
187 [email protected]
188 [email protected]
189 [email protected]
190 [email protected]
191 [email protected]
192 [email protected] "Self"
193 [email protected] ">"
194 [email protected] ")"
195 [email protected] " "
196 [email protected]
197 [email protected] "{"
198 [email protected] "\n "
199 [email protected]
200 [email protected] "#"
201 [email protected] "!"
202 [email protected] "["
203 [email protected]
204 [email protected]
205 [email protected]
206 [email protected] "allow"
207 [email protected]
208 [email protected] "("
209 [email protected] "unused_variables"
210 [email protected] ")"
211 [email protected] "]"
212 [email protected] " "
213 [email protected] "// this is `inner_at ..."
214 [email protected] "\n "
215 [email protected] "}"
216 [email protected] "\n"
217 [email protected] "}"
218 [email protected] "\n"
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs
index 88df8138e..ed4593759 100644
--- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rs
+++ b/crates/syntax/test_data/parser/ok/0045_block_attrs.rs
@@ -1,4 +1,4 @@
1fn block() { 1fn inner() {
2 #![doc("Inner attributes allowed here")] 2 #![doc("Inner attributes allowed here")]
3 //! As are ModuleDoc style comments 3 //! As are ModuleDoc style comments
4 { 4 {
@@ -12,6 +12,10 @@ fn block() {
12 } 12 }
13} 13}
14 14
15fn outer() {
16 let _ = #[doc("Outer attributes are always allowed")] {};
17}
18
15// https://github.com/rust-analyzer/rust-analyzer/issues/689 19// https://github.com/rust-analyzer/rust-analyzer/issues/689
16impl Whatever { 20impl Whatever {
17 fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) { 21 fn salsa_event(&self, event_fn: impl Fn() -> Event<Self>) {
diff --git a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast b/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast
deleted file mode 100644
index 6afed5f05..000000000
--- a/crates/syntax/test_data/parser/ok/0045_block_inner_attrs.rast
+++ /dev/null
@@ -1,178 +0,0 @@
1[email protected]
2 [email protected]
3 [email protected] "fn"
4 [email protected] " "
5 [email protected]
6 [email protected] "block"
7 [email protected]
8 [email protected] "("
9 [email protected] ")"
10 [email protected] " "
11 [email protected]
12 [email protected] "{"
13 [email protected] "\n "
14 [email protected]
15 [email protected] "#"
16 [email protected] "!"
17 [email protected] "["
18 [email protected]
19 [email protected]
20 [email protected]
21 [email protected] "doc"
22 [email protected]
23 [email protected] "("
24 [email protected] "\"Inner attributes all ..."
25 [email protected] ")"
26 [email protected] "]"
27 [email protected] "\n "
28 [email protected] "//! As are ModuleDoc ..."
29 [email protected] "\n "
30 [email protected]
31 [email protected]
32 [email protected] "{"
33 [email protected] "\n "
34 [email protected]
35 [email protected] "#"
36 [email protected] "!"
37 [email protected] "["
38 [email protected]
39 [email protected]
40 [email protected]
41 [email protected] "doc"
42 [email protected]
43 [email protected] "("
44 [email protected] "\"Inner attributes are ..."
45 [email protected] ")"
46 [email protected] "]"
47 [email protected] "\n "
48 [email protected]
49 [email protected] "#"
50 [email protected] "!"
51 [email protected] "["
52 [email protected]
53 [email protected]
54 [email protected]
55 [email protected] "doc"
56 [email protected]
57 [email protected] "("
58 [email protected] "\"Being validated is n ..."
59 [email protected] ")"
60 [email protected] "]"
61 [email protected] "\n "
62 [email protected] "//! As are ModuleDoc ..."
63 [email protected] "\n "
64 [email protected] "}"
65 [email protected] ";"
66 [email protected] "\n "
67 [email protected]
68 [email protected] "{"
69 [email protected] "\n "
70 [email protected]
71 [email protected] "#"
72 [email protected] "!"
73 [email protected] "["
74 [email protected]
75 [email protected]
76 [email protected]
77 [email protected] "doc"
78 [email protected]
79 [email protected] "("
80 [email protected] "\"Inner attributes are ..."
81 [email protected] ")"
82 [email protected] "]"
83 [email protected] "\n "
84 [email protected] "//! As are ModuleDoc ..."
85 [email protected] "\n "
86 [email protected] "}"
87 [email protected] "\n"
88 [email protected] "}"
89 [email protected] "\n\n"
90 [email protected] "// https://github.com ..."
91 [email protected] "\n"
92 [email protected]
93 [email protected] "impl"
94 [email protected] " "
95 [email protected]
96 [email protected]
97 [email protected]
98 [email protected]
99 [email protected] "Whatever"
100 [email protected] " "
101 [email protected]
102 [email protected] "{"
103 [email protected] "\n "
104 [email protected]
105 [email protected] "fn"
106 [email protected] " "
107 [email protected]
108 [email protected] "salsa_event"
109 [email protected]
110 [email protected] "("
111 [email protected]
112 [email protected] "&"
113 [email protected]
114 [email protected] "self"
115 [email protected] ","
116 [email protected] " "
117 [email protected]
118 [email protected]
119 [email protected]
120 [email protected] "event_fn"
121 [email protected] ":"
122 [email protected] " "
123 [email protected]
124 [email protected] "impl"
125 [email protected] " "
126 [email protected]
127 [email protected]
128 [email protected]
129 [email protected]
130 [email protected]
131 [email protected]
132 [email protected] "Fn"
133 [email protected]
134 [email protected] "("
135 [email protected] ")"
136 [email protected] " "
137 [email protected]
138 [email protected] "->"
139 [email protected] " "
140 [email protected]
141 [email protected]
142 [email protected]
143 [email protected]
144 [email protected] "Event"
145 [email protected]
146 [email protected] "<"
147 [email protected]
148 [email protected]
149 [email protected]
150 [email protected]
151 [email protected]
152 [email protected] "Self"
153 [email protected] ">"
154 [email protected] ")"
155 [email protected] " "
156 [email protected]
157 [email protected] "{"
158 [email protected] "\n "
159 [email protected]
160 [email protected] "#"
161 [email protected] "!"
162 [email protected] "["
163 [email protected]
164 [email protected]
165 [email protected]
166 [email protected] "allow"
167 [email protected]
168 [email protected] "("
169 [email protected] "unused_variables"
170 [email protected] ")"
171 [email protected] "]"
172 [email protected] " "
173 [email protected] "// this is `inner_at ..."
174 [email protected] "\n "
175 [email protected] "}"
176 [email protected] "\n"
177 [email protected] "}"
178 [email protected] "\n"
diff --git a/crates/test_utils/src/assert_linear.rs b/crates/test_utils/src/assert_linear.rs
new file mode 100644
index 000000000..6ecc232e1
--- /dev/null
+++ b/crates/test_utils/src/assert_linear.rs
@@ -0,0 +1,112 @@
1//! Checks that a set of measurements looks like a linear function rather than
2//! like a quadratic function. Algorithm:
3//!
4//! 1. Linearly scale input to be in [0; 1)
5//! 2. Using linear regression, compute the best linear function approximating
6//! the input.
7//! 3. Compute RMSE and maximal absolute error.
8//! 4. Check that errors are within tolerances and that the constant term is not
9//! too negative.
10//!
11//! Ideally, we should use a proper "model selection" to directly compare
12//! quadratic and linear models, but that sounds rather complicated:
13//!
14//! https://stats.stackexchange.com/questions/21844/selecting-best-model-based-on-linear-quadratic-and-cubic-fit-of-data
15//!
16//! We might get false positives on a VM, but never false negatives. So, if the
17//! first round fails, we repeat the ordeal three more times and fail only if
18//! every time there's a fault.
19use stdx::format_to;
20
21#[derive(Default)]
22pub struct AssertLinear {
23 rounds: Vec<Round>,
24}
25
26#[derive(Default)]
27struct Round {
28 samples: Vec<(f64, f64)>,
29 plot: String,
30 linear: bool,
31}
32
33impl AssertLinear {
34 pub fn next_round(&mut self) -> bool {
35 if let Some(round) = self.rounds.last_mut() {
36 round.finish();
37 }
38 if self.rounds.iter().any(|it| it.linear) || self.rounds.len() == 4 {
39 return false;
40 }
41 self.rounds.push(Round::default());
42 true
43 }
44
45 pub fn sample(&mut self, x: f64, y: f64) {
46 self.rounds.last_mut().unwrap().samples.push((x, y))
47 }
48}
49
50impl Drop for AssertLinear {
51 fn drop(&mut self) {
52 assert!(!self.rounds.is_empty());
53 if self.rounds.iter().all(|it| !it.linear) {
54 for round in &self.rounds {
55 eprintln!("\n{}", round.plot);
56 }
57 panic!("Doesn't look linear!")
58 }
59 }
60}
61
62impl Round {
63 fn finish(&mut self) {
64 let (mut xs, mut ys): (Vec<_>, Vec<_>) = self.samples.iter().copied().unzip();
65 normalize(&mut xs);
66 normalize(&mut ys);
67 let xy = xs.iter().copied().zip(ys.iter().copied());
68
69 // Linear regression: finding a and b to fit y = a + b*x.
70
71 let mean_x = mean(&xs);
72 let mean_y = mean(&ys);
73
74 let b = {
75 let mut num = 0.0;
76 let mut denom = 0.0;
77 for (x, y) in xy.clone() {
78 num += (x - mean_x) * (y - mean_y);
79 denom += (x - mean_x).powi(2);
80 }
81 num / denom
82 };
83
84 let a = mean_y - b * mean_x;
85
86 self.plot = format!("y_pred = {:.3} + {:.3} * x\n\nx y y_pred\n", a, b);
87
88 let mut se = 0.0;
89 let mut max_error = 0.0f64;
90 for (x, y) in xy {
91 let y_pred = a + b * x;
92 se += (y - y_pred).powi(2);
93 max_error = max_error.max((y_pred - y).abs());
94
95 format_to!(self.plot, "{:.3} {:.3} {:.3}\n", x, y, y_pred);
96 }
97
98 let rmse = (se / xs.len() as f64).sqrt();
99 format_to!(self.plot, "\nrmse = {:.3} max error = {:.3}", rmse, max_error);
100
101 self.linear = rmse < 0.05 && max_error < 0.1 && a > -0.1;
102
103 fn normalize(xs: &mut Vec<f64>) {
104 let max = xs.iter().copied().max_by(|a, b| a.partial_cmp(b).unwrap()).unwrap();
105 xs.iter_mut().for_each(|it| *it /= max);
106 }
107
108 fn mean(xs: &[f64]) -> f64 {
109 xs.iter().copied().sum::<f64>() / (xs.len() as f64)
110 }
111 }
112}
diff --git a/crates/test_utils/src/bench_fixture.rs b/crates/test_utils/src/bench_fixture.rs
index 3a37c4473..979156263 100644
--- a/crates/test_utils/src/bench_fixture.rs
+++ b/crates/test_utils/src/bench_fixture.rs
@@ -8,7 +8,10 @@ use crate::project_root;
8 8
9pub fn big_struct() -> String { 9pub fn big_struct() -> String {
10 let n = 1_000; 10 let n = 1_000;
11 big_struct_n(n)
12}
11 13
14pub fn big_struct_n(n: u32) -> String {
12 let mut buf = "pub struct RegisterBlock {".to_string(); 15 let mut buf = "pub struct RegisterBlock {".to_string();
13 for i in 0..n { 16 for i in 0..n {
14 format_to!(buf, " /// Doc comment for {}.\n", i); 17 format_to!(buf, " /// Doc comment for {}.\n", i);
diff --git a/crates/test_utils/src/fixture.rs b/crates/test_utils/src/fixture.rs
index 6bc824e94..099baeca2 100644
--- a/crates/test_utils/src/fixture.rs
+++ b/crates/test_utils/src/fixture.rs
@@ -1,5 +1,65 @@
1//! Defines `Fixture` -- a convenient way to describe the initial state of 1//! Defines `Fixture` -- a convenient way to describe the initial state of
2//! rust-analyzer database from a single string. 2//! rust-analyzer database from a single string.
3//!
4//! Fixtures are strings containing rust source code with optional metadata.
5//! A fixture without metadata is parsed into a single source file.
6//! Use this to test functionality local to one file.
7//!
8//! Simple Example:
9//! ```
10//! r#"
11//! fn main() {
12//! println!("Hello World")
13//! }
14//! "#
15//! ```
16//!
17//! Metadata can be added to a fixture after a `//-` comment.
18//! The basic form is specifying filenames,
19//! which is also how to define multiple files in a single test fixture
20//!
21//! Example using two files in the same crate:
22//! ```
23//! "
24//! //- /main.rs
25//! mod foo;
26//! fn main() {
27//! foo::bar();
28//! }
29//!
30//! //- /foo.rs
31//! pub fn bar() {}
32//! "
33//! ```
34//!
35//! Example using two crates with one file each, with one crate depending on the other:
36//! ```
37//! r#"
38//! //- /main.rs crate:a deps:b
39//! fn main() {
40//! b::foo();
41//! }
42//! //- /lib.rs crate:b
43//! pub fn b() {
44//! println!("Hello World")
45//! }
46//! "#
47//! ```
48//!
49//! Metadata allows specifying all settings and variables
50//! that are available in a real rust project:
51//! - crate names via `crate:cratename`
52//! - dependencies via `deps:dep1,dep2`
53//! - configuration settings via `cfg:dbg=false,opt_level=2`
54//! - environment variables via `env:PATH=/bin,RUST_LOG=debug`
55//!
56//! Example using all available metadata:
57//! ```
58//! "
59//! //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo
60//! fn insert_source_code_here() {}
61//! "
62//! ```
3 63
4use rustc_hash::FxHashMap; 64use rustc_hash::FxHashMap;
5use stdx::{lines_with_ends, split_once, trim_indent}; 65use stdx::{lines_with_ends, split_once, trim_indent};
@@ -24,7 +84,7 @@ impl Fixture {
24 /// //- some meta 84 /// //- some meta
25 /// line 1 85 /// line 1
26 /// line 2 86 /// line 2
27 /// // - other meta 87 /// //- other meta
28 /// ``` 88 /// ```
29 pub fn parse(ra_fixture: &str) -> Vec<Fixture> { 89 pub fn parse(ra_fixture: &str) -> Vec<Fixture> {
30 let fixture = trim_indent(ra_fixture); 90 let fixture = trim_indent(ra_fixture);
diff --git a/crates/test_utils/src/lib.rs b/crates/test_utils/src/lib.rs
index c5f859790..72466c957 100644
--- a/crates/test_utils/src/lib.rs
+++ b/crates/test_utils/src/lib.rs
@@ -8,6 +8,7 @@
8 8
9pub mod bench_fixture; 9pub mod bench_fixture;
10mod fixture; 10mod fixture;
11mod assert_linear;
11 12
12use std::{ 13use std::{
13 convert::{TryFrom, TryInto}, 14 convert::{TryFrom, TryInto},
@@ -22,7 +23,7 @@ use text_size::{TextRange, TextSize};
22pub use dissimilar::diff as __diff; 23pub use dissimilar::diff as __diff;
23pub use rustc_hash::FxHashMap; 24pub use rustc_hash::FxHashMap;
24 25
25pub use crate::fixture::Fixture; 26pub use crate::{assert_linear::AssertLinear, fixture::Fixture};
26 27
27pub const CURSOR_MARKER: &str = "$0"; 28pub const CURSOR_MARKER: &str = "$0";
28pub const ESCAPED_CURSOR_MARKER: &str = "\\$0"; 29pub const ESCAPED_CURSOR_MARKER: &str = "\\$0";
diff --git a/crates/vfs/Cargo.toml b/crates/vfs/Cargo.toml
index c318a68f7..894944b18 100644
--- a/crates/vfs/Cargo.toml
+++ b/crates/vfs/Cargo.toml
@@ -14,3 +14,4 @@ rustc-hash = "1.0"
14fst = "0.4" 14fst = "0.4"
15 15
16paths = { path = "../paths", version = "0.0.0" } 16paths = { path = "../paths", version = "0.0.0" }
17indexmap = "1.6.2"
diff --git a/crates/vfs/src/path_interner.rs b/crates/vfs/src/path_interner.rs
index 2189e5e25..6e049f0d4 100644
--- a/crates/vfs/src/path_interner.rs
+++ b/crates/vfs/src/path_interner.rs
@@ -1,15 +1,22 @@
1//! Maps paths to compact integer ids. We don't care about clearings paths which 1//! Maps paths to compact integer ids. We don't care about clearings paths which
2//! no longer exist -- the assumption is total size of paths we ever look at is 2//! no longer exist -- the assumption is total size of paths we ever look at is
3//! not too big. 3//! not too big.
4use rustc_hash::FxHashMap; 4use std::hash::BuildHasherDefault;
5
6use indexmap::IndexSet;
7use rustc_hash::FxHasher;
5 8
6use crate::{FileId, VfsPath}; 9use crate::{FileId, VfsPath};
7 10
8/// Structure to map between [`VfsPath`] and [`FileId`]. 11/// Structure to map between [`VfsPath`] and [`FileId`].
9#[derive(Default)]
10pub(crate) struct PathInterner { 12pub(crate) struct PathInterner {
11 map: FxHashMap<VfsPath, FileId>, 13 map: IndexSet<VfsPath, BuildHasherDefault<FxHasher>>,
12 vec: Vec<VfsPath>, 14}
15
16impl Default for PathInterner {
17 fn default() -> Self {
18 Self { map: IndexSet::default() }
19 }
13} 20}
14 21
15impl PathInterner { 22impl PathInterner {
@@ -17,7 +24,7 @@ impl PathInterner {
17 /// 24 ///
18 /// If `path` does not exists in `self`, returns [`None`]. 25 /// If `path` does not exists in `self`, returns [`None`].
19 pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> { 26 pub(crate) fn get(&self, path: &VfsPath) -> Option<FileId> {
20 self.map.get(path).copied() 27 self.map.get_index_of(path).map(|i| FileId(i as u32))
21 } 28 }
22 29
23 /// Insert `path` in `self`. 30 /// Insert `path` in `self`.
@@ -25,13 +32,9 @@ impl PathInterner {
25 /// - If `path` already exists in `self`, returns its associated id; 32 /// - If `path` already exists in `self`, returns its associated id;
26 /// - Else, returns a newly allocated id. 33 /// - Else, returns a newly allocated id.
27 pub(crate) fn intern(&mut self, path: VfsPath) -> FileId { 34 pub(crate) fn intern(&mut self, path: VfsPath) -> FileId {
28 if let Some(id) = self.get(&path) { 35 let (id, _added) = self.map.insert_full(path);
29 return id; 36 assert!(id < u32::MAX as usize);
30 } 37 FileId(id as u32)
31 let id = FileId(self.vec.len() as u32);
32 self.map.insert(path.clone(), id);
33 self.vec.push(path);
34 id
35 } 38 }
36 39
37 /// Returns the path corresponding to `id`. 40 /// Returns the path corresponding to `id`.
@@ -40,6 +43,6 @@ impl PathInterner {
40 /// 43 ///
41 /// Panics if `id` does not exists in `self`. 44 /// Panics if `id` does not exists in `self`.
42 pub(crate) fn lookup(&self, id: FileId) -> &VfsPath { 45 pub(crate) fn lookup(&self, id: FileId) -> &VfsPath {
43 &self.vec[id.0 as usize] 46 self.map.get_index(id.0 as usize).unwrap()
44 } 47 }
45} 48}