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/lib.rs3
-rw-r--r--crates/cfg/src/tests.rs8
-rw-r--r--crates/hir/Cargo.toml2
-rw-r--r--crates/hir/src/db.rs10
-rw-r--r--crates/hir/src/display.rs27
-rw-r--r--crates/hir/src/lib.rs230
-rw-r--r--crates/hir/src/semantics.rs10
-rw-r--r--crates/hir/src/source_analyzer.rs63
-rw-r--r--crates/hir_def/Cargo.toml1
-rw-r--r--crates/hir_def/src/adt.rs9
-rw-r--r--crates/hir_def/src/attr.rs199
-rw-r--r--crates/hir_def/src/body.rs24
-rw-r--r--crates/hir_def/src/body/lower.rs83
-rw-r--r--crates/hir_def/src/body/tests.rs4
-rw-r--r--crates/hir_def/src/child_by_source.rs6
-rw-r--r--crates/hir_def/src/data.rs90
-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.rs604
-rw-r--r--crates/hir_def/src/generics.rs62
-rw-r--r--crates/hir_def/src/intern.rs216
-rw-r--r--crates/hir_def/src/item_scope.rs35
-rw-r--r--crates/hir_def/src/item_tree.rs159
-rw-r--r--crates/hir_def/src/item_tree/lower.rs123
-rw-r--r--crates/hir_def/src/lib.rs62
-rw-r--r--crates/hir_def/src/nameres.rs66
-rw-r--r--crates/hir_def/src/nameres/collector.rs136
-rw-r--r--crates/hir_def/src/nameres/path_resolution.rs59
-rw-r--r--crates/hir_def/src/nameres/tests/diagnostics.rs26
-rw-r--r--crates/hir_def/src/path.rs22
-rw-r--r--crates/hir_def/src/path/lower.rs14
-rw-r--r--crates/hir_def/src/resolver.rs3
-rw-r--r--crates/hir_def/src/test_db.rs64
-rw-r--r--crates/hir_def/src/type_ref.rs17
-rw-r--r--crates/hir_def/src/visibility.rs6
-rw-r--r--crates/hir_expand/src/builtin_derive.rs10
-rw-r--r--crates/hir_expand/src/builtin_macro.rs36
-rw-r--r--crates/hir_expand/src/db.rs15
-rw-r--r--crates/hir_expand/src/eager.rs9
-rw-r--r--crates/hir_expand/src/lib.rs21
-rw-r--r--crates/hir_expand/src/name.rs11
-rw-r--r--crates/hir_expand/src/quote.rs1
-rw-r--r--crates/hir_ty/Cargo.toml2
-rw-r--r--crates/hir_ty/src/autoderef.rs105
-rw-r--r--crates/hir_ty/src/builder.rs223
-rw-r--r--crates/hir_ty/src/chalk_cast.rs53
-rw-r--r--crates/hir_ty/src/chalk_db.rs (renamed from crates/hir_ty/src/traits/chalk.rs)276
-rw-r--r--crates/hir_ty/src/chalk_ext.rs305
-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.rs174
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs24
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs49
-rw-r--r--crates/hir_ty/src/diagnostics/unsafe_check.rs12
-rw-r--r--crates/hir_ty/src/display.rs321
-rw-r--r--crates/hir_ty/src/infer.rs198
-rw-r--r--crates/hir_ty/src/infer/coerce.rs64
-rw-r--r--crates/hir_ty/src/infer/expr.rs221
-rw-r--r--crates/hir_ty/src/infer/pat.rs92
-rw-r--r--crates/hir_ty/src/infer/path.rs39
-rw-r--r--crates/hir_ty/src/infer/unify.rs266
-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.rs1347
-rw-r--r--crates/hir_ty/src/lower.rs340
-rw-r--r--crates/hir_ty/src/mapping.rs154
-rw-r--r--crates/hir_ty/src/method_resolution.rs316
-rw-r--r--crates/hir_ty/src/op.rs74
-rw-r--r--crates/hir_ty/src/primitive.rs5
-rw-r--r--crates/hir_ty/src/tests.rs2
-rw-r--r--crates/hir_ty/src/tests/macros.rs28
-rw-r--r--crates/hir_ty/src/tests/method_resolution.rs22
-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.rs1504
-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.rs560
-rw-r--r--crates/hir_ty/src/utils.rs73
-rw-r--r--crates/hir_ty/src/walk.rs150
-rw-r--r--crates/ide/src/annotations.rs2
-rw-r--r--crates/ide/src/diagnostics.rs158
-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.rs197
-rw-r--r--crates/ide/src/expand_macro.rs46
-rw-r--r--crates/ide/src/extend_selection.rs2
-rw-r--r--crates/ide/src/file_structure.rs3
-rw-r--r--crates/ide/src/folding_ranges.rs56
-rw-r--r--crates/ide/src/goto_definition.rs83
-rw-r--r--crates/ide/src/goto_implementation.rs2
-rw-r--r--crates/ide/src/goto_type_definition.rs2
-rw-r--r--crates/ide/src/hover.rs156
-rw-r--r--crates/ide/src/inlay_hints.rs4
-rw-r--r--crates/ide/src/join_lines.rs20
-rw-r--r--crates/ide/src/lib.rs36
-rw-r--r--crates/ide/src/matching_brace.rs2
-rw-r--r--crates/ide/src/move_item.rs348
-rw-r--r--crates/ide/src/parent_module.rs2
-rw-r--r--crates/ide/src/references.rs2
-rw-r--r--crates/ide/src/references/rename.rs4
-rw-r--r--crates/ide/src/runnables.rs3
-rw-r--r--crates/ide/src/status.rs1
-rw-r--r--crates/ide/src/syntax_highlighting.rs3
-rw-r--r--crates/ide/src/syntax_highlighting/highlight.rs108
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs118
-rw-r--r--crates/ide/src/syntax_highlighting/tags.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html8
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html12
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_injection.html2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html6
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlighting.html6
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs44
-rw-r--r--crates/ide/src/syntax_tree.rs1
-rw-r--r--crates/ide/src/typing.rs371
-rw-r--r--crates/ide/src/typing/on_enter.rs232
-rw-r--r--crates/ide/src/view_hir.rs1
-rw-r--r--crates/ide_assists/src/assist_context.rs5
-rw-r--r--crates/ide_assists/src/handlers/auto_import.rs2
-rw-r--r--crates/ide_assists/src/handlers/convert_into_to_from.rs355
-rw-r--r--crates/ide_assists/src/handlers/extract_function.rs176
-rw-r--r--crates/ide_assists/src/handlers/extract_type_alias.rs149
-rw-r--r--crates/ide_assists/src/handlers/extract_variable.rs73
-rw-r--r--crates/ide_assists/src/handlers/fill_match_arms.rs22
-rw-r--r--crates/ide_assists/src/handlers/flip_comma.rs18
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs2
-rw-r--r--crates/ide_assists/src/handlers/generate_is_empty_from_len.rs2
-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/lib.rs6
-rw-r--r--crates/ide_assists/src/tests.rs6
-rw-r--r--crates/ide_assists/src/tests/generated.rs51
-rw-r--r--crates/ide_assists/src/utils.rs4
-rw-r--r--crates/ide_completion/src/completions.rs2
-rw-r--r--crates/ide_completion/src/completions/flyimport.rs116
-rw-r--r--crates/ide_completion/src/completions/pattern.rs2
-rw-r--r--crates/ide_completion/src/completions/postfix/format_like.rs2
-rw-r--r--crates/ide_completion/src/completions/qualified_path.rs4
-rw-r--r--crates/ide_completion/src/item.rs2
-rw-r--r--crates/ide_completion/src/lib.rs30
-rw-r--r--crates/ide_db/src/apply_change.rs7
-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/defs.rs41
-rw-r--r--crates/ide_db/src/helpers.rs4
-rw-r--r--crates/ide_db/src/helpers/famous_defs_fixture.rs6
-rw-r--r--crates/ide_db/src/helpers/import_assets.rs24
-rw-r--r--crates/mbe/src/benchmark.rs2
-rw-r--r--crates/mbe/src/expander.rs6
-rw-r--r--crates/mbe/src/lib.rs6
-rw-r--r--crates/mbe/src/syntax_bridge.rs23
-rw-r--r--crates/mbe/src/tests.rs11
-rw-r--r--crates/mbe/src/tests/expand.rs33
-rw-r--r--crates/mbe/src/tests/rule.rs2
-rw-r--r--crates/mbe/src/tt_iter.rs11
-rw-r--r--crates/parser/src/grammar.rs37
-rw-r--r--crates/parser/src/grammar/attributes.rs28
-rw-r--r--crates/paths/src/lib.rs7
-rw-r--r--crates/proc_macro_srv/src/rustc_server.rs19
-rw-r--r--crates/profile/src/google_cpu_profiler.rs19
-rw-r--r--crates/profile/src/hprof.rs107
-rw-r--r--crates/profile/src/lib.rs39
-rw-r--r--crates/project_model/src/build_data.rs274
-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.rs74
-rw-r--r--crates/rust-analyzer/src/bin/flags.rs56
-rw-r--r--crates/rust-analyzer/src/bin/main.rs31
-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/cargo_target_spec.rs2
-rw-r--r--crates/rust-analyzer/src/cli.rs4
-rw-r--r--crates/rust-analyzer/src/cli/analysis_bench.rs196
-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.rs23
-rw-r--r--crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt138
-rw-r--r--crates/rust-analyzer/src/diagnostics/to_proto.rs101
-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.rs133
-rw-r--r--crates/rust-analyzer/src/lib.rs3
-rw-r--r--crates/rust-analyzer/src/lsp_ext.rs32
-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/op_queue.rs38
-rw-r--r--crates/rust-analyzer/src/reload.rs214
-rw-r--r--crates/rust-analyzer/src/semantic_tokens.rs6
-rw-r--r--crates/rust-analyzer/src/to_proto.rs99
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/main.rs4
-rw-r--r--crates/rust-analyzer/tests/rust-analyzer/support.rs32
-rw-r--r--crates/stdx/src/lib.rs8
-rw-r--r--crates/syntax/Cargo.toml6
-rw-r--r--crates/syntax/src/ast/make.rs18
-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
206 files changed, 9717 insertions, 6391 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/lib.rs b/crates/base_db/src/lib.rs
index 5f77a0b1f..980a0ed98 100644
--- a/crates/base_db/src/lib.rs
+++ b/crates/base_db/src/lib.rs
@@ -59,6 +59,8 @@ pub trait CheckCanceled {
59 Self: Sized + panic::RefUnwindSafe, 59 Self: Sized + panic::RefUnwindSafe,
60 F: FnOnce(&Self) -> T + panic::UnwindSafe, 60 F: FnOnce(&Self) -> T + panic::UnwindSafe,
61 { 61 {
62 // Uncomment to debug missing cancellations.
63 // let _span = profile::heartbeat_span();
62 panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() { 64 panic::catch_unwind(|| f(self)).map_err(|err| match err.downcast::<Canceled>() {
63 Ok(canceled) => *canceled, 65 Ok(canceled) => *canceled,
64 Err(payload) => panic::resume_unwind(payload), 66 Err(payload) => panic::resume_unwind(payload),
@@ -68,6 +70,7 @@ pub trait CheckCanceled {
68 70
69impl<T: salsa::Database> CheckCanceled for T { 71impl<T: salsa::Database> CheckCanceled for T {
70 fn check_canceled(&self) { 72 fn check_canceled(&self) {
73 // profile::heartbeat();
71 if self.salsa_runtime().is_current_revision_canceled() { 74 if self.salsa_runtime().is_current_revision_canceled() {
72 Canceled::throw() 75 Canceled::throw()
73 } 76 }
diff --git a/crates/cfg/src/tests.rs b/crates/cfg/src/tests.rs
index bd0f9ec48..d8736c893 100644
--- a/crates/cfg/src/tests.rs
+++ b/crates/cfg/src/tests.rs
@@ -8,7 +8,7 @@ fn assert_parse_result(input: &str, expected: CfgExpr) {
8 let (tt, _) = { 8 let (tt, _) = {
9 let source_file = ast::SourceFile::parse(input).ok().unwrap(); 9 let source_file = ast::SourceFile::parse(input).ok().unwrap();
10 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 10 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
11 ast_to_token_tree(&tt).unwrap() 11 ast_to_token_tree(&tt)
12 }; 12 };
13 let cfg = CfgExpr::parse(&tt); 13 let cfg = CfgExpr::parse(&tt);
14 assert_eq!(cfg, expected); 14 assert_eq!(cfg, expected);
@@ -18,7 +18,7 @@ fn check_dnf(input: &str, expect: Expect) {
18 let (tt, _) = { 18 let (tt, _) = {
19 let source_file = ast::SourceFile::parse(input).ok().unwrap(); 19 let source_file = ast::SourceFile::parse(input).ok().unwrap();
20 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 20 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
21 ast_to_token_tree(&tt).unwrap() 21 ast_to_token_tree(&tt)
22 }; 22 };
23 let cfg = CfgExpr::parse(&tt); 23 let cfg = CfgExpr::parse(&tt);
24 let actual = format!("#![cfg({})]", DnfExpr::new(cfg)); 24 let actual = format!("#![cfg({})]", DnfExpr::new(cfg));
@@ -29,7 +29,7 @@ fn check_why_inactive(input: &str, opts: &CfgOptions, expect: Expect) {
29 let (tt, _) = { 29 let (tt, _) = {
30 let source_file = ast::SourceFile::parse(input).ok().unwrap(); 30 let source_file = ast::SourceFile::parse(input).ok().unwrap();
31 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 31 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
32 ast_to_token_tree(&tt).unwrap() 32 ast_to_token_tree(&tt)
33 }; 33 };
34 let cfg = CfgExpr::parse(&tt); 34 let cfg = CfgExpr::parse(&tt);
35 let dnf = DnfExpr::new(cfg); 35 let dnf = DnfExpr::new(cfg);
@@ -42,7 +42,7 @@ fn check_enable_hints(input: &str, opts: &CfgOptions, expected_hints: &[&str]) {
42 let (tt, _) = { 42 let (tt, _) = {
43 let source_file = ast::SourceFile::parse(input).ok().unwrap(); 43 let source_file = ast::SourceFile::parse(input).ok().unwrap();
44 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 44 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
45 ast_to_token_tree(&tt).unwrap() 45 ast_to_token_tree(&tt)
46 }; 46 };
47 let cfg = CfgExpr::parse(&tt); 47 let cfg = CfgExpr::parse(&tt);
48 let dnf = DnfExpr::new(cfg); 48 let dnf = DnfExpr::new(cfg);
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/db.rs b/crates/hir/src/db.rs
index 1902a8d16..df5758342 100644
--- a/crates/hir/src/db.rs
+++ b/crates/hir/src/db.rs
@@ -1,14 +1,6 @@
1//! FIXME: write short doc here 1//! FIXME: write short doc here
2 2
3pub use hir_def::db::{ 3pub use hir_def::db::*;
4 AttrsQuery, BlockDefMapQuery, BodyQuery, BodyWithSourceMapQuery, ConstDataQuery,
5 CrateDefMapQueryQuery, CrateLangItemsQuery, DefDatabase, DefDatabaseStorage, EnumDataQuery,
6 ExprScopesQuery, FileItemTreeQuery, FunctionDataQuery, GenericParamsQuery, ImplDataQuery,
7 ImportMapQuery, InternConstQuery, InternDatabase, InternDatabaseStorage, InternEnumQuery,
8 InternFunctionQuery, InternImplQuery, InternStaticQuery, InternStructQuery, InternTraitQuery,
9 InternTypeAliasQuery, InternUnionQuery, LangItemQuery, StaticDataQuery, StructDataQuery,
10 TraitDataQuery, TypeAliasDataQuery, UnionDataQuery,
11};
12pub use hir_expand::db::{ 4pub use hir_expand::db::{
13 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery, 5 AstDatabase, AstDatabaseStorage, AstIdMapQuery, HygieneFrameQuery, InternEagerExpansionQuery,
14 InternMacroQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery, 6 InternMacroQuery, MacroArgTextQuery, MacroDefQuery, MacroExpandQuery, ParseMacroExpansionQuery,
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 97a78ca25..01a4d205f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -9,33 +9,33 @@ 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::{
15 Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam, 16 Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasVisibility, LifetimeParam,
16 Module, Static, Struct, Substitution, Trait, Type, TypeAlias, TypeParam, Union, Variant, 17 Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union, Variant,
17}; 18};
18 19
19impl HirDisplay for Function { 20impl HirDisplay for Function {
20 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 21 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
21 let data = f.db.function_data(self.id); 22 let data = f.db.function_data(self.id);
22 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?; 23 write_visibility(self.module(f.db).id, self.visibility(f.db), f)?;
23 let qual = &data.qualifier; 24 if data.is_default() {
24 if qual.is_default {
25 write!(f, "default ")?; 25 write!(f, "default ")?;
26 } 26 }
27 if qual.is_const { 27 if data.is_const() {
28 write!(f, "const ")?; 28 write!(f, "const ")?;
29 } 29 }
30 if qual.is_async { 30 if data.is_async() {
31 write!(f, "async ")?; 31 write!(f, "async ")?;
32 } 32 }
33 if qual.is_unsafe { 33 if data.is_unsafe() {
34 write!(f, "unsafe ")?; 34 write!(f, "unsafe ")?;
35 } 35 }
36 if let Some(abi) = &qual.abi { 36 if let Some(abi) = &data.abi {
37 // FIXME: String escape? 37 // FIXME: String escape?
38 write!(f, "extern \"{}\" ", abi)?; 38 write!(f, "extern \"{}\" ", &**abi)?;
39 } 39 }
40 write!(f, "fn {}", data.name)?; 40 write!(f, "fn {}", data.name)?;
41 41
@@ -68,7 +68,7 @@ impl HirDisplay for Function {
68 write!(f, ", ")?; 68 write!(f, ", ")?;
69 } else { 69 } else {
70 first = false; 70 first = false;
71 if data.has_self_param { 71 if data.has_self_param() {
72 write_self_param(type_ref, f)?; 72 write_self_param(type_ref, f)?;
73 continue; 73 continue;
74 } 74 }
@@ -88,10 +88,10 @@ impl HirDisplay for Function {
88 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns. 88 // `FunctionData::ret_type` will be `::core::future::Future<Output = ...>` for async fns.
89 // Use ugly pattern match to strip the Future trait. 89 // Use ugly pattern match to strip the Future trait.
90 // Better way? 90 // Better way?
91 let ret_type = if !qual.is_async { 91 let ret_type = if !data.is_async() {
92 &data.ret_type 92 &data.ret_type
93 } else { 93 } else {
94 match &data.ret_type { 94 match &*data.ret_type {
95 TypeRef::ImplTrait(bounds) => match &bounds[0] { 95 TypeRef::ImplTrait(bounds) => match &bounds[0] {
96 TypeBound::Path(path) => { 96 TypeBound::Path(path) => {
97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings 97 path.segments().iter().last().unwrap().args_and_bindings.unwrap().bindings
@@ -235,8 +235,9 @@ impl HirDisplay for TypeParam {
235 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 235 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
236 write!(f, "{}", self.name(f.db))?; 236 write!(f, "{}", self.name(f.db))?;
237 let bounds = f.db.generic_predicates_for_param(self.id); 237 let bounds = f.db.generic_predicates_for_param(self.id);
238 let substs = Substitution::type_params(f.db, self.id.parent); 238 let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
239 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<_>>();
240 if !(predicates.is_empty() || f.omit_verbose_types()) { 241 if !(predicates.is_empty() || f.omit_verbose_types()) {
241 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?; 242 write_bounds_like_dyn_trait_with_prefix(":", &predicates, f)?;
242 } 243 }
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 4ee08ef21..0acfa582a 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -44,6 +44,7 @@ use hir_def::{
44 per_ns::PerNs, 44 per_ns::PerNs,
45 resolver::{HasResolver, Resolver}, 45 resolver::{HasResolver, Resolver},
46 src::HasSource as _, 46 src::HasSource as _,
47 type_ref::TraitRef,
47 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, 48 AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
48 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, 49 DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
49 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, 50 LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
@@ -52,13 +53,14 @@ use hir_def::{
52use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind}; 53use hir_expand::{diagnostics::DiagnosticSink, name::name, MacroDefKind};
53use hir_ty::{ 54use hir_ty::{
54 autoderef, could_unify, 55 autoderef, could_unify,
55 method_resolution::{self, TyFingerprint}, 56 method_resolution::{self, def_crates, TyFingerprint},
56 primitive::UintTy, 57 primitive::UintTy,
57 to_assoc_type_id, 58 subst_prefix,
58 traits::{FnTrait, Solution, SolutionVariables}, 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, ProjectionTy, QuantifiedWhereClause, Scalar, 61 DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
61 Substitution, TraitEnvironment, Ty, 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;
@@ -514,8 +516,8 @@ impl Field {
514 VariantDef::Union(it) => it.id.into(), 516 VariantDef::Union(it) => it.id.into(),
515 VariantDef::Variant(it) => it.parent.id.into(), 517 VariantDef::Variant(it) => it.parent.id.into(),
516 }; 518 };
517 let substs = Substitution::type_params(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
@@ -831,7 +833,7 @@ impl Function {
831 } 833 }
832 834
833 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> { 835 pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
834 if !db.function_data(self.id).has_self_param { 836 if !db.function_data(self.id).has_self_param() {
835 return None; 837 return None;
836 } 838 }
837 Some(SelfParam { func: self.id }) 839 Some(SelfParam { func: self.id })
@@ -863,7 +865,7 @@ impl Function {
863 } 865 }
864 866
865 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { 867 pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool {
866 db.function_data(self.id).qualifier.is_unsafe 868 db.function_data(self.id).is_unsafe()
867 } 869 }
868 870
869 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { 871 pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) {
@@ -877,7 +879,7 @@ impl Function {
877 /// 879 ///
878 /// This is false in the case of required (not provided) trait methods. 880 /// This is false in the case of required (not provided) trait methods.
879 pub fn has_body(self, db: &dyn HirDatabase) -> bool { 881 pub fn has_body(self, db: &dyn HirDatabase) -> bool {
880 db.function_data(self.id).has_body 882 db.function_data(self.id).has_body()
881 } 883 }
882 884
883 /// A textual representation of the HIR of this function for debugging purposes. 885 /// A textual representation of the HIR of this function for debugging purposes.
@@ -956,7 +958,7 @@ impl SelfParam {
956 func_data 958 func_data
957 .params 959 .params
958 .first() 960 .first()
959 .map(|param| match *param { 961 .map(|param| match &**param {
960 TypeRef::Reference(.., mutability) => match mutability { 962 TypeRef::Reference(.., mutability) => match mutability {
961 hir_def::type_ref::Mutability::Shared => Access::Shared, 963 hir_def::type_ref::Mutability::Shared => Access::Shared,
962 hir_def::type_ref::Mutability::Mut => Access::Exclusive, 964 hir_def::type_ref::Mutability::Mut => Access::Exclusive,
@@ -1010,7 +1012,7 @@ impl Const {
1010 } 1012 }
1011 1013
1012 pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef { 1014 pub fn type_ref(self, db: &dyn HirDatabase) -> TypeRef {
1013 db.const_data(self.id).type_ref.clone() 1015 db.const_data(self.id).type_ref.as_ref().clone()
1014 } 1016 }
1015} 1017}
1016 1018
@@ -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 {
@@ -1100,7 +1102,7 @@ impl TypeAlias {
1100 } 1102 }
1101 1103
1102 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1104 pub fn type_ref(self, db: &dyn HirDatabase) -> Option<TypeRef> {
1103 db.type_alias_data(self.id).type_ref.clone() 1105 db.type_alias_data(self.id).type_ref.as_deref().cloned()
1104 } 1106 }
1105 1107
1106 pub fn ty(self, db: &dyn HirDatabase) -> Type { 1108 pub fn ty(self, db: &dyn HirDatabase) -> Type {
@@ -1128,7 +1130,7 @@ pub struct BuiltinType {
1128impl BuiltinType { 1130impl BuiltinType {
1129 pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type { 1131 pub fn ty(self, db: &dyn HirDatabase, module: Module) -> Type {
1130 let resolver = module.id.resolver(db.upcast()); 1132 let resolver = module.id.resolver(db.upcast());
1131 Type::new_with_resolver(db, &resolver, Ty::builtin(self.inner)) 1133 Type::new_with_resolver(db, &resolver, TyBuilder::builtin(self.inner))
1132 .expect("crate not present in resolver") 1134 .expect("crate not present in resolver")
1133 } 1135 }
1134 1136
@@ -1501,8 +1503,8 @@ impl TypeParam {
1501 let resolver = self.id.parent.resolver(db.upcast()); 1503 let resolver = self.id.parent.resolver(db.upcast());
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 = Substitution::type_params(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,22 +1569,35 @@ 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 };
1574 1576
1575 let filter = |impl_def: &Impl| { 1577 let filter = |impl_def: &Impl| {
1576 let target_ty = impl_def.target_ty(db); 1578 let self_ty = impl_def.self_ty(db);
1577 let rref = target_ty.remove_ref(); 1579 let rref = self_ty.remove_ref();
1578 ty.equals_ctor(rref.as_ref().map_or(&target_ty.ty, |it| &it.ty)) 1580 ty.equals_ctor(rref.as_ref().map_or(&self_ty.ty, |it| &it.ty))
1581 };
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();
1579 }; 1588 };
1580 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 }
@@ -1613,16 +1627,16 @@ impl Impl {
1613 1627
1614 // FIXME: the return type is wrong. This should be a hir version of 1628 // FIXME: the return type is wrong. This should be a hir version of
1615 // `TraitRef` (ie, resolved `TypeRef`). 1629 // `TraitRef` (ie, resolved `TypeRef`).
1616 pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { 1630 pub fn trait_(self, db: &dyn HirDatabase) -> Option<TraitRef> {
1617 db.impl_data(self.id).target_trait.clone() 1631 db.impl_data(self.id).target_trait.as_deref().cloned()
1618 } 1632 }
1619 1633
1620 pub fn target_ty(self, db: &dyn HirDatabase) -> Type { 1634 pub fn self_ty(self, db: &dyn HirDatabase) -> Type {
1621 let impl_data = db.impl_data(self.id); 1635 let impl_data = db.impl_data(self.id);
1622 let resolver = self.id.resolver(db.upcast()); 1636 let resolver = self.id.resolver(db.upcast());
1623 let krate = self.id.lookup(db.upcast()).container.krate(); 1637 let krate = self.id.lookup(db.upcast()).container.krate();
1624 let ctx = hir_ty::TyLoweringContext::new(db, &resolver); 1638 let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
1625 let ty = ctx.lower_ty(&impl_data.target_type); 1639 let ty = ctx.lower_ty(&impl_data.self_ty);
1626 Type::new_with_resolver_inner(db, krate, &resolver, ty) 1640 Type::new_with_resolver_inner(db, krate, &resolver, ty)
1627 } 1641 }
1628 1642
@@ -1702,30 +1716,29 @@ impl Type {
1702 fn from_def( 1716 fn from_def(
1703 db: &dyn HirDatabase, 1717 db: &dyn HirDatabase,
1704 krate: CrateId, 1718 krate: CrateId,
1705 def: impl HasResolver + Into<TyDefId> + Into<GenericDefId>, 1719 def: impl HasResolver + Into<TyDefId>,
1706 ) -> Type { 1720 ) -> Type {
1707 let substs = Substitution::build_for_def(db, def).fill_with_unknown().build(); 1721 let ty = TyBuilder::def_ty(db, def.into()).fill_with_unknown().build();
1708 let ty = db.ty(def.into()).subst(&substs);
1709 Type::new(db, krate, def, ty) 1722 Type::new(db, krate, def, ty)
1710 } 1723 }
1711 1724
1712 pub fn is_unit(&self) -> bool { 1725 pub fn is_unit(&self) -> bool {
1713 matches!(self.ty.interned(&Interner), TyKind::Tuple(0, ..)) 1726 matches!(self.ty.kind(&Interner), TyKind::Tuple(0, ..))
1714 } 1727 }
1715 pub fn is_bool(&self) -> bool { 1728 pub fn is_bool(&self) -> bool {
1716 matches!(self.ty.interned(&Interner), TyKind::Scalar(Scalar::Bool)) 1729 matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Bool))
1717 } 1730 }
1718 1731
1719 pub fn is_mutable_reference(&self) -> bool { 1732 pub fn is_mutable_reference(&self) -> bool {
1720 matches!(self.ty.interned(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..)) 1733 matches!(self.ty.kind(&Interner), TyKind::Ref(hir_ty::Mutability::Mut, ..))
1721 } 1734 }
1722 1735
1723 pub fn is_usize(&self) -> bool { 1736 pub fn is_usize(&self) -> bool {
1724 matches!(self.ty.interned(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize))) 1737 matches!(self.ty.kind(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)))
1725 } 1738 }
1726 1739
1727 pub fn remove_ref(&self) -> Option<Type> { 1740 pub fn remove_ref(&self) -> Option<Type> {
1728 match &self.ty.interned(&Interner) { 1741 match &self.ty.kind(&Interner) {
1729 TyKind::Ref(.., ty) => Some(self.derived(ty.clone())), 1742 TyKind::Ref(.., ty) => Some(self.derived(ty.clone())),
1730 _ => None, 1743 _ => None,
1731 } 1744 }
@@ -1784,16 +1797,13 @@ impl Type {
1784 } 1797 }
1785 1798
1786 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool { 1799 pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
1787 let trait_ref = hir_ty::TraitRef { 1800 let trait_ref = TyBuilder::trait_ref(db, trait_.id)
1788 trait_id: hir_ty::to_chalk_trait_id(trait_.id), 1801 .push(self.ty.clone())
1789 substitution: Substitution::build_for_def(db, trait_.id) 1802 .fill(args.iter().map(|t| t.ty.clone()))
1790 .push(self.ty.clone()) 1803 .build();
1791 .fill(args.iter().map(|t| t.ty.clone()))
1792 .build(),
1793 };
1794 1804
1795 let goal = Canonical { 1805 let goal = Canonical {
1796 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)),
1797 binders: CanonicalVarKinds::empty(&Interner), 1807 binders: CanonicalVarKinds::empty(&Interner),
1798 }; 1808 };
1799 1809
@@ -1803,22 +1813,18 @@ impl Type {
1803 pub fn normalize_trait_assoc_type( 1813 pub fn normalize_trait_assoc_type(
1804 &self, 1814 &self,
1805 db: &dyn HirDatabase, 1815 db: &dyn HirDatabase,
1806 trait_: Trait,
1807 args: &[Type], 1816 args: &[Type],
1808 alias: TypeAlias, 1817 alias: TypeAlias,
1809 ) -> Option<Type> { 1818 ) -> Option<Type> {
1810 let subst = Substitution::build_for_def(db, trait_.id) 1819 let projection = TyBuilder::assoc_type_projection(db, alias.id)
1811 .push(self.ty.clone()) 1820 .push(self.ty.clone())
1812 .fill(args.iter().map(|t| t.ty.clone())) 1821 .fill(args.iter().map(|t| t.ty.clone()))
1813 .build(); 1822 .build();
1814 let goal = Canonical::new( 1823 let goal = hir_ty::make_canonical(
1815 InEnvironment::new( 1824 InEnvironment::new(
1816 self.env.env.clone(), 1825 &self.env.env,
1817 AliasEq { 1826 AliasEq {
1818 alias: AliasTy::Projection(ProjectionTy { 1827 alias: AliasTy::Projection(projection),
1819 associated_ty_id: to_assoc_type_id(alias.id),
1820 substitution: subst,
1821 }),
1822 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)) 1828 ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
1823 .intern(&Interner), 1829 .intern(&Interner),
1824 } 1830 }
@@ -1828,9 +1834,12 @@ impl Type {
1828 ); 1834 );
1829 1835
1830 match db.trait_solve(self.krate, goal)? { 1836 match db.trait_solve(self.krate, goal)? {
1831 Solution::Unique(SolutionVariables(subst)) => { 1837 Solution::Unique(s) => s
1832 subst.value.first().map(|ty| self.derived(ty.clone())) 1838 .value
1833 } 1839 .subst
1840 .as_slice(&Interner)
1841 .first()
1842 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone())),
1834 Solution::Ambig(_) => None, 1843 Solution::Ambig(_) => None,
1835 } 1844 }
1836 } 1845 }
@@ -1852,15 +1861,15 @@ impl Type {
1852 } 1861 }
1853 1862
1854 pub fn is_closure(&self) -> bool { 1863 pub fn is_closure(&self) -> bool {
1855 matches!(&self.ty.interned(&Interner), TyKind::Closure { .. }) 1864 matches!(&self.ty.kind(&Interner), TyKind::Closure { .. })
1856 } 1865 }
1857 1866
1858 pub fn is_fn(&self) -> bool { 1867 pub fn is_fn(&self) -> bool {
1859 matches!(&self.ty.interned(&Interner), TyKind::FnDef(..) | TyKind::Function { .. }) 1868 matches!(&self.ty.kind(&Interner), TyKind::FnDef(..) | TyKind::Function { .. })
1860 } 1869 }
1861 1870
1862 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool { 1871 pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
1863 let adt_id = match self.ty.interned(&Interner) { 1872 let adt_id = match self.ty.kind(&Interner) {
1864 &TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id, 1873 &TyKind::Adt(hir_ty::AdtId(adt_id), ..) => adt_id,
1865 _ => return false, 1874 _ => return false,
1866 }; 1875 };
@@ -1873,27 +1882,30 @@ impl Type {
1873 } 1882 }
1874 1883
1875 pub fn is_raw_ptr(&self) -> bool { 1884 pub fn is_raw_ptr(&self) -> bool {
1876 matches!(&self.ty.interned(&Interner), TyKind::Raw(..)) 1885 matches!(&self.ty.kind(&Interner), TyKind::Raw(..))
1877 } 1886 }
1878 1887
1879 pub fn contains_unknown(&self) -> bool { 1888 pub fn contains_unknown(&self) -> bool {
1880 return go(&self.ty); 1889 return go(&self.ty);
1881 1890
1882 fn go(ty: &Ty) -> bool { 1891 fn go(ty: &Ty) -> bool {
1883 match ty.interned(&Interner) { 1892 match ty.kind(&Interner) {
1884 TyKind::Unknown => true, 1893 TyKind::Error => true,
1885 1894
1886 TyKind::Adt(_, substs) 1895 TyKind::Adt(_, substs)
1887 | TyKind::AssociatedType(_, substs) 1896 | TyKind::AssociatedType(_, substs)
1888 | TyKind::Tuple(_, substs) 1897 | TyKind::Tuple(_, substs)
1889 | TyKind::OpaqueType(_, substs) 1898 | TyKind::OpaqueType(_, substs)
1890 | TyKind::FnDef(_, substs) 1899 | TyKind::FnDef(_, substs)
1891 | TyKind::Closure(_, substs) => substs.iter().any(go), 1900 | TyKind::Closure(_, substs) => {
1892 1901 substs.iter(&Interner).filter_map(|a| a.ty(&Interner)).any(go)
1893 TyKind::Array(ty) | TyKind::Slice(ty) | TyKind::Raw(_, ty) | TyKind::Ref(_, ty) => {
1894 go(ty)
1895 } 1902 }
1896 1903
1904 TyKind::Array(ty, _)
1905 | TyKind::Slice(ty)
1906 | TyKind::Raw(_, ty)
1907 | TyKind::Ref(_, _, ty) => go(ty),
1908
1897 TyKind::Scalar(_) 1909 TyKind::Scalar(_)
1898 | TyKind::Str 1910 | TyKind::Str
1899 | TyKind::Never 1911 | TyKind::Never
@@ -1903,13 +1915,15 @@ impl Type {
1903 | TyKind::Dyn(_) 1915 | TyKind::Dyn(_)
1904 | TyKind::Function(_) 1916 | TyKind::Function(_)
1905 | TyKind::Alias(_) 1917 | TyKind::Alias(_)
1906 | TyKind::ForeignType(_) => false, 1918 | TyKind::Foreign(_)
1919 | TyKind::Generator(..)
1920 | TyKind::GeneratorWitness(..) => false,
1907 } 1921 }
1908 } 1922 }
1909 } 1923 }
1910 1924
1911 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { 1925 pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> {
1912 let (variant_id, substs) = match self.ty.interned(&Interner) { 1926 let (variant_id, substs) = match self.ty.kind(&Interner) {
1913 &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs), 1927 &TyKind::Adt(hir_ty::AdtId(AdtId::StructId(s)), ref substs) => (s.into(), substs),
1914 &TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs), 1928 &TyKind::Adt(hir_ty::AdtId(AdtId::UnionId(u)), ref substs) => (u.into(), substs),
1915 _ => return Vec::new(), 1929 _ => return Vec::new(),
@@ -1919,15 +1933,18 @@ impl Type {
1919 .iter() 1933 .iter()
1920 .map(|(local_id, ty)| { 1934 .map(|(local_id, ty)| {
1921 let def = Field { parent: variant_id.into(), id: local_id }; 1935 let def = Field { parent: variant_id.into(), id: local_id };
1922 let ty = ty.clone().subst(substs); 1936 let ty = ty.clone().substitute(&Interner, substs);
1923 (def, self.derived(ty)) 1937 (def, self.derived(ty))
1924 }) 1938 })
1925 .collect() 1939 .collect()
1926 } 1940 }
1927 1941
1928 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> { 1942 pub fn tuple_fields(&self, _db: &dyn HirDatabase) -> Vec<Type> {
1929 if let TyKind::Tuple(_, substs) = &self.ty.interned(&Interner) { 1943 if let TyKind::Tuple(_, substs) = &self.ty.kind(&Interner) {
1930 substs.iter().map(|ty| self.derived(ty.clone())).collect() 1944 substs
1945 .iter(&Interner)
1946 .map(|ty| self.derived(ty.assert_ty_ref(&Interner).clone()))
1947 .collect()
1931 } else { 1948 } else {
1932 Vec::new() 1949 Vec::new()
1933 } 1950 }
@@ -1953,7 +1970,7 @@ impl Type {
1953 krate: Crate, 1970 krate: Crate,
1954 mut callback: impl FnMut(AssocItem) -> Option<T>, 1971 mut callback: impl FnMut(AssocItem) -> Option<T>,
1955 ) -> Option<T> { 1972 ) -> Option<T> {
1956 for krate in self.ty.def_crates(db, krate.id)? { 1973 for krate in def_crates(db, &self.ty, krate.id)? {
1957 let impls = db.inherent_impls_in_crate(krate); 1974 let impls = db.inherent_impls_in_crate(krate);
1958 1975
1959 for impl_def in impls.for_self_ty(&self.ty) { 1976 for impl_def in impls.for_self_ty(&self.ty) {
@@ -1970,10 +1987,11 @@ impl Type {
1970 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ { 1987 pub fn type_parameters(&self) -> impl Iterator<Item = Type> + '_ {
1971 self.ty 1988 self.ty
1972 .strip_references() 1989 .strip_references()
1973 .substs() 1990 .as_adt()
1974 .into_iter() 1991 .into_iter()
1975 .flat_map(|substs| substs.iter()) 1992 .flat_map(|(_, substs)| substs.iter(&Interner))
1976 .map(move |ty| self.derived(ty.clone())) 1993 .filter_map(|arg| arg.ty(&Interner).cloned())
1994 .map(move |ty| self.derived(ty))
1977 } 1995 }
1978 1996
1979 pub fn iterate_method_candidates<T>( 1997 pub fn iterate_method_candidates<T>(
@@ -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()
@@ -2079,7 +2109,7 @@ impl Type {
2079 substs: &Substitution, 2109 substs: &Substitution,
2080 cb: &mut impl FnMut(Type), 2110 cb: &mut impl FnMut(Type),
2081 ) { 2111 ) {
2082 for ty in substs.iter() { 2112 for ty in substs.iter(&Interner).filter_map(|a| a.ty(&Interner)) {
2083 walk_type(db, &type_.derived(ty.clone()), cb); 2113 walk_type(db, &type_.derived(ty.clone()), cb);
2084 } 2114 }
2085 } 2115 }
@@ -2095,7 +2125,12 @@ impl Type {
2095 WhereClause::Implemented(trait_ref) => { 2125 WhereClause::Implemented(trait_ref) => {
2096 cb(type_.clone()); 2126 cb(type_.clone());
2097 // skip the self type. it's likely the type we just got the bounds from 2127 // skip the self type. it's likely the type we just got the bounds from
2098 for ty in trait_ref.substitution.iter().skip(1) { 2128 for ty in trait_ref
2129 .substitution
2130 .iter(&Interner)
2131 .skip(1)
2132 .filter_map(|a| a.ty(&Interner))
2133 {
2099 walk_type(db, &type_.derived(ty.clone()), cb); 2134 walk_type(db, &type_.derived(ty.clone()), cb);
2100 } 2135 }
2101 } 2136 }
@@ -2106,19 +2141,23 @@ impl Type {
2106 2141
2107 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)) {
2108 let ty = type_.ty.strip_references(); 2143 let ty = type_.ty.strip_references();
2109 match ty.interned(&Interner) { 2144 match ty.kind(&Interner) {
2110 TyKind::Adt(..) => { 2145 TyKind::Adt(_, substs) => {
2111 cb(type_.derived(ty.clone())); 2146 cb(type_.derived(ty.clone()));
2147 walk_substs(db, type_, &substs, cb);
2112 } 2148 }
2113 TyKind::AssociatedType(..) => { 2149 TyKind::AssociatedType(_, substs) => {
2114 if let Some(_) = ty.associated_type_parent_trait(db) { 2150 if let Some(_) = ty.associated_type_parent_trait(db) {
2115 cb(type_.derived(ty.clone())); 2151 cb(type_.derived(ty.clone()));
2116 } 2152 }
2153 walk_substs(db, type_, &substs, cb);
2117 } 2154 }
2118 TyKind::OpaqueType(..) => { 2155 TyKind::OpaqueType(_, subst) => {
2119 if let Some(bounds) = ty.impl_trait_bounds(db) { 2156 if let Some(bounds) = ty.impl_trait_bounds(db) {
2120 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb); 2157 walk_bounds(db, &type_.derived(ty.clone()), &bounds, cb);
2121 } 2158 }
2159
2160 walk_substs(db, type_, subst, cb);
2122 } 2161 }
2123 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => { 2162 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
2124 if let Some(bounds) = ty.impl_trait_bounds(db) { 2163 if let Some(bounds) = ty.impl_trait_bounds(db) {
@@ -2141,15 +2180,24 @@ impl Type {
2141 ); 2180 );
2142 } 2181 }
2143 2182
2144 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) => {
2145 walk_type(db, &type_.derived(ty.clone()), cb); 2187 walk_type(db, &type_.derived(ty.clone()), cb);
2146 } 2188 }
2147 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
2148 _ => {} 2199 _ => {}
2149 } 2200 }
2150 if let Some(substs) = ty.substs() {
2151 walk_substs(db, type_, &substs, cb);
2152 }
2153 } 2201 }
2154 2202
2155 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 d3caeef4e..7955bf0b5 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -76,9 +76,11 @@ impl PathResolution {
76 pub fn assoc_type_shorthand_candidates<R>( 76 pub fn assoc_type_shorthand_candidates<R>(
77 &self, 77 &self,
78 db: &dyn HirDatabase, 78 db: &dyn HirDatabase,
79 mut cb: impl FnMut(TypeAlias) -> Option<R>, 79 mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
80 ) -> Option<R> { 80 ) -> Option<R> {
81 associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into())) 81 associated_type_shorthand_candidates(db, self.in_type_ns()?, |name, _, id| {
82 cb(name, id.into())
83 })
82 } 84 }
83} 85}
84 86
@@ -492,9 +494,9 @@ impl<'db> SemanticsImpl<'db> {
492 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> { 494 fn resolve_method_call_as_callable(&self, call: &ast::MethodCallExpr) -> Option<Callable> {
493 // FIXME: this erases Substs 495 // FIXME: this erases Substs
494 let func = self.resolve_method_call(call)?; 496 let func = self.resolve_method_call(call)?;
495 let ty = self.db.value_ty(func.into()); 497 let (ty, _) = self.db.value_ty(func.into()).into_value_and_skipped_binders();
496 let resolver = self.analyze(call.syntax()).resolver; 498 let resolver = self.analyze(call.syntax()).resolver;
497 let ty = Type::new_with_resolver(self.db, &resolver, ty.value)?; 499 let ty = Type::new_with_resolver(self.db, &resolver, ty)?;
498 let mut res = ty.as_callable(self.db)?; 500 let mut res = ty.as_callable(self.db)?;
499 res.is_bound_method = true; 501 res.is_bound_method = true;
500 Some(res) 502 Some(res)
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 37d162b32..847d2537d 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -20,7 +20,7 @@ use hir_def::{
20use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile}; 20use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
21use hir_ty::{ 21use hir_ty::{
22 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields}, 22 diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
23 InferenceResult, Substitution, 23 InferenceResult, Interner, Substitution, TyExt, TyLoweringContext,
24}; 24};
25use syntax::{ 25use syntax::{
26 ast::{self, AstNode}, 26 ast::{self, AstNode},
@@ -161,14 +161,15 @@ impl SourceAnalyzer {
161 db: &dyn HirDatabase, 161 db: &dyn HirDatabase,
162 field: &ast::RecordExprField, 162 field: &ast::RecordExprField,
163 ) -> Option<(Field, Option<Local>)> { 163 ) -> Option<(Field, Option<Local>)> {
164 let expr_id = 164 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))?; 165 let expr = ast::Expr::from(record_expr);
166 let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
166 167
168 let local_name = field.field_name()?.as_name();
167 let local = if field.name_ref().is_some() { 169 let local = if field.name_ref().is_some() {
168 None 170 None
169 } else { 171 } else {
170 let local_name = field.field_name()?.as_name(); 172 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) { 173 match self.resolver.resolve_path_in_value_ns_fully(db.upcast(), &path) {
173 Some(ValueNs::LocalBinding(pat_id)) => { 174 Some(ValueNs::LocalBinding(pat_id)) => {
174 Some(Local { pat_id, parent: self.resolver.body_owner()? }) 175 Some(Local { pat_id, parent: self.resolver.body_owner()? })
@@ -176,18 +177,24 @@ impl SourceAnalyzer {
176 _ => None, 177 _ => None,
177 } 178 }
178 }; 179 };
179 let struct_field = self.infer.as_ref()?.record_field_resolution(expr_id)?; 180 let variant = self.infer.as_ref()?.variant_resolution_for_expr(expr_id)?;
180 Some((struct_field.into(), local)) 181 let variant_data = variant.variant_data(db.upcast());
182 let field = FieldId { parent: variant, local_id: variant_data.field(&local_name)? };
183 Some((field.into(), local))
181 } 184 }
182 185
183 pub(crate) fn resolve_record_pat_field( 186 pub(crate) fn resolve_record_pat_field(
184 &self, 187 &self,
185 _db: &dyn HirDatabase, 188 db: &dyn HirDatabase,
186 field: &ast::RecordPatField, 189 field: &ast::RecordPatField,
187 ) -> Option<Field> { 190 ) -> Option<Field> {
188 let pat_id = self.pat_id(&field.pat()?)?; 191 let field_name = field.field_name()?.as_name();
189 let struct_field = self.infer.as_ref()?.record_pat_field_resolution(pat_id)?; 192 let record_pat = ast::RecordPat::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
190 Some(struct_field.into()) 193 let pat_id = self.pat_id(&record_pat.into())?;
194 let variant = self.infer.as_ref()?.variant_resolution_for_pat(pat_id)?;
195 let variant_data = variant.variant_data(db.upcast());
196 let field = FieldId { parent: variant, local_id: variant_data.field(&field_name)? };
197 Some(field.into())
191 } 198 }
192 199
193 pub(crate) fn resolve_macro_call( 200 pub(crate) fn resolve_macro_call(
@@ -299,7 +306,7 @@ impl SourceAnalyzer {
299 let infer = self.infer.as_ref()?; 306 let infer = self.infer.as_ref()?;
300 307
301 let expr_id = self.expr_id(db, &literal.clone().into())?; 308 let expr_id = self.expr_id(db, &literal.clone().into())?;
302 let substs = infer.type_of_expr[expr_id].substs()?; 309 let substs = infer.type_of_expr[expr_id].as_adt()?.1;
303 310
304 let (variant, missing_fields, _exhaustive) = 311 let (variant, missing_fields, _exhaustive) =
305 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?; 312 record_literal_missing_fields(db, infer, expr_id, &body[expr_id])?;
@@ -317,7 +324,7 @@ impl SourceAnalyzer {
317 let infer = self.infer.as_ref()?; 324 let infer = self.infer.as_ref()?;
318 325
319 let pat_id = self.pat_id(&pattern.clone().into())?; 326 let pat_id = self.pat_id(&pattern.clone().into())?;
320 let substs = infer.type_of_pat[pat_id].substs()?; 327 let substs = infer.type_of_pat[pat_id].as_adt()?.1;
321 328
322 let (variant, missing_fields, _exhaustive) = 329 let (variant, missing_fields, _exhaustive) =
323 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?; 330 record_pattern_missing_fields(db, infer, pat_id, &body[pat_id])?;
@@ -339,7 +346,7 @@ impl SourceAnalyzer {
339 .into_iter() 346 .into_iter()
340 .map(|local_id| { 347 .map(|local_id| {
341 let field = FieldId { parent: variant, local_id }; 348 let field = FieldId { parent: variant, local_id };
342 let ty = field_types[local_id].clone().subst(substs); 349 let ty = field_types[local_id].clone().substitute(&Interner, substs);
343 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty)) 350 (field.into(), Type::new_with_resolver_inner(db, krate, &self.resolver, ty))
344 }) 351 })
345 .collect() 352 .collect()
@@ -466,7 +473,21 @@ fn resolve_hir_path_(
466 prefer_value_ns: bool, 473 prefer_value_ns: bool,
467) -> Option<PathResolution> { 474) -> Option<PathResolution> {
468 let types = || { 475 let types = || {
469 resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty { 476 let (ty, unresolved) = match path.type_anchor() {
477 Some(type_ref) => {
478 let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
479 res.map(|ty_ns| (ty_ns, path.segments().first()))
480 }
481 None => {
482 let (ty, remaining) =
483 resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
484 match remaining {
485 Some(remaining) if remaining > 1 => None,
486 _ => Some((ty, path.segments().get(1))),
487 }
488 }
489 }?;
490 let res = match ty {
470 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()), 491 TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
471 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }), 492 TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
472 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => { 493 TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
@@ -476,7 +497,17 @@ fn resolve_hir_path_(
476 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()), 497 TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
477 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()), 498 TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
478 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()), 499 TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
479 }) 500 };
501 match unresolved {
502 Some(unresolved) => res
503 .assoc_type_shorthand_candidates(db, |name, alias| {
504 (name == unresolved.name).then(|| alias)
505 })
506 .map(TypeAlias::from)
507 .map(Into::into)
508 .map(PathResolution::Def),
509 None => Some(res),
510 }
480 }; 511 };
481 512
482 let body_owner = resolver.body_owner(); 513 let body_owner = resolver.body_owner();
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index 475d337f3..43324d8d9 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -11,6 +11,7 @@ doctest = false
11 11
12[dependencies] 12[dependencies]
13cov-mark = { version = "1.1", features = ["thread-local"] } 13cov-mark = { version = "1.1", features = ["thread-local"] }
14dashmap = { version = "4.0.2", features = ["raw-api"] }
14log = "0.4.8" 15log = "0.4.8"
15once_cell = "1.3.1" 16once_cell = "1.3.1"
16rustc-hash = "1.1.0" 17rustc-hash = "1.1.0"
diff --git a/crates/hir_def/src/adt.rs b/crates/hir_def/src/adt.rs
index 58e35353b..402fb1d8d 100644
--- a/crates/hir_def/src/adt.rs
+++ b/crates/hir_def/src/adt.rs
@@ -15,6 +15,7 @@ use tt::{Delimiter, DelimiterKind, Leaf, Subtree, TokenTree};
15use crate::{ 15use crate::{
16 body::{CfgExpander, LowerCtx}, 16 body::{CfgExpander, LowerCtx},
17 db::DefDatabase, 17 db::DefDatabase,
18 intern::Interned,
18 item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId}, 19 item_tree::{AttrOwner, Field, Fields, ItemTree, ModItem, RawVisibilityId},
19 src::HasChildSource, 20 src::HasChildSource,
20 src::HasSource, 21 src::HasSource,
@@ -58,7 +59,7 @@ pub enum VariantData {
58#[derive(Debug, Clone, PartialEq, Eq)] 59#[derive(Debug, Clone, PartialEq, Eq)]
59pub struct FieldData { 60pub struct FieldData {
60 pub name: Name, 61 pub name: Name,
61 pub type_ref: TypeRef, 62 pub type_ref: Interned<TypeRef>,
62 pub visibility: RawVisibility, 63 pub visibility: RawVisibility,
63} 64}
64 65
@@ -292,7 +293,7 @@ fn lower_struct(
292 || Either::Left(fd.clone()), 293 || Either::Left(fd.clone()),
293 || FieldData { 294 || FieldData {
294 name: Name::new_tuple_field(i), 295 name: Name::new_tuple_field(i),
295 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), 296 type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())),
296 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 297 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
297 }, 298 },
298 ); 299 );
@@ -309,7 +310,7 @@ fn lower_struct(
309 || Either::Right(fd.clone()), 310 || Either::Right(fd.clone()),
310 || FieldData { 311 || FieldData {
311 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), 312 name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing),
312 type_ref: TypeRef::from_ast_opt(&ctx, fd.ty()), 313 type_ref: Interned::new(TypeRef::from_ast_opt(&ctx, fd.ty())),
313 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), 314 visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())),
314 }, 315 },
315 ); 316 );
@@ -358,7 +359,7 @@ fn lower_field(
358) -> FieldData { 359) -> FieldData {
359 FieldData { 360 FieldData {
360 name: field.name.clone(), 361 name: field.name.clone(),
361 type_ref: item_tree[field.type_ref].clone(), 362 type_ref: field.type_ref.clone(),
362 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(), 363 visibility: item_tree[override_visibility.unwrap_or(field.visibility)].clone(),
363 } 364 }
364} 365}
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 52a2bce9b..786fad6e1 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -1,23 +1,28 @@
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
19use crate::{ 23use crate::{
20 db::DefDatabase, 24 db::DefDatabase,
25 intern::Interned,
21 item_tree::{ItemTreeId, ItemTreeNode}, 26 item_tree::{ItemTreeId, ItemTreeNode},
22 nameres::ModuleSource, 27 nameres::ModuleSource,
23 path::{ModPath, PathKind}, 28 path::{ModPath, PathKind},
@@ -93,13 +98,16 @@ impl RawAttrs {
93 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self { 98 pub(crate) fn new(owner: &dyn ast::AttrsOwner, hygiene: &Hygiene) -> Self {
94 let entries = collect_attrs(owner) 99 let entries = collect_attrs(owner)
95 .enumerate() 100 .enumerate()
96 .flat_map(|(i, attr)| match attr { 101 .flat_map(|(i, attr)| {
97 Either::Left(attr) => Attr::from_src(attr, hygiene, i as u32), 102 let index = AttrId(i as u32);
98 Either::Right(comment) => comment.doc_comment().map(|doc| Attr { 103 match attr {
99 index: i as u32, 104 Either::Left(attr) => Attr::from_src(attr, hygiene, index),
100 input: Some(AttrInput::Literal(SmolStr::new(doc))), 105 Either::Right(comment) => comment.doc_comment().map(|doc| Attr {
101 path: ModPath::from(hir_expand::name!(doc)), 106 id: index,
102 }), 107 input: Some(AttrInput::Literal(SmolStr::new(doc))),
108 path: Interned::new(ModPath::from(hir_expand::name!(doc))),
109 }),
110 }
103 }) 111 })
104 .collect::<Arc<_>>(); 112 .collect::<Arc<_>>();
105 113
@@ -156,7 +164,7 @@ impl RawAttrs {
156 let cfg = parts.next().unwrap(); 164 let cfg = parts.next().unwrap();
157 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() }; 165 let cfg = Subtree { delimiter: subtree.delimiter, token_trees: cfg.to_vec() };
158 let cfg = CfgExpr::parse(&cfg); 166 let cfg = CfgExpr::parse(&cfg);
159 let index = attr.index; 167 let index = attr.id;
160 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| { 168 let attrs = parts.filter(|a| !a.is_empty()).filter_map(|attr| {
161 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() }; 169 let tree = Subtree { delimiter: None, token_trees: attr.to_vec() };
162 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?; 170 let attr = ast::Attr::parse(&format!("#[{}]", tree)).ok()?;
@@ -210,12 +218,11 @@ impl Attrs {
210 let mut res = ArenaMap::default(); 218 let mut res = ArenaMap::default();
211 219
212 for (id, fld) in src.value.iter() { 220 for (id, fld) in src.value.iter() {
213 let attrs = match fld { 221 let owner: &dyn AttrsOwner = match fld {
214 Either::Left(_tuple) => Attrs::default(), 222 Either::Left(tuple) => tuple,
215 Either::Right(record) => { 223 Either::Right(record) => record,
216 RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
217 }
218 }; 224 };
225 let attrs = RawAttrs::from_attrs_owner(db, src.with_value(owner)).filter(db, krate);
219 226
220 res.insert(id, attrs); 227 res.insert(id, attrs);
221 } 228 }
@@ -399,10 +406,14 @@ impl AttrsWithOwner {
399 return AttrSourceMap { attrs }; 406 return AttrSourceMap { attrs };
400 } 407 }
401 AttrDefId::FieldId(id) => { 408 AttrDefId::FieldId(id) => {
402 id.parent.child_source(db).map(|source| match &source[id.local_id] { 409 let map = db.fields_attrs_source_map(id.parent);
403 Either::Left(field) => ast::AttrsOwnerNode::new(field.clone()), 410 let file_id = id.parent.file_id(db);
404 Either::Right(field) => ast::AttrsOwnerNode::new(field.clone()), 411 let root = db.parse_or_expand(file_id).unwrap();
405 }) 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)
406 } 417 }
407 AttrDefId::AdtId(adt) => match adt { 418 AttrDefId::AdtId(adt) => match adt {
408 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),
@@ -410,10 +421,12 @@ impl AttrsWithOwner {
410 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),
411 }, 422 },
412 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),
413 AttrDefId::EnumVariantId(id) => id 424 AttrDefId::EnumVariantId(id) => {
414 .parent 425 let map = db.variants_attrs_source_map(id.parent);
415 .child_source(db) 426 let file_id = id.parent.lookup(db).id.file_id();
416 .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 }
417 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),
418 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),
419 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),
@@ -451,6 +464,55 @@ impl AttrsWithOwner {
451 .collect(), 464 .collect(),
452 } 465 }
453 } 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 }
454} 516}
455 517
456fn inner_attributes( 518fn inner_attributes(
@@ -501,16 +563,54 @@ impl AttrSourceMap {
501 /// the attribute represented by `Attr`. 563 /// the attribute represented by `Attr`.
502 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>> {
503 self.attrs 565 self.attrs
504 .get(attr.index as usize) 566 .get(attr.id.0 as usize)
505 .unwrap_or_else(|| panic!("cannot find `Attr` at index {}", attr.index)) 567 .unwrap_or_else(|| panic!("cannot find `Attr` at index {:?}", attr.id))
506 .as_ref() 568 .as_ref()
507 } 569 }
508} 570}
509 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
510#[derive(Debug, Clone, PartialEq, Eq)] 610#[derive(Debug, Clone, PartialEq, Eq)]
511pub struct Attr { 611pub struct Attr {
512 index: u32, 612 pub(crate) id: AttrId,
513 pub(crate) path: ModPath, 613 pub(crate) path: Interned<ModPath>,
514 pub(crate) input: Option<AttrInput>, 614 pub(crate) input: Option<AttrInput>,
515} 615}
516 616
@@ -523,8 +623,8 @@ pub enum AttrInput {
523} 623}
524 624
525impl Attr { 625impl Attr {
526 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> {
527 let path = ModPath::from_src(ast.path()?, hygiene)?; 627 let path = Interned::new(ModPath::from_src(ast.path()?, hygiene)?);
528 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() { 628 let input = if let Some(ast::Expr::Literal(lit)) = ast.expr() {
529 let value = match lit.kind() { 629 let value = match lit.kind() {
530 ast::LiteralKind::String(string) => string.value()?.into(), 630 ast::LiteralKind::String(string) => string.value()?.into(),
@@ -532,11 +632,11 @@ impl Attr {
532 }; 632 };
533 Some(AttrInput::Literal(value)) 633 Some(AttrInput::Literal(value))
534 } else if let Some(tt) = ast.token_tree() { 634 } else if let Some(tt) = ast.token_tree() {
535 Some(AttrInput::TokenTree(ast_to_token_tree(&tt)?.0)) 635 Some(AttrInput::TokenTree(ast_to_token_tree(&tt).0))
536 } else { 636 } else {
537 None 637 None
538 }; 638 };
539 Some(Attr { index, path, input }) 639 Some(Attr { id, path, input })
540 } 640 }
541 641
542 /// 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
@@ -651,7 +751,38 @@ fn collect_attrs(
651 .chain(inner_docs.into_iter().flatten()) 751 .chain(inner_docs.into_iter().flatten())
652 .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)));
653 // 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
654 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 }
655 786
656 attrs.into_iter().map(|(_, attr)| attr) 787 Arc::new(res)
657} 788}
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index 1080d9c2c..96b959967 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -226,7 +226,7 @@ pub struct Body {
226 /// The `ExprId` of the actual body expression. 226 /// The `ExprId` of the actual body expression.
227 pub body_expr: ExprId, 227 pub body_expr: ExprId,
228 /// Block expressions in this body that may contain inner items. 228 /// Block expressions in this body that may contain inner items.
229 pub block_scopes: Vec<BlockId>, 229 block_scopes: Vec<BlockId>,
230 _c: Count<Self>, 230 _c: Count<Self>,
231} 231}
232 232
@@ -302,7 +302,8 @@ impl Body {
302 } 302 }
303 }; 303 };
304 let expander = Expander::new(db, file_id, module); 304 let expander = Expander::new(db, file_id, module);
305 let (body, source_map) = Body::new(db, expander, params, body); 305 let (mut body, source_map) = Body::new(db, expander, params, body);
306 body.shrink_to_fit();
306 (Arc::new(body), Arc::new(source_map)) 307 (Arc::new(body), Arc::new(source_map))
307 } 308 }
308 309
@@ -310,6 +311,16 @@ impl Body {
310 db.body_with_source_map(def).0 311 db.body_with_source_map(def).0
311 } 312 }
312 313
314 /// Returns an iterator over all block expressions in this body that define inner items.
315 pub fn blocks<'a>(
316 &'a self,
317 db: &'a dyn DefDatabase,
318 ) -> impl Iterator<Item = (BlockId, Arc<DefMap>)> + '_ {
319 self.block_scopes
320 .iter()
321 .map(move |block| (*block, db.block_def_map(*block).expect("block ID without DefMap")))
322 }
323
313 fn new( 324 fn new(
314 db: &dyn DefDatabase, 325 db: &dyn DefDatabase,
315 expander: Expander, 326 expander: Expander,
@@ -318,6 +329,15 @@ impl Body {
318 ) -> (Body, BodySourceMap) { 329 ) -> (Body, BodySourceMap) {
319 lower::lower(db, expander, params, body) 330 lower::lower(db, expander, params, body)
320 } 331 }
332
333 fn shrink_to_fit(&mut self) {
334 let Self { _c: _, body_expr: _, block_scopes, exprs, labels, params, pats } = self;
335 block_scopes.shrink_to_fit();
336 exprs.shrink_to_fit();
337 labels.shrink_to_fit();
338 params.shrink_to_fit();
339 pats.shrink_to_fit();
340 }
321} 341}
322 342
323impl Index<ExprId> for Body { 343impl Index<ExprId> for Body {
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 229e81dd4..c0b0b7841 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -30,6 +30,7 @@ use crate::{
30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, 30 LabelId, Literal, LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField,
31 Statement, 31 Statement,
32 }, 32 },
33 intern::Interned,
33 item_scope::BuiltinShadowMode, 34 item_scope::BuiltinShadowMode,
34 path::{GenericArgs, Path}, 35 path::{GenericArgs, Path},
35 type_ref::{Mutability, Rawness, TypeRef}, 36 type_ref::{Mutability, Rawness, TypeRef},
@@ -322,8 +323,10 @@ impl ExprCollector<'_> {
322 Vec::new() 323 Vec::new()
323 }; 324 };
324 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 325 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
325 let generic_args = 326 let generic_args = e
326 e.generic_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx(), it)); 327 .generic_arg_list()
328 .and_then(|it| GenericArgs::from_ast(&self.ctx(), it))
329 .map(Box::new);
327 self.alloc_expr( 330 self.alloc_expr(
328 Expr::MethodCall { receiver, method_name, args, generic_args }, 331 Expr::MethodCall { receiver, method_name, args, generic_args },
329 syntax_ptr, 332 syntax_ptr,
@@ -385,7 +388,7 @@ impl ExprCollector<'_> {
385 self.alloc_expr(Expr::Yield { expr }, syntax_ptr) 388 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
386 } 389 }
387 ast::Expr::RecordExpr(e) => { 390 ast::Expr::RecordExpr(e) => {
388 let path = e.path().and_then(|path| self.expander.parse_path(path)); 391 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() { 392 let record_lit = if let Some(nfl) = e.record_expr_field_list() {
390 let fields = nfl 393 let fields = nfl
391 .fields() 394 .fields()
@@ -430,7 +433,7 @@ impl ExprCollector<'_> {
430 } 433 }
431 ast::Expr::CastExpr(e) => { 434 ast::Expr::CastExpr(e) => {
432 let expr = self.collect_expr_opt(e.expr()); 435 let expr = self.collect_expr_opt(e.expr());
433 let type_ref = TypeRef::from_ast_opt(&self.ctx(), e.ty()); 436 let type_ref = Interned::new(TypeRef::from_ast_opt(&self.ctx(), e.ty()));
434 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) 437 self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr)
435 } 438 }
436 ast::Expr::RefExpr(e) => { 439 ast::Expr::RefExpr(e) => {
@@ -464,13 +467,16 @@ impl ExprCollector<'_> {
464 if let Some(pl) = e.param_list() { 467 if let Some(pl) = e.param_list() {
465 for param in pl.params() { 468 for param in pl.params() {
466 let pat = self.collect_pat_opt(param.pat()); 469 let pat = self.collect_pat_opt(param.pat());
467 let type_ref = param.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 470 let type_ref =
471 param.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
468 args.push(pat); 472 args.push(pat);
469 arg_types.push(type_ref); 473 arg_types.push(type_ref);
470 } 474 }
471 } 475 }
472 let ret_type = 476 let ret_type = e
473 e.ret_type().and_then(|r| r.ty()).map(|it| TypeRef::from_ast(&self.ctx(), it)); 477 .ret_type()
478 .and_then(|r| r.ty())
479 .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
474 let body = self.collect_expr_opt(e.body()); 480 let body = self.collect_expr_opt(e.body());
475 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) 481 self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr)
476 } 482 }
@@ -525,8 +531,9 @@ impl ExprCollector<'_> {
525 } 531 }
526 } 532 }
527 ast::Expr::MacroCall(e) => { 533 ast::Expr::MacroCall(e) => {
534 let macro_ptr = AstPtr::new(&e);
528 let mut ids = vec![]; 535 let mut ids = vec![];
529 self.collect_macro_call(e, syntax_ptr.clone(), true, |this, expansion| { 536 self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
530 ids.push(match expansion { 537 ids.push(match expansion {
531 Some(it) => this.collect_expr(it), 538 Some(it) => this.collect_expr(it),
532 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()), 539 None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
@@ -549,7 +556,7 @@ impl ExprCollector<'_> {
549 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>( 556 fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
550 &mut self, 557 &mut self,
551 e: ast::MacroCall, 558 e: ast::MacroCall,
552 syntax_ptr: AstPtr<ast::Expr>, 559 syntax_ptr: AstPtr<ast::MacroCall>,
553 is_error_recoverable: bool, 560 is_error_recoverable: bool,
554 mut collector: F, 561 mut collector: F,
555 ) { 562 ) {
@@ -561,9 +568,13 @@ impl ExprCollector<'_> {
561 568
562 let res = match res { 569 let res = match res {
563 Ok(res) => res, 570 Ok(res) => res,
564 Err(UnresolvedMacro) => { 571 Err(UnresolvedMacro { path }) => {
565 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall( 572 self.source_map.diagnostics.push(BodyDiagnostic::UnresolvedMacroCall(
566 UnresolvedMacroCall { file: outer_file, node: syntax_ptr.cast().unwrap() }, 573 UnresolvedMacroCall {
574 file: outer_file,
575 node: syntax_ptr.cast().unwrap(),
576 path,
577 },
567 )); 578 ));
568 collector(self, None); 579 collector(self, None);
569 return; 580 return;
@@ -625,7 +636,8 @@ impl ExprCollector<'_> {
625 return; 636 return;
626 } 637 }
627 let pat = self.collect_pat_opt(stmt.pat()); 638 let pat = self.collect_pat_opt(stmt.pat());
628 let type_ref = stmt.ty().map(|it| TypeRef::from_ast(&self.ctx(), it)); 639 let type_ref =
640 stmt.ty().map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
629 let initializer = stmt.initializer().map(|e| self.collect_expr(e)); 641 let initializer = stmt.initializer().map(|e| self.collect_expr(e));
630 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer }); 642 self.statements_in_scope.push(Statement::Let { pat, type_ref, initializer });
631 } 643 }
@@ -636,10 +648,14 @@ impl ExprCollector<'_> {
636 648
637 // Note that macro could be expended to multiple statements 649 // Note that macro could be expended to multiple statements
638 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() { 650 if let Some(ast::Expr::MacroCall(m)) = stmt.expr() {
651 let macro_ptr = AstPtr::new(&m);
639 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap()); 652 let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
640 653
641 self.collect_macro_call(m, syntax_ptr.clone(), false, |this, expansion| { 654 self.collect_macro_call(
642 match expansion { 655 m,
656 macro_ptr,
657 false,
658 |this, expansion| match expansion {
643 Some(expansion) => { 659 Some(expansion) => {
644 let statements: ast::MacroStmts = expansion; 660 let statements: ast::MacroStmts = expansion;
645 661
@@ -653,8 +669,8 @@ impl ExprCollector<'_> {
653 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone()); 669 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
654 this.statements_in_scope.push(Statement::Expr(expr)); 670 this.statements_in_scope.push(Statement::Expr(expr));
655 } 671 }
656 } 672 },
657 }); 673 );
658 } else { 674 } else {
659 let expr = self.collect_expr_opt(stmt.expr()); 675 let expr = self.collect_expr_opt(stmt.expr());
660 self.statements_in_scope.push(Statement::Expr(expr)); 676 self.statements_in_scope.push(Statement::Expr(expr));
@@ -673,12 +689,14 @@ impl ExprCollector<'_> {
673 let block_loc = 689 let block_loc =
674 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) }; 690 BlockLoc { ast_id, module: self.expander.def_map.module_id(self.expander.module) };
675 let block_id = self.db.intern_block(block_loc); 691 let block_id = self.db.intern_block(block_loc);
676 self.body.block_scopes.push(block_id);
677 692
678 let opt_def_map = self.db.block_def_map(block_id); 693 let (module, def_map) = match self.db.block_def_map(block_id) {
679 let has_def_map = opt_def_map.is_some(); 694 Some(def_map) => {
680 let def_map = opt_def_map.unwrap_or_else(|| self.expander.def_map.clone()); 695 self.body.block_scopes.push(block_id);
681 let module = if has_def_map { def_map.root() } else { self.expander.module }; 696 (def_map.root(), def_map)
697 }
698 None => (self.expander.module, self.expander.def_map.clone()),
699 };
682 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map); 700 let prev_def_map = mem::replace(&mut self.expander.def_map, def_map);
683 let prev_local_module = mem::replace(&mut self.expander.module, module); 701 let prev_local_module = mem::replace(&mut self.expander.module, module);
684 let prev_statements = std::mem::take(&mut self.statements_in_scope); 702 let prev_statements = std::mem::take(&mut self.statements_in_scope);
@@ -753,7 +771,7 @@ impl ExprCollector<'_> {
753 } 771 }
754 } 772 }
755 ast::Pat::TupleStructPat(p) => { 773 ast::Pat::TupleStructPat(p) => {
756 let path = p.path().and_then(|path| self.expander.parse_path(path)); 774 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
757 let (args, ellipsis) = self.collect_tuple_pat(p.fields()); 775 let (args, ellipsis) = self.collect_tuple_pat(p.fields());
758 Pat::TupleStruct { path, args, ellipsis } 776 Pat::TupleStruct { path, args, ellipsis }
759 } 777 }
@@ -763,7 +781,7 @@ impl ExprCollector<'_> {
763 Pat::Ref { pat, mutability } 781 Pat::Ref { pat, mutability }
764 } 782 }
765 ast::Pat::PathPat(p) => { 783 ast::Pat::PathPat(p) => {
766 let path = p.path().and_then(|path| self.expander.parse_path(path)); 784 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
767 path.map(Pat::Path).unwrap_or(Pat::Missing) 785 path.map(Pat::Path).unwrap_or(Pat::Missing)
768 } 786 }
769 ast::Pat::OrPat(p) => { 787 ast::Pat::OrPat(p) => {
@@ -777,7 +795,7 @@ impl ExprCollector<'_> {
777 } 795 }
778 ast::Pat::WildcardPat(_) => Pat::Wild, 796 ast::Pat::WildcardPat(_) => Pat::Wild,
779 ast::Pat::RecordPat(p) => { 797 ast::Pat::RecordPat(p) => {
780 let path = p.path().and_then(|path| self.expander.parse_path(path)); 798 let path = p.path().and_then(|path| self.expander.parse_path(path)).map(Box::new);
781 let args: Vec<_> = p 799 let args: Vec<_> = p
782 .record_pat_field_list() 800 .record_pat_field_list()
783 .expect("every struct should have a field list") 801 .expect("every struct should have a field list")
@@ -839,8 +857,23 @@ impl ExprCollector<'_> {
839 Pat::Missing 857 Pat::Missing
840 } 858 }
841 } 859 }
860 ast::Pat::MacroPat(mac) => match mac.macro_call() {
861 Some(call) => {
862 let macro_ptr = AstPtr::new(&call);
863 let mut pat = None;
864 self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
865 pat = Some(this.collect_pat_opt(expanded_pat));
866 });
867
868 match pat {
869 Some(pat) => return pat,
870 None => Pat::Missing,
871 }
872 }
873 None => Pat::Missing,
874 },
842 // FIXME: implement 875 // FIXME: implement
843 ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, 876 ast::Pat::RangePat(_) => Pat::Missing,
844 }; 877 };
845 let ptr = AstPtr::new(&pat); 878 let ptr = AstPtr::new(&pat);
846 self.alloc_pat(pattern, Either::Left(ptr)) 879 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..63f5fe88d 100644
--- a/crates/hir_def/src/body/tests.rs
+++ b/crates/hir_def/src/body/tests.rs
@@ -143,7 +143,7 @@ fn f() {
143 //^^^^^^^^^^^^^ could not convert tokens 143 //^^^^^^^^^^^^^ could not convert tokens
144 144
145 env!("OUT_DIR"); 145 env!("OUT_DIR");
146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 146 //^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
147 147
148 compile_error!("compile_error works"); 148 compile_error!("compile_error works");
149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works 149 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ compile_error works
@@ -180,7 +180,7 @@ fn unresolved_macro_diag() {
180 r#" 180 r#"
181fn f() { 181fn f() {
182 m!(); 182 m!();
183 //^^^^ unresolved macro call 183 //^^^^ unresolved macro `m!`
184} 184}
185 "#, 185 "#,
186 ); 186 );
diff --git a/crates/hir_def/src/child_by_source.rs b/crates/hir_def/src/child_by_source.rs
index 2a331dcaf..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) {
@@ -160,7 +164,7 @@ impl ChildBySource for EnumId {
160impl ChildBySource for DefWithBodyId { 164impl ChildBySource for DefWithBodyId {
161 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) { 165 fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap) {
162 let body = db.body(*self); 166 let body = db.body(*self);
163 for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { 167 for (_, def_map) in body.blocks(db) {
164 // All block expressions are merged into the same map, because they logically all add 168 // All block expressions are merged into the same map, because they logically all add
165 // inner items to the containing `DefWithBodyId`. 169 // inner items to the containing `DefWithBodyId`.
166 def_map[def_map.root()].scope.child_by_source_to(db, res); 170 def_map[def_map.root()].scope.child_by_source_to(db, res);
diff --git a/crates/hir_def/src/data.rs b/crates/hir_def/src/data.rs
index 0be868ba2..135a6698e 100644
--- a/crates/hir_def/src/data.rs
+++ b/crates/hir_def/src/data.rs
@@ -9,8 +9,9 @@ use crate::{
9 attr::Attrs, 9 attr::Attrs,
10 body::Expander, 10 body::Expander,
11 db::DefDatabase, 11 db::DefDatabase,
12 item_tree::{AssocItem, FunctionQualifier, ItemTreeId, ModItem, Param}, 12 intern::Interned,
13 type_ref::{TypeBound, TypeRef}, 13 item_tree::{AssocItem, FnFlags, ItemTreeId, ModItem, Param},
14 type_ref::{TraitRef, TypeBound, TypeRef},
14 visibility::RawVisibility, 15 visibility::RawVisibility,
15 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId, 16 AssocContainerId, AssocItemId, ConstId, ConstLoc, FunctionId, FunctionLoc, HasModule, ImplId,
16 Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc, 17 Intern, Lookup, ModuleId, StaticId, TraitId, TypeAliasId, TypeAliasLoc,
@@ -19,17 +20,12 @@ use crate::{
19#[derive(Debug, Clone, PartialEq, Eq)] 20#[derive(Debug, Clone, PartialEq, Eq)]
20pub struct FunctionData { 21pub struct FunctionData {
21 pub name: Name, 22 pub name: Name,
22 pub params: Vec<TypeRef>, 23 pub params: Vec<Interned<TypeRef>>,
23 pub ret_type: TypeRef, 24 pub ret_type: Interned<TypeRef>,
24 pub attrs: Attrs, 25 pub attrs: Attrs,
25 /// True if the first param is `self`. This is relevant to decide whether this
26 /// can be called as a method.
27 pub has_self_param: bool,
28 pub has_body: bool,
29 pub qualifier: FunctionQualifier,
30 pub is_in_extern_block: bool,
31 pub is_varargs: bool,
32 pub visibility: RawVisibility, 26 pub visibility: RawVisibility,
27 pub abi: Option<Interned<str>>,
28 flags: FnFlags,
33} 29}
34 30
35impl FunctionData { 31impl FunctionData {
@@ -52,31 +48,67 @@ impl FunctionData {
52 .next_back() 48 .next_back()
53 .map_or(false, |param| matches!(item_tree[param], Param::Varargs)); 49 .map_or(false, |param| matches!(item_tree[param], Param::Varargs));
54 50
51 let mut flags = func.flags;
52 if is_varargs {
53 flags.bits |= FnFlags::IS_VARARGS;
54 }
55
55 Arc::new(FunctionData { 56 Arc::new(FunctionData {
56 name: func.name.clone(), 57 name: func.name.clone(),
57 params: enabled_params 58 params: enabled_params
58 .clone() 59 .clone()
59 .filter_map(|id| match &item_tree[id] { 60 .filter_map(|id| match &item_tree[id] {
60 Param::Normal(ty) => Some(item_tree[*ty].clone()), 61 Param::Normal(ty) => Some(ty.clone()),
61 Param::Varargs => None, 62 Param::Varargs => None,
62 }) 63 })
63 .collect(), 64 .collect(),
64 ret_type: item_tree[func.ret_type].clone(), 65 ret_type: func.ret_type.clone(),
65 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()), 66 attrs: item_tree.attrs(db, krate, ModItem::from(loc.id.value).into()),
66 has_self_param: func.has_self_param,
67 has_body: func.has_body,
68 qualifier: func.qualifier.clone(),
69 is_in_extern_block: func.is_in_extern_block,
70 is_varargs,
71 visibility: item_tree[func.visibility].clone(), 67 visibility: item_tree[func.visibility].clone(),
68 abi: func.abi.clone(),
69 flags,
72 }) 70 })
73 } 71 }
72
73 pub fn has_body(&self) -> bool {
74 self.flags.bits & FnFlags::HAS_BODY != 0
75 }
76
77 /// True if the first param is `self`. This is relevant to decide whether this
78 /// can be called as a method.
79 pub fn has_self_param(&self) -> bool {
80 self.flags.bits & FnFlags::HAS_SELF_PARAM != 0
81 }
82
83 pub fn is_default(&self) -> bool {
84 self.flags.bits & FnFlags::IS_DEFAULT != 0
85 }
86
87 pub fn is_const(&self) -> bool {
88 self.flags.bits & FnFlags::IS_CONST != 0
89 }
90
91 pub fn is_async(&self) -> bool {
92 self.flags.bits & FnFlags::IS_ASYNC != 0
93 }
94
95 pub fn is_unsafe(&self) -> bool {
96 self.flags.bits & FnFlags::IS_UNSAFE != 0
97 }
98
99 pub fn is_in_extern_block(&self) -> bool {
100 self.flags.bits & FnFlags::IS_IN_EXTERN_BLOCK != 0
101 }
102
103 pub fn is_varargs(&self) -> bool {
104 self.flags.bits & FnFlags::IS_VARARGS != 0
105 }
74} 106}
75 107
76#[derive(Debug, Clone, PartialEq, Eq)] 108#[derive(Debug, Clone, PartialEq, Eq)]
77pub struct TypeAliasData { 109pub struct TypeAliasData {
78 pub name: Name, 110 pub name: Name,
79 pub type_ref: Option<TypeRef>, 111 pub type_ref: Option<Interned<TypeRef>>,
80 pub visibility: RawVisibility, 112 pub visibility: RawVisibility,
81 pub is_extern: bool, 113 pub is_extern: bool,
82 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl). 114 /// Bounds restricting the type alias itself (eg. `type Ty: Bound;` in a trait or impl).
@@ -94,7 +126,7 @@ impl TypeAliasData {
94 126
95 Arc::new(TypeAliasData { 127 Arc::new(TypeAliasData {
96 name: typ.name.clone(), 128 name: typ.name.clone(),
97 type_ref: typ.type_ref.map(|id| item_tree[id].clone()), 129 type_ref: typ.type_ref.clone(),
98 visibility: item_tree[typ.visibility].clone(), 130 visibility: item_tree[typ.visibility].clone(),
99 is_extern: typ.is_extern, 131 is_extern: typ.is_extern,
100 bounds: typ.bounds.to_vec(), 132 bounds: typ.bounds.to_vec(),
@@ -156,8 +188,8 @@ impl TraitData {
156 188
157#[derive(Debug, Clone, PartialEq, Eq)] 189#[derive(Debug, Clone, PartialEq, Eq)]
158pub struct ImplData { 190pub struct ImplData {
159 pub target_trait: Option<TypeRef>, 191 pub target_trait: Option<Interned<TraitRef>>,
160 pub target_type: TypeRef, 192 pub self_ty: Interned<TypeRef>,
161 pub items: Vec<AssocItemId>, 193 pub items: Vec<AssocItemId>,
162 pub is_negative: bool, 194 pub is_negative: bool,
163} 195}
@@ -169,8 +201,8 @@ impl ImplData {
169 201
170 let item_tree = impl_loc.id.item_tree(db); 202 let item_tree = impl_loc.id.item_tree(db);
171 let impl_def = &item_tree[impl_loc.id.value]; 203 let impl_def = &item_tree[impl_loc.id.value];
172 let target_trait = impl_def.target_trait.map(|id| item_tree[id].clone()); 204 let target_trait = impl_def.target_trait.clone();
173 let target_type = item_tree[impl_def.target_type].clone(); 205 let self_ty = impl_def.self_ty.clone();
174 let is_negative = impl_def.is_negative; 206 let is_negative = impl_def.is_negative;
175 let module_id = impl_loc.container; 207 let module_id = impl_loc.container;
176 let container = AssocContainerId::ImplId(id); 208 let container = AssocContainerId::ImplId(id);
@@ -187,7 +219,7 @@ impl ImplData {
187 ); 219 );
188 let items = items.into_iter().map(|(_, item)| item).collect(); 220 let items = items.into_iter().map(|(_, item)| item).collect();
189 221
190 Arc::new(ImplData { target_trait, target_type, items, is_negative }) 222 Arc::new(ImplData { target_trait, self_ty, items, is_negative })
191 } 223 }
192} 224}
193 225
@@ -195,7 +227,7 @@ impl ImplData {
195pub struct ConstData { 227pub struct ConstData {
196 /// const _: () = (); 228 /// const _: () = ();
197 pub name: Option<Name>, 229 pub name: Option<Name>,
198 pub type_ref: TypeRef, 230 pub type_ref: Interned<TypeRef>,
199 pub visibility: RawVisibility, 231 pub visibility: RawVisibility,
200} 232}
201 233
@@ -207,7 +239,7 @@ impl ConstData {
207 239
208 Arc::new(ConstData { 240 Arc::new(ConstData {
209 name: konst.name.clone(), 241 name: konst.name.clone(),
210 type_ref: item_tree[konst.type_ref].clone(), 242 type_ref: konst.type_ref.clone(),
211 visibility: item_tree[konst.visibility].clone(), 243 visibility: item_tree[konst.visibility].clone(),
212 }) 244 })
213 } 245 }
@@ -216,7 +248,7 @@ impl ConstData {
216#[derive(Debug, Clone, PartialEq, Eq)] 248#[derive(Debug, Clone, PartialEq, Eq)]
217pub struct StaticData { 249pub struct StaticData {
218 pub name: Option<Name>, 250 pub name: Option<Name>,
219 pub type_ref: TypeRef, 251 pub type_ref: Interned<TypeRef>,
220 pub visibility: RawVisibility, 252 pub visibility: RawVisibility,
221 pub mutable: bool, 253 pub mutable: bool,
222 pub is_extern: bool, 254 pub is_extern: bool,
@@ -230,7 +262,7 @@ impl StaticData {
230 262
231 Arc::new(StaticData { 263 Arc::new(StaticData {
232 name: Some(statik.name.clone()), 264 name: Some(statik.name.clone()),
233 type_ref: item_tree[statik.type_ref].clone(), 265 type_ref: statik.type_ref.clone(),
234 visibility: item_tree[statik.visibility].clone(), 266 visibility: item_tree[statik.visibility].clone(),
235 mutable: statik.mutable, 267 mutable: statik.mutable,
236 is_extern: statik.is_extern, 268 is_extern: statik.is_extern,
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..2c4bbe585 100644
--- a/crates/hir_def/src/find_path.rs
+++ b/crates/hir_def/src/find_path.rs
@@ -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,14 +938,14 @@ 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 "#,
889 "module::CompleteMe", 950 "module::CompleteMe",
890 "module::CompleteMe", 951 "module::CompleteMe",
@@ -894,6 +955,29 @@ mod tests {
894 } 955 }
895 956
896 #[test] 957 #[test]
958 fn from_inside_module() {
959 // This worked correctly, but the test suite logic was broken.
960 cov_mark::check!(submodule_in_testdb);
961 check_found_path(
962 r#"
963mod baz {
964 pub struct Foo {}
965}
966
967mod bar {
968 fn bar() {
969 $0
970 }
971}
972 "#,
973 "crate::baz::Foo",
974 "crate::baz::Foo",
975 "crate::baz::Foo",
976 "crate::baz::Foo",
977 )
978 }
979
980 #[test]
897 fn recursive_pub_mod_reexport() { 981 fn recursive_pub_mod_reexport() {
898 cov_mark::check!(recursive_imports); 982 cov_mark::check!(recursive_imports);
899 check_found_path( 983 check_found_path(
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
new file mode 100644
index 000000000..abc304ef0
--- /dev/null
+++ b/crates/hir_def/src/intern.rs
@@ -0,0 +1,216 @@
1//! Global `Arc`-based object interning infrastructure.
2//!
3//! Eventually this should probably be replaced with salsa-based interning.
4
5use std::{
6 collections::HashMap,
7 fmt::{self, Debug},
8 hash::{BuildHasherDefault, Hash, Hasher},
9 ops::Deref,
10 sync::Arc,
11};
12
13use dashmap::{lock::RwLockWriteGuard, DashMap, SharedValue};
14use once_cell::sync::OnceCell;
15use rustc_hash::FxHasher;
16
17use crate::generics::GenericParams;
18
19type InternMap<T> = DashMap<Arc<T>, (), BuildHasherDefault<FxHasher>>;
20type Guard<T> =
21 RwLockWriteGuard<'static, HashMap<Arc<T>, SharedValue<()>, BuildHasherDefault<FxHasher>>>;
22
23pub struct Interned<T: Internable + ?Sized> {
24 arc: Arc<T>,
25}
26
27impl<T: Internable> Interned<T> {
28 pub fn new(obj: T) -> Self {
29 match Interned::lookup(&obj) {
30 Ok(this) => this,
31 Err(shard) => {
32 let arc = Arc::new(obj);
33 Self::alloc(arc, shard)
34 }
35 }
36 }
37}
38
39impl<T: Internable + ?Sized> Interned<T> {
40 fn lookup(obj: &T) -> Result<Self, Guard<T>> {
41 let storage = T::storage().get();
42 let shard_idx = storage.determine_map(obj);
43 let shard = &storage.shards()[shard_idx];
44 let shard = shard.write();
45
46 // Atomically,
47 // - check if `obj` is already in the map
48 // - if so, clone its `Arc` and return it
49 // - if not, box it up, insert it, and return a clone
50 // This needs to be atomic (locking the shard) to avoid races with other thread, which could
51 // insert the same object between us looking it up and inserting it.
52
53 // FIXME: avoid double lookup/hashing by using raw entry API (once stable, or when
54 // hashbrown can be plugged into dashmap)
55 match shard.get_key_value(obj) {
56 Some((arc, _)) => Ok(Self { arc: arc.clone() }),
57 None => Err(shard),
58 }
59 }
60
61 fn alloc(arc: Arc<T>, mut shard: Guard<T>) -> Self {
62 let arc2 = arc.clone();
63
64 shard.insert(arc2, SharedValue::new(()));
65
66 Self { arc }
67 }
68}
69
70impl Interned<str> {
71 pub fn new_str(s: &str) -> Self {
72 match Interned::lookup(s) {
73 Ok(this) => this,
74 Err(shard) => {
75 let arc = Arc::<str>::from(s);
76 Self::alloc(arc, shard)
77 }
78 }
79 }
80}
81
82impl<T: Internable + ?Sized> Drop for Interned<T> {
83 #[inline]
84 fn drop(&mut self) {
85 // When the last `Ref` is dropped, remove the object from the global map.
86 if Arc::strong_count(&self.arc) == 2 {
87 // Only `self` and the global map point to the object.
88
89 self.drop_slow();
90 }
91 }
92}
93
94impl<T: Internable + ?Sized> Interned<T> {
95 #[cold]
96 fn drop_slow(&mut self) {
97 let storage = T::storage().get();
98 let shard_idx = storage.determine_map(&self.arc);
99 let shard = &storage.shards()[shard_idx];
100 let mut shard = shard.write();
101
102 // FIXME: avoid double lookup
103 let (arc, _) = shard.get_key_value(&self.arc).expect("interned value removed prematurely");
104
105 if Arc::strong_count(arc) != 2 {
106 // Another thread has interned another copy
107 return;
108 }
109
110 shard.remove(&self.arc);
111
112 // Shrink the backing storage if the shard is less than 50% occupied.
113 if shard.len() * 2 < shard.capacity() {
114 shard.shrink_to_fit();
115 }
116 }
117}
118
119/// Compares interned `Ref`s using pointer equality.
120impl<T: Internable> PartialEq for Interned<T> {
121 // NOTE: No `?Sized` because `ptr_eq` doesn't work right with trait objects.
122
123 #[inline]
124 fn eq(&self, other: &Self) -> bool {
125 Arc::ptr_eq(&self.arc, &other.arc)
126 }
127}
128
129impl<T: Internable> Eq for Interned<T> {}
130
131impl PartialEq for Interned<str> {
132 fn eq(&self, other: &Self) -> bool {
133 Arc::ptr_eq(&self.arc, &other.arc)
134 }
135}
136
137impl Eq for Interned<str> {}
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
146impl<T: Internable + ?Sized> AsRef<T> for Interned<T> {
147 #[inline]
148 fn as_ref(&self) -> &T {
149 &self.arc
150 }
151}
152
153impl<T: Internable + ?Sized> Deref for Interned<T> {
154 type Target = T;
155
156 #[inline]
157 fn deref(&self) -> &Self::Target {
158 &self.arc
159 }
160}
161
162impl<T: Internable + ?Sized> Clone for Interned<T> {
163 fn clone(&self) -> Self {
164 Self { arc: self.arc.clone() }
165 }
166}
167
168impl<T: Debug + Internable + ?Sized> Debug for Interned<T> {
169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
170 (*self.arc).fmt(f)
171 }
172}
173
174pub struct InternStorage<T: ?Sized> {
175 map: OnceCell<InternMap<T>>,
176}
177
178impl<T: ?Sized> InternStorage<T> {
179 pub const fn new() -> Self {
180 Self { map: OnceCell::new() }
181 }
182}
183
184impl<T: Internable + ?Sized> InternStorage<T> {
185 fn get(&self) -> &InternMap<T> {
186 self.map.get_or_init(DashMap::default)
187 }
188}
189
190pub trait Internable: Hash + Eq + 'static {
191 fn storage() -> &'static InternStorage<Self>;
192}
193
194/// Implements `Internable` for a given list of types, making them usable with `Interned`.
195#[macro_export]
196#[doc(hidden)]
197macro_rules! _impl_internable {
198 ( $($t:path),+ $(,)? ) => { $(
199 impl Internable for $t {
200 fn storage() -> &'static InternStorage<Self> {
201 static STORAGE: InternStorage<$t> = InternStorage::new();
202 &STORAGE
203 }
204 }
205 )+ };
206}
207
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 f3ebe7c72..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 }
@@ -285,6 +294,30 @@ impl ItemScope {
285 buf.push('\n'); 294 buf.push('\n');
286 } 295 }
287 } 296 }
297
298 pub(crate) fn shrink_to_fit(&mut self) {
299 // Exhaustive match to require handling new fields.
300 let Self {
301 types,
302 values,
303 macros,
304 unresolved,
305 defs,
306 impls,
307 unnamed_consts,
308 unnamed_trait_imports,
309 legacy_macros,
310 } = self;
311 types.shrink_to_fit();
312 values.shrink_to_fit();
313 macros.shrink_to_fit();
314 unresolved.shrink_to_fit();
315 defs.shrink_to_fit();
316 impls.shrink_to_fit();
317 unnamed_consts.shrink_to_fit();
318 unnamed_trait_imports.shrink_to_fit();
319 legacy_macros.shrink_to_fit();
320 }
288} 321}
289 322
290impl PerNs { 323impl PerNs {
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index ca0048b16..94e08f835 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -24,14 +24,15 @@ use la_arena::{Arena, Idx, RawIdx};
24use profile::Count; 24use profile::Count;
25use rustc_hash::FxHashMap; 25use rustc_hash::FxHashMap;
26use smallvec::SmallVec; 26use smallvec::SmallVec;
27use syntax::{ast, match_ast, SmolStr, SyntaxKind}; 27use syntax::{ast, match_ast, SyntaxKind};
28 28
29use crate::{ 29use crate::{
30 attr::{Attrs, RawAttrs}, 30 attr::{Attrs, RawAttrs},
31 db::DefDatabase, 31 db::DefDatabase,
32 generics::GenericParams, 32 generics::GenericParams,
33 intern::Interned,
33 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind}, 34 path::{path, AssociatedTypeBinding, GenericArgs, ImportAlias, ModPath, Path, PathKind},
34 type_ref::{Mutability, TypeBound, TypeRef}, 35 type_ref::{Mutability, TraitRef, TypeBound, TypeRef},
35 visibility::RawVisibility, 36 visibility::RawVisibility,
36}; 37};
37 38
@@ -57,13 +58,6 @@ impl fmt::Debug for RawVisibilityId {
57 } 58 }
58} 59}
59 60
60#[derive(Debug, Copy, Clone, Eq, PartialEq)]
61pub struct GenericParamsId(u32);
62
63impl GenericParamsId {
64 pub const EMPTY: Self = GenericParamsId(u32::max_value());
65}
66
67/// The item tree of a source file. 61/// The item tree of a source file.
68#[derive(Debug, Default, Eq, PartialEq)] 62#[derive(Debug, Default, Eq, PartialEq)]
69pub struct ItemTree { 63pub struct ItemTree {
@@ -105,6 +99,11 @@ impl ItemTree {
105 // items. 99 // items.
106 ctx.lower_macro_stmts(stmts) 100 ctx.lower_macro_stmts(stmts)
107 }, 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 },
108 ast::Expr(e) => { 107 ast::Expr(e) => {
109 // Macros can expand to expressions. We return an empty item tree in this case, but 108 // Macros can expand to expressions. We return an empty item tree in this case, but
110 // still need to collect inner items. 109 // still need to collect inner items.
@@ -145,8 +144,6 @@ impl ItemTree {
145 macro_rules, 144 macro_rules,
146 macro_defs, 145 macro_defs,
147 vis, 146 vis,
148 generics,
149 type_refs,
150 inner_items, 147 inner_items,
151 } = &mut **data; 148 } = &mut **data;
152 149
@@ -170,9 +167,6 @@ impl ItemTree {
170 macro_defs.shrink_to_fit(); 167 macro_defs.shrink_to_fit();
171 168
172 vis.arena.shrink_to_fit(); 169 vis.arena.shrink_to_fit();
173 generics.arena.shrink_to_fit();
174 type_refs.arena.shrink_to_fit();
175 type_refs.map.shrink_to_fit();
176 170
177 inner_items.shrink_to_fit(); 171 inner_items.shrink_to_fit();
178 } 172 }
@@ -244,58 +238,6 @@ static VIS_PRIV: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKi
244static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate)); 238static VIS_PUB_CRATE: RawVisibility = RawVisibility::Module(ModPath::from_kind(PathKind::Crate));
245 239
246#[derive(Default, Debug, Eq, PartialEq)] 240#[derive(Default, Debug, Eq, PartialEq)]
247struct GenericParamsStorage {
248 arena: Arena<GenericParams>,
249}
250
251impl GenericParamsStorage {
252 fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
253 if params.types.is_empty()
254 && params.lifetimes.is_empty()
255 && params.consts.is_empty()
256 && params.where_predicates.is_empty()
257 {
258 return GenericParamsId::EMPTY;
259 }
260
261 GenericParamsId(self.arena.alloc(params).into_raw().into())
262 }
263}
264
265static EMPTY_GENERICS: GenericParams = GenericParams {
266 types: Arena::new(),
267 lifetimes: Arena::new(),
268 consts: Arena::new(),
269 where_predicates: Vec::new(),
270};
271
272/// `TypeRef` interner.
273#[derive(Default, Debug, Eq, PartialEq)]
274struct TypeRefStorage {
275 arena: Arena<Arc<TypeRef>>,
276 map: FxHashMap<Arc<TypeRef>, Idx<Arc<TypeRef>>>,
277}
278
279impl TypeRefStorage {
280 // Note: We lie about the `Idx<TypeRef>` to hide the interner details.
281
282 fn intern(&mut self, ty: TypeRef) -> Idx<TypeRef> {
283 if let Some(id) = self.map.get(&ty) {
284 return Idx::from_raw(id.into_raw());
285 }
286
287 let ty = Arc::new(ty);
288 let idx = self.arena.alloc(ty.clone());
289 self.map.insert(ty, idx);
290 Idx::from_raw(idx.into_raw())
291 }
292
293 fn lookup(&self, id: Idx<TypeRef>) -> &TypeRef {
294 &self.arena[Idx::from_raw(id.into_raw())]
295 }
296}
297
298#[derive(Default, Debug, Eq, PartialEq)]
299struct ItemTreeData { 241struct ItemTreeData {
300 imports: Arena<Import>, 242 imports: Arena<Import>,
301 extern_crates: Arena<ExternCrate>, 243 extern_crates: Arena<ExternCrate>,
@@ -317,8 +259,6 @@ struct ItemTreeData {
317 macro_defs: Arena<MacroDef>, 259 macro_defs: Arena<MacroDef>,
318 260
319 vis: ItemVisibilities, 261 vis: ItemVisibilities,
320 generics: GenericParamsStorage,
321 type_refs: TypeRefStorage,
322 262
323 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>, 263 inner_items: FxHashMap<FileAstId<ast::BlockExpr>, SmallVec<[ModItem; 1]>>,
324} 264}
@@ -537,25 +477,6 @@ impl Index<RawVisibilityId> for ItemTree {
537 } 477 }
538} 478}
539 479
540impl Index<GenericParamsId> for ItemTree {
541 type Output = GenericParams;
542
543 fn index(&self, index: GenericParamsId) -> &Self::Output {
544 match index {
545 GenericParamsId::EMPTY => &EMPTY_GENERICS,
546 _ => &self.data().generics.arena[Idx::from_raw(index.0.into())],
547 }
548 }
549}
550
551impl Index<Idx<TypeRef>> for ItemTree {
552 type Output = TypeRef;
553
554 fn index(&self, id: Idx<TypeRef>) -> &Self::Output {
555 self.data().type_refs.lookup(id)
556 }
557}
558
559impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree { 480impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
560 type Output = N; 481 type Output = N;
561 fn index(&self, id: FileItemTreeId<N>) -> &N { 482 fn index(&self, id: FileItemTreeId<N>) -> &N {
@@ -566,7 +487,7 @@ impl<N: ItemTreeNode> Index<FileItemTreeId<N>> for ItemTree {
566/// A desugared `use` import. 487/// A desugared `use` import.
567#[derive(Debug, Clone, Eq, PartialEq)] 488#[derive(Debug, Clone, Eq, PartialEq)]
568pub struct Import { 489pub struct Import {
569 pub path: ModPath, 490 pub path: Interned<ModPath>,
570 pub alias: Option<ImportAlias>, 491 pub alias: Option<ImportAlias>,
571 pub visibility: RawVisibilityId, 492 pub visibility: RawVisibilityId,
572 pub is_glob: bool, 493 pub is_glob: bool,
@@ -592,38 +513,42 @@ pub struct ExternCrate {
592pub struct Function { 513pub struct Function {
593 pub name: Name, 514 pub name: Name,
594 pub visibility: RawVisibilityId, 515 pub visibility: RawVisibilityId,
595 pub generic_params: GenericParamsId, 516 pub generic_params: Interned<GenericParams>,
596 pub has_self_param: bool, 517 pub abi: Option<Interned<str>>,
597 pub has_body: bool,
598 pub qualifier: FunctionQualifier,
599 /// Whether the function is located in an `extern` block (*not* whether it is an
600 /// `extern "abi" fn`).
601 pub is_in_extern_block: bool,
602 pub params: IdRange<Param>, 518 pub params: IdRange<Param>,
603 pub ret_type: Idx<TypeRef>, 519 pub ret_type: Interned<TypeRef>,
604 pub ast_id: FileAstId<ast::Fn>, 520 pub ast_id: FileAstId<ast::Fn>,
521 pub(crate) flags: FnFlags,
605} 522}
606 523
607#[derive(Debug, Clone, Eq, PartialEq)] 524#[derive(Debug, Clone, Eq, PartialEq)]
608pub enum Param { 525pub enum Param {
609 Normal(Idx<TypeRef>), 526 Normal(Interned<TypeRef>),
610 Varargs, 527 Varargs,
611} 528}
612 529
613#[derive(Debug, Clone, PartialEq, Eq)] 530#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
614pub struct FunctionQualifier { 531pub(crate) struct FnFlags {
615 pub is_default: bool, 532 pub(crate) bits: u8,
616 pub is_const: bool, 533}
617 pub is_async: bool, 534impl FnFlags {
618 pub is_unsafe: bool, 535 pub(crate) const HAS_SELF_PARAM: u8 = 1 << 0;
619 pub abi: Option<SmolStr>, 536 pub(crate) const HAS_BODY: u8 = 1 << 1;
537 pub(crate) const IS_DEFAULT: u8 = 1 << 2;
538 pub(crate) const IS_CONST: u8 = 1 << 3;
539 pub(crate) const IS_ASYNC: u8 = 1 << 4;
540 pub(crate) const IS_UNSAFE: u8 = 1 << 5;
541 /// Whether the function is located in an `extern` block (*not* whether it is an
542 /// `extern "abi" fn`).
543 pub(crate) const IS_IN_EXTERN_BLOCK: u8 = 1 << 6;
544 pub(crate) const IS_VARARGS: u8 = 1 << 7;
620} 545}
621 546
622#[derive(Debug, Clone, Eq, PartialEq)] 547#[derive(Debug, Clone, Eq, PartialEq)]
623pub struct Struct { 548pub struct Struct {
624 pub name: Name, 549 pub name: Name,
625 pub visibility: RawVisibilityId, 550 pub visibility: RawVisibilityId,
626 pub generic_params: GenericParamsId, 551 pub generic_params: Interned<GenericParams>,
627 pub fields: Fields, 552 pub fields: Fields,
628 pub ast_id: FileAstId<ast::Struct>, 553 pub ast_id: FileAstId<ast::Struct>,
629 pub kind: StructDefKind, 554 pub kind: StructDefKind,
@@ -643,7 +568,7 @@ pub enum StructDefKind {
643pub struct Union { 568pub struct Union {
644 pub name: Name, 569 pub name: Name,
645 pub visibility: RawVisibilityId, 570 pub visibility: RawVisibilityId,
646 pub generic_params: GenericParamsId, 571 pub generic_params: Interned<GenericParams>,
647 pub fields: Fields, 572 pub fields: Fields,
648 pub ast_id: FileAstId<ast::Union>, 573 pub ast_id: FileAstId<ast::Union>,
649} 574}
@@ -652,7 +577,7 @@ pub struct Union {
652pub struct Enum { 577pub struct Enum {
653 pub name: Name, 578 pub name: Name,
654 pub visibility: RawVisibilityId, 579 pub visibility: RawVisibilityId,
655 pub generic_params: GenericParamsId, 580 pub generic_params: Interned<GenericParams>,
656 pub variants: IdRange<Variant>, 581 pub variants: IdRange<Variant>,
657 pub ast_id: FileAstId<ast::Enum>, 582 pub ast_id: FileAstId<ast::Enum>,
658} 583}
@@ -662,7 +587,7 @@ pub struct Const {
662 /// const _: () = (); 587 /// const _: () = ();
663 pub name: Option<Name>, 588 pub name: Option<Name>,
664 pub visibility: RawVisibilityId, 589 pub visibility: RawVisibilityId,
665 pub type_ref: Idx<TypeRef>, 590 pub type_ref: Interned<TypeRef>,
666 pub ast_id: FileAstId<ast::Const>, 591 pub ast_id: FileAstId<ast::Const>,
667} 592}
668 593
@@ -673,7 +598,7 @@ pub struct Static {
673 pub mutable: bool, 598 pub mutable: bool,
674 /// Whether the static is in an `extern` block. 599 /// Whether the static is in an `extern` block.
675 pub is_extern: bool, 600 pub is_extern: bool,
676 pub type_ref: Idx<TypeRef>, 601 pub type_ref: Interned<TypeRef>,
677 pub ast_id: FileAstId<ast::Static>, 602 pub ast_id: FileAstId<ast::Static>,
678} 603}
679 604
@@ -681,7 +606,7 @@ pub struct Static {
681pub struct Trait { 606pub struct Trait {
682 pub name: Name, 607 pub name: Name,
683 pub visibility: RawVisibilityId, 608 pub visibility: RawVisibilityId,
684 pub generic_params: GenericParamsId, 609 pub generic_params: Interned<GenericParams>,
685 pub is_auto: bool, 610 pub is_auto: bool,
686 pub is_unsafe: bool, 611 pub is_unsafe: bool,
687 pub bounds: Box<[TypeBound]>, 612 pub bounds: Box<[TypeBound]>,
@@ -691,9 +616,9 @@ pub struct Trait {
691 616
692#[derive(Debug, Clone, Eq, PartialEq)] 617#[derive(Debug, Clone, Eq, PartialEq)]
693pub struct Impl { 618pub struct Impl {
694 pub generic_params: GenericParamsId, 619 pub generic_params: Interned<GenericParams>,
695 pub target_trait: Option<Idx<TypeRef>>, 620 pub target_trait: Option<Interned<TraitRef>>,
696 pub target_type: Idx<TypeRef>, 621 pub self_ty: Interned<TypeRef>,
697 pub is_negative: bool, 622 pub is_negative: bool,
698 pub items: Box<[AssocItem]>, 623 pub items: Box<[AssocItem]>,
699 pub ast_id: FileAstId<ast::Impl>, 624 pub ast_id: FileAstId<ast::Impl>,
@@ -705,8 +630,8 @@ pub struct TypeAlias {
705 pub visibility: RawVisibilityId, 630 pub visibility: RawVisibilityId,
706 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`. 631 /// Bounds on the type alias itself. Only valid in trait declarations, eg. `type Assoc: Copy;`.
707 pub bounds: Box<[TypeBound]>, 632 pub bounds: Box<[TypeBound]>,
708 pub generic_params: GenericParamsId, 633 pub generic_params: Interned<GenericParams>,
709 pub type_ref: Option<Idx<TypeRef>>, 634 pub type_ref: Option<Interned<TypeRef>>,
710 pub is_extern: bool, 635 pub is_extern: bool,
711 pub ast_id: FileAstId<ast::TypeAlias>, 636 pub ast_id: FileAstId<ast::TypeAlias>,
712} 637}
@@ -731,7 +656,7 @@ pub enum ModKind {
731#[derive(Debug, Clone, Eq, PartialEq)] 656#[derive(Debug, Clone, Eq, PartialEq)]
732pub struct MacroCall { 657pub struct MacroCall {
733 /// Path to the called macro. 658 /// Path to the called macro.
734 pub path: ModPath, 659 pub path: Interned<ModPath>,
735 pub ast_id: FileAstId<ast::MacroCall>, 660 pub ast_id: FileAstId<ast::MacroCall>,
736} 661}
737 662
@@ -896,6 +821,6 @@ pub enum Fields {
896#[derive(Debug, Clone, PartialEq, Eq)] 821#[derive(Debug, Clone, PartialEq, Eq)]
897pub struct Field { 822pub struct Field {
898 pub name: Name, 823 pub name: Name,
899 pub type_ref: Idx<TypeRef>, 824 pub type_ref: Interned<TypeRef>,
900 pub visibility: RawVisibilityId, 825 pub visibility: RawVisibilityId,
901} 826}
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 3f558edd8..45b099cf3 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -11,7 +11,7 @@ use syntax::{
11 11
12use crate::{ 12use crate::{
13 generics::{GenericParams, TypeParamData, TypeParamProvenance}, 13 generics::{GenericParams, TypeParamData, TypeParamProvenance},
14 type_ref::LifetimeRef, 14 type_ref::{LifetimeRef, TraitRef},
15}; 15};
16 16
17use super::*; 17use super::*;
@@ -174,6 +174,12 @@ impl Ctx {
174 let forced_vis = self.forced_visibility.take(); 174 let forced_vis = self.forced_visibility.take();
175 175
176 let mut block_stack = Vec::new(); 176 let mut block_stack = Vec::new();
177
178 // if container itself is block, add it to the stack
179 if let Some(block) = ast::BlockExpr::cast(container.clone()) {
180 block_stack.push(self.source_ast_id_map.ast_id(&block));
181 }
182
177 for event in container.preorder().skip(1) { 183 for event in container.preorder().skip(1) {
178 match event { 184 match event {
179 WalkEvent::Enter(node) => { 185 WalkEvent::Enter(node) => {
@@ -183,7 +189,7 @@ impl Ctx {
183 block_stack.push(self.source_ast_id_map.ast_id(&block)); 189 block_stack.push(self.source_ast_id_map.ast_id(&block));
184 }, 190 },
185 ast::Item(item) => { 191 ast::Item(item) => {
186 // FIXME: This triggers for macro calls in expression position 192 // FIXME: This triggers for macro calls in expression/pattern/type position
187 let mod_items = self.lower_mod_item(&item, true); 193 let mod_items = self.lower_mod_item(&item, true);
188 let current_block = block_stack.last(); 194 let current_block = block_stack.last();
189 if let (Some(mod_items), Some(block)) = (mod_items, current_block) { 195 if let (Some(mod_items), Some(block)) = (mod_items, current_block) {
@@ -356,7 +362,7 @@ impl Ctx {
356 } 362 }
357 } 363 }
358 }; 364 };
359 let ty = self.data().type_refs.intern(self_type); 365 let ty = Interned::new(self_type);
360 let idx = self.data().params.alloc(Param::Normal(ty)); 366 let idx = self.data().params.alloc(Param::Normal(ty));
361 self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene)); 367 self.add_attrs(idx.into(), RawAttrs::new(&self_param, &self.hygiene));
362 has_self_param = true; 368 has_self_param = true;
@@ -366,7 +372,7 @@ impl Ctx {
366 Some(_) => self.data().params.alloc(Param::Varargs), 372 Some(_) => self.data().params.alloc(Param::Varargs),
367 None => { 373 None => {
368 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty()); 374 let type_ref = TypeRef::from_ast_opt(&self.body_ctx, param.ty());
369 let ty = self.data().type_refs.intern(type_ref); 375 let ty = Interned::new(type_ref);
370 self.data().params.alloc(Param::Normal(ty)) 376 self.data().params.alloc(Param::Normal(ty))
371 } 377 }
372 }; 378 };
@@ -389,41 +395,51 @@ impl Ctx {
389 ret_type 395 ret_type
390 }; 396 };
391 397
392 let ret_type = self.data().type_refs.intern(ret_type); 398 let abi = func.abi().map(|abi| {
393 399 // FIXME: Abi::abi() -> Option<SyntaxToken>?
394 let has_body = func.body().is_some(); 400 match abi.syntax().last_token() {
401 Some(tok) if tok.kind() == SyntaxKind::STRING => {
402 // FIXME: Better way to unescape?
403 Interned::new_str(tok.text().trim_matches('"'))
404 }
405 _ => {
406 // `extern` default to be `extern "C"`.
407 Interned::new_str("C")
408 }
409 }
410 });
395 411
396 let ast_id = self.source_ast_id_map.ast_id(func); 412 let ast_id = self.source_ast_id_map.ast_id(func);
397 let qualifier = FunctionQualifier { 413
398 is_default: func.default_token().is_some(), 414 let mut flags = FnFlags::default();
399 is_const: func.const_token().is_some(), 415 if func.body().is_some() {
400 is_async: func.async_token().is_some(), 416 flags.bits |= FnFlags::HAS_BODY;
401 is_unsafe: func.unsafe_token().is_some(), 417 }
402 abi: func.abi().map(|abi| { 418 if has_self_param {
403 // FIXME: Abi::abi() -> Option<SyntaxToken>? 419 flags.bits |= FnFlags::HAS_SELF_PARAM;
404 match abi.syntax().last_token() { 420 }
405 Some(tok) if tok.kind() == SyntaxKind::STRING => { 421 if func.default_token().is_some() {
406 // FIXME: Better way to unescape? 422 flags.bits |= FnFlags::IS_DEFAULT;
407 tok.text().trim_matches('"').into() 423 }
408 } 424 if func.const_token().is_some() {
409 _ => { 425 flags.bits |= FnFlags::IS_CONST;
410 // `extern` default to be `extern "C"`. 426 }
411 "C".into() 427 if func.async_token().is_some() {
412 } 428 flags.bits |= FnFlags::IS_ASYNC;
413 } 429 }
414 }), 430 if func.unsafe_token().is_some() {
415 }; 431 flags.bits |= FnFlags::IS_UNSAFE;
432 }
433
416 let mut res = Function { 434 let mut res = Function {
417 name, 435 name,
418 visibility, 436 visibility,
419 generic_params: GenericParamsId::EMPTY, 437 generic_params: Interned::new(GenericParams::default()),
420 has_self_param, 438 abi,
421 has_body,
422 qualifier,
423 is_in_extern_block: false,
424 params, 439 params,
425 ret_type, 440 ret_type: Interned::new(ret_type),
426 ast_id, 441 ast_id,
442 flags,
427 }; 443 };
428 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func); 444 res.generic_params = self.lower_generic_params(GenericsOwner::Function(&res), func);
429 445
@@ -536,8 +552,11 @@ impl Ctx {
536 fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> { 552 fn lower_impl(&mut self, impl_def: &ast::Impl) -> Option<FileItemTreeId<Impl>> {
537 let generic_params = 553 let generic_params =
538 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def); 554 self.lower_generic_params_and_inner_items(GenericsOwner::Impl, impl_def);
539 let target_trait = impl_def.trait_().map(|tr| self.lower_type_ref(&tr)); 555 // FIXME: If trait lowering fails, due to a non PathType for example, we treat this impl
540 let target_type = self.lower_type_ref(&impl_def.self_ty()?); 556 // as if it was an non-trait impl. Ideally we want to create a unique missing ref that only
557 // equals itself.
558 let target_trait = impl_def.trait_().and_then(|tr| self.lower_trait_ref(&tr));
559 let self_ty = self.lower_type_ref(&impl_def.self_ty()?);
541 let is_negative = impl_def.excl_token().is_some(); 560 let is_negative = impl_def.excl_token().is_some();
542 561
543 // We cannot use `assoc_items()` here as that does not include macro calls. 562 // We cannot use `assoc_items()` here as that does not include macro calls.
@@ -554,7 +573,7 @@ impl Ctx {
554 }) 573 })
555 .collect(); 574 .collect();
556 let ast_id = self.source_ast_id_map.ast_id(impl_def); 575 let ast_id = self.source_ast_id_map.ast_id(impl_def);
557 let res = Impl { generic_params, target_trait, target_type, is_negative, items, ast_id }; 576 let res = Impl { generic_params, target_trait, self_ty, is_negative, items, ast_id };
558 Some(id(self.data().impls.alloc(res))) 577 Some(id(self.data().impls.alloc(res)))
559 } 578 }
560 579
@@ -570,7 +589,7 @@ impl Ctx {
570 &self.hygiene, 589 &self.hygiene,
571 |path, _use_tree, is_glob, alias| { 590 |path, _use_tree, is_glob, alias| {
572 imports.push(id(tree.imports.alloc(Import { 591 imports.push(id(tree.imports.alloc(Import {
573 path, 592 path: Interned::new(path),
574 alias, 593 alias,
575 visibility, 594 visibility,
576 is_glob, 595 is_glob,
@@ -599,7 +618,7 @@ impl Ctx {
599 } 618 }
600 619
601 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> { 620 fn lower_macro_call(&mut self, m: &ast::MacroCall) -> Option<FileItemTreeId<MacroCall>> {
602 let path = ModPath::from_src(m.path()?, &self.hygiene)?; 621 let path = Interned::new(ModPath::from_src(m.path()?, &self.hygiene)?);
603 let ast_id = self.source_ast_id_map.ast_id(m); 622 let ast_id = self.source_ast_id_map.ast_id(m);
604 let res = MacroCall { path, ast_id }; 623 let res = MacroCall { path, ast_id };
605 Some(id(self.data().macro_calls.alloc(res))) 624 Some(id(self.data().macro_calls.alloc(res)))
@@ -633,8 +652,10 @@ impl Ctx {
633 ast::ExternItem::Fn(ast) => { 652 ast::ExternItem::Fn(ast) => {
634 let func_id = self.lower_function(&ast)?; 653 let func_id = self.lower_function(&ast)?;
635 let func = &mut self.data().functions[func_id.index]; 654 let func = &mut self.data().functions[func_id.index];
636 func.qualifier.is_unsafe = is_intrinsic_fn_unsafe(&func.name); 655 if is_intrinsic_fn_unsafe(&func.name) {
637 func.is_in_extern_block = true; 656 func.flags.bits |= FnFlags::IS_UNSAFE;
657 }
658 func.flags.bits |= FnFlags::IS_IN_EXTERN_BLOCK;
638 func_id.into() 659 func_id.into()
639 } 660 }
640 ast::ExternItem::Static(ast) => { 661 ast::ExternItem::Static(ast) => {
@@ -661,7 +682,7 @@ impl Ctx {
661 &mut self, 682 &mut self,
662 owner: GenericsOwner<'_>, 683 owner: GenericsOwner<'_>,
663 node: &impl ast::GenericParamsOwner, 684 node: &impl ast::GenericParamsOwner,
664 ) -> GenericParamsId { 685 ) -> Interned<GenericParams> {
665 // 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.
666 if let Some(params) = node.generic_param_list() { 687 if let Some(params) = node.generic_param_list() {
667 self.collect_inner_items(params.syntax()); 688 self.collect_inner_items(params.syntax());
@@ -677,7 +698,7 @@ impl Ctx {
677 &mut self, 698 &mut self,
678 owner: GenericsOwner<'_>, 699 owner: GenericsOwner<'_>,
679 node: &impl ast::GenericParamsOwner, 700 node: &impl ast::GenericParamsOwner,
680 ) -> GenericParamsId { 701 ) -> Interned<GenericParams> {
681 let mut sm = &mut Default::default(); 702 let mut sm = &mut Default::default();
682 let mut generics = GenericParams::default(); 703 let mut generics = GenericParams::default();
683 match owner { 704 match owner {
@@ -685,8 +706,7 @@ impl Ctx {
685 generics.fill(&self.body_ctx, sm, node); 706 generics.fill(&self.body_ctx, sm, node);
686 // lower `impl Trait` in arguments 707 // lower `impl Trait` in arguments
687 for id in func.params.clone() { 708 for id in func.params.clone() {
688 if let Param::Normal(ty) = self.data().params[id] { 709 if let Param::Normal(ty) = &self.data().params[id] {
689 let ty = self.data().type_refs.lookup(ty);
690 generics.fill_implicit_impl_trait_args(ty); 710 generics.fill_implicit_impl_trait_args(ty);
691 } 711 }
692 } 712 }
@@ -719,7 +739,8 @@ impl Ctx {
719 } 739 }
720 } 740 }
721 741
722 self.data().generics.alloc(generics) 742 generics.shrink_to_fit();
743 Interned::new(generics)
723 } 744 }
724 745
725 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> {
@@ -740,14 +761,20 @@ impl Ctx {
740 self.data().vis.alloc(vis) 761 self.data().vis.alloc(vis)
741 } 762 }
742 763
743 fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Idx<TypeRef> { 764 fn lower_trait_ref(&mut self, trait_ref: &ast::Type) -> Option<Interned<TraitRef>> {
765 let trait_ref = TraitRef::from_ast(&self.body_ctx, trait_ref.clone())?;
766 Some(Interned::new(trait_ref))
767 }
768
769 fn lower_type_ref(&mut self, type_ref: &ast::Type) -> Interned<TypeRef> {
744 let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone()); 770 let tyref = TypeRef::from_ast(&self.body_ctx, type_ref.clone());
745 self.data().type_refs.intern(tyref) 771 Interned::new(tyref)
746 } 772 }
747 fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Idx<TypeRef> { 773
774 fn lower_type_ref_opt(&mut self, type_ref: Option<ast::Type>) -> Interned<TypeRef> {
748 match type_ref.map(|ty| self.lower_type_ref(&ty)) { 775 match type_ref.map(|ty| self.lower_type_ref(&ty)) {
749 Some(it) => it, 776 Some(it) => it,
750 None => self.data().type_refs.intern(TypeRef::Error), 777 None => Interned::new(TypeRef::Error),
751 } 778 }
752 } 779 }
753 780
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index c9e07de86..000567d99 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;
@@ -55,15 +56,17 @@ use std::{
55 sync::Arc, 56 sync::Arc,
56}; 57};
57 58
59use adt::VariantData;
58use base_db::{impl_intern_key, salsa, CrateId}; 60use base_db::{impl_intern_key, salsa, CrateId};
59use hir_expand::{ 61use hir_expand::{
60 ast_id_map::FileAstId, 62 ast_id_map::FileAstId,
61 eager::{expand_eager_macro, ErrorEmitted, ErrorSink}, 63 eager::{expand_eager_macro, ErrorEmitted, ErrorSink},
62 hygiene::Hygiene, 64 hygiene::Hygiene,
63 AstId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, 65 AstId, AttrId, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
64}; 66};
65use la_arena::Idx; 67use la_arena::Idx;
66use nameres::DefMap; 68use nameres::DefMap;
69use path::ModPath;
67use syntax::ast; 70use syntax::ast;
68 71
69use crate::builtin_type::BuiltinType; 72use crate::builtin_type::BuiltinType;
@@ -433,6 +436,16 @@ impl_from!(
433 for AttrDefId 436 for AttrDefId
434); 437);
435 438
439impl From<AssocContainerId> for AttrDefId {
440 fn from(acid: AssocContainerId) -> Self {
441 match acid {
442 AssocContainerId::ModuleId(mid) => AttrDefId::ModuleId(mid),
443 AssocContainerId::ImplId(iid) => AttrDefId::ImplId(iid),
444 AssocContainerId::TraitId(tid) => AttrDefId::TraitId(tid),
445 }
446 }
447}
448
436#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] 449#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
437pub enum VariantId { 450pub enum VariantId {
438 EnumVariantId(EnumVariantId), 451 EnumVariantId(EnumVariantId),
@@ -441,6 +454,26 @@ pub enum VariantId {
441} 454}
442impl_from!(EnumVariantId, StructId, UnionId for VariantId); 455impl_from!(EnumVariantId, StructId, UnionId for VariantId);
443 456
457impl VariantId {
458 pub fn variant_data(self, db: &dyn db::DefDatabase) -> Arc<VariantData> {
459 match self {
460 VariantId::StructId(it) => db.struct_data(it).variant_data.clone(),
461 VariantId::UnionId(it) => db.union_data(it).variant_data.clone(),
462 VariantId::EnumVariantId(it) => {
463 db.enum_data(it.parent).variants[it.local_id].variant_data.clone()
464 }
465 }
466 }
467
468 pub fn file_id(self, db: &dyn db::DefDatabase) -> HirFileId {
469 match self {
470 VariantId::EnumVariantId(it) => it.parent.lookup(db).id.file_id(),
471 VariantId::StructId(it) => it.lookup(db).id.file_id(),
472 VariantId::UnionId(it) => it.lookup(db).id.file_id(),
473 }
474 }
475}
476
444trait Intern { 477trait Intern {
445 type ID; 478 type ID;
446 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID; 479 fn intern(self, db: &dyn db::DefDatabase) -> Self::ID;
@@ -643,7 +676,9 @@ impl<T: ast::AstNode> AstIdWithPath<T> {
643 } 676 }
644} 677}
645 678
646pub struct UnresolvedMacro; 679pub struct UnresolvedMacro {
680 pub path: ModPath,
681}
647 682
648fn macro_call_as_call_id( 683fn macro_call_as_call_id(
649 call: &AstIdWithPath<ast::MacroCall>, 684 call: &AstIdWithPath<ast::MacroCall>,
@@ -652,7 +687,8 @@ fn macro_call_as_call_id(
652 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 687 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
653 error_sink: &mut dyn FnMut(mbe::ExpandError), 688 error_sink: &mut dyn FnMut(mbe::ExpandError),
654) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> { 689) -> Result<Result<MacroCallId, ErrorEmitted>, UnresolvedMacro> {
655 let def: MacroDefId = resolver(call.path.clone()).ok_or(UnresolvedMacro)?; 690 let def: MacroDefId =
691 resolver(call.path.clone()).ok_or_else(|| UnresolvedMacro { path: call.path.clone() })?;
656 692
657 let res = if let MacroDefKind::BuiltInEager(..) = def.kind { 693 let res = if let MacroDefKind::BuiltInEager(..) = def.kind {
658 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast())); 694 let macro_call = InFile::new(call.ast_id.file_id, call.ast_id.to_node(db.upcast()));
@@ -668,24 +704,36 @@ fn macro_call_as_call_id(
668 ) 704 )
669 .map(MacroCallId::from) 705 .map(MacroCallId::from)
670 } else { 706 } else {
671 Ok(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(call.ast_id)).into()) 707 Ok(def
708 .as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike { ast_id: call.ast_id })
709 .into())
672 }; 710 };
673 Ok(res) 711 Ok(res)
674} 712}
675 713
676fn derive_macro_as_call_id( 714fn derive_macro_as_call_id(
677 item_attr: &AstIdWithPath<ast::Item>, 715 item_attr: &AstIdWithPath<ast::Item>,
716 derive_attr: AttrId,
678 db: &dyn db::DefDatabase, 717 db: &dyn db::DefDatabase,
679 krate: CrateId, 718 krate: CrateId,
680 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, 719 resolver: impl Fn(path::ModPath) -> Option<MacroDefId>,
681) -> Result<MacroCallId, UnresolvedMacro> { 720) -> Result<MacroCallId, UnresolvedMacro> {
682 let def: MacroDefId = resolver(item_attr.path.clone()).ok_or(UnresolvedMacro)?; 721 let def: MacroDefId = resolver(item_attr.path.clone())
683 let last_segment = item_attr.path.segments().last().ok_or(UnresolvedMacro)?; 722 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
723 let last_segment = item_attr
724 .path
725 .segments()
726 .last()
727 .ok_or_else(|| UnresolvedMacro { path: item_attr.path.clone() })?;
684 let res = def 728 let res = def
685 .as_lazy_macro( 729 .as_lazy_macro(
686 db.upcast(), 730 db.upcast(),
687 krate, 731 krate,
688 MacroCallKind::Derive(item_attr.ast_id, last_segment.to_string()), 732 MacroCallKind::Derive {
733 ast_id: item_attr.ast_id,
734 derive_name: last_segment.to_string(),
735 derive_attr,
736 },
689 ) 737 )
690 .into(); 738 .into();
691 Ok(res) 739 Ok(res)
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 9e8e4e9ec..542f190a1 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -409,6 +409,31 @@ impl DefMap {
409 } 409 }
410 } 410 }
411 } 411 }
412
413 fn shrink_to_fit(&mut self) {
414 // Exhaustive match to require handling new fields.
415 let Self {
416 _c: _,
417 exported_proc_macros,
418 extern_prelude,
419 diagnostics,
420 modules,
421 block: _,
422 edition: _,
423 krate: _,
424 prelude: _,
425 root: _,
426 } = self;
427
428 extern_prelude.shrink_to_fit();
429 exported_proc_macros.shrink_to_fit();
430 diagnostics.shrink_to_fit();
431 modules.shrink_to_fit();
432 for (_, module) in modules.iter_mut() {
433 module.children.shrink_to_fit();
434 module.scope.shrink_to_fit();
435 }
436 }
412} 437}
413 438
414impl ModuleData { 439impl ModuleData {
@@ -456,7 +481,7 @@ mod diagnostics {
456 481
457 UnresolvedProcMacro { ast: MacroCallKind }, 482 UnresolvedProcMacro { ast: MacroCallKind },
458 483
459 UnresolvedMacroCall { ast: AstId<ast::MacroCall> }, 484 UnresolvedMacroCall { ast: AstId<ast::MacroCall>, path: ModPath },
460 485
461 MacroError { ast: MacroCallKind, message: String }, 486 MacroError { ast: MacroCallKind, message: String },
462 } 487 }
@@ -521,8 +546,9 @@ mod diagnostics {
521 pub(super) fn unresolved_macro_call( 546 pub(super) fn unresolved_macro_call(
522 container: LocalModuleId, 547 container: LocalModuleId,
523 ast: AstId<ast::MacroCall>, 548 ast: AstId<ast::MacroCall>,
549 path: ModPath,
524 ) -> Self { 550 ) -> Self {
525 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast } } 551 Self { in_module: container, kind: DiagnosticKind::UnresolvedMacroCall { ast, path } }
526 } 552 }
527 553
528 pub(super) fn add_to( 554 pub(super) fn add_to(
@@ -588,12 +614,12 @@ mod diagnostics {
588 DiagnosticKind::UnresolvedProcMacro { ast } => { 614 DiagnosticKind::UnresolvedProcMacro { ast } => {
589 let mut precise_location = None; 615 let mut precise_location = None;
590 let (file, ast, name) = match ast { 616 let (file, ast, name) = match ast {
591 MacroCallKind::FnLike(ast) => { 617 MacroCallKind::FnLike { ast_id } => {
592 let node = ast.to_node(db.upcast()); 618 let node = ast_id.to_node(db.upcast());
593 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None) 619 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)), None)
594 } 620 }
595 MacroCallKind::Derive(ast, name) => { 621 MacroCallKind::Derive { ast_id, derive_name, .. } => {
596 let node = ast.to_node(db.upcast()); 622 let node = ast_id.to_node(db.upcast());
597 623
598 // Compute the precise location of the macro name's token in the derive 624 // Compute the precise location of the macro name's token in the derive
599 // list. 625 // list.
@@ -614,7 +640,7 @@ mod diagnostics {
614 }); 640 });
615 for token in tokens { 641 for token in tokens {
616 if token.kind() == SyntaxKind::IDENT 642 if token.kind() == SyntaxKind::IDENT
617 && token.text() == name.as_str() 643 && token.text() == derive_name.as_str()
618 { 644 {
619 precise_location = Some(token.text_range()); 645 precise_location = Some(token.text_range());
620 break 'outer; 646 break 'outer;
@@ -623,9 +649,9 @@ mod diagnostics {
623 } 649 }
624 650
625 ( 651 (
626 ast.file_id, 652 ast_id.file_id,
627 SyntaxNodePtr::from(AstPtr::new(&node)), 653 SyntaxNodePtr::from(AstPtr::new(&node)),
628 Some(name.clone()), 654 Some(derive_name.clone()),
629 ) 655 )
630 } 656 }
631 }; 657 };
@@ -637,20 +663,24 @@ mod diagnostics {
637 }); 663 });
638 } 664 }
639 665
640 DiagnosticKind::UnresolvedMacroCall { ast } => { 666 DiagnosticKind::UnresolvedMacroCall { ast, path } => {
641 let node = ast.to_node(db.upcast()); 667 let node = ast.to_node(db.upcast());
642 sink.push(UnresolvedMacroCall { file: ast.file_id, node: AstPtr::new(&node) }); 668 sink.push(UnresolvedMacroCall {
669 file: ast.file_id,
670 node: AstPtr::new(&node),
671 path: path.clone(),
672 });
643 } 673 }
644 674
645 DiagnosticKind::MacroError { ast, message } => { 675 DiagnosticKind::MacroError { ast, message } => {
646 let (file, ast) = match ast { 676 let (file, ast) = match ast {
647 MacroCallKind::FnLike(ast) => { 677 MacroCallKind::FnLike { ast_id, .. } => {
648 let node = ast.to_node(db.upcast()); 678 let node = ast_id.to_node(db.upcast());
649 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 679 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
650 } 680 }
651 MacroCallKind::Derive(ast, _) => { 681 MacroCallKind::Derive { ast_id, .. } => {
652 let node = ast.to_node(db.upcast()); 682 let node = ast_id.to_node(db.upcast());
653 (ast.file_id, SyntaxNodePtr::from(AstPtr::new(&node))) 683 (ast_id.file_id, SyntaxNodePtr::from(AstPtr::new(&node)))
654 } 684 }
655 }; 685 };
656 sink.push(MacroError { file, node: ast, message: message.clone() }); 686 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 d58135ec9..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};
@@ -23,6 +23,7 @@ use crate::{
23 attr::Attrs, 23 attr::Attrs,
24 db::DefDatabase, 24 db::DefDatabase,
25 derive_macro_as_call_id, 25 derive_macro_as_call_id,
26 intern::Interned,
26 item_scope::{ImportType, PerNsGlobImports}, 27 item_scope::{ImportType, PerNsGlobImports},
27 item_tree::{ 28 item_tree::{
28 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem, 29 self, FileItemTreeId, ItemTree, ItemTreeId, MacroCall, MacroDef, MacroRules, Mod, ModItem,
@@ -54,20 +55,22 @@ pub(super) fn collect_defs(
54) -> DefMap { 55) -> DefMap {
55 let crate_graph = db.crate_graph(); 56 let crate_graph = db.crate_graph();
56 57
57 // populate external prelude 58 if block.is_none() {
58 for dep in &crate_graph[def_map.krate].dependencies { 59 // populate external prelude
59 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id); 60 for dep in &crate_graph[def_map.krate].dependencies {
60 let dep_def_map = db.crate_def_map(dep.crate_id); 61 log::debug!("crate dep {:?} -> {:?}", dep.name, dep.crate_id);
61 def_map 62 let dep_def_map = db.crate_def_map(dep.crate_id);
62 .extern_prelude 63 def_map
63 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into()); 64 .extern_prelude
64 65 .insert(dep.as_name(), dep_def_map.module_id(dep_def_map.root).into());
65 // look for the prelude 66
66 // If the dependency defines a prelude, we overwrite an already defined 67 // look for the prelude
67 // prelude. This is necessary to import the "std" prelude if a crate 68 // If the dependency defines a prelude, we overwrite an already defined
68 // depends on both "core" and "std". 69 // prelude. This is necessary to import the "std" prelude if a crate
69 if dep_def_map.prelude.is_some() { 70 // depends on both "core" and "std".
70 def_map.prelude = dep_def_map.prelude; 71 if dep_def_map.prelude.is_some() {
72 def_map.prelude = dep_def_map.prelude;
73 }
71 } 74 }
72 } 75 }
73 76
@@ -106,7 +109,9 @@ pub(super) fn collect_defs(
106 } 109 }
107 } 110 }
108 collector.collect(); 111 collector.collect();
109 collector.finish() 112 let mut def_map = collector.finish();
113 def_map.shrink_to_fit();
114 def_map
110} 115}
111 116
112#[derive(Copy, Clone, Debug, Eq, PartialEq)] 117#[derive(Copy, Clone, Debug, Eq, PartialEq)]
@@ -137,7 +142,7 @@ enum ImportSource {
137 142
138#[derive(Clone, Debug, Eq, PartialEq)] 143#[derive(Clone, Debug, Eq, PartialEq)]
139struct Import { 144struct Import {
140 path: ModPath, 145 path: Interned<ModPath>,
141 alias: Option<ImportAlias>, 146 alias: Option<ImportAlias>,
142 visibility: RawVisibility, 147 visibility: RawVisibility,
143 is_glob: bool, 148 is_glob: bool,
@@ -179,7 +184,10 @@ impl Import {
179 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into()); 184 let attrs = &tree.attrs(db, krate, ModItem::from(id.value).into());
180 let visibility = &tree[it.visibility]; 185 let visibility = &tree[it.visibility];
181 Self { 186 Self {
182 path: ModPath::from_segments(PathKind::Plain, iter::once(it.name.clone())), 187 path: Interned::new(ModPath::from_segments(
188 PathKind::Plain,
189 iter::once(it.name.clone()),
190 )),
183 alias: it.alias.clone(), 191 alias: it.alias.clone(),
184 visibility: visibility.clone(), 192 visibility: visibility.clone(),
185 is_glob: false, 193 is_glob: false,
@@ -207,8 +215,8 @@ struct MacroDirective {
207 215
208#[derive(Clone, Debug, Eq, PartialEq)] 216#[derive(Clone, Debug, Eq, PartialEq)]
209enum MacroDirectiveKind { 217enum MacroDirectiveKind {
210 FnLike { ast_id: AstIdWithPath<ast::MacroCall>, legacy: Option<MacroCallId> }, 218 FnLike { ast_id: AstIdWithPath<ast::MacroCall> },
211 Derive { ast_id: AstIdWithPath<ast::Item> }, 219 Derive { ast_id: AstIdWithPath<ast::Item>, derive_attr: AttrId },
212} 220}
213 221
214struct DefData<'a> { 222struct DefData<'a> {
@@ -470,7 +478,7 @@ impl DefCollector<'_> {
470 self.def_map.edition, 478 self.def_map.edition,
471 ); 479 );
472 480
473 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);
474 482
475 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() { 483 if let Some(ModuleDefId::ModuleId(m)) = res.take_types() {
476 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);
@@ -526,6 +534,7 @@ impl DefCollector<'_> {
526 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition); 534 log::debug!("resolving import: {:?} ({:?})", import, self.def_map.edition);
527 if import.is_extern_crate { 535 if import.is_extern_crate {
528 let res = self.def_map.resolve_name_in_extern_prelude( 536 let res = self.def_map.resolve_name_in_extern_prelude(
537 self.db,
529 &import 538 &import
530 .path 539 .path
531 .as_ident() 540 .as_ident()
@@ -798,13 +807,7 @@ impl DefCollector<'_> {
798 let mut res = ReachedFixedPoint::Yes; 807 let mut res = ReachedFixedPoint::Yes;
799 macros.retain(|directive| { 808 macros.retain(|directive| {
800 match &directive.kind { 809 match &directive.kind {
801 MacroDirectiveKind::FnLike { ast_id, legacy } => { 810 MacroDirectiveKind::FnLike { ast_id } => {
802 if let Some(call_id) = legacy {
803 res = ReachedFixedPoint::No;
804 resolved.push((directive.module_id, *call_id, directive.depth));
805 return false;
806 }
807
808 match macro_call_as_call_id( 811 match macro_call_as_call_id(
809 ast_id, 812 ast_id,
810 self.db, 813 self.db,
@@ -826,19 +829,23 @@ impl DefCollector<'_> {
826 res = ReachedFixedPoint::No; 829 res = ReachedFixedPoint::No;
827 return false; 830 return false;
828 } 831 }
829 Err(UnresolvedMacro) | Ok(Err(_)) => {} 832 Err(UnresolvedMacro { .. }) | Ok(Err(_)) => {}
830 } 833 }
831 } 834 }
832 MacroDirectiveKind::Derive { ast_id } => { 835 MacroDirectiveKind::Derive { ast_id, derive_attr } => {
833 match derive_macro_as_call_id(ast_id, self.db, self.def_map.krate, |path| { 836 match derive_macro_as_call_id(
834 self.resolve_derive_macro(directive.module_id, &path) 837 ast_id,
835 }) { 838 *derive_attr,
839 self.db,
840 self.def_map.krate,
841 |path| self.resolve_derive_macro(directive.module_id, &path),
842 ) {
836 Ok(call_id) => { 843 Ok(call_id) => {
837 resolved.push((directive.module_id, call_id, 0)); 844 resolved.push((directive.module_id, call_id, directive.depth));
838 res = ReachedFixedPoint::No; 845 res = ReachedFixedPoint::No;
839 return false; 846 return false;
840 } 847 }
841 Err(UnresolvedMacro) => (), 848 Err(UnresolvedMacro { .. }) => (),
842 } 849 }
843 } 850 }
844 } 851 }
@@ -936,10 +943,11 @@ impl DefCollector<'_> {
936 &mut |_| (), 943 &mut |_| (),
937 ) { 944 ) {
938 Ok(_) => (), 945 Ok(_) => (),
939 Err(UnresolvedMacro) => { 946 Err(UnresolvedMacro { path }) => {
940 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call( 947 self.def_map.diagnostics.push(DefDiagnostic::unresolved_macro_call(
941 directive.module_id, 948 directive.module_id,
942 ast_id.ast_id, 949 ast_id.ast_id,
950 path,
943 )); 951 ));
944 } 952 }
945 }, 953 },
@@ -1161,19 +1169,27 @@ impl ModCollector<'_, '_> {
1161 } 1169 }
1162 ModItem::Const(id) => { 1170 ModItem::Const(id) => {
1163 let it = &self.item_tree[id]; 1171 let it = &self.item_tree[id];
1164 1172 let const_id = ConstLoc {
1165 if let Some(name) = &it.name { 1173 container: module.into(),
1166 def = Some(DefData { 1174 id: ItemTreeId::new(self.file_id, id),
1167 id: ConstLoc { 1175 }
1168 container: module.into(), 1176 .intern(self.def_collector.db);
1169 id: ItemTreeId::new(self.file_id, id), 1177
1170 } 1178 match &it.name {
1171 .intern(self.def_collector.db) 1179 Some(name) => {
1172 .into(), 1180 def = Some(DefData {
1173 name, 1181 id: const_id.into(),
1174 visibility: &self.item_tree[it.visibility], 1182 name,
1175 has_constructor: false, 1183 visibility: &self.item_tree[it.visibility],
1176 }); 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 }
1177 } 1193 }
1178 } 1194 }
1179 ModItem::Static(id) => { 1195 ModItem::Static(id) => {
@@ -1358,7 +1374,7 @@ impl ModCollector<'_, '_> {
1358 self.def_collector.unexpanded_macros.push(MacroDirective { 1374 self.def_collector.unexpanded_macros.push(MacroDirective {
1359 module_id: self.module_id, 1375 module_id: self.module_id,
1360 depth: self.macro_depth + 1, 1376 depth: self.macro_depth + 1,
1361 kind: MacroDirectiveKind::Derive { ast_id }, 1377 kind: MacroDirectiveKind::Derive { ast_id, derive_attr: derive.id },
1362 }); 1378 });
1363 } 1379 }
1364 } 1380 }
@@ -1400,8 +1416,18 @@ impl ModCollector<'_, '_> {
1400 1416
1401 // Case 1: builtin macros 1417 // Case 1: builtin macros
1402 if attrs.by_key("rustc_builtin_macro").exists() { 1418 if attrs.by_key("rustc_builtin_macro").exists() {
1419 // `#[rustc_builtin_macro = "builtin_name"]` overrides the `macro_rules!` name.
1420 let name;
1421 let name = match attrs.by_key("rustc_builtin_macro").string_value() {
1422 Some(it) => {
1423 // FIXME: a hacky way to create a Name from string.
1424 name = tt::Ident { text: it.clone(), id: tt::TokenId::unspecified() }.as_name();
1425 &name
1426 }
1427 None => &mac.name,
1428 };
1403 let krate = self.def_collector.def_map.krate; 1429 let krate = self.def_collector.def_map.krate;
1404 if let Some(macro_id) = find_builtin_macro(&mac.name, krate, ast_id) { 1430 if let Some(macro_id) = find_builtin_macro(name, krate, ast_id) {
1405 self.def_collector.define_macro_rules( 1431 self.def_collector.define_macro_rules(
1406 self.module_id, 1432 self.module_id,
1407 mac.name.clone(), 1433 mac.name.clone(),
@@ -1464,7 +1490,7 @@ impl ModCollector<'_, '_> {
1464 } 1490 }
1465 1491
1466 fn collect_macro_call(&mut self, mac: &MacroCall) { 1492 fn collect_macro_call(&mut self, mac: &MacroCall) {
1467 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, mac.path.clone()); 1493 let mut ast_id = AstIdWithPath::new(self.file_id, mac.ast_id, (*mac.path).clone());
1468 1494
1469 // Case 1: try to resolve in legacy scope and expand macro_rules 1495 // Case 1: try to resolve in legacy scope and expand macro_rules
1470 let mut error = None; 1496 let mut error = None;
@@ -1500,12 +1526,12 @@ impl ModCollector<'_, '_> {
1500 // Built-in macro failed eager expansion. 1526 // Built-in macro failed eager expansion.
1501 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error( 1527 self.def_collector.def_map.diagnostics.push(DefDiagnostic::macro_error(
1502 self.module_id, 1528 self.module_id,
1503 MacroCallKind::FnLike(ast_id.ast_id), 1529 MacroCallKind::FnLike { ast_id: ast_id.ast_id },
1504 error.unwrap().to_string(), 1530 error.unwrap().to_string(),
1505 )); 1531 ));
1506 return; 1532 return;
1507 } 1533 }
1508 Err(UnresolvedMacro) => (), 1534 Err(UnresolvedMacro { .. }) => (),
1509 } 1535 }
1510 1536
1511 // Case 2: resolve in module scope, expand during name resolution. 1537 // Case 2: resolve in module scope, expand during name resolution.
@@ -1517,7 +1543,7 @@ impl ModCollector<'_, '_> {
1517 self.def_collector.unexpanded_macros.push(MacroDirective { 1543 self.def_collector.unexpanded_macros.push(MacroDirective {
1518 module_id: self.module_id, 1544 module_id: self.module_id,
1519 depth: self.macro_depth + 1, 1545 depth: self.macro_depth + 1,
1520 kind: MacroDirectiveKind::FnLike { ast_id, legacy: None }, 1546 kind: MacroDirectiveKind::FnLike { ast_id },
1521 }); 1547 });
1522 } 1548 }
1523 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 a89061c2e..543975e07 100644
--- a/crates/hir_def/src/nameres/tests/diagnostics.rs
+++ b/crates/hir_def/src/nameres/tests/diagnostics.rs
@@ -7,6 +7,11 @@ fn check_diagnostics(ra_fixture: &str) {
7 db.check_diagnostics(); 7 db.check_diagnostics();
8} 8}
9 9
10fn check_no_diagnostics(ra_fixture: &str) {
11 let db: TestDB = TestDB::with_files(ra_fixture);
12 db.check_no_diagnostics();
13}
14
10#[test] 15#[test]
11fn unresolved_import() { 16fn unresolved_import() {
12 check_diagnostics( 17 check_diagnostics(
@@ -165,7 +170,7 @@ fn unresolved_legacy_scope_macro() {
165 170
166 m!(); 171 m!();
167 m2!(); 172 m2!();
168 //^^^^^^ unresolved macro call 173 //^^^^^^ unresolved macro `self::m2!`
169 "#, 174 "#,
170 ); 175 );
171} 176}
@@ -182,7 +187,7 @@ fn unresolved_module_scope_macro() {
182 187
183 self::m!(); 188 self::m!();
184 self::m2!(); 189 self::m2!();
185 //^^^^^^^^^^^^ unresolved macro call 190 //^^^^^^^^^^^^ unresolved macro `self::m2!`
186 "#, 191 "#,
187 ); 192 );
188} 193}
@@ -202,6 +207,21 @@ fn builtin_macro_fails_expansion() {
202} 207}
203 208
204#[test] 209#[test]
210fn include_macro_should_allow_empty_content() {
211 check_no_diagnostics(
212 r#"
213 //- /lib.rs
214 #[rustc_builtin_macro]
215 macro_rules! include { () => {} }
216
217 include!("bar.rs");
218 //- /bar.rs
219 // empty
220 "#,
221 );
222}
223
224#[test]
205fn good_out_dir_diagnostic() { 225fn good_out_dir_diagnostic() {
206 check_diagnostics( 226 check_diagnostics(
207 r#" 227 r#"
@@ -213,7 +233,7 @@ fn good_out_dir_diagnostic() {
213 macro_rules! concat { () => {} } 233 macro_rules! concat { () => {} }
214 234
215 include!(concat!(env!("OUT_DIR"), "/out.rs")); 235 include!(concat!(env!("OUT_DIR"), "/out.rs"));
216 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "load out dirs from check" to fix 236 //^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `OUT_DIR` not set, enable "run build scripts" to fix
217 "#, 237 "#,
218 ); 238 );
219} 239}
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 8c923bb7b..b528ff8ba 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -7,7 +7,7 @@ use std::{
7 sync::Arc, 7 sync::Arc,
8}; 8};
9 9
10use crate::{body::LowerCtx, type_ref::LifetimeRef}; 10use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
11use base_db::CrateId; 11use base_db::CrateId;
12use hir_expand::{ 12use hir_expand::{
13 hygiene::Hygiene, 13 hygiene::Hygiene,
@@ -48,7 +48,7 @@ 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) 51 lower::lower_path(path, hygiene).map(|it| (*it.mod_path).clone())
52 } 52 }
53 53
54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath { 54 pub fn from_segments(kind: PathKind, segments: impl IntoIterator<Item = Name>) -> ModPath {
@@ -122,8 +122,8 @@ impl ModPath {
122pub struct Path { 122pub struct Path {
123 /// Type based path like `<T>::foo`. 123 /// Type based path like `<T>::foo`.
124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`. 124 /// Note that paths like `<Type as Trait>::foo` are desugard to `Trait::<Self=Type>::foo`.
125 type_anchor: Option<Box<TypeRef>>, 125 type_anchor: Option<Interned<TypeRef>>,
126 mod_path: ModPath, 126 mod_path: Interned<ModPath>,
127 /// Invariant: the same len as `self.mod_path.segments` 127 /// Invariant: the same len as `self.mod_path.segments`
128 generic_args: Vec<Option<Arc<GenericArgs>>>, 128 generic_args: Vec<Option<Arc<GenericArgs>>>,
129} 129}
@@ -176,7 +176,7 @@ impl Path {
176 path: ModPath, 176 path: ModPath,
177 generic_args: Vec<Option<Arc<GenericArgs>>>, 177 generic_args: Vec<Option<Arc<GenericArgs>>>,
178 ) -> Path { 178 ) -> Path {
179 Path { type_anchor: None, mod_path: path, generic_args } 179 Path { type_anchor: None, mod_path: Interned::new(path), generic_args }
180 } 180 }
181 181
182 pub fn kind(&self) -> &PathKind { 182 pub fn kind(&self) -> &PathKind {
@@ -204,10 +204,10 @@ impl Path {
204 } 204 }
205 let res = Path { 205 let res = Path {
206 type_anchor: self.type_anchor.clone(), 206 type_anchor: self.type_anchor.clone(),
207 mod_path: ModPath::from_segments( 207 mod_path: Interned::new(ModPath::from_segments(
208 self.mod_path.kind.clone(), 208 self.mod_path.kind.clone(),
209 self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(), 209 self.mod_path.segments[..self.mod_path.segments.len() - 1].iter().cloned(),
210 ), 210 )),
211 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(), 211 generic_args: self.generic_args[..self.generic_args.len() - 1].to_vec(),
212 }; 212 };
213 Some(res) 213 Some(res)
@@ -283,12 +283,18 @@ impl From<Name> for Path {
283 fn from(name: Name) -> Path { 283 fn from(name: Name) -> Path {
284 Path { 284 Path {
285 type_anchor: None, 285 type_anchor: None,
286 mod_path: ModPath::from_segments(PathKind::Plain, iter::once(name)), 286 mod_path: Interned::new(ModPath::from_segments(PathKind::Plain, iter::once(name))),
287 generic_args: vec![None], 287 generic_args: vec![None],
288 } 288 }
289 } 289 }
290} 290}
291 291
292impl From<Name> for Box<Path> {
293 fn from(name: Name) -> Box<Path> {
294 Box::new(Path::from(name))
295 }
296}
297
292impl From<Name> for ModPath { 298impl From<Name> for ModPath {
293 fn from(name: Name) -> ModPath { 299 fn from(name: Name) -> ModPath {
294 ModPath::from_segments(PathKind::Plain, iter::once(name)) 300 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 505493a74..7b29d9d4f 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -2,6 +2,7 @@
2 2
3mod lower_use; 3mod lower_use;
4 4
5use crate::intern::Interned;
5use std::sync::Arc; 6use std::sync::Arc;
6 7
7use either::Either; 8use either::Either;
@@ -68,15 +69,17 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
68 match trait_ref { 69 match trait_ref {
69 // <T>::foo 70 // <T>::foo
70 None => { 71 None => {
71 type_anchor = Some(Box::new(self_type)); 72 type_anchor = Some(Interned::new(self_type));
72 kind = PathKind::Plain; 73 kind = PathKind::Plain;
73 } 74 }
74 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo 75 // <T as Trait<A>>::Foo desugars to Trait<Self=T, A>::Foo
75 Some(trait_ref) => { 76 Some(trait_ref) => {
76 let path = Path::from_src(trait_ref.path()?, hygiene)?; 77 let path = Path::from_src(trait_ref.path()?, hygiene)?;
77 kind = path.mod_path.kind; 78 let mod_path = (*path.mod_path).clone();
79 let num_segments = path.mod_path.segments.len();
80 kind = mod_path.kind;
78 81
79 let mut prefix_segments = path.mod_path.segments; 82 let mut prefix_segments = mod_path.segments;
80 prefix_segments.reverse(); 83 prefix_segments.reverse();
81 segments.extend(prefix_segments); 84 segments.extend(prefix_segments);
82 85
@@ -85,7 +88,8 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
85 generic_args.extend(prefix_args); 88 generic_args.extend(prefix_args);
86 89
87 // Insert the type reference (T in the above example) as Self parameter for the trait 90 // Insert the type reference (T in the above example) as Self parameter for the trait
88 let last_segment = generic_args.last_mut()?; 91 let last_segment =
92 generic_args.iter_mut().rev().nth(num_segments.saturating_sub(1))?;
89 if last_segment.is_none() { 93 if last_segment.is_none() {
90 *last_segment = Some(Arc::new(GenericArgs::empty())); 94 *last_segment = Some(Arc::new(GenericArgs::empty()));
91 }; 95 };
@@ -138,7 +142,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path>
138 } 142 }
139 } 143 }
140 144
141 let mod_path = ModPath::from_segments(kind, segments); 145 let mod_path = Interned::new(ModPath::from_segments(kind, segments));
142 return Some(Path { type_anchor, mod_path, generic_args }); 146 return Some(Path { type_anchor, mod_path, generic_args });
143 147
144 fn qualifier(path: &ast::Path) -> Option<ast::Path> { 148 fn qualifier(path: &ast::Path) -> Option<ast::Path> {
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 10977761c..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;
@@ -265,4 +312,17 @@ impl TestDB {
265 312
266 assert_eq!(annotations, actual); 313 assert_eq!(annotations, actual);
267 } 314 }
315
316 pub(crate) fn check_no_diagnostics(&self) {
317 let db: &TestDB = self;
318 let annotations = db.extract_annotations();
319 assert!(annotations.is_empty());
320
321 let mut has_diagnostics = false;
322 db.diagnostics(|_| {
323 has_diagnostics = true;
324 });
325
326 assert!(!has_diagnostics);
327 }
268} 328}
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index 049b2e462..4c24aae94 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -51,6 +51,23 @@ impl Rawness {
51 } 51 }
52} 52}
53 53
54#[derive(Clone, PartialEq, Eq, Hash, Debug)]
55pub struct TraitRef {
56 pub path: Path,
57}
58
59impl TraitRef {
60 /// Converts an `ast::PathType` to a `hir::TraitRef`.
61 pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> {
62 // FIXME: Use `Path::from_src`
63 match node {
64 ast::Type::PathType(path) => {
65 path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
66 }
67 _ => None,
68 }
69 }
70}
54/// Compare ty::Ty 71/// Compare ty::Ty
55#[derive(Clone, PartialEq, Eq, Hash, Debug)] 72#[derive(Clone, PartialEq, Eq, Hash, Debug)]
56pub enum TypeRef { 73pub enum TypeRef {
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 7d00a37c4..9908cd926 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
@@ -217,6 +217,6 @@ pub(crate) fn field_visibilities_query(
217 217
218/// Resolve visibility of a function. 218/// Resolve visibility of a function.
219pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility { 219pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -> Visibility {
220 let resolver = ModuleDefId::from(def).module(db).unwrap().resolver(db); 220 let resolver = def.resolver(db);
221 db.function_data(def).visibility.resolve(db, &resolver) 221 db.function_data(def).visibility.resolve(db, &resolver)
222} 222}
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 4d52904b9..80365fc16 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -1,10 +1,10 @@
1//! Builtin macro 1//! Builtin macro
2use crate::{ 2use crate::{
3 db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, 3 db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId,
4 MacroDefId, MacroDefKind, TextSize, 4 MacroCallLoc, MacroDefId, MacroDefKind, TextSize,
5}; 5};
6 6
7use base_db::{AnchoredPath, FileId}; 7use base_db::{AnchoredPath, Edition, FileId};
8use cfg::CfgExpr; 8use cfg::CfgExpr;
9use either::Either; 9use either::Either;
10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult}; 10use mbe::{parse_exprs_with_sep, parse_to_token_tree, ExpandResult};
@@ -111,6 +111,8 @@ register_builtin! {
111 (llvm_asm, LlvmAsm) => asm_expand, 111 (llvm_asm, LlvmAsm) => asm_expand,
112 (asm, Asm) => asm_expand, 112 (asm, Asm) => asm_expand,
113 (cfg, Cfg) => cfg_expand, 113 (cfg, Cfg) => cfg_expand,
114 (core_panic, CorePanic) => panic_expand,
115 (std_panic, StdPanic) => panic_expand,
114 116
115 EAGER: 117 EAGER:
116 (compile_error, CompileError) => compile_error_expand, 118 (compile_error, CompileError) => compile_error_expand,
@@ -284,6 +286,25 @@ fn cfg_expand(
284 ExpandResult::ok(expanded) 286 ExpandResult::ok(expanded)
285} 287}
286 288
289fn panic_expand(
290 db: &dyn AstDatabase,
291 id: LazyMacroId,
292 tt: &tt::Subtree,
293) -> ExpandResult<tt::Subtree> {
294 let loc: MacroCallLoc = db.lookup_intern_macro(id);
295 // Expand to a macro call `$crate::panic::panic_{edition}`
296 let krate = tt::Ident { text: "$crate".into(), id: tt::TokenId::unspecified() };
297 let mut call = if db.crate_graph()[loc.krate].edition == Edition::Edition2021 {
298 quote!(#krate::panic::panic_2021!)
299 } else {
300 quote!(#krate::panic::panic_2015!)
301 };
302
303 // Pass the original arguments
304 call.token_trees.push(tt::TokenTree::Subtree(tt.clone()));
305 ExpandResult::ok(call)
306}
307
287fn unquote_str(lit: &tt::Literal) -> Option<String> { 308fn unquote_str(lit: &tt::Literal) -> Option<String> {
288 let lit = ast::make::tokens::literal(&lit.to_string()); 309 let lit = ast::make::tokens::literal(&lit.to_string());
289 let token = ast::String::cast(lit)?; 310 let token = ast::String::cast(lit)?;
@@ -469,7 +490,7 @@ fn env_expand(
469 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`. 490 // unnecessary diagnostics for eg. `CARGO_PKG_NAME`.
470 if key == "OUT_DIR" { 491 if key == "OUT_DIR" {
471 err = Some(mbe::ExpandError::Other( 492 err = Some(mbe::ExpandError::Other(
472 r#"`OUT_DIR` not set, enable "load out dirs from check" to fix"#.into(), 493 r#"`OUT_DIR` not set, enable "run build scripts" to fix"#.into(),
473 )); 494 ));
474 } 495 }
475 496
@@ -545,10 +566,9 @@ mod tests {
545 let loc = MacroCallLoc { 566 let loc = MacroCallLoc {
546 def, 567 def,
547 krate, 568 krate,
548 kind: MacroCallKind::FnLike(AstId::new( 569 kind: MacroCallKind::FnLike {
549 file_id.into(), 570 ast_id: AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)),
550 ast_id_map.ast_id(&macro_call), 571 },
551 )),
552 }; 572 };
553 573
554 let id: MacroCallId = db.intern_macro(loc).into(); 574 let id: MacroCallId = db.intern_macro(loc).into();
@@ -563,7 +583,7 @@ mod tests {
563 }; 583 };
564 584
565 let args = macro_call.token_tree().unwrap(); 585 let args = macro_call.token_tree().unwrap();
566 let parsed_args = mbe::ast_to_token_tree(&args).unwrap().0; 586 let parsed_args = mbe::ast_to_token_tree(&args).0;
567 let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call)); 587 let call_id = AstId::new(file_id.into(), ast_id_map.ast_id(&macro_call));
568 588
569 let arg_id = db.intern_eager_expansion({ 589 let arg_id = db.intern_eager_expansion({
diff --git a/crates/hir_expand/src/db.rs b/crates/hir_expand/src/db.rs
index c0ab70b60..ca705ee9d 100644
--- a/crates/hir_expand/src/db.rs
+++ b/crates/hir_expand/src/db.rs
@@ -119,7 +119,7 @@ pub fn expand_hypothetical(
119 token_to_map: syntax::SyntaxToken, 119 token_to_map: syntax::SyntaxToken,
120) -> Option<(SyntaxNode, syntax::SyntaxToken)> { 120) -> Option<(SyntaxNode, syntax::SyntaxToken)> {
121 let macro_file = MacroFile { macro_call_id: actual_macro_call }; 121 let macro_file = MacroFile { macro_call_id: actual_macro_call };
122 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax()).unwrap(); 122 let (tt, tmap_1) = mbe::syntax_node_to_token_tree(hypothetical_args.syntax());
123 let range = 123 let range =
124 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?; 124 token_to_map.text_range().checked_sub(hypothetical_args.syntax().text_range().start())?;
125 let token_id = tmap_1.token_by_range(range)?; 125 let token_id = tmap_1.token_by_range(range)?;
@@ -143,10 +143,7 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) { 143 MacroDefKind::Declarative(ast_id) => match ast_id.to_node(db) {
144 syntax::ast::Macro::MacroRules(macro_rules) => { 144 syntax::ast::Macro::MacroRules(macro_rules) => {
145 let arg = macro_rules.token_tree()?; 145 let arg = macro_rules.token_tree()?;
146 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 146 let (tt, tmap) = mbe::ast_to_token_tree(&arg);
147 log::warn!("fail on macro_rules to token tree: {:#?}", arg);
148 None
149 })?;
150 let rules = match MacroRules::parse(&tt) { 147 let rules = match MacroRules::parse(&tt) {
151 Ok(it) => it, 148 Ok(it) => it,
152 Err(err) => { 149 Err(err) => {
@@ -159,10 +156,7 @@ fn macro_def(db: &dyn AstDatabase, id: MacroDefId) -> Option<Arc<(TokenExpander,
159 } 156 }
160 syntax::ast::Macro::MacroDef(macro_def) => { 157 syntax::ast::Macro::MacroDef(macro_def) => {
161 let arg = macro_def.body()?; 158 let arg = macro_def.body()?;
162 let (tt, tmap) = mbe::ast_to_token_tree(&arg).or_else(|| { 159 let (tt, tmap) = mbe::ast_to_token_tree(&arg);
163 log::warn!("fail on macro_def to token tree: {:#?}", arg);
164 None
165 })?;
166 let rules = match MacroDef::parse(&tt) { 160 let rules = match MacroDef::parse(&tt) {
167 Ok(it) => it, 161 Ok(it) => it,
168 Err(err) => { 162 Err(err) => {
@@ -202,7 +196,7 @@ fn macro_arg_text(db: &dyn AstDatabase, id: MacroCallId) -> Option<GreenNode> {
202 196
203fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> { 197fn macro_arg(db: &dyn AstDatabase, id: MacroCallId) -> Option<Arc<(tt::Subtree, mbe::TokenMap)>> {
204 let arg = db.macro_arg_text(id)?; 198 let arg = db.macro_arg_text(id)?;
205 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg))?; 199 let (tt, tmap) = mbe::syntax_node_to_token_tree(&SyntaxNode::new_root(arg));
206 Some(Arc::new((tt, tmap))) 200 Some(Arc::new((tt, tmap)))
207} 201}
208 202
@@ -445,6 +439,7 @@ fn to_fragment_kind(db: &dyn AstDatabase, id: MacroCallId) -> FragmentKind {
445 match parent.kind() { 439 match parent.kind() {
446 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items, 440 MACRO_ITEMS | SOURCE_FILE => FragmentKind::Items,
447 MACRO_STMTS => FragmentKind::Statements, 441 MACRO_STMTS => FragmentKind::Statements,
442 MACRO_PAT => FragmentKind::Pattern,
448 ITEM_LIST => FragmentKind::Items, 443 ITEM_LIST => FragmentKind::Items,
449 LET_STMT => { 444 LET_STMT => {
450 // FIXME: Handle LHS Pattern 445 // FIXME: Handle LHS Pattern
diff --git a/crates/hir_expand/src/eager.rs b/crates/hir_expand/src/eager.rs
index 9eedc8461..ef126e4ad 100644
--- a/crates/hir_expand/src/eager.rs
+++ b/crates/hir_expand/src/eager.rs
@@ -106,7 +106,7 @@ pub fn expand_eager_macro(
106 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError), 106 mut diagnostic_sink: &mut dyn FnMut(mbe::ExpandError),
107) -> Result<EagerMacroId, ErrorEmitted> { 107) -> Result<EagerMacroId, ErrorEmitted> {
108 let parsed_args = diagnostic_sink.option_with( 108 let parsed_args = diagnostic_sink.option_with(
109 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?)?.0), 109 || Some(mbe::ast_to_token_tree(&macro_call.value.token_tree()?).0),
110 || err("malformed macro invocation"), 110 || err("malformed macro invocation"),
111 )?; 111 )?;
112 112
@@ -161,7 +161,7 @@ pub fn expand_eager_macro(
161} 161}
162 162
163fn to_subtree(node: &SyntaxNode) -> Option<tt::Subtree> { 163fn to_subtree(node: &SyntaxNode) -> Option<tt::Subtree> {
164 let mut subtree = mbe::syntax_node_to_token_tree(node)?.0; 164 let mut subtree = mbe::syntax_node_to_token_tree(node).0;
165 subtree.delimiter = None; 165 subtree.delimiter = None;
166 Some(subtree) 166 Some(subtree)
167} 167}
@@ -174,8 +174,9 @@ fn lazy_expand(
174) -> ExpandResult<Option<InFile<SyntaxNode>>> { 174) -> ExpandResult<Option<InFile<SyntaxNode>>> {
175 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value); 175 let ast_id = db.ast_id_map(macro_call.file_id).ast_id(&macro_call.value);
176 176
177 let id: MacroCallId = 177 let id: MacroCallId = def
178 def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); 178 .as_lazy_macro(db, krate, MacroCallKind::FnLike { ast_id: macro_call.with_value(ast_id) })
179 .into();
179 180
180 let err = db.macro_expand_error(id); 181 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)); 182 let value = db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node));
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 cd691b1d2..a0f8766b0 100644
--- a/crates/hir_expand/src/name.rs
+++ b/crates/hir_expand/src/name.rs
@@ -55,6 +55,15 @@ impl Name {
55 } 55 }
56 } 56 }
57 57
58 /// A fake name for things missing in the source code.
59 ///
60 /// For example, `impl Foo for {}` should be treated as a trait impl for a
61 /// type with a missing name. Similarly, `struct S { : u32 }` should have a
62 /// single field with a missing name.
63 ///
64 /// Ideally, we want a `gensym` semantics for missing names -- each missing
65 /// name is equal only to itself. It's not clear how to implement this in
66 /// salsa though, so we punt on that bit for a moment.
58 pub fn missing() -> Name { 67 pub fn missing() -> Name {
59 Name::new_text("[missing name]".into()) 68 Name::new_text("[missing name]".into())
60 } 69 }
@@ -199,6 +208,8 @@ pub mod known {
199 line, 208 line,
200 module_path, 209 module_path,
201 assert, 210 assert,
211 core_panic,
212 std_panic,
202 stringify, 213 stringify,
203 concat, 214 concat,
204 include, 215 include,
diff --git a/crates/hir_expand/src/quote.rs b/crates/hir_expand/src/quote.rs
index 08bc5aa49..c82487ef0 100644
--- a/crates/hir_expand/src/quote.rs
+++ b/crates/hir_expand/src/quote.rs
@@ -104,6 +104,7 @@ macro_rules! __quote {
104 ( . ) => {$crate::__quote!(@PUNCT '.')}; 104 ( . ) => {$crate::__quote!(@PUNCT '.')};
105 ( < ) => {$crate::__quote!(@PUNCT '<')}; 105 ( < ) => {$crate::__quote!(@PUNCT '<')};
106 ( > ) => {$crate::__quote!(@PUNCT '>')}; 106 ( > ) => {$crate::__quote!(@PUNCT '>')};
107 ( ! ) => {$crate::__quote!(@PUNCT '!')};
107 108
108 ( $first:tt $($tail:tt)+ ) => { 109 ( $first:tt $($tail:tt)+ ) => {
109 { 110 {
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 030b7eebe..abc0e7532 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -12,7 +12,7 @@ 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"
diff --git a/crates/hir_ty/src/autoderef.rs b/crates/hir_ty/src/autoderef.rs
index dc5fc759a..2c07494a9 100644
--- a/crates/hir_ty/src/autoderef.rs
+++ b/crates/hir_ty/src/autoderef.rs
@@ -6,18 +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 to_assoc_type_id, to_chalk_trait_id, 16 DebruijnIndex, InEnvironment, Interner, ProjectionTyExt, Solution, Substitution, Ty, TyBuilder,
17 traits::{InEnvironment, Solution}, 17 TyKind,
18 utils::generics,
19 AliasEq, AliasTy, BoundVar, Canonical, CanonicalVarKinds, DebruijnIndex, Interner,
20 ProjectionTy, Substitution, TraitRef, Ty, TyKind,
21}; 18};
22 19
23const AUTODEREF_RECURSION_LIMIT: usize = 10; 20const AUTODEREF_RECURSION_LIMIT: usize = 10;
@@ -39,39 +36,48 @@ pub(crate) fn deref(
39 krate: CrateId, 36 krate: CrateId,
40 ty: InEnvironment<&Canonical<Ty>>, 37 ty: InEnvironment<&Canonical<Ty>>,
41) -> Option<Canonical<Ty>> { 38) -> Option<Canonical<Ty>> {
42 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) {
43 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() }) 41 Some(Canonical { value: derefed, binders: ty.goal.binders.clone() })
44 } else { 42 } else {
45 deref_by_trait(db, krate, ty) 43 deref_by_trait(db, krate, ty)
46 } 44 }
47} 45}
48 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
49fn deref_by_trait( 55fn deref_by_trait(
50 db: &dyn HirDatabase, 56 db: &dyn HirDatabase,
51 krate: CrateId, 57 krate: CrateId,
52 ty: InEnvironment<&Canonical<Ty>>, 58 ty: InEnvironment<&Canonical<Ty>>,
53) -> Option<Canonical<Ty>> { 59) -> Option<Canonical<Ty>> {
60 let _p = profile::span("deref_by_trait");
54 let deref_trait = match db.lang_item(krate, "deref".into())? { 61 let deref_trait = match db.lang_item(krate, "deref".into())? {
55 LangItemTarget::TraitId(it) => it, 62 LangItemTarget::TraitId(it) => it,
56 _ => return None, 63 _ => return None,
57 }; 64 };
58 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?; 65 let target = db.trait_data(deref_trait).associated_type_by_name(&name![Target])?;
59 66
60 let generic_params = generics(db.upcast(), target.into()); 67 let projection = {
61 if generic_params.len() != 1 { 68 let b = TyBuilder::assoc_type_projection(db, target);
62 // the Target type + Deref trait should only have one generic parameter, 69 if b.remaining() != 1 {
63 // namely Deref's Self type 70 // the Target type + Deref trait should only have one generic parameter,
64 return None; 71 // namely Deref's Self type
65 } 72 return None;
73 }
74 b.push(ty.goal.value.clone()).build()
75 };
66 76
67 // FIXME make the Canonical / bound var handling nicer 77 // FIXME make the Canonical / bound var handling nicer
68 78
69 let parameters =
70 Substitution::build_for_generics(&generic_params).push(ty.goal.value.clone()).build();
71
72 // Check that the type implements Deref at all 79 // Check that the type implements Deref at all
73 let trait_ref = 80 let trait_ref = projection.trait_ref(db);
74 TraitRef { trait_id: to_chalk_trait_id(deref_trait), substitution: parameters.clone() };
75 let implements_goal = Canonical { 81 let implements_goal = Canonical {
76 binders: ty.goal.binders.clone(), 82 binders: ty.goal.binders.clone(),
77 value: InEnvironment { 83 value: InEnvironment {
@@ -84,11 +90,8 @@ fn deref_by_trait(
84 } 90 }
85 91
86 // Now do the assoc type projection 92 // Now do the assoc type projection
87 let projection = AliasEq { 93 let alias_eq = AliasEq {
88 alias: AliasTy::Projection(ProjectionTy { 94 alias: AliasTy::Projection(projection),
89 associated_ty_id: to_assoc_type_id(target),
90 substitution: parameters,
91 }),
92 ty: TyKind::BoundVar(BoundVar::new( 95 ty: TyKind::BoundVar(BoundVar::new(
93 DebruijnIndex::INNERMOST, 96 DebruijnIndex::INNERMOST,
94 ty.goal.binders.len(&Interner), 97 ty.goal.binders.len(&Interner),
@@ -96,16 +99,14 @@ fn deref_by_trait(
96 .intern(&Interner), 99 .intern(&Interner),
97 }; 100 };
98 101
99 let obligation = projection.cast(&Interner); 102 let in_env = InEnvironment { goal: alias_eq.cast(&Interner), environment: ty.environment };
100
101 let in_env = InEnvironment { goal: obligation, environment: ty.environment };
102 103
103 let canonical = Canonical { 104 let canonical = Canonical {
104 value: in_env, 105 value: in_env,
105 binders: CanonicalVarKinds::from_iter( 106 binders: CanonicalVarKinds::from_iter(
106 &Interner, 107 &Interner,
107 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(
108 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 109 VariableKind::Ty(chalk_ir::TyVariableKind::General),
109 chalk_ir::UniverseIndex::ROOT, 110 chalk_ir::UniverseIndex::ROOT,
110 ))), 111 ))),
111 ), 112 ),
@@ -130,18 +131,25 @@ fn deref_by_trait(
130 // assumptions will be broken. We would need to properly introduce 131 // assumptions will be broken. We would need to properly introduce
131 // new variables in that case 132 // new variables in that case
132 133
133 for i in 1..vars.0.binders.len(&Interner) { 134 for i in 1..vars.binders.len(&Interner) {
134 if vars.0.value[i - 1].interned(&Interner) 135 if vars.value.subst.at(&Interner, i - 1).assert_ty_ref(&Interner).kind(&Interner)
135 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1)) 136 != &TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, i - 1))
136 { 137 {
137 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution); 138 warn!("complex solution for derefing {:?}: {:?}, ignoring", ty.goal, solution);
138 return None; 139 return None;
139 } 140 }
140 } 141 }
141 Some(Canonical { 142 // FIXME: we remove lifetime variables here since they can confuse
142 value: vars.0.value[vars.0.value.len() - 1].clone(), 143 // the method resolution code later
143 binders: vars.0.binders.clone(), 144 Some(fixup_lifetime_variables(Canonical {
144 }) 145 value: vars
146 .value
147 .subst
148 .at(&Interner, vars.value.subst.len(&Interner) - 1)
149 .assert_ty_ref(&Interner)
150 .clone(),
151 binders: vars.binders.clone(),
152 }))
145 } 153 }
146 Solution::Ambig(_) => { 154 Solution::Ambig(_) => {
147 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution); 155 info!("Ambiguous solution for derefing {:?}: {:?}", ty.goal, solution);
@@ -149,3 +157,32 @@ fn deref_by_trait(
149 } 157 }
150 } 158 }
151} 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
new file mode 100644
index 000000000..e25ef866d
--- /dev/null
+++ b/crates/hir_ty/src/builder.rs
@@ -0,0 +1,223 @@
1//! `TyBuilder`, a helper for building instances of `Ty` and related types.
2
3use std::iter;
4
5use chalk_ir::{
6 cast::{Cast, CastTo, Caster},
7 fold::Fold,
8 interner::HasInterner,
9 AdtId, BoundVar, DebruijnIndex, Safety, Scalar,
10};
11use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
12use smallvec::SmallVec;
13
14use crate::{
15 db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
16 CallableSig, FnPointer, FnSig, FnSubst, GenericArg, Interner, ProjectionTy, Substitution,
17 TraitRef, Ty, TyDefId, TyExt, TyKind, ValueTyDefId,
18};
19
20/// This is a builder for `Ty` or anything that needs a `Substitution`.
21pub struct TyBuilder<D> {
22 /// The `data` field is used to keep track of what we're building (e.g. an
23 /// ADT, a `TraitRef`, ...).
24 data: D,
25 vec: SmallVec<[GenericArg; 2]>,
26 param_count: usize,
27}
28
29impl<D> TyBuilder<D> {
30 fn new(data: D, param_count: usize) -> TyBuilder<D> {
31 TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) }
32 }
33
34 fn build_internal(self) -> (D, Substitution) {
35 assert_eq!(self.vec.len(), self.param_count);
36 let subst = Substitution::from_iter(&Interner, self.vec);
37 (self.data, subst)
38 }
39
40 pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
41 self.vec.push(arg.cast(&Interner));
42 self
43 }
44
45 pub fn remaining(&self) -> usize {
46 self.param_count - self.vec.len()
47 }
48
49 pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
50 self.fill(
51 (starting_from..)
52 .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)),
53 )
54 }
55
56 pub fn fill_with_unknown(self) -> Self {
57 self.fill(iter::repeat(TyKind::Error.intern(&Interner)))
58 }
59
60 pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self {
61 self.vec.extend(filler.take(self.remaining()).casted(&Interner));
62 assert_eq!(self.remaining(), 0);
63 self
64 }
65
66 pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
67 assert!(self.vec.is_empty());
68 assert!(parent_substs.len(&Interner) <= self.param_count);
69 self.vec.extend(parent_substs.iter(&Interner).cloned());
70 self
71 }
72}
73
74impl TyBuilder<()> {
75 pub fn unit() -> Ty {
76 TyKind::Tuple(0, Substitution::empty(&Interner)).intern(&Interner)
77 }
78
79 pub fn fn_ptr(sig: CallableSig) -> Ty {
80 TyKind::Function(FnPointer {
81 num_binders: 0,
82 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
83 substitution: FnSubst(Substitution::from_iter(
84 &Interner,
85 sig.params_and_return.iter().cloned(),
86 )),
87 })
88 .intern(&Interner)
89 }
90
91 pub fn builtin(builtin: BuiltinType) -> Ty {
92 match builtin {
93 BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner),
94 BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner),
95 BuiltinType::Str => TyKind::Str.intern(&Interner),
96 BuiltinType::Int(t) => {
97 TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner)
98 }
99 BuiltinType::Uint(t) => {
100 TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner)
101 }
102 BuiltinType::Float(t) => {
103 TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner)
104 }
105 }
106 }
107
108 pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
109 let params = generics(db.upcast(), def.into());
110 params.type_params_subst(db)
111 }
112
113 pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
114 let def = def.into();
115 let params = generics(db.upcast(), def);
116 let param_count = params.len();
117 TyBuilder::new((), param_count)
118 }
119
120 pub fn build(self) -> Substitution {
121 let ((), subst) = self.build_internal();
122 subst
123 }
124}
125
126impl TyBuilder<hir_def::AdtId> {
127 pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
128 let generics = generics(db.upcast(), adt.into());
129 let param_count = generics.len();
130 TyBuilder::new(adt, param_count)
131 }
132
133 pub fn fill_with_defaults(
134 mut self,
135 db: &dyn HirDatabase,
136 mut fallback: impl FnMut() -> Ty,
137 ) -> Self {
138 let defaults = db.generic_defaults(self.data.into());
139 for default_ty in defaults.iter().skip(self.vec.len()) {
140 if default_ty.skip_binders().is_unknown() {
141 self.vec.push(fallback().cast(&Interner));
142 } else {
143 // each default can depend on the previous parameters
144 let subst_so_far = Substitution::from_iter(&Interner, self.vec.clone());
145 self.vec
146 .push(default_ty.clone().substitute(&Interner, &subst_so_far).cast(&Interner));
147 }
148 }
149 self
150 }
151
152 pub fn build(self) -> Ty {
153 let (adt, subst) = self.build_internal();
154 TyKind::Adt(AdtId(adt), subst).intern(&Interner)
155 }
156}
157
158pub struct Tuple(usize);
159impl TyBuilder<Tuple> {
160 pub fn tuple(size: usize) -> TyBuilder<Tuple> {
161 TyBuilder::new(Tuple(size), size)
162 }
163
164 pub fn build(self) -> Ty {
165 let (Tuple(size), subst) = self.build_internal();
166 TyKind::Tuple(size, subst).intern(&Interner)
167 }
168}
169
170impl TyBuilder<TraitId> {
171 pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> {
172 let generics = generics(db.upcast(), trait_id.into());
173 let param_count = generics.len();
174 TyBuilder::new(trait_id, param_count)
175 }
176
177 pub fn build(self) -> TraitRef {
178 let (trait_id, substitution) = self.build_internal();
179 TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution }
180 }
181}
182
183impl TyBuilder<TypeAliasId> {
184 pub fn assoc_type_projection(
185 db: &dyn HirDatabase,
186 type_alias: TypeAliasId,
187 ) -> TyBuilder<TypeAliasId> {
188 let generics = generics(db.upcast(), type_alias.into());
189 let param_count = generics.len();
190 TyBuilder::new(type_alias, param_count)
191 }
192
193 pub fn build(self) -> ProjectionTy {
194 let (type_alias, substitution) = self.build_internal();
195 ProjectionTy { associated_ty_id: to_assoc_type_id(type_alias), substitution }
196 }
197}
198
199impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
200 fn subst_binders(b: Binders<T>) -> Self {
201 let param_count = b.binders.len(&Interner);
202 TyBuilder::new(b, param_count)
203 }
204
205 pub fn build(self) -> <T as Fold<Interner>>::Result {
206 let (b, subst) = self.build_internal();
207 b.substitute(&Interner, &subst)
208 }
209}
210
211impl TyBuilder<Binders<Ty>> {
212 pub fn def_ty(db: &dyn HirDatabase, def: TyDefId) -> TyBuilder<Binders<Ty>> {
213 TyBuilder::subst_binders(db.ty(def.into()))
214 }
215
216 pub fn impl_self_ty(db: &dyn HirDatabase, def: hir_def::ImplId) -> TyBuilder<Binders<Ty>> {
217 TyBuilder::subst_binders(db.impl_self_ty(def))
218 }
219
220 pub fn value_ty(db: &dyn HirDatabase, def: ValueTyDefId) -> TyBuilder<Binders<Ty>> {
221 TyBuilder::subst_binders(db.value_ty(def))
222 }
223}
diff --git a/crates/hir_ty/src/chalk_cast.rs b/crates/hir_ty/src/chalk_cast.rs
deleted file mode 100644
index bf884ae15..000000000
--- a/crates/hir_ty/src/chalk_cast.rs
+++ /dev/null
@@ -1,53 +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, Interner, TraitRef, 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);
20
21impl CastTo<WhereClause> for TraitRef {
22 fn cast_to(self, _interner: &Interner) -> WhereClause {
23 WhereClause::Implemented(self)
24 }
25}
26
27impl CastTo<WhereClause> for AliasEq {
28 fn cast_to(self, _interner: &Interner) -> WhereClause {
29 WhereClause::AliasEq(self)
30 }
31}
32
33impl CastTo<DomainGoal> for WhereClause {
34 fn cast_to(self, _interner: &Interner) -> DomainGoal {
35 DomainGoal::Holds(self)
36 }
37}
38
39macro_rules! transitive_impl {
40 ($a:ty, $b:ty, $c:ty) => {
41 impl CastTo<$c> for $a {
42 fn cast_to(self, interner: &Interner) -> $c {
43 self.cast::<$b>(interner).cast(interner)
44 }
45 }
46 };
47}
48
49// In Chalk, these can be done as blanket impls, but that doesn't work here
50// because of coherence
51
52transitive_impl!(TraitRef, WhereClause, DomainGoal);
53transitive_impl!(AliasEq, WhereClause, DomainGoal);
diff --git a/crates/hir_ty/src/traits/chalk.rs b/crates/hir_ty/src/chalk_db.rs
index 011bef6f6..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, GenericArg}; 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, 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> {
@@ -80,19 +75,19 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
80 fn impls_for_trait( 75 fn impls_for_trait(
81 &self, 76 &self,
82 trait_id: TraitId, 77 trait_id: TraitId,
83 parameters: &[GenericArg<Interner>], 78 parameters: &[chalk_ir::GenericArg<Interner>],
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,
93 binders: &CanonicalVarKinds<Interner>, 88 binders: &CanonicalVarKinds<Interner>,
94 ) -> Option<chalk_ir::TyVariableKind> { 89 ) -> Option<chalk_ir::TyVariableKind> {
95 if let TyKind::BoundVar(bv) = ty.interned(&Interner) { 90 if let TyKind::BoundVar(bv) = ty.kind(&Interner) {
96 let binders = binders.as_slice(&Interner); 91 let binders = binders.as_slice(&Interner);
97 if bv.debruijn == DebruijnIndex::INNERMOST { 92 if bv.debruijn == DebruijnIndex::INNERMOST {
98 if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind { 93 if let chalk_ir::VariableKind::Ty(tk) = binders[bv.index].kind {
@@ -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 = Ty::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().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 {
@@ -387,7 +383,7 @@ pub(crate) fn associated_ty_data_query(
387 // Lower bounds -- we could/should maybe move this to a separate query in `lower` 383 // Lower bounds -- we could/should maybe move this to a separate query in `lower`
388 let type_alias_data = db.type_alias_data(type_alias); 384 let type_alias_data = db.type_alias_data(type_alias);
389 let generic_params = generics(db.upcast(), type_alias.into()); 385 let generic_params = generics(db.upcast(), type_alias.into());
390 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 386 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
391 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast()); 387 let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
392 let ctx = crate::TyLoweringContext::new(db, &resolver) 388 let ctx = crate::TyLoweringContext::new(db, &resolver)
393 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable); 389 .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
@@ -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,11 +413,11 @@ 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());
424 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 420 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
425 let flags = rust_ir::TraitFlags { 421 let flags = rust_ir::TraitFlags {
426 auto: trait_data.is_auto, 422 auto: trait_data.is_auto,
427 upstream: trait_.lookup(db.upcast()).container.krate() != krate, 423 upstream: trait_.lookup(db.upcast()).container.krate() != krate,
@@ -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()), 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,
@@ -490,7 +486,7 @@ pub(crate) fn struct_datum_query(
490 let upstream = adt_id.module(db.upcast()).krate() != krate; 486 let upstream = adt_id.module(db.upcast()).krate() != krate;
491 let where_clauses = { 487 let where_clauses = {
492 let generic_params = generics(db.upcast(), adt_id.into()); 488 let generic_params = generics(db.upcast(), adt_id.into());
493 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 489 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
494 convert_where_clauses(db, adt_id.into(), &bound_vars) 490 convert_where_clauses(db, adt_id.into(), &bound_vars)
495 }; 491 };
496 let flags = rust_ir::AdtFlags { 492 let flags = rust_ir::AdtFlags {
@@ -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,11 +531,12 @@ 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());
542 let bound_vars = Substitution::bound_vars(&generic_params, DebruijnIndex::INNERMOST); 539 let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
543 let trait_ = trait_ref.hir_trait_id(); 540 let trait_ = trait_ref.hir_trait_id();
544 let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate { 541 let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
545 rust_ir::ImplType::Local 542 rust_ir::ImplType::Local
@@ -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()), 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 = Substitution::bound_vars(&generic_params, 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
new file mode 100644
index 000000000..8c4542956
--- /dev/null
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -0,0 +1,305 @@
1//! Various extensions traits for Chalk types.
2
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};
14
15pub trait TyExt {
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;
40}
41
42impl TyExt for Ty {
43 fn is_unit(&self) -> bool {
44 matches!(self.kind(&Interner), TyKind::Tuple(0, _))
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 }
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 33a0f4d7d..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,15 +85,44 @@ 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) {
93 let data = self.db.function_data(func); 124 let data = self.db.function_data(func);
94 if data.is_in_extern_block { 125 if data.is_in_extern_block() {
95 cov_mark::hit!(extern_func_incorrect_case_ignored); 126 cov_mark::hit!(extern_func_incorrect_case_ignored);
96 return; 127 return;
97 } 128 }
@@ -99,8 +130,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
99 let body = self.db.body(func.into()); 130 let body = self.db.body(func.into());
100 131
101 // Recursively validate inner scope items, such as static variables and constants. 132 // Recursively validate inner scope items, such as static variables and constants.
102 let db = self.db; 133 for (_, block_def_map) in body.blocks(self.db.upcast()) {
103 for block_def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) {
104 for (_, module) in block_def_map.modules() { 134 for (_, module) in block_def_map.modules() {
105 for def_id in module.scope.declarations() { 135 for def_id in module.scope.declarations() {
106 let mut validator = DeclValidator::new(self.db, self.krate, self.sink); 136 let mut validator = DeclValidator::new(self.db, self.krate, self.sink);
@@ -110,7 +140,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
110 } 140 }
111 141
112 // Check whether non-snake case identifiers are allowed for this function. 142 // Check whether non-snake case identifiers are allowed for this function.
113 if self.allowed(func.into(), allow::NON_SNAKE_CASE) { 143 if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
114 return; 144 return;
115 } 145 }
116 146
@@ -329,8 +359,9 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
329 fn validate_struct(&mut self, struct_id: StructId) { 359 fn validate_struct(&mut self, struct_id: StructId) {
330 let data = self.db.struct_data(struct_id); 360 let data = self.db.struct_data(struct_id);
331 361
332 let non_camel_case_allowed = self.allowed(struct_id.into(), allow::NON_CAMEL_CASE_TYPES); 362 let non_camel_case_allowed =
333 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);
334 365
335 // Check the structure name. 366 // Check the structure name.
336 let struct_name = data.name.to_string(); 367 let struct_name = data.name.to_string();
@@ -462,7 +493,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
462 let data = self.db.enum_data(enum_id); 493 let data = self.db.enum_data(enum_id);
463 494
464 // Check whether non-camel case names are allowed for this enum. 495 // Check whether non-camel case names are allowed for this enum.
465 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES) { 496 if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
466 return; 497 return;
467 } 498 }
468 499
@@ -585,7 +616,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
585 fn validate_const(&mut self, const_id: ConstId) { 616 fn validate_const(&mut self, const_id: ConstId) {
586 let data = self.db.const_data(const_id); 617 let data = self.db.const_data(const_id);
587 618
588 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 619 if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
589 return; 620 return;
590 } 621 }
591 622
@@ -633,7 +664,7 @@ impl<'a, 'b> DeclValidator<'a, 'b> {
633 return; 664 return;
634 } 665 }
635 666
636 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL) { 667 if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
637 return; 668 return;
638 } 669 }
639 670
@@ -868,23 +899,116 @@ fn main() {
868 fn allow_attributes() { 899 fn allow_attributes() {
869 check_diagnostics( 900 check_diagnostics(
870 r#" 901 r#"
871 #[allow(non_snake_case)] 902#[allow(non_snake_case)]
872 fn NonSnakeCaseName(SOME_VAR: u8) -> u8{ 903fn NonSnakeCaseName(SOME_VAR: u8) -> u8{
873 let OtherVar = SOME_VAR + 1; 904 // cov_flags generated output from elsewhere in this file
874 OtherVar 905 extern "C" {
906 #[no_mangle]
907 static lower_case: u8;
875 } 908 }
876 909
877 #[allow(non_snake_case, non_camel_case_types)] 910 let OtherVar = SOME_VAR + 1;
878 pub struct some_type { 911 OtherVar
879 SOME_FIELD: u8, 912}
880 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 );
881 } 942 }
882 943
883 #[allow(non_upper_case_globals)] 944 #[test]
884 pub const some_const: u8 = 10; 945 fn allow_attributes_crate_attr() {
946 check_diagnostics(
947 r#"
948#![allow(non_snake_case)]
885 949
886 #[allow(non_upper_case_globals)] 950mod F {
887 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}
888 "#, 1012 "#,
889 ); 1013 );
890 } 1014 }
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index 3909ad354..79602c3dd 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -14,8 +14,7 @@ use crate::{
14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr, 14 MismatchedArgCount, MissingFields, MissingMatchArms, MissingOkOrSomeInTailExpr,
15 MissingPatFields, RemoveThisSemicolon, 15 MissingPatFields, RemoveThisSemicolon,
16 }, 16 },
17 utils::variant_data, 17 AdtId, InferenceResult, Interner, TyExt, TyKind,
18 AdtId, InferenceResult, Interner, Ty, TyKind,
19}; 18};
20 19
21pub(crate) use hir_def::{ 20pub(crate) use hir_def::{
@@ -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
@@ -378,7 +378,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
378 _ => return, 378 _ => return,
379 }; 379 };
380 380
381 let (params, required) = match mismatch.expected.interned(&Interner) { 381 let (params, required) = match mismatch.expected.kind(&Interner) {
382 TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters) 382 TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ref parameters)
383 if *enum_id == core_result_enum => 383 if *enum_id == core_result_enum =>
384 { 384 {
@@ -392,7 +392,9 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
392 _ => return, 392 _ => return,
393 }; 393 };
394 394
395 if params.len() > 0 && params[0] == mismatch.actual { 395 if params.len(&Interner) > 0
396 && params.at(&Interner, 0).ty(&Interner) == Some(&mismatch.actual)
397 {
396 let (_, source_map) = db.body_with_source_map(self.owner); 398 let (_, source_map) = db.body_with_source_map(self.owner);
397 399
398 if let Ok(source_ptr) = source_map.expr_syntax(id) { 400 if let Ok(source_ptr) = source_map.expr_syntax(id) {
@@ -421,7 +423,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
421 None => return, 423 None => return,
422 }; 424 };
423 425
424 if mismatch.actual != Ty::unit() || mismatch.expected != *possible_tail_ty { 426 if !mismatch.actual.is_unit() || mismatch.expected != *possible_tail_ty {
425 return; 427 return;
426 } 428 }
427 429
@@ -450,7 +452,7 @@ pub fn record_literal_missing_fields(
450 return None; 452 return None;
451 } 453 }
452 454
453 let variant_data = variant_data(db.upcast(), variant_def); 455 let variant_data = variant_def.variant_data(db.upcast());
454 456
455 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 457 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
456 let missed_fields: Vec<LocalFieldId> = variant_data 458 let missed_fields: Vec<LocalFieldId> = variant_data
@@ -480,7 +482,7 @@ pub fn record_pattern_missing_fields(
480 return None; 482 return None;
481 } 483 }
482 484
483 let variant_data = variant_data(db.upcast(), variant_def); 485 let variant_data = variant_def.variant_data(db.upcast());
484 486
485 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect(); 487 let specified_fields: FxHashSet<_> = fields.iter().map(|f| &f.name).collect();
486 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 5a5cdcbf3..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
@@ -539,7 +539,7 @@ impl Matrix {
539 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { 539 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
540 // Or patterns are expanded here 540 // Or patterns are expanded here
541 for pat_id in pat_ids { 541 for pat_id in pat_ids {
542 self.0.push(PatStack::from_pattern(pat_id)); 542 self.0.push(row.replace_head_with([pat_id].iter()));
543 } 543 }
544 } else { 544 } else {
545 self.0.push(row); 545 self.0.push(row);
@@ -626,7 +626,7 @@ pub(super) fn is_useful(
626 // - enum with no variants 626 // - enum with no variants
627 // - `!` type 627 // - `!` type
628 // In those cases, no match arm is useful. 628 // In those cases, no match arm is useful.
629 match cx.infer[cx.match_expr].strip_references().interned(&Interner) { 629 match cx.infer[cx.match_expr].strip_references().kind(&Interner) {
630 TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => { 630 TyKind::Adt(AdtId(hir_def::AdtId::EnumId(enum_id)), ..) => {
631 if cx.db.enum_data(*enum_id).variants.is_empty() { 631 if cx.db.enum_data(*enum_id).variants.is_empty() {
632 return Ok(Usefulness::NotUseful); 632 return Ok(Usefulness::NotUseful);
@@ -792,7 +792,10 @@ fn pat_constructor(cx: &MatchCheckCtx, pat: PatIdOrWild) -> MatchCheckResult<Opt
792 Pat::Tuple { .. } => { 792 Pat::Tuple { .. } => {
793 let pat_id = pat.as_id().expect("we already know this pattern is not a wild"); 793 let pat_id = pat.as_id().expect("we already know this pattern is not a wild");
794 Some(Constructor::Tuple { 794 Some(Constructor::Tuple {
795 arity: cx.infer.type_of_pat[pat_id].as_tuple().ok_or(MatchCheckErr::Unknown)?.len(), 795 arity: cx.infer.type_of_pat[pat_id]
796 .as_tuple()
797 .ok_or(MatchCheckErr::Unknown)?
798 .len(&Interner),
796 }) 799 })
797 } 800 }
798 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] { 801 Pat::Lit(lit_expr) => match cx.body.exprs[lit_expr] {
@@ -1085,6 +1088,20 @@ fn main() {
1085 } 1088 }
1086 1089
1087 #[test] 1090 #[test]
1091 fn or_pattern_no_diagnostic() {
1092 check_diagnostics(
1093 r#"
1094enum Either {A, B}
1095
1096fn main() {
1097 match (Either::A, Either::B) {
1098 (Either::A | Either::B, _) => (),
1099 }
1100}"#,
1101 )
1102 }
1103
1104 #[test]
1088 fn mismatched_types() { 1105 fn mismatched_types() {
1089 // Match statements with arms that don't match the 1106 // Match statements with arms that don't match the
1090 // expression pattern do not fire this diagnostic. 1107 // expression pattern do not fire this diagnostic.
@@ -1336,30 +1353,6 @@ fn bang(never: !) {
1336 } 1353 }
1337 1354
1338 #[test] 1355 #[test]
1339 fn or_pattern_panic() {
1340 check_diagnostics(
1341 r#"
1342pub enum Category { Infinity, Zero }
1343
1344fn panic(a: Category, b: Category) {
1345 match (a, b) {
1346 (Category::Zero | Category::Infinity, _) => (),
1347 (_, Category::Zero | Category::Infinity) => (),
1348 }
1349
1350 // FIXME: This is a false positive, but the code used to cause a panic in the match checker,
1351 // so this acts as a regression test for that.
1352 match (a, b) {
1353 //^^^^^^ Missing match arm
1354 (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => (),
1355 (Category::Infinity | Category::Zero, _) => (),
1356 }
1357}
1358"#,
1359 );
1360 }
1361
1362 #[test]
1363 fn unknown_type() { 1356 fn unknown_type() {
1364 check_diagnostics( 1357 check_diagnostics(
1365 r#" 1358 r#"
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index 1f49a4909..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,
@@ -32,7 +34,7 @@ impl<'a, 'b> UnsafeValidator<'a, 'b> {
32 let def = self.owner; 34 let def = self.owner;
33 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def); 35 let unsafe_expressions = unsafe_expressions(db, self.infer.as_ref(), def);
34 let is_unsafe = match self.owner { 36 let is_unsafe = match self.owner {
35 DefWithBodyId::FunctionId(it) => db.function_data(it).qualifier.is_unsafe, 37 DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
36 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false, 38 DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
37 }; 39 };
38 if is_unsafe 40 if is_unsafe
@@ -86,7 +88,7 @@ fn walk_unsafe(
86 match expr { 88 match expr {
87 &Expr::Call { callee, .. } => { 89 &Expr::Call { callee, .. } => {
88 if let Some(func) = infer[callee].as_fn_def(db) { 90 if let Some(func) = infer[callee].as_fn_def(db) {
89 if db.function_data(func).qualifier.is_unsafe { 91 if db.function_data(func).is_unsafe() {
90 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 92 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
91 } 93 }
92 } 94 }
@@ -103,14 +105,14 @@ fn walk_unsafe(
103 Expr::MethodCall { .. } => { 105 Expr::MethodCall { .. } => {
104 if infer 106 if infer
105 .method_resolution(current) 107 .method_resolution(current)
106 .map(|func| db.function_data(func).qualifier.is_unsafe) 108 .map(|func| db.function_data(func).is_unsafe())
107 .unwrap_or(false) 109 .unwrap_or(false)
108 { 110 {
109 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 111 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
110 } 112 }
111 } 113 }
112 Expr::UnaryOp { expr, op: UnaryOp::Deref } => { 114 Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
113 if let TyKind::Raw(..) = &infer[*expr].interned(&Interner) { 115 if let TyKind::Raw(..) = &infer[*expr].kind(&Interner) {
114 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block }); 116 unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
115 } 117 }
116 } 118 }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 51480304b..e7c9dabc2 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -1,14 +1,19 @@
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::{
7 db::DefDatabase, 12 db::DefDatabase,
8 find_path, 13 find_path,
9 generics::TypeParamProvenance, 14 generics::TypeParamProvenance,
10 item_scope::ItemInNs, 15 item_scope::ItemInNs,
11 path::{GenericArg, Path, PathKind}, 16 path::{Path, PathKind},
12 type_ref::{TypeBound, TypeRef}, 17 type_ref::{TypeBound, TypeRef},
13 visibility::Visibility, 18 visibility::Visibility,
14 AssocContainerId, Lookup, ModuleId, TraitId, 19 AssocContainerId, Lookup, ModuleId, TraitId,
@@ -16,10 +21,12 @@ use hir_def::{
16use hir_expand::name::Name; 21use hir_expand::name::Name;
17 22
18use crate::{ 23use crate::{
19 db::HirDatabase, from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, primitive, 24 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, 25 from_placeholder_idx, lt_from_placeholder_idx, mapping::from_chalk, primitive, subst_prefix,
21 CallableDefId, CallableSig, DomainGoal, ImplTraitId, Interner, Lifetime, OpaqueTy, 26 to_assoc_type_id, utils::generics, AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const,
22 ProjectionTy, QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TyKind, WhereClause, 27 ConstValue, DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData,
28 LifetimeOutlives, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause,
29 Scalar, TraitRef, TraitRefExt, Ty, TyExt, TyKind, WhereClause,
23}; 30};
24 31
25pub struct HirFormatter<'a> { 32pub struct HirFormatter<'a> {
@@ -46,6 +53,10 @@ pub trait HirDisplay {
46 where 53 where
47 Self: Sized, 54 Self: Sized,
48 { 55 {
56 assert!(
57 !matches!(display_target, DisplayTarget::SourceCode { .. }),
58 "HirDisplayWrapper cannot fail with DisplaySourceCodeError, use HirDisplay::hir_fmt directly instead"
59 );
49 HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target } 60 HirDisplayWrapper { db, t: self, max_size, omit_verbose_types, display_target }
50 } 61 }
51 62
@@ -230,7 +241,7 @@ where
230 Err(HirDisplayError::FmtError) => Err(fmt::Error), 241 Err(HirDisplayError::FmtError) => Err(fmt::Error),
231 Err(HirDisplayError::DisplaySourceCodeError(_)) => { 242 Err(HirDisplayError::DisplaySourceCodeError(_)) => {
232 // This should never happen 243 // This should never happen
233 panic!("HirDisplay failed when calling Display::fmt!") 244 panic!("HirDisplay::hir_fmt failed with DisplaySourceCodeError when calling Display::fmt!")
234 } 245 }
235 } 246 }
236 } 247 }
@@ -251,16 +262,12 @@ impl HirDisplay for ProjectionTy {
251 } 262 }
252 263
253 let trait_ = f.db.trait_data(self.trait_(f.db)); 264 let trait_ = f.db.trait_data(self.trait_(f.db));
254 let first_parameter = self.substitution[0].into_displayable( 265 write!(f, "<")?;
255 f.db, 266 self.self_type_parameter(&Interner).hir_fmt(f)?;
256 f.max_size, 267 write!(f, " as {}", trait_.name)?;
257 f.omit_verbose_types, 268 if self.substitution.len(&Interner) > 1 {
258 f.display_target,
259 );
260 write!(f, "<{} as {}", first_parameter, trait_.name)?;
261 if self.substitution.len() > 1 {
262 write!(f, "<")?; 269 write!(f, "<")?;
263 f.write_joined(&self.substitution[1..], ", ")?; 270 f.write_joined(&self.substitution.as_slice(&Interner)[1..], ", ")?;
264 write!(f, ">")?; 271 write!(f, ">")?;
265 } 272 }
266 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?; 273 write!(f, ">::{}", f.db.type_alias_data(from_assoc_type_id(self.associated_ty_id)).name)?;
@@ -274,7 +281,40 @@ impl HirDisplay for OpaqueTy {
274 return write!(f, "{}", TYPE_HINT_TRUNCATION); 281 return write!(f, "{}", TYPE_HINT_TRUNCATION);
275 } 282 }
276 283
277 self.substitution[0].hir_fmt(f) 284 self.substitution.at(&Interner, 0).hir_fmt(f)
285 }
286}
287
288impl HirDisplay for GenericArg {
289 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
290 match self.interned() {
291 crate::GenericArgData::Ty(ty) => ty.hir_fmt(f),
292 crate::GenericArgData::Lifetime(lt) => lt.hir_fmt(f),
293 crate::GenericArgData::Const(c) => c.hir_fmt(f),
294 }
295 }
296}
297
298impl HirDisplay for Const {
299 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
300 let data = self.interned();
301 match data.value {
302 ConstValue::BoundVar(idx) => idx.hir_fmt(f),
303 ConstValue::InferenceVar(..) => write!(f, "_"),
304 ConstValue::Placeholder(idx) => {
305 let id = const_from_placeholder_idx(f.db, idx);
306 let generics = generics(f.db.upcast(), id.parent);
307 let param_data = &generics.params.consts[id.local_id];
308 write!(f, "{}", param_data.name)
309 }
310 ConstValue::Concrete(_) => write!(f, "_"),
311 }
312 }
313}
314
315impl HirDisplay for BoundVar {
316 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
317 write!(f, "?{}.{}", self.debruijn.depth(), self.index)
278 } 318 }
279} 319}
280 320
@@ -284,7 +324,7 @@ impl HirDisplay for Ty {
284 return write!(f, "{}", TYPE_HINT_TRUNCATION); 324 return write!(f, "{}", TYPE_HINT_TRUNCATION);
285 } 325 }
286 326
287 match self.interned(&Interner) { 327 match self.kind(&Interner) {
288 TyKind::Never => write!(f, "!")?, 328 TyKind::Never => write!(f, "!")?,
289 TyKind::Str => write!(f, "str")?, 329 TyKind::Str => write!(f, "str")?,
290 TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?, 330 TyKind::Scalar(Scalar::Bool) => write!(f, "bool")?,
@@ -297,16 +337,15 @@ impl HirDisplay for Ty {
297 t.hir_fmt(f)?; 337 t.hir_fmt(f)?;
298 write!(f, "]")?; 338 write!(f, "]")?;
299 } 339 }
300 TyKind::Array(t) => { 340 TyKind::Array(t, c) => {
301 write!(f, "[")?; 341 write!(f, "[")?;
302 t.hir_fmt(f)?; 342 t.hir_fmt(f)?;
303 write!(f, "; _]")?; 343 write!(f, "; ")?;
344 c.hir_fmt(f)?;
345 write!(f, "]")?;
304 } 346 }
305 TyKind::Raw(m, t) | TyKind::Ref(m, t) => { 347 TyKind::Raw(m, t) | TyKind::Ref(m, _, t) => {
306 let ty_display = 348 if matches!(self.kind(&Interner), TyKind::Raw(..)) {
307 t.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target);
308
309 if matches!(self.interned(&Interner), TyKind::Raw(..)) {
310 write!( 349 write!(
311 f, 350 f,
312 "*{}", 351 "*{}",
@@ -328,7 +367,7 @@ impl HirDisplay for Ty {
328 367
329 // FIXME: all this just to decide whether to use parentheses... 368 // FIXME: all this just to decide whether to use parentheses...
330 let datas; 369 let datas;
331 let predicates: Vec<_> = match t.interned(&Interner) { 370 let predicates: Vec<_> = match t.kind(&Interner) {
332 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => { 371 TyKind::Dyn(dyn_ty) if dyn_ty.bounds.skip_binders().interned().len() > 1 => {
333 dyn_ty.bounds.skip_binders().interned().iter().cloned().collect() 372 dyn_ty.bounds.skip_binders().interned().iter().cloned().collect()
334 } 373 }
@@ -344,8 +383,8 @@ impl HirDisplay for Ty {
344 let data = (*datas) 383 let data = (*datas)
345 .as_ref() 384 .as_ref()
346 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 385 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
347 let bounds = data.subst(parameters); 386 let bounds = data.substitute(&Interner, parameters);
348 bounds.value 387 bounds.into_value_and_skipped_binders().0
349 } else { 388 } else {
350 Vec::new() 389 Vec::new()
351 } 390 }
@@ -360,26 +399,26 @@ impl HirDisplay for Ty {
360 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_) 399 if fn_traits(f.db.upcast(), trait_).any(|it| it == trait_)
361 && predicates.len() <= 2 400 && predicates.len() <= 2
362 { 401 {
363 return write!(f, "{}", ty_display); 402 return t.hir_fmt(f);
364 } 403 }
365 } 404 }
366 405
367 if predicates.len() > 1 { 406 if predicates.len() > 1 {
368 write!(f, "(")?; 407 write!(f, "(")?;
369 write!(f, "{}", ty_display)?; 408 t.hir_fmt(f)?;
370 write!(f, ")")?; 409 write!(f, ")")?;
371 } else { 410 } else {
372 write!(f, "{}", ty_display)?; 411 t.hir_fmt(f)?;
373 } 412 }
374 } 413 }
375 TyKind::Tuple(_, substs) => { 414 TyKind::Tuple(_, substs) => {
376 if substs.len() == 1 { 415 if substs.len(&Interner) == 1 {
377 write!(f, "(")?; 416 write!(f, "(")?;
378 substs[0].hir_fmt(f)?; 417 substs.at(&Interner, 0).hir_fmt(f)?;
379 write!(f, ",)")?; 418 write!(f, ",)")?;
380 } else { 419 } else {
381 write!(f, "(")?; 420 write!(f, "(")?;
382 f.write_joined(&*substs.0, ", ")?; 421 f.write_joined(&*substs.as_slice(&Interner), ", ")?;
383 write!(f, ")")?; 422 write!(f, ")")?;
384 } 423 }
385 } 424 }
@@ -389,7 +428,7 @@ impl HirDisplay for Ty {
389 } 428 }
390 TyKind::FnDef(def, parameters) => { 429 TyKind::FnDef(def, parameters) => {
391 let def = from_chalk(f.db, *def); 430 let def = from_chalk(f.db, *def);
392 let sig = f.db.callable_item_signature(def).subst(parameters); 431 let sig = f.db.callable_item_signature(def).substitute(&Interner, parameters);
393 match def { 432 match def {
394 CallableDefId::FunctionId(ff) => { 433 CallableDefId::FunctionId(ff) => {
395 write!(f, "fn {}", f.db.function_data(ff).name)? 434 write!(f, "fn {}", f.db.function_data(ff).name)?
@@ -399,7 +438,7 @@ impl HirDisplay for Ty {
399 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)? 438 write!(f, "{}", f.db.enum_data(e.parent).variants[e.local_id].name)?
400 } 439 }
401 }; 440 };
402 if parameters.len() > 0 { 441 if parameters.len(&Interner) > 0 {
403 let generics = generics(f.db.upcast(), def.into()); 442 let generics = generics(f.db.upcast(), def.into());
404 let (parent_params, self_param, type_params, _impl_trait_params) = 443 let (parent_params, self_param, type_params, _impl_trait_params) =
405 generics.provenance_split(); 444 generics.provenance_split();
@@ -407,7 +446,7 @@ impl HirDisplay for Ty {
407 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self? 446 // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
408 if total_len > 0 { 447 if total_len > 0 {
409 write!(f, "<")?; 448 write!(f, "<")?;
410 f.write_joined(&parameters.0[..total_len], ", ")?; 449 f.write_joined(&parameters.as_slice(&Interner)[..total_len], ", ")?;
411 write!(f, ">")?; 450 write!(f, ">")?;
412 } 451 }
413 } 452 }
@@ -415,15 +454,9 @@ impl HirDisplay for Ty {
415 f.write_joined(sig.params(), ", ")?; 454 f.write_joined(sig.params(), ", ")?;
416 write!(f, ")")?; 455 write!(f, ")")?;
417 let ret = sig.ret(); 456 let ret = sig.ret();
418 if *ret != Ty::unit() { 457 if !ret.is_unit() {
419 let ret_display = ret.into_displayable( 458 write!(f, " -> ")?;
420 f.db, 459 ret.hir_fmt(f)?;
421 f.max_size,
422 f.omit_verbose_types,
423 f.display_target,
424 );
425
426 write!(f, " -> {}", ret_display)?;
427 } 460 }
428 } 461 }
429 TyKind::Adt(AdtId(def_id), parameters) => { 462 TyKind::Adt(AdtId(def_id), parameters) => {
@@ -451,7 +484,7 @@ impl HirDisplay for Ty {
451 } 484 }
452 } 485 }
453 486
454 if parameters.len() > 0 { 487 if parameters.len(&Interner) > 0 {
455 let parameters_to_write = if f.display_target.is_source_code() 488 let parameters_to_write = if f.display_target.is_source_code()
456 || f.omit_verbose_types() 489 || f.omit_verbose_types()
457 { 490 {
@@ -460,30 +493,35 @@ impl HirDisplay for Ty {
460 .map(|generic_def_id| f.db.generic_defaults(generic_def_id)) 493 .map(|generic_def_id| f.db.generic_defaults(generic_def_id))
461 .filter(|defaults| !defaults.is_empty()) 494 .filter(|defaults| !defaults.is_empty())
462 { 495 {
463 None => parameters.0.as_ref(), 496 None => parameters.as_slice(&Interner),
464 Some(default_parameters) => { 497 Some(default_parameters) => {
465 let mut default_from = 0; 498 let mut default_from = 0;
466 for (i, parameter) in parameters.iter().enumerate() { 499 for (i, parameter) in parameters.iter(&Interner).enumerate() {
467 match (parameter.interned(&Interner), default_parameters.get(i)) 500 match (
468 { 501 parameter.assert_ty_ref(&Interner).kind(&Interner),
469 (&TyKind::Unknown, _) | (_, None) => { 502 default_parameters.get(i),
503 ) {
504 (&TyKind::Error, _) | (_, None) => {
470 default_from = i + 1; 505 default_from = i + 1;
471 } 506 }
472 (_, Some(default_parameter)) => { 507 (_, Some(default_parameter)) => {
473 let actual_default = default_parameter 508 let actual_default =
474 .clone() 509 default_parameter.clone().substitute(
475 .subst(&parameters.prefix(i)); 510 &Interner,
476 if parameter != &actual_default { 511 &subst_prefix(parameters, i),
512 );
513 if parameter.assert_ty_ref(&Interner) != &actual_default
514 {
477 default_from = i + 1; 515 default_from = i + 1;
478 } 516 }
479 } 517 }
480 } 518 }
481 } 519 }
482 &parameters.0[0..default_from] 520 &parameters.as_slice(&Interner)[0..default_from]
483 } 521 }
484 } 522 }
485 } else { 523 } else {
486 parameters.0.as_ref() 524 parameters.as_slice(&Interner)
487 }; 525 };
488 if !parameters_to_write.is_empty() { 526 if !parameters_to_write.is_empty() {
489 write!(f, "<")?; 527 write!(f, "<")?;
@@ -504,9 +542,9 @@ impl HirDisplay for Ty {
504 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types) 542 // Use placeholder associated types when the target is test (https://rust-lang.github.io/chalk/book/clauses/type_equality.html#placeholder-associated-types)
505 if f.display_target.is_test() { 543 if f.display_target.is_test() {
506 write!(f, "{}::{}", trait_.name, type_alias_data.name)?; 544 write!(f, "{}::{}", trait_.name, type_alias_data.name)?;
507 if parameters.len() > 0 { 545 if parameters.len(&Interner) > 0 {
508 write!(f, "<")?; 546 write!(f, "<")?;
509 f.write_joined(&*parameters.0, ", ")?; 547 f.write_joined(&*parameters.as_slice(&Interner), ", ")?;
510 write!(f, ">")?; 548 write!(f, ">")?;
511 } 549 }
512 } else { 550 } else {
@@ -518,7 +556,7 @@ impl HirDisplay for Ty {
518 projection_ty.hir_fmt(f)?; 556 projection_ty.hir_fmt(f)?;
519 } 557 }
520 } 558 }
521 TyKind::ForeignType(type_alias) => { 559 TyKind::Foreign(type_alias) => {
522 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias)); 560 let type_alias = f.db.type_alias_data(from_foreign_def_id(*type_alias));
523 write!(f, "{}", type_alias.name)?; 561 write!(f, "{}", type_alias.name)?;
524 } 562 }
@@ -531,13 +569,13 @@ impl HirDisplay for Ty {
531 let data = (*datas) 569 let data = (*datas)
532 .as_ref() 570 .as_ref()
533 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 571 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
534 let bounds = data.subst(&parameters); 572 let bounds = data.substitute(&Interner, &parameters);
535 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?; 573 write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
536 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution 574 // FIXME: it would maybe be good to distinguish this from the alias type (when debug printing), and to show the substitution
537 } 575 }
538 ImplTraitId::AsyncBlockTypeImplTrait(..) => { 576 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
539 write!(f, "impl Future<Output = ")?; 577 write!(f, "impl Future<Output = ")?;
540 parameters[0].hir_fmt(f)?; 578 parameters.at(&Interner, 0).hir_fmt(f)?;
541 write!(f, ">")?; 579 write!(f, ">")?;
542 } 580 }
543 } 581 }
@@ -548,7 +586,7 @@ impl HirDisplay for Ty {
548 DisplaySourceCodeError::Closure, 586 DisplaySourceCodeError::Closure,
549 )); 587 ));
550 } 588 }
551 let sig = substs[0].callable_sig(f.db); 589 let sig = substs.at(&Interner, 0).assert_ty_ref(&Interner).callable_sig(f.db);
552 if let Some(sig) = sig { 590 if let Some(sig) = sig {
553 if sig.params().is_empty() { 591 if sig.params().is_empty() {
554 write!(f, "||")?; 592 write!(f, "||")?;
@@ -560,13 +598,8 @@ impl HirDisplay for Ty {
560 write!(f, "|")?; 598 write!(f, "|")?;
561 }; 599 };
562 600
563 let ret_display = sig.ret().into_displayable( 601 write!(f, " -> ")?;
564 f.db, 602 sig.ret().hir_fmt(f)?;
565 f.max_size,
566 f.omit_verbose_types,
567 f.display_target,
568 );
569 write!(f, " -> {}", ret_display)?;
570 } else { 603 } else {
571 write!(f, "{{closure}}")?; 604 write!(f, "{{closure}}")?;
572 } 605 }
@@ -580,26 +613,27 @@ impl HirDisplay for Ty {
580 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))? 613 write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
581 } 614 }
582 TypeParamProvenance::ArgumentImplTrait => { 615 TypeParamProvenance::ArgumentImplTrait => {
583 let substs = Substitution::type_params_for_generics(f.db, &generics); 616 let substs = generics.type_params_subst(f.db);
584 let bounds = f 617 let bounds =
585 .db 618 f.db.generic_predicates(id.parent)
586 .generic_predicates(id.parent) 619 .into_iter()
587 .into_iter() 620 .map(|pred| pred.clone().substitute(&Interner, &substs))
588 .map(|pred| pred.clone().subst(&substs)) 621 .filter(|wc| match &wc.skip_binders() {
589 .filter(|wc| match &wc.skip_binders() { 622 WhereClause::Implemented(tr) => {
590 WhereClause::Implemented(tr) => tr.self_type_parameter() == self, 623 &tr.self_type_parameter(&Interner) == self
591 WhereClause::AliasEq(AliasEq { 624 }
592 alias: AliasTy::Projection(proj), 625 WhereClause::AliasEq(AliasEq {
593 ty: _, 626 alias: AliasTy::Projection(proj),
594 }) => proj.self_type_parameter() == self, 627 ty: _,
595 _ => false, 628 }) => &proj.self_type_parameter(&Interner) == self,
596 }) 629 _ => false,
597 .collect::<Vec<_>>(); 630 })
631 .collect::<Vec<_>>();
598 write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?; 632 write_bounds_like_dyn_trait_with_prefix("impl", &bounds, f)?;
599 } 633 }
600 } 634 }
601 } 635 }
602 TyKind::BoundVar(idx) => write!(f, "?{}.{}", idx.debruijn.depth(), idx.index)?, 636 TyKind::BoundVar(idx) => idx.hir_fmt(f)?,
603 TyKind::Dyn(dyn_ty) => { 637 TyKind::Dyn(dyn_ty) => {
604 write_bounds_like_dyn_trait_with_prefix( 638 write_bounds_like_dyn_trait_with_prefix(
605 "dyn", 639 "dyn",
@@ -617,15 +651,15 @@ impl HirDisplay for Ty {
617 let data = (*datas) 651 let data = (*datas)
618 .as_ref() 652 .as_ref()
619 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); 653 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
620 let bounds = data.subst(&opaque_ty.substitution); 654 let bounds = data.substitute(&Interner, &opaque_ty.substitution);
621 write_bounds_like_dyn_trait_with_prefix("impl", &bounds.value, f)?; 655 write_bounds_like_dyn_trait_with_prefix("impl", bounds.skip_binders(), f)?;
622 } 656 }
623 ImplTraitId::AsyncBlockTypeImplTrait(..) => { 657 ImplTraitId::AsyncBlockTypeImplTrait(..) => {
624 write!(f, "{{async block}}")?; 658 write!(f, "{{async block}}")?;
625 } 659 }
626 }; 660 };
627 } 661 }
628 TyKind::Unknown => { 662 TyKind::Error => {
629 if f.display_target.is_source_code() { 663 if f.display_target.is_source_code() {
630 return Err(HirDisplayError::DisplaySourceCodeError( 664 return Err(HirDisplayError::DisplaySourceCodeError(
631 DisplaySourceCodeError::UnknownType, 665 DisplaySourceCodeError::UnknownType,
@@ -634,6 +668,8 @@ impl HirDisplay for Ty {
634 write!(f, "{{unknown}}")?; 668 write!(f, "{{unknown}}")?;
635 } 669 }
636 TyKind::InferenceVar(..) => write!(f, "_")?, 670 TyKind::InferenceVar(..) => write!(f, "_")?,
671 TyKind::Generator(..) => write!(f, "{{generator}}")?,
672 TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
637 } 673 }
638 Ok(()) 674 Ok(())
639 } 675 }
@@ -652,10 +688,9 @@ impl HirDisplay for CallableSig {
652 } 688 }
653 write!(f, ")")?; 689 write!(f, ")")?;
654 let ret = self.ret(); 690 let ret = self.ret();
655 if *ret != Ty::unit() { 691 if !ret.is_unit() {
656 let ret_display = 692 write!(f, " -> ")?;
657 ret.into_displayable(f.db, f.max_size, f.omit_verbose_types, f.display_target); 693 ret.hir_fmt(f)?;
658 write!(f, " -> {}", ret_display)?;
659 } 694 }
660 Ok(()) 695 Ok(())
661 } 696 }
@@ -712,15 +747,17 @@ fn write_bounds_like_dyn_trait(
712 if !first { 747 if !first {
713 write!(f, " + ")?; 748 write!(f, " + ")?;
714 } 749 }
715 // We assume that the self type is $0 (i.e. the 750 // We assume that the self type is ^0.0 (i.e. the
716 // existential) here, which is the only thing that's 751 // existential) here, which is the only thing that's
717 // possible in actual Rust, and hence don't print it 752 // possible in actual Rust, and hence don't print it
718 write!(f, "{}", f.db.trait_data(trait_).name)?; 753 write!(f, "{}", f.db.trait_data(trait_).name)?;
719 if let [_, params @ ..] = &*trait_ref.substitution.0 { 754 if let [_, params @ ..] = &*trait_ref.substitution.as_slice(&Interner) {
720 if is_fn_trait { 755 if is_fn_trait {
721 if let Some(args) = params.first().and_then(|it| it.as_tuple()) { 756 if let Some(args) =
757 params.first().and_then(|it| it.assert_ty_ref(&Interner).as_tuple())
758 {
722 write!(f, "(")?; 759 write!(f, "(")?;
723 f.write_joined(&*args.0, ", ")?; 760 f.write_joined(args.as_slice(&Interner), ", ")?;
724 write!(f, ")")?; 761 write!(f, ")")?;
725 } 762 }
726 } else if !params.is_empty() { 763 } else if !params.is_empty() {
@@ -752,6 +789,10 @@ fn write_bounds_like_dyn_trait(
752 } 789 }
753 ty.hir_fmt(f)?; 790 ty.hir_fmt(f)?;
754 } 791 }
792
793 // FIXME implement these
794 WhereClause::LifetimeOutlives(_) => {}
795 WhereClause::TypeOutlives(_) => {}
755 } 796 }
756 first = false; 797 first = false;
757 } 798 }
@@ -761,31 +802,29 @@ fn write_bounds_like_dyn_trait(
761 Ok(()) 802 Ok(())
762} 803}
763 804
764impl TraitRef { 805fn fmt_trait_ref(tr: &TraitRef, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> {
765 fn hir_fmt_ext(&self, f: &mut HirFormatter, use_as: bool) -> Result<(), HirDisplayError> { 806 if f.should_truncate() {
766 if f.should_truncate() { 807 return write!(f, "{}", TYPE_HINT_TRUNCATION);
767 return write!(f, "{}", TYPE_HINT_TRUNCATION); 808 }
768 }
769 809
770 self.substitution[0].hir_fmt(f)?; 810 tr.self_type_parameter(&Interner).hir_fmt(f)?;
771 if use_as { 811 if use_as {
772 write!(f, " as ")?; 812 write!(f, " as ")?;
773 } else { 813 } else {
774 write!(f, ": ")?; 814 write!(f, ": ")?;
775 } 815 }
776 write!(f, "{}", f.db.trait_data(self.hir_trait_id()).name)?; 816 write!(f, "{}", f.db.trait_data(tr.hir_trait_id()).name)?;
777 if self.substitution.len() > 1 { 817 if tr.substitution.len(&Interner) > 1 {
778 write!(f, "<")?; 818 write!(f, "<")?;
779 f.write_joined(&self.substitution[1..], ", ")?; 819 f.write_joined(&tr.substitution.as_slice(&Interner)[1..], ", ")?;
780 write!(f, ">")?; 820 write!(f, ">")?;
781 }
782 Ok(())
783 } 821 }
822 Ok(())
784} 823}
785 824
786impl HirDisplay for TraitRef { 825impl HirDisplay for TraitRef {
787 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 826 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
788 self.hir_fmt_ext(f, false) 827 fmt_trait_ref(self, f, false)
789 } 828 }
790} 829}
791 830
@@ -799,7 +838,7 @@ impl HirDisplay for WhereClause {
799 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?, 838 WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
800 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => { 839 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
801 write!(f, "<")?; 840 write!(f, "<")?;
802 projection_ty.trait_ref(f.db).hir_fmt_ext(f, true)?; 841 fmt_trait_ref(&projection_ty.trait_ref(f.db), f, true)?;
803 write!( 842 write!(
804 f, 843 f,
805 ">::{} = ", 844 ">::{} = ",
@@ -808,20 +847,44 @@ impl HirDisplay for WhereClause {
808 ty.hir_fmt(f)?; 847 ty.hir_fmt(f)?;
809 } 848 }
810 WhereClause::AliasEq(_) => write!(f, "{{error}}")?, 849 WhereClause::AliasEq(_) => write!(f, "{{error}}")?,
850
851 // FIXME implement these
852 WhereClause::TypeOutlives(..) => {}
853 WhereClause::LifetimeOutlives(..) => {}
811 } 854 }
812 Ok(()) 855 Ok(())
813 } 856 }
814} 857}
815 858
859impl HirDisplay for LifetimeOutlives {
860 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
861 self.a.hir_fmt(f)?;
862 write!(f, ": ")?;
863 self.b.hir_fmt(f)
864 }
865}
866
816impl HirDisplay for Lifetime { 867impl HirDisplay for Lifetime {
817 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 868 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
869 self.interned().hir_fmt(f)
870 }
871}
872
873impl HirDisplay for LifetimeData {
874 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
818 match self { 875 match self {
819 Lifetime::Parameter(id) => { 876 LifetimeData::BoundVar(idx) => idx.hir_fmt(f),
877 LifetimeData::InferenceVar(_) => write!(f, "_"),
878 LifetimeData::Placeholder(idx) => {
879 let id = lt_from_placeholder_idx(f.db, *idx);
820 let generics = generics(f.db.upcast(), id.parent); 880 let generics = generics(f.db.upcast(), id.parent);
821 let param_data = &generics.params.lifetimes[id.local_id]; 881 let param_data = &generics.params.lifetimes[id.local_id];
822 write!(f, "{}", &param_data.name) 882 write!(f, "{}", param_data.name)
823 } 883 }
824 Lifetime::Static => write!(f, "'static"), 884 LifetimeData::Static => write!(f, "'static"),
885 LifetimeData::Empty(_) => Ok(()),
886 LifetimeData::Erased => Ok(()),
887 LifetimeData::Phantom(_, _) => Ok(()),
825 } 888 }
826 } 889 }
827} 890}
@@ -832,9 +895,11 @@ impl HirDisplay for DomainGoal {
832 DomainGoal::Holds(wc) => { 895 DomainGoal::Holds(wc) => {
833 write!(f, "Holds(")?; 896 write!(f, "Holds(")?;
834 wc.hir_fmt(f)?; 897 wc.hir_fmt(f)?;
835 write!(f, ")") 898 write!(f, ")")?;
836 } 899 }
900 _ => write!(f, "?")?,
837 } 901 }
902 Ok(())
838 } 903 }
839} 904}
840 905
@@ -1016,11 +1081,11 @@ impl HirDisplay for Path {
1016 } 1081 }
1017} 1082}
1018 1083
1019impl HirDisplay for GenericArg { 1084impl HirDisplay for hir_def::path::GenericArg {
1020 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> { 1085 fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
1021 match self { 1086 match self {
1022 GenericArg::Type(ty) => ty.hir_fmt(f), 1087 hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
1023 GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name), 1088 hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
1024 } 1089 }
1025 } 1090 }
1026} 1091}
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index e4407ff50..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, Substitution, 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, to_chalk_trait_id, AliasEq, AliasTy, Interner, 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 }
@@ -210,6 +201,7 @@ struct InferenceContext<'a> {
210 table: unify::InferenceTable, 201 table: unify::InferenceTable,
211 trait_env: Arc<TraitEnvironment>, 202 trait_env: Arc<TraitEnvironment>,
212 obligations: Vec<DomainGoal>, 203 obligations: Vec<DomainGoal>,
204 last_obligations_check: Option<u32>,
213 result: InferenceResult, 205 result: InferenceResult,
214 /// The return type of the function being inferred, or the closure if we're 206 /// The return type of the function being inferred, or the closure if we're
215 /// currently within one. 207 /// currently within one.
@@ -245,7 +237,8 @@ impl<'a> InferenceContext<'a> {
245 result: InferenceResult::default(), 237 result: InferenceResult::default(),
246 table: unify::InferenceTable::new(), 238 table: unify::InferenceTable::new(),
247 obligations: Vec::default(), 239 obligations: Vec::default(),
248 return_ty: TyKind::Unknown.intern(&Interner), // set in collect_fn_signature 240 last_obligations_check: None,
241 return_ty: TyKind::Error.intern(&Interner), // set in collect_fn_signature
249 trait_env: owner 242 trait_env: owner
250 .as_generic_def_id() 243 .as_generic_def_id()
251 .map_or_else(Default::default, |d| db.trait_environment(d)), 244 .map_or_else(Default::default, |d| db.trait_environment(d)),
@@ -259,7 +252,7 @@ impl<'a> InferenceContext<'a> {
259 } 252 }
260 253
261 fn err_ty(&self) -> Ty { 254 fn err_ty(&self) -> Ty {
262 TyKind::Unknown.intern(&Interner) 255 TyKind::Error.intern(&Interner)
263 } 256 }
264 257
265 fn resolve_all(mut self) -> InferenceResult { 258 fn resolve_all(mut self) -> InferenceResult {
@@ -323,30 +316,44 @@ impl<'a> InferenceContext<'a> {
323 316
324 /// 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.
325 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty { 318 fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
326 match ty.interned(&Interner) { 319 match ty.kind(&Interner) {
327 TyKind::Unknown => self.table.new_type_var(), 320 TyKind::Error => self.table.new_type_var(),
328 _ => ty, 321 _ => ty,
329 } 322 }
330 } 323 }
331 324
332 fn insert_type_vars(&mut self, ty: Ty) -> Ty { 325 fn insert_type_vars(&mut self, ty: Ty) -> Ty {
333 ty.fold(&mut |ty| self.insert_type_vars_shallow(ty)) 326 fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
334 } 327 }
335 328
336 fn resolve_obligations_as_possible(&mut self) { 329 fn resolve_obligations_as_possible(&mut self) {
330 if self.last_obligations_check == Some(self.table.revision) {
331 // no change
332 return;
333 }
334 let _span = profile::span("resolve_obligations_as_possible");
335
336 self.last_obligations_check = Some(self.table.revision);
337 let obligations = mem::replace(&mut self.obligations, Vec::new()); 337 let obligations = mem::replace(&mut self.obligations, Vec::new());
338 for obligation in obligations { 338 for obligation in obligations {
339 let in_env = InEnvironment::new(self.trait_env.env.clone(), obligation.clone()); 339 let in_env = InEnvironment::new(&self.trait_env.env, obligation.clone());
340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env); 340 let canonicalized = self.canonicalizer().canonicalize_obligation(in_env);
341 let solution = 341 let solution =
342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone()); 342 self.db.trait_solve(self.resolver.krate().unwrap(), canonicalized.value.clone());
343 343
344 match solution { 344 match solution {
345 Some(Solution::Unique(substs)) => { 345 Some(Solution::Unique(canonical_subst)) => {
346 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 );
347 } 354 }
348 Some(Solution::Ambig(Guidance::Definite(substs))) => { 355 Some(Solution::Ambig(Guidance::Definite(substs))) => {
349 canonicalized.apply_solution(self, substs.0); 356 canonicalized.apply_solution(self, substs);
350 self.obligations.push(obligation); 357 self.obligations.push(obligation);
351 } 358 }
352 Some(_) => { 359 Some(_) => {
@@ -360,6 +367,11 @@ impl<'a> InferenceContext<'a> {
360 } 367 }
361 } 368 }
362 369
370 fn push_obligation(&mut self, o: DomainGoal) {
371 self.obligations.push(o);
372 self.last_obligations_check = None;
373 }
374
363 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool { 375 fn unify(&mut self, ty1: &Ty, ty2: &Ty) -> bool {
364 self.table.unify(ty1, ty2) 376 self.table.unify(ty1, ty2)
365 } 377 }
@@ -395,21 +407,19 @@ impl<'a> InferenceContext<'a> {
395 _ => panic!("resolve_associated_type called with non-associated type"), 407 _ => panic!("resolve_associated_type called with non-associated type"),
396 }; 408 };
397 let ty = self.table.new_type_var(); 409 let ty = self.table.new_type_var();
398 let substs = Substitution::build_for_def(self.db, res_assoc_ty) 410 let trait_ref = TyBuilder::trait_ref(self.db, trait_)
399 .push(inner_ty) 411 .push(inner_ty)
400 .fill(params.iter().cloned()) 412 .fill(params.iter().cloned())
401 .build(); 413 .build();
402 let trait_ref =
403 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs.clone() };
404 let alias_eq = AliasEq { 414 let alias_eq = AliasEq {
405 alias: AliasTy::Projection(ProjectionTy { 415 alias: AliasTy::Projection(ProjectionTy {
406 associated_ty_id: to_assoc_type_id(res_assoc_ty), 416 associated_ty_id: to_assoc_type_id(res_assoc_ty),
407 substitution: substs, 417 substitution: trait_ref.substitution.clone(),
408 }), 418 }),
409 ty: ty.clone(), 419 ty: ty.clone(),
410 }; 420 };
411 self.obligations.push(trait_ref.cast(&Interner)); 421 self.push_obligation(trait_ref.cast(&Interner));
412 self.obligations.push(alias_eq.cast(&Interner)); 422 self.push_obligation(alias_eq.cast(&Interner));
413 self.resolve_ty_as_possible(ty) 423 self.resolve_ty_as_possible(ty)
414 } 424 }
415 None => self.err_ty(), 425 None => self.err_ty(),
@@ -424,19 +434,23 @@ impl<'a> InferenceContext<'a> {
424 /// to do it as well. 434 /// to do it as well.
425 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty { 435 fn normalize_associated_types_in(&mut self, ty: Ty) -> Ty {
426 let ty = self.resolve_ty_as_possible(ty); 436 let ty = self.resolve_ty_as_possible(ty);
427 ty.fold(&mut |ty| match ty.interned(&Interner) { 437 fold_tys(
428 TyKind::Alias(AliasTy::Projection(proj_ty)) => { 438 ty,
429 self.normalize_projection_ty(proj_ty.clone()) 439 |ty, _| match ty.kind(&Interner) {
430 } 440 TyKind::Alias(AliasTy::Projection(proj_ty)) => {
431 _ => ty, 441 self.normalize_projection_ty(proj_ty.clone())
432 }) 442 }
443 _ => ty,
444 },
445 DebruijnIndex::INNERMOST,
446 )
433 } 447 }
434 448
435 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty { 449 fn normalize_projection_ty(&mut self, proj_ty: ProjectionTy) -> Ty {
436 let var = self.table.new_type_var(); 450 let var = self.table.new_type_var();
437 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() }; 451 let alias_eq = AliasEq { alias: AliasTy::Projection(proj_ty), ty: var.clone() };
438 let obligation = alias_eq.cast(&Interner); 452 let obligation = alias_eq.cast(&Interner);
439 self.obligations.push(obligation); 453 self.push_obligation(obligation);
440 var 454 var
441 } 455 }
442 456
@@ -458,56 +472,32 @@ impl<'a> InferenceContext<'a> {
458 TypeNs::AdtId(AdtId::StructId(strukt)) => { 472 TypeNs::AdtId(AdtId::StructId(strukt)) => {
459 let substs = ctx.substs_from_path(path, strukt.into(), true); 473 let substs = ctx.substs_from_path(path, strukt.into(), true);
460 let ty = self.db.ty(strukt.into()); 474 let ty = self.db.ty(strukt.into());
461 let ty = self.insert_type_vars(ty.subst(&substs)); 475 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
462 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved) 476 forbid_unresolved_segments((ty, Some(strukt.into())), unresolved)
463 } 477 }
464 TypeNs::AdtId(AdtId::UnionId(u)) => { 478 TypeNs::AdtId(AdtId::UnionId(u)) => {
465 let substs = ctx.substs_from_path(path, u.into(), true); 479 let substs = ctx.substs_from_path(path, u.into(), true);
466 let ty = self.db.ty(u.into()); 480 let ty = self.db.ty(u.into());
467 let ty = self.insert_type_vars(ty.subst(&substs)); 481 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
468 forbid_unresolved_segments((ty, Some(u.into())), unresolved) 482 forbid_unresolved_segments((ty, Some(u.into())), unresolved)
469 } 483 }
470 TypeNs::EnumVariantId(var) => { 484 TypeNs::EnumVariantId(var) => {
471 let substs = ctx.substs_from_path(path, var.into(), true); 485 let substs = ctx.substs_from_path(path, var.into(), true);
472 let ty = self.db.ty(var.parent.into()); 486 let ty = self.db.ty(var.parent.into());
473 let ty = self.insert_type_vars(ty.subst(&substs)); 487 let ty = self.insert_type_vars(ty.substitute(&Interner, &substs));
474 forbid_unresolved_segments((ty, Some(var.into())), unresolved) 488 forbid_unresolved_segments((ty, Some(var.into())), unresolved)
475 } 489 }
476 TypeNs::SelfType(impl_id) => { 490 TypeNs::SelfType(impl_id) => {
477 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 491 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
478 let substs = Substitution::type_params_for_generics(self.db, &generics); 492 let substs = generics.type_params_subst(self.db);
479 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 493 let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs);
480 match unresolved { 494 self.resolve_variant_on_alias(ty, unresolved, path)
481 None => {
482 let variant = ty_variant(&ty);
483 (ty, variant)
484 }
485 Some(1) => {
486 let segment = path.mod_path().segments().last().unwrap();
487 // this could be an enum variant or associated type
488 if let Some((AdtId::EnumId(enum_id), _)) = ty.as_adt() {
489 let enum_data = self.db.enum_data(enum_id);
490 if let Some(local_id) = enum_data.variant(segment) {
491 let variant = EnumVariantId { parent: enum_id, local_id };
492 return (ty, Some(variant.into()));
493 }
494 }
495 // FIXME potentially resolve assoc type
496 (self.err_ty(), None)
497 }
498 Some(_) => {
499 // FIXME diagnostic
500 (self.err_ty(), None)
501 }
502 }
503 } 495 }
504 TypeNs::TypeAliasId(it) => { 496 TypeNs::TypeAliasId(it) => {
505 let substs = Substitution::build_for_def(self.db, it) 497 let ty = TyBuilder::def_ty(self.db, it.into())
506 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 498 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
507 .build(); 499 .build();
508 let ty = self.db.ty(it.into()).subst(&substs); 500 self.resolve_variant_on_alias(ty, unresolved, path)
509 let variant = ty_variant(&ty);
510 forbid_unresolved_segments((ty, variant), unresolved)
511 } 501 }
512 TypeNs::AdtSelfType(_) => { 502 TypeNs::AdtSelfType(_) => {
513 // 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
@@ -531,19 +521,46 @@ impl<'a> InferenceContext<'a> {
531 result 521 result
532 } else { 522 } else {
533 // FIXME diagnostic 523 // FIXME diagnostic
534 (TyKind::Unknown.intern(&Interner), None) 524 (TyKind::Error.intern(&Interner), None)
535 } 525 }
536 } 526 }
527 }
537 528
538 fn ty_variant(ty: &Ty) -> Option<VariantId> { 529 fn resolve_variant_on_alias(
539 ty.as_adt().and_then(|(adt_id, _)| match adt_id { 530 &mut self,
540 AdtId::StructId(s) => Some(VariantId::StructId(s)), 531 ty: Ty,
541 AdtId::UnionId(u) => Some(VariantId::UnionId(u)), 532 unresolved: Option<usize>,
542 AdtId::EnumId(_) => { 533 path: &Path,
543 // FIXME Error E0071, expected struct, variant or union type, found enum `Foo` 534 ) -> (Ty, Option<VariantId>) {
544 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 }
545 } 556 }
546 }) 557 // FIXME potentially resolve assoc type
558 (self.err_ty(), None)
559 }
560 Some(_) => {
561 // FIXME diagnostic
562 (self.err_ty(), None)
563 }
547 } 564 }
548 } 565 }
549 566
@@ -681,25 +698,6 @@ impl<'a> InferenceContext<'a> {
681 } 698 }
682} 699}
683 700
684/// The kinds of placeholders we need during type inference. There's separate
685/// values for general types, and for integer and float variables. The latter
686/// two are used for inference of literal values (e.g. `100` could be one of
687/// several integer types).
688#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug)]
689pub struct InferenceVar {
690 index: u32,
691}
692
693impl InferenceVar {
694 fn to_inner(self) -> unify::TypeVarId {
695 unify::TypeVarId(self.index)
696 }
697
698 fn from_inner(unify::TypeVarId(index): unify::TypeVarId) -> Self {
699 InferenceVar { index }
700 }
701}
702
703/// When inferring an expression, we propagate downward whatever type hint we 701/// When inferring an expression, we propagate downward whatever type hint we
704/// are able in the form of an `Expectation`. 702/// are able in the form of an `Expectation`.
705#[derive(Clone, PartialEq, Eq, Debug)] 703#[derive(Clone, PartialEq, Eq, Debug)]
@@ -744,7 +742,7 @@ impl Expectation {
744 fn none() -> Self { 742 fn none() -> Self {
745 Expectation { 743 Expectation {
746 // FIXME 744 // FIXME
747 ty: TyKind::Unknown.intern(&Interner), 745 ty: TyKind::Error.intern(&Interner),
748 rvalue_hint: false, 746 rvalue_hint: false,
749 } 747 }
750 } 748 }
@@ -752,7 +750,7 @@ impl Expectation {
752 fn coercion_target(&self) -> Ty { 750 fn coercion_target(&self) -> Ty {
753 if self.rvalue_hint { 751 if self.rvalue_hint {
754 // FIXME 752 // FIXME
755 TyKind::Unknown.intern(&Interner) 753 TyKind::Error.intern(&Interner)
756 } else { 754 } else {
757 self.ty.clone() 755 self.ty.clone()
758 } 756 }
diff --git a/crates/hir_ty/src/infer/coerce.rs b/crates/hir_ty/src/infer/coerce.rs
index 9c62932b1..1f463a425 100644
--- a/crates/hir_ty/src/infer/coerce.rs
+++ b/crates/hir_ty/src/infer/coerce.rs
@@ -7,9 +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::{ 10use crate::{autoderef, Canonical, Interner, Solution, Ty, TyBuilder, TyExt, TyKind};
11 autoderef, to_chalk_trait_id, traits::Solution, Interner, Substitution, TraitRef, Ty, TyKind,
12};
13 11
14use super::{InEnvironment, InferenceContext}; 12use super::{InEnvironment, InferenceContext};
15 13
@@ -36,7 +34,7 @@ impl<'a> InferenceContext<'a> {
36 ty1.clone() 34 ty1.clone()
37 } else { 35 } else {
38 if let (TyKind::FnDef(..), TyKind::FnDef(..)) = 36 if let (TyKind::FnDef(..), TyKind::FnDef(..)) =
39 (ty1.interned(&Interner), ty2.interned(&Interner)) 37 (ty1.kind(&Interner), ty2.kind(&Interner))
40 { 38 {
41 cov_mark::hit!(coerce_fn_reification); 39 cov_mark::hit!(coerce_fn_reification);
42 // Special case: two function types. Try to coerce both to 40 // Special case: two function types. Try to coerce both to
@@ -44,8 +42,8 @@ impl<'a> InferenceContext<'a> {
44 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916 42 // https://github.com/rust-lang/rust/blob/7b805396bf46dce972692a6846ce2ad8481c5f85/src/librustc_typeck/check/coercion.rs#L877-L916
45 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig"); 43 let sig1 = ty1.callable_sig(self.db).expect("FnDef without callable sig");
46 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig"); 44 let sig2 = ty2.callable_sig(self.db).expect("FnDef without callable sig");
47 let ptr_ty1 = Ty::fn_ptr(sig1); 45 let ptr_ty1 = TyBuilder::fn_ptr(sig1);
48 let ptr_ty2 = Ty::fn_ptr(sig2); 46 let ptr_ty2 = TyBuilder::fn_ptr(sig2);
49 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) 47 self.coerce_merge_branch(&ptr_ty1, &ptr_ty2)
50 } else { 48 } else {
51 cov_mark::hit!(coerce_merge_fail_fallback); 49 cov_mark::hit!(coerce_merge_fail_fallback);
@@ -55,7 +53,7 @@ impl<'a> InferenceContext<'a> {
55 } 53 }
56 54
57 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool { 55 fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
58 match (from_ty.interned(&Interner), to_ty.interned(&Interner)) { 56 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
59 // Never type will make type variable to fallback to Never Type instead of Unknown. 57 // Never type will make type variable to fallback to Never Type instead of Unknown.
60 (TyKind::Never, TyKind::InferenceVar(tv, TyVariableKind::General)) => { 58 (TyKind::Never, TyKind::InferenceVar(tv, TyVariableKind::General)) => {
61 self.table.type_variable_table.set_diverging(*tv, true); 59 self.table.type_variable_table.set_diverging(*tv, true);
@@ -73,17 +71,19 @@ impl<'a> InferenceContext<'a> {
73 } 71 }
74 72
75 // Pointer weakening and function to pointer 73 // Pointer weakening and function to pointer
76 match (from_ty.interned_mut(), to_ty.interned(&Interner)) { 74 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
77 // `*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 }
78 // `&mut T` -> `&T` 79 // `&mut T` -> `&T`
79 (TyKind::Raw(m1, ..), TyKind::Raw(m2 @ Mutability::Not, ..)) 80 (TyKind::Ref(_, lt, inner), TyKind::Ref(m2 @ Mutability::Not, ..)) => {
80 | (TyKind::Ref(m1, ..), TyKind::Ref(m2 @ Mutability::Not, ..)) => { 81 from_ty = TyKind::Ref(*m2, lt.clone(), inner.clone()).intern(&Interner);
81 *m1 = *m2;
82 } 82 }
83 // `&T` -> `*const T` 83 // `&T` -> `*const T`
84 // `&mut T` -> `*mut T`/`*const T` 84 // `&mut T` -> `*mut T`/`*const T`
85 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..)) 85 (TyKind::Ref(.., substs), &TyKind::Raw(m2 @ Mutability::Not, ..))
86 | (TyKind::Ref(Mutability::Mut, substs), &TyKind::Raw(m2, ..)) => { 86 | (TyKind::Ref(Mutability::Mut, _, substs), &TyKind::Raw(m2, ..)) => {
87 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner); 87 from_ty = TyKind::Raw(m2, substs.clone()).intern(&Interner);
88 } 88 }
89 89
@@ -95,12 +95,12 @@ impl<'a> InferenceContext<'a> {
95 (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) { 95 (TyKind::FnDef(..), TyKind::Function { .. }) => match from_ty.callable_sig(self.db) {
96 None => return false, 96 None => return false,
97 Some(sig) => { 97 Some(sig) => {
98 from_ty = Ty::fn_ptr(sig); 98 from_ty = TyBuilder::fn_ptr(sig);
99 } 99 }
100 }, 100 },
101 101
102 (TyKind::Closure(.., substs), TyKind::Function { .. }) => { 102 (TyKind::Closure(.., substs), TyKind::Function { .. }) => {
103 from_ty = substs[0].clone(); 103 from_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner).clone();
104 } 104 }
105 105
106 _ => {} 106 _ => {}
@@ -111,9 +111,11 @@ impl<'a> InferenceContext<'a> {
111 } 111 }
112 112
113 // Auto Deref if cannot coerce 113 // Auto Deref if cannot coerce
114 match (from_ty.interned(&Interner), to_ty.interned(&Interner)) { 114 match (from_ty.kind(&Interner), to_ty.kind(&Interner)) {
115 // FIXME: DerefMut 115 // FIXME: DerefMut
116 (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 }
117 119
118 // Otherwise, normal unify 120 // Otherwise, normal unify
119 _ => self.unify(&from_ty, to_ty), 121 _ => self.unify(&from_ty, to_ty),
@@ -130,19 +132,16 @@ impl<'a> InferenceContext<'a> {
130 _ => return None, 132 _ => return None,
131 }; 133 };
132 134
133 let generic_params = crate::utils::generics(self.db.upcast(), coerce_unsized_trait.into()); 135 let trait_ref = {
134 if generic_params.len() != 2 { 136 let b = TyBuilder::trait_ref(self.db, coerce_unsized_trait);
135 // The CoerceUnsized trait should have two generic params: Self and T. 137 if b.remaining() != 2 {
136 return None; 138 // The CoerceUnsized trait should have two generic params: Self and T.
137 } 139 return None;
140 }
141 b.push(from_ty.clone()).push(to_ty.clone()).build()
142 };
138 143
139 let substs = Substitution::build_for_generics(&generic_params) 144 let goal = InEnvironment::new(&self.trait_env.env, trait_ref.cast(&Interner));
140 .push(from_ty.clone())
141 .push(to_ty.clone())
142 .build();
143 let trait_ref =
144 TraitRef { trait_id: to_chalk_trait_id(coerce_unsized_trait), substitution: substs };
145 let goal = InEnvironment::new(self.trait_env.env.clone(), trait_ref.cast(&Interner));
146 145
147 let canonicalizer = self.canonicalizer(); 146 let canonicalizer = self.canonicalizer();
148 let canonicalized = canonicalizer.canonicalize_obligation(goal); 147 let canonicalized = canonicalizer.canonicalize_obligation(goal);
@@ -151,7 +150,14 @@ impl<'a> InferenceContext<'a> {
151 150
152 match solution { 151 match solution {
153 Solution::Unique(v) => { 152 Solution::Unique(v) => {
154 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 );
155 } 161 }
156 _ => return None, 162 _ => return None,
157 }; 163 };
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index e6ede05ca..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_assoc_type_id, 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, DomainGoal, FnPointer, FnSig, Interner, Rawness, Scalar, 26 AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
26 Substitution, TraitRef, Ty, TyKind, 27 ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
27}; 28};
28 29
29use super::{ 30use super::{
@@ -73,38 +74,33 @@ impl<'a> InferenceContext<'a> {
73 let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; 74 let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?;
74 let output_assoc_type = 75 let output_assoc_type =
75 self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; 76 self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?;
76 let generic_params = generics(self.db.upcast(), fn_once_trait.into());
77 if generic_params.len() != 2 {
78 return None;
79 }
80 77
81 let mut param_builder = Substitution::builder(num_args);
82 let mut arg_tys = vec![]; 78 let mut arg_tys = vec![];
83 for _ in 0..num_args { 79 let arg_ty = TyBuilder::tuple(num_args)
84 let arg = self.table.new_type_var(); 80 .fill(repeat_with(|| {
85 param_builder = param_builder.push(arg.clone()); 81 let arg = self.table.new_type_var();
86 arg_tys.push(arg); 82 arg_tys.push(arg.clone());
87 } 83 arg
88 let parameters = param_builder.build(); 84 }))
89 let arg_ty = TyKind::Tuple(num_args, parameters).intern(&Interner); 85 .build();
90 let substs = 86
91 Substitution::build_for_generics(&generic_params).push(ty.clone()).push(arg_ty).build(); 87 let projection = {
88 let b = TyBuilder::assoc_type_projection(self.db, output_assoc_type);
89 if b.remaining() != 2 {
90 return None;
91 }
92 b.push(ty.clone()).push(arg_ty).build()
93 };
92 94
93 let trait_env = self.trait_env.env.clone(); 95 let trait_env = self.trait_env.env.clone();
94 let implements_fn_trait: DomainGoal = 96 let obligation = InEnvironment {
95 TraitRef { trait_id: to_chalk_trait_id(fn_once_trait), substitution: substs.clone() } 97 goal: projection.trait_ref(self.db).cast(&Interner),
96 .cast(&Interner);
97 let goal = self.canonicalizer().canonicalize_obligation(InEnvironment {
98 goal: implements_fn_trait.clone(),
99 environment: trait_env, 98 environment: trait_env,
100 }); 99 };
101 if self.db.trait_solve(krate, goal.value).is_some() { 100 let canonical = self.canonicalizer().canonicalize_obligation(obligation.clone());
102 self.obligations.push(implements_fn_trait); 101 if self.db.trait_solve(krate, canonical.value).is_some() {
103 let output_proj_ty = crate::ProjectionTy { 102 self.push_obligation(obligation.goal);
104 associated_ty_id: to_assoc_type_id(output_assoc_type), 103 let return_ty = self.normalize_projection_ty(projection);
105 substitution: substs,
106 };
107 let return_ty = self.normalize_projection_ty(output_proj_ty);
108 Some((arg_tys, return_ty)) 104 Some((arg_tys, return_ty))
109 } else { 105 } else {
110 None 106 None
@@ -119,6 +115,8 @@ impl<'a> InferenceContext<'a> {
119 } 115 }
120 116
121 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { 117 fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
118 self.db.check_canceled();
119
122 let body = Arc::clone(&self.body); // avoid borrow checker problem 120 let body = Arc::clone(&self.body); // avoid borrow checker problem
123 let ty = match &body[tgt_expr] { 121 let ty = match &body[tgt_expr] {
124 Expr::Missing => self.err_ty(), 122 Expr::Missing => self.err_ty(),
@@ -136,7 +134,7 @@ impl<'a> InferenceContext<'a> {
136 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe); 134 both_arms_diverge &= mem::replace(&mut self.diverges, Diverges::Maybe);
137 let else_ty = match else_branch { 135 let else_ty = match else_branch {
138 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected), 136 Some(else_branch) => self.infer_expr_inner(*else_branch, &expected),
139 None => Ty::unit(), 137 None => TyBuilder::unit(),
140 }; 138 };
141 both_arms_diverge &= self.diverges; 139 both_arms_diverge &= self.diverges;
142 140
@@ -183,7 +181,8 @@ impl<'a> InferenceContext<'a> {
183 let inner_ty = self.infer_expr(*body, &Expectation::none()); 181 let inner_ty = self.infer_expr(*body, &Expectation::none());
184 let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body); 182 let impl_trait_id = crate::ImplTraitId::AsyncBlockTypeImplTrait(self.owner, *body);
185 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();
186 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)
187 } 186 }
188 Expr::Loop { body, label } => { 187 Expr::Loop { body, label } => {
189 self.breakables.push(BreakableContext { 188 self.breakables.push(BreakableContext {
@@ -191,7 +190,7 @@ impl<'a> InferenceContext<'a> {
191 break_ty: self.table.new_type_var(), 190 break_ty: self.table.new_type_var(),
192 label: label.map(|label| self.body[label].name.clone()), 191 label: label.map(|label| self.body[label].name.clone()),
193 }); 192 });
194 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 193 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
195 194
196 let ctxt = self.breakables.pop().expect("breakable stack broken"); 195 let ctxt = self.breakables.pop().expect("breakable stack broken");
197 if ctxt.may_break { 196 if ctxt.may_break {
@@ -215,11 +214,11 @@ impl<'a> InferenceContext<'a> {
215 *condition, 214 *condition,
216 &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)), 215 &Expectation::has_type(TyKind::Scalar(Scalar::Bool).intern(&Interner)),
217 ); 216 );
218 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 217 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
219 let _ctxt = self.breakables.pop().expect("breakable stack broken"); 218 let _ctxt = self.breakables.pop().expect("breakable stack broken");
220 // the body may not run, so it diverging doesn't mean we diverge 219 // the body may not run, so it diverging doesn't mean we diverge
221 self.diverges = Diverges::Maybe; 220 self.diverges = Diverges::Maybe;
222 Ty::unit() 221 TyBuilder::unit()
223 } 222 }
224 Expr::For { iterable, body, pat, label } => { 223 Expr::For { iterable, body, pat, label } => {
225 let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); 224 let iterable_ty = self.infer_expr(*iterable, &Expectation::none());
@@ -234,11 +233,11 @@ impl<'a> InferenceContext<'a> {
234 233
235 self.infer_pat(*pat, &pat_ty, BindingMode::default()); 234 self.infer_pat(*pat, &pat_ty, BindingMode::default());
236 235
237 self.infer_expr(*body, &Expectation::has_type(Ty::unit())); 236 self.infer_expr(*body, &Expectation::has_type(TyBuilder::unit()));
238 let _ctxt = self.breakables.pop().expect("breakable stack broken"); 237 let _ctxt = self.breakables.pop().expect("breakable stack broken");
239 // the body may not run, so it diverging doesn't mean we diverge 238 // the body may not run, so it diverging doesn't mean we diverge
240 self.diverges = Diverges::Maybe; 239 self.diverges = Diverges::Maybe;
241 Ty::unit() 240 TyBuilder::unit()
242 } 241 }
243 Expr::Lambda { body, args, ret_type, arg_types } => { 242 Expr::Lambda { body, args, ret_type, arg_types } => {
244 assert_eq!(args.len(), arg_types.len()); 243 assert_eq!(args.len(), arg_types.len());
@@ -262,14 +261,17 @@ impl<'a> InferenceContext<'a> {
262 }; 261 };
263 sig_tys.push(ret_ty.clone()); 262 sig_tys.push(ret_ty.clone());
264 let sig_ty = TyKind::Function(FnPointer { 263 let sig_ty = TyKind::Function(FnPointer {
265 num_args: sig_tys.len() - 1, 264 num_binders: 0,
266 sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false }, 265 sig: FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic: false },
267 substs: Substitution(sig_tys.clone().into()), 266 substitution: FnSubst(
267 Substitution::from_iter(&Interner, sig_tys.clone()).shifted_in(&Interner),
268 ),
268 }) 269 })
269 .intern(&Interner); 270 .intern(&Interner);
270 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();
271 let closure_ty = 272 let closure_ty =
272 TyKind::Closure(closure_id, Substitution::single(sig_ty)).intern(&Interner); 273 TyKind::Closure(closure_id, Substitution::from1(&Interner, sig_ty))
274 .intern(&Interner);
273 275
274 // Eagerly try to relate the closure type with the expected 276 // Eagerly try to relate the closure type with the expected
275 // type, otherwise we often won't have enough information to 277 // type, otherwise we often won't have enough information to
@@ -316,7 +318,13 @@ impl<'a> InferenceContext<'a> {
316 self.normalize_associated_types_in(ret_ty) 318 self.normalize_associated_types_in(ret_ty)
317 } 319 }
318 Expr::MethodCall { receiver, args, method_name, generic_args } => self 320 Expr::MethodCall { receiver, args, method_name, generic_args } => self
319 .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 ),
320 Expr::Match { expr, arms } => { 328 Expr::Match { expr, arms } => {
321 let input_ty = self.infer_expr(*expr, &Expectation::none()); 329 let input_ty = self.infer_expr(*expr, &Expectation::none());
322 330
@@ -358,7 +366,7 @@ impl<'a> InferenceContext<'a> {
358 let val_ty = if let Some(expr) = expr { 366 let val_ty = if let Some(expr) = expr {
359 self.infer_expr(*expr, &Expectation::none()) 367 self.infer_expr(*expr, &Expectation::none())
360 } else { 368 } else {
361 Ty::unit() 369 TyBuilder::unit()
362 }; 370 };
363 371
364 let last_ty = 372 let last_ty =
@@ -384,7 +392,7 @@ impl<'a> InferenceContext<'a> {
384 if let Some(expr) = expr { 392 if let Some(expr) = expr {
385 self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone())); 393 self.infer_expr_coerce(*expr, &Expectation::has_type(self.return_ty.clone()));
386 } else { 394 } else {
387 let unit = Ty::unit(); 395 let unit = TyBuilder::unit();
388 self.coerce(&unit, &self.return_ty.clone()); 396 self.coerce(&unit, &self.return_ty.clone());
389 } 397 }
390 TyKind::Never.intern(&Interner) 398 TyKind::Never.intern(&Interner)
@@ -397,16 +405,19 @@ impl<'a> InferenceContext<'a> {
397 TyKind::Never.intern(&Interner) 405 TyKind::Never.intern(&Interner)
398 } 406 }
399 Expr::RecordLit { path, fields, spread } => { 407 Expr::RecordLit { path, fields, spread } => {
400 let (ty, def_id) = self.resolve_variant(path.as_ref()); 408 let (ty, def_id) = self.resolve_variant(path.as_deref());
401 if let Some(variant) = def_id { 409 if let Some(variant) = def_id {
402 self.write_variant_resolution(tgt_expr.into(), variant); 410 self.write_variant_resolution(tgt_expr.into(), variant);
403 } 411 }
404 412
405 self.unify(&ty, &expected.ty); 413 self.unify(&ty, &expected.ty);
406 414
407 let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); 415 let substs = ty
416 .as_adt()
417 .map(|(_, s)| s.clone())
418 .unwrap_or_else(|| Substitution::empty(&Interner));
408 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();
409 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()));
410 for field in fields.iter() { 421 for field in fields.iter() {
411 let field_def = 422 let field_def =
412 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) {
@@ -418,11 +429,8 @@ impl<'a> InferenceContext<'a> {
418 None 429 None
419 } 430 }
420 }); 431 });
421 if let Some(field_def) = field_def {
422 self.result.record_field_resolutions.insert(field.expr, field_def);
423 }
424 let field_ty = field_def.map_or(self.err_ty(), |it| { 432 let field_ty = field_def.map_or(self.err_ty(), |it| {
425 field_types[it.local_id].clone().subst(&substs) 433 field_types[it.local_id].clone().substitute(&Interner, &substs)
426 }); 434 });
427 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty)); 435 self.infer_expr_coerce(field.expr, &Expectation::has_type(field_ty));
428 } 436 }
@@ -453,10 +461,14 @@ impl<'a> InferenceContext<'a> {
453 }) 461 })
454 .unwrap_or(true) 462 .unwrap_or(true)
455 }; 463 };
456 match canonicalized.decanonicalize_ty(derefed_ty.value).interned(&Interner) { 464 match canonicalized.decanonicalize_ty(derefed_ty.value).kind(&Interner) {
457 TyKind::Tuple(_, substs) => { 465 TyKind::Tuple(_, substs) => name.as_tuple_index().and_then(|idx| {
458 name.as_tuple_index().and_then(|idx| substs.0.get(idx).cloned()) 466 substs
459 } 467 .as_slice(&Interner)
468 .get(idx)
469 .map(|a| a.assert_ty_ref(&Interner))
470 .cloned()
471 }),
460 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => { 472 TyKind::Adt(AdtId(hir_def::AdtId::StructId(s)), parameters) => {
461 let local_id = self.db.struct_data(*s).variant_data.field(name)?; 473 let local_id = self.db.struct_data(*s).variant_data.field(name)?;
462 let field = FieldId { parent: (*s).into(), local_id }; 474 let field = FieldId { parent: (*s).into(), local_id };
@@ -465,7 +477,7 @@ impl<'a> InferenceContext<'a> {
465 Some( 477 Some(
466 self.db.field_types((*s).into())[field.local_id] 478 self.db.field_types((*s).into())[field.local_id]
467 .clone() 479 .clone()
468 .subst(&parameters), 480 .substitute(&Interner, &parameters),
469 ) 481 )
470 } else { 482 } else {
471 None 483 None
@@ -479,7 +491,7 @@ impl<'a> InferenceContext<'a> {
479 Some( 491 Some(
480 self.db.field_types((*u).into())[field.local_id] 492 self.db.field_types((*u).into())[field.local_id]
481 .clone() 493 .clone()
482 .subst(&parameters), 494 .substitute(&Interner, &parameters),
483 ) 495 )
484 } else { 496 } else {
485 None 497 None
@@ -526,24 +538,17 @@ impl<'a> InferenceContext<'a> {
526 let inner_ty = self.infer_expr_inner(*expr, &expectation); 538 let inner_ty = self.infer_expr_inner(*expr, &expectation);
527 match rawness { 539 match rawness {
528 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty), 540 Rawness::RawPtr => TyKind::Raw(mutability, inner_ty),
529 Rawness::Ref => TyKind::Ref(mutability, inner_ty), 541 Rawness::Ref => TyKind::Ref(mutability, static_lifetime(), inner_ty),
530 } 542 }
531 .intern(&Interner) 543 .intern(&Interner)
532 } 544 }
533 Expr::Box { expr } => { 545 Expr::Box { expr } => {
534 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); 546 let inner_ty = self.infer_expr_inner(*expr, &Expectation::none());
535 if let Some(box_) = self.resolve_boxed_box() { 547 if let Some(box_) = self.resolve_boxed_box() {
536 let mut sb = 548 TyBuilder::adt(self.db, box_)
537 Substitution::build_for_generics(&generics(self.db.upcast(), box_.into())); 549 .push(inner_ty)
538 sb = sb.push(inner_ty); 550 .fill_with_defaults(self.db, || self.table.new_type_var())
539 match self.db.generic_defaults(box_.into()).get(1) { 551 .build()
540 Some(alloc_ty) if !alloc_ty.value.is_unknown() && sb.remaining() > 0 => {
541 sb = sb.push(alloc_ty.value.clone());
542 }
543 _ => (),
544 }
545 sb = sb.fill(repeat_with(|| self.table.new_type_var()));
546 Ty::adt_ty(box_, sb.build())
547 } else { 552 } else {
548 self.err_ty() 553 self.err_ty()
549 } 554 }
@@ -571,7 +576,7 @@ impl<'a> InferenceContext<'a> {
571 None => self.err_ty(), 576 None => self.err_ty(),
572 }, 577 },
573 UnaryOp::Neg => { 578 UnaryOp::Neg => {
574 match inner_ty.interned(&Interner) { 579 match inner_ty.kind(&Interner) {
575 // Fast path for builtins 580 // Fast path for builtins
576 TyKind::Scalar(Scalar::Int(_)) 581 TyKind::Scalar(Scalar::Int(_))
577 | TyKind::Scalar(Scalar::Uint(_)) 582 | TyKind::Scalar(Scalar::Uint(_))
@@ -584,7 +589,7 @@ impl<'a> InferenceContext<'a> {
584 } 589 }
585 } 590 }
586 UnaryOp::Not => { 591 UnaryOp::Not => {
587 match inner_ty.interned(&Interner) { 592 match inner_ty.kind(&Interner) {
588 // Fast path for builtins 593 // Fast path for builtins
589 TyKind::Scalar(Scalar::Bool) 594 TyKind::Scalar(Scalar::Bool)
590 | TyKind::Scalar(Scalar::Int(_)) 595 | TyKind::Scalar(Scalar::Int(_))
@@ -633,31 +638,31 @@ impl<'a> InferenceContext<'a> {
633 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect)); 638 let rhs_ty = rhs.map(|e| self.infer_expr(e, &rhs_expect));
634 match (range_type, lhs_ty, rhs_ty) { 639 match (range_type, lhs_ty, rhs_ty) {
635 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() { 640 (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
636 Some(adt) => Ty::adt_ty(adt, Substitution::empty()), 641 Some(adt) => TyBuilder::adt(self.db, adt).build(),
637 None => self.err_ty(), 642 None => self.err_ty(),
638 }, 643 },
639 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() { 644 (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
640 Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), 645 Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
641 None => self.err_ty(), 646 None => self.err_ty(),
642 }, 647 },
643 (RangeOp::Inclusive, None, Some(ty)) => { 648 (RangeOp::Inclusive, None, Some(ty)) => {
644 match self.resolve_range_to_inclusive() { 649 match self.resolve_range_to_inclusive() {
645 Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), 650 Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
646 None => self.err_ty(), 651 None => self.err_ty(),
647 } 652 }
648 } 653 }
649 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() { 654 (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
650 Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), 655 Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
651 None => self.err_ty(), 656 None => self.err_ty(),
652 }, 657 },
653 (RangeOp::Inclusive, Some(_), Some(ty)) => { 658 (RangeOp::Inclusive, Some(_), Some(ty)) => {
654 match self.resolve_range_inclusive() { 659 match self.resolve_range_inclusive() {
655 Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), 660 Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
656 None => self.err_ty(), 661 None => self.err_ty(),
657 } 662 }
658 } 663 }
659 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() { 664 (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
660 Some(adt) => Ty::adt_ty(adt, Substitution::single(ty)), 665 Some(adt) => TyBuilder::adt(self.db, adt).push(ty).build(),
661 None => self.err_ty(), 666 None => self.err_ty(),
662 }, 667 },
663 (RangeOp::Inclusive, _, None) => self.err_ty(), 668 (RangeOp::Inclusive, _, None) => self.err_ty(),
@@ -690,10 +695,10 @@ impl<'a> InferenceContext<'a> {
690 } 695 }
691 } 696 }
692 Expr::Tuple { exprs } => { 697 Expr::Tuple { exprs } => {
693 let mut tys = match expected.ty.interned(&Interner) { 698 let mut tys = match expected.ty.kind(&Interner) {
694 TyKind::Tuple(_, substs) => substs 699 TyKind::Tuple(_, substs) => substs
695 .iter() 700 .iter(&Interner)
696 .cloned() 701 .map(|a| a.assert_ty_ref(&Interner).clone())
697 .chain(repeat_with(|| self.table.new_type_var())) 702 .chain(repeat_with(|| self.table.new_type_var()))
698 .take(exprs.len()) 703 .take(exprs.len())
699 .collect::<Vec<_>>(), 704 .collect::<Vec<_>>(),
@@ -704,11 +709,11 @@ impl<'a> InferenceContext<'a> {
704 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone())); 709 self.infer_expr_coerce(*expr, &Expectation::has_type(ty.clone()));
705 } 710 }
706 711
707 TyKind::Tuple(tys.len(), Substitution(tys.into())).intern(&Interner) 712 TyKind::Tuple(tys.len(), Substitution::from_iter(&Interner, tys)).intern(&Interner)
708 } 713 }
709 Expr::Array(array) => { 714 Expr::Array(array) => {
710 let elem_ty = match expected.ty.interned(&Interner) { 715 let elem_ty = match expected.ty.kind(&Interner) {
711 TyKind::Array(st) | TyKind::Slice(st) => st.clone(), 716 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
712 _ => self.table.new_type_var(), 717 _ => self.table.new_type_var(),
713 }; 718 };
714 719
@@ -732,17 +737,19 @@ impl<'a> InferenceContext<'a> {
732 } 737 }
733 } 738 }
734 739
735 TyKind::Array(elem_ty).intern(&Interner) 740 TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner)
736 } 741 }
737 Expr::Literal(lit) => match lit { 742 Expr::Literal(lit) => match lit {
738 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 743 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
739 Literal::String(..) => { 744 Literal::String(..) => {
740 TyKind::Ref(Mutability::Not, TyKind::Str.intern(&Interner)).intern(&Interner) 745 TyKind::Ref(Mutability::Not, static_lifetime(), TyKind::Str.intern(&Interner))
746 .intern(&Interner)
741 } 747 }
742 Literal::ByteString(..) => { 748 Literal::ByteString(..) => {
743 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner); 749 let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);
744 let array_type = TyKind::Array(byte_type).intern(&Interner); 750 let array_type =
745 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)
746 } 753 }
747 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner), 754 Literal::Char(..) => TyKind::Scalar(Scalar::Char).intern(&Interner),
748 Literal::Int(_v, ty) => match ty { 755 Literal::Int(_v, ty) => match ty {
@@ -822,8 +829,8 @@ impl<'a> InferenceContext<'a> {
822 // we don't even make an attempt at coercion 829 // we don't even make an attempt at coercion
823 self.table.new_maybe_never_var() 830 self.table.new_maybe_never_var()
824 } else { 831 } else {
825 self.coerce(&Ty::unit(), &expected.coercion_target()); 832 self.coerce(&TyBuilder::unit(), &expected.coercion_target());
826 Ty::unit() 833 TyBuilder::unit()
827 } 834 }
828 }; 835 };
829 ty 836 ty
@@ -859,10 +866,10 @@ impl<'a> InferenceContext<'a> {
859 self.write_method_resolution(tgt_expr, func); 866 self.write_method_resolution(tgt_expr, func);
860 (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())))
861 } 868 }
862 None => (receiver_ty, Binders::new(0, self.err_ty()), None), 869 None => (receiver_ty, Binders::empty(&Interner, self.err_ty()), None),
863 }; 870 };
864 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);
865 let method_ty = method_ty.subst(&substs); 872 let method_ty = method_ty.substitute(&Interner, &substs);
866 let method_ty = self.insert_type_vars(method_ty); 873 let method_ty = self.insert_type_vars(method_ty);
867 self.register_obligations_for_call(&method_ty); 874 self.register_obligations_for_call(&method_ty);
868 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) {
@@ -878,7 +885,9 @@ impl<'a> InferenceContext<'a> {
878 // Apply autoref so the below unification works correctly 885 // Apply autoref so the below unification works correctly
879 // FIXME: return correct autorefs from lookup_method 886 // FIXME: return correct autorefs from lookup_method
880 let actual_receiver_ty = match expected_receiver_ty.as_reference() { 887 let actual_receiver_ty = match expected_receiver_ty.as_reference() {
881 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 }
882 _ => derefed_receiver_ty, 891 _ => derefed_receiver_ty,
883 }; 892 };
884 self.unify(&expected_receiver_ty, &actual_receiver_ty); 893 self.unify(&expected_receiver_ty, &actual_receiver_ty);
@@ -951,18 +960,20 @@ impl<'a> InferenceContext<'a> {
951 substs.push(self.err_ty()); 960 substs.push(self.err_ty());
952 } 961 }
953 assert_eq!(substs.len(), total_len); 962 assert_eq!(substs.len(), total_len);
954 Substitution(substs.into()) 963 Substitution::from_iter(&Interner, substs)
955 } 964 }
956 965
957 fn register_obligations_for_call(&mut self, callable_ty: &Ty) { 966 fn register_obligations_for_call(&mut self, callable_ty: &Ty) {
958 if let TyKind::FnDef(fn_def, parameters) = callable_ty.interned(&Interner) { 967 if let TyKind::FnDef(fn_def, parameters) = callable_ty.kind(&Interner) {
959 let def: CallableDefId = from_chalk(self.db, *fn_def); 968 let def: CallableDefId = from_chalk(self.db, *fn_def);
960 let generic_predicates = self.db.generic_predicates(def.into()); 969 let generic_predicates = self.db.generic_predicates(def.into());
961 for predicate in generic_predicates.iter() { 970 for predicate in generic_predicates.iter() {
962 let (predicate, binders) = 971 let (predicate, binders) = predicate
963 predicate.clone().subst(parameters).into_value_and_skipped_binders(); 972 .clone()
964 always!(binders == 0); // quantified where clauses not yet handled 973 .substitute(&Interner, parameters)
965 self.obligations.push(predicate.cast(&Interner)); 974 .into_value_and_skipped_binders();
975 always!(binders.len(&Interner) == 0); // quantified where clauses not yet handled
976 self.push_obligation(predicate.cast(&Interner));
966 } 977 }
967 // add obligation for trait implementation, if this is a trait method 978 // add obligation for trait implementation, if this is a trait method
968 match def { 979 match def {
@@ -970,9 +981,11 @@ impl<'a> InferenceContext<'a> {
970 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container 981 if let AssocContainerId::TraitId(trait_) = f.lookup(self.db.upcast()).container
971 { 982 {
972 // construct a TraitRef 983 // construct a TraitRef
973 let substs = 984 let substs = crate::subst_prefix(
974 parameters.prefix(generics(self.db.upcast(), trait_.into()).len()); 985 &*parameters,
975 self.obligations.push( 986 generics(self.db.upcast(), trait_.into()).len(),
987 );
988 self.push_obligation(
976 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs } 989 TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs }
977 .cast(&Interner), 990 .cast(&Interner),
978 ); 991 );
diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs
index 474363709..aea354cde 100644
--- a/crates/hir_ty/src/infer/pat.rs
+++ b/crates/hir_ty/src/infer/pat.rs
@@ -7,15 +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, 15 lower::lower_to_chalk_mutability, static_lifetime, Interner, Substitution, Ty, TyBuilder,
17 utils::{generics, variant_data}, 16 TyExt, TyKind,
18 Interner, Substitution, Ty, TyKind,
19}; 17};
20 18
21impl<'a> InferenceContext<'a> { 19impl<'a> InferenceContext<'a> {
@@ -29,13 +27,14 @@ impl<'a> InferenceContext<'a> {
29 ellipsis: Option<usize>, 27 ellipsis: Option<usize>,
30 ) -> Ty { 28 ) -> Ty {
31 let (ty, def) = self.resolve_variant(path); 29 let (ty, def) = self.resolve_variant(path);
32 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()));
33 if let Some(variant) = def { 31 if let Some(variant) = def {
34 self.write_variant_resolution(id.into(), variant); 32 self.write_variant_resolution(id.into(), variant);
35 } 33 }
36 self.unify(&ty, expected); 34 self.unify(&ty, expected);
37 35
38 let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); 36 let substs =
37 ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
39 38
40 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();
41 let (pre, post) = match ellipsis { 40 let (pre, post) = match ellipsis {
@@ -50,7 +49,9 @@ impl<'a> InferenceContext<'a> {
50 let expected_ty = var_data 49 let expected_ty = var_data
51 .as_ref() 50 .as_ref()
52 .and_then(|d| d.field(&Name::new_tuple_field(i))) 51 .and_then(|d| d.field(&Name::new_tuple_field(i)))
53 .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 });
54 let expected_ty = self.normalize_associated_types_in(expected_ty); 55 let expected_ty = self.normalize_associated_types_in(expected_ty);
55 self.infer_pat(subpat, &expected_ty, default_bm); 56 self.infer_pat(subpat, &expected_ty, default_bm);
56 } 57 }
@@ -67,25 +68,22 @@ impl<'a> InferenceContext<'a> {
67 id: PatId, 68 id: PatId,
68 ) -> Ty { 69 ) -> Ty {
69 let (ty, def) = self.resolve_variant(path); 70 let (ty, def) = self.resolve_variant(path);
70 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()));
71 if let Some(variant) = def { 72 if let Some(variant) = def {
72 self.write_variant_resolution(id.into(), variant); 73 self.write_variant_resolution(id.into(), variant);
73 } 74 }
74 75
75 self.unify(&ty, expected); 76 self.unify(&ty, expected);
76 77
77 let substs = ty.substs().cloned().unwrap_or_else(Substitution::empty); 78 let substs =
79 ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(&Interner));
78 80
79 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();
80 for subpat in subpats { 82 for subpat in subpats {
81 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));
82 if let Some(local_id) = matching_field { 84 let expected_ty = matching_field.map_or(self.err_ty(), |field| {
83 let field_def = FieldId { parent: def.unwrap(), local_id }; 85 field_tys[field].clone().substitute(&Interner, &substs)
84 self.result.record_pat_field_resolutions.insert(subpat.pat, field_def); 86 });
85 }
86
87 let expected_ty = matching_field
88 .map_or(self.err_ty(), |field| field_tys[field].clone().subst(&substs));
89 let expected_ty = self.normalize_associated_types_in(expected_ty); 87 let expected_ty = self.normalize_associated_types_in(expected_ty);
90 self.infer_pat(subpat.pat, &expected_ty, default_bm); 88 self.infer_pat(subpat.pat, &expected_ty, default_bm);
91 } 89 }
@@ -102,7 +100,7 @@ impl<'a> InferenceContext<'a> {
102 let body = Arc::clone(&self.body); // avoid borrow checker problem 100 let body = Arc::clone(&self.body); // avoid borrow checker problem
103 101
104 if is_non_ref_pat(&body, pat) { 102 if is_non_ref_pat(&body, pat) {
105 while let Some((inner, mutability)) = expected.as_reference() { 103 while let Some((inner, _lifetime, mutability)) = expected.as_reference() {
106 expected = inner; 104 expected = inner;
107 default_bm = match default_bm { 105 default_bm = match default_bm {
108 BindingMode::Move => BindingMode::Ref(mutability), 106 BindingMode::Move => BindingMode::Ref(mutability),
@@ -124,7 +122,7 @@ impl<'a> InferenceContext<'a> {
124 let ty = match &body[pat] { 122 let ty = match &body[pat] {
125 &Pat::Tuple { ref args, ellipsis } => { 123 &Pat::Tuple { ref args, ellipsis } => {
126 let expectations = match expected.as_tuple() { 124 let expectations = match expected.as_tuple() {
127 Some(parameters) => &*parameters.0, 125 Some(parameters) => &*parameters.as_slice(&Interner),
128 _ => &[], 126 _ => &[],
129 }; 127 };
130 128
@@ -134,7 +132,8 @@ impl<'a> InferenceContext<'a> {
134 }; 132 };
135 let n_uncovered_patterns = expectations.len().saturating_sub(args.len()); 133 let n_uncovered_patterns = expectations.len().saturating_sub(args.len());
136 let err_ty = self.err_ty(); 134 let err_ty = self.err_ty();
137 let mut expectations_iter = expectations.iter().chain(repeat(&err_ty)); 135 let mut expectations_iter =
136 expectations.iter().map(|a| a.assert_ty_ref(&Interner)).chain(repeat(&err_ty));
138 let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm); 137 let mut infer_pat = |(&pat, ty)| self.infer_pat(pat, ty, default_bm);
139 138
140 let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len()); 139 let mut inner_tys = Vec::with_capacity(n_uncovered_patterns + args.len());
@@ -142,7 +141,8 @@ impl<'a> InferenceContext<'a> {
142 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned()); 141 inner_tys.extend(expectations_iter.by_ref().take(n_uncovered_patterns).cloned());
143 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat)); 142 inner_tys.extend(post.iter().zip(expectations_iter).map(infer_pat));
144 143
145 TyKind::Tuple(inner_tys.len(), Substitution(inner_tys.into())).intern(&Interner) 144 TyKind::Tuple(inner_tys.len(), Substitution::from_iter(&Interner, inner_tys))
145 .intern(&Interner)
146 } 146 }
147 Pat::Or(ref pats) => { 147 Pat::Or(ref pats) => {
148 if let Some((first_pat, rest)) = pats.split_first() { 148 if let Some((first_pat, rest)) = pats.split_first() {
@@ -158,7 +158,7 @@ impl<'a> InferenceContext<'a> {
158 Pat::Ref { pat, mutability } => { 158 Pat::Ref { pat, mutability } => {
159 let mutability = lower_to_chalk_mutability(*mutability); 159 let mutability = lower_to_chalk_mutability(*mutability);
160 let expectation = match expected.as_reference() { 160 let expectation = match expected.as_reference() {
161 Some((inner_ty, exp_mut)) => { 161 Some((inner_ty, _lifetime, exp_mut)) => {
162 if mutability != exp_mut { 162 if mutability != exp_mut {
163 // FIXME: emit type error? 163 // FIXME: emit type error?
164 } 164 }
@@ -167,10 +167,10 @@ impl<'a> InferenceContext<'a> {
167 _ => self.result.standard_types.unknown.clone(), 167 _ => self.result.standard_types.unknown.clone(),
168 }; 168 };
169 let subty = self.infer_pat(*pat, &expectation, default_bm); 169 let subty = self.infer_pat(*pat, &expectation, default_bm);
170 TyKind::Ref(mutability, subty).intern(&Interner) 170 TyKind::Ref(mutability, static_lifetime(), subty).intern(&Interner)
171 } 171 }
172 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(
173 p.as_ref(), 173 p.as_deref(),
174 subpats, 174 subpats,
175 expected, 175 expected,
176 default_bm, 176 default_bm,
@@ -178,7 +178,7 @@ impl<'a> InferenceContext<'a> {
178 *ellipsis, 178 *ellipsis,
179 ), 179 ),
180 Pat::Record { path: p, args: fields, ellipsis: _ } => { 180 Pat::Record { path: p, args: fields, ellipsis: _ } => {
181 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)
182 } 182 }
183 Pat::Path(path) => { 183 Pat::Path(path) => {
184 // FIXME use correct resolver for the surrounding expression 184 // FIXME use correct resolver for the surrounding expression
@@ -200,7 +200,8 @@ impl<'a> InferenceContext<'a> {
200 200
201 let bound_ty = match mode { 201 let bound_ty = match mode {
202 BindingMode::Ref(mutability) => { 202 BindingMode::Ref(mutability) => {
203 TyKind::Ref(mutability, inner_ty.clone()).intern(&Interner) 203 TyKind::Ref(mutability, static_lifetime(), inner_ty.clone())
204 .intern(&Interner)
204 } 205 }
205 BindingMode::Move => inner_ty.clone(), 206 BindingMode::Move => inner_ty.clone(),
206 }; 207 };
@@ -209,17 +210,20 @@ impl<'a> InferenceContext<'a> {
209 return inner_ty; 210 return inner_ty;
210 } 211 }
211 Pat::Slice { prefix, slice, suffix } => { 212 Pat::Slice { prefix, slice, suffix } => {
212 let (container_ty, elem_ty): (fn(_) -> _, _) = match expected.interned(&Interner) { 213 let elem_ty = match expected.kind(&Interner) {
213 TyKind::Array(st) => (TyKind::Array, st.clone()), 214 TyKind::Array(st, _) | TyKind::Slice(st) => st.clone(),
214 TyKind::Slice(st) => (TyKind::Slice, st.clone()), 215 _ => self.err_ty(),
215 _ => (TyKind::Slice, self.err_ty()),
216 }; 216 };
217 217
218 for pat_id in prefix.iter().chain(suffix) { 218 for pat_id in prefix.iter().chain(suffix) {
219 self.infer_pat(*pat_id, &elem_ty, default_bm); 219 self.infer_pat(*pat_id, &elem_ty, default_bm);
220 } 220 }
221 221
222 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);
223 if let Some(slice_pat_id) = slice { 227 if let Some(slice_pat_id) = slice {
224 self.infer_pat(*slice_pat_id, &pat_ty, default_bm); 228 self.infer_pat(*slice_pat_id, &pat_ty, default_bm);
225 } 229 }
@@ -236,30 +240,20 @@ impl<'a> InferenceContext<'a> {
236 Pat::Box { inner } => match self.resolve_boxed_box() { 240 Pat::Box { inner } => match self.resolve_boxed_box() {
237 Some(box_adt) => { 241 Some(box_adt) => {
238 let (inner_ty, alloc_ty) = match expected.as_adt() { 242 let (inner_ty, alloc_ty) = match expected.as_adt() {
239 Some((adt, subst)) if adt == box_adt => { 243 Some((adt, subst)) if adt == box_adt => (
240 (subst[0].clone(), subst.get(1).cloned()) 244 subst.at(&Interner, 0).assert_ty_ref(&Interner).clone(),
241 } 245 subst.as_slice(&Interner).get(1).and_then(|a| a.ty(&Interner).cloned()),
246 ),
242 _ => (self.result.standard_types.unknown.clone(), None), 247 _ => (self.result.standard_types.unknown.clone(), None),
243 }; 248 };
244 249
245 let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm); 250 let inner_ty = self.infer_pat(*inner, &inner_ty, default_bm);
246 let mut sb = Substitution::build_for_generics(&generics( 251 let mut b = TyBuilder::adt(self.db, box_adt).push(inner_ty);
247 self.db.upcast(), 252
248 box_adt.into(), 253 if let Some(alloc_ty) = alloc_ty {
249 )); 254 b = b.push(alloc_ty);
250 sb = sb.push(inner_ty);
251 if sb.remaining() == 1 {
252 sb = sb.push(match alloc_ty {
253 Some(alloc_ty) if !alloc_ty.is_unknown() => alloc_ty,
254 _ => match self.db.generic_defaults(box_adt.into()).get(1) {
255 Some(alloc_ty) if !alloc_ty.value.is_unknown() => {
256 alloc_ty.value.clone()
257 }
258 _ => self.table.new_type_var(),
259 },
260 });
261 } 255 }
262 Ty::adt_ty(box_adt, sb.build()) 256 b.fill_with_defaults(self.db, || self.table.new_type_var()).build()
263 } 257 }
264 None => self.err_ty(), 258 None => self.err_ty(),
265 }, 259 },
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index cefa38509..495282eba 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -11,7 +11,8 @@ use hir_def::{
11use hir_expand::name::Name; 11use hir_expand::name::Name;
12 12
13use crate::{ 13use crate::{
14 method_resolution, to_chalk_trait_id, Interner, Substitution, Ty, TyKind, ValueTyDefId, 14 method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
15 ValueTyDefId,
15}; 16};
16 17
17use super::{ExprOrPatId, InferenceContext, TraitRef}; 18use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -82,10 +83,10 @@ impl<'a> InferenceContext<'a> {
82 } 83 }
83 ValueNs::ImplSelf(impl_id) => { 84 ValueNs::ImplSelf(impl_id) => {
84 let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); 85 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
85 let substs = Substitution::type_params_for_generics(self.db, &generics); 86 let substs = generics.type_params_subst(self.db);
86 let ty = self.db.impl_self_ty(impl_id).subst(&substs); 87 let ty = self.db.impl_self_ty(impl_id).substitute(&Interner, &substs);
87 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { 88 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
88 let ty = self.db.value_ty(struct_id.into()).subst(&substs); 89 let ty = self.db.value_ty(struct_id.into()).substitute(&Interner, &substs);
89 return Some(ty); 90 return Some(ty);
90 } else { 91 } else {
91 // FIXME: diagnostic, invalid Self reference 92 // FIXME: diagnostic, invalid Self reference
@@ -95,16 +96,13 @@ impl<'a> InferenceContext<'a> {
95 ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)), 96 ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
96 }; 97 };
97 98
98 let ty = self.db.value_ty(typable); 99 let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(&Interner));
99 // self_subst is just for the parent
100 let parent_substs = self_subst.unwrap_or_else(Substitution::empty);
101 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver); 100 let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
102 let substs = ctx.substs_from_path(path, typable, true); 101 let substs = ctx.substs_from_path(path, typable, true);
103 let full_substs = Substitution::builder(substs.len()) 102 let ty = TyBuilder::value_ty(self.db, typable)
104 .use_parent_substs(&parent_substs) 103 .use_parent_substs(&parent_substs)
105 .fill(substs.0[parent_substs.len()..].iter().cloned()) 104 .fill(substs.as_slice(&Interner)[parent_substs.len(&Interner)..].iter().cloned())
106 .build(); 105 .build();
107 let ty = ty.subst(&full_substs);
108 Some(ty) 106 Some(ty)
109 } 107 }
110 108
@@ -147,7 +145,7 @@ impl<'a> InferenceContext<'a> {
147 remaining_segments_for_ty, 145 remaining_segments_for_ty,
148 true, 146 true,
149 ); 147 );
150 if let TyKind::Unknown = ty.interned(&Interner) { 148 if let TyKind::Error = ty.kind(&Interner) {
151 return None; 149 return None;
152 } 150 }
153 151
@@ -212,7 +210,7 @@ impl<'a> InferenceContext<'a> {
212 name: &Name, 210 name: &Name,
213 id: ExprOrPatId, 211 id: ExprOrPatId,
214 ) -> Option<(ValueNs, Option<Substitution>)> { 212 ) -> Option<(ValueNs, Option<Substitution>)> {
215 if let TyKind::Unknown = ty.interned(&Interner) { 213 if let TyKind::Error = ty.kind(&Interner) {
216 return None; 214 return None;
217 } 215 }
218 216
@@ -245,27 +243,22 @@ impl<'a> InferenceContext<'a> {
245 }; 243 };
246 let substs = match container { 244 let substs = match container {
247 AssocContainerId::ImplId(impl_id) => { 245 AssocContainerId::ImplId(impl_id) => {
248 let impl_substs = Substitution::build_for_def(self.db, impl_id) 246 let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
249 .fill(iter::repeat_with(|| self.table.new_type_var())) 247 .fill(iter::repeat_with(|| self.table.new_type_var()))
250 .build(); 248 .build();
251 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);
252 self.unify(&impl_self_ty, &ty); 251 self.unify(&impl_self_ty, &ty);
253 Some(impl_substs) 252 Some(impl_substs)
254 } 253 }
255 AssocContainerId::TraitId(trait_) => { 254 AssocContainerId::TraitId(trait_) => {
256 // we're picking this method 255 // we're picking this method
257 let trait_substs = Substitution::build_for_def(self.db, trait_) 256 let trait_ref = TyBuilder::trait_ref(self.db, trait_)
258 .push(ty.clone()) 257 .push(ty.clone())
259 .fill(std::iter::repeat_with(|| self.table.new_type_var())) 258 .fill(std::iter::repeat_with(|| self.table.new_type_var()))
260 .build(); 259 .build();
261 self.obligations.push( 260 self.push_obligation(trait_ref.clone().cast(&Interner));
262 TraitRef { 261 Some(trait_ref.substitution)
263 trait_id: to_chalk_trait_id(trait_),
264 substitution: trait_substs.clone(),
265 }
266 .cast(&Interner),
267 );
268 Some(trait_substs)
269 } 262 }
270 AssocContainerId::ModuleId(_) => None, 263 AssocContainerId::ModuleId(_) => None,
271 }; 264 };
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index 6e7b0f5a6..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.interned(&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(
@@ -129,29 +137,30 @@ impl<T> Canonicalized<T> {
129 solution: Canonical<Substitution>, 137 solution: Canonical<Substitution>,
130 ) { 138 ) {
131 // the solution may contain new variables, which we need to convert to new inference vars 139 // the solution may contain new variables, which we need to convert to new inference vars
132 let new_vars = Substitution( 140 let new_vars = Substitution::from_iter(
133 solution 141 &Interner,
134 .binders 142 solution.binders.iter(&Interner).map(|k| match k.kind {
135 .iter(&Interner) 143 VariableKind::Ty(TyVariableKind::General) => {
136 .map(|k| match k.kind { 144 ctx.table.new_type_var().cast(&Interner)
137 VariableKind::Ty(TyVariableKind::General) => ctx.table.new_type_var(), 145 }
138 VariableKind::Ty(TyVariableKind::Integer) => ctx.table.new_integer_var(), 146 VariableKind::Ty(TyVariableKind::Integer) => {
139 VariableKind::Ty(TyVariableKind::Float) => ctx.table.new_float_var(), 147 ctx.table.new_integer_var().cast(&Interner)
140 // HACK: Chalk can sometimes return new lifetime variables. We 148 }
141 // want to just skip them, but to not mess up the indices of 149 VariableKind::Ty(TyVariableKind::Float) => {
142 // other variables, we'll just create a new type variable in 150 ctx.table.new_float_var().cast(&Interner)
143 // their place instead. This should not matter (we never see the 151 }
144 // actual *uses* of the lifetime variable). 152 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
145 VariableKind::Lifetime => ctx.table.new_type_var(), 153 VariableKind::Lifetime => static_lifetime().cast(&Interner),
146 _ => panic!("const variable in solution"), 154 _ => panic!("const variable in solution"),
147 }) 155 }),
148 .collect(),
149 ); 156 );
150 for (i, ty) in solution.value.into_iter().enumerate() { 157 for (i, ty) in solution.value.iter(&Interner).enumerate() {
151 let (v, k) = self.free_vars[i]; 158 let (v, k) = self.free_vars[i];
152 // eagerly replace projections in the type; we may be getting types 159 // eagerly replace projections in the type; we may be getting types
153 // e.g. from where clauses where this hasn't happened yet 160 // e.g. from where clauses where this hasn't happened yet
154 let ty = ctx.normalize_associated_types_in(ty.clone().subst_bound_vars(&new_vars)); 161 let ty = ctx.normalize_associated_types_in(
162 new_vars.apply(ty.assert_ty_ref(&Interner).clone(), &Interner),
163 );
155 ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty); 164 ctx.table.unify(&TyKind::InferenceVar(v, k).intern(&Interner), &ty);
156 } 165 }
157 } 166 }
@@ -163,22 +172,23 @@ pub fn could_unify(t1: &Ty, t2: &Ty) -> bool {
163 172
164pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> { 173pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
165 let mut table = InferenceTable::new(); 174 let mut table = InferenceTable::new();
166 let vars = Substitution( 175 let vars = Substitution::from_iter(
176 &Interner,
167 tys.binders 177 tys.binders
168 .iter(&Interner) 178 .iter(&Interner)
169 // we always use type vars here because we want everything to 179 // we always use type vars here because we want everything to
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 .collect(),
173 ); 182 );
174 let ty1_with_vars = tys.value.0.clone().subst_bound_vars(&vars); 183 let ty1_with_vars = vars.apply(tys.value.0.clone(), &Interner);
175 let ty2_with_vars = tys.value.1.clone().subst_bound_vars(&vars); 184 let ty2_with_vars = vars.apply(tys.value.1.clone(), &Interner);
176 if !table.unify(&ty1_with_vars, &ty2_with_vars) { 185 if !table.unify(&ty1_with_vars, &ty2_with_vars) {
177 return None; 186 return None;
178 } 187 }
179 // default any type vars that weren't unified back to their original bound vars 188 // default any type vars that weren't unified back to their original bound vars
180 // (kind of hacky) 189 // (kind of hacky)
181 for (i, var) in vars.iter().enumerate() { 190 for (i, var) in vars.iter(&Interner).enumerate() {
191 let var = var.assert_ty_ref(&Interner);
182 if &*table.resolve_ty_shallow(var) == var { 192 if &*table.resolve_ty_shallow(var) == var {
183 table.unify( 193 table.unify(
184 var, 194 var,
@@ -186,11 +196,11 @@ pub(crate) fn unify(tys: &Canonical<(Ty, Ty)>) -> Option<Substitution> {
186 ); 196 );
187 } 197 }
188 } 198 }
189 Some( 199 Some(Substitution::from_iter(
190 Substitution::builder(tys.binders.len(&Interner)) 200 &Interner,
191 .fill(vars.iter().map(|v| table.resolve_ty_completely(v.clone()))) 201 vars.iter(&Interner)
192 .build(), 202 .map(|v| table.resolve_ty_completely(v.assert_ty_ref(&Interner).clone())),
193 ) 203 ))
194} 204}
195 205
196#[derive(Clone, Debug)] 206#[derive(Clone, Debug)]
@@ -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 }
@@ -231,6 +241,7 @@ pub(crate) struct TypeVariableData {
231pub(crate) struct InferenceTable { 241pub(crate) struct InferenceTable {
232 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>, 242 pub(super) var_unification_table: InPlaceUnificationTable<TypeVarId>,
233 pub(super) type_variable_table: TypeVariableTable, 243 pub(super) type_variable_table: TypeVariableTable,
244 pub(super) revision: u32,
234} 245}
235 246
236impl InferenceTable { 247impl InferenceTable {
@@ -238,6 +249,7 @@ impl InferenceTable {
238 InferenceTable { 249 InferenceTable {
239 var_unification_table: InPlaceUnificationTable::new(), 250 var_unification_table: InPlaceUnificationTable::new(),
240 type_variable_table: TypeVariableTable { inner: Vec::new() }, 251 type_variable_table: TypeVariableTable { inner: Vec::new() },
252 revision: 0,
241 } 253 }
242 } 254 }
243 255
@@ -245,7 +257,7 @@ impl InferenceTable {
245 self.type_variable_table.push(TypeVariableData { diverging }); 257 self.type_variable_table.push(TypeVariableData { diverging });
246 let key = self.var_unification_table.new_key(TypeVarValue::Unknown); 258 let key = self.var_unification_table.new_key(TypeVarValue::Unknown);
247 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);
248 TyKind::InferenceVar(InferenceVar::from_inner(key), kind).intern(&Interner) 260 TyKind::InferenceVar(to_inference_var(key), kind).intern(&Interner)
249 } 261 }
250 262
251 pub(crate) fn new_type_var(&mut self) -> Ty { 263 pub(crate) fn new_type_var(&mut self) -> Ty {
@@ -282,7 +294,9 @@ impl InferenceTable {
282 substs2: &Substitution, 294 substs2: &Substitution,
283 depth: usize, 295 depth: usize,
284 ) -> bool { 296 ) -> bool {
285 substs1.0.iter().zip(substs2.0.iter()).all(|(t1, t2)| self.unify_inner(t1, t2, depth)) 297 substs1.iter(&Interner).zip(substs2.iter(&Interner)).all(|(t1, t2)| {
298 self.unify_inner(t1.assert_ty_ref(&Interner), t2.assert_ty_ref(&Interner), depth)
299 })
286 } 300 }
287 301
288 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool { 302 fn unify_inner(&mut self, ty1: &Ty, ty2: &Ty, depth: usize) -> bool {
@@ -297,12 +311,12 @@ impl InferenceTable {
297 let ty1 = self.resolve_ty_shallow(ty1); 311 let ty1 = self.resolve_ty_shallow(ty1);
298 let ty2 = self.resolve_ty_shallow(ty2); 312 let ty2 = self.resolve_ty_shallow(ty2);
299 if ty1.equals_ctor(&ty2) { 313 if ty1.equals_ctor(&ty2) {
300 match (ty1.interned(&Interner), ty2.interned(&Interner)) { 314 match (ty1.kind(&Interner), ty2.kind(&Interner)) {
301 (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2)) 315 (TyKind::Adt(_, substs1), TyKind::Adt(_, substs2))
302 | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2)) 316 | (TyKind::FnDef(_, substs1), TyKind::FnDef(_, substs2))
303 | ( 317 | (
304 TyKind::Function(FnPointer { substs: substs1, .. }), 318 TyKind::Function(FnPointer { substitution: FnSubst(substs1), .. }),
305 TyKind::Function(FnPointer { substs: substs2, .. }), 319 TyKind::Function(FnPointer { substitution: FnSubst(substs2), .. }),
306 ) 320 )
307 | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2)) 321 | (TyKind::Tuple(_, substs1), TyKind::Tuple(_, substs2))
308 | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2)) 322 | (TyKind::OpaqueType(_, substs1), TyKind::OpaqueType(_, substs2))
@@ -310,9 +324,11 @@ impl InferenceTable {
310 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => { 324 | (TyKind::Closure(.., substs1), TyKind::Closure(.., substs2)) => {
311 self.unify_substs(substs1, substs2, depth + 1) 325 self.unify_substs(substs1, substs2, depth + 1)
312 } 326 }
313 (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))
314 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2)) 331 | (TyKind::Raw(_, ty1), TyKind::Raw(_, ty2))
315 | (TyKind::Array(ty1), TyKind::Array(ty2))
316 | (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),
317 _ => true, /* we checked equals_ctor already */ 333 _ => true, /* we checked equals_ctor already */
318 } 334 }
@@ -322,8 +338,8 @@ impl InferenceTable {
322 } 338 }
323 339
324 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 {
325 match (ty1.interned(&Interner), ty2.interned(&Interner)) { 341 match (ty1.kind(&Interner), ty2.kind(&Interner)) {
326 (TyKind::Unknown, _) | (_, TyKind::Unknown) => true, 342 (TyKind::Error, _) | (_, TyKind::Error) => true,
327 343
328 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true, 344 (TyKind::Placeholder(p1), TyKind::Placeholder(p2)) if *p1 == *p2 => true,
329 345
@@ -360,7 +376,14 @@ impl InferenceTable {
360 == self.type_variable_table.is_diverging(*tv2) => 376 == self.type_variable_table.is_diverging(*tv2) =>
361 { 377 {
362 // both type vars are unknown since we tried to resolve them 378 // both type vars are unknown since we tried to resolve them
363 self.var_unification_table.union(tv1.to_inner(), tv2.to_inner()); 379 if !self
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));
385 self.revision += 1;
386 }
364 true 387 true
365 } 388 }
366 389
@@ -395,9 +418,10 @@ impl InferenceTable {
395 ) => { 418 ) => {
396 // the type var is unknown since we tried to resolve it 419 // the type var is unknown since we tried to resolve it
397 self.var_unification_table.union_value( 420 self.var_unification_table.union_value(
398 tv.to_inner(), 421 from_inference_var(*tv),
399 TypeVarValue::Known(other.clone().intern(&Interner)), 422 TypeVarValue::Known(other.clone().intern(&Interner)),
400 ); 423 );
424 self.revision += 1;
401 true 425 true
402 } 426 }
403 427
@@ -447,9 +471,9 @@ impl InferenceTable {
447 if i > 0 { 471 if i > 0 {
448 cov_mark::hit!(type_var_resolves_to_int_var); 472 cov_mark::hit!(type_var_resolves_to_int_var);
449 } 473 }
450 match ty.interned(&Interner) { 474 match ty.kind(&Interner) {
451 TyKind::InferenceVar(tv, _) => { 475 TyKind::InferenceVar(tv, _) => {
452 let inner = tv.to_inner(); 476 let inner = from_inference_var(*tv);
453 match self.var_unification_table.inlined_probe_value(inner).known() { 477 match self.var_unification_table.inlined_probe_value(inner).known() {
454 Some(known_ty) => { 478 Some(known_ty) => {
455 // The known_ty can't be a type var itself 479 // The known_ty can't be a type var itself
@@ -470,55 +494,63 @@ impl InferenceTable {
470 /// 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
471 /// known type. 495 /// known type.
472 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 {
473 ty.fold(&mut |ty| match ty.interned(&Interner) { 497 fold_tys(
474 &TyKind::InferenceVar(tv, kind) => { 498 ty,
475 let inner = tv.to_inner(); 499 |ty, _| match ty.kind(&Interner) {
476 if tv_stack.contains(&inner) { 500 &TyKind::InferenceVar(tv, kind) => {
477 cov_mark::hit!(type_var_cycles_resolve_as_possible); 501 let inner = from_inference_var(tv);
478 // recursive type 502 if tv_stack.contains(&inner) {
479 return self.type_variable_table.fallback_value(tv, kind); 503 cov_mark::hit!(type_var_cycles_resolve_as_possible);
480 } 504 // recursive type
481 if let Some(known_ty) = 505 return self.type_variable_table.fallback_value(tv, kind);
482 self.var_unification_table.inlined_probe_value(inner).known() 506 }
483 { 507 if let Some(known_ty) =
484 // known_ty may contain other variables that are known by now 508 self.var_unification_table.inlined_probe_value(inner).known()
485 tv_stack.push(inner); 509 {
486 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
487 tv_stack.pop(); 511 tv_stack.push(inner);
488 result 512 let result = self.resolve_ty_as_possible_inner(tv_stack, known_ty.clone());
489 } else { 513 tv_stack.pop();
490 ty 514 result
515 } else {
516 ty
517 }
491 } 518 }
492 } 519 _ => ty,
493 _ => ty, 520 },
494 }) 521 DebruijnIndex::INNERMOST,
522 )
495 } 523 }
496 524
497 /// Resolves the type completely; type variables without known type are 525 /// Resolves the type completely; type variables without known type are
498 /// replaced by TyKind::Unknown. 526 /// replaced by TyKind::Unknown.
499 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 {
500 ty.fold(&mut |ty| match ty.interned(&Interner) { 528 fold_tys(
501 &TyKind::InferenceVar(tv, kind) => { 529 ty,
502 let inner = tv.to_inner(); 530 |ty, _| match ty.kind(&Interner) {
503 if tv_stack.contains(&inner) { 531 &TyKind::InferenceVar(tv, kind) => {
504 cov_mark::hit!(type_var_cycles_resolve_completely); 532 let inner = from_inference_var(tv);
505 // recursive type 533 if tv_stack.contains(&inner) {
506 return self.type_variable_table.fallback_value(tv, kind); 534 cov_mark::hit!(type_var_cycles_resolve_completely);
507 } 535 // recursive type
508 if let Some(known_ty) = 536 return self.type_variable_table.fallback_value(tv, kind);
509 self.var_unification_table.inlined_probe_value(inner).known() 537 }
510 { 538 if let Some(known_ty) =
511 // known_ty may contain other variables that are known by now 539 self.var_unification_table.inlined_probe_value(inner).known()
512 tv_stack.push(inner); 540 {
513 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone()); 541 // known_ty may contain other variables that are known by now
514 tv_stack.pop(); 542 tv_stack.push(inner);
515 result 543 let result = self.resolve_ty_completely_inner(tv_stack, known_ty.clone());
516 } else { 544 tv_stack.pop();
517 self.type_variable_table.fallback_value(tv, kind) 545 result
546 } else {
547 self.type_variable_table.fallback_value(tv, kind)
548 }
518 } 549 }
519 } 550 _ => ty,
520 _ => ty, 551 },
521 }) 552 DebruijnIndex::INNERMOST,
553 )
522 } 554 }
523} 555}
524 556
@@ -542,6 +574,14 @@ impl UnifyKey for TypeVarId {
542 } 574 }
543} 575}
544 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
545/// 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
546/// know it yet. 586/// know it yet.
547#[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 6f9c698e6..0505fa4ae 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -1,59 +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; 10mod builder;
10pub mod traits; 11mod chalk_db;
11pub mod method_resolution; 12mod chalk_ext;
12mod op; 13mod infer;
14mod interner;
13mod lower; 15mod lower;
14pub(crate) mod infer; 16mod mapping;
15pub(crate) mod utils; 17mod op;
16mod chalk_cast; 18mod tls;
17 19mod utils;
18pub mod display; 20mod walk;
19pub mod db; 21pub mod db;
20pub mod diagnostics; 22pub mod diagnostics;
23pub mod display;
24pub mod method_resolution;
25pub mod primitive;
26pub mod traits;
21 27
22#[cfg(test)] 28#[cfg(test)]
23mod tests; 29mod tests;
24#[cfg(test)] 30#[cfg(test)]
25mod test_db; 31mod test_db;
26 32
27use std::{iter, mem, ops::Deref, sync::Arc}; 33use std::sync::Arc;
28 34
29use base_db::salsa; 35use chalk_ir::{
30use hir_def::{ 36 fold::{Fold, Shift},
31 builtin_type::BuiltinType, expr::ExprId, type_ref::Rawness, AssocContainerId, FunctionId, 37 interner::HasInterner,
32 GenericDefId, HasModule, LifetimeParamId, Lookup, TraitId, TypeAliasId, TypeParamId, 38 UintTy,
33}; 39};
34use itertools::Itertools; 40use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};
35use smallvec::SmallVec;
36 41
37use crate::{ 42use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
38 db::HirDatabase,
39 display::HirDisplay,
40 utils::{generics, make_mut_slice, Generics},
41};
42 43
43pub use autoderef::autoderef; 44pub use autoderef::autoderef;
44pub use infer::{could_unify, InferenceResult, InferenceVar}; 45pub use builder::TyBuilder;
46pub use chalk_ext::*;
47pub use infer::{could_unify, InferenceResult};
48pub use interner::Interner;
45pub use lower::{ 49pub use lower::{
46 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode, 50 associated_type_shorthand_candidates, callable_item_sig, CallableDefId, ImplTraitLoweringMode,
47 TyDefId, TyLoweringContext, ValueTyDefId, 51 TyDefId, TyLoweringContext, ValueTyDefId,
48}; 52};
49pub 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;
50 61
51pub use chalk_ir::{ 62pub use chalk_ir::{
52 cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind, 63 cast::Cast, AdtId, BoundVar, DebruijnIndex, Mutability, Safety, Scalar, TyVariableKind,
53}; 64};
54 65
55pub use crate::traits::chalk::Interner;
56
57pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>; 66pub type ForeignDefId = chalk_ir::ForeignDefId<Interner>;
58pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; 67pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>;
59pub type FnDefId = chalk_ir::FnDefId<Interner>; 68pub type FnDefId = chalk_ir::FnDefId<Interner>;
@@ -61,371 +70,56 @@ pub type ClosureId = chalk_ir::ClosureId<Interner>;
61pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>; 70pub type OpaqueTyId = chalk_ir::OpaqueTyId<Interner>;
62pub type PlaceholderIndex = chalk_ir::PlaceholderIndex; 71pub type PlaceholderIndex = chalk_ir::PlaceholderIndex;
63 72
73pub type VariableKind = chalk_ir::VariableKind<Interner>;
74pub type VariableKinds = chalk_ir::VariableKinds<Interner>;
64pub 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>;
65 100
66pub type ChalkTraitId = chalk_ir::TraitId<Interner>; 101pub type ChalkTraitId = chalk_ir::TraitId<Interner>;
67 102pub type TraitRef = chalk_ir::TraitRef<Interner>;
68#[derive(Clone, PartialEq, Eq, Debug, Hash)] 103pub type QuantifiedWhereClause = Binders<WhereClause>;
69pub enum Lifetime { 104pub type QuantifiedWhereClauses = chalk_ir::QuantifiedWhereClauses<Interner>;
70 Parameter(LifetimeParamId), 105pub type Canonical<T> = chalk_ir::Canonical<T>;
71 Static,
72}
73
74#[derive(Clone, PartialEq, Eq, Debug, Hash)]
75pub struct OpaqueTy {
76 pub opaque_ty_id: OpaqueTyId,
77 pub substitution: Substitution,
78}
79
80impl TypeWalk for OpaqueTy {
81 fn walk(&self, f: &mut impl FnMut(&Ty)) {
82 self.substitution.walk(f);
83 }
84
85 fn walk_mut_binders(
86 &mut self,
87 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
88 binders: DebruijnIndex,
89 ) {
90 self.substitution.walk_mut_binders(f, binders);
91 }
92}
93
94/// A "projection" type corresponds to an (unnormalized)
95/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
96/// trait and all its parameters are fully known.
97#[derive(Clone, PartialEq, Eq, Debug, Hash)]
98pub struct ProjectionTy {
99 pub associated_ty_id: AssocTypeId,
100 pub substitution: Substitution,
101}
102
103impl ProjectionTy {
104 pub fn trait_ref(&self, db: &dyn HirDatabase) -> TraitRef {
105 TraitRef {
106 trait_id: to_chalk_trait_id(self.trait_(db)),
107 substitution: self.substitution.clone(),
108 }
109 }
110
111 pub fn self_type_parameter(&self) -> &Ty {
112 &self.substitution[0]
113 }
114
115 fn trait_(&self, db: &dyn HirDatabase) -> TraitId {
116 match from_assoc_type_id(self.associated_ty_id).lookup(db.upcast()).container {
117 AssocContainerId::TraitId(it) => it,
118 _ => panic!("projection ty without parent trait"),
119 }
120 }
121}
122
123impl TypeWalk for ProjectionTy {
124 fn walk(&self, f: &mut impl FnMut(&Ty)) {
125 self.substitution.walk(f);
126 }
127
128 fn walk_mut_binders(
129 &mut self,
130 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
131 binders: DebruijnIndex,
132 ) {
133 self.substitution.walk_mut_binders(f, binders);
134 }
135}
136
137#[derive(Clone, PartialEq, Eq, Debug, Hash)]
138pub struct DynTy {
139 /// The unknown self type.
140 pub bounds: Binders<QuantifiedWhereClauses>,
141}
142 106
143pub type FnSig = chalk_ir::FnSig<Interner>; 107pub type FnSig = chalk_ir::FnSig<Interner>;
144 108
145#[derive(Clone, PartialEq, Eq, Debug, Hash)] 109pub type InEnvironment<T> = chalk_ir::InEnvironment<T>;
146pub struct FnPointer { 110pub type DomainGoal = chalk_ir::DomainGoal<Interner>;
147 pub num_args: usize, 111pub type AliasEq = chalk_ir::AliasEq<Interner>;
148 pub sig: FnSig, 112pub type Solution = chalk_solve::Solution<Interner>;
149 pub substs: Substitution, 113pub type ConstrainedSubst = chalk_ir::ConstrainedSubst<Interner>;
150} 114pub type Guidance = chalk_solve::Guidance<Interner>;
151 115pub type WhereClause = chalk_ir::WhereClause<Interner>;
152#[derive(Clone, PartialEq, Eq, Debug, Hash)]
153pub enum AliasTy {
154 /// A "projection" type corresponds to an (unnormalized)
155 /// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
156 /// trait and all its parameters are fully known.
157 Projection(ProjectionTy),
158 /// An opaque type (`impl Trait`).
159 ///
160 /// This is currently only used for return type impl trait; each instance of
161 /// `impl Trait` in a return type gets its own ID.
162 Opaque(OpaqueTy),
163}
164
165impl TypeWalk for AliasTy {
166 fn walk(&self, f: &mut impl FnMut(&Ty)) {
167 match self {
168 AliasTy::Projection(it) => it.walk(f),
169 AliasTy::Opaque(it) => it.walk(f),
170 }
171 }
172
173 fn walk_mut_binders(
174 &mut self,
175 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
176 binders: DebruijnIndex,
177 ) {
178 match self {
179 AliasTy::Projection(it) => it.walk_mut_binders(f, binders),
180 AliasTy::Opaque(it) => it.walk_mut_binders(f, binders),
181 }
182 }
183}
184/// A type.
185///
186/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
187/// the same thing (but in a different way).
188///
189/// This should be cheap to clone.
190#[derive(Clone, PartialEq, Eq, Debug, Hash)]
191pub enum TyKind {
192 /// Structures, enumerations and unions.
193 Adt(AdtId<Interner>, Substitution),
194
195 /// Represents an associated item like `Iterator::Item`. This is used
196 /// when we have tried to normalize a projection like `T::Item` but
197 /// couldn't find a better representation. In that case, we generate
198 /// an **application type** like `(Iterator::Item)<T>`.
199 AssociatedType(AssocTypeId, Substitution),
200
201 /// a scalar type like `bool` or `u32`
202 Scalar(Scalar),
203
204 /// A tuple type. For example, `(i32, bool)`.
205 Tuple(usize, Substitution),
206
207 /// An array with the given length. Written as `[T; n]`.
208 Array(Ty),
209
210 /// The pointee of an array slice. Written as `[T]`.
211 Slice(Ty),
212
213 /// A raw pointer. Written as `*mut T` or `*const T`
214 Raw(Mutability, Ty),
215
216 /// A reference; a pointer with an associated lifetime. Written as
217 /// `&'a mut T` or `&'a T`.
218 Ref(Mutability, Ty),
219 116
220 /// This represents a placeholder for an opaque type in situations where we 117// FIXME: get rid of this
221 /// don't know the hidden type (i.e. currently almost always). This is 118pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
222 /// analogous to the `AssociatedType` type constructor. 119 Substitution::from_iter(
223 /// It is also used as the type of async block, with one type parameter 120 &Interner,
224 /// representing the Future::Output type. 121 s.as_slice(&Interner)[..std::cmp::min(s.len(&Interner), n)].iter().cloned(),
225 OpaqueType(OpaqueTyId, Substitution), 122 )
226
227 /// The anonymous type of a function declaration/definition. Each
228 /// function has a unique type, which is output (for a function
229 /// named `foo` returning an `i32`) as `fn() -> i32 {foo}`.
230 ///
231 /// This includes tuple struct / enum variant constructors as well.
232 ///
233 /// For example the type of `bar` here:
234 ///
235 /// ```
236 /// fn foo() -> i32 { 1 }
237 /// let bar = foo; // bar: fn() -> i32 {foo}
238 /// ```
239 FnDef(FnDefId, Substitution),
240
241 /// The pointee of a string slice. Written as `str`.
242 Str,
243
244 /// The never type `!`.
245 Never,
246
247 /// The type of a specific closure.
248 ///
249 /// The closure signature is stored in a `FnPtr` type in the first type
250 /// parameter.
251 Closure(ClosureId, Substitution),
252
253 /// Represents a foreign type declared in external blocks.
254 ForeignType(ForeignDefId),
255
256 /// A pointer to a function. Written as `fn() -> i32`.
257 ///
258 /// For example the type of `bar` here:
259 ///
260 /// ```
261 /// fn foo() -> i32 { 1 }
262 /// let bar: fn() -> i32 = foo;
263 /// ```
264 Function(FnPointer),
265
266 /// An "alias" type represents some form of type alias, such as:
267 /// - An associated type projection like `<T as Iterator>::Item`
268 /// - `impl Trait` types
269 /// - Named type aliases like `type Foo<X> = Vec<X>`
270 Alias(AliasTy),
271
272 /// A placeholder for a type parameter; for example, `T` in `fn f<T>(x: T)
273 /// {}` when we're type-checking the body of that function. In this
274 /// situation, we know this stands for *some* type, but don't know the exact
275 /// type.
276 Placeholder(PlaceholderIndex),
277
278 /// A bound type variable. This is used in various places: when representing
279 /// some polymorphic type like the type of function `fn f<T>`, the type
280 /// parameters get turned into variables; during trait resolution, inference
281 /// variables get turned into bound variables and back; and in `Dyn` the
282 /// `Self` type is represented with a bound variable as well.
283 BoundVar(BoundVar),
284
285 /// A type variable used during type checking.
286 InferenceVar(InferenceVar, TyVariableKind),
287
288 /// A trait object (`dyn Trait` or bare `Trait` in pre-2018 Rust).
289 ///
290 /// The predicates are quantified over the `Self` type, i.e. `Ty::Bound(0)`
291 /// represents the `Self` type inside the bounds. This is currently
292 /// implicit; Chalk has the `Binders` struct to make it explicit, but it
293 /// didn't seem worth the overhead yet.
294 Dyn(DynTy),
295
296 /// A placeholder for a type which could not be computed; this is propagated
297 /// to avoid useless error messages. Doubles as a placeholder where type
298 /// variables are inserted before type checking, since we want to try to
299 /// infer a better type here anyway -- for the IDE use case, we want to try
300 /// to infer as much as possible even in the presence of type errors.
301 Unknown,
302}
303
304#[derive(Clone, PartialEq, Eq, Debug, Hash)]
305pub struct Ty(Arc<TyKind>);
306
307impl TyKind {
308 pub fn intern(self, _interner: &Interner) -> Ty {
309 Ty(Arc::new(self))
310 }
311}
312
313impl Ty {
314 pub fn interned(&self, _interner: &Interner) -> &TyKind {
315 &self.0
316 }
317
318 pub fn interned_mut(&mut self) -> &mut TyKind {
319 Arc::make_mut(&mut self.0)
320 }
321
322 pub fn into_inner(self) -> TyKind {
323 Arc::try_unwrap(self.0).unwrap_or_else(|a| (*a).clone())
324 }
325}
326
327/// A list of substitutions for generic parameters.
328#[derive(Clone, PartialEq, Eq, Debug, Hash)]
329pub struct Substitution(SmallVec<[Ty; 2]>);
330
331impl TypeWalk for Substitution {
332 fn walk(&self, f: &mut impl FnMut(&Ty)) {
333 for t in self.0.iter() {
334 t.walk(f);
335 }
336 }
337
338 fn walk_mut_binders(
339 &mut self,
340 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
341 binders: DebruijnIndex,
342 ) {
343 for t in &mut self.0 {
344 t.walk_mut_binders(f, binders);
345 }
346 }
347}
348
349impl Substitution {
350 pub fn interned(&self, _: &Interner) -> &[Ty] {
351 &self.0
352 }
353
354 pub fn empty() -> Substitution {
355 Substitution(SmallVec::new())
356 }
357
358 pub fn single(ty: Ty) -> Substitution {
359 Substitution({
360 let mut v = SmallVec::new();
361 v.push(ty);
362 v
363 })
364 }
365
366 pub fn prefix(&self, n: usize) -> Substitution {
367 Substitution(self.0[..std::cmp::min(self.0.len(), n)].into())
368 }
369
370 pub fn suffix(&self, n: usize) -> Substitution {
371 Substitution(self.0[self.0.len() - std::cmp::min(self.0.len(), n)..].into())
372 }
373
374 pub fn as_single(&self) -> &Ty {
375 if self.0.len() != 1 {
376 panic!("expected substs of len 1, got {:?}", self);
377 }
378 &self.0[0]
379 }
380
381 pub fn from_iter(_interner: &Interner, elements: impl IntoIterator<Item = Ty>) -> Self {
382 Substitution(elements.into_iter().collect())
383 }
384
385 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
386 pub(crate) fn type_params_for_generics(
387 db: &dyn HirDatabase,
388 generic_params: &Generics,
389 ) -> Substitution {
390 Substitution(
391 generic_params
392 .iter()
393 .map(|(id, _)| TyKind::Placeholder(to_placeholder_idx(db, id)).intern(&Interner))
394 .collect(),
395 )
396 }
397
398 /// Return Substs that replace each parameter by itself (i.e. `Ty::Param`).
399 pub fn type_params(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
400 let params = generics(db.upcast(), def.into());
401 Substitution::type_params_for_generics(db, &params)
402 }
403
404 /// Return Substs that replace each parameter by a bound variable.
405 pub(crate) fn bound_vars(generic_params: &Generics, debruijn: DebruijnIndex) -> Substitution {
406 Substitution(
407 generic_params
408 .iter()
409 .enumerate()
410 .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner))
411 .collect(),
412 )
413 }
414
415 pub fn build_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> SubstsBuilder {
416 let def = def.into();
417 let params = generics(db.upcast(), def);
418 let param_count = params.len();
419 Substitution::builder(param_count)
420 }
421
422 pub(crate) fn build_for_generics(generic_params: &Generics) -> SubstsBuilder {
423 Substitution::builder(generic_params.len())
424 }
425
426 fn builder(param_count: usize) -> SubstsBuilder {
427 SubstsBuilder { vec: Vec::with_capacity(param_count), param_count }
428 }
429} 123}
430 124
431/// 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.
@@ -433,244 +127,39 @@ pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
433 generics(db.upcast(), id.parent).param_idx(id) 127 generics(db.upcast(), id.parent).param_idx(id)
434} 128}
435 129
436#[derive(Debug, Clone)] 130pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
437pub struct SubstsBuilder { 131where
438 vec: Vec<Ty>, 132 T: Fold<Interner, Result = T> + HasInterner<Interner = Interner>,
439 param_count: usize, 133{
440} 134 Binders::empty(&Interner, value.shifted_in_from(&Interner, DebruijnIndex::ONE))
441 135}
442impl SubstsBuilder { 136
443 pub fn build(self) -> Substitution { 137pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
444 assert_eq!(self.vec.len(), self.param_count); 138 num_vars: usize,
445 Substitution(self.vec.into()) 139 value: T,
446 } 140) -> Binders<T> {
447 141 Binders::new(
448 pub fn push(mut self, ty: Ty) -> Self { 142 VariableKinds::from_iter(
449 self.vec.push(ty); 143 &Interner,
450 self 144 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
451 } 145 .take(num_vars),
452 146 ),
453 fn remaining(&self) -> usize { 147 value,
454 self.param_count - self.vec.len() 148 )
455 } 149}
456 150
457 pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self { 151// FIXME: get rid of this
458 self.fill( 152pub fn make_canonical<T: HasInterner<Interner = Interner>>(
459 (starting_from..) 153 value: T,
460 .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)), 154 kinds: impl IntoIterator<Item = TyVariableKind>,
155) -> Canonical<T> {
156 let kinds = kinds.into_iter().map(|tk| {
157 chalk_ir::CanonicalVarKind::new(
158 chalk_ir::VariableKind::Ty(tk),
159 chalk_ir::UniverseIndex::ROOT,
461 ) 160 )
462 } 161 });
463 162 Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
464 pub fn fill_with_unknown(self) -> Self {
465 self.fill(iter::repeat(TyKind::Unknown.intern(&Interner)))
466 }
467
468 pub fn fill(mut self, filler: impl Iterator<Item = Ty>) -> Self {
469 self.vec.extend(filler.take(self.remaining()));
470 assert_eq!(self.remaining(), 0);
471 self
472 }
473
474 pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
475 assert!(self.vec.is_empty());
476 assert!(parent_substs.len() <= self.param_count);
477 self.vec.extend(parent_substs.iter().cloned());
478 self
479 }
480}
481
482impl Deref for Substitution {
483 type Target = [Ty];
484
485 fn deref(&self) -> &[Ty] {
486 &self.0
487 }
488}
489
490#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)]
491pub struct Binders<T> {
492 pub num_binders: usize,
493 pub value: T,
494}
495
496impl<T> Binders<T> {
497 pub fn new(num_binders: usize, value: T) -> Self {
498 Self { num_binders, value }
499 }
500
501 pub fn wrap_empty(value: T) -> Self
502 where
503 T: TypeWalk,
504 {
505 Self { num_binders: 0, value: value.shift_bound_vars(DebruijnIndex::ONE) }
506 }
507
508 pub fn as_ref(&self) -> Binders<&T> {
509 Binders { num_binders: self.num_binders, value: &self.value }
510 }
511
512 pub fn map<U>(self, f: impl FnOnce(T) -> U) -> Binders<U> {
513 Binders { num_binders: self.num_binders, value: f(self.value) }
514 }
515
516 pub fn filter_map<U>(self, f: impl FnOnce(T) -> Option<U>) -> Option<Binders<U>> {
517 Some(Binders { num_binders: self.num_binders, value: f(self.value)? })
518 }
519
520 pub fn skip_binders(&self) -> &T {
521 &self.value
522 }
523
524 pub fn into_value_and_skipped_binders(self) -> (T, usize) {
525 (self.value, self.num_binders)
526 }
527}
528
529impl<T: Clone> Binders<&T> {
530 pub fn cloned(&self) -> Binders<T> {
531 Binders { num_binders: self.num_binders, value: self.value.clone() }
532 }
533}
534
535impl<T: TypeWalk> Binders<T> {
536 /// Substitutes all variables.
537 pub fn subst(self, subst: &Substitution) -> T {
538 assert_eq!(subst.len(), self.num_binders);
539 self.value.subst_bound_vars(subst)
540 }
541}
542
543impl<T: TypeWalk> TypeWalk for Binders<T> {
544 fn walk(&self, f: &mut impl FnMut(&Ty)) {
545 self.value.walk(f);
546 }
547
548 fn walk_mut_binders(
549 &mut self,
550 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
551 binders: DebruijnIndex,
552 ) {
553 self.value.walk_mut_binders(f, binders.shifted_in())
554 }
555}
556
557/// A trait with type parameters. This includes the `Self`, so this represents a concrete type implementing the trait.
558#[derive(Clone, PartialEq, Eq, Debug, Hash)]
559pub struct TraitRef {
560 pub trait_id: ChalkTraitId,
561 pub substitution: Substitution,
562}
563
564impl TraitRef {
565 pub fn self_type_parameter(&self) -> &Ty {
566 &self.substitution[0]
567 }
568
569 pub fn hir_trait_id(&self) -> TraitId {
570 from_chalk_trait_id(self.trait_id)
571 }
572}
573
574impl TypeWalk for TraitRef {
575 fn walk(&self, f: &mut impl FnMut(&Ty)) {
576 self.substitution.walk(f);
577 }
578
579 fn walk_mut_binders(
580 &mut self,
581 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
582 binders: DebruijnIndex,
583 ) {
584 self.substitution.walk_mut_binders(f, binders);
585 }
586}
587
588/// Like `generics::WherePredicate`, but with resolved types: A condition on the
589/// parameters of a generic item.
590#[derive(Debug, Clone, PartialEq, Eq, Hash)]
591pub enum WhereClause {
592 /// The given trait needs to be implemented for its type parameters.
593 Implemented(TraitRef),
594 /// An associated type bindings like in `Iterator<Item = T>`.
595 AliasEq(AliasEq),
596}
597
598impl WhereClause {
599 pub fn is_implemented(&self) -> bool {
600 matches!(self, WhereClause::Implemented(_))
601 }
602
603 pub fn trait_ref(&self, db: &dyn HirDatabase) -> Option<TraitRef> {
604 match self {
605 WhereClause::Implemented(tr) => Some(tr.clone()),
606 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(proj), .. }) => {
607 Some(proj.trait_ref(db))
608 }
609 WhereClause::AliasEq(_) => None,
610 }
611 }
612}
613
614impl TypeWalk for WhereClause {
615 fn walk(&self, f: &mut impl FnMut(&Ty)) {
616 match self {
617 WhereClause::Implemented(trait_ref) => trait_ref.walk(f),
618 WhereClause::AliasEq(alias_eq) => alias_eq.walk(f),
619 }
620 }
621
622 fn walk_mut_binders(
623 &mut self,
624 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
625 binders: DebruijnIndex,
626 ) {
627 match self {
628 WhereClause::Implemented(trait_ref) => trait_ref.walk_mut_binders(f, binders),
629 WhereClause::AliasEq(alias_eq) => alias_eq.walk_mut_binders(f, binders),
630 }
631 }
632}
633
634pub type QuantifiedWhereClause = Binders<WhereClause>;
635
636#[derive(Debug, Clone, PartialEq, Eq, Hash)]
637pub struct QuantifiedWhereClauses(Arc<[QuantifiedWhereClause]>);
638
639impl QuantifiedWhereClauses {
640 pub fn from_iter(
641 _interner: &Interner,
642 elements: impl IntoIterator<Item = QuantifiedWhereClause>,
643 ) -> Self {
644 QuantifiedWhereClauses(elements.into_iter().collect())
645 }
646
647 pub fn interned(&self) -> &Arc<[QuantifiedWhereClause]> {
648 &self.0
649 }
650}
651
652/// Basically a claim (currently not validated / checked) that the contained
653/// type / trait ref contains no inference variables; any inference variables it
654/// contained have been replaced by bound variables, and `kinds` tells us how
655/// many there are and whether they were normal or float/int variables. This is
656/// used to erase irrelevant differences between types before using them in
657/// queries.
658#[derive(Debug, Clone, PartialEq, Eq, Hash)]
659pub struct Canonical<T> {
660 pub value: T,
661 pub binders: CanonicalVarKinds,
662}
663
664impl<T> Canonical<T> {
665 pub fn new(value: T, kinds: impl IntoIterator<Item = TyVariableKind>) -> Self {
666 let kinds = kinds.into_iter().map(|tk| {
667 chalk_ir::CanonicalVarKind::new(
668 chalk_ir::VariableKind::Ty(tk),
669 chalk_ir::UniverseIndex::ROOT,
670 )
671 });
672 Self { value, binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds) }
673 }
674} 163}
675 164
676/// 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
@@ -681,6 +170,8 @@ pub struct CallableSig {
681 is_varargs: bool, 170 is_varargs: bool,
682} 171}
683 172
173has_interner!(CallableSig);
174
684/// A polymorphic function signature. 175/// A polymorphic function signature.
685pub type PolyFnSig = Binders<CallableSig>; 176pub type PolyFnSig = Binders<CallableSig>;
686 177
@@ -692,23 +183,21 @@ impl CallableSig {
692 183
693 pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig { 184 pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
694 CallableSig { 185 CallableSig {
695 // FIXME: what to do about lifetime params? 186 // FIXME: what to do about lifetime params? -> return PolyFnSig
696 params_and_return: fn_ptr 187 params_and_return: fn_ptr
697 .substs 188 .substitution
698 .clone() 189 .clone()
699 .shift_bound_vars_out(DebruijnIndex::ONE) 190 .shifted_out_to(&Interner, DebruijnIndex::ONE)
700 .interned(&Interner) 191 .expect("unexpected lifetime vars in fn ptr")
192 .0
193 .as_slice(&Interner)
701 .iter() 194 .iter()
702 .cloned() 195 .map(|arg| arg.assert_ty_ref(&Interner).clone())
703 .collect(), 196 .collect(),
704 is_varargs: fn_ptr.sig.variadic, 197 is_varargs: fn_ptr.sig.variadic,
705 } 198 }
706 } 199 }
707 200
708 pub fn from_substs(substs: &Substitution) -> CallableSig {
709 CallableSig { params_and_return: substs.iter().cloned().collect(), is_varargs: false }
710 }
711
712 pub fn params(&self) -> &[Ty] { 201 pub fn params(&self) -> &[Ty] {
713 &self.params_and_return[0..self.params_and_return.len() - 1] 202 &self.params_and_return[0..self.params_and_return.len() - 1]
714 } 203 }
@@ -718,516 +207,20 @@ impl CallableSig {
718 } 207 }
719} 208}
720 209
721impl TypeWalk for CallableSig { 210impl Fold<Interner> for CallableSig {
722 fn walk(&self, f: &mut impl FnMut(&Ty)) { 211 type Result = CallableSig;
723 for t in self.params_and_return.iter() {
724 t.walk(f);
725 }
726 }
727
728 fn walk_mut_binders(
729 &mut self,
730 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
731 binders: DebruijnIndex,
732 ) {
733 for t in make_mut_slice(&mut self.params_and_return) {
734 t.walk_mut_binders(f, binders);
735 }
736 }
737}
738
739impl Ty {
740 pub fn unit() -> Self {
741 TyKind::Tuple(0, Substitution::empty()).intern(&Interner)
742 }
743
744 pub fn adt_ty(adt: hir_def::AdtId, substs: Substitution) -> Ty {
745 TyKind::Adt(AdtId(adt), substs).intern(&Interner)
746 }
747
748 pub fn fn_ptr(sig: CallableSig) -> Self {
749 TyKind::Function(FnPointer {
750 num_args: sig.params().len(),
751 sig: FnSig { abi: (), safety: Safety::Safe, variadic: sig.is_varargs },
752 substs: Substitution::from_iter(&Interner, sig.params_and_return.iter().cloned()),
753 })
754 .intern(&Interner)
755 }
756
757 pub fn builtin(builtin: BuiltinType) -> Self {
758 match builtin {
759 BuiltinType::Char => TyKind::Scalar(Scalar::Char).intern(&Interner),
760 BuiltinType::Bool => TyKind::Scalar(Scalar::Bool).intern(&Interner),
761 BuiltinType::Str => TyKind::Str.intern(&Interner),
762 BuiltinType::Int(t) => {
763 TyKind::Scalar(Scalar::Int(primitive::int_ty_from_builtin(t))).intern(&Interner)
764 }
765 BuiltinType::Uint(t) => {
766 TyKind::Scalar(Scalar::Uint(primitive::uint_ty_from_builtin(t))).intern(&Interner)
767 }
768 BuiltinType::Float(t) => {
769 TyKind::Scalar(Scalar::Float(primitive::float_ty_from_builtin(t))).intern(&Interner)
770 }
771 }
772 }
773
774 pub fn as_reference(&self) -> Option<(&Ty, Mutability)> {
775 match self.interned(&Interner) {
776 TyKind::Ref(mutability, ty) => Some((ty, *mutability)),
777 _ => None,
778 }
779 }
780
781 pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> {
782 match self.interned(&Interner) {
783 TyKind::Ref(mutability, ty) => Some((ty, Rawness::Ref, *mutability)),
784 TyKind::Raw(mutability, ty) => Some((ty, Rawness::RawPtr, *mutability)),
785 _ => None,
786 }
787 }
788
789 pub fn strip_references(&self) -> &Ty {
790 let mut t: &Ty = self;
791
792 while let TyKind::Ref(_mutability, ty) = t.interned(&Interner) {
793 t = ty;
794 }
795
796 t
797 }
798
799 pub fn as_adt(&self) -> Option<(hir_def::AdtId, &Substitution)> {
800 match self.interned(&Interner) {
801 TyKind::Adt(AdtId(adt), parameters) => Some((*adt, parameters)),
802 _ => None,
803 }
804 }
805
806 pub fn as_tuple(&self) -> Option<&Substitution> {
807 match self.interned(&Interner) {
808 TyKind::Tuple(_, substs) => Some(substs),
809 _ => None,
810 }
811 }
812 212
813 pub fn as_generic_def(&self, db: &dyn HirDatabase) -> Option<GenericDefId> { 213 fn fold_with<'i>(
814 match *self.interned(&Interner) { 214 self,
815 TyKind::Adt(AdtId(adt), ..) => Some(adt.into()), 215 folder: &mut dyn chalk_ir::fold::Folder<'i, Interner>,
816 TyKind::FnDef(callable, ..) => { 216 outer_binder: DebruijnIndex,
817 Some(db.lookup_intern_callable_def(callable.into()).into()) 217 ) -> chalk_ir::Fallible<Self::Result>
818 }
819 TyKind::AssociatedType(type_alias, ..) => Some(from_assoc_type_id(type_alias).into()),
820 TyKind::ForeignType(type_alias, ..) => Some(from_foreign_def_id(type_alias).into()),
821 _ => None,
822 }
823 }
824
825 pub fn is_never(&self) -> bool {
826 matches!(self.interned(&Interner), TyKind::Never)
827 }
828
829 pub fn is_unknown(&self) -> bool {
830 matches!(self.interned(&Interner), TyKind::Unknown)
831 }
832
833 pub fn equals_ctor(&self, other: &Ty) -> bool {
834 match (self.interned(&Interner), other.interned(&Interner)) {
835 (TyKind::Adt(adt, ..), TyKind::Adt(adt2, ..)) => adt == adt2,
836 (TyKind::Slice(_), TyKind::Slice(_)) | (TyKind::Array(_), TyKind::Array(_)) => true,
837 (TyKind::FnDef(def_id, ..), TyKind::FnDef(def_id2, ..)) => def_id == def_id2,
838 (TyKind::OpaqueType(ty_id, ..), TyKind::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
839 (TyKind::AssociatedType(ty_id, ..), TyKind::AssociatedType(ty_id2, ..)) => {
840 ty_id == ty_id2
841 }
842 (TyKind::ForeignType(ty_id, ..), TyKind::ForeignType(ty_id2, ..)) => ty_id == ty_id2,
843 (TyKind::Closure(id1, _), TyKind::Closure(id2, _)) => id1 == id2,
844 (TyKind::Ref(mutability, ..), TyKind::Ref(mutability2, ..))
845 | (TyKind::Raw(mutability, ..), TyKind::Raw(mutability2, ..)) => {
846 mutability == mutability2
847 }
848 (
849 TyKind::Function(FnPointer { num_args, sig, .. }),
850 TyKind::Function(FnPointer { num_args: num_args2, sig: sig2, .. }),
851 ) => num_args == num_args2 && sig == sig2,
852 (TyKind::Tuple(cardinality, _), TyKind::Tuple(cardinality2, _)) => {
853 cardinality == cardinality2
854 }
855 (TyKind::Str, TyKind::Str) | (TyKind::Never, TyKind::Never) => true,
856 (TyKind::Scalar(scalar), TyKind::Scalar(scalar2)) => scalar == scalar2,
857 _ => false,
858 }
859 }
860
861 /// If this is a `dyn Trait` type, this returns the `Trait` part.
862 fn dyn_trait_ref(&self) -> Option<&TraitRef> {
863 match self.interned(&Interner) {
864 TyKind::Dyn(dyn_ty) => {
865 dyn_ty.bounds.value.interned().get(0).and_then(|b| match b.skip_binders() {
866 WhereClause::Implemented(trait_ref) => Some(trait_ref),
867 _ => None,
868 })
869 }
870 _ => None,
871 }
872 }
873
874 /// If this is a `dyn Trait`, returns that trait.
875 pub fn dyn_trait(&self) -> Option<TraitId> {
876 self.dyn_trait_ref().map(|it| it.trait_id).map(from_chalk_trait_id)
877 }
878
879 fn builtin_deref(&self) -> Option<Ty> {
880 match self.interned(&Interner) {
881 TyKind::Ref(.., ty) => Some(ty.clone()),
882 TyKind::Raw(.., ty) => Some(ty.clone()),
883 _ => None,
884 }
885 }
886
887 pub fn callable_def(&self, db: &dyn HirDatabase) -> Option<CallableDefId> {
888 match self.interned(&Interner) {
889 &TyKind::FnDef(def, ..) => Some(db.lookup_intern_callable_def(def.into())),
890 _ => None,
891 }
892 }
893
894 pub fn as_fn_def(&self, db: &dyn HirDatabase) -> Option<FunctionId> {
895 if let Some(CallableDefId::FunctionId(func)) = self.callable_def(db) {
896 Some(func)
897 } else {
898 None
899 }
900 }
901
902 pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
903 match self.interned(&Interner) {
904 TyKind::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
905 TyKind::FnDef(def, parameters) => {
906 let callable_def = db.lookup_intern_callable_def((*def).into());
907 let sig = db.callable_item_signature(callable_def);
908 Some(sig.subst(&parameters))
909 }
910 TyKind::Closure(.., substs) => {
911 let sig_param = &substs[0];
912 sig_param.callable_sig(db)
913 }
914 _ => None,
915 }
916 }
917
918 /// Returns the type parameters of this type if it has some (i.e. is an ADT
919 /// or function); so if `self` is `Option<u32>`, this returns the `u32`.
920 pub fn substs(&self) -> Option<&Substitution> {
921 match self.interned(&Interner) {
922 TyKind::Adt(_, substs)
923 | TyKind::FnDef(_, substs)
924 | TyKind::Function(FnPointer { substs, .. })
925 | TyKind::Tuple(_, substs)
926 | TyKind::OpaqueType(_, substs)
927 | TyKind::AssociatedType(_, substs)
928 | TyKind::Closure(.., substs) => Some(substs),
929 _ => None,
930 }
931 }
932
933 fn substs_mut(&mut self) -> Option<&mut Substitution> {
934 match self.interned_mut() {
935 TyKind::Adt(_, substs)
936 | TyKind::FnDef(_, substs)
937 | TyKind::Function(FnPointer { substs, .. })
938 | TyKind::Tuple(_, substs)
939 | TyKind::OpaqueType(_, substs)
940 | TyKind::AssociatedType(_, substs)
941 | TyKind::Closure(.., substs) => Some(substs),
942 _ => None,
943 }
944 }
945
946 pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<QuantifiedWhereClause>> {
947 match self.interned(&Interner) {
948 TyKind::OpaqueType(opaque_ty_id, ..) => {
949 match db.lookup_intern_impl_trait_id((*opaque_ty_id).into()) {
950 ImplTraitId::AsyncBlockTypeImplTrait(def, _expr) => {
951 let krate = def.module(db.upcast()).krate();
952 if let Some(future_trait) = db
953 .lang_item(krate, "future_trait".into())
954 .and_then(|item| item.as_trait())
955 {
956 // This is only used by type walking.
957 // Parameters will be walked outside, and projection predicate is not used.
958 // So just provide the Future trait.
959 let impl_bound = Binders::new(
960 0,
961 WhereClause::Implemented(TraitRef {
962 trait_id: to_chalk_trait_id(future_trait),
963 substitution: Substitution::empty(),
964 }),
965 );
966 Some(vec![impl_bound])
967 } else {
968 None
969 }
970 }
971 ImplTraitId::ReturnTypeImplTrait(..) => None,
972 }
973 }
974 TyKind::Alias(AliasTy::Opaque(opaque_ty)) => {
975 let predicates = match db.lookup_intern_impl_trait_id(opaque_ty.opaque_ty_id.into())
976 {
977 ImplTraitId::ReturnTypeImplTrait(func, idx) => {
978 db.return_type_impl_traits(func).map(|it| {
979 let data = (*it)
980 .as_ref()
981 .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone());
982 data.subst(&opaque_ty.substitution)
983 })
984 }
985 // It always has an parameter for Future::Output type.
986 ImplTraitId::AsyncBlockTypeImplTrait(..) => unreachable!(),
987 };
988
989 predicates.map(|it| it.value)
990 }
991 TyKind::Placeholder(idx) => {
992 let id = from_placeholder_idx(db, *idx);
993 let generic_params = db.generic_params(id.parent);
994 let param_data = &generic_params.types[id.local_id];
995 match param_data.provenance {
996 hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
997 let substs = Substitution::type_params(db, id.parent);
998 let predicates = db
999 .generic_predicates(id.parent)
1000 .into_iter()
1001 .map(|pred| pred.clone().subst(&substs))
1002 .filter(|wc| match &wc.skip_binders() {
1003 WhereClause::Implemented(tr) => tr.self_type_parameter() == self,
1004 WhereClause::AliasEq(AliasEq {
1005 alias: AliasTy::Projection(proj),
1006 ty: _,
1007 }) => proj.self_type_parameter() == self,
1008 _ => false,
1009 })
1010 .collect_vec();
1011
1012 Some(predicates)
1013 }
1014 _ => None,
1015 }
1016 }
1017 _ => None,
1018 }
1019 }
1020
1021 pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> {
1022 match self.interned(&Interner) {
1023 TyKind::AssociatedType(id, ..) => {
1024 match from_assoc_type_id(*id).lookup(db.upcast()).container {
1025 AssocContainerId::TraitId(trait_id) => Some(trait_id),
1026 _ => None,
1027 }
1028 }
1029 TyKind::Alias(AliasTy::Projection(projection_ty)) => {
1030 match from_assoc_type_id(projection_ty.associated_ty_id)
1031 .lookup(db.upcast())
1032 .container
1033 {
1034 AssocContainerId::TraitId(trait_id) => Some(trait_id),
1035 _ => None,
1036 }
1037 }
1038 _ => None,
1039 }
1040 }
1041}
1042
1043/// This allows walking structures that contain types to do something with those
1044/// types, similar to Chalk's `Fold` trait.
1045pub trait TypeWalk {
1046 fn walk(&self, f: &mut impl FnMut(&Ty));
1047 fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
1048 self.walk_mut_binders(&mut |ty, _binders| f(ty), DebruijnIndex::INNERMOST);
1049 }
1050 /// Walk the type, counting entered binders.
1051 ///
1052 /// `TyKind::Bound` variables use DeBruijn indexing, which means that 0 refers
1053 /// to the innermost binder, 1 to the next, etc.. So when we want to
1054 /// substitute a certain bound variable, we can't just walk the whole type
1055 /// and blindly replace each instance of a certain index; when we 'enter'
1056 /// things that introduce new bound variables, we have to keep track of
1057 /// that. Currently, the only thing that introduces bound variables on our
1058 /// side are `TyKind::Dyn` and `TyKind::Opaque`, which each introduce a bound
1059 /// variable for the self type.
1060 fn walk_mut_binders(
1061 &mut self,
1062 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1063 binders: DebruijnIndex,
1064 );
1065
1066 fn fold_binders(
1067 mut self,
1068 f: &mut impl FnMut(Ty, DebruijnIndex) -> Ty,
1069 binders: DebruijnIndex,
1070 ) -> Self
1071 where
1072 Self: Sized,
1073 {
1074 self.walk_mut_binders(
1075 &mut |ty_mut, binders| {
1076 let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
1077 *ty_mut = f(ty, binders);
1078 },
1079 binders,
1080 );
1081 self
1082 }
1083
1084 fn fold(mut self, f: &mut impl FnMut(Ty) -> Ty) -> Self
1085 where
1086 Self: Sized,
1087 {
1088 self.walk_mut(&mut |ty_mut| {
1089 let ty = mem::replace(ty_mut, TyKind::Unknown.intern(&Interner));
1090 *ty_mut = f(ty);
1091 });
1092 self
1093 }
1094
1095 /// Substitutes `TyKind::Bound` vars with the given substitution.
1096 fn subst_bound_vars(self, substs: &Substitution) -> Self
1097 where
1098 Self: Sized,
1099 {
1100 self.subst_bound_vars_at_depth(substs, DebruijnIndex::INNERMOST)
1101 }
1102
1103 /// Substitutes `TyKind::Bound` vars with the given substitution.
1104 fn subst_bound_vars_at_depth(mut self, substs: &Substitution, depth: DebruijnIndex) -> Self
1105 where
1106 Self: Sized,
1107 {
1108 self.walk_mut_binders(
1109 &mut |ty, binders| {
1110 if let &mut TyKind::BoundVar(bound) = ty.interned_mut() {
1111 if bound.debruijn >= binders {
1112 *ty = substs.0[bound.index].clone().shift_bound_vars(binders);
1113 }
1114 }
1115 },
1116 depth,
1117 );
1118 self
1119 }
1120
1121 /// Shifts up debruijn indices of `TyKind::Bound` vars by `n`.
1122 fn shift_bound_vars(self, n: DebruijnIndex) -> Self
1123 where
1124 Self: Sized,
1125 {
1126 self.fold_binders(
1127 &mut |ty, binders| match ty.interned(&Interner) {
1128 TyKind::BoundVar(bound) if bound.debruijn >= binders => {
1129 TyKind::BoundVar(bound.shifted_in_from(n)).intern(&Interner)
1130 }
1131 _ => ty,
1132 },
1133 DebruijnIndex::INNERMOST,
1134 )
1135 }
1136
1137 /// Shifts debruijn indices of `TyKind::Bound` vars out (down) by `n`.
1138 fn shift_bound_vars_out(self, n: DebruijnIndex) -> Self
1139 where 218 where
1140 Self: Sized + std::fmt::Debug, 219 Interner: 'i,
1141 { 220 {
1142 self.fold_binders( 221 let vec = self.params_and_return.to_vec();
1143 &mut |ty, binders| match ty.interned(&Interner) { 222 let folded = vec.fold_with(folder, outer_binder)?;
1144 TyKind::BoundVar(bound) if bound.debruijn >= binders => { 223 Ok(CallableSig { params_and_return: folded.into(), is_varargs: self.is_varargs })
1145 TyKind::BoundVar(bound.shifted_out_to(n).unwrap_or(bound.clone()))
1146 .intern(&Interner)
1147 }
1148 _ => ty,
1149 },
1150 DebruijnIndex::INNERMOST,
1151 )
1152 }
1153}
1154
1155impl TypeWalk for Ty {
1156 fn walk(&self, f: &mut impl FnMut(&Ty)) {
1157 match self.interned(&Interner) {
1158 TyKind::Alias(AliasTy::Projection(p_ty)) => {
1159 for t in p_ty.substitution.iter() {
1160 t.walk(f);
1161 }
1162 }
1163 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
1164 for t in o_ty.substitution.iter() {
1165 t.walk(f);
1166 }
1167 }
1168 TyKind::Dyn(dyn_ty) => {
1169 for p in dyn_ty.bounds.value.interned().iter() {
1170 p.walk(f);
1171 }
1172 }
1173 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
1174 ty.walk(f);
1175 }
1176 _ => {
1177 if let Some(substs) = self.substs() {
1178 for t in substs.iter() {
1179 t.walk(f);
1180 }
1181 }
1182 }
1183 }
1184 f(self);
1185 }
1186
1187 fn walk_mut_binders(
1188 &mut self,
1189 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1190 binders: DebruijnIndex,
1191 ) {
1192 match self.interned_mut() {
1193 TyKind::Alias(AliasTy::Projection(p_ty)) => {
1194 p_ty.substitution.walk_mut_binders(f, binders);
1195 }
1196 TyKind::Dyn(dyn_ty) => {
1197 for p in make_mut_slice(&mut dyn_ty.bounds.value.0) {
1198 p.walk_mut_binders(f, binders.shifted_in());
1199 }
1200 }
1201 TyKind::Alias(AliasTy::Opaque(o_ty)) => {
1202 o_ty.substitution.walk_mut_binders(f, binders);
1203 }
1204 TyKind::Slice(ty) | TyKind::Array(ty) | TyKind::Ref(_, ty) | TyKind::Raw(_, ty) => {
1205 ty.walk_mut_binders(f, binders);
1206 }
1207 _ => {
1208 if let Some(substs) = self.substs_mut() {
1209 substs.walk_mut_binders(f, binders);
1210 }
1211 }
1212 }
1213 f(self, binders);
1214 }
1215}
1216
1217impl<T: TypeWalk> TypeWalk for Vec<T> {
1218 fn walk(&self, f: &mut impl FnMut(&Ty)) {
1219 for t in self {
1220 t.walk(f);
1221 }
1222 }
1223 fn walk_mut_binders(
1224 &mut self,
1225 f: &mut impl FnMut(&mut Ty, DebruijnIndex),
1226 binders: DebruijnIndex,
1227 ) {
1228 for t in self {
1229 t.walk_mut_binders(f, binders);
1230 }
1231 } 224 }
1232} 225}
1233 226
@@ -1242,45 +235,75 @@ pub struct ReturnTypeImplTraits {
1242 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>, 235 pub(crate) impl_traits: Vec<ReturnTypeImplTrait>,
1243} 236}
1244 237
238has_interner!(ReturnTypeImplTraits);
239
1245#[derive(Clone, PartialEq, Eq, Debug, Hash)] 240#[derive(Clone, PartialEq, Eq, Debug, Hash)]
1246pub(crate) struct ReturnTypeImplTrait { 241pub(crate) struct ReturnTypeImplTrait {
1247 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>, 242 pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
1248} 243}
1249 244
1250pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId { 245pub fn static_lifetime() -> Lifetime {
1251 chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id)) 246 LifetimeData::Static.intern(&Interner)
1252} 247}
1253 248
1254pub fn from_foreign_def_id(id: ForeignDefId) -> TypeAliasId { 249pub fn dummy_usize_const() -> Const {
1255 salsa::InternKey::from_intern_id(id.0) 250 let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
1256} 251 chalk_ir::ConstData {
1257 252 ty: usize_ty,
1258pub fn to_assoc_type_id(id: TypeAliasId) -> AssocTypeId { 253 value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
1259 chalk_ir::AssocTypeId(salsa::InternKey::as_intern_id(&id)) 254 }
255 .intern(&Interner)
1260} 256}
1261 257
1262pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId { 258pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
1263 salsa::InternKey::from_intern_id(id.0) 259 t: T,
1264} 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 }
1265 268
1266pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId { 269 fn interner(&self) -> &'i Interner {
1267 assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT); 270 &Interner
1268 let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx)); 271 }
1269 db.lookup_intern_type_param_id(interned_id)
1270}
1271 272
1272pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex { 273 fn fold_free_var_ty(
1273 let interned_id = db.intern_type_param_id(id); 274 &mut self,
1274 PlaceholderIndex { 275 bound_var: BoundVar,
1275 ui: chalk_ir::UniverseIndex::ROOT, 276 outer_binder: DebruijnIndex,
1276 idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(), 277 ) -> Fallible<Ty> {
278 Ok(self.0(bound_var, outer_binder))
279 }
1277 } 280 }
281 t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
1278} 282}
1279 283
1280pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId { 284pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
1281 chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id)) 285 t: T,
1282} 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 }
1283 302
1284pub fn from_chalk_trait_id(id: ChalkTraitId) -> TraitId { 303 fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
1285 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")
1286} 309}
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index c87789d45..a035686bc 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -8,14 +8,14 @@
8use std::{iter, sync::Arc}; 8use std::{iter, sync::Arc};
9 9
10use base_db::CrateId; 10use base_db::CrateId;
11use chalk_ir::{cast::Cast, Mutability, Safety}; 11use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
12use hir_def::{ 12use hir_def::{
13 adt::StructKind, 13 adt::StructKind,
14 builtin_type::BuiltinType, 14 builtin_type::BuiltinType,
15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget}, 15 generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
16 path::{GenericArg, Path, PathSegment, PathSegments}, 16 path::{GenericArg, Path, PathSegment, PathSegments},
17 resolver::{HasResolver, Resolver, TypeNs}, 17 resolver::{HasResolver, Resolver, TypeNs},
18 type_ref::{TypeBound, TypeRef}, 18 type_ref::{TraitRef as HirTraitRef, TypeBound, TypeRef},
19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, 19 AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, 20 GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
21 TypeAliasId, TypeParamId, UnionId, VariantId, 21 TypeAliasId, TypeParamId, UnionId, VariantId,
@@ -27,16 +27,16 @@ use stdx::impl_from;
27 27
28use crate::{ 28use crate::{
29 db::HirDatabase, 29 db::HirDatabase,
30 to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, 30 dummy_usize_const,
31 traits::chalk::{Interner, ToChalk}, 31 mapping::ToChalk,
32 static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
32 utils::{ 33 utils::{
33 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, 34 all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
34 variant_data,
35 }, 35 },
36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, 36 AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
37 ImplTraitId, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, QuantifiedWhereClauses, 37 FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
38 ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, TraitEnvironment, TraitRef, Ty, 38 QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
39 TyKind, TypeWalk, WhereClause, 39 TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
40}; 40};
41 41
42#[derive(Debug)] 42#[derive(Debug)]
@@ -146,7 +146,7 @@ impl<'a> TyLoweringContext<'a> {
146 self.lower_ty_ext(type_ref).0 146 self.lower_ty_ext(type_ref).0
147 } 147 }
148 148
149 fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) { 149 pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
150 let mut res = None; 150 let mut res = None;
151 let ty = match type_ref { 151 let ty = match type_ref {
152 TypeRef::Never => TyKind::Never.intern(&Interner), 152 TypeRef::Never => TyKind::Never.intern(&Interner),
@@ -166,7 +166,7 @@ impl<'a> TyLoweringContext<'a> {
166 } 166 }
167 TypeRef::Array(inner) => { 167 TypeRef::Array(inner) => {
168 let inner_ty = self.lower_ty(inner); 168 let inner_ty = self.lower_ty(inner);
169 TyKind::Array(inner_ty).intern(&Interner) 169 TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
170 } 170 }
171 TypeRef::Slice(inner) => { 171 TypeRef::Slice(inner) => {
172 let inner_ty = self.lower_ty(inner); 172 let inner_ty = self.lower_ty(inner);
@@ -174,15 +174,19 @@ impl<'a> TyLoweringContext<'a> {
174 } 174 }
175 TypeRef::Reference(inner, _, mutability) => { 175 TypeRef::Reference(inner, _, mutability) => {
176 let inner_ty = self.lower_ty(inner); 176 let inner_ty = self.lower_ty(inner);
177 TyKind::Ref(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner) 177 let lifetime = static_lifetime();
178 TyKind::Ref(lower_to_chalk_mutability(*mutability), lifetime, inner_ty)
179 .intern(&Interner)
178 } 180 }
179 TypeRef::Placeholder => TyKind::Unknown.intern(&Interner), 181 TypeRef::Placeholder => TyKind::Error.intern(&Interner),
180 TypeRef::Fn(params, is_varargs) => { 182 TypeRef::Fn(params, is_varargs) => {
181 let substs = Substitution(params.iter().map(|tr| self.lower_ty(tr)).collect()); 183 let substs = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
184 Substitution::from_iter(&Interner, params.iter().map(|tr| ctx.lower_ty(tr)))
185 });
182 TyKind::Function(FnPointer { 186 TyKind::Function(FnPointer {
183 num_args: substs.len() - 1, 187 num_binders: 0, // FIXME lower `for<'a> fn()` correctly
184 sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs }, 188 sig: FnSig { abi: (), safety: Safety::Safe, variadic: *is_varargs },
185 substs, 189 substitution: FnSubst(substs),
186 }) 190 })
187 .intern(&Interner) 191 .intern(&Interner)
188 } 192 }
@@ -195,8 +199,8 @@ impl<'a> TyLoweringContext<'a> {
195 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)), 199 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
196 ) 200 )
197 }); 201 });
198 let bounds = Binders::new(1, bounds); 202 let bounds = crate::make_only_type_binders(1, bounds);
199 TyKind::Dyn(DynTy { bounds }).intern(&Interner) 203 TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(&Interner)
200 } 204 }
201 TypeRef::ImplTrait(bounds) => { 205 TypeRef::ImplTrait(bounds) => {
202 match self.impl_trait_mode { 206 match self.impl_trait_mode {
@@ -208,9 +212,9 @@ impl<'a> TyLoweringContext<'a> {
208 // this dance is to make sure the data is in the right 212 // this dance is to make sure the data is in the right
209 // place even if we encounter more opaque types while 213 // place even if we encounter more opaque types while
210 // lowering the bounds 214 // lowering the bounds
211 self.opaque_type_data 215 self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
212 .borrow_mut() 216 bounds: crate::make_only_type_binders(1, Vec::new()),
213 .push(ReturnTypeImplTrait { bounds: Binders::new(1, Vec::new()) }); 217 });
214 // We don't want to lower the bounds inside the binders 218 // We don't want to lower the bounds inside the binders
215 // we're currently in, because they don't end up inside 219 // we're currently in, because they don't end up inside
216 // those binders. E.g. when we have `impl Trait<impl 220 // those binders. E.g. when we have `impl Trait<impl
@@ -233,7 +237,7 @@ impl<'a> TyLoweringContext<'a> {
233 let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx); 237 let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
234 let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into(); 238 let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
235 let generics = generics(self.db.upcast(), func.into()); 239 let generics = generics(self.db.upcast(), func.into());
236 let parameters = Substitution::bound_vars(&generics, self.in_binders); 240 let parameters = generics.bound_vars_subst(self.in_binders);
237 TyKind::Alias(AliasTy::Opaque(OpaqueTy { 241 TyKind::Alias(AliasTy::Opaque(OpaqueTy {
238 opaque_ty_id, 242 opaque_ty_id,
239 substitution: parameters, 243 substitution: parameters,
@@ -252,12 +256,12 @@ impl<'a> TyLoweringContext<'a> {
252 data.provenance == TypeParamProvenance::ArgumentImplTrait 256 data.provenance == TypeParamProvenance::ArgumentImplTrait
253 }) 257 })
254 .nth(idx as usize) 258 .nth(idx as usize)
255 .map_or(TyKind::Unknown, |(id, _)| { 259 .map_or(TyKind::Error, |(id, _)| {
256 TyKind::Placeholder(to_placeholder_idx(self.db, id)) 260 TyKind::Placeholder(to_placeholder_idx(self.db, id))
257 }); 261 });
258 param.intern(&Interner) 262 param.intern(&Interner)
259 } else { 263 } else {
260 TyKind::Unknown.intern(&Interner) 264 TyKind::Error.intern(&Interner)
261 } 265 }
262 } 266 }
263 ImplTraitLoweringMode::Variable => { 267 ImplTraitLoweringMode::Variable => {
@@ -279,11 +283,11 @@ impl<'a> TyLoweringContext<'a> {
279 } 283 }
280 ImplTraitLoweringMode::Disallowed => { 284 ImplTraitLoweringMode::Disallowed => {
281 // FIXME: report error 285 // FIXME: report error
282 TyKind::Unknown.intern(&Interner) 286 TyKind::Error.intern(&Interner)
283 } 287 }
284 } 288 }
285 } 289 }
286 TypeRef::Error => TyKind::Unknown.intern(&Interner), 290 TypeRef::Error => TyKind::Error.intern(&Interner),
287 }; 291 };
288 (ty, res) 292 (ty, res)
289 } 293 }
@@ -327,7 +331,7 @@ impl<'a> TyLoweringContext<'a> {
327 (self.select_associated_type(res, segment), None) 331 (self.select_associated_type(res, segment), None)
328 } else if remaining_segments.len() > 1 { 332 } else if remaining_segments.len() > 1 {
329 // FIXME report error (ambiguous associated type) 333 // FIXME report error (ambiguous associated type)
330 (TyKind::Unknown.intern(&Interner), None) 334 (TyKind::Error.intern(&Interner), None)
331 } else { 335 } else {
332 (ty, res) 336 (ty, res)
333 } 337 }
@@ -371,21 +375,24 @@ impl<'a> TyLoweringContext<'a> {
371 } 375 }
372 None => { 376 None => {
373 // FIXME: report error (associated type not found) 377 // FIXME: report error (associated type not found)
374 TyKind::Unknown.intern(&Interner) 378 TyKind::Error.intern(&Interner)
375 } 379 }
376 } 380 }
377 } else if remaining_segments.len() > 1 { 381 } else if remaining_segments.len() > 1 {
378 // FIXME report error (ambiguous associated type) 382 // FIXME report error (ambiguous associated type)
379 TyKind::Unknown.intern(&Interner) 383 TyKind::Error.intern(&Interner)
380 } else { 384 } else {
381 let dyn_ty = DynTy { 385 let dyn_ty = DynTy {
382 bounds: Binders::new( 386 bounds: crate::make_only_type_binders(
383 1, 387 1,
384 QuantifiedWhereClauses::from_iter( 388 QuantifiedWhereClauses::from_iter(
385 &Interner, 389 &Interner,
386 Some(Binders::wrap_empty(WhereClause::Implemented(trait_ref))), 390 Some(crate::wrap_empty_binders(WhereClause::Implemented(
391 trait_ref,
392 ))),
387 ), 393 ),
388 ), 394 ),
395 lifetime: static_lifetime(),
389 }; 396 };
390 TyKind::Dyn(dyn_ty).intern(&Interner) 397 TyKind::Dyn(dyn_ty).intern(&Interner)
391 }; 398 };
@@ -410,26 +417,18 @@ impl<'a> TyLoweringContext<'a> {
410 TypeNs::SelfType(impl_id) => { 417 TypeNs::SelfType(impl_id) => {
411 let generics = generics(self.db.upcast(), impl_id.into()); 418 let generics = generics(self.db.upcast(), impl_id.into());
412 let substs = match self.type_param_mode { 419 let substs = match self.type_param_mode {
413 TypeParamLoweringMode::Placeholder => { 420 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
414 Substitution::type_params_for_generics(self.db, &generics) 421 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
415 }
416 TypeParamLoweringMode::Variable => {
417 Substitution::bound_vars(&generics, self.in_binders)
418 }
419 }; 422 };
420 self.db.impl_self_ty(impl_id).subst(&substs) 423 self.db.impl_self_ty(impl_id).substitute(&Interner, &substs)
421 } 424 }
422 TypeNs::AdtSelfType(adt) => { 425 TypeNs::AdtSelfType(adt) => {
423 let generics = generics(self.db.upcast(), adt.into()); 426 let generics = generics(self.db.upcast(), adt.into());
424 let substs = match self.type_param_mode { 427 let substs = match self.type_param_mode {
425 TypeParamLoweringMode::Placeholder => { 428 TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
426 Substitution::type_params_for_generics(self.db, &generics) 429 TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
427 }
428 TypeParamLoweringMode::Variable => {
429 Substitution::bound_vars(&generics, self.in_binders)
430 }
431 }; 430 };
432 self.db.ty(adt.into()).subst(&substs) 431 self.db.ty(adt.into()).substitute(&Interner, &substs)
433 } 432 }
434 433
435 TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args), 434 TypeNs::AdtId(it) => self.lower_path_inner(resolved_segment, it.into(), infer_args),
@@ -440,7 +439,7 @@ impl<'a> TyLoweringContext<'a> {
440 self.lower_path_inner(resolved_segment, it.into(), infer_args) 439 self.lower_path_inner(resolved_segment, it.into(), infer_args)
441 } 440 }
442 // FIXME: report error 441 // FIXME: report error
443 TypeNs::EnumVariantId(_) => return (TyKind::Unknown.intern(&Interner), None), 442 TypeNs::EnumVariantId(_) => return (TyKind::Error.intern(&Interner), None),
444 }; 443 };
445 self.lower_ty_relative_path(ty, Some(resolution), remaining_segments) 444 self.lower_ty_relative_path(ty, Some(resolution), remaining_segments)
446 } 445 }
@@ -454,7 +453,7 @@ impl<'a> TyLoweringContext<'a> {
454 let (resolution, remaining_index) = 453 let (resolution, remaining_index) =
455 match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) { 454 match self.resolver.resolve_path_in_type_ns(self.db.upcast(), path.mod_path()) {
456 Some(it) => it, 455 Some(it) => it,
457 None => return (TyKind::Unknown.intern(&Interner), None), 456 None => return (TyKind::Error.intern(&Interner), None),
458 }; 457 };
459 let (resolved_segment, remaining_segments) = match remaining_index { 458 let (resolved_segment, remaining_segments) = match remaining_index {
460 None => ( 459 None => (
@@ -477,19 +476,20 @@ impl<'a> TyLoweringContext<'a> {
477 TypeParamLoweringMode::Placeholder => { 476 TypeParamLoweringMode::Placeholder => {
478 // if we're lowering to placeholders, we have to put 477 // if we're lowering to placeholders, we have to put
479 // them in now 478 // them in now
480 let s = Substitution::type_params( 479 let generics = generics(
481 self.db, 480 self.db.upcast(),
482 self.resolver.generic_def().expect( 481 self.resolver.generic_def().expect(
483 "there should be generics if there's a generic param", 482 "there should be generics if there's a generic param",
484 ), 483 ),
485 ); 484 );
486 t.substitution.clone().subst_bound_vars(&s) 485 let s = generics.type_params_subst(self.db);
486 s.apply(t.substitution.clone(), &Interner)
487 } 487 }
488 TypeParamLoweringMode::Variable => t.substitution.clone(), 488 TypeParamLoweringMode::Variable => t.substitution.clone(),
489 }; 489 };
490 // We need to shift in the bound vars, since 490 // We need to shift in the bound vars, since
491 // associated_type_shorthand_candidates does not do that 491 // associated_type_shorthand_candidates does not do that
492 let substs = substs.shift_bound_vars(self.in_binders); 492 let substs = substs.shifted_in_from(&Interner, self.in_binders);
493 // FIXME handle type parameters on the segment 493 // FIXME handle type parameters on the segment
494 return Some( 494 return Some(
495 TyKind::Alias(AliasTy::Projection(ProjectionTy { 495 TyKind::Alias(AliasTy::Projection(ProjectionTy {
@@ -504,9 +504,9 @@ impl<'a> TyLoweringContext<'a> {
504 }, 504 },
505 ); 505 );
506 506
507 ty.unwrap_or(TyKind::Unknown.intern(&Interner)) 507 ty.unwrap_or(TyKind::Error.intern(&Interner))
508 } else { 508 } else {
509 TyKind::Unknown.intern(&Interner) 509 TyKind::Error.intern(&Interner)
510 } 510 }
511 } 511 }
512 512
@@ -522,7 +522,7 @@ impl<'a> TyLoweringContext<'a> {
522 TyDefId::TypeAliasId(it) => Some(it.into()), 522 TyDefId::TypeAliasId(it) => Some(it.into()),
523 }; 523 };
524 let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None); 524 let substs = self.substs_from_path_segment(segment, generic_def, infer_args, None);
525 self.db.ty(typeable).subst(&substs) 525 self.db.ty(typeable).substitute(&Interner, &substs)
526 } 526 }
527 527
528 /// Collect generic arguments from a path into a `Substs`. See also 528 /// Collect generic arguments from a path into a `Substs`. See also
@@ -575,13 +575,13 @@ impl<'a> TyLoweringContext<'a> {
575 def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split()); 575 def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
576 let total_len = parent_params + self_params + type_params + impl_trait_params; 576 let total_len = parent_params + self_params + type_params + impl_trait_params;
577 577
578 substs.extend(iter::repeat(TyKind::Unknown.intern(&Interner)).take(parent_params)); 578 substs.extend(iter::repeat(TyKind::Error.intern(&Interner)).take(parent_params));
579 579
580 let fill_self_params = || { 580 let fill_self_params = || {
581 substs.extend( 581 substs.extend(
582 explicit_self_ty 582 explicit_self_ty
583 .into_iter() 583 .into_iter()
584 .chain(iter::repeat(TyKind::Unknown.intern(&Interner))) 584 .chain(iter::repeat(TyKind::Error.intern(&Interner)))
585 .take(self_params), 585 .take(self_params),
586 ) 586 )
587 }; 587 };
@@ -625,8 +625,8 @@ impl<'a> TyLoweringContext<'a> {
625 625
626 for default_ty in defaults.iter().skip(substs.len()) { 626 for default_ty in defaults.iter().skip(substs.len()) {
627 // each default can depend on the previous parameters 627 // each default can depend on the previous parameters
628 let substs_so_far = Substitution(substs.clone().into()); 628 let substs_so_far = Substitution::from_iter(&Interner, substs.clone());
629 substs.push(default_ty.clone().subst(&substs_so_far)); 629 substs.push(default_ty.clone().substitute(&Interner, &substs_so_far));
630 } 630 }
631 } 631 }
632 } 632 }
@@ -634,11 +634,11 @@ impl<'a> TyLoweringContext<'a> {
634 // add placeholders for args that were not provided 634 // add placeholders for args that were not provided
635 // FIXME: emit diagnostics in contexts where this is not allowed 635 // FIXME: emit diagnostics in contexts where this is not allowed
636 for _ in substs.len()..total_len { 636 for _ in substs.len()..total_len {
637 substs.push(TyKind::Unknown.intern(&Interner)); 637 substs.push(TyKind::Error.intern(&Interner));
638 } 638 }
639 assert_eq!(substs.len(), total_len); 639 assert_eq!(substs.len(), total_len);
640 640
641 Substitution(substs.into()) 641 Substitution::from_iter(&Interner, substs)
642 } 642 }
643 643
644 fn lower_trait_ref_from_path( 644 fn lower_trait_ref_from_path(
@@ -667,14 +667,10 @@ impl<'a> TyLoweringContext<'a> {
667 667
668 fn lower_trait_ref( 668 fn lower_trait_ref(
669 &self, 669 &self,
670 type_ref: &TypeRef, 670 trait_ref: &HirTraitRef,
671 explicit_self_ty: Option<Ty>, 671 explicit_self_ty: Option<Ty>,
672 ) -> Option<TraitRef> { 672 ) -> Option<TraitRef> {
673 let path = match type_ref { 673 self.lower_trait_ref_from_path(&trait_ref.path, explicit_self_ty)
674 TypeRef::Path(path) => path,
675 _ => return None,
676 };
677 self.lower_trait_ref_from_path(path, explicit_self_ty)
678 } 674 }
679 675
680 fn trait_ref_substs_from_path( 676 fn trait_ref_substs_from_path(
@@ -730,7 +726,7 @@ impl<'a> TyLoweringContext<'a> {
730 let trait_ref = match bound { 726 let trait_ref = match bound {
731 TypeBound::Path(path) => { 727 TypeBound::Path(path) => {
732 bindings = self.lower_trait_ref_from_path(path, Some(self_ty)); 728 bindings = self.lower_trait_ref_from_path(path, Some(self_ty));
733 bindings.clone().map(WhereClause::Implemented).map(|b| Binders::wrap_empty(b)) 729 bindings.clone().map(WhereClause::Implemented).map(|b| crate::wrap_empty_binders(b))
734 } 730 }
735 TypeBound::Lifetime(_) => None, 731 TypeBound::Lifetime(_) => None,
736 TypeBound::Error => None, 732 TypeBound::Error => None,
@@ -777,7 +773,7 @@ impl<'a> TyLoweringContext<'a> {
777 let ty = self.lower_ty(type_ref); 773 let ty = self.lower_ty(type_ref);
778 let alias_eq = 774 let alias_eq =
779 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty }; 775 AliasEq { alias: AliasTy::Projection(projection_ty.clone()), ty };
780 preds.push(Binders::wrap_empty(WhereClause::AliasEq(alias_eq))); 776 preds.push(crate::wrap_empty_binders(WhereClause::AliasEq(alias_eq)));
781 } 777 }
782 for bound in &binding.bounds { 778 for bound in &binding.bounds {
783 preds.extend(self.lower_type_bound( 779 preds.extend(self.lower_type_bound(
@@ -797,7 +793,7 @@ impl<'a> TyLoweringContext<'a> {
797 let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| { 793 let predicates = self.with_shifted_in(DebruijnIndex::ONE, |ctx| {
798 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect() 794 bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)).collect()
799 }); 795 });
800 ReturnTypeImplTrait { bounds: Binders::new(1, predicates) } 796 ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
801 } 797 }
802} 798}
803 799
@@ -825,58 +821,57 @@ pub fn associated_type_shorthand_candidates<R>(
825 res: TypeNs, 821 res: TypeNs,
826 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>, 822 mut cb: impl FnMut(&Name, &TraitRef, TypeAliasId) -> Option<R>,
827) -> Option<R> { 823) -> Option<R> {
828 let traits_from_env: Vec<_> = match res { 824 let mut search = |t| {
829 TypeNs::SelfType(impl_id) => match db.impl_trait(impl_id) { 825 for t in all_super_trait_refs(db, t) {
830 None => vec![], 826 let data = db.trait_data(t.hir_trait_id());
831 // FIXME: how to correctly handle higher-ranked bounds here? 827
832 Some(trait_ref) => vec![trait_ref.value.shift_bound_vars_out(DebruijnIndex::ONE)], 828 for (name, assoc_id) in &data.items {
833 }, 829 if let AssocItemId::TypeAliasId(alias) = assoc_id {
830 if let Some(result) = cb(name, &t, *alias) {
831 return Some(result);
832 }
833 }
834 }
835 }
836 None
837 };
838
839 match res {
840 TypeNs::SelfType(impl_id) => search(
841 // we're _in_ the impl -- the binders get added back later. Correct,
842 // but it would be nice to make this more explicit
843 db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
844 ),
834 TypeNs::GenericParam(param_id) => { 845 TypeNs::GenericParam(param_id) => {
835 let predicates = db.generic_predicates_for_param(param_id); 846 let predicates = db.generic_predicates_for_param(param_id);
836 let mut traits_: Vec<_> = predicates 847 let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
837 .iter() 848 // FIXME: how to correctly handle higher-ranked bounds here?
838 .filter_map(|pred| match &pred.value.value { 849 WhereClause::Implemented(tr) => search(
839 // FIXME: how to correctly handle higher-ranked bounds here? 850 tr.clone()
840 WhereClause::Implemented(tr) => { 851 .shifted_out_to(&Interner, DebruijnIndex::ONE)
841 Some(tr.clone().shift_bound_vars_out(DebruijnIndex::ONE)) 852 .expect("FIXME unexpected higher-ranked trait bound"),
842 } 853 ),
843 _ => None, 854 _ => None,
844 }) 855 });
845 .collect(); 856 if let res @ Some(_) = res {
857 return res;
858 }
846 // Handle `Self::Type` referring to own associated type in trait definitions 859 // Handle `Self::Type` referring to own associated type in trait definitions
847 if let GenericDefId::TraitId(trait_id) = param_id.parent { 860 if let GenericDefId::TraitId(trait_id) = param_id.parent {
848 let generics = generics(db.upcast(), trait_id.into()); 861 let generics = generics(db.upcast(), trait_id.into());
849 if generics.params.types[param_id.local_id].provenance 862 if generics.params.types[param_id.local_id].provenance
850 == TypeParamProvenance::TraitSelf 863 == TypeParamProvenance::TraitSelf
851 { 864 {
852 let trait_ref = TraitRef { 865 let trait_ref = TyBuilder::trait_ref(db, trait_id)
853 trait_id: to_chalk_trait_id(trait_id), 866 .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
854 substitution: Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST), 867 .build();
855 }; 868 return search(trait_ref);
856 traits_.push(trait_ref);
857 } 869 }
858 } 870 }
859 traits_ 871 None
860 }
861 _ => vec![],
862 };
863
864 for t in traits_from_env.into_iter().flat_map(move |t| all_super_trait_refs(db, t)) {
865 let data = db.trait_data(t.hir_trait_id());
866
867 for (name, assoc_id) in &data.items {
868 match assoc_id {
869 AssocItemId::TypeAliasId(alias) => {
870 if let Some(result) = cb(name, &t, *alias) {
871 return Some(result);
872 }
873 }
874 AssocItemId::FunctionId(_) | AssocItemId::ConstId(_) => {}
875 }
876 } 872 }
873 _ => None,
877 } 874 }
878
879 None
880} 875}
881 876
882/// Build the type of all specific fields of a struct or enum variant. 877/// Build the type of all specific fields of a struct or enum variant.
@@ -884,7 +879,7 @@ pub(crate) fn field_types_query(
884 db: &dyn HirDatabase, 879 db: &dyn HirDatabase,
885 variant_id: VariantId, 880 variant_id: VariantId,
886) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> { 881) -> Arc<ArenaMap<LocalFieldId, Binders<Ty>>> {
887 let var_data = variant_data(db.upcast(), variant_id); 882 let var_data = variant_id.variant_data(db.upcast());
888 let (resolver, def): (_, GenericDefId) = match variant_id { 883 let (resolver, def): (_, GenericDefId) = match variant_id {
889 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()), 884 VariantId::StructId(it) => (it.resolver(db.upcast()), it.into()),
890 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()), 885 VariantId::UnionId(it) => (it.resolver(db.upcast()), it.into()),
@@ -895,7 +890,7 @@ pub(crate) fn field_types_query(
895 let ctx = 890 let ctx =
896 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 891 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
897 for (field_id, field_data) in var_data.fields().iter() { 892 for (field_id, field_data) in var_data.fields().iter() {
898 res.insert(field_id, Binders::new(generics.len(), ctx.lower_ty(&field_data.type_ref))) 893 res.insert(field_id, make_binders(&generics, ctx.lower_ty(&field_data.type_ref)))
899 } 894 }
900 Arc::new(res) 895 Arc::new(res)
901} 896}
@@ -929,9 +924,7 @@ pub(crate) fn generic_predicates_for_param_query(
929 }, 924 },
930 WherePredicate::Lifetime { .. } => false, 925 WherePredicate::Lifetime { .. } => false,
931 }) 926 })
932 .flat_map(|pred| { 927 .flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
933 ctx.lower_where_predicate(pred, true).map(|p| Binders::new(generics.len(), p))
934 })
935 .collect() 928 .collect()
936} 929}
937 930
@@ -955,10 +948,10 @@ pub(crate) fn trait_environment_query(
955 for pred in resolver.where_predicates_in_scope() { 948 for pred in resolver.where_predicates_in_scope() {
956 for pred in ctx.lower_where_predicate(pred, false) { 949 for pred in ctx.lower_where_predicate(pred, false) {
957 if let WhereClause::Implemented(tr) = &pred.skip_binders() { 950 if let WhereClause::Implemented(tr) = &pred.skip_binders() {
958 traits_in_scope.push((tr.self_type_parameter().clone(), tr.hir_trait_id())); 951 traits_in_scope
952 .push((tr.self_type_parameter(&Interner).clone(), tr.hir_trait_id()));
959 } 953 }
960 let program_clause: chalk_ir::ProgramClause<Interner> = 954 let program_clause: chalk_ir::ProgramClause<Interner> = pred.clone().cast(&Interner);
961 pred.clone().to_chalk(db).cast(&Interner);
962 clauses.push(program_clause.into_from_env_clause(&Interner)); 955 clauses.push(program_clause.into_from_env_clause(&Interner));
963 } 956 }
964 } 957 }
@@ -978,10 +971,10 @@ pub(crate) fn trait_environment_query(
978 // function default implementations (and hypothetical code 971 // function default implementations (and hypothetical code
979 // inside consts or type aliases) 972 // inside consts or type aliases)
980 cov_mark::hit!(trait_self_implements_self); 973 cov_mark::hit!(trait_self_implements_self);
981 let substs = Substitution::type_params(db, trait_id); 974 let substs = TyBuilder::type_params_subst(db, trait_id);
982 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs }; 975 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
983 let pred = WhereClause::Implemented(trait_ref); 976 let pred = WhereClause::Implemented(trait_ref);
984 let program_clause: chalk_ir::ProgramClause<Interner> = pred.to_chalk(db).cast(&Interner); 977 let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(&Interner);
985 clauses.push(program_clause.into_from_env_clause(&Interner)); 978 clauses.push(program_clause.into_from_env_clause(&Interner));
986 } 979 }
987 980
@@ -1001,9 +994,7 @@ pub(crate) fn generic_predicates_query(
1001 let generics = generics(db.upcast(), def); 994 let generics = generics(db.upcast(), def);
1002 resolver 995 resolver
1003 .where_predicates_in_scope() 996 .where_predicates_in_scope()
1004 .flat_map(|pred| { 997 .flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
1005 ctx.lower_where_predicate(pred, false).map(|p| Binders::new(generics.len(), p))
1006 })
1007 .collect() 998 .collect()
1008} 999}
1009 1000
@@ -1022,25 +1013,21 @@ pub(crate) fn generic_defaults_query(
1022 .enumerate() 1013 .enumerate()
1023 .map(|(idx, (_, p))| { 1014 .map(|(idx, (_, p))| {
1024 let mut ty = 1015 let mut ty =
1025 p.default.as_ref().map_or(TyKind::Unknown.intern(&Interner), |t| ctx.lower_ty(t)); 1016 p.default.as_ref().map_or(TyKind::Error.intern(&Interner), |t| ctx.lower_ty(t));
1026 1017
1027 // Each default can only refer to previous parameters. 1018 // Each default can only refer to previous parameters.
1028 ty.walk_mut_binders( 1019 ty = crate::fold_free_vars(ty, |bound, binders| {
1029 &mut |ty, binders| match ty.interned_mut() { 1020 if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
1030 TyKind::BoundVar(BoundVar { debruijn, index }) if *debruijn == binders => { 1021 // type variable default referring to parameter coming
1031 if *index >= idx { 1022 // after it. This is forbidden (FIXME: report
1032 // type variable default referring to parameter coming 1023 // diagnostic)
1033 // after it. This is forbidden (FIXME: report 1024 TyKind::Error.intern(&Interner)
1034 // diagnostic) 1025 } else {
1035 *ty = TyKind::Unknown.intern(&Interner); 1026 bound.shifted_in_from(binders).to_ty(&Interner)
1036 } 1027 }
1037 } 1028 });
1038 _ => {}
1039 },
1040 DebruijnIndex::INNERMOST,
1041 );
1042 1029
1043 Binders::new(idx, ty) 1030 crate::make_only_type_binders(idx, ty)
1044 }) 1031 })
1045 .collect(); 1032 .collect();
1046 1033
@@ -1053,23 +1040,22 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
1053 let ctx_params = TyLoweringContext::new(db, &resolver) 1040 let ctx_params = TyLoweringContext::new(db, &resolver)
1054 .with_impl_trait_mode(ImplTraitLoweringMode::Variable) 1041 .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
1055 .with_type_param_mode(TypeParamLoweringMode::Variable); 1042 .with_type_param_mode(TypeParamLoweringMode::Variable);
1056 let params = data.params.iter().map(|tr| (&ctx_params).lower_ty(tr)).collect::<Vec<_>>(); 1043 let params = data.params.iter().map(|tr| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
1057 let ctx_ret = TyLoweringContext::new(db, &resolver) 1044 let ctx_ret = TyLoweringContext::new(db, &resolver)
1058 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque) 1045 .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
1059 .with_type_param_mode(TypeParamLoweringMode::Variable); 1046 .with_type_param_mode(TypeParamLoweringMode::Variable);
1060 let ret = (&ctx_ret).lower_ty(&data.ret_type); 1047 let ret = ctx_ret.lower_ty(&data.ret_type);
1061 let generics = generics(db.upcast(), def.into()); 1048 let generics = generics(db.upcast(), def.into());
1062 let num_binders = generics.len(); 1049 make_binders(&generics, CallableSig::from_params_and_return(params, ret, data.is_varargs()))
1063 Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs))
1064} 1050}
1065 1051
1066/// Build the declared type of a function. This should not need to look at the 1052/// Build the declared type of a function. This should not need to look at the
1067/// function body. 1053/// function body.
1068fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> { 1054fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
1069 let generics = generics(db.upcast(), def.into()); 1055 let generics = generics(db.upcast(), def.into());
1070 let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); 1056 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1071 Binders::new( 1057 make_binders(
1072 substs.len(), 1058 &generics,
1073 TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner), 1059 TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(&Interner),
1074 ) 1060 )
1075} 1061}
@@ -1082,7 +1068,7 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
1082 let ctx = 1068 let ctx =
1083 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1069 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1084 1070
1085 Binders::new(generics.len(), ctx.lower_ty(&data.type_ref)) 1071 make_binders(&generics, ctx.lower_ty(&data.type_ref))
1086} 1072}
1087 1073
1088/// Build the declared type of a static. 1074/// Build the declared type of a static.
@@ -1091,7 +1077,7 @@ fn type_for_static(db: &dyn HirDatabase, def: StaticId) -> Binders<Ty> {
1091 let resolver = def.resolver(db.upcast()); 1077 let resolver = def.resolver(db.upcast());
1092 let ctx = TyLoweringContext::new(db, &resolver); 1078 let ctx = TyLoweringContext::new(db, &resolver);
1093 1079
1094 Binders::new(0, ctx.lower_ty(&data.type_ref)) 1080 Binders::empty(&Interner, ctx.lower_ty(&data.type_ref))
1095} 1081}
1096 1082
1097fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig { 1083fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnSig {
@@ -1101,8 +1087,8 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
1101 let ctx = 1087 let ctx =
1102 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1088 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1103 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); 1089 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
1104 let ret = type_for_adt(db, def.into()); 1090 let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
1105 Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false)) 1091 Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
1106} 1092}
1107 1093
1108/// Build the type of a tuple struct constructor. 1094/// Build the type of a tuple struct constructor.
@@ -1112,9 +1098,9 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
1112 return type_for_adt(db, def.into()); 1098 return type_for_adt(db, def.into());
1113 } 1099 }
1114 let generics = generics(db.upcast(), def.into()); 1100 let generics = generics(db.upcast(), def.into());
1115 let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); 1101 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1116 Binders::new( 1102 make_binders(
1117 substs.len(), 1103 &generics,
1118 TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner), 1104 TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(&Interner),
1119 ) 1105 )
1120} 1106}
@@ -1127,8 +1113,8 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
1127 let ctx = 1113 let ctx =
1128 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1114 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1129 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>(); 1115 let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
1130 let ret = type_for_adt(db, def.parent.into()); 1116 let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
1131 Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false)) 1117 Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
1132} 1118}
1133 1119
1134/// Build the type of a tuple enum variant constructor. 1120/// Build the type of a tuple enum variant constructor.
@@ -1139,17 +1125,18 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
1139 return type_for_adt(db, def.parent.into()); 1125 return type_for_adt(db, def.parent.into());
1140 } 1126 }
1141 let generics = generics(db.upcast(), def.parent.into()); 1127 let generics = generics(db.upcast(), def.parent.into());
1142 let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); 1128 let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
1143 Binders::new( 1129 make_binders(
1144 substs.len(), 1130 &generics,
1145 TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner), 1131 TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(&Interner),
1146 ) 1132 )
1147} 1133}
1148 1134
1149fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> { 1135fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
1150 let generics = generics(db.upcast(), adt.into()); 1136 let generics = generics(db.upcast(), adt.into());
1151 let substs = Substitution::bound_vars(&generics, DebruijnIndex::INNERMOST); 1137 let b = TyBuilder::adt(db, adt);
1152 Binders::new(substs.len(), Ty::adt_ty(adt, substs)) 1138 let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
1139 make_binders(&generics, ty)
1153} 1140}
1154 1141
1155fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> { 1142fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
@@ -1158,11 +1145,11 @@ fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
1158 let ctx = 1145 let ctx =
1159 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1146 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1160 if db.type_alias_data(t).is_extern { 1147 if db.type_alias_data(t).is_extern {
1161 Binders::new(0, TyKind::ForeignType(crate::to_foreign_def_id(t)).intern(&Interner)) 1148 Binders::empty(&Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(&Interner))
1162 } else { 1149 } else {
1163 let type_ref = &db.type_alias_data(t).type_ref; 1150 let type_ref = &db.type_alias_data(t).type_ref;
1164 let inner = ctx.lower_ty(type_ref.as_ref().unwrap_or(&TypeRef::Error)); 1151 let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
1165 Binders::new(generics.len(), inner) 1152 make_binders(&generics, inner)
1166 } 1153 }
1167} 1154}
1168 1155
@@ -1221,19 +1208,21 @@ impl_from!(FunctionId, StructId, UnionId, EnumVariantId, ConstId, StaticId for V
1221/// namespace. 1208/// namespace.
1222pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> { 1209pub(crate) fn ty_query(db: &dyn HirDatabase, def: TyDefId) -> Binders<Ty> {
1223 match def { 1210 match def {
1224 TyDefId::BuiltinType(it) => Binders::new(0, Ty::builtin(it)), 1211 TyDefId::BuiltinType(it) => Binders::empty(&Interner, TyBuilder::builtin(it)),
1225 TyDefId::AdtId(it) => type_for_adt(db, it), 1212 TyDefId::AdtId(it) => type_for_adt(db, it),
1226 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it), 1213 TyDefId::TypeAliasId(it) => type_for_type_alias(db, it),
1227 } 1214 }
1228} 1215}
1229 1216
1230pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> { 1217pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId) -> Binders<Ty> {
1231 let num_binders = match *def { 1218 let generics = match *def {
1232 TyDefId::BuiltinType(_) => 0, 1219 TyDefId::BuiltinType(_) => {
1233 TyDefId::AdtId(it) => generics(db.upcast(), it.into()).len(), 1220 return Binders::empty(&Interner, TyKind::Error.intern(&Interner))
1234 TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()).len(), 1221 }
1222 TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
1223 TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
1235 }; 1224 };
1236 Binders::new(num_binders, TyKind::Unknown.intern(&Interner)) 1225 make_binders(&generics, TyKind::Error.intern(&Interner))
1237} 1226}
1238 1227
1239pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> { 1228pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
@@ -1253,7 +1242,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
1253 let generics = generics(db.upcast(), impl_id.into()); 1242 let generics = generics(db.upcast(), impl_id.into());
1254 let ctx = 1243 let ctx =
1255 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1244 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1256 Binders::new(generics.len(), ctx.lower_ty(&impl_data.target_type)) 1245 make_binders(&generics, ctx.lower_ty(&impl_data.self_ty))
1257} 1246}
1258 1247
1259pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty { 1248pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
@@ -1271,7 +1260,7 @@ pub(crate) fn impl_self_ty_recover(
1271 impl_id: &ImplId, 1260 impl_id: &ImplId,
1272) -> Binders<Ty> { 1261) -> Binders<Ty> {
1273 let generics = generics(db.upcast(), (*impl_id).into()); 1262 let generics = generics(db.upcast(), (*impl_id).into());
1274 Binders::new(generics.len(), TyKind::Unknown.intern(&Interner)) 1263 make_binders(&generics, TyKind::Error.intern(&Interner))
1275} 1264}
1276 1265
1277pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> { 1266pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
@@ -1279,9 +1268,9 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
1279 let resolver = impl_id.resolver(db.upcast()); 1268 let resolver = impl_id.resolver(db.upcast());
1280 let ctx = 1269 let ctx =
1281 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable); 1270 TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
1282 let self_ty = db.impl_self_ty(impl_id); 1271 let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
1283 let target_trait = impl_data.target_trait.as_ref()?; 1272 let target_trait = impl_data.target_trait.as_ref()?;
1284 Some(Binders::new(self_ty.num_binders, ctx.lower_trait_ref(target_trait, Some(self_ty.value))?)) 1273 Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
1285} 1274}
1286 1275
1287pub(crate) fn return_type_impl_traits( 1276pub(crate) fn return_type_impl_traits(
@@ -1296,13 +1285,12 @@ pub(crate) fn return_type_impl_traits(
1296 .with_type_param_mode(TypeParamLoweringMode::Variable); 1285 .with_type_param_mode(TypeParamLoweringMode::Variable);
1297 let _ret = (&ctx_ret).lower_ty(&data.ret_type); 1286 let _ret = (&ctx_ret).lower_ty(&data.ret_type);
1298 let generics = generics(db.upcast(), def.into()); 1287 let generics = generics(db.upcast(), def.into());
1299 let num_binders = generics.len();
1300 let return_type_impl_traits = 1288 let return_type_impl_traits =
1301 ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() }; 1289 ReturnTypeImplTraits { impl_traits: ctx_ret.opaque_type_data.into_inner() };
1302 if return_type_impl_traits.impl_traits.is_empty() { 1290 if return_type_impl_traits.impl_traits.is_empty() {
1303 None 1291 None
1304 } else { 1292 } else {
1305 Some(Arc::new(Binders::new(num_binders, return_type_impl_traits))) 1293 Some(Arc::new(make_binders(&generics, return_type_impl_traits)))
1306 } 1294 }
1307} 1295}
1308 1296
@@ -1312,3 +1300,7 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
1312 hir_def::type_ref::Mutability::Mut => Mutability::Mut, 1300 hir_def::type_ref::Mutability::Mut => Mutability::Mut,
1313 } 1301 }
1314} 1302}
1303
1304fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
1305 crate::make_only_type_binders(generics.len(), value)
1306}
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 bf7d5eded..3693e3284 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,52 +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 to_chalk_trait_id, 22 static_lifetime,
23 utils::all_super_traits, 23 utils::all_super_traits,
24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, FnPointer, FnSig, ForeignDefId, 24 AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
25 InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRef, Ty, TyKind, 25 Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
26 TypeWalk,
27}; 26};
28 27
29/// This is used as a key for indexing impls. 28/// This is used as a key for indexing impls.
30#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] 29#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
31pub enum TyFingerprint { 30pub enum TyFingerprint {
31 // These are lang item impls:
32 Str, 32 Str,
33 Slice, 33 Slice,
34 Array, 34 Array,
35 Never, 35 Never,
36 RawPtr(Mutability), 36 RawPtr(Mutability),
37 Scalar(Scalar), 37 Scalar(Scalar),
38 // These can have user-defined impls:
38 Adt(hir_def::AdtId), 39 Adt(hir_def::AdtId),
39 Dyn(TraitId), 40 Dyn(TraitId),
40 Tuple(usize),
41 ForeignType(ForeignDefId), 41 ForeignType(ForeignDefId),
42 FnPtr(usize, FnSig), 42 // These only exist for trait impls
43 Unit,
44 Unnameable,
45 Function(u32),
43} 46}
44 47
45impl TyFingerprint { 48impl TyFingerprint {
46 /// Creates a TyFingerprint for looking up an impl. Only certain types can 49 /// Creates a TyFingerprint for looking up an inherent impl. Only certain
47 /// 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
48 /// `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
49 pub fn for_impl(ty: &Ty) -> Option<TyFingerprint> { 52 /// reference types and such.
50 let fp = match *ty.interned(&Interner) { 53 pub fn for_inherent_impl(ty: &Ty) -> Option<TyFingerprint> {
54 let fp = match ty.kind(&Interner) {
51 TyKind::Str => TyFingerprint::Str, 55 TyKind::Str => TyFingerprint::Str,
52 TyKind::Never => TyFingerprint::Never, 56 TyKind::Never => TyFingerprint::Never,
53 TyKind::Slice(..) => TyFingerprint::Slice, 57 TyKind::Slice(..) => TyFingerprint::Slice,
54 TyKind::Array(..) => TyFingerprint::Array, 58 TyKind::Array(..) => TyFingerprint::Array,
55 TyKind::Scalar(scalar) => TyFingerprint::Scalar(scalar), 59 TyKind::Scalar(scalar) => TyFingerprint::Scalar(*scalar),
56 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(adt), 60 TyKind::Adt(AdtId(adt), _) => TyFingerprint::Adt(*adt),
57 TyKind::Tuple(cardinality, _) => TyFingerprint::Tuple(cardinality), 61 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(*mutability),
58 TyKind::Raw(mutability, ..) => TyFingerprint::RawPtr(mutability), 62 TyKind::Foreign(alias_id, ..) => TyFingerprint::ForeignType(*alias_id),
59 TyKind::ForeignType(alias_id, ..) => TyFingerprint::ForeignType(alias_id),
60 TyKind::Function(FnPointer { num_args, sig, .. }) => {
61 TyFingerprint::FnPtr(num_args, sig)
62 }
63 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?, 63 TyKind::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
64 _ => return None, 64 _ => return None,
65 }; 65 };
66 Some(fp) 66 Some(fp)
67 } 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 }
68} 107}
69 108
70pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [ 109pub(crate) const ALL_INT_FPS: [TyFingerprint; 12] = [
@@ -100,25 +139,38 @@ impl TraitImpls {
100 let mut impls = Self { map: FxHashMap::default() }; 139 let mut impls = Self { map: FxHashMap::default() };
101 140
102 let crate_def_map = db.crate_def_map(krate); 141 let crate_def_map = db.crate_def_map(krate);
103 for (_module_id, module_data) in crate_def_map.modules() { 142 collect_def_map(db, &crate_def_map, &mut impls);
104 for impl_id in module_data.scope.impls() { 143
105 let target_trait = match db.impl_trait(impl_id) { 144 return Arc::new(impls);
106 Some(tr) => tr.value.hir_trait_id(), 145
107 None => continue, 146 fn collect_def_map(db: &dyn HirDatabase, def_map: &DefMap, impls: &mut TraitImpls) {
108 }; 147 for (_module_id, module_data) in def_map.modules() {
109 let self_ty = db.impl_self_ty(impl_id); 148 for impl_id in module_data.scope.impls() {
110 let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); 149 let target_trait = match db.impl_trait(impl_id) {
111 impls 150 Some(tr) => tr.skip_binders().hir_trait_id(),
112 .map 151 None => continue,
113 .entry(target_trait) 152 };
114 .or_default() 153 let self_ty = db.impl_self_ty(impl_id);
115 .entry(self_ty_fp) 154 let self_ty_fp = TyFingerprint::for_trait_impl(self_ty.skip_binders());
116 .or_default() 155 impls
117 .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 }
118 } 172 }
119 } 173 }
120
121 Arc::new(impls)
122 } 174 }
123 175
124 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> {
@@ -144,10 +196,13 @@ impl TraitImpls {
144 } 196 }
145 197
146 /// Queries all trait impls for the given type. 198 /// Queries all trait impls for the given type.
147 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> + '_ {
148 self.map 203 self.map
149 .values() 204 .values()
150 .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())
151 .flat_map(|it| it.iter().copied()) 206 .flat_map(|it| it.iter().copied())
152 } 207 }
153 208
@@ -202,17 +257,22 @@ impl InherentImpls {
202 } 257 }
203 258
204 let self_ty = db.impl_self_ty(impl_id); 259 let self_ty = db.impl_self_ty(impl_id);
205 if let Some(fp) = TyFingerprint::for_impl(&self_ty.value) { 260 let fp = TyFingerprint::for_inherent_impl(self_ty.skip_binders());
261 if let Some(fp) = fp {
206 map.entry(fp).or_default().push(impl_id); 262 map.entry(fp).or_default().push(impl_id);
207 } 263 }
264 // `fp` should only be `None` in error cases (either erroneous code or incomplete name resolution)
208 } 265 }
209 } 266 }
210 267
268 // NOTE: We're not collecting inherent impls from unnamed consts here, we intentionally only
269 // support trait impls there.
270
211 Arc::new(Self { map }) 271 Arc::new(Self { map })
212 } 272 }
213 273
214 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] { 274 pub fn for_self_ty(&self, self_ty: &Ty) -> &[ImplId] {
215 match TyFingerprint::for_impl(self_ty) { 275 match TyFingerprint::for_inherent_impl(self_ty) {
216 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]), 276 Some(fp) => self.map.get(&fp).map(|vec| vec.as_ref()).unwrap_or(&[]),
217 None => &[], 277 None => &[],
218 } 278 }
@@ -223,15 +283,14 @@ impl InherentImpls {
223 } 283 }
224} 284}
225 285
226impl Ty { 286pub fn def_crates(
227 pub fn def_crates( 287 db: &dyn HirDatabase,
228 &self, 288 ty: &Ty,
229 db: &dyn HirDatabase, 289 cur_crate: CrateId,
230 cur_crate: CrateId, 290) -> Option<ArrayVec<CrateId, 2>> {
231 ) -> Option<ArrayVec<CrateId, 2>> { 291 // Types like slice can have inherent impls in several crates, (core and alloc).
232 // Types like slice can have inherent impls in several crates, (core and alloc). 292 // The corresponding impls are marked with lang items, so we can use them to find the required crates.
233 // The corresponding impls are marked with lang items, so we can use them to find the required crates. 293 macro_rules! lang_item_crate {
234 macro_rules! lang_item_crate {
235 ($($name:expr),+ $(,)?) => {{ 294 ($($name:expr),+ $(,)?) => {{
236 let mut v = ArrayVec::<LangItemTarget, 2>::new(); 295 let mut v = ArrayVec::<LangItemTarget, 2>::new();
237 $( 296 $(
@@ -241,51 +300,50 @@ impl Ty {
241 }}; 300 }};
242 } 301 }
243 302
244 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect()); 303 let mod_to_crate_ids = |module: ModuleId| Some(std::iter::once(module.krate()).collect());
245 304
246 let lang_item_targets = match self.interned(&Interner) { 305 let lang_item_targets = match ty.kind(&Interner) {
247 TyKind::Adt(AdtId(def_id), _) => { 306 TyKind::Adt(AdtId(def_id), _) => {
248 return mod_to_crate_ids(def_id.module(db.upcast())); 307 return mod_to_crate_ids(def_id.module(db.upcast()));
249 } 308 }
250 TyKind::ForeignType(id) => { 309 TyKind::Foreign(id) => {
251 return mod_to_crate_ids( 310 return mod_to_crate_ids(
252 from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()), 311 from_foreign_def_id(*id).lookup(db.upcast()).module(db.upcast()),
253 ); 312 );
254 } 313 }
255 TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"), 314 TyKind::Scalar(Scalar::Bool) => lang_item_crate!("bool"),
256 TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"), 315 TyKind::Scalar(Scalar::Char) => lang_item_crate!("char"),
257 TyKind::Scalar(Scalar::Float(f)) => match f { 316 TyKind::Scalar(Scalar::Float(f)) => match f {
258 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime) 317 // There are two lang items: one in libcore (fXX) and one in libstd (fXX_runtime)
259 FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"), 318 FloatTy::F32 => lang_item_crate!("f32", "f32_runtime"),
260 FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"), 319 FloatTy::F64 => lang_item_crate!("f64", "f64_runtime"),
261 }, 320 },
262 &TyKind::Scalar(Scalar::Int(t)) => { 321 &TyKind::Scalar(Scalar::Int(t)) => {
263 lang_item_crate!(primitive::int_ty_to_string(t)) 322 lang_item_crate!(primitive::int_ty_to_string(t))
264 } 323 }
265 &TyKind::Scalar(Scalar::Uint(t)) => { 324 &TyKind::Scalar(Scalar::Uint(t)) => {
266 lang_item_crate!(primitive::uint_ty_to_string(t)) 325 lang_item_crate!(primitive::uint_ty_to_string(t))
267 } 326 }
268 TyKind::Str => lang_item_crate!("str_alloc", "str"), 327 TyKind::Str => lang_item_crate!("str_alloc", "str"),
269 TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"), 328 TyKind::Slice(_) => lang_item_crate!("slice_alloc", "slice"),
270 TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"), 329 TyKind::Raw(Mutability::Not, _) => lang_item_crate!("const_ptr"),
271 TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"), 330 TyKind::Raw(Mutability::Mut, _) => lang_item_crate!("mut_ptr"),
272 TyKind::Dyn(_) => { 331 TyKind::Dyn(_) => {
273 return self.dyn_trait().and_then(|trait_| { 332 return ty.dyn_trait().and_then(|trait_| {
274 mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast())) 333 mod_to_crate_ids(GenericDefId::TraitId(trait_).module(db.upcast()))
275 }); 334 });
276 } 335 }
277 _ => return None, 336 _ => return None,
278 }; 337 };
279 let res = lang_item_targets 338 let res = lang_item_targets
280 .into_iter() 339 .into_iter()
281 .filter_map(|it| match it { 340 .filter_map(|it| match it {
282 LangItemTarget::ImplDefId(it) => Some(it), 341 LangItemTarget::ImplDefId(it) => Some(it),
283 _ => None, 342 _ => None,
284 }) 343 })
285 .map(|it| it.lookup(db.upcast()).container.krate()) 344 .map(|it| it.lookup(db.upcast()).container.krate())
286 .collect(); 345 .collect();
287 Some(res) 346 Some(res)
288 }
289} 347}
290 348
291/// Look up the method with the given name, returning the actual autoderefed 349/// Look up the method with the given name, returning the actual autoderefed
@@ -454,7 +512,8 @@ fn iterate_method_candidates_with_autoref(
454 } 512 }
455 let refed = Canonical { 513 let refed = Canonical {
456 binders: deref_chain[0].binders.clone(), 514 binders: deref_chain[0].binders.clone(),
457 value: TyKind::Ref(Mutability::Not, deref_chain[0].value.clone()).intern(&Interner), 515 value: TyKind::Ref(Mutability::Not, static_lifetime(), deref_chain[0].value.clone())
516 .intern(&Interner),
458 }; 517 };
459 if iterate_method_candidates_by_receiver( 518 if iterate_method_candidates_by_receiver(
460 &refed, 519 &refed,
@@ -471,7 +530,8 @@ fn iterate_method_candidates_with_autoref(
471 } 530 }
472 let ref_muted = Canonical { 531 let ref_muted = Canonical {
473 binders: deref_chain[0].binders.clone(), 532 binders: deref_chain[0].binders.clone(),
474 value: TyKind::Ref(Mutability::Mut, deref_chain[0].value.clone()).intern(&Interner), 533 value: TyKind::Ref(Mutability::Mut, static_lifetime(), deref_chain[0].value.clone())
534 .intern(&Interner),
475 }; 535 };
476 if iterate_method_candidates_by_receiver( 536 if iterate_method_candidates_by_receiver(
477 &ref_muted, 537 &ref_muted,
@@ -563,7 +623,7 @@ fn iterate_trait_method_candidates(
563 // if ty is `dyn Trait`, the trait doesn't need to be in scope 623 // if ty is `dyn Trait`, the trait doesn't need to be in scope
564 let inherent_trait = 624 let inherent_trait =
565 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t)); 625 self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
566 let env_traits = if let TyKind::Placeholder(_) = self_ty.value.interned(&Interner) { 626 let env_traits = if let TyKind::Placeholder(_) = self_ty.value.kind(&Interner) {
567 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope 627 // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
568 env.traits_in_scope_from_clauses(&self_ty.value) 628 env.traits_in_scope_from_clauses(&self_ty.value)
569 .flat_map(|t| all_super_traits(db.upcast(), t)) 629 .flat_map(|t| all_super_traits(db.upcast(), t))
@@ -593,6 +653,7 @@ fn iterate_trait_method_candidates(
593 } 653 }
594 } 654 }
595 known_implemented = true; 655 known_implemented = true;
656 // FIXME: we shouldn't be ignoring the binders here
596 if callback(&self_ty.value, *item) { 657 if callback(&self_ty.value, *item) {
597 return true; 658 return true;
598 } 659 }
@@ -610,7 +671,7 @@ fn iterate_inherent_methods(
610 visible_from_module: Option<ModuleId>, 671 visible_from_module: Option<ModuleId>,
611 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool, 672 callback: &mut dyn FnMut(&Ty, AssocItemId) -> bool,
612) -> bool { 673) -> bool {
613 let def_crates = match self_ty.value.def_crates(db, krate) { 674 let def_crates = match def_crates(db, &self_ty.value, krate) {
614 Some(k) => k, 675 Some(k) => k,
615 None => return false, 676 None => return false,
616 }; 677 };
@@ -675,7 +736,7 @@ fn is_valid_candidate(
675 } 736 }
676 } 737 }
677 if let Some(receiver_ty) = receiver_ty { 738 if let Some(receiver_ty) = receiver_ty {
678 if !data.has_self_param { 739 if !data.has_self_param() {
679 return false; 740 return false;
680 } 741 }
681 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) { 742 let transformed_receiver_ty = match transform_receiver_ty(db, m, self_ty) {
@@ -710,48 +771,44 @@ pub(crate) fn inherent_impl_substs(
710) -> Option<Substitution> { 771) -> Option<Substitution> {
711 // we create a var for each type parameter of the impl; we need to keep in 772 // we create a var for each type parameter of the impl; we need to keep in
712 // mind here that `self_ty` might have vars of its own 773 // mind here that `self_ty` might have vars of its own
713 let vars = Substitution::build_for_def(db, impl_id) 774 let self_ty_vars = self_ty.binders.len(&Interner);
714 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty.binders.len(&Interner)) 775 let vars = TyBuilder::subst_for_def(db, impl_id)
776 .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty_vars)
715 .build(); 777 .build();
716 let self_ty_with_vars = db.impl_self_ty(impl_id).subst(&vars); 778 let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(&Interner, &vars);
717 let mut kinds = self_ty.binders.interned().to_vec(); 779 let mut kinds = self_ty.binders.interned().to_vec();
718 kinds.extend( 780 kinds.extend(
719 iter::repeat(chalk_ir::WithKind::new( 781 iter::repeat(chalk_ir::WithKind::new(
720 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 782 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
721 UniverseIndex::ROOT, 783 UniverseIndex::ROOT,
722 )) 784 ))
723 .take(vars.len()), 785 .take(vars.len(&Interner)),
724 ); 786 );
725 let tys = Canonical { 787 let tys = Canonical {
726 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 788 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
727 value: (self_ty_with_vars, self_ty.value.clone()), 789 value: (self_ty_with_vars, self_ty.value.clone()),
728 }; 790 };
729 let substs = super::infer::unify(&tys); 791 let substs = super::infer::unify(&tys)?;
730 // We only want the substs for the vars we added, not the ones from self_ty. 792 // We only want the substs for the vars we added, not the ones from self_ty.
731 // Also, if any of the vars we added are still in there, we replace them by 793 // Also, if any of the vars we added are still in there, we replace them by
732 // Unknown. I think this can only really happen if self_ty contained 794 // Unknown. I think this can only really happen if self_ty contained
733 // Unknown, and in that case we want the result to contain Unknown in those 795 // Unknown, and in that case we want the result to contain Unknown in those
734 // places again. 796 // places again.
735 substs.map(|s| fallback_bound_vars(s.suffix(vars.len()), self_ty.binders.len(&Interner))) 797 let suffix =
798 Substitution::from_iter(&Interner, substs.iter(&Interner).cloned().skip(self_ty_vars));
799 Some(fallback_bound_vars(suffix, self_ty_vars))
736} 800}
737 801
738/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past 802/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
739/// num_vars_to_keep) by `TyKind::Unknown`. 803/// num_vars_to_keep) by `TyKind::Unknown`.
740fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution { 804fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
741 s.fold_binders( 805 crate::fold_free_vars(s, |bound, binders| {
742 &mut |ty, binders| { 806 if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
743 if let TyKind::BoundVar(bound) = ty.interned(&Interner) { 807 TyKind::Error.intern(&Interner)
744 if bound.index >= num_vars_to_keep && bound.debruijn >= binders { 808 } else {
745 TyKind::Unknown.intern(&Interner) 809 bound.shifted_in_from(binders).to_ty(&Interner)
746 } else { 810 }
747 ty 811 })
748 }
749 } else {
750 ty
751 }
752 },
753 DebruijnIndex::INNERMOST,
754 )
755} 812}
756 813
757fn transform_receiver_ty( 814fn transform_receiver_ty(
@@ -760,13 +817,13 @@ fn transform_receiver_ty(
760 self_ty: &Canonical<Ty>, 817 self_ty: &Canonical<Ty>,
761) -> Option<Ty> { 818) -> Option<Ty> {
762 let substs = match function_id.lookup(db.upcast()).container { 819 let substs = match function_id.lookup(db.upcast()).container {
763 AssocContainerId::TraitId(_) => Substitution::build_for_def(db, function_id) 820 AssocContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
764 .push(self_ty.value.clone()) 821 .push(self_ty.value.clone())
765 .fill_with_unknown() 822 .fill_with_unknown()
766 .build(), 823 .build(),
767 AssocContainerId::ImplId(impl_id) => { 824 AssocContainerId::ImplId(impl_id) => {
768 let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?; 825 let impl_substs = inherent_impl_substs(db, impl_id, &self_ty)?;
769 Substitution::build_for_def(db, function_id) 826 TyBuilder::subst_for_def(db, function_id)
770 .use_parent_substs(&impl_substs) 827 .use_parent_substs(&impl_substs)
771 .fill_with_unknown() 828 .fill_with_unknown()
772 .build() 829 .build()
@@ -774,7 +831,7 @@ fn transform_receiver_ty(
774 AssocContainerId::ModuleId(_) => unreachable!(), 831 AssocContainerId::ModuleId(_) => unreachable!(),
775 }; 832 };
776 let sig = db.callable_item_signature(function_id.into()); 833 let sig = db.callable_item_signature(function_id.into());
777 Some(sig.value.params()[0].clone().subst_bound_vars(&substs)) 834 Some(sig.map(|s| s.params()[0].clone()).substitute(&Interner, &substs))
778} 835}
779 836
780pub fn implements_trait( 837pub fn implements_trait(
@@ -800,7 +857,7 @@ pub fn implements_trait_unique(
800 let goal = generic_implements_goal(db, env, trait_, ty.clone()); 857 let goal = generic_implements_goal(db, env, trait_, ty.clone());
801 let solution = db.trait_solve(krate, goal); 858 let solution = db.trait_solve(krate, goal);
802 859
803 matches!(solution, Some(crate::traits::Solution::Unique(_))) 860 matches!(solution, Some(crate::Solution::Unique(_)))
804} 861}
805 862
806/// This creates Substs for a trait with the given Self type and type variables 863/// This creates Substs for a trait with the given Self type and type variables
@@ -812,7 +869,7 @@ fn generic_implements_goal(
812 self_ty: Canonical<Ty>, 869 self_ty: Canonical<Ty>,
813) -> Canonical<InEnvironment<super::DomainGoal>> { 870) -> Canonical<InEnvironment<super::DomainGoal>> {
814 let mut kinds = self_ty.binders.interned().to_vec(); 871 let mut kinds = self_ty.binders.interned().to_vec();
815 let substs = super::Substitution::build_for_def(db, trait_) 872 let trait_ref = TyBuilder::trait_ref(db, trait_)
816 .push(self_ty.value) 873 .push(self_ty.value)
817 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len()) 874 .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
818 .build(); 875 .build();
@@ -821,13 +878,12 @@ fn generic_implements_goal(
821 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General), 878 chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
822 UniverseIndex::ROOT, 879 UniverseIndex::ROOT,
823 )) 880 ))
824 .take(substs.len() - 1), 881 .take(trait_ref.substitution.len(&Interner) - 1),
825 ); 882 );
826 let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_), substitution: substs };
827 let obligation = trait_ref.cast(&Interner); 883 let obligation = trait_ref.cast(&Interner);
828 Canonical { 884 Canonical {
829 binders: CanonicalVarKinds::from_iter(&Interner, kinds), 885 binders: CanonicalVarKinds::from_iter(&Interner, kinds),
830 value: InEnvironment::new(env.env.clone(), obligation), 886 value: InEnvironment::new(&env.env, obligation),
831 } 887 }
832} 888}
833 889
@@ -838,8 +894,8 @@ fn autoderef_method_receiver(
838) -> Vec<Canonical<Ty>> { 894) -> Vec<Canonical<Ty>> {
839 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect(); 895 let mut deref_chain: Vec<_> = autoderef::autoderef(db, Some(krate), ty).collect();
840 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!) 896 // As a last step, we can do array unsizing (that's the only unsizing that rustc does for method receivers!)
841 if let Some(TyKind::Array(parameters)) = 897 if let Some(TyKind::Array(parameters, _)) =
842 deref_chain.last().map(|ty| ty.value.interned(&Interner)) 898 deref_chain.last().map(|ty| ty.value.kind(&Interner))
843 { 899 {
844 let kinds = deref_chain.last().unwrap().binders.clone(); 900 let kinds = deref_chain.last().unwrap().binders.clone();
845 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner); 901 let unsized_ty = TyKind::Slice(parameters.clone()).intern(&Interner);
diff --git a/crates/hir_ty/src/op.rs b/crates/hir_ty/src/op.rs
index 527c5cbbd..0222de2bc 100644
--- a/crates/hir_ty/src/op.rs
+++ b/crates/hir_ty/src/op.rs
@@ -2,29 +2,63 @@
2use chalk_ir::TyVariableKind; 2use chalk_ir::TyVariableKind;
3use hir_def::expr::{ArithOp, BinaryOp, CmpOp}; 3use hir_def::expr::{ArithOp, BinaryOp, CmpOp};
4 4
5use crate::{Interner, Scalar, Ty, TyKind}; 5use crate::{Interner, Scalar, Ty, TyBuilder, TyKind};
6 6
7pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty { 7pub(super) fn binary_op_return_ty(op: BinaryOp, lhs_ty: Ty, rhs_ty: Ty) -> Ty {
8 match op { 8 match op {
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 { .. } => Ty::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.interned(&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.interned(&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}
@@ -33,24 +67,24 @@ pub(super) fn binary_op_rhs_expectation(op: BinaryOp, lhs_ty: Ty) -> Ty {
33 match op { 67 match op {
34 BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner), 68 BinaryOp::LogicOp(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
35 BinaryOp::Assignment { op: None } => lhs_ty, 69 BinaryOp::Assignment { op: None } => lhs_ty,
36 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.interned(&Interner) { 70 BinaryOp::CmpOp(CmpOp::Eq { .. }) => match lhs_ty.kind(&Interner) {
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(_) }
47 | BinaryOp::ArithOp(_) => match lhs_ty.interned(&Interner) { 81 | BinaryOp::ArithOp(_) => match lhs_ty.kind(&Interner) {
48 TyKind::Scalar(Scalar::Int(_)) 82 TyKind::Scalar(Scalar::Int(_))
49 | TyKind::Scalar(Scalar::Uint(_)) 83 | TyKind::Scalar(Scalar::Uint(_))
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.rs b/crates/hir_ty/src/tests.rs
index ad283c1e0..ccfb88c52 100644
--- a/crates/hir_ty/src/tests.rs
+++ b/crates/hir_ty/src/tests.rs
@@ -288,7 +288,7 @@ fn visit_module(
288 } 288 }
289 289
290 fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) { 290 fn visit_body(db: &TestDB, body: &Body, cb: &mut dyn FnMut(DefWithBodyId)) {
291 for def_map in body.block_scopes.iter().filter_map(|block| db.block_def_map(*block)) { 291 for (_, def_map) in body.blocks(db) {
292 for (mod_id, _) in def_map.modules() { 292 for (mod_id, _) in def_map.modules() {
293 visit_module(db, &def_map, mod_id, cb); 293 visit_module(db, &def_map, mod_id, cb);
294 } 294 }
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 3eb01dbd0..b8e373ed8 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -373,6 +373,32 @@ fn recursive_inner_item_macro_rules() {
373} 373}
374 374
375#[test] 375#[test]
376fn infer_macro_defining_block_with_items() {
377 check_infer(
378 r#"
379 macro_rules! foo {
380 () => {{
381 fn bar() -> usize { 0 }
382 bar()
383 }};
384 }
385 fn main() {
386 let _a = foo!();
387 }
388 "#,
389 expect![[r#"
390 !15..18 '{0}': usize
391 !16..17 '0': usize
392 !0..24 '{fnbar...bar()}': usize
393 !18..21 'bar': fn bar() -> usize
394 !18..23 'bar()': usize
395 98..122 '{ ...!(); }': ()
396 108..110 '_a': usize
397 "#]],
398 );
399}
400
401#[test]
376fn infer_type_value_macro_having_same_name() { 402fn infer_type_value_macro_having_same_name() {
377 check_infer( 403 check_infer(
378 r#" 404 r#"
@@ -1039,11 +1065,11 @@ fn macro_in_arm() {
1039 } 1065 }
1040 "#, 1066 "#,
1041 expect![[r#" 1067 expect![[r#"
1068 !0..2 '()': ()
1042 51..110 '{ ... }; }': () 1069 51..110 '{ ... }; }': ()
1043 61..62 'x': u32 1070 61..62 'x': u32
1044 65..107 'match ... }': u32 1071 65..107 'match ... }': u32
1045 71..73 '()': () 1072 71..73 '()': ()
1046 84..91 'unit!()': ()
1047 95..100 '92u32': u32 1073 95..100 '92u32': u32
1048 "#]], 1074 "#]],
1049 ); 1075 );
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 61f18b0d2..4b2c82b41 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1292,3 +1292,25 @@ mod b {
1292 "#]], 1292 "#]],
1293 ) 1293 )
1294} 1294}
1295
1296#[test]
1297fn 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}
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 2ba97f814..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
@@ -3370,3 +3357,120 @@ fn test() {
3370 "#]], 3357 "#]],
3371 ) 3358 )
3372} 3359}
3360
3361#[test]
3362fn qualified_path_as_qualified_trait() {
3363 check_infer(
3364 r#"
3365mod foo {
3366
3367 pub trait Foo {
3368 type Target;
3369 }
3370 pub trait Bar {
3371 type Output;
3372 fn boo() -> Self::Output {
3373 loop {}
3374 }
3375 }
3376}
3377
3378struct F;
3379impl foo::Foo for F {
3380 type Target = ();
3381}
3382impl foo::Bar for F {
3383 type Output = <F as foo::Foo>::Target;
3384}
3385
3386fn foo() {
3387 use foo::Bar;
3388 let x = <F as Bar>::boo();
3389}"#,
3390 expect![[r#"
3391 132..163 '{ ... }': Bar::Output<Self>
3392 146..153 'loop {}': !
3393 151..153 '{}': ()
3394 306..358 '{ ...o(); }': ()
3395 334..335 'x': ()
3396 338..353 '<F as Bar>::boo': fn boo<F>() -> <F as Bar>::Output
3397 338..355 '<F as ...:boo()': ()
3398 "#]],
3399 );
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 ccee0e5ad..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.substitution[0].interned(&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 aef6b8a15..000000000
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ /dev/null
@@ -1,560 +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, 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() - 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 Substitution {
220 type Chalk = chalk_ir::Substitution<Interner>;
221
222 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Substitution<Interner> {
223 chalk_ir::Substitution::from_iter(&Interner, self.iter().map(|ty| ty.clone().to_chalk(db)))
224 }
225
226 fn from_chalk(
227 db: &dyn HirDatabase,
228 parameters: chalk_ir::Substitution<Interner>,
229 ) -> Substitution {
230 let tys = parameters
231 .iter(&Interner)
232 .map(|p| match p.ty(&Interner) {
233 Some(ty) => from_chalk(db, ty.clone()),
234 None => unimplemented!(),
235 })
236 .collect();
237 Substitution(tys)
238 }
239}
240
241impl ToChalk for TraitRef {
242 type Chalk = chalk_ir::TraitRef<Interner>;
243
244 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
245 let trait_id = self.trait_id;
246 let substitution = self.substitution.to_chalk(db);
247 chalk_ir::TraitRef { trait_id, substitution }
248 }
249
250 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
251 let trait_id = trait_ref.trait_id;
252 let substs = from_chalk(db, trait_ref.substitution);
253 TraitRef { trait_id, substitution: substs }
254 }
255}
256
257impl ToChalk for hir_def::TraitId {
258 type Chalk = TraitId;
259
260 fn to_chalk(self, _db: &dyn HirDatabase) -> TraitId {
261 chalk_ir::TraitId(self.as_intern_id())
262 }
263
264 fn from_chalk(_db: &dyn HirDatabase, trait_id: TraitId) -> hir_def::TraitId {
265 InternKey::from_intern_id(trait_id.0)
266 }
267}
268
269impl ToChalk for hir_def::ImplId {
270 type Chalk = ImplId;
271
272 fn to_chalk(self, _db: &dyn HirDatabase) -> ImplId {
273 chalk_ir::ImplId(self.as_intern_id())
274 }
275
276 fn from_chalk(_db: &dyn HirDatabase, impl_id: ImplId) -> hir_def::ImplId {
277 InternKey::from_intern_id(impl_id.0)
278 }
279}
280
281impl ToChalk for CallableDefId {
282 type Chalk = FnDefId;
283
284 fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId {
285 db.intern_callable_def(self).into()
286 }
287
288 fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDefId {
289 db.lookup_intern_callable_def(fn_def_id.into())
290 }
291}
292
293pub(crate) struct TypeAliasAsValue(pub(crate) TypeAliasId);
294
295impl ToChalk for TypeAliasAsValue {
296 type Chalk = AssociatedTyValueId;
297
298 fn to_chalk(self, _db: &dyn HirDatabase) -> AssociatedTyValueId {
299 rust_ir::AssociatedTyValueId(self.0.as_intern_id())
300 }
301
302 fn from_chalk(
303 _db: &dyn HirDatabase,
304 assoc_ty_value_id: AssociatedTyValueId,
305 ) -> TypeAliasAsValue {
306 TypeAliasAsValue(TypeAliasId::from_intern_id(assoc_ty_value_id.0))
307 }
308}
309
310impl ToChalk for WhereClause {
311 type Chalk = chalk_ir::WhereClause<Interner>;
312
313 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
314 match self {
315 WhereClause::Implemented(trait_ref) => {
316 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
317 }
318 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
319 }
320 }
321
322 fn from_chalk(
323 db: &dyn HirDatabase,
324 where_clause: chalk_ir::WhereClause<Interner>,
325 ) -> WhereClause {
326 match where_clause {
327 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
328 chalk_ir::WhereClause::AliasEq(alias_eq) => {
329 WhereClause::AliasEq(from_chalk(db, alias_eq))
330 }
331
332 chalk_ir::WhereClause::LifetimeOutlives(_) => {
333 // we shouldn't get these from Chalk
334 panic!("encountered LifetimeOutlives from Chalk")
335 }
336
337 chalk_ir::WhereClause::TypeOutlives(_) => {
338 // we shouldn't get these from Chalk
339 panic!("encountered TypeOutlives from Chalk")
340 }
341 }
342 }
343}
344
345impl ToChalk for ProjectionTy {
346 type Chalk = chalk_ir::ProjectionTy<Interner>;
347
348 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::ProjectionTy<Interner> {
349 chalk_ir::ProjectionTy {
350 associated_ty_id: self.associated_ty_id,
351 substitution: self.substitution.to_chalk(db),
352 }
353 }
354
355 fn from_chalk(
356 db: &dyn HirDatabase,
357 projection_ty: chalk_ir::ProjectionTy<Interner>,
358 ) -> ProjectionTy {
359 ProjectionTy {
360 associated_ty_id: projection_ty.associated_ty_id,
361 substitution: from_chalk(db, projection_ty.substitution),
362 }
363 }
364}
365impl ToChalk for OpaqueTy {
366 type Chalk = chalk_ir::OpaqueTy<Interner>;
367
368 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
369 chalk_ir::OpaqueTy {
370 opaque_ty_id: self.opaque_ty_id,
371 substitution: self.substitution.to_chalk(db),
372 }
373 }
374
375 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
376 OpaqueTy {
377 opaque_ty_id: chalk.opaque_ty_id,
378 substitution: from_chalk(db, chalk.substitution),
379 }
380 }
381}
382
383impl ToChalk for AliasTy {
384 type Chalk = chalk_ir::AliasTy<Interner>;
385
386 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
387 match self {
388 AliasTy::Projection(projection_ty) => {
389 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
390 }
391 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
392 }
393 }
394
395 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
396 match chalk {
397 chalk_ir::AliasTy::Projection(projection_ty) => {
398 AliasTy::Projection(from_chalk(db, projection_ty))
399 }
400 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
401 }
402 }
403}
404
405impl ToChalk for AliasEq {
406 type Chalk = chalk_ir::AliasEq<Interner>;
407
408 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
409 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
410 }
411
412 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
413 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
414 }
415}
416
417impl ToChalk for DomainGoal {
418 type Chalk = chalk_ir::DomainGoal<Interner>;
419
420 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
421 match self {
422 DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
423 DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
424 alias_eq.to_chalk(db).cast(&Interner)
425 }
426 }
427 }
428
429 fn from_chalk(_db: &dyn HirDatabase, _goal: chalk_ir::DomainGoal<Interner>) -> Self {
430 unimplemented!()
431 }
432}
433
434impl<T> ToChalk for Canonical<T>
435where
436 T: ToChalk,
437 T::Chalk: HasInterner<Interner = Interner>,
438{
439 type Chalk = chalk_ir::Canonical<T::Chalk>;
440
441 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
442 let value = self.value.to_chalk(db);
443 chalk_ir::Canonical { value, binders: self.binders }
444 }
445
446 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
447 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
448 }
449}
450
451impl<T: ToChalk> ToChalk for InEnvironment<T>
452where
453 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
454{
455 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
456
457 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
458 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
459 }
460
461 fn from_chalk(
462 _db: &dyn HirDatabase,
463 _in_env: chalk_ir::InEnvironment<T::Chalk>,
464 ) -> InEnvironment<T> {
465 unimplemented!()
466 }
467}
468
469impl<T: ToChalk> ToChalk for crate::Binders<T>
470where
471 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
472{
473 type Chalk = chalk_ir::Binders<T::Chalk>;
474
475 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
476 chalk_ir::Binders::new(
477 chalk_ir::VariableKinds::from_iter(
478 &Interner,
479 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
480 .take(self.num_binders),
481 ),
482 self.value.to_chalk(db),
483 )
484 }
485
486 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
487 let (v, b) = binders.into_value_and_skipped_binders();
488 crate::Binders::new(b.len(&Interner), from_chalk(db, v))
489 }
490}
491
492pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
493where
494 T: HasInterner<Interner = Interner>,
495{
496 chalk_ir::Binders::new(
497 chalk_ir::VariableKinds::from_iter(
498 &Interner,
499 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
500 .take(num_vars),
501 ),
502 value,
503 )
504}
505
506pub(super) fn convert_where_clauses(
507 db: &dyn HirDatabase,
508 def: GenericDefId,
509 substs: &Substitution,
510) -> Vec<chalk_ir::QuantifiedWhereClause<Interner>> {
511 let generic_predicates = db.generic_predicates(def);
512 let mut result = Vec::with_capacity(generic_predicates.len());
513 for pred in generic_predicates.iter() {
514 result.push(pred.clone().subst(substs).to_chalk(db));
515 }
516 result
517}
518
519pub(super) fn generic_predicate_to_inline_bound(
520 db: &dyn HirDatabase,
521 pred: &QuantifiedWhereClause,
522 self_ty: &Ty,
523) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
524 // An InlineBound is like a GenericPredicate, except the self type is left out.
525 // We don't have a special type for this, but Chalk does.
526 let self_ty_shifted_in = self_ty.clone().shift_bound_vars(DebruijnIndex::ONE);
527 match &pred.value {
528 WhereClause::Implemented(trait_ref) => {
529 if trait_ref.self_type_parameter() != &self_ty_shifted_in {
530 // we can only convert predicates back to type bounds if they
531 // have the expected self type
532 return None;
533 }
534 let args_no_self = trait_ref.substitution[1..]
535 .iter()
536 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
537 .collect();
538 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
539 Some(make_binders(rust_ir::InlineBound::TraitBound(trait_bound), pred.num_binders))
540 }
541 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
542 if projection_ty.self_type_parameter() != &self_ty_shifted_in {
543 return None;
544 }
545 let trait_ = projection_ty.trait_(db);
546 let args_no_self = projection_ty.substitution[1..]
547 .iter()
548 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
549 .collect();
550 let alias_eq_bound = rust_ir::AliasEqBound {
551 value: ty.clone().to_chalk(db),
552 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
553 associated_ty_id: projection_ty.associated_ty_id,
554 parameters: Vec::new(), // FIXME we don't support generic associated types yet
555 };
556 Some(make_binders(rust_ir::InlineBound::AliasEqBound(alias_eq_bound), pred.num_binders))
557 }
558 _ => None,
559 }
560}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 42d7af146..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::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, TraitRef, 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
@@ -249,6 +232,26 @@ impl Generics {
249 self.parent_generics.as_ref().and_then(|g| g.find_param(param)) 232 self.parent_generics.as_ref().and_then(|g| g.find_param(param))
250 } 233 }
251 } 234 }
235
236 /// Returns a Substitution that replaces each parameter by a bound variable.
237 pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
238 Substitution::from_iter(
239 &Interner,
240 self.iter()
241 .enumerate()
242 .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(&Interner)),
243 )
244 }
245
246 /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
247 pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
248 Substitution::from_iter(
249 &Interner,
250 self.iter().map(|(id, _)| {
251 TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(&Interner)
252 }),
253 )
254 }
252} 255}
253 256
254fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> { 257fn parent_generic_def(db: &dyn DefDatabase, def: GenericDefId) -> Option<GenericDefId> {
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/annotations.rs b/crates/ide/src/annotations.rs
index 64bc926f1..5ebe7fd0e 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -19,6 +19,8 @@ use crate::{
19// 19//
20// Provides user with annotations above items for looking up references or impl blocks 20// Provides user with annotations above items for looking up references or impl blocks
21// and running/debugging binaries. 21// and running/debugging binaries.
22//
23// image::https://user-images.githubusercontent.com/48062697/113020672-b7c34f00-917a-11eb-8f6e-858735660a0e.png[]
22#[derive(Debug)] 24#[derive(Debug)]
23pub struct Annotation { 25pub struct Annotation {
24 pub range: TextRange, 26 pub range: TextRange,
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 22697a537..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,15 +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_unused(true)
169 .with_fix(d.fix(&sema))
170 .with_code(Some(d.code())),
171 ); 158 );
172 }) 159 })
173 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| { 160 .on::<hir::diagnostics::UnresolvedProcMacro, _>(|d| {
@@ -222,15 +209,23 @@ pub(crate) fn diagnostics(
222 res.into_inner() 209 res.into_inner()
223} 210}
224 211
225fn 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 {
226 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())
227 .with_fix(d.fix(&sema)) 218 .with_fix(d.fix(&sema, resolve))
228 .with_code(Some(d.code())) 219 .with_code(Some(d.code()))
229} 220}
230 221
231fn 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 {
232 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())
233 .with_fix(d.fix(&sema)) 228 .with_fix(d.fix(&sema, resolve))
234 .with_code(Some(d.code())) 229 .with_code(Some(d.code()))
235} 230}
236 231
@@ -260,7 +255,8 @@ fn check_unnecessary_braces_in_use_statement(
260 255
261 acc.push( 256 acc.push(
262 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string()) 257 Diagnostic::hint(use_range, "Unnecessary braces in use statement".to_string())
263 .with_fix(Some(Fix::new( 258 .with_fix(Some(fix(
259 "remove_braces",
264 "Remove unnecessary braces", 260 "Remove unnecessary braces",
265 SourceChange::from_text_edit(file_id, edit), 261 SourceChange::from_text_edit(file_id, edit),
266 use_range, 262 use_range,
@@ -283,6 +279,23 @@ fn text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(
283 None 279 None
284} 280}
285 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
286#[cfg(test)] 299#[cfg(test)]
287mod tests { 300mod tests {
288 use expect_test::{expect, Expect}; 301 use expect_test::{expect, Expect};
@@ -301,16 +314,17 @@ mod tests {
301 314
302 let (analysis, file_position) = fixture::position(ra_fixture_before); 315 let (analysis, file_position) = fixture::position(ra_fixture_before);
303 let diagnostic = analysis 316 let diagnostic = analysis
304 .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) 317 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
305 .unwrap() 318 .unwrap()
306 .pop() 319 .pop()
307 .unwrap(); 320 .unwrap();
308 let fix = diagnostic.fix.unwrap(); 321 let fix = diagnostic.fix.unwrap();
309 let actual = { 322 let actual = {
310 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();
311 let mut actual = analysis.file_text(file_id).unwrap().to_string(); 325 let mut actual = analysis.file_text(file_id).unwrap().to_string();
312 326
313 for edit in fix.source_change.source_file_edits.values() { 327 for edit in source_change.source_file_edits.values() {
314 edit.apply(&mut actual); 328 edit.apply(&mut actual);
315 } 329 }
316 actual 330 actual
@@ -318,9 +332,9 @@ mod tests {
318 332
319 assert_eq_text!(&after, &actual); 333 assert_eq_text!(&after, &actual);
320 assert!( 334 assert!(
321 fix.fix_trigger_range.contains_inclusive(file_position.offset), 335 fix.target.contains_inclusive(file_position.offset),
322 "diagnostic fix range {:?} does not touch cursor position {:?}", 336 "diagnostic fix range {:?} does not touch cursor position {:?}",
323 fix.fix_trigger_range, 337 fix.target,
324 file_position.offset 338 file_position.offset
325 ); 339 );
326 } 340 }
@@ -329,7 +343,7 @@ mod tests {
329 fn check_no_fix(ra_fixture: &str) { 343 fn check_no_fix(ra_fixture: &str) {
330 let (analysis, file_position) = fixture::position(ra_fixture); 344 let (analysis, file_position) = fixture::position(ra_fixture);
331 let diagnostic = analysis 345 let diagnostic = analysis
332 .diagnostics(&DiagnosticsConfig::default(), file_position.file_id) 346 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
333 .unwrap() 347 .unwrap()
334 .pop() 348 .pop()
335 .unwrap(); 349 .unwrap();
@@ -343,7 +357,7 @@ mod tests {
343 let diagnostics = files 357 let diagnostics = files
344 .into_iter() 358 .into_iter()
345 .flat_map(|file_id| { 359 .flat_map(|file_id| {
346 analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap() 360 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap()
347 }) 361 })
348 .collect::<Vec<_>>(); 362 .collect::<Vec<_>>();
349 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics); 363 assert_eq!(diagnostics.len(), 0, "unexpected diagnostics:\n{:#?}", diagnostics);
@@ -351,7 +365,8 @@ mod tests {
351 365
352 fn check_expect(ra_fixture: &str, expect: Expect) { 366 fn check_expect(ra_fixture: &str, expect: Expect) {
353 let (analysis, file_id) = fixture::file(ra_fixture); 367 let (analysis, file_id) = fixture::file(ra_fixture);
354 let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); 368 let diagnostics =
369 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap();
355 expect.assert_debug_eq(&diagnostics) 370 expect.assert_debug_eq(&diagnostics)
356 } 371 }
357 372
@@ -664,24 +679,31 @@ fn test_fn() {
664 range: 0..8, 679 range: 0..8,
665 severity: Error, 680 severity: Error,
666 fix: Some( 681 fix: Some(
667 Fix { 682 Assist {
683 id: AssistId(
684 "create_module",
685 QuickFix,
686 ),
668 label: "Create module", 687 label: "Create module",
669 source_change: SourceChange { 688 group: None,
670 source_file_edits: {}, 689 target: 0..8,
671 file_system_edits: [ 690 source_change: Some(
672 CreateFile { 691 SourceChange {
673 dst: AnchoredPathBuf { 692 source_file_edits: {},
674 anchor: FileId( 693 file_system_edits: [
675 0, 694 CreateFile {
676 ), 695 dst: AnchoredPathBuf {
677 path: "foo.rs", 696 anchor: FileId(
697 0,
698 ),
699 path: "foo.rs",
700 },
701 initial_contents: "",
678 }, 702 },
679 initial_contents: "", 703 ],
680 }, 704 is_snippet: false,
681 ], 705 },
682 is_snippet: false, 706 ),
683 },
684 fix_trigger_range: 0..8,
685 }, 707 },
686 ), 708 ),
687 unused: false, 709 unused: false,
@@ -703,7 +725,7 @@ fn test_fn() {
703 expect![[r#" 725 expect![[r#"
704 [ 726 [
705 Diagnostic { 727 Diagnostic {
706 message: "unresolved macro call", 728 message: "unresolved macro `foo::bar!`",
707 range: 5..8, 729 range: 5..8,
708 severity: Error, 730 severity: Error,
709 fix: None, 731 fix: None,
@@ -889,10 +911,11 @@ struct Foo {
889 911
890 let (analysis, file_id) = fixture::file(r#"mod foo;"#); 912 let (analysis, file_id) = fixture::file(r#"mod foo;"#);
891 913
892 let diagnostics = analysis.diagnostics(&config, file_id).unwrap(); 914 let diagnostics = analysis.diagnostics(&config, true, file_id).unwrap();
893 assert!(diagnostics.is_empty()); 915 assert!(diagnostics.is_empty());
894 916
895 let diagnostics = analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap(); 917 let diagnostics =
918 analysis.diagnostics(&DiagnosticsConfig::default(), true, file_id).unwrap();
896 assert!(!diagnostics.is_empty()); 919 assert!(!diagnostics.is_empty());
897 } 920 }
898 921
@@ -998,8 +1021,9 @@ impl TestStruct {
998 let expected = r#"fn foo() {}"#; 1021 let expected = r#"fn foo() {}"#;
999 1022
1000 let (analysis, file_position) = fixture::position(input); 1023 let (analysis, file_position) = fixture::position(input);
1001 let diagnostics = 1024 let diagnostics = analysis
1002 analysis.diagnostics(&DiagnosticsConfig::default(), file_position.file_id).unwrap(); 1025 .diagnostics(&DiagnosticsConfig::default(), true, file_position.file_id)
1026 .unwrap();
1003 assert_eq!(diagnostics.len(), 1); 1027 assert_eq!(diagnostics.len(), 1);
1004 1028
1005 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 9301cdeff..c5dc14a23 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| {
@@ -98,76 +95,52 @@ pub(crate) fn remove_links(markdown: &str) -> String {
98 out 95 out
99} 96}
100 97
98/// Retrieve a link to documentation for the given symbol.
99pub(crate) fn external_docs(
100 db: &RootDatabase,
101 position: &FilePosition,
102) -> Option<DocumentationLink> {
103 let sema = Semantics::new(db);
104 let file = sema.parse(position.file_id).syntax().clone();
105 let token = pick_best(file.token_at_offset(position.offset))?;
106 let token = sema.descend_into_macros(token);
107
108 let node = token.parent()?;
109 let definition = match_ast! {
110 match node {
111 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
112 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
113 _ => None,
114 }
115 };
116
117 get_doc_link(db, definition?)
118}
119
120/// Extracts all links from a given markdown text.
101pub(crate) fn extract_definitions_from_markdown( 121pub(crate) fn extract_definitions_from_markdown(
102 markdown: &str, 122 markdown: &str,
103) -> Vec<(Range<usize>, String, Option<hir::Namespace>)> { 123) -> Vec<(TextRange, String, Option<hir::Namespace>)> {
104 let mut res = vec![]; 124 Parser::new_with_broken_link_callback(
105 let mut cb = |link: BrokenLink| { 125 markdown,
106 // These allocations are actually unnecessary but the lifetimes on BrokenLinkCallback are wrong 126 Options::empty(),
107 // this is fixed in the repo but not on the crates.io release yet 127 Some(&mut broken_link_clone_cb),
108 Some(( 128 )
109 /*url*/ link.reference.to_owned().into(), 129 .into_offset_iter()
110 /*title*/ link.reference.to_owned().into(), 130 .filter_map(|(event, range)| {
111 ))
112 };
113 let doc = Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(&mut cb));
114 for (event, range) in doc.into_offset_iter() {
115 if let Event::Start(Tag::Link(_, target, title)) = event { 131 if let Event::Start(Tag::Link(_, target, title)) = event {
116 let link = if target.is_empty() { title } else { target }; 132 let link = if target.is_empty() { title } else { target };
117 let (link, ns) = parse_intra_doc_link(&link); 133 let (link, ns) = parse_intra_doc_link(&link);
118 res.push((range, link.to_string(), ns)); 134 Some((
119 } 135 TextRange::new(range.start.try_into().ok()?, range.end.try_into().ok()?),
120 } 136 link.to_string(),
121 res 137 ns,
122} 138 ))
123 139 } else {
124/// Extracts a link from a comment at the given position returning the spanning range, link and 140 None
125/// optionally it's namespace.
126pub(crate) fn extract_positioned_link_from_comment(
127 position: TextSize,
128 comment: &ast::Comment,
129) -> Option<(TextRange, String, Option<hir::Namespace>)> {
130 let doc_comment = comment.doc_comment()?;
131 let comment_start =
132 comment.syntax().text_range().start() + TextSize::from(comment.prefix().len() as u32);
133 let def_links = extract_definitions_from_markdown(doc_comment);
134 let (range, def_link, ns) =
135 def_links.into_iter().find_map(|(Range { start, end }, def_link, ns)| {
136 let range = TextRange::at(
137 comment_start + TextSize::from(start as u32),
138 TextSize::from((end - start) as u32),
139 );
140 range.contains(position).then(|| (range, def_link, ns))
141 })?;
142 Some((range, def_link, ns))
143}
144
145/// Turns a syntax node into it's [`Definition`] if it can hold docs.
146pub(crate) fn doc_owner_to_def(
147 sema: &Semantics<RootDatabase>,
148 item: &SyntaxNode,
149) -> Option<Definition> {
150 let res: hir::ModuleDef = match_ast! {
151 match item {
152 ast::SourceFile(_it) => sema.scope(item).module()?.into(),
153 ast::Fn(it) => sema.to_def(&it)?.into(),
154 ast::Struct(it) => sema.to_def(&it)?.into(),
155 ast::Enum(it) => sema.to_def(&it)?.into(),
156 ast::Union(it) => sema.to_def(&it)?.into(),
157 ast::Trait(it) => sema.to_def(&it)?.into(),
158 ast::Const(it) => sema.to_def(&it)?.into(),
159 ast::Static(it) => sema.to_def(&it)?.into(),
160 ast::TypeAlias(it) => sema.to_def(&it)?.into(),
161 ast::Variant(it) => sema.to_def(&it)?.into(),
162 ast::Trait(it) => sema.to_def(&it)?.into(),
163 ast::Impl(it) => return sema.to_def(&it).map(Definition::SelfType),
164 ast::Macro(it) => return sema.to_def(&it).map(Definition::Macro),
165 ast::TupleField(it) => return sema.to_def(&it).map(Definition::Field),
166 ast::RecordField(it) => return sema.to_def(&it).map(Definition::Field),
167 _ => return None,
168 } 141 }
169 }; 142 })
170 Some(Definition::ModuleDef(res)) 143 .collect()
171} 144}
172 145
173pub(crate) fn resolve_doc_path_for_def( 146pub(crate) fn resolve_doc_path_for_def(
@@ -178,15 +151,15 @@ pub(crate) fn resolve_doc_path_for_def(
178) -> Option<hir::ModuleDef> { 151) -> Option<hir::ModuleDef> {
179 match def { 152 match def {
180 Definition::ModuleDef(def) => match def { 153 Definition::ModuleDef(def) => match def {
181 ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns), 154 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
182 ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns), 155 hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
183 ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns), 156 hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
184 ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns), 157 hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
185 ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns), 158 hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
186 ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns), 159 hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
187 ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns), 160 hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
188 ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns), 161 hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
189 ModuleDef::BuiltinType(_) => None, 162 hir::ModuleDef::BuiltinType(_) => None,
190 }, 163 },
191 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns), 164 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
192 Definition::Field(it) => it.resolve_doc_path(db, &link, ns), 165 Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
@@ -197,6 +170,42 @@ pub(crate) fn resolve_doc_path_for_def(
197 } 170 }
198} 171}
199 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
200// FIXME: 209// FIXME:
201// BUG: For Option::Some 210// BUG: For Option::Some
202// 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
@@ -214,7 +223,7 @@ fn get_doc_link(db: &RootDatabase, definition: Definition) -> Option<String> {
214 .and_then(|assoc| match assoc.container(db) { 223 .and_then(|assoc| match assoc.container(db) {
215 AssocItemContainer::Trait(t) => Some(t.into()), 224 AssocItemContainer::Trait(t) => Some(t.into()),
216 AssocItemContainer::Impl(impld) => { 225 AssocItemContainer::Impl(impld) => {
217 impld.target_ty(db).as_adt().map(|adt| adt.into()) 226 impld.self_ty(db).as_adt().map(|adt| adt.into())
218 } 227 }
219 }) 228 })
220 .unwrap_or_else(|| f.clone().into()), 229 .unwrap_or_else(|| f.clone().into()),
@@ -328,28 +337,6 @@ fn rewrite_url_link(db: &RootDatabase, def: ModuleDef, target: &str) -> Option<S
328 .map(|url| url.into_string()) 337 .map(|url| url.into_string())
329} 338}
330 339
331/// Retrieve a link to documentation for the given symbol.
332pub(crate) fn external_docs(
333 db: &RootDatabase,
334 position: &FilePosition,
335) -> Option<DocumentationLink> {
336 let sema = Semantics::new(db);
337 let file = sema.parse(position.file_id).syntax().clone();
338 let token = pick_best(file.token_at_offset(position.offset))?;
339 let token = sema.descend_into_macros(token);
340
341 let node = token.parent()?;
342 let definition = match_ast! {
343 match node {
344 ast::NameRef(name_ref) => NameRefClass::classify(&sema, &name_ref).map(|d| d.referenced(sema.db)),
345 ast::Name(name) => NameClass::classify(&sema, &name).map(|d| d.referenced_or_defined(sema.db)),
346 _ => None,
347 }
348 };
349
350 get_doc_link(db, definition?)
351}
352
353/// Rewrites a markdown document, applying 'callback' to each link. 340/// Rewrites a markdown document, applying 'callback' to each link.
354fn map_links<'e>( 341fn map_links<'e>(
355 events: impl Iterator<Item = Event<'e>>, 342 events: impl Iterator<Item = Event<'e>>,
diff --git a/crates/ide/src/expand_macro.rs b/crates/ide/src/expand_macro.rs
index ffb3a6f7d..be0ee03bf 100644
--- a/crates/ide/src/expand_macro.rs
+++ b/crates/ide/src/expand_macro.rs
@@ -1,3 +1,5 @@
1use std::iter;
2
1use hir::Semantics; 3use hir::Semantics;
2use ide_db::RootDatabase; 4use ide_db::RootDatabase;
3use syntax::{ 5use syntax::{
@@ -23,6 +25,8 @@ pub struct ExpandedMacro {
23// 25//
24// | VS Code | **Rust Analyzer: Expand macro recursively** 26// | VS Code | **Rust Analyzer: Expand macro recursively**
25// |=== 27// |===
28//
29// image::https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif[]
26pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> { 30pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
27 let sema = Semantics::new(db); 31 let sema = Semantics::new(db);
28 let file = sema.parse(position.file_id); 32 let file = sema.parse(position.file_id);
@@ -89,24 +93,42 @@ fn insert_whitespaces(syn: SyntaxNode) -> String {
89 let is_last = 93 let is_last =
90 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) }; 94 |f: fn(SyntaxKind) -> bool, default| -> bool { last.map(f).unwrap_or(default) };
91 95
92 res += &match token.kind() { 96 match token.kind() {
93 k if is_text(k) && is_next(|it| !it.is_punct(), true) => token.text().to_string() + " ", 97 k if is_text(k) && is_next(|it| !it.is_punct(), true) => {
98 res.push_str(token.text());
99 res.push(' ');
100 }
94 L_CURLY if is_next(|it| it != R_CURLY, true) => { 101 L_CURLY if is_next(|it| it != R_CURLY, true) => {
95 indent += 1; 102 indent += 1;
96 let leading_space = if is_last(is_text, false) { " " } else { "" }; 103 if is_last(is_text, false) {
97 format!("{}{{\n{}", leading_space, " ".repeat(indent)) 104 res.push(' ');
105 }
106 res.push_str("{\n");
107 res.extend(iter::repeat(" ").take(2 * indent));
98 } 108 }
99 R_CURLY if is_last(|it| it != L_CURLY, true) => { 109 R_CURLY if is_last(|it| it != L_CURLY, true) => {
100 indent = indent.saturating_sub(1); 110 indent = indent.saturating_sub(1);
101 format!("\n{}}}", " ".repeat(indent)) 111 res.push('\n');
112 res.extend(iter::repeat(" ").take(2 * indent));
113 res.push_str("}");
102 } 114 }
103 R_CURLY => format!("}}\n{}", " ".repeat(indent)), 115 R_CURLY => {
104 T![;] => format!(";\n{}", " ".repeat(indent)), 116 res.push_str("}\n");
105 T![->] => " -> ".to_string(), 117 res.extend(iter::repeat(" ").take(2 * indent));
106 T![=] => " = ".to_string(), 118 }
107 T![=>] => " => ".to_string(), 119 LIFETIME_IDENT if is_next(|it| it == IDENT, true) => {
108 _ => token.text().to_string(), 120 res.push_str(token.text());
109 }; 121 res.push(' ');
122 }
123 T![;] => {
124 res.push_str(";\n");
125 res.extend(iter::repeat(" ").take(2 * indent));
126 }
127 T![->] => res.push_str(" -> "),
128 T![=] => res.push_str(" = "),
129 T![=>] => res.push_str(" => "),
130 _ => res.push_str(token.text()),
131 }
110 132
111 last = Some(token.kind()); 133 last = Some(token.kind());
112 } 134 }
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index 5201ce587..7032889ac 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -24,6 +24,8 @@ use crate::FileRange;
24// 24//
25// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←] 25// | VS Code | kbd:[Alt+Shift+→], kbd:[Alt+Shift+←]
26// |=== 26// |===
27//
28// image::https://user-images.githubusercontent.com/48062697/113020651-b42fc800-917a-11eb-8a4f-cf1a07859fac.gif[]
27pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange { 29pub(crate) fn extend_selection(db: &RootDatabase, frange: FileRange) -> TextRange {
28 let sema = Semantics::new(db); 30 let sema = Semantics::new(db);
29 let src = sema.parse(frange.file_id); 31 let src = sema.parse(frange.file_id);
diff --git a/crates/ide/src/file_structure.rs b/crates/ide/src/file_structure.rs
index 2c898eae8..19071d6be 100644
--- a/crates/ide/src/file_structure.rs
+++ b/crates/ide/src/file_structure.rs
@@ -35,6 +35,9 @@ pub enum StructureNodeKind {
35// 35//
36// | VS Code | kbd:[Ctrl+Shift+O] 36// | VS Code | kbd:[Ctrl+Shift+O]
37// |=== 37// |===
38//
39// image::https://user-images.githubusercontent.com/48062697/113020654-b42fc800-917a-11eb-8388-e7dc4d92b02e.gif[]
40
38pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> { 41pub(crate) fn file_structure(file: &SourceFile) -> Vec<StructureNode> {
39 let mut res = Vec::new(); 42 let mut res = Vec::new();
40 let mut stack = Vec::new(); 43 let mut stack = Vec::new();
diff --git a/crates/ide/src/folding_ranges.rs b/crates/ide/src/folding_ranges.rs
index 4b1b24562..2b9ed123c 100644
--- a/crates/ide/src/folding_ranges.rs
+++ b/crates/ide/src/folding_ranges.rs
@@ -17,6 +17,9 @@ pub enum FoldKind {
17 Block, 17 Block,
18 ArgList, 18 ArgList,
19 Region, 19 Region,
20 Consts,
21 Statics,
22 Array,
20} 23}
21 24
22#[derive(Debug)] 25#[derive(Debug)]
@@ -30,6 +33,8 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
30 let mut visited_comments = FxHashSet::default(); 33 let mut visited_comments = FxHashSet::default();
31 let mut visited_imports = FxHashSet::default(); 34 let mut visited_imports = FxHashSet::default();
32 let mut visited_mods = FxHashSet::default(); 35 let mut visited_mods = FxHashSet::default();
36 let mut visited_consts = FxHashSet::default();
37 let mut visited_statics = FxHashSet::default();
33 // regions can be nested, here is a LIFO buffer 38 // regions can be nested, here is a LIFO buffer
34 let mut regions_starts: Vec<TextSize> = vec![]; 39 let mut regions_starts: Vec<TextSize> = vec![];
35 40
@@ -91,6 +96,19 @@ pub(crate) fn folding_ranges(file: &SourceFile) -> Vec<Fold> {
91 res.push(Fold { range, kind: FoldKind::Mods }) 96 res.push(Fold { range, kind: FoldKind::Mods })
92 } 97 }
93 } 98 }
99
100 // Fold groups of consts
101 if node.kind() == CONST && !visited_consts.contains(&node) {
102 if let Some(range) = contiguous_range_for_group(&node, &mut visited_consts) {
103 res.push(Fold { range, kind: FoldKind::Consts })
104 }
105 }
106 // Fold groups of consts
107 if node.kind() == STATIC && !visited_statics.contains(&node) {
108 if let Some(range) = contiguous_range_for_group(&node, &mut visited_statics) {
109 res.push(Fold { range, kind: FoldKind::Statics })
110 }
111 }
94 } 112 }
95 } 113 }
96 } 114 }
@@ -102,6 +120,7 @@ fn fold_kind(kind: SyntaxKind) -> Option<FoldKind> {
102 match kind { 120 match kind {
103 COMMENT => Some(FoldKind::Comment), 121 COMMENT => Some(FoldKind::Comment),
104 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList), 122 ARG_LIST | PARAM_LIST => Some(FoldKind::ArgList),
123 ARRAY_EXPR => Some(FoldKind::Array),
105 ASSOC_ITEM_LIST 124 ASSOC_ITEM_LIST
106 | RECORD_FIELD_LIST 125 | RECORD_FIELD_LIST
107 | RECORD_PAT_FIELD_LIST 126 | RECORD_PAT_FIELD_LIST
@@ -250,6 +269,9 @@ mod tests {
250 FoldKind::Block => "block", 269 FoldKind::Block => "block",
251 FoldKind::ArgList => "arglist", 270 FoldKind::ArgList => "arglist",
252 FoldKind::Region => "region", 271 FoldKind::Region => "region",
272 FoldKind::Consts => "consts",
273 FoldKind::Statics => "statics",
274 FoldKind::Array => "array",
253 }; 275 };
254 assert_eq!(kind, &attr.unwrap()); 276 assert_eq!(kind, &attr.unwrap());
255 } 277 }
@@ -446,6 +468,20 @@ fn foo<fold arglist>(
446 } 468 }
447 469
448 #[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]
449 fn fold_region() { 485 fn fold_region() {
450 check( 486 check(
451 r#" 487 r#"
@@ -457,4 +493,24 @@ calling_function(x,y);
457"#, 493"#,
458 ) 494 )
459 } 495 }
496
497 #[test]
498 fn fold_consecutive_const() {
499 check(
500 r#"
501<fold consts>const FIRST_CONST: &str = "first";
502const SECOND_CONST: &str = "second";</fold>
503 "#,
504 )
505 }
506
507 #[test]
508 fn fold_consecutive_static() {
509 check(
510 r#"
511<fold statics>static FIRST_STATIC: &str = "first";
512static SECOND_STATIC: &str = "second";</fold>
513 "#,
514 )
515 }
460} 516}
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index a2c97061f..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
@@ -21,6 +21,8 @@ use crate::{
21// 21//
22// | VS Code | kbd:[F12] 22// | VS Code | kbd:[F12]
23// |=== 23// |===
24//
25// image::https://user-images.githubusercontent.com/48062697/113065563-025fbe00-91b1-11eb-83e4-a5a703610b23.gif[]
24pub(crate) fn goto_definition( 26pub(crate) fn goto_definition(
25 db: &RootDatabase, 27 db: &RootDatabase,
26 position: FilePosition, 28 position: FilePosition,
@@ -30,9 +32,16 @@ pub(crate) fn goto_definition(
30 let original_token = pick_best(file.token_at_offset(position.offset))?; 32 let original_token = pick_best(file.token_at_offset(position.offset))?;
31 let token = sema.descend_into_macros(original_token.clone()); 33 let token = sema.descend_into_macros(original_token.clone());
32 let parent = token.parent()?; 34 let parent = token.parent()?;
33 if let Some(comment) = ast::Comment::cast(token) { 35 if let Some(_) = ast::Comment::cast(token) {
34 let (_, link, ns) = extract_positioned_link_from_comment(position.offset, &comment)?; 36 let (attributes, def) = doc_attributes(&sema, &parent)?;
35 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 })?;
36 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)?;
37 return Some(RangeInfo::new(original_token.text_range(), vec![nav])); 46 return Some(RangeInfo::new(original_token.text_range(), vec![nav]));
38 } 47 }
@@ -101,6 +110,13 @@ mod tests {
101 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() });
102 } 111 }
103 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
104 #[test] 120 #[test]
105 fn goto_def_for_extern_crate() { 121 fn goto_def_for_extern_crate() {
106 check( 122 check(
@@ -918,6 +934,16 @@ fn f() -> impl Iterator<Item$0 = u8> {}
918 } 934 }
919 935
920 #[test] 936 #[test]
937 fn unknown_assoc_ty() {
938 check_unresolved(
939 r#"
940trait Iterator { type Item; }
941fn f() -> impl Iterator<Invalid$0 = u8> {}
942"#,
943 )
944 }
945
946 #[test]
921 fn goto_def_for_assoc_ty_in_path_multiple() { 947 fn goto_def_for_assoc_ty_in_path_multiple() {
922 check( 948 check(
923 r#" 949 r#"
@@ -1143,4 +1169,51 @@ fn fn_macro() {}
1143 "#, 1169 "#,
1144 ) 1170 )
1145 } 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 }
1146} 1219}
diff --git a/crates/ide/src/goto_implementation.rs b/crates/ide/src/goto_implementation.rs
index f4d7c14a6..05130a237 100644
--- a/crates/ide/src/goto_implementation.rs
+++ b/crates/ide/src/goto_implementation.rs
@@ -16,6 +16,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
16// 16//
17// | VS Code | kbd:[Ctrl+F12] 17// | VS Code | kbd:[Ctrl+F12]
18// |=== 18// |===
19//
20// image::https://user-images.githubusercontent.com/48062697/113065566-02f85480-91b1-11eb-9288-aaad8abd8841.gif[]
19pub(crate) fn goto_implementation( 21pub(crate) fn goto_implementation(
20 db: &RootDatabase, 22 db: &RootDatabase,
21 position: FilePosition, 23 position: FilePosition,
diff --git a/crates/ide/src/goto_type_definition.rs b/crates/ide/src/goto_type_definition.rs
index 2d38cb112..9d34b109b 100644
--- a/crates/ide/src/goto_type_definition.rs
+++ b/crates/ide/src/goto_type_definition.rs
@@ -12,6 +12,8 @@ use crate::{display::TryToNav, FilePosition, NavigationTarget, RangeInfo};
12// 12//
13// | VS Code | **Go to Type Definition* 13// | VS Code | **Go to Type Definition*
14// |=== 14// |===
15//
16// image::https://user-images.githubusercontent.com/48062697/113020657-b560f500-917a-11eb-9007-0f809733a338.gif[]
15pub(crate) fn goto_type_definition( 17pub(crate) fn goto_type_definition(
16 db: &RootDatabase, 18 db: &RootDatabase,
17 position: FilePosition, 19 position: FilePosition,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 3c951c507..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,
@@ -82,6 +82,8 @@ pub struct HoverResult {
82// 82//
83// Shows additional information, like type of an expression or documentation for definition when "focusing" code. 83// Shows additional information, like type of an expression or documentation for definition when "focusing" code.
84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut. 84// Focusing is usually hovering with a mouse, but can also be triggered with a shortcut.
85//
86// image::https://user-images.githubusercontent.com/48062697/113020658-b5f98b80-917a-11eb-9f88-3dbc27320c95.gif[]
85pub(crate) fn hover( 87pub(crate) fn hover(
86 db: &RootDatabase, 88 db: &RootDatabase,
87 position: FilePosition, 89 position: FilePosition,
@@ -114,11 +116,19 @@ pub(crate) fn hover(
114 ), 116 ),
115 117
116 _ => ast::Comment::cast(token.clone()) 118 _ => ast::Comment::cast(token.clone())
117 .and_then(|comment| { 119 .and_then(|_| {
120 let (attributes, def) = doc_attributes(&sema, &node)?;
121 let (docs, doc_mapping) = attributes.docs_with_rangemap(db)?;
118 let (idl_range, link, ns) = 122 let (idl_range, link, ns) =
119 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 })?;
120 range = Some(idl_range); 131 range = Some(idl_range);
121 let def = doc_owner_to_def(&sema, &node)?;
122 resolve_doc_path_for_def(db, def, &link, ns) 132 resolve_doc_path_for_def(db, def, &link, ns)
123 }) 133 })
124 .map(Definition::ModuleDef), 134 .map(Definition::ModuleDef),
@@ -195,7 +205,7 @@ fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<Hov
195 let adt = match def { 205 let adt = match def {
196 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action), 206 Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
197 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it), 207 Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
198 Definition::SelfType(it) => it.target_ty(db).as_adt(), 208 Definition::SelfType(it) => it.self_ty(db).as_adt(),
199 _ => None, 209 _ => None,
200 }?; 210 }?;
201 adt.try_to_nav(db).map(to_action) 211 adt.try_to_nav(db).map(to_action)
@@ -318,7 +328,7 @@ fn definition_owner_name(db: &RootDatabase, def: &Definition) -> Option<String>
318 Definition::ModuleDef(md) => match md { 328 Definition::ModuleDef(md) => match md {
319 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) { 329 ModuleDef::Function(f) => match f.as_assoc_item(db)?.container(db) {
320 AssocItemContainer::Trait(t) => Some(t.name(db)), 330 AssocItemContainer::Trait(t) => Some(t.name(db)),
321 AssocItemContainer::Impl(i) => i.target_ty(db).as_adt().map(|adt| adt.name(db)), 331 AssocItemContainer::Impl(i) => i.self_ty(db).as_adt().map(|adt| adt.name(db)),
322 }, 332 },
323 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)), 333 ModuleDef::Variant(e) => Some(e.parent_enum(db).name(db)),
324 _ => None, 334 _ => None,
@@ -376,7 +386,7 @@ fn hover_for_definition(
376 }, 386 },
377 Definition::Local(it) => hover_for_local(it, db), 387 Definition::Local(it) => hover_for_local(it, db),
378 Definition::SelfType(impl_def) => { 388 Definition::SelfType(impl_def) => {
379 impl_def.target_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path)) 389 impl_def.self_ty(db).as_adt().and_then(|adt| from_hir_fmt(db, adt, mod_path))
380 } 390 }
381 Definition::GenericParam(it) => from_hir_fmt(db, it, None), 391 Definition::GenericParam(it) => from_hir_fmt(db, it, None),
382 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))), 392 Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
@@ -470,6 +480,7 @@ fn find_std_module(famous_defs: &FamousDefs, name: &str) -> Option<hir::Module>
470 480
471fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> { 481fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
472 return tokens.max_by_key(priority); 482 return tokens.max_by_key(priority);
483
473 fn priority(n: &SyntaxToken) -> usize { 484 fn priority(n: &SyntaxToken) -> usize {
474 match n.kind() { 485 match n.kind() {
475 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3, 486 IDENT | INT_NUMBER | LIFETIME_IDENT | T![self] | T![super] | T![crate] => 3,
@@ -3811,24 +3822,139 @@ fn main() {
3811 fn hover_intra_doc_links() { 3822 fn hover_intra_doc_links() {
3812 check( 3823 check(
3813 r#" 3824 r#"
3814/// This is the [`foo`](foo$0) function. 3825
3815fn 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}
3816"#, 3837"#,
3817 expect![[r#" 3838 expect![[r#"
3818 *[`foo`](foo)* 3839 *[`TheItem`]*
3819 3840
3820 ```rust 3841 ```rust
3821 test 3842 test::theitem
3822 ``` 3843 ```
3823 3844
3824 ```rust 3845 ```rust
3825 fn foo() 3846 pub struct TheItem
3826 ``` 3847 ```
3827 3848
3828 --- 3849 ---
3829 3850
3830 This is the [`foo`](https://docs.rs/test/*/test/fn.foo.html) function. 3851 This is the item. Cool!
3852 "#]],
3853 );
3854 }
3855
3856 #[test]
3857 fn hover_generic_assoc() {
3858 check(
3859 r#"
3860fn foo<T: A>() where T::Assoc$0: {}
3861
3862trait A {
3863 type Assoc;
3864}"#,
3865 expect![[r#"
3866 *Assoc*
3867
3868 ```rust
3869 test
3870 ```
3871
3872 ```rust
3873 type Assoc
3874 ```
3875 "#]],
3876 );
3877 check(
3878 r#"
3879fn foo<T: A>() {
3880 let _: <T>::Assoc$0;
3881}
3882
3883trait A {
3884 type Assoc;
3885}"#,
3886 expect![[r#"
3887 *Assoc*
3888
3889 ```rust
3890 test
3891 ```
3892
3893 ```rust
3894 type Assoc
3895 ```
3896 "#]],
3897 );
3898 check(
3899 r#"
3900trait A where
3901 Self::Assoc$0: ,
3902{
3903 type Assoc;
3904}"#,
3905 expect![[r#"
3906 *Assoc*
3907
3908 ```rust
3909 test
3910 ```
3911
3912 ```rust
3913 type Assoc
3914 ```
3831 "#]], 3915 "#]],
3832 ); 3916 );
3833 } 3917 }
3918
3919 #[test]
3920 fn string_shadowed_with_inner_items() {
3921 check(
3922 r#"
3923//- /main.rs crate:main deps:alloc
3924
3925/// Custom `String` type.
3926struct String;
3927
3928fn f() {
3929 let _: String$0;
3930
3931 fn inner() {}
3932}
3933
3934//- /alloc.rs crate:alloc
3935#[prelude_import]
3936pub use string::*;
3937
3938mod string {
3939 /// This is `alloc::String`.
3940 pub struct String;
3941}
3942 "#,
3943 expect![[r#"
3944 *String*
3945
3946 ```rust
3947 main
3948 ```
3949
3950 ```rust
3951 struct String
3952 ```
3953
3954 ---
3955
3956 Custom `String` type.
3957 "#]],
3958 )
3959 }
3834} 3960}
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 25f96222c..d5ef054d8 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -52,6 +52,8 @@ pub struct InlayHint {
52// 52//
53// | VS Code | **Rust Analyzer: Toggle inlay hints* 53// | VS Code | **Rust Analyzer: Toggle inlay hints*
54// |=== 54// |===
55//
56// image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
55pub(crate) fn inlay_hints( 57pub(crate) fn inlay_hints(
56 db: &RootDatabase, 58 db: &RootDatabase,
57 file_id: FileId, 59 file_id: FileId,
@@ -232,7 +234,7 @@ fn hint_iterator(
232 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias), 234 hir::AssocItem::TypeAlias(alias) if alias.name(db) == known::Item => Some(alias),
233 _ => None, 235 _ => None,
234 })?; 236 })?;
235 if let Some(ty) = ty.normalize_trait_assoc_type(db, iter_trait, &[], assoc_type_item) { 237 if let Some(ty) = ty.normalize_trait_assoc_type(db, &[], assoc_type_item) {
236 const LABEL_START: &str = "impl Iterator<Item = "; 238 const LABEL_START: &str = "impl Iterator<Item = ";
237 const LABEL_END: &str = ">"; 239 const LABEL_END: &str = ">";
238 240
diff --git a/crates/ide/src/join_lines.rs b/crates/ide/src/join_lines.rs
index 4b25135cd..fe2a349e6 100644
--- a/crates/ide/src/join_lines.rs
+++ b/crates/ide/src/join_lines.rs
@@ -19,6 +19,8 @@ use text_edit::{TextEdit, TextEditBuilder};
19// 19//
20// | VS Code | **Rust Analyzer: Join lines** 20// | VS Code | **Rust Analyzer: Join lines**
21// |=== 21// |===
22//
23// image::https://user-images.githubusercontent.com/48062697/113020661-b6922200-917a-11eb-87c4-b75acc028f11.gif[]
22pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit { 24pub(crate) fn join_lines(file: &SourceFile, range: TextRange) -> TextEdit {
23 let range = if range.is_empty() { 25 let range = if range.is_empty() {
24 let syntax = file.syntax(); 26 let syntax = file.syntax();
@@ -86,8 +88,11 @@ fn remove_newline(edit: &mut TextEditBuilder, token: &SyntaxToken, offset: TextS
86 } 88 }
87 89
88 // The node is between two other nodes 90 // The node is between two other nodes
89 let prev = token.prev_sibling_or_token().unwrap(); 91 let (prev, next) = match (token.prev_sibling_or_token(), token.next_sibling_or_token()) {
90 let next = token.next_sibling_or_token().unwrap(); 92 (Some(prev), Some(next)) => (prev, next),
93 _ => return,
94 };
95
91 if is_trailing_comma(prev.kind(), next.kind()) { 96 if is_trailing_comma(prev.kind(), next.kind()) {
92 // Removes: trailing comma, newline (incl. surrounding whitespace) 97 // Removes: trailing comma, newline (incl. surrounding whitespace)
93 edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end())); 98 edit.delete(TextRange::new(prev.text_range().start(), token.text_range().end()));
@@ -827,4 +832,15 @@ $0hello world
827"#, 832"#,
828 ); 833 );
829 } 834 }
835 #[test]
836 fn join_last_line_empty() {
837 check_join_lines(
838 r#"
839fn main() {$0}
840"#,
841 r#"
842fn main() {$0}
843"#,
844 );
845 }
830} 846}
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 3f73c0632..b24c664ba 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};
@@ -526,9 +526,39 @@ impl Analysis {
526 pub fn diagnostics( 526 pub fn diagnostics(
527 &self, 527 &self,
528 config: &DiagnosticsConfig, 528 config: &DiagnosticsConfig,
529 resolve: bool,
529 file_id: FileId, 530 file_id: FileId,
530 ) -> Cancelable<Vec<Diagnostic>> { 531 ) -> Cancelable<Vec<Diagnostic>> {
531 self.with_db(|db| diagnostics::diagnostics(db, config, file_id)) 532 self.with_db(|db| diagnostics::diagnostics(db, config, resolve, file_id))
533 }
534
535 /// Convenience function to return assists + quick fixes for diagnostics
536 pub fn assists_with_fixes(
537 &self,
538 assist_config: &AssistConfig,
539 diagnostics_config: &DiagnosticsConfig,
540 resolve: bool,
541 frange: FileRange,
542 ) -> Cancelable<Vec<Assist>> {
543 let include_fixes = match &assist_config.allowed {
544 Some(it) => it.iter().any(|&it| it == AssistKind::None || it == AssistKind::QuickFix),
545 None => true,
546 };
547
548 self.with_db(|db| {
549 let mut res = Assist::get(db, assist_config, resolve, frange);
550 ssr::add_ssr_assist(db, &mut res, resolve, frange);
551
552 if include_fixes {
553 res.extend(
554 diagnostics::diagnostics(db, diagnostics_config, resolve, frange.file_id)
555 .into_iter()
556 .filter_map(|it| it.fix)
557 .filter(|it| it.target.intersect(frange.range).is_some()),
558 );
559 }
560 res
561 })
532 } 562 }
533 563
534 /// Returns the edit required to rename reference at the position to the new 564 /// Returns the edit required to rename reference at the position to the new
diff --git a/crates/ide/src/matching_brace.rs b/crates/ide/src/matching_brace.rs
index 4241a6dac..261dcc255 100644
--- a/crates/ide/src/matching_brace.rs
+++ b/crates/ide/src/matching_brace.rs
@@ -14,6 +14,8 @@ use syntax::{
14// 14//
15// | VS Code | **Rust Analyzer: Find matching brace** 15// | VS Code | **Rust Analyzer: Find matching brace**
16// |=== 16// |===
17//
18// image::https://user-images.githubusercontent.com/48062697/113065573-04298180-91b1-11eb-8dec-d4e2a202f304.gif[]
17pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> { 19pub(crate) fn matching_brace(file: &SourceFile, offset: TextSize) -> Option<TextSize> {
18 const BRACES: &[SyntaxKind] = 20 const BRACES: &[SyntaxKind] =
19 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]]; 21 &[T!['{'], T!['}'], T!['['], T![']'], T!['('], T![')'], T![<], T![>], T![|], T![|]];
diff --git a/crates/ide/src/move_item.rs b/crates/ide/src/move_item.rs
index 05fa8fc13..246f10a0a 100644
--- a/crates/ide/src/move_item.rs
+++ b/crates/ide/src/move_item.rs
@@ -1,13 +1,15 @@
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};
5use itertools::Itertools; 5use itertools::Itertools;
6use syntax::{ 6use syntax::{
7 algo, ast, match_ast, AstNode, NodeOrToken, SyntaxElement, SyntaxKind, SyntaxNode, TextRange, 7 algo, ast, match_ast, AstNode, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxToken, TextRange,
8 TokenAtOffset,
8}; 9};
9use text_edit::{TextEdit, TextEditBuilder}; 10use text_edit::{TextEdit, TextEditBuilder};
10 11
12#[derive(Copy, Clone, Debug)]
11pub enum Direction { 13pub enum Direction {
12 Up, 14 Up,
13 Down, 15 Down,
@@ -23,6 +25,8 @@ pub enum Direction {
23// | VS Code | **Rust Analyzer: Move item up** 25// | VS Code | **Rust Analyzer: Move item up**
24// | VS Code | **Rust Analyzer: Move item down** 26// | VS Code | **Rust Analyzer: Move item down**
25// |=== 27// |===
28//
29// image::https://user-images.githubusercontent.com/48062697/113065576-04298180-91b1-11eb-91ce-4505e99ed598.gif[]
26pub(crate) fn move_item( 30pub(crate) fn move_item(
27 db: &RootDatabase, 31 db: &RootDatabase,
28 range: FileRange, 32 range: FileRange,
@@ -31,14 +35,19 @@ pub(crate) fn move_item(
31 let sema = Semantics::new(db); 35 let sema = Semantics::new(db);
32 let file = sema.parse(range.file_id); 36 let file = sema.parse(range.file_id);
33 37
34 let item = file.syntax().covering_element(range.range); 38 let item = if range.range.is_empty() {
39 SyntaxElement::Token(pick_best(file.syntax().token_at_offset(range.range.start()))?)
40 } else {
41 file.syntax().covering_element(range.range)
42 };
43
35 find_ancestors(item, direction, range.range) 44 find_ancestors(item, direction, range.range)
36} 45}
37 46
38fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> { 47fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -> Option<TextEdit> {
39 let root = match item { 48 let root = match item {
40 NodeOrToken::Node(node) => node, 49 SyntaxElement::Node(node) => node,
41 NodeOrToken::Token(token) => token.parent()?, 50 SyntaxElement::Token(token) => token.parent()?,
42 }; 51 };
43 52
44 let movable = [ 53 let movable = [
@@ -51,6 +60,11 @@ fn find_ancestors(item: SyntaxElement, direction: Direction, range: TextRange) -
51 SyntaxKind::PARAM, 60 SyntaxKind::PARAM,
52 SyntaxKind::LET_STMT, 61 SyntaxKind::LET_STMT,
53 SyntaxKind::EXPR_STMT, 62 SyntaxKind::EXPR_STMT,
63 SyntaxKind::IF_EXPR,
64 SyntaxKind::FOR_EXPR,
65 SyntaxKind::LOOP_EXPR,
66 SyntaxKind::WHILE_EXPR,
67 SyntaxKind::RETURN_EXPR,
54 SyntaxKind::MATCH_EXPR, 68 SyntaxKind::MATCH_EXPR,
55 SyntaxKind::MACRO_CALL, 69 SyntaxKind::MACRO_CALL,
56 SyntaxKind::TYPE_ALIAS, 70 SyntaxKind::TYPE_ALIAS,
@@ -83,12 +97,12 @@ fn move_in_direction(
83) -> Option<TextEdit> { 97) -> Option<TextEdit> {
84 match_ast! { 98 match_ast! {
85 match node { 99 match node {
86 ast::ArgList(it) => swap_sibling_in_list(it.args(), range, direction), 100 ast::ArgList(it) => swap_sibling_in_list(node, it.args(), range, direction),
87 ast::GenericParamList(it) => swap_sibling_in_list(it.generic_params(), range, direction), 101 ast::GenericParamList(it) => swap_sibling_in_list(node, it.generic_params(), range, direction),
88 ast::GenericArgList(it) => swap_sibling_in_list(it.generic_args(), range, direction), 102 ast::GenericArgList(it) => swap_sibling_in_list(node, it.generic_args(), range, direction),
89 ast::VariantList(it) => swap_sibling_in_list(it.variants(), range, direction), 103 ast::VariantList(it) => swap_sibling_in_list(node, it.variants(), range, direction),
90 ast::TypeBoundList(it) => swap_sibling_in_list(it.bounds(), range, direction), 104 ast::TypeBoundList(it) => swap_sibling_in_list(node, it.bounds(), range, direction),
91 _ => Some(replace_nodes(node, &match direction { 105 _ => Some(replace_nodes(range, node, &match direction {
92 Direction::Up => node.prev_sibling(), 106 Direction::Up => node.prev_sibling(),
93 Direction::Down => node.next_sibling(), 107 Direction::Down => node.next_sibling(),
94 }?)) 108 }?))
@@ -97,30 +111,77 @@ fn move_in_direction(
97} 111}
98 112
99fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>( 113fn swap_sibling_in_list<A: AstNode + Clone, I: Iterator<Item = A>>(
114 node: &SyntaxNode,
100 list: I, 115 list: I,
101 range: TextRange, 116 range: TextRange,
102 direction: Direction, 117 direction: Direction,
103) -> Option<TextEdit> { 118) -> Option<TextEdit> {
104 let (l, r) = list 119 let list_lookup = list
105 .tuple_windows() 120 .tuple_windows()
106 .filter(|(l, r)| match direction { 121 .filter(|(l, r)| match direction {
107 Direction::Up => r.syntax().text_range().contains_range(range), 122 Direction::Up => r.syntax().text_range().contains_range(range),
108 Direction::Down => l.syntax().text_range().contains_range(range), 123 Direction::Down => l.syntax().text_range().contains_range(range),
109 }) 124 })
110 .next()?; 125 .next();
111 126
112 Some(replace_nodes(l.syntax(), r.syntax())) 127 if let Some((l, r)) = list_lookup {
128 Some(replace_nodes(range, l.syntax(), r.syntax()))
129 } else {
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),
132 // and we have to continue tree traversal to find suitable node.
133 find_ancestors(SyntaxElement::Node(node.parent()?), direction, range)
134 }
113} 135}
114 136
115fn 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
116 let mut edit = TextEditBuilder::default(); 165 let mut edit = TextEditBuilder::default();
117 166
118 algo::diff(first, second).into_text_edit(&mut edit); 167 algo::diff(first, second).into_text_edit(&mut edit);
119 algo::diff(second, first).into_text_edit(&mut edit); 168 edit.replace(second.text_range(), first_with_cursor);
120 169
121 edit.finish() 170 edit.finish()
122} 171}
123 172
173fn pick_best(tokens: TokenAtOffset<SyntaxToken>) -> Option<SyntaxToken> {
174 return tokens.max_by_key(priority);
175
176 fn priority(n: &SyntaxToken) -> usize {
177 match n.kind() {
178 SyntaxKind::IDENT | SyntaxKind::LIFETIME_IDENT => 2,
179 kind if kind.is_trivia() => 0,
180 _ => 1,
181 }
182 }
183}
184
124#[cfg(test)] 185#[cfg(test)]
125mod tests { 186mod tests {
126 use crate::fixture; 187 use crate::fixture;
@@ -154,7 +215,7 @@ fn main() {
154 expect![[r#" 215 expect![[r#"
155fn main() { 216fn main() {
156 match true { 217 match true {
157 false => { 218 false =>$0 {
158 println!("Test"); 219 println!("Test");
159 }, 220 },
160 true => { 221 true => {
@@ -188,7 +249,7 @@ fn main() {
188 false => { 249 false => {
189 println!("Test"); 250 println!("Test");
190 }, 251 },
191 true => { 252 true =>$0 {
192 println!("Hello, world"); 253 println!("Hello, world");
193 } 254 }
194 }; 255 };
@@ -240,7 +301,7 @@ fn main() {
240 "#, 301 "#,
241 expect![[r#" 302 expect![[r#"
242fn main() { 303fn main() {
243 let test2 = 456; 304 let test2$0 = 456;
244 let test = 123; 305 let test = 123;
245} 306}
246 "#]], 307 "#]],
@@ -259,7 +320,108 @@ fn main() {
259 "#, 320 "#,
260 expect![[r#" 321 expect![[r#"
261fn main() { 322fn main() {
262 println!("All I want to say is..."); 323 println!("All I want to say is...");$0
324 println!("Hello, world");
325}
326 "#]],
327 Direction::Up,
328 );
329 check(
330 r#"
331fn main() {
332 println!("Hello, world");
333
334 if true {
335 println!("Test");
336 }$0$0
337}
338 "#,
339 expect![[r#"
340fn main() {
341 if true {
342 println!("Test");
343 }$0
344
345 println!("Hello, world");
346}
347 "#]],
348 Direction::Up,
349 );
350 check(
351 r#"
352fn main() {
353 println!("Hello, world");
354
355 for i in 0..10 {
356 println!("Test");
357 }$0$0
358}
359 "#,
360 expect![[r#"
361fn main() {
362 for i in 0..10 {
363 println!("Test");
364 }$0
365
366 println!("Hello, world");
367}
368 "#]],
369 Direction::Up,
370 );
371 check(
372 r#"
373fn main() {
374 println!("Hello, world");
375
376 loop {
377 println!("Test");
378 }$0$0
379}
380 "#,
381 expect![[r#"
382fn main() {
383 loop {
384 println!("Test");
385 }$0
386
387 println!("Hello, world");
388}
389 "#]],
390 Direction::Up,
391 );
392 check(
393 r#"
394fn main() {
395 println!("Hello, world");
396
397 while true {
398 println!("Test");
399 }$0$0
400}
401 "#,
402 expect![[r#"
403fn main() {
404 while true {
405 println!("Test");
406 }$0
407
408 println!("Hello, world");
409}
410 "#]],
411 Direction::Up,
412 );
413 check(
414 r#"
415fn main() {
416 println!("Hello, world");
417
418 return 123;$0$0
419}
420 "#,
421 expect![[r#"
422fn main() {
423 return 123;$0
424
263 println!("Hello, world"); 425 println!("Hello, world");
264} 426}
265 "#]], 427 "#]],
@@ -295,7 +457,7 @@ fn main() {}
295fn foo() {}$0$0 457fn foo() {}$0$0
296 "#, 458 "#,
297 expect![[r#" 459 expect![[r#"
298fn foo() {} 460fn foo() {}$0
299 461
300fn main() {} 462fn main() {}
301 "#]], 463 "#]],
@@ -316,7 +478,7 @@ impl Wow for Yay $0$0{}
316 expect![[r#" 478 expect![[r#"
317struct Yay; 479struct Yay;
318 480
319impl Wow for Yay {} 481impl Wow for Yay $0{}
320 482
321trait Wow {} 483trait Wow {}
322 "#]], 484 "#]],
@@ -332,7 +494,7 @@ use std::vec::Vec;
332use std::collections::HashMap$0$0; 494use std::collections::HashMap$0$0;
333 "#, 495 "#,
334 expect![[r#" 496 expect![[r#"
335use std::collections::HashMap; 497use std::collections::HashMap$0;
336use std::vec::Vec; 498use std::vec::Vec;
337 "#]], 499 "#]],
338 Direction::Up, 500 Direction::Up,
@@ -367,7 +529,7 @@ fn main() {
367 } 529 }
368 530
369 #[test] 531 #[test]
370 fn test_moves_param_up() { 532 fn test_moves_param() {
371 check( 533 check(
372 r#" 534 r#"
373fn test(one: i32, two$0$0: u32) {} 535fn test(one: i32, two$0$0: u32) {}
@@ -377,7 +539,7 @@ fn main() {
377} 539}
378 "#, 540 "#,
379 expect![[r#" 541 expect![[r#"
380fn test(two: u32, one: i32) {} 542fn test(two$0: u32, one: i32) {}
381 543
382fn main() { 544fn main() {
383 test(123, 456); 545 test(123, 456);
@@ -385,6 +547,15 @@ fn main() {
385 "#]], 547 "#]],
386 Direction::Up, 548 Direction::Up,
387 ); 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 );
388 } 559 }
389 560
390 #[test] 561 #[test]
@@ -401,7 +572,7 @@ fn main() {
401fn test(one: i32, two: u32) {} 572fn test(one: i32, two: u32) {}
402 573
403fn main() { 574fn main() {
404 test(456, 123); 575 test(456$0, 123);
405} 576}
406 "#]], 577 "#]],
407 Direction::Up, 578 Direction::Up,
@@ -422,7 +593,7 @@ fn main() {
422fn test(one: i32, two: u32) {} 593fn test(one: i32, two: u32) {}
423 594
424fn main() { 595fn main() {
425 test(456, 123); 596 test(456, 123$0);
426} 597}
427 "#]], 598 "#]],
428 Direction::Down, 599 Direction::Down,
@@ -459,7 +630,7 @@ struct Test<A, B$0$0>(A, B);
459fn main() {} 630fn main() {}
460 "#, 631 "#,
461 expect![[r#" 632 expect![[r#"
462struct Test<B, A>(A, B); 633struct Test<B$0, A>(A, B);
463 634
464fn main() {} 635fn main() {}
465 "#]], 636 "#]],
@@ -481,7 +652,7 @@ fn main() {
481struct Test<A, B>(A, B); 652struct Test<A, B>(A, B);
482 653
483fn main() { 654fn main() {
484 let t = Test::<&str, i32>(123, "yay"); 655 let t = Test::<&str$0, i32>(123, "yay");
485} 656}
486 "#]], 657 "#]],
487 Direction::Up, 658 Direction::Up,
@@ -501,7 +672,7 @@ fn main() {}
501 "#, 672 "#,
502 expect![[r#" 673 expect![[r#"
503enum Hello { 674enum Hello {
504 Two, 675 Two$0,
505 One 676 One
506} 677}
507 678
@@ -528,7 +699,7 @@ trait One {}
528 699
529trait Two {} 700trait Two {}
530 701
531fn test<T: Two + One>(t: T) {} 702fn test<T: Two$0 + One>(t: T) {}
532 703
533fn main() {} 704fn main() {}
534 "#]], 705 "#]],
@@ -574,7 +745,7 @@ trait Yay {
574impl Yay for Test { 745impl Yay for Test {
575 type One = i32; 746 type One = i32;
576 747
577 fn inner() { 748 fn inner() {$0
578 println!("Mmmm"); 749 println!("Mmmm");
579 } 750 }
580 751
@@ -601,7 +772,7 @@ fn test() {
601 "#, 772 "#,
602 expect![[r#" 773 expect![[r#"
603fn test() { 774fn test() {
604 mod hi { 775 mod hi {$0
605 fn inner() {} 776 fn inner() {}
606 } 777 }
607 778
@@ -615,6 +786,115 @@ fn test() {
615 } 786 }
616 787
617 #[test] 788 #[test]
789 fn test_cursor_at_item_start() {
790 check(
791 r#"
792$0$0#[derive(Debug)]
793enum FooBar {
794 Foo,
795 Bar,
796}
797
798fn main() {}
799 "#,
800 expect![[r#"
801fn main() {}
802
803$0#[derive(Debug)]
804enum FooBar {
805 Foo,
806 Bar,
807}
808 "#]],
809 Direction::Down,
810 );
811 check(
812 r#"
813$0$0enum FooBar {
814 Foo,
815 Bar,
816}
817
818fn main() {}
819 "#,
820 expect![[r#"
821fn main() {}
822
823$0enum FooBar {
824 Foo,
825 Bar,
826}
827 "#]],
828 Direction::Down,
829 );
830 check(
831 r#"
832struct Test;
833
834trait SomeTrait {}
835
836$0$0impl SomeTrait for Test {}
837
838fn main() {}
839 "#,
840 expect![[r#"
841struct Test;
842
843$0impl SomeTrait for Test {}
844
845trait SomeTrait {}
846
847fn main() {}
848 "#]],
849 Direction::Up,
850 );
851 }
852
853 #[test]
854 fn test_cursor_at_item_end() {
855 check(
856 r#"
857enum FooBar {
858 Foo,
859 Bar,
860}$0$0
861
862fn main() {}
863 "#,
864 expect![[r#"
865fn main() {}
866
867enum FooBar {
868 Foo,
869 Bar,
870}$0
871 "#]],
872 Direction::Down,
873 );
874 check(
875 r#"
876struct Test;
877
878trait SomeTrait {}
879
880impl SomeTrait for Test {}$0$0
881
882fn main() {}
883 "#,
884 expect![[r#"
885struct Test;
886
887impl SomeTrait for Test {}$0
888
889trait SomeTrait {}
890
891fn main() {}
892 "#]],
893 Direction::Up,
894 );
895 }
896
897 #[test]
618 fn handles_empty_file() { 898 fn handles_empty_file() {
619 check(r#"$0$0"#, expect![[r#""#]], Direction::Up); 899 check(r#"$0$0"#, expect![[r#""#]], Direction::Up);
620 } 900 }
diff --git a/crates/ide/src/parent_module.rs b/crates/ide/src/parent_module.rs
index 22b0d6ecb..99365c8a7 100644
--- a/crates/ide/src/parent_module.rs
+++ b/crates/ide/src/parent_module.rs
@@ -18,6 +18,8 @@ use crate::NavigationTarget;
18// 18//
19// | VS Code | **Rust Analyzer: Locate parent module** 19// | VS Code | **Rust Analyzer: Locate parent module**
20// |=== 20// |===
21//
22// image::https://user-images.githubusercontent.com/48062697/113065580-04c21800-91b1-11eb-9a32-00086161c0bd.gif[]
21 23
22/// This returns `Vec` because a module may be included from several places. 24/// This returns `Vec` because a module may be included from several places.
23pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> { 25pub(crate) fn parent_module(db: &RootDatabase, position: FilePosition) -> Vec<NavigationTarget> {
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 95ed8a045..11ca7ec6b 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -48,6 +48,8 @@ pub struct Declaration {
48// 48//
49// | VS Code | kbd:[Shift+Alt+F12] 49// | VS Code | kbd:[Shift+Alt+F12]
50// |=== 50// |===
51//
52// image::https://user-images.githubusercontent.com/48062697/113020670-b7c34f00-917a-11eb-8003-370ac5f2b3cb.gif[]
51pub(crate) fn find_all_refs( 53pub(crate) fn find_all_refs(
52 sema: &Semantics<RootDatabase>, 54 sema: &Semantics<RootDatabase>,
53 position: FilePosition, 55 position: FilePosition,
diff --git a/crates/ide/src/references/rename.rs b/crates/ide/src/references/rename.rs
index 26d6dc9c9..2408a0181 100644
--- a/crates/ide/src/references/rename.rs
+++ b/crates/ide/src/references/rename.rs
@@ -70,6 +70,8 @@ pub(crate) fn prepare_rename(
70// 70//
71// | VS Code | kbd:[F2] 71// | VS Code | kbd:[F2]
72// |=== 72// |===
73//
74// image::https://user-images.githubusercontent.com/48062697/113065582-055aae80-91b1-11eb-8ade-2b58e6d81883.gif[]
73pub(crate) fn rename( 75pub(crate) fn rename(
74 db: &RootDatabase, 76 db: &RootDatabase,
75 position: FilePosition, 77 position: FilePosition,
@@ -307,7 +309,7 @@ fn rename_to_self(sema: &Semantics<RootDatabase>, local: hir::Local) -> RenameRe
307 hir::AssocItemContainer::Impl(impl_) => impl_, 309 hir::AssocItemContainer::Impl(impl_) => impl_,
308 }; 310 };
309 let first_param_ty = first_param.ty(); 311 let first_param_ty = first_param.ty();
310 let impl_ty = impl_.target_ty(sema.db); 312 let impl_ty = impl_.self_ty(sema.db);
311 let (ty, self_param) = if impl_ty.remove_ref().is_some() { 313 let (ty, self_param) = if impl_ty.remove_ref().is_some() {
312 // if the impl is a ref to the type we can just match the `&T` with self directly 314 // if the impl is a ref to the type we can just match the `&T` with self directly
313 (first_param_ty.clone(), "self") 315 (first_param_ty.clone(), "self")
diff --git a/crates/ide/src/runnables.rs b/crates/ide/src/runnables.rs
index 7e4c5a078..3eb9e27ee 100644
--- a/crates/ide/src/runnables.rs
+++ b/crates/ide/src/runnables.rs
@@ -98,6 +98,7 @@ impl Runnable {
98// 98//
99// | VS Code | **Rust Analyzer: Run** 99// | VS Code | **Rust Analyzer: Run**
100// |=== 100// |===
101// image::https://user-images.githubusercontent.com/48062697/113065583-055aae80-91b1-11eb-958f-d67efcaf6a2f.gif[]
101pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> { 102pub(crate) fn runnables(db: &RootDatabase, file_id: FileId) -> Vec<Runnable> {
102 let sema = Semantics::new(db); 103 let sema = Semantics::new(db);
103 104
@@ -298,7 +299,7 @@ fn module_def_doctest(sema: &Semantics<RootDatabase>, def: hir::ModuleDef) -> Op
298 // FIXME: this also looks very wrong 299 // FIXME: this also looks very wrong
299 if let Some(assoc_def) = assoc_def { 300 if let Some(assoc_def) = assoc_def {
300 if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) { 301 if let hir::AssocItemContainer::Impl(imp) = assoc_def.container(sema.db) {
301 let ty = imp.target_ty(sema.db); 302 let ty = imp.self_ty(sema.db);
302 if let Some(adt) = ty.as_adt() { 303 if let Some(adt) = ty.as_adt() {
303 let name = adt.name(sema.db); 304 let name = adt.name(sema.db);
304 let idx = path.rfind(':').map_or(0, |idx| idx + 1); 305 let idx = path.rfind(':').map_or(0, |idx| idx + 1);
diff --git a/crates/ide/src/status.rs b/crates/ide/src/status.rs
index 137c38c0d..49fde1945 100644
--- a/crates/ide/src/status.rs
+++ b/crates/ide/src/status.rs
@@ -31,6 +31,7 @@ fn macro_syntax_tree_stats(db: &RootDatabase) -> SyntaxTreeStats {
31// 31//
32// | VS Code | **Rust Analyzer: Status** 32// | VS Code | **Rust Analyzer: Status**
33// |=== 33// |===
34// image::https://user-images.githubusercontent.com/48062697/113065584-05f34500-91b1-11eb-98cc-5c196f76be7f.gif[]
34pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String { 35pub(crate) fn status(db: &RootDatabase, file_id: Option<FileId>) -> String {
35 let mut buf = String::new(); 36 let mut buf = String::new();
36 format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>()); 37 format_to!(buf, "{}\n", FileTextQuery.in_db(db).entries::<FilesStats>());
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 67a10766b..9df8d21af 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -48,6 +48,9 @@ pub struct HlRange {
48// 48//
49// The general rule is that a reference to an entity gets colored the same way as the entity itself. 49// The general rule is that a reference to an entity gets colored the same way as the entity itself.
50// We also give special modifier for `mut` and `&mut` local variables. 50// We also give special modifier for `mut` and `&mut` local variables.
51//
52// image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[]
53// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
51pub(crate) fn highlight( 54pub(crate) fn highlight(
52 db: &RootDatabase, 55 db: &RootDatabase,
53 file_id: FileId, 56 file_id: FileId,
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index b0cfdd8b7..8cc877c1c 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -1,6 +1,6 @@
1//! Computes color for a single element. 1//! Computes color for a single element.
2 2
3use hir::{AsAssocItem, Semantics, VariantDef}; 3use hir::{AsAssocItem, AssocItemContainer, Semantics, VariantDef};
4use ide_db::{ 4use ide_db::{
5 defs::{Definition, NameClass, NameRefClass}, 5 defs::{Definition, NameClass, NameRefClass},
6 RootDatabase, SymbolKind, 6 RootDatabase, SymbolKind,
@@ -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::Comparision).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,
@@ -275,12 +310,24 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
275 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module), 310 hir::ModuleDef::Module(_) => HlTag::Symbol(SymbolKind::Module),
276 hir::ModuleDef::Function(func) => { 311 hir::ModuleDef::Function(func) => {
277 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function)); 312 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Function));
278 if func.as_assoc_item(db).is_some() { 313 if let Some(item) = func.as_assoc_item(db) {
279 h |= HlMod::Associated; 314 h |= HlMod::Associated;
280 if func.self_param(db).is_none() { 315 if func.self_param(db).is_none() {
281 h |= HlMod::Static 316 h |= HlMod::Static
282 } 317 }
318
319 match item.container(db) {
320 AssocItemContainer::Impl(i) => {
321 if i.trait_(db).is_some() {
322 h |= HlMod::Trait;
323 }
324 }
325 AssocItemContainer::Trait(_t) => {
326 h |= HlMod::Trait;
327 }
328 }
283 } 329 }
330
284 if func.is_unsafe(db) { 331 if func.is_unsafe(db) {
285 h |= HlMod::Unsafe; 332 h |= HlMod::Unsafe;
286 } 333 }
@@ -292,16 +339,37 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
292 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant), 339 hir::ModuleDef::Variant(_) => HlTag::Symbol(SymbolKind::Variant),
293 hir::ModuleDef::Const(konst) => { 340 hir::ModuleDef::Const(konst) => {
294 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const)); 341 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::Const));
295 if konst.as_assoc_item(db).is_some() { 342 if let Some(item) = konst.as_assoc_item(db) {
296 h |= HlMod::Associated 343 h |= HlMod::Associated;
344 match item.container(db) {
345 AssocItemContainer::Impl(i) => {
346 if i.trait_(db).is_some() {
347 h |= HlMod::Trait;
348 }
349 }
350 AssocItemContainer::Trait(_t) => {
351 h |= HlMod::Trait;
352 }
353 }
297 } 354 }
355
298 return h; 356 return h;
299 } 357 }
300 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait), 358 hir::ModuleDef::Trait(_) => HlTag::Symbol(SymbolKind::Trait),
301 hir::ModuleDef::TypeAlias(type_) => { 359 hir::ModuleDef::TypeAlias(type_) => {
302 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias)); 360 let mut h = Highlight::new(HlTag::Symbol(SymbolKind::TypeAlias));
303 if type_.as_assoc_item(db).is_some() { 361 if let Some(item) = type_.as_assoc_item(db) {
304 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 }
305 } 373 }
306 return h; 374 return h;
307 } 375 }
@@ -362,6 +430,10 @@ fn highlight_method_call(
362 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) { 430 if func.is_unsafe(sema.db) || sema.is_unsafe_method_call(&method_call) {
363 h |= HlMod::Unsafe; 431 h |= HlMod::Unsafe;
364 } 432 }
433 if func.as_assoc_item(sema.db).and_then(|it| it.containing_trait(sema.db)).is_some() {
434 h |= HlMod::Trait
435 }
436
365 if let Some(self_param) = func.self_param(sema.db) { 437 if let Some(self_param) = func.self_param(sema.db) {
366 match self_param.access(sema.db) { 438 match self_param.access(sema.db) {
367 hir::Access::Shared => (), 439 hir::Access::Shared => (),
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index 963c3fb59..04fafd244 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -1,17 +1,18 @@
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, 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, Analysis, HlMod, HlRange, HlTag, RootDatabase, 14 doc_links::{doc_attributes, extract_definitions_from_markdown, resolve_doc_path_for_def},
15 Analysis, HlMod, HlRange, HlTag, RootDatabase,
15}; 16};
16 17
17use super::{highlights::Highlights, injector::Injector}; 18use super::{highlights::Highlights, injector::Injector};
@@ -89,33 +90,6 @@ const RUSTDOC_FENCE_TOKENS: &[&'static str] = &[
89 "edition2021", 90 "edition2021",
90]; 91];
91 92
92fn doc_attributes<'node>(
93 sema: &Semantics<RootDatabase>,
94 node: &'node SyntaxNode,
95) -> Option<(hir::AttrsWithOwner, Definition)> {
96 match_ast! {
97 match node {
98 ast::SourceFile(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
99 ast::Module(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Module(def)))),
100 ast::Fn(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Function(def)))),
101 ast::Struct(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Struct(def))))),
102 ast::Union(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Union(def))))),
103 ast::Enum(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Adt(hir::Adt::Enum(def))))),
104 ast::Variant(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Variant(def)))),
105 ast::Trait(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Trait(def)))),
106 ast::Static(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Static(def)))),
107 ast::Const(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::Const(def)))),
108 ast::TypeAlias(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::ModuleDef(hir::ModuleDef::TypeAlias(def)))),
109 ast::Impl(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::SelfType(def))),
110 ast::RecordField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
111 ast::TupleField(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Field(def))),
112 ast::Macro(it) => sema.to_def(&it).map(|def| (def.attrs(sema.db), Definition::Macro(def))),
113 // ast::Use(it) => sema.to_def(&it).map(|def| (Box::new(it) as _, def.attrs(sema.db))),
114 _ => return None
115 }
116 }
117}
118
119/// Injection of syntax highlighting of doctests. 93/// Injection of syntax highlighting of doctests.
120pub(super) fn doc_comment( 94pub(super) fn doc_comment(
121 hl: &mut Highlights, 95 hl: &mut Highlights,
@@ -138,8 +112,28 @@ pub(super) fn doc_comment(
138 // Replace the original, line-spanning comment ranges by new, only comment-prefix 112 // Replace the original, line-spanning comment ranges by new, only comment-prefix
139 // spanning comment ranges. 113 // spanning comment ranges.
140 let mut new_comments = Vec::new(); 114 let mut new_comments = Vec::new();
141 let mut intra_doc_links = Vec::new();
142 let mut string; 115 let mut string;
116
117 if let Some((docs, doc_mapping)) = attributes.docs_with_rangemap(sema.db) {
118 extract_definitions_from_markdown(docs.as_str())
119 .into_iter()
120 .filter_map(|(range, link, ns)| {
121 let def = resolve_doc_path_for_def(sema.db, def, &link, ns)?;
122 let InFile { file_id, value: range } = doc_mapping.map(range)?;
123 (file_id == node.file_id).then(|| (range, def))
124 })
125 .for_each(|(range, def)| {
126 hl.add(HlRange {
127 range,
128 highlight: module_def_to_hl_tag(def)
129 | HlMod::Documentation
130 | HlMod::Injected
131 | HlMod::IntraDocLink,
132 binding_hash: None,
133 })
134 });
135 }
136
143 for attr in attributes.by_key("doc").attrs() { 137 for attr in attributes.by_key("doc").attrs() {
144 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr); 138 let InFile { file_id, value: src } = attrs_source_map.source_of(&attr);
145 if file_id != node.file_id { 139 if file_id != node.file_id {
@@ -185,25 +179,7 @@ pub(super) fn doc_comment(
185 is_doctest = is_codeblock && is_rust; 179 is_doctest = is_codeblock && is_rust;
186 continue; 180 continue;
187 } 181 }
188 None if !is_doctest => { 182 None if !is_doctest => continue,
189 intra_doc_links.extend(
190 extract_definitions_from_markdown(line)
191 .into_iter()
192 .filter_map(|(range, link, ns)| {
193 Some(range).zip(validate_intra_doc_link(sema.db, &def, &link, ns))
194 })
195 .map(|(Range { start, end }, def)| {
196 (
197 def,
198 TextRange::at(
199 prev_range_start + TextSize::from(start as u32),
200 TextSize::from((end - start) as u32),
201 ),
202 )
203 }),
204 );
205 continue;
206 }
207 None => (), 183 None => (),
208 } 184 }
209 185
@@ -222,17 +198,6 @@ pub(super) fn doc_comment(
222 } 198 }
223 } 199 }
224 200
225 for (def, range) in intra_doc_links {
226 hl.add(HlRange {
227 range,
228 highlight: module_def_to_hl_tag(def)
229 | HlMod::Documentation
230 | HlMod::Injected
231 | HlMod::IntraDocLink,
232 binding_hash: None,
233 });
234 }
235
236 if new_comments.is_empty() { 201 if new_comments.is_empty() {
237 return; // no need to run an analysis on an empty file 202 return; // no need to run an analysis on an empty file
238 } 203 }
@@ -283,33 +248,6 @@ fn find_doc_string_in_attr(attr: &hir::Attr, it: &ast::Attr) -> Option<ast::Stri
283 } 248 }
284} 249}
285 250
286fn validate_intra_doc_link(
287 db: &RootDatabase,
288 def: &Definition,
289 link: &str,
290 ns: Option<hir::Namespace>,
291) -> Option<hir::ModuleDef> {
292 match def {
293 Definition::ModuleDef(def) => match def {
294 hir::ModuleDef::Module(it) => it.resolve_doc_path(db, &link, ns),
295 hir::ModuleDef::Function(it) => it.resolve_doc_path(db, &link, ns),
296 hir::ModuleDef::Adt(it) => it.resolve_doc_path(db, &link, ns),
297 hir::ModuleDef::Variant(it) => it.resolve_doc_path(db, &link, ns),
298 hir::ModuleDef::Const(it) => it.resolve_doc_path(db, &link, ns),
299 hir::ModuleDef::Static(it) => it.resolve_doc_path(db, &link, ns),
300 hir::ModuleDef::Trait(it) => it.resolve_doc_path(db, &link, ns),
301 hir::ModuleDef::TypeAlias(it) => it.resolve_doc_path(db, &link, ns),
302 hir::ModuleDef::BuiltinType(_) => None,
303 },
304 Definition::Macro(it) => it.resolve_doc_path(db, &link, ns),
305 Definition::Field(it) => it.resolve_doc_path(db, &link, ns),
306 Definition::SelfType(_)
307 | Definition::Local(_)
308 | Definition::GenericParam(_)
309 | Definition::Label(_) => None,
310 }
311}
312
313fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag { 251fn module_def_to_hl_tag(def: hir::ModuleDef) -> HlTag {
314 let symbol = match def { 252 let symbol = match def {
315 hir::ModuleDef::Module(_) => SymbolKind::Module, 253 hir::ModuleDef::Module(_) => SymbolKind::Module,
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 93db79b89..8128d231d 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,
@@ -58,6 +58,8 @@ pub enum HlMod {
58 Associated, 58 Associated,
59 /// Used for intra doc links in doc injection. 59 /// Used for intra doc links in doc injection.
60 IntraDocLink, 60 IntraDocLink,
61 /// Used for items in traits and trait impls.
62 Trait,
61 63
62 /// Keep this last! 64 /// Keep this last!
63 Unsafe, 65 Unsafe,
@@ -85,6 +87,20 @@ pub enum HlPunct {
85 Other, 87 Other,
86} 88}
87 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 Comparision,
100 ///
101 Other,
102}
103
88impl HlTag { 104impl HlTag {
89 fn as_str(self) -> &'static str { 105 fn as_str(self) -> &'static str {
90 match self { 106 match self {
@@ -131,7 +147,13 @@ impl HlTag {
131 HlPunct::Other => "punctuation", 147 HlPunct::Other => "punctuation",
132 }, 148 },
133 HlTag::NumericLiteral => "numeric_literal", 149 HlTag::NumericLiteral => "numeric_literal",
134 HlTag::Operator => "operator", 150 HlTag::Operator(op) => match op {
151 HlOperator::Bitwise => "bitwise",
152 HlOperator::Arithmetic => "arithmetic",
153 HlOperator::Logical => "logical",
154 HlOperator::Comparision => "comparision",
155 HlOperator::Other => "operator",
156 },
135 HlTag::StringLiteral => "string_literal", 157 HlTag::StringLiteral => "string_literal",
136 HlTag::UnresolvedReference => "unresolved_reference", 158 HlTag::UnresolvedReference => "unresolved_reference",
137 HlTag::None => "none", 159 HlTag::None => "none",
@@ -158,6 +180,7 @@ impl HlMod {
158 HlMod::Callable, 180 HlMod::Callable,
159 HlMod::Static, 181 HlMod::Static,
160 HlMod::Associated, 182 HlMod::Associated,
183 HlMod::Trait,
161 HlMod::Unsafe, 184 HlMod::Unsafe,
162 ]; 185 ];
163 186
@@ -174,6 +197,7 @@ impl HlMod {
174 HlMod::IntraDocLink => "intra_doc_link", 197 HlMod::IntraDocLink => "intra_doc_link",
175 HlMod::Mutable => "mutable", 198 HlMod::Mutable => "mutable",
176 HlMod::Static => "static", 199 HlMod::Static => "static",
200 HlMod::Trait => "trait",
177 HlMod::Unsafe => "unsafe", 201 HlMod::Unsafe => "unsafe",
178 } 202 }
179 } 203 }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index 4635ea927..8cde3906c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -47,12 +47,12 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
47<span class="brace">}</span> 47<span class="brace">}</span>
48 48
49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span> 49<span class="keyword">trait</span> <span class="trait declaration">t</span> <span class="brace">{</span>
50 <span class="keyword">fn</span> <span class="function declaration static associated">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 50 <span class="keyword">fn</span> <span class="function declaration static associated trait">t_is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
51 <span class="keyword">fn</span> <span class="function declaration associated">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 51 <span class="keyword">fn</span> <span class="function declaration associated trait">t_is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
52<span class="brace">}</span> 52<span class="brace">}</span>
53 53
54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span> 54<span class="keyword">impl</span> <span class="trait">t</span> <span class="keyword">for</span> <span class="struct">foo</span> <span class="brace">{</span>
55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 55 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration static associated trait">is_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 56 <span class="keyword">pub</span> <span class="keyword">fn</span> <span class="function declaration associated trait">is_not_static</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
57<span class="brace">}</span> 57<span class="brace">}</span>
58 </code></pre> \ No newline at end of file 58 </code></pre> \ No newline at end of file
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/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 9215ddd9e..7c6694a27 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -42,7 +42,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 42<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span> 43 <span class="function">fixture</span><span class="parenthesis">(</span><span class="string_literal">r#"</span>
44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span> 44 <span class="keyword">trait</span> <span class="trait declaration">Foo</span> <span class="brace">{</span>
45 <span class="keyword">fn</span> <span class="function declaration static associated">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 45 <span class="keyword">fn</span> <span class="function declaration static associated trait">foo</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span> 46 <span class="macro">println!</span><span class="parenthesis">(</span><span class="string_literal">"2 + 2 = {}"</span><span class="comma">,</span> <span class="numeric_literal">4</span><span class="parenthesis">)</span><span class="semicolon">;</span>
47 <span class="brace">}</span> 47 <span class="brace">}</span>
48 <span class="brace">}</span><span class="string_literal">"#</span> 48 <span class="brace">}</span><span class="string_literal">"#</span>
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 6a6555208..72910421d 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -62,11 +62,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
62<span class="brace">}</span> 62<span class="brace">}</span>
63 63
64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span> 64<span class="keyword">trait</span> <span class="trait declaration">DoTheAutoref</span> <span class="brace">{</span>
65 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span> 65 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span><span class="semicolon">;</span>
66<span class="brace">}</span> 66<span class="brace">}</span>
67 67
68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span> 68<span class="keyword">impl</span> <span class="trait">DoTheAutoref</span> <span class="keyword">for</span> <span class="builtin_type">u16</span> <span class="brace">{</span>
69 <span class="keyword">fn</span> <span class="function declaration associated">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span> 69 <span class="keyword">fn</span> <span class="function declaration associated trait">calls_autoref</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
70<span class="brace">}</span> 70<span class="brace">}</span>
71 71
72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span> 72<span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
@@ -96,6 +96,6 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span> 96 <span class="keyword">let</span> <span class="struct">Packed</span> <span class="brace">{</span> <span class="field">a</span><span class="colon">:</span> <span class="keyword unsafe">ref</span> <span class="variable declaration">_a</span> <span class="brace">}</span> <span class="operator">=</span> <span class="variable">packed</span><span class="semicolon">;</span>
97 97
98 <span class="comment">// unsafe auto ref of packed field</span> 98 <span class="comment">// unsafe auto ref of packed field</span>
99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span> 99 <span class="variable">packed</span><span class="operator">.</span><span class="field">a</span><span class="operator">.</span><span class="function associated trait unsafe">calls_autoref</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
100 <span class="brace">}</span> 100 <span class="brace">}</span>
101<span class="brace">}</span></code></pre> \ No newline at end of file 101<span class="brace">}</span></code></pre> \ No newline at end of file
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 1eaa7b75b..c43bcb691 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -67,11 +67,11 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
67<span class="brace">}</span> 67<span class="brace">}</span>
68 68
69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span> 69<span class="keyword">trait</span> <span class="trait declaration">Bar</span> <span class="brace">{</span>
70 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span> 70 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span><span class="semicolon">;</span>
71<span class="brace">}</span> 71<span class="brace">}</span>
72 72
73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span> 73<span class="keyword">impl</span> <span class="trait">Bar</span> <span class="keyword">for</span> <span class="struct">Foo</span> <span class="brace">{</span>
74 <span class="keyword">fn</span> <span class="function declaration associated">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span> 74 <span class="keyword">fn</span> <span class="function declaration associated trait">bar</span><span class="parenthesis">(</span><span class="operator">&</span><span class="self_keyword declaration">self</span><span class="parenthesis">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">i32</span> <span class="brace">{</span>
75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span> 75 <span class="self_keyword">self</span><span class="operator">.</span><span class="field">x</span>
76 <span class="brace">}</span> 76 <span class="brace">}</span>
77<span class="brace">}</span> 77<span class="brace">}</span>
@@ -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..933cfa6f3 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;
@@ -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/syntax_tree.rs b/crates/ide/src/syntax_tree.rs
index 8979de528..633878d1c 100644
--- a/crates/ide/src/syntax_tree.rs
+++ b/crates/ide/src/syntax_tree.rs
@@ -14,6 +14,7 @@ use syntax::{
14// 14//
15// | VS Code | **Rust Analyzer: Show Syntax Tree** 15// | VS Code | **Rust Analyzer: Show Syntax Tree**
16// |=== 16// |===
17// image::https://user-images.githubusercontent.com/48062697/113065586-068bdb80-91b1-11eb-9507-fee67f9f45a0.gif[]
17pub(crate) fn syntax_tree( 18pub(crate) fn syntax_tree(
18 db: &RootDatabase, 19 db: &RootDatabase,
19 file_id: FileId, 20 file_id: FileId,
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index e10b7d98e..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//
@@ -49,33 +51,87 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
49// ---- 51// ----
50// "editor.formatOnType": true, 52// "editor.formatOnType": true,
51// ---- 53// ----
54//
55// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[]
56// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[]
52pub(crate) fn on_char_typed( 57pub(crate) fn on_char_typed(
53 db: &RootDatabase, 58 db: &RootDatabase,
54 position: FilePosition, 59 position: FilePosition,
55 char_typed: char, 60 char_typed: char,
56) -> Option<SourceChange> { 61) -> Option<SourceChange> {
57 assert!(TRIGGER_CHARS.contains(char_typed)); 62 if !stdx::always!(TRIGGER_CHARS.contains(char_typed)) {
58 let file = &db.parse(position.file_id).tree(); 63 return None;
59 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 }
60 let edit = on_char_typed_inner(file, position.offset, char_typed)?; 69 let edit = on_char_typed_inner(file, position.offset, char_typed)?;
61 Some(SourceChange::from_text_edit(position.file_id, edit)) 70 Some(SourceChange::from_text_edit(position.file_id, edit))
62} 71}
63 72
64fn on_char_typed_inner(file: &SourceFile, offset: TextSize, char_typed: char) -> Option<TextEdit> { 73fn on_char_typed_inner(
65 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 }
66 match char_typed { 81 match char_typed {
67 '.' => on_dot_typed(file, offset), 82 '.' => on_dot_typed(&file.tree(), offset),
68 '=' => on_eq_typed(file, offset), 83 '=' => on_eq_typed(&file.tree(), offset),
69 '>' => on_arrow_typed(file, offset), 84 '>' => on_arrow_typed(&file.tree(), offset),
85 '{' => on_opening_brace_typed(file, offset),
70 _ => unreachable!(), 86 _ => unreachable!(),
71 } 87 }
72} 88}
73 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
74/// Returns an edit which should be applied after `=` was typed. Primarily, 128/// Returns an edit which should be applied after `=` was typed. Primarily,
75/// this works when adding `let =`. 129/// this works when adding `let =`.
76// FIXME: use a snippet completion instead of this hack here. 130// FIXME: use a snippet completion instead of this hack here.
77fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 131fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
78 assert_eq!(file.syntax().text().char_at(offset), Some('=')); 132 if !stdx::always!(file.syntax().text().char_at(offset) == Some('=')) {
133 return None;
134 }
79 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)?;
80 if let_stmt.semicolon_token().is_some() { 136 if let_stmt.semicolon_token().is_some() {
81 return None; 137 return None;
@@ -97,7 +153,9 @@ fn on_eq_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
97 153
98/// 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.
99fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 155fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
100 assert_eq!(file.syntax().text().char_at(offset), Some('.')); 156 if !stdx::always!(file.syntax().text().char_at(offset) == Some('.')) {
157 return None;
158 }
101 let whitespace = 159 let whitespace =
102 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)?;
103 161
@@ -126,7 +184,9 @@ fn on_dot_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
126/// 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() -> { ... }`
127fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> { 185fn on_arrow_typed(file: &SourceFile, offset: TextSize) -> Option<TextEdit> {
128 let file_text = file.syntax().text(); 186 let file_text = file.syntax().text();
129 assert_eq!(file_text.char_at(offset), Some('>')); 187 if !stdx::always!(file_text.char_at(offset) == Some('>')) {
188 return None;
189 }
130 let after_arrow = offset + TextSize::of('>'); 190 let after_arrow = offset + TextSize::of('>');
131 if file_text.char_at(after_arrow) != Some('{') { 191 if file_text.char_at(after_arrow) != Some('{') {
132 return None; 192 return None;
@@ -149,7 +209,7 @@ mod tests {
149 let edit = TextEdit::insert(offset, char_typed.to_string()); 209 let edit = TextEdit::insert(offset, char_typed.to_string());
150 edit.apply(&mut before); 210 edit.apply(&mut before);
151 let parse = SourceFile::parse(&before); 211 let parse = SourceFile::parse(&before);
152 on_char_typed_inner(&parse.tree(), offset, char_typed).map(|it| { 212 on_char_typed_inner(&parse, offset, char_typed).map(|it| {
153 it.apply(&mut before); 213 it.apply(&mut before);
154 before.to_string() 214 before.to_string()
155 }) 215 })
@@ -162,8 +222,8 @@ mod tests {
162 assert_eq_text!(ra_fixture_after, &actual); 222 assert_eq_text!(ra_fixture_after, &actual);
163 } 223 }
164 224
165 fn type_char_noop(char_typed: char, before: &str) { 225 fn type_char_noop(char_typed: char, ra_fixture_before: &str) {
166 let file_change = do_type_char(char_typed, before); 226 let file_change = do_type_char(char_typed, ra_fixture_before);
167 assert!(file_change.is_none()) 227 assert!(file_change.is_none())
168 } 228 }
169 229
@@ -180,16 +240,16 @@ mod tests {
180 // "); 240 // ");
181 type_char( 241 type_char(
182 '=', 242 '=',
183 r" 243 r#"
184fn foo() { 244fn foo() {
185 let foo $0 1 + 1 245 let foo $0 1 + 1
186} 246}
187", 247"#,
188 r" 248 r#"
189fn foo() { 249fn foo() {
190 let foo = 1 + 1; 250 let foo = 1 + 1;
191} 251}
192", 252"#,
193 ); 253 );
194 // do_check(r" 254 // do_check(r"
195 // fn foo() { 255 // fn foo() {
@@ -208,27 +268,27 @@ fn foo() {
208 fn indents_new_chain_call() { 268 fn indents_new_chain_call() {
209 type_char( 269 type_char(
210 '.', 270 '.',
211 r" 271 r#"
212 fn main() { 272fn main() {
213 xs.foo() 273 xs.foo()
214 $0 274 $0
215 } 275}
216 ", 276 "#,
217 r" 277 r#"
218 fn main() { 278fn main() {
219 xs.foo() 279 xs.foo()
220 . 280 .
221 } 281}
222 ", 282 "#,
223 ); 283 );
224 type_char_noop( 284 type_char_noop(
225 '.', 285 '.',
226 r" 286 r#"
227 fn main() { 287fn main() {
228 xs.foo() 288 xs.foo()
229 $0 289 $0
230 } 290}
231 ", 291 "#,
232 ) 292 )
233 } 293 }
234 294
@@ -237,26 +297,26 @@ fn foo() {
237 type_char( 297 type_char(
238 '.', 298 '.',
239 r" 299 r"
240 fn main() { 300fn main() {
241 xs.foo() 301 xs.foo()
242 $0; 302 $0;
243 } 303}
244 ",
245 r"
246 fn main() {
247 xs.foo()
248 .;
249 }
250 ", 304 ",
305 r#"
306fn main() {
307 xs.foo()
308 .;
309}
310 "#,
251 ); 311 );
252 type_char_noop( 312 type_char_noop(
253 '.', 313 '.',
254 r" 314 r#"
255 fn main() { 315fn main() {
256 xs.foo() 316 xs.foo()
257 $0; 317 $0;
258 } 318}
259 ", 319 "#,
260 ) 320 )
261 } 321 }
262 322
@@ -285,30 +345,30 @@ fn main() {
285 fn indents_continued_chain_call() { 345 fn indents_continued_chain_call() {
286 type_char( 346 type_char(
287 '.', 347 '.',
288 r" 348 r#"
289 fn main() { 349fn main() {
290 xs.foo() 350 xs.foo()
291 .first() 351 .first()
292 $0 352 $0
293 } 353}
294 ", 354 "#,
295 r" 355 r#"
296 fn main() { 356fn main() {
297 xs.foo() 357 xs.foo()
298 .first() 358 .first()
299 . 359 .
300 } 360}
301 ", 361 "#,
302 ); 362 );
303 type_char_noop( 363 type_char_noop(
304 '.', 364 '.',
305 r" 365 r#"
306 fn main() { 366fn main() {
307 xs.foo() 367 xs.foo()
308 .first() 368 .first()
309 $0 369 $0
310 } 370}
311 ", 371 "#,
312 ); 372 );
313 } 373 }
314 374
@@ -316,33 +376,33 @@ fn main() {
316 fn indents_middle_of_chain_call() { 376 fn indents_middle_of_chain_call() {
317 type_char( 377 type_char(
318 '.', 378 '.',
319 r" 379 r#"
320 fn source_impl() { 380fn source_impl() {
321 let var = enum_defvariant_list().unwrap() 381 let var = enum_defvariant_list().unwrap()
322 $0 382 $0
323 .nth(92) 383 .nth(92)
324 .unwrap(); 384 .unwrap();
325 } 385}
326 ", 386 "#,
327 r" 387 r#"
328 fn source_impl() { 388fn source_impl() {
329 let var = enum_defvariant_list().unwrap() 389 let var = enum_defvariant_list().unwrap()
330 . 390 .
331 .nth(92) 391 .nth(92)
332 .unwrap(); 392 .unwrap();
333 } 393}
334 ", 394 "#,
335 ); 395 );
336 type_char_noop( 396 type_char_noop(
337 '.', 397 '.',
338 r" 398 r#"
339 fn source_impl() { 399fn source_impl() {
340 let var = enum_defvariant_list().unwrap() 400 let var = enum_defvariant_list().unwrap()
341 $0 401 $0
342 .nth(92) 402 .nth(92)
343 .unwrap(); 403 .unwrap();
344 } 404}
345 ", 405 "#,
346 ); 406 );
347 } 407 }
348 408
@@ -350,24 +410,113 @@ fn main() {
350 fn dont_indent_freestanding_dot() { 410 fn dont_indent_freestanding_dot() {
351 type_char_noop( 411 type_char_noop(
352 '.', 412 '.',
353 r" 413 r#"
354 fn main() { 414fn main() {
355 $0 415 $0
356 } 416}
357 ", 417 "#,
358 ); 418 );
359 type_char_noop( 419 type_char_noop(
360 '.', 420 '.',
361 r" 421 r#"
362 fn main() { 422fn main() {
363 $0 423$0
364 } 424}
365 ", 425 "#,
366 ); 426 );
367 } 427 }
368 428
369 #[test] 429 #[test]
370 fn adds_space_after_return_type() { 430 fn adds_space_after_return_type() {
371 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 );
372 } 521 }
373} 522}
diff --git a/crates/ide/src/typing/on_enter.rs b/crates/ide/src/typing/on_enter.rs
index 978c479de..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//
@@ -32,28 +35,48 @@ use text_edit::TextEdit;
32// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust" 35// "when": "editorTextFocus && !suggestWidgetVisible && editorLangId == rust"
33// } 36// }
34// ---- 37// ----
38//
39// image::https://user-images.githubusercontent.com/48062697/113065578-04c21800-91b1-11eb-82b8-22b8c481e645.gif[]
35pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> { 40pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<TextEdit> {
36 let parse = db.parse(position.file_id); 41 let parse = db.parse(position.file_id);
37 let file = parse.tree(); 42 let file = parse.tree();
38 let comment = file 43 let token = file.syntax().token_at_offset(position.offset).left_biased()?;
39 .syntax() 44
40 .token_at_offset(position.offset) 45 if let Some(comment) = ast::Comment::cast(token.clone()) {
41 .left_biased() 46 return on_enter_in_comment(&comment, &file, position.offset);
42 .and_then(ast::Comment::cast)?; 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}
43 61
62fn on_enter_in_comment(
63 comment: &ast::Comment,
64 file: &ast::SourceFile,
65 offset: TextSize,
66) -> Option<TextEdit> {
44 if comment.kind().shape.is_block() { 67 if comment.kind().shape.is_block() {
45 return None; 68 return None;
46 } 69 }
47 70
48 let prefix = comment.prefix(); 71 let prefix = comment.prefix();
49 let comment_range = comment.syntax().text_range(); 72 let comment_range = comment.syntax().text_range();
50 if position.offset < comment_range.start() + TextSize::of(prefix) { 73 if offset < comment_range.start() + TextSize::of(prefix) {
51 return None; 74 return None;
52 } 75 }
53 76
54 let mut remove_trailing_whitespace = false; 77 let mut remove_trailing_whitespace = false;
55 // Continuing single-line non-doc comments (like this one :) ) is annoying 78 // Continuing single-line non-doc comments (like this one :) ) is annoying
56 if prefix == "//" && comment_range.end() == position.offset { 79 if prefix == "//" && comment_range.end() == offset {
57 if comment.text().ends_with(' ') { 80 if comment.text().ends_with(' ') {
58 cov_mark::hit!(continues_end_of_line_comment_with_space); 81 cov_mark::hit!(continues_end_of_line_comment_with_space);
59 remove_trailing_whitespace = true; 82 remove_trailing_whitespace = true;
@@ -67,14 +90,42 @@ pub(crate) fn on_enter(db: &RootDatabase, position: FilePosition) -> Option<Text
67 let delete = if remove_trailing_whitespace { 90 let delete = if remove_trailing_whitespace {
68 let trimmed_len = comment.text().trim_end().len() as u32; 91 let trimmed_len = comment.text().trim_end().len() as u32;
69 let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len; 92 let trailing_whitespace_len = comment.text().len() as u32 - trimmed_len;
70 TextRange::new(position.offset - TextSize::from(trailing_whitespace_len), position.offset) 93 TextRange::new(offset - TextSize::from(trailing_whitespace_len), offset)
71 } else { 94 } else {
72 TextRange::empty(position.offset) 95 TextRange::empty(offset)
73 }; 96 };
74 let edit = TextEdit::replace(delete, inserted); 97 let edit = TextEdit::replace(delete, inserted);
75 Some(edit) 98 Some(edit)
76} 99}
77 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
78fn followed_by_comment(comment: &ast::Comment) -> bool { 129fn followed_by_comment(comment: &ast::Comment) -> bool {
79 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) {
80 Some(it) => it, 131 Some(it) => it,
@@ -185,6 +236,25 @@ fn foo() {
185 } 236 }
186 237
187 #[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]
188 fn continues_code_comment_in_the_middle_of_line() { 258 fn continues_code_comment_in_the_middle_of_line() {
189 do_check( 259 do_check(
190 r" 260 r"
@@ -274,4 +344,144 @@ fn main() {
274", 344",
275 ); 345 );
276 } 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 }
277} 487}
diff --git a/crates/ide/src/view_hir.rs b/crates/ide/src/view_hir.rs
index f8f3fae3d..7312afe53 100644
--- a/crates/ide/src/view_hir.rs
+++ b/crates/ide/src/view_hir.rs
@@ -10,6 +10,7 @@ use syntax::{algo::find_node_at_offset, ast, AstNode};
10// 10//
11// | VS Code | **Rust Analyzer: View Hir** 11// | VS Code | **Rust Analyzer: View Hir**
12// |=== 12// |===
13// image::https://user-images.githubusercontent.com/48062697/113065588-068bdb80-91b1-11eb-9a78-0b4ef1e972fb.gif[]
13pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String { 14pub(crate) fn view_hir(db: &RootDatabase, position: FilePosition) -> String {
14 body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string()) 15 body_hir(db, position).unwrap_or_else(|| "Not inside a function body".to_string())
15} 16}
diff --git a/crates/ide_assists/src/assist_context.rs b/crates/ide_assists/src/assist_context.rs
index 1482d37f8..8714e4978 100644
--- a/crates/ide_assists/src/assist_context.rs
+++ b/crates/ide_assists/src/assist_context.rs
@@ -13,7 +13,7 @@ use ide_db::{
13 RootDatabase, 13 RootDatabase,
14}; 14};
15use syntax::{ 15use syntax::{
16 algo::{self, find_node_at_offset, SyntaxRewriter}, 16 algo::{self, find_node_at_offset, find_node_at_range, SyntaxRewriter},
17 AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr, 17 AstNode, AstToken, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
18 SyntaxToken, TextRange, TextSize, TokenAtOffset, 18 SyntaxToken, TextRange, TextSize, TokenAtOffset,
19}; 19};
@@ -89,6 +89,9 @@ impl<'a> AssistContext<'a> {
89 pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> { 89 pub(crate) fn find_node_at_offset<N: AstNode>(&self) -> Option<N> {
90 find_node_at_offset(self.source_file.syntax(), self.offset()) 90 find_node_at_offset(self.source_file.syntax(), self.offset())
91 } 91 }
92 pub(crate) fn find_node_at_range<N: AstNode>(&self) -> Option<N> {
93 find_node_at_range(self.source_file.syntax(), self.frange.range)
94 }
92 pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> { 95 pub(crate) fn find_node_at_offset_with_descend<N: AstNode>(&self) -> Option<N> {
93 self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset()) 96 self.sema.find_node_at_offset_with_descend(self.source_file.syntax(), self.offset())
94 } 97 }
diff --git a/crates/ide_assists/src/handlers/auto_import.rs b/crates/ide_assists/src/handlers/auto_import.rs
index 7019039b9..5ccd7f7a2 100644
--- a/crates/ide_assists/src/handlers/auto_import.rs
+++ b/crates/ide_assists/src/handlers/auto_import.rs
@@ -61,6 +61,8 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
61// - `plain`: This setting does not impose any restrictions in imports. 61// - `plain`: This setting does not impose any restrictions in imports.
62// 62//
63// In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`. 63// In `VS Code` the configuration for this is `rust-analyzer.assist.importPrefix`.
64//
65// image::https://user-images.githubusercontent.com/48062697/113020673-b85be580-917a-11eb-9022-59585f35d4f8.gif[]
64 66
65// Assist: auto_import 67// Assist: auto_import
66// 68//
diff --git a/crates/ide_assists/src/handlers/convert_into_to_from.rs b/crates/ide_assists/src/handlers/convert_into_to_from.rs
new file mode 100644
index 000000000..199e1ad5c
--- /dev/null
+++ b/crates/ide_assists/src/handlers/convert_into_to_from.rs
@@ -0,0 +1,355 @@
1use ide_db::{
2 helpers::{mod_path_to_ast, FamousDefs},
3 traits::resolve_target_trait,
4};
5use syntax::ast::{self, AstNode, NameOwner};
6
7use crate::{AssistContext, AssistId, AssistKind, Assists};
8
9// Assist: convert_into_to_from
10//
11// Converts an Into impl to an equivalent From impl.
12//
13// ```
14// # //- /lib.rs crate:core
15// # pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } }
16// # //- /lib.rs crate:main deps:core
17// # use core::convert::Into;
18// impl $0Into<Thing> for usize {
19// fn into(self) -> Thing {
20// Thing {
21// b: self.to_string(),
22// a: self
23// }
24// }
25// }
26// ```
27// ->
28// ```
29// # use core::convert::Into;
30// impl From<usize> for Thing {
31// fn from(val: usize) -> Self {
32// Thing {
33// b: val.to_string(),
34// a: val
35// }
36// }
37// }
38// ```
39pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
40 let impl_ = ctx.find_node_at_offset::<ast::Impl>()?;
41 let src_type = impl_.self_ty()?;
42 let ast_trait = impl_.trait_()?;
43
44 let module = ctx.sema.scope(impl_.syntax()).module()?;
45
46 let trait_ = resolve_target_trait(&ctx.sema, &impl_)?;
47 if trait_ != FamousDefs(&ctx.sema, Some(module.krate())).core_convert_Into()? {
48 return None;
49 }
50
51 let src_type_path = {
52 let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?;
53 let src_type_def = match ctx.sema.resolve_path(&src_type_path) {
54 Some(hir::PathResolution::Def(module_def)) => module_def,
55 _ => return None,
56 };
57
58 mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
59 };
60
61 let dest_type = match &ast_trait {
62 ast::Type::PathType(path) => {
63 path.path()?.segment()?.generic_arg_list()?.generic_args().next()?
64 }
65 _ => return None,
66 };
67
68 let into_fn = impl_.assoc_item_list()?.assoc_items().find_map(|item| {
69 if let ast::AssocItem::Fn(f) = item {
70 if f.name()?.text() == "into" {
71 return Some(f);
72 }
73 };
74 None
75 })?;
76
77 let into_fn_name = into_fn.name()?;
78 let into_fn_params = into_fn.param_list()?;
79 let into_fn_return = into_fn.ret_type()?;
80
81 let selfs = into_fn
82 .body()?
83 .syntax()
84 .descendants()
85 .filter_map(ast::NameRef::cast)
86 .filter(|name| name.text() == "self" || name.text() == "Self");
87
88 acc.add(
89 AssistId("convert_into_to_from", AssistKind::RefactorRewrite),
90 "Convert Into to From",
91 impl_.syntax().text_range(),
92 |builder| {
93 builder.replace(src_type.syntax().text_range(), dest_type.to_string());
94 builder.replace(ast_trait.syntax().text_range(), format!("From<{}>", src_type));
95 builder.replace(into_fn_return.syntax().text_range(), "-> Self");
96 builder.replace(
97 into_fn_params.syntax().text_range(),
98 format!("(val: {})", src_type.to_string()),
99 );
100 builder.replace(into_fn_name.syntax().text_range(), "from");
101
102 for s in selfs {
103 match s.text().as_ref() {
104 "self" => builder.replace(s.syntax().text_range(), "val"),
105 "Self" => builder.replace(s.syntax().text_range(), src_type_path.to_string()),
106 _ => {}
107 }
108 }
109 },
110 )
111}
112
113#[cfg(test)]
114mod tests {
115 use super::*;
116
117 use crate::tests::check_assist;
118
119 #[test]
120 fn convert_into_to_from_converts_a_struct() {
121 check_convert_into_to_from(
122 r#"
123struct Thing {
124 a: String,
125 b: usize
126}
127
128impl $0core::convert::Into<Thing> for usize {
129 fn into(self) -> Thing {
130 Thing {
131 b: self.to_string(),
132 a: self
133 }
134 }
135}
136"#,
137 r#"
138struct Thing {
139 a: String,
140 b: usize
141}
142
143impl From<usize> for Thing {
144 fn from(val: usize) -> Self {
145 Thing {
146 b: val.to_string(),
147 a: val
148 }
149 }
150}
151"#,
152 )
153 }
154
155 #[test]
156 fn convert_into_to_from_converts_enums() {
157 check_convert_into_to_from(
158 r#"
159enum Thing {
160 Foo(String),
161 Bar(String)
162}
163
164impl $0core::convert::Into<String> for Thing {
165 fn into(self) -> String {
166 match self {
167 Self::Foo(s) => s,
168 Self::Bar(s) => s
169 }
170 }
171}
172"#,
173 r#"
174enum Thing {
175 Foo(String),
176 Bar(String)
177}
178
179impl From<Thing> for String {
180 fn from(val: Thing) -> Self {
181 match val {
182 Thing::Foo(s) => s,
183 Thing::Bar(s) => s
184 }
185 }
186}
187"#,
188 )
189 }
190
191 #[test]
192 fn convert_into_to_from_on_enum_with_lifetimes() {
193 check_convert_into_to_from(
194 r#"
195enum Thing<'a> {
196 Foo(&'a str),
197 Bar(&'a str)
198}
199
200impl<'a> $0core::convert::Into<&'a str> for Thing<'a> {
201 fn into(self) -> &'a str {
202 match self {
203 Self::Foo(s) => s,
204 Self::Bar(s) => s
205 }
206 }
207}
208"#,
209 r#"
210enum Thing<'a> {
211 Foo(&'a str),
212 Bar(&'a str)
213}
214
215impl<'a> From<Thing<'a>> for &'a str {
216 fn from(val: Thing<'a>) -> Self {
217 match val {
218 Thing::Foo(s) => s,
219 Thing::Bar(s) => s
220 }
221 }
222}
223"#,
224 )
225 }
226
227 #[test]
228 fn convert_into_to_from_works_on_references() {
229 check_convert_into_to_from(
230 r#"
231struct Thing(String);
232
233impl $0core::convert::Into<String> for &Thing {
234 fn into(self) -> Thing {
235 self.0.clone()
236 }
237}
238"#,
239 r#"
240struct Thing(String);
241
242impl From<&Thing> for String {
243 fn from(val: &Thing) -> Self {
244 val.0.clone()
245 }
246}
247"#,
248 )
249 }
250
251 #[test]
252 fn convert_into_to_from_works_on_qualified_structs() {
253 check_convert_into_to_from(
254 r#"
255mod things {
256 pub struct Thing(String);
257 pub struct BetterThing(String);
258}
259
260impl $0core::convert::Into<things::BetterThing> for &things::Thing {
261 fn into(self) -> Thing {
262 things::BetterThing(self.0.clone())
263 }
264}
265"#,
266 r#"
267mod things {
268 pub struct Thing(String);
269 pub struct BetterThing(String);
270}
271
272impl From<&things::Thing> for things::BetterThing {
273 fn from(val: &things::Thing) -> Self {
274 things::BetterThing(val.0.clone())
275 }
276}
277"#,
278 )
279 }
280
281 #[test]
282 fn convert_into_to_from_works_on_qualified_enums() {
283 check_convert_into_to_from(
284 r#"
285mod things {
286 pub enum Thing {
287 A(String)
288 }
289 pub struct BetterThing {
290 B(String)
291 }
292}
293
294impl $0core::convert::Into<things::BetterThing> for &things::Thing {
295 fn into(self) -> Thing {
296 match self {
297 Self::A(s) => things::BetterThing::B(s)
298 }
299 }
300}
301"#,
302 r#"
303mod things {
304 pub enum Thing {
305 A(String)
306 }
307 pub struct BetterThing {
308 B(String)
309 }
310}
311
312impl From<&things::Thing> for things::BetterThing {
313 fn from(val: &things::Thing) -> Self {
314 match val {
315 things::Thing::A(s) => things::BetterThing::B(s)
316 }
317 }
318}
319"#,
320 )
321 }
322
323 #[test]
324 fn convert_into_to_from_not_applicable_on_any_trait_named_into() {
325 check_assist_not_applicable(
326 r#"
327pub trait Into<T> {{
328 pub fn into(self) -> T;
329}}
330
331struct Thing {
332 a: String,
333}
334
335impl $0Into<Thing> for String {
336 fn into(self) -> Thing {
337 Thing {
338 a: self
339 }
340 }
341}
342"#,
343 );
344 }
345
346 fn check_convert_into_to_from(before: &str, after: &str) {
347 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
348 check_assist(convert_into_to_from, before, after);
349 }
350
351 fn check_assist_not_applicable(before: &str) {
352 let before = &format!("//- /main.rs crate:main deps:core{}{}", before, FamousDefs::FIXTURE);
353 crate::tests::check_assist_not_applicable(convert_into_to_from, before);
354 }
355}
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 5fdc8bf38..059414274 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:
@@ -707,10 +714,10 @@ fn has_exclusive_usages(ctx: &AssistContext, usages: &LocalUsages, body: &Functi
707 .any(|reference| reference_is_exclusive(reference, body, ctx)) 714 .any(|reference| reference_is_exclusive(reference, body, ctx))
708} 715}
709 716
710/// checks if this reference requires `&mut` access inside body 717/// checks if this reference requires `&mut` access inside node
711fn reference_is_exclusive( 718fn reference_is_exclusive(
712 reference: &FileReference, 719 reference: &FileReference,
713 body: &FunctionBody, 720 node: &dyn HasTokenAtOffset,
714 ctx: &AssistContext, 721 ctx: &AssistContext,
715) -> bool { 722) -> bool {
716 // we directly modify variable with set: `n = 0`, `n += 1` 723 // we directly modify variable with set: `n = 0`, `n += 1`
@@ -719,7 +726,7 @@ fn reference_is_exclusive(
719 } 726 }
720 727
721 // we take `&mut` reference to variable: `&mut v` 728 // we take `&mut` reference to variable: `&mut v`
722 let path = match path_element_of_reference(body, reference) { 729 let path = match path_element_of_reference(node, reference) {
723 Some(path) => path, 730 Some(path) => path,
724 None => return false, 731 None => return false,
725 }; 732 };
@@ -729,6 +736,14 @@ fn reference_is_exclusive(
729 736
730/// checks if this expr requires `&mut` access, recurses on field access 737/// checks if this expr requires `&mut` access, recurses on field access
731fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> { 738fn expr_require_exclusive_access(ctx: &AssistContext, expr: &ast::Expr) -> Option<bool> {
739 match expr {
740 ast::Expr::MacroCall(_) => {
741 // FIXME: expand macro and check output for mutable usages of the variable?
742 return None;
743 }
744 _ => (),
745 }
746
732 let parent = expr.syntax().parent()?; 747 let parent = expr.syntax().parent()?;
733 748
734 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) { 749 if let Some(bin_expr) = ast::BinExpr::cast(parent.clone()) {
@@ -787,7 +802,7 @@ impl HasTokenAtOffset for SyntaxNode {
787 } 802 }
788} 803}
789 804
790/// find relevant `ast::PathExpr` for reference 805/// find relevant `ast::Expr` for reference
791/// 806///
792/// # Preconditions 807/// # Preconditions
793/// 808///
@@ -804,7 +819,11 @@ fn path_element_of_reference(
804 stdx::never!(false, "cannot find path parent of variable usage: {:?}", token); 819 stdx::never!(false, "cannot find path parent of variable usage: {:?}", token);
805 None 820 None
806 })?; 821 })?;
807 stdx::always!(matches!(path, ast::Expr::PathExpr(_))); 822 stdx::always!(
823 matches!(path, ast::Expr::PathExpr(_) | ast::Expr::MacroCall(_)),
824 "unexpected expression type for variable usage: {:?}",
825 path
826 );
808 Some(path) 827 Some(path)
809} 828}
810 829
@@ -820,10 +839,16 @@ fn vars_defined_in_body(body: &FunctionBody, ctx: &AssistContext) -> Vec<Local>
820} 839}
821 840
822/// list local variables defined inside `body` that should be returned from extracted function 841/// 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> { 842fn vars_defined_in_body_and_outlive(
824 let mut vars_defined_in_body = vars_defined_in_body(&body, ctx); 843 ctx: &AssistContext,
825 vars_defined_in_body.retain(|var| var_outlives_body(ctx, body, var)); 844 body: &FunctionBody,
845 parent: &SyntaxNode,
846) -> Vec<OutlivedLocal> {
847 let vars_defined_in_body = vars_defined_in_body(&body, ctx);
826 vars_defined_in_body 848 vars_defined_in_body
849 .into_iter()
850 .filter_map(|var| var_outlives_body(ctx, body, var, parent))
851 .collect()
827} 852}
828 853
829/// checks if the relevant local was defined before(outside of) body 854/// checks if the relevant local was defined before(outside of) body
@@ -843,11 +868,23 @@ fn either_syntax(value: &Either<ast::IdentPat, ast::SelfParam>) -> &SyntaxNode {
843 } 868 }
844} 869}
845 870
846/// checks if local variable is used after(outside of) body 871/// returns usage details if local variable is used after(outside of) body
847fn var_outlives_body(ctx: &AssistContext, body: &FunctionBody, var: &Local) -> bool { 872fn var_outlives_body(
848 let usages = LocalUsages::find(ctx, *var); 873 ctx: &AssistContext,
874 body: &FunctionBody,
875 var: Local,
876 parent: &SyntaxNode,
877) -> Option<OutlivedLocal> {
878 let usages = LocalUsages::find(ctx, var);
849 let has_usages = usages.iter().any(|reference| body.preceedes_range(reference.range)); 879 let has_usages = usages.iter().any(|reference| body.preceedes_range(reference.range));
850 has_usages 880 if !has_usages {
881 return None;
882 }
883 let has_mut_usages = usages
884 .iter()
885 .filter(|reference| body.preceedes_range(reference.range))
886 .any(|reference| reference_is_exclusive(reference, parent, ctx));
887 Some(OutlivedLocal { local: var, mut_usage_outside_body: has_mut_usages })
851} 888}
852 889
853fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option<RetType> { 890fn body_return_ty(ctx: &AssistContext, body: &FunctionBody) -> Option<RetType> {
@@ -927,16 +964,25 @@ fn format_replacement(ctx: &AssistContext, fun: &Function, indent: IndentLevel)
927 let mut buf = String::new(); 964 let mut buf = String::new();
928 match fun.vars_defined_in_body_and_outlive.as_slice() { 965 match fun.vars_defined_in_body_and_outlive.as_slice() {
929 [] => {} 966 [] => {}
930 [var] => format_to!(buf, "let {} = ", var.name(ctx.db()).unwrap()), 967 [var] => {
968 format_to!(buf, "let {}{} = ", mut_modifier(var), var.local.name(ctx.db()).unwrap())
969 }
931 [v0, vs @ ..] => { 970 [v0, vs @ ..] => {
932 buf.push_str("let ("); 971 buf.push_str("let (");
933 format_to!(buf, "{}", v0.name(ctx.db()).unwrap()); 972 format_to!(buf, "{}{}", mut_modifier(v0), v0.local.name(ctx.db()).unwrap());
934 for var in vs { 973 for var in vs {
935 format_to!(buf, ", {}", var.name(ctx.db()).unwrap()); 974 format_to!(buf, ", {}{}", mut_modifier(var), var.local.name(ctx.db()).unwrap());
936 } 975 }
937 buf.push_str(") = "); 976 buf.push_str(") = ");
938 } 977 }
939 } 978 }
979 fn mut_modifier(var: &OutlivedLocal) -> &'static str {
980 if var.mut_usage_outside_body {
981 "mut "
982 } else {
983 ""
984 }
985 }
940 format_to!(buf, "{}", expr); 986 format_to!(buf, "{}", expr);
941 if fun.ret_ty.is_unit() 987 if fun.ret_ty.is_unit()
942 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like()) 988 && (!fun.vars_defined_in_body_and_outlive.is_empty() || !expr.is_block_like())
@@ -1199,10 +1245,10 @@ fn make_body(
1199 match fun.vars_defined_in_body_and_outlive.as_slice() { 1245 match fun.vars_defined_in_body_and_outlive.as_slice() {
1200 [] => {} 1246 [] => {}
1201 [var] => { 1247 [var] => {
1202 tail_expr = Some(path_expr_from_local(ctx, *var)); 1248 tail_expr = Some(path_expr_from_local(ctx, var.local));
1203 } 1249 }
1204 vars => { 1250 vars => {
1205 let exprs = vars.iter().map(|var| path_expr_from_local(ctx, *var)); 1251 let exprs = vars.iter().map(|var| path_expr_from_local(ctx, var.local));
1206 let expr = make::expr_tuple(exprs); 1252 let expr = make::expr_tuple(exprs);
1207 tail_expr = Some(expr); 1253 tail_expr = Some(expr);
1208 } 1254 }
@@ -2111,6 +2157,30 @@ fn $0fun_name(n: i32) -> i32 {
2111 } 2157 }
2112 2158
2113 #[test] 2159 #[test]
2160 fn variable_defined_inside_and_used_after_mutably_no_ret() {
2161 check_assist(
2162 extract_function,
2163 r"
2164fn foo() {
2165 let n = 1;
2166 $0let mut k = n * n;$0
2167 k += 1;
2168}",
2169 r"
2170fn foo() {
2171 let n = 1;
2172 let mut k = fun_name(n);
2173 k += 1;
2174}
2175
2176fn $0fun_name(n: i32) -> i32 {
2177 let mut k = n * n;
2178 k
2179}",
2180 );
2181 }
2182
2183 #[test]
2114 fn two_variables_defined_inside_and_used_after_no_ret() { 2184 fn two_variables_defined_inside_and_used_after_no_ret() {
2115 check_assist( 2185 check_assist(
2116 extract_function, 2186 extract_function,
@@ -2137,6 +2207,38 @@ fn $0fun_name(n: i32) -> (i32, i32) {
2137 } 2207 }
2138 2208
2139 #[test] 2209 #[test]
2210 fn multi_variables_defined_inside_and_used_after_mutably_no_ret() {
2211 check_assist(
2212 extract_function,
2213 r"
2214fn foo() {
2215 let n = 1;
2216 $0let mut k = n * n;
2217 let mut m = k + 2;
2218 let mut o = m + 3;
2219 o += 1;$0
2220 k += o;
2221 m = 1;
2222}",
2223 r"
2224fn foo() {
2225 let n = 1;
2226 let (mut k, mut m, o) = fun_name(n);
2227 k += o;
2228 m = 1;
2229}
2230
2231fn $0fun_name(n: i32) -> (i32, i32, i32) {
2232 let mut k = n * n;
2233 let mut m = k + 2;
2234 let mut o = m + 3;
2235 o += 1;
2236 (k, m, o)
2237}",
2238 );
2239 }
2240
2241 #[test]
2140 fn nontrivial_patterns_define_variables() { 2242 fn nontrivial_patterns_define_variables() {
2141 check_assist( 2243 check_assist(
2142 extract_function, 2244 extract_function,
@@ -3372,4 +3474,36 @@ fn foo() -> Result<(), i64> {
3372}"##, 3474}"##,
3373 ); 3475 );
3374 } 3476 }
3477
3478 #[test]
3479 fn param_usage_in_macro() {
3480 check_assist(
3481 extract_function,
3482 r"
3483macro_rules! m {
3484 ($val:expr) => { $val };
3485}
3486
3487fn foo() {
3488 let n = 1;
3489 $0let k = n * m!(n);$0
3490 let m = k + 1;
3491}",
3492 r"
3493macro_rules! m {
3494 ($val:expr) => { $val };
3495}
3496
3497fn foo() {
3498 let n = 1;
3499 let k = fun_name(n);
3500 let m = k + 1;
3501}
3502
3503fn $0fun_name(n: i32) -> i32 {
3504 let k = n * m!(n);
3505 k
3506}",
3507 );
3508 }
3375} 3509}
diff --git a/crates/ide_assists/src/handlers/extract_type_alias.rs b/crates/ide_assists/src/handlers/extract_type_alias.rs
new file mode 100644
index 000000000..442a209b9
--- /dev/null
+++ b/crates/ide_assists/src/handlers/extract_type_alias.rs
@@ -0,0 +1,149 @@
1use syntax::ast::{self, AstNode};
2
3use crate::{AssistContext, AssistId, AssistKind, Assists};
4
5// Assist: extract_type_alias
6//
7// Extracts the selected type as a type alias.
8//
9// ```
10// struct S {
11// field: $0(u8, u8, u8)$0,
12// }
13// ```
14// ->
15// ```
16// type $0Type = (u8, u8, u8);
17//
18// struct S {
19// field: Type,
20// }
21// ```
22pub(crate) fn extract_type_alias(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
23 if ctx.frange.range.is_empty() {
24 return None;
25 }
26
27 let node = ctx.find_node_at_range::<ast::Type>()?;
28 let insert = ctx.find_node_at_offset::<ast::Item>()?.syntax().text_range().start();
29 let target = node.syntax().text_range();
30
31 acc.add(
32 AssistId("extract_type_alias", AssistKind::RefactorExtract),
33 "Extract type as type alias",
34 target,
35 |builder| {
36 builder.edit_file(ctx.frange.file_id);
37 builder.replace(target, "Type");
38 match ctx.config.snippet_cap {
39 Some(cap) => {
40 builder.insert_snippet(cap, insert, format!("type $0Type = {};\n\n", node));
41 }
42 None => {
43 builder.insert(insert, format!("type Type = {};\n\n", node));
44 }
45 }
46 },
47 )
48}
49
50#[cfg(test)]
51mod tests {
52 use crate::tests::{check_assist, check_assist_not_applicable};
53
54 use super::*;
55
56 #[test]
57 fn test_not_applicable_without_selection() {
58 check_assist_not_applicable(
59 extract_type_alias,
60 r"
61struct S {
62 field: $0(u8, u8, u8),
63}
64 ",
65 );
66 }
67
68 #[test]
69 fn test_simple_types() {
70 check_assist(
71 extract_type_alias,
72 r"
73struct S {
74 field: $0u8$0,
75}
76 ",
77 r#"
78type $0Type = u8;
79
80struct S {
81 field: Type,
82}
83 "#,
84 );
85 }
86
87 #[test]
88 fn test_generic_type_arg() {
89 check_assist(
90 extract_type_alias,
91 r"
92fn generic<T>() {}
93
94fn f() {
95 generic::<$0()$0>();
96}
97 ",
98 r#"
99fn generic<T>() {}
100
101type $0Type = ();
102
103fn f() {
104 generic::<Type>();
105}
106 "#,
107 );
108 }
109
110 #[test]
111 fn test_inner_type_arg() {
112 check_assist(
113 extract_type_alias,
114 r"
115struct Vec<T> {}
116struct S {
117 v: Vec<Vec<$0Vec<u8>$0>>,
118}
119 ",
120 r#"
121struct Vec<T> {}
122type $0Type = Vec<u8>;
123
124struct S {
125 v: Vec<Vec<Type>>,
126}
127 "#,
128 );
129 }
130
131 #[test]
132 fn test_extract_inner_type() {
133 check_assist(
134 extract_type_alias,
135 r"
136struct S {
137 field: ($0u8$0,),
138}
139 ",
140 r#"
141type $0Type = u8;
142
143struct S {
144 field: (Type,),
145}
146 "#,
147 );
148 }
149}
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..80bd1b7e8 100644
--- a/crates/ide_assists/src/handlers/fill_match_arms.rs
+++ b/crates/ide_assists/src/handlers/fill_match_arms.rs
@@ -71,12 +71,6 @@ pub(crate) fn fill_match_arms(acc: &mut Assists, ctx: &AssistContext) -> Option<
71 return None; 71 return None;
72 } 72 }
73 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 74 // When calculating the match arms for a tuple of enums, we want
81 // to create a match arm for each possible combination of enum 75 // to create a match arm for each possible combination of enum
82 // values. The `multi_cartesian_product` method transforms 76 // values. The `multi_cartesian_product` method transforms
@@ -514,10 +508,7 @@ fn main() {
514 508
515 #[test] 509 #[test]
516 fn fill_match_arms_single_element_tuple_of_enum() { 510 fn fill_match_arms_single_element_tuple_of_enum() {
517 // For now we don't hande the case of a single element tuple, but 511 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, 512 fill_match_arms,
522 r#" 513 r#"
523 enum A { One, Two } 514 enum A { One, Two }
@@ -528,6 +519,17 @@ fn main() {
528 } 519 }
529 } 520 }
530 "#, 521 "#,
522 r#"
523 enum A { One, Two }
524
525 fn main() {
526 let a = A::One;
527 match (a, ) {
528 $0(A::One,) => {}
529 (A::Two,) => {}
530 }
531 }
532 "#,
531 ); 533 );
532 } 534 }
533 535
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_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 81c54ba3e..dc14552d6 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -92,7 +92,7 @@ fn is_default_implemented(ctx: &AssistContext, impl_: &Impl) -> bool {
92 None => return false, 92 None => return false,
93 }; 93 };
94 94
95 let ty = impl_def.target_ty(db); 95 let ty = impl_def.self_ty(db);
96 let krate = impl_def.module(db).krate(); 96 let krate = impl_def.module(db).krate();
97 let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default(); 97 let default = FamousDefs(&ctx.sema, Some(krate)).core_default_Default();
98 let default_trait = match default { 98 let default_trait = match default {
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index b8834d283..910010a04 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -91,7 +91,7 @@ fn get_impl_method(
91 91
92 let scope = ctx.sema.scope(impl_.syntax()); 92 let scope = ctx.sema.scope(impl_.syntax());
93 let krate = impl_def.module(db).krate(); 93 let krate = impl_def.module(db).krate();
94 let ty = impl_def.target_ty(db); 94 let ty = impl_def.self_ty(db);
95 let traits_in_scope = scope.traits_in_scope(); 95 let traits_in_scope = scope.traits_in_scope();
96 ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func)) 96 ty.iterate_method_candidates(db, krate, &traits_in_scope, Some(fn_name), |_, func| Some(func))
97} 97}
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/lib.rs b/crates/ide_assists/src/lib.rs
index 8c068a6c0..3694f468f 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,
@@ -117,10 +119,12 @@ mod handlers {
117 mod convert_integer_literal; 119 mod convert_integer_literal;
118 mod convert_comment_block; 120 mod convert_comment_block;
119 mod convert_iter_for_each_to_for; 121 mod convert_iter_for_each_to_for;
122 mod convert_into_to_from;
120 mod early_return; 123 mod early_return;
121 mod expand_glob_import; 124 mod expand_glob_import;
122 mod extract_function; 125 mod extract_function;
123 mod extract_struct_from_enum_variant; 126 mod extract_struct_from_enum_variant;
127 mod extract_type_alias;
124 mod extract_variable; 128 mod extract_variable;
125 mod fill_match_arms; 129 mod fill_match_arms;
126 mod fix_visibility; 130 mod fix_visibility;
@@ -184,9 +188,11 @@ mod handlers {
184 convert_integer_literal::convert_integer_literal, 188 convert_integer_literal::convert_integer_literal,
185 convert_comment_block::convert_comment_block, 189 convert_comment_block::convert_comment_block,
186 convert_iter_for_each_to_for::convert_iter_for_each_to_for, 190 convert_iter_for_each_to_for::convert_iter_for_each_to_for,
191 convert_into_to_from::convert_into_to_from,
187 early_return::convert_to_guarded_return, 192 early_return::convert_to_guarded_return,
188 expand_glob_import::expand_glob_import, 193 expand_glob_import::expand_glob_import,
189 extract_struct_from_enum_variant::extract_struct_from_enum_variant, 194 extract_struct_from_enum_variant::extract_struct_from_enum_variant,
195 extract_type_alias::extract_type_alias,
190 fill_match_arms::fill_match_arms, 196 fill_match_arms::fill_match_arms,
191 fix_visibility::fix_visibility, 197 fix_visibility::fix_visibility,
192 flip_binexpr::flip_binexpr, 198 flip_binexpr::flip_binexpr,
diff --git a/crates/ide_assists/src/tests.rs b/crates/ide_assists/src/tests.rs
index a7a923beb..60e3a1474 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;
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index 736027ff0..27a22ca10 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -206,6 +206,38 @@ const _: i32 = 0b1010;
206} 206}
207 207
208#[test] 208#[test]
209fn doctest_convert_into_to_from() {
210 check_doc_test(
211 "convert_into_to_from",
212 r#####"
213//- /lib.rs crate:core
214pub mod convert { pub trait Into<T> { pub fn into(self) -> T; } }
215//- /lib.rs crate:main deps:core
216use core::convert::Into;
217impl $0Into<Thing> for usize {
218 fn into(self) -> Thing {
219 Thing {
220 b: self.to_string(),
221 a: self
222 }
223 }
224}
225"#####,
226 r#####"
227use core::convert::Into;
228impl From<usize> for Thing {
229 fn from(val: usize) -> Self {
230 Thing {
231 b: val.to_string(),
232 a: val
233 }
234 }
235}
236"#####,
237 )
238}
239
240#[test]
209fn doctest_convert_iter_for_each_to_for() { 241fn doctest_convert_iter_for_each_to_for() {
210 check_doc_test( 242 check_doc_test(
211 "convert_iter_for_each_to_for", 243 "convert_iter_for_each_to_for",
@@ -329,6 +361,25 @@ enum A { One(One) }
329} 361}
330 362
331#[test] 363#[test]
364fn doctest_extract_type_alias() {
365 check_doc_test(
366 "extract_type_alias",
367 r#####"
368struct S {
369 field: $0(u8, u8, u8)$0,
370}
371"#####,
372 r#####"
373type $0Type = (u8, u8, u8);
374
375struct S {
376 field: Type,
377}
378"#####,
379 )
380}
381
382#[test]
332fn doctest_extract_variable() { 383fn doctest_extract_variable() {
333 check_doc_test( 384 check_doc_test(
334 "extract_variable", 385 "extract_variable",
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index 5f630ec75..d67524937 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -338,11 +338,11 @@ pub(crate) fn find_struct_impl(
338 // (we currently use the wrong type parameter) 338 // (we currently use the wrong type parameter)
339 // also we wouldn't want to use e.g. `impl S<u32>` 339 // also we wouldn't want to use e.g. `impl S<u32>`
340 340
341 let same_ty = match blk.target_ty(db).as_adt() { 341 let same_ty = match blk.self_ty(db).as_adt() {
342 Some(def) => def == struct_def, 342 Some(def) => def == struct_def,
343 None => false, 343 None => false,
344 }; 344 };
345 let not_trait_impl = blk.target_trait(db).is_none(); 345 let not_trait_impl = blk.trait_(db).is_none();
346 346
347 if !(same_ty && not_trait_impl) { 347 if !(same_ty && not_trait_impl) {
348 None 348 None
diff --git a/crates/ide_completion/src/completions.rs b/crates/ide_completion/src/completions.rs
index 6d572a836..e2994eed4 100644
--- a/crates/ide_completion/src/completions.rs
+++ b/crates/ide_completion/src/completions.rs
@@ -220,7 +220,7 @@ fn complete_enum_variants(
220 }; 220 };
221 221
222 if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) { 222 if let Some(impl_) = ctx.impl_def.as_ref().and_then(|impl_| ctx.sema.to_def(impl_)) {
223 if impl_.target_ty(ctx.db) == *ty { 223 if impl_.self_ty(ctx.db) == *ty {
224 for &variant in &variants { 224 for &variant in &variants {
225 let self_path = hir::ModPath::from_segments( 225 let self_path = hir::ModPath::from_segments(
226 hir::PathKind::Plain, 226 hir::PathKind::Plain,
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/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index b06498e6d..808d7ff7e 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -40,7 +40,7 @@ pub(crate) fn complete_pattern(acc: &mut Completions, ctx: &CompletionContext) {
40 _ => false, 40 _ => false,
41 }, 41 },
42 hir::ScopeDef::MacroDef(_) => true, 42 hir::ScopeDef::MacroDef(_) => true,
43 hir::ScopeDef::ImplSelfType(impl_) => match impl_.target_ty(ctx.db).as_adt() { 43 hir::ScopeDef::ImplSelfType(impl_) => match impl_.self_ty(ctx.db).as_adt() {
44 Some(hir::Adt::Struct(strukt)) => { 44 Some(hir::Adt::Struct(strukt)) => {
45 acc.add_struct_pat(ctx, strukt, Some(name.clone())); 45 acc.add_struct_pat(ctx, strukt, Some(name.clone()));
46 true 46 true
diff --git a/crates/ide_completion/src/completions/postfix/format_like.rs b/crates/ide_completion/src/completions/postfix/format_like.rs
index 3f1c6730b..e86ffa8f8 100644
--- a/crates/ide_completion/src/completions/postfix/format_like.rs
+++ b/crates/ide_completion/src/completions/postfix/format_like.rs
@@ -13,6 +13,8 @@
13// + `logi` -> `log::info!(...)` 13// + `logi` -> `log::info!(...)`
14// + `logw` -> `log::warn!(...)` 14// + `logw` -> `log::warn!(...)`
15// + `loge` -> `log::error!(...)` 15// + `loge` -> `log::error!(...)`
16//
17// image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
16 18
17use ide_db::helpers::SnippetCap; 19use ide_db::helpers::SnippetCap;
18use syntax::ast::{self, AstToken}; 20use syntax::ast::{self, AstToken};
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 105ff6013..969249df6 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -24,7 +24,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
24 }; 24 };
25 25
26 // Add associated types on type parameters and `Self`. 26 // Add associated types on type parameters and `Self`.
27 resolution.assoc_type_shorthand_candidates(ctx.db, |alias| { 27 resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
28 acc.add_type_alias(ctx, alias); 28 acc.add_type_alias(ctx, alias);
29 None::<()> 29 None::<()>
30 }); 30 });
@@ -117,7 +117,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
117 if let Some(krate) = ctx.krate { 117 if let Some(krate) = ctx.krate {
118 let ty = match resolution { 118 let ty = match resolution {
119 PathResolution::TypeParam(param) => param.ty(ctx.db), 119 PathResolution::TypeParam(param) => param.ty(ctx.db),
120 PathResolution::SelfType(impl_def) => impl_def.target_ty(ctx.db), 120 PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
121 _ => return, 121 _ => return,
122 }; 122 };
123 123
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 5ac1cb48d..6f3d5c5c5 100644
--- a/crates/ide_completion/src/lib.rs
+++ b/crates/ide_completion/src/lib.rs
@@ -81,6 +81,8 @@ pub use crate::{
81// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities. 81// And the auto import completions, enabled with the `rust-analyzer.completion.autoimport.enable` setting and the corresponding LSP client capabilities.
82// Those are the additional completion options with automatic `use` import and options from all project importable items, 82// Those are the additional completion options with automatic `use` import and options from all project importable items,
83// fuzzy matched agains the completion imput. 83// fuzzy matched agains the completion imput.
84//
85// image::https://user-images.githubusercontent.com/48062697/113020667-b72ab880-917a-11eb-8778-716cf26a0eb3.gif[]
84 86
85/// Main entry point for completion. We run completion as a two-phase process. 87/// Main entry point for completion. We run completion as a two-phase process.
86/// 88///
@@ -104,6 +106,34 @@ pub use crate::{
104/// `foo` *should* be present among the completion variants. Filtering by 106/// `foo` *should* be present among the completion variants. Filtering by
105/// 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
106/// 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.
107pub fn completions( 137pub fn completions(
108 db: &RootDatabase, 138 db: &RootDatabase,
109 config: &CompletionConfig, 139 config: &CompletionConfig,
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index 047a9b6bc..eac5ef6b9 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -101,6 +101,7 @@ impl RootDatabase {
101 // 101 //
102 // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)** 102 // | VS Code | **Rust Analyzer: Memory Usage (Clears Database)**
103 // |=== 103 // |===
104 // image::https://user-images.githubusercontent.com/48062697/113065592-08559f00-91b1-11eb-8c96-64b88068ec02.gif[]
104 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> { 105 pub fn per_query_memory_usage(&mut self) -> Vec<(String, Bytes)> {
105 let mut acc: Vec<(String, Bytes)> = vec![]; 106 let mut acc: Vec<(String, Bytes)> = vec![];
106 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions(); 107 let sweep = SweepStrategy::default().discard_values().sweep_all_revisions();
@@ -151,6 +152,10 @@ impl RootDatabase {
151 hir::db::FileItemTreeQuery 152 hir::db::FileItemTreeQuery
152 hir::db::BlockDefMapQuery 153 hir::db::BlockDefMapQuery
153 hir::db::CrateDefMapQueryQuery 154 hir::db::CrateDefMapQueryQuery
155 hir::db::FieldsAttrsQuery
156 hir::db::VariantsAttrsQuery
157 hir::db::FieldsAttrsSourceMapQuery
158 hir::db::VariantsAttrsSourceMapQuery
154 hir::db::StructDataQuery 159 hir::db::StructDataQuery
155 hir::db::UnionDataQuery 160 hir::db::UnionDataQuery
156 hir::db::EnumDataQuery 161 hir::db::EnumDataQuery
@@ -196,7 +201,7 @@ impl RootDatabase {
196 hir::db::InternImplTraitIdQuery 201 hir::db::InternImplTraitIdQuery
197 hir::db::InternClosureQuery 202 hir::db::InternClosureQuery
198 hir::db::AssociatedTyValueQuery 203 hir::db::AssociatedTyValueQuery
199 hir::db::TraitSolveQuery 204 hir::db::TraitSolveQueryQuery
200 205
201 // SymbolsDatabase 206 // SymbolsDatabase
202 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/defs.rs b/crates/ide_db/src/defs.rs
index 0d9808d24..de0dc2a40 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -330,25 +330,30 @@ impl NameRefClass {
330 } 330 }
331 } 331 }
332 332
333 if ast::AssocTypeArg::cast(parent.clone()).is_some() { 333 if let Some(assoc_type_arg) = ast::AssocTypeArg::cast(parent.clone()) {
334 // `Trait<Assoc = Ty>` 334 if assoc_type_arg.name_ref().as_ref() == Some(name_ref) {
335 // ^^^^^ 335 // `Trait<Assoc = Ty>`
336 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?; 336 // ^^^^^
337 let resolved = sema.resolve_path(&path)?; 337 let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
338 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved { 338 let resolved = sema.resolve_path(&path)?;
339 if let Some(ty) = tr 339 if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
340 .items(sema.db) 340 // FIXME: resolve in supertraits
341 .iter() 341 if let Some(ty) = tr
342 .filter_map(|assoc| match assoc { 342 .items(sema.db)
343 hir::AssocItem::TypeAlias(it) => Some(*it), 343 .iter()
344 _ => None, 344 .filter_map(|assoc| match assoc {
345 }) 345 hir::AssocItem::TypeAlias(it) => Some(*it),
346 .find(|alias| &alias.name(sema.db).to_string() == &name_ref.text()) 346 _ => None,
347 { 347 })
348 return Some(NameRefClass::Definition(Definition::ModuleDef( 348 .find(|alias| &alias.name(sema.db).to_string() == &name_ref.text())
349 ModuleDef::TypeAlias(ty), 349 {
350 ))); 350 return Some(NameRefClass::Definition(Definition::ModuleDef(
351 ModuleDef::TypeAlias(ty),
352 )));
353 }
351 } 354 }
355
356 return None;
352 } 357 }
353 } 358 }
354 359
diff --git a/crates/ide_db/src/helpers.rs b/crates/ide_db/src/helpers.rs
index 9992a92bd..66798ea3a 100644
--- a/crates/ide_db/src/helpers.rs
+++ b/crates/ide_db/src/helpers.rs
@@ -93,6 +93,10 @@ impl FamousDefs<'_, '_> {
93 self.find_trait("core:convert:From") 93 self.find_trait("core:convert:From")
94 } 94 }
95 95
96 pub fn core_convert_Into(&self) -> Option<Trait> {
97 self.find_trait("core:convert:Into")
98 }
99
96 pub fn core_option_Option(&self) -> Option<Enum> { 100 pub fn core_option_Option(&self) -> Option<Enum> {
97 self.find_enum("core:option:Option") 101 self.find_enum("core:option:Option")
98 } 102 }
diff --git a/crates/ide_db/src/helpers/famous_defs_fixture.rs b/crates/ide_db/src/helpers/famous_defs_fixture.rs
index d3464ae17..4d79e064e 100644
--- a/crates/ide_db/src/helpers/famous_defs_fixture.rs
+++ b/crates/ide_db/src/helpers/famous_defs_fixture.rs
@@ -14,6 +14,10 @@ pub mod convert {
14 pub trait From<T> { 14 pub trait From<T> {
15 fn from(t: T) -> Self; 15 fn from(t: T) -> Self;
16 } 16 }
17
18 pub trait Into<T> {
19 pub fn into(self) -> T;
20 }
17} 21}
18 22
19pub mod default { 23pub mod default {
@@ -120,7 +124,7 @@ pub mod option {
120pub mod prelude { 124pub mod prelude {
121 pub use crate::{ 125 pub use crate::{
122 cmp::Ord, 126 cmp::Ord,
123 convert::From, 127 convert::{From, Into},
124 default::Default, 128 default::Default,
125 iter::{IntoIterator, Iterator}, 129 iter::{IntoIterator, Iterator},
126 ops::{Fn, FnMut, FnOnce}, 130 ops::{Fn, FnMut, FnOnce},
diff --git a/crates/ide_db/src/helpers/import_assets.rs b/crates/ide_db/src/helpers/import_assets.rs
index 3deb0d159..91d6a4665 100644
--- a/crates/ide_db/src/helpers/import_assets.rs
+++ b/crates/ide_db/src/helpers/import_assets.rs
@@ -361,7 +361,7 @@ fn item_for_path_search(db: &RootDatabase, item: ItemInNs) -> Option<ItemInNs> {
361 Some(assoc_item) => match assoc_item.container(db) { 361 Some(assoc_item) => match assoc_item.container(db) {
362 AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)), 362 AssocItemContainer::Trait(trait_) => ItemInNs::from(ModuleDef::from(trait_)),
363 AssocItemContainer::Impl(impl_) => { 363 AssocItemContainer::Impl(impl_) => {
364 ItemInNs::from(ModuleDef::from(impl_.target_ty(db).as_adt()?)) 364 ItemInNs::from(ModuleDef::from(impl_.self_ty(db).as_adt()?))
365 } 365 }
366 }, 366 },
367 None => item, 367 None => item,
@@ -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/mbe/src/benchmark.rs b/crates/mbe/src/benchmark.rs
index ba814a2e1..38707ffa5 100644
--- a/crates/mbe/src/benchmark.rs
+++ b/crates/mbe/src/benchmark.rs
@@ -65,7 +65,7 @@ fn macro_rules_fixtures_tt() -> FxHashMap<String, tt::Subtree> {
65 .filter_map(ast::MacroRules::cast) 65 .filter_map(ast::MacroRules::cast)
66 .map(|rule| { 66 .map(|rule| {
67 let id = rule.name().unwrap().to_string(); 67 let id = rule.name().unwrap().to_string();
68 let (def_tt, _) = ast_to_token_tree(&rule.token_tree().unwrap()).unwrap(); 68 let (def_tt, _) = ast_to_token_tree(&rule.token_tree().unwrap());
69 (id, def_tt) 69 (id, def_tt)
70 }) 70 })
71 .collect() 71 .collect()
diff --git a/crates/mbe/src/expander.rs b/crates/mbe/src/expander.rs
index 3197c834c..bfef7f73d 100644
--- a/crates/mbe/src/expander.rs
+++ b/crates/mbe/src/expander.rs
@@ -159,8 +159,7 @@ mod tests {
159 let macro_definition = 159 let macro_definition =
160 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); 160 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
161 161
162 let (definition_tt, _) = 162 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap());
163 ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap();
164 crate::MacroRules::parse(&definition_tt).unwrap() 163 crate::MacroRules::parse(&definition_tt).unwrap()
165 } 164 }
166 165
@@ -169,8 +168,7 @@ mod tests {
169 let macro_invocation = 168 let macro_invocation =
170 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 169 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
171 170
172 let (invocation_tt, _) = 171 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap());
173 ast_to_token_tree(&macro_invocation.token_tree().unwrap()).unwrap();
174 172
175 expand_rules(&rules.rules, &invocation_tt) 173 expand_rules(&rules.rules, &invocation_tt)
176 } 174 }
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index e74f8cf3f..3af5bc18b 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -220,9 +220,11 @@ impl MacroDef {
220 while src.len() > 0 { 220 while src.len() > 0 {
221 let rule = Rule::parse(&mut src, true)?; 221 let rule = Rule::parse(&mut src, true)?;
222 rules.push(rule); 222 rules.push(rule);
223 if let Err(()) = src.expect_char(';') { 223 if let Err(()) = src.expect_any_char(&[';', ',']) {
224 if src.len() > 0 { 224 if src.len() > 0 {
225 return Err(ParseError::Expected("expected `;`".to_string())); 225 return Err(ParseError::Expected(
226 "expected `;` or `,` to delimit rules".to_string(),
227 ));
226 } 228 }
227 break; 229 break;
228 } 230 }
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index cfab99da8..a7c8c13c6 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -43,18 +43,18 @@ pub struct TokenMap {
43 43
44/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro 44/// Convert the syntax tree (what user has written) to a `TokenTree` (what macro
45/// will consume). 45/// will consume).
46pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> Option<(tt::Subtree, TokenMap)> { 46pub fn ast_to_token_tree(ast: &impl ast::AstNode) -> (tt::Subtree, TokenMap) {
47 syntax_node_to_token_tree(ast.syntax()) 47 syntax_node_to_token_tree(ast.syntax())
48} 48}
49 49
50/// Convert the syntax node to a `TokenTree` (what macro 50/// Convert the syntax node to a `TokenTree` (what macro
51/// will consume). 51/// will consume).
52pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> Option<(tt::Subtree, TokenMap)> { 52pub fn syntax_node_to_token_tree(node: &SyntaxNode) -> (tt::Subtree, TokenMap) {
53 let global_offset = node.text_range().start(); 53 let global_offset = node.text_range().start();
54 let mut c = Convertor::new(node, global_offset); 54 let mut c = Convertor::new(node, global_offset);
55 let subtree = c.go()?; 55 let subtree = c.go();
56 c.id_alloc.map.entries.shrink_to_fit(); 56 c.id_alloc.map.entries.shrink_to_fit();
57 Some((subtree, c.id_alloc.map)) 57 (subtree, c.id_alloc.map)
58} 58}
59 59
60// The following items are what `rustc` macro can be parsed into : 60// The following items are what `rustc` macro can be parsed into :
@@ -108,7 +108,7 @@ pub fn parse_to_token_tree(text: &str) -> Option<(tt::Subtree, TokenMap)> {
108 }, 108 },
109 }; 109 };
110 110
111 let subtree = conv.go()?; 111 let subtree = conv.go();
112 Some((subtree, conv.id_alloc.map)) 112 Some((subtree, conv.id_alloc.map))
113} 113}
114 114
@@ -319,21 +319,18 @@ trait SrcToken: std::fmt::Debug {
319trait TokenConvertor { 319trait TokenConvertor {
320 type Token: SrcToken; 320 type Token: SrcToken;
321 321
322 fn go(&mut self) -> Option<tt::Subtree> { 322 fn go(&mut self) -> tt::Subtree {
323 let mut subtree = tt::Subtree::default(); 323 let mut subtree = tt::Subtree::default();
324 subtree.delimiter = None; 324 subtree.delimiter = None;
325 while self.peek().is_some() { 325 while self.peek().is_some() {
326 self.collect_leaf(&mut subtree.token_trees); 326 self.collect_leaf(&mut subtree.token_trees);
327 } 327 }
328 if subtree.token_trees.is_empty() {
329 return None;
330 }
331 if subtree.token_trees.len() == 1 { 328 if subtree.token_trees.len() == 1 {
332 if let tt::TokenTree::Subtree(first) = &subtree.token_trees[0] { 329 if let tt::TokenTree::Subtree(first) = &subtree.token_trees[0] {
333 return Some(first.clone()); 330 return first.clone();
334 } 331 }
335 } 332 }
336 Some(subtree) 333 subtree
337 } 334 }
338 335
339 fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) { 336 fn collect_leaf(&mut self, result: &mut Vec<tt::TokenTree>) {
@@ -861,7 +858,7 @@ mod tests {
861 // - T!['}'] 858 // - T!['}']
862 // - WHITE_SPACE 859 // - WHITE_SPACE
863 let token_tree = ast::TokenTree::cast(token_tree).unwrap(); 860 let token_tree = ast::TokenTree::cast(token_tree).unwrap();
864 let tt = ast_to_token_tree(&token_tree).unwrap().0; 861 let tt = ast_to_token_tree(&token_tree).0;
865 862
866 assert_eq!(tt.delimiter_kind(), Some(tt::DelimiterKind::Brace)); 863 assert_eq!(tt.delimiter_kind(), Some(tt::DelimiterKind::Brace));
867 } 864 }
@@ -870,7 +867,7 @@ mod tests {
870 fn test_token_tree_multi_char_punct() { 867 fn test_token_tree_multi_char_punct() {
871 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap(); 868 let source_file = ast::SourceFile::parse("struct Foo { a: x::Y }").ok().unwrap();
872 let struct_def = source_file.syntax().descendants().find_map(ast::Struct::cast).unwrap(); 869 let struct_def = source_file.syntax().descendants().find_map(ast::Struct::cast).unwrap();
873 let tt = ast_to_token_tree(&struct_def).unwrap().0; 870 let tt = ast_to_token_tree(&struct_def).0;
874 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap(); 871 token_tree_to_syntax_node(&tt, FragmentKind::Item).unwrap();
875 } 872 }
876} 873}
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs
index 6da18ecf4..3698ff3f0 100644
--- a/crates/mbe/src/tests.rs
+++ b/crates/mbe/src/tests.rs
@@ -29,8 +29,7 @@ macro_rules! impl_fixture {
29 let macro_invocation = 29 let macro_invocation =
30 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); 30 source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap();
31 31
32 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap()) 32 let (invocation_tt, _) = ast_to_token_tree(&macro_invocation.token_tree().unwrap());
33 .ok_or_else(|| ExpandError::ConversionError)?;
34 33
35 self.rules.expand(&invocation_tt).result() 34 self.rules.expand(&invocation_tt).result()
36 } 35 }
@@ -101,7 +100,7 @@ macro_rules! impl_fixture {
101 .descendants() 100 .descendants()
102 .find_map(ast::TokenTree::cast) 101 .find_map(ast::TokenTree::cast)
103 .unwrap(); 102 .unwrap();
104 let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; 103 let mut wrapped = ast_to_token_tree(&wrapped).0;
105 wrapped.delimiter = None; 104 wrapped.delimiter = None;
106 wrapped 105 wrapped
107 }; 106 };
@@ -151,7 +150,7 @@ pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError {
151 150
152pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree { 151pub(crate) fn parse_to_token_tree_by_syntax(ra_fixture: &str) -> tt::Subtree {
153 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); 152 let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap();
154 let tt = syntax_node_to_token_tree(source_file.syntax()).unwrap().0; 153 let tt = syntax_node_to_token_tree(source_file.syntax()).0;
155 154
156 let parsed = parse_to_token_tree(ra_fixture).unwrap().0; 155 let parsed = parse_to_token_tree(ra_fixture).unwrap().0;
157 assert_eq!(tt, parsed); 156 assert_eq!(tt, parsed);
@@ -164,7 +163,7 @@ fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree {
164 let macro_definition = 163 let macro_definition =
165 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); 164 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
166 165
167 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 166 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap());
168 167
169 let parsed = parse_to_token_tree( 168 let parsed = parse_to_token_tree(
170 &ra_fixture[macro_definition.token_tree().unwrap().syntax().text_range()], 169 &ra_fixture[macro_definition.token_tree().unwrap().syntax().text_range()],
@@ -181,7 +180,7 @@ fn parse_macro_def_to_tt(ra_fixture: &str) -> tt::Subtree {
181 let macro_definition = 180 let macro_definition =
182 source_file.syntax().descendants().find_map(ast::MacroDef::cast).unwrap(); 181 source_file.syntax().descendants().find_map(ast::MacroDef::cast).unwrap();
183 182
184 let (definition_tt, _) = ast_to_token_tree(&macro_definition.body().unwrap()).unwrap(); 183 let (definition_tt, _) = ast_to_token_tree(&macro_definition.body().unwrap());
185 184
186 let parsed = 185 let parsed =
187 parse_to_token_tree(&ra_fixture[macro_definition.body().unwrap().syntax().text_range()]) 186 parse_to_token_tree(&ra_fixture[macro_definition.body().unwrap().syntax().text_range()])
diff --git a/crates/mbe/src/tests/expand.rs b/crates/mbe/src/tests/expand.rs
index 84f19d3e2..3a1d840ea 100644
--- a/crates/mbe/src/tests/expand.rs
+++ b/crates/mbe/src/tests/expand.rs
@@ -663,6 +663,21 @@ macro foo {
663} 663}
664 664
665#[test] 665#[test]
666fn test_macro_2_0_panic_2015() {
667 parse_macro2(
668 r#"
669macro panic_2015 {
670 () => (
671 ),
672 (bar) => (
673 ),
674}
675"#,
676 )
677 .assert_expand_items("panic_2015!(bar);", "");
678}
679
680#[test]
666fn test_path() { 681fn test_path() {
667 parse_macro( 682 parse_macro(
668 r#" 683 r#"
@@ -926,6 +941,24 @@ fn test_meta_doc_comments() {
926} 941}
927 942
928#[test] 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 () {}"#,
958 );
959}
960
961#[test]
929fn test_meta_doc_comments_non_latin() { 962fn test_meta_doc_comments_non_latin() {
930 parse_macro( 963 parse_macro(
931 r#" 964 r#"
diff --git a/crates/mbe/src/tests/rule.rs b/crates/mbe/src/tests/rule.rs
index bf48112b3..5c61a98fd 100644
--- a/crates/mbe/src/tests/rule.rs
+++ b/crates/mbe/src/tests/rule.rs
@@ -44,6 +44,6 @@ fn parse_macro_arm(arm_definition: &str) -> Result<crate::MacroRules, ParseError
44 let macro_definition = 44 let macro_definition =
45 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); 45 source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap();
46 46
47 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap()).unwrap(); 47 let (definition_tt, _) = ast_to_token_tree(&macro_definition.token_tree().unwrap());
48 crate::MacroRules::parse(&definition_tt) 48 crate::MacroRules::parse(&definition_tt)
49} 49}
diff --git a/crates/mbe/src/tt_iter.rs b/crates/mbe/src/tt_iter.rs
index 319a40f2a..195b8cf30 100644
--- a/crates/mbe/src/tt_iter.rs
+++ b/crates/mbe/src/tt_iter.rs
@@ -34,6 +34,17 @@ impl<'a> TtIter<'a> {
34 } 34 }
35 } 35 }
36 36
37 pub(crate) fn expect_any_char(&mut self, chars: &[char]) -> Result<(), ()> {
38 match self.next() {
39 Some(tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: c, .. })))
40 if chars.contains(c) =>
41 {
42 Ok(())
43 }
44 _ => Err(()),
45 }
46 }
47
37 pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree, ()> { 48 pub(crate) fn expect_subtree(&mut self) -> Result<&'a tt::Subtree, ()> {
38 match self.next() { 49 match self.next() {
39 Some(tt::TokenTree::Subtree(it)) => Ok(it), 50 Some(tt::TokenTree::Subtree(it)) => Ok(it),
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/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_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index c147484c0..5d765f6e2 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -534,8 +534,12 @@ impl server::Literal for Rustc {
534 } 534 }
535 535
536 fn integer(&mut self, n: &str) -> Self::Literal { 536 fn integer(&mut self, n: &str) -> Self::Literal {
537 let n: i128 = n.parse().unwrap(); 537 let n = if let Ok(n) = n.parse::<i128>() {
538 Literal { text: n.to_string().into(), id: tt::TokenId::unspecified() } 538 n.to_string()
539 } else {
540 n.parse::<u128>().unwrap().to_string()
541 };
542 return Literal { text: n.into(), id: tt::TokenId::unspecified() };
539 } 543 }
540 544
541 fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal { 545 fn typed_integer(&mut self, n: &str, kind: &str) -> Self::Literal {
@@ -757,6 +761,17 @@ mod tests {
757 assert_eq!(srv.string("hello_world").text, "\"hello_world\""); 761 assert_eq!(srv.string("hello_world").text, "\"hello_world\"");
758 assert_eq!(srv.character('c').text, "'c'"); 762 assert_eq!(srv.character('c').text, "'c'");
759 assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\""); 763 assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\"");
764
765 // u128::max
766 assert_eq!(
767 srv.integer("340282366920938463463374607431768211455").text,
768 "340282366920938463463374607431768211455"
769 );
770 // i128::min
771 assert_eq!(
772 srv.integer("-170141183460469231731687303715884105728").text,
773 "-170141183460469231731687303715884105728"
774 );
760 } 775 }
761 776
762 #[test] 777 #[test]
diff --git a/crates/profile/src/google_cpu_profiler.rs b/crates/profile/src/google_cpu_profiler.rs
index db865c65b..cae6caeaa 100644
--- a/crates/profile/src/google_cpu_profiler.rs
+++ b/crates/profile/src/google_cpu_profiler.rs
@@ -14,26 +14,31 @@ extern "C" {
14 fn ProfilerStop(); 14 fn ProfilerStop();
15} 15}
16 16
17static PROFILER_STATE: AtomicUsize = AtomicUsize::new(OFF);
18const OFF: usize = 0; 17const OFF: usize = 0;
19const ON: usize = 1; 18const ON: usize = 1;
20const PENDING: usize = 2; 19const PENDING: usize = 2;
21 20
22pub fn start(path: &Path) { 21fn transition(current: usize, new: usize) -> bool {
23 if PROFILER_STATE.compare_and_swap(OFF, PENDING, Ordering::SeqCst) != OFF { 22 static STATE: AtomicUsize = AtomicUsize::new(OFF);
23
24 STATE.compare_exchange(current, new, Ordering::SeqCst, Ordering::SeqCst).is_ok()
25}
26
27pub(crate) fn start(path: &Path) {
28 if !transition(OFF, PENDING) {
24 panic!("profiler already started"); 29 panic!("profiler already started");
25 } 30 }
26 let path = CString::new(path.display().to_string()).unwrap(); 31 let path = CString::new(path.display().to_string()).unwrap();
27 if unsafe { ProfilerStart(path.as_ptr()) } == 0 { 32 if unsafe { ProfilerStart(path.as_ptr()) } == 0 {
28 panic!("profiler failed to start") 33 panic!("profiler failed to start")
29 } 34 }
30 assert!(PROFILER_STATE.compare_and_swap(PENDING, ON, Ordering::SeqCst) == PENDING); 35 assert!(transition(PENDING, ON));
31} 36}
32 37
33pub fn stop() { 38pub(crate) fn stop() {
34 if PROFILER_STATE.compare_and_swap(ON, PENDING, Ordering::SeqCst) != ON { 39 if !transition(ON, PENDING) {
35 panic!("profiler is not started") 40 panic!("profiler is not started")
36 } 41 }
37 unsafe { ProfilerStop() }; 42 unsafe { ProfilerStop() };
38 assert!(PROFILER_STATE.compare_and_swap(PENDING, OFF, Ordering::SeqCst) == PENDING); 43 assert!(transition(PENDING, OFF));
39} 44}
diff --git a/crates/profile/src/hprof.rs b/crates/profile/src/hprof.rs
index 29d2ed518..5fdb37206 100644
--- a/crates/profile/src/hprof.rs
+++ b/crates/profile/src/hprof.rs
@@ -1,5 +1,4 @@
1//! Simple hierarchical profiler 1//! Simple hierarchical profiler
2use once_cell::sync::Lazy;
3use std::{ 2use std::{
4 cell::RefCell, 3 cell::RefCell,
5 collections::{BTreeMap, HashSet}, 4 collections::{BTreeMap, HashSet},
@@ -12,6 +11,8 @@ use std::{
12 time::{Duration, Instant}, 11 time::{Duration, Instant},
13}; 12};
14 13
14use once_cell::sync::Lazy;
15
15use crate::tree::{Idx, Tree}; 16use crate::tree::{Idx, Tree};
16 17
17/// Filtering syntax 18/// Filtering syntax
@@ -56,18 +57,32 @@ type Label = &'static str;
56/// 0ms - profile 57/// 0ms - profile
57/// 0ms - profile2 58/// 0ms - profile2
58/// ``` 59/// ```
60#[inline]
59pub fn span(label: Label) -> ProfileSpan { 61pub fn span(label: Label) -> ProfileSpan {
60 assert!(!label.is_empty()); 62 debug_assert!(!label.is_empty());
61 63
62 if PROFILING_ENABLED.load(Ordering::Relaxed) 64 let enabled = PROFILING_ENABLED.load(Ordering::Relaxed);
63 && PROFILE_STACK.with(|stack| stack.borrow_mut().push(label)) 65 if enabled && with_profile_stack(|stack| stack.push(label)) {
64 {
65 ProfileSpan(Some(ProfilerImpl { label, detail: None })) 66 ProfileSpan(Some(ProfilerImpl { label, detail: None }))
66 } else { 67 } else {
67 ProfileSpan(None) 68 ProfileSpan(None)
68 } 69 }
69} 70}
70 71
72#[inline]
73pub fn heartbeat_span() -> HeartbeatSpan {
74 let enabled = PROFILING_ENABLED.load(Ordering::Relaxed);
75 HeartbeatSpan::new(enabled)
76}
77
78#[inline]
79pub fn heartbeat() {
80 let enabled = PROFILING_ENABLED.load(Ordering::Relaxed);
81 if enabled {
82 with_profile_stack(|it| it.heartbeat(1));
83 }
84}
85
71pub struct ProfileSpan(Option<ProfilerImpl>); 86pub struct ProfileSpan(Option<ProfilerImpl>);
72 87
73struct ProfilerImpl { 88struct ProfilerImpl {
@@ -85,20 +100,48 @@ impl ProfileSpan {
85} 100}
86 101
87impl Drop for ProfilerImpl { 102impl Drop for ProfilerImpl {
103 #[inline]
104 fn drop(&mut self) {
105 with_profile_stack(|it| it.pop(self.label, self.detail.take()));
106 }
107}
108
109pub struct HeartbeatSpan {
110 enabled: bool,
111}
112
113impl HeartbeatSpan {
114 #[inline]
115 pub fn new(enabled: bool) -> Self {
116 if enabled {
117 with_profile_stack(|it| it.heartbeats(true))
118 }
119 Self { enabled }
120 }
121}
122
123impl Drop for HeartbeatSpan {
88 fn drop(&mut self) { 124 fn drop(&mut self) {
89 PROFILE_STACK.with(|it| it.borrow_mut().pop(self.label, self.detail.take())); 125 if self.enabled {
126 with_profile_stack(|it| it.heartbeats(false))
127 }
90 } 128 }
91} 129}
92 130
93static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false); 131static PROFILING_ENABLED: AtomicBool = AtomicBool::new(false);
94static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default); 132static FILTER: Lazy<RwLock<Filter>> = Lazy::new(Default::default);
95thread_local!(static PROFILE_STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new())); 133
134fn with_profile_stack<T>(f: impl FnOnce(&mut ProfileStack) -> T) -> T {
135 thread_local!(static STACK: RefCell<ProfileStack> = RefCell::new(ProfileStack::new()));
136 STACK.with(|it| f(&mut *it.borrow_mut()))
137}
96 138
97#[derive(Default, Clone, Debug)] 139#[derive(Default, Clone, Debug)]
98struct Filter { 140struct Filter {
99 depth: usize, 141 depth: usize,
100 allowed: HashSet<String>, 142 allowed: HashSet<String>,
101 longer_than: Duration, 143 longer_than: Duration,
144 heartbeat_longer_than: Duration,
102 version: usize, 145 version: usize,
103} 146}
104 147
@@ -115,6 +158,7 @@ impl Filter {
115 } else { 158 } else {
116 Duration::new(0, 0) 159 Duration::new(0, 0)
117 }; 160 };
161 let heartbeat_longer_than = longer_than;
118 162
119 let depth = if let Some(idx) = spec.rfind('@') { 163 let depth = if let Some(idx) = spec.rfind('@') {
120 let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth"); 164 let depth: usize = spec[idx + 1..].parse().expect("invalid profile depth");
@@ -125,7 +169,7 @@ impl Filter {
125 }; 169 };
126 let allowed = 170 let allowed =
127 if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() }; 171 if spec == "*" { HashSet::new() } else { spec.split('|').map(String::from).collect() };
128 Filter { depth, allowed, longer_than, version: 0 } 172 Filter { depth, allowed, longer_than, heartbeat_longer_than, version: 0 }
129 } 173 }
130 174
131 fn install(mut self) { 175 fn install(mut self) {
@@ -137,9 +181,15 @@ impl Filter {
137} 181}
138 182
139struct ProfileStack { 183struct ProfileStack {
140 starts: Vec<Instant>, 184 frames: Vec<Frame>,
141 filter: Filter, 185 filter: Filter,
142 messages: Tree<Message>, 186 messages: Tree<Message>,
187 heartbeats: bool,
188}
189
190struct Frame {
191 t: Instant,
192 heartbeats: u32,
143} 193}
144 194
145#[derive(Default)] 195#[derive(Default)]
@@ -151,35 +201,49 @@ struct Message {
151 201
152impl ProfileStack { 202impl ProfileStack {
153 fn new() -> ProfileStack { 203 fn new() -> ProfileStack {
154 ProfileStack { starts: Vec::new(), messages: Tree::default(), filter: Default::default() } 204 ProfileStack {
205 frames: Vec::new(),
206 messages: Tree::default(),
207 filter: Default::default(),
208 heartbeats: false,
209 }
155 } 210 }
156 211
157 fn push(&mut self, label: Label) -> bool { 212 fn push(&mut self, label: Label) -> bool {
158 if self.starts.is_empty() { 213 if self.frames.is_empty() {
159 if let Ok(f) = FILTER.try_read() { 214 if let Ok(f) = FILTER.try_read() {
160 if f.version > self.filter.version { 215 if f.version > self.filter.version {
161 self.filter = f.clone(); 216 self.filter = f.clone();
162 } 217 }
163 }; 218 };
164 } 219 }
165 if self.starts.len() > self.filter.depth { 220 if self.frames.len() > self.filter.depth {
166 return false; 221 return false;
167 } 222 }
168 let allowed = &self.filter.allowed; 223 let allowed = &self.filter.allowed;
169 if self.starts.is_empty() && !allowed.is_empty() && !allowed.contains(label) { 224 if self.frames.is_empty() && !allowed.is_empty() && !allowed.contains(label) {
170 return false; 225 return false;
171 } 226 }
172 227
173 self.starts.push(Instant::now()); 228 self.frames.push(Frame { t: Instant::now(), heartbeats: 0 });
174 self.messages.start(); 229 self.messages.start();
175 true 230 true
176 } 231 }
177 232
178 fn pop(&mut self, label: Label, detail: Option<String>) { 233 fn pop(&mut self, label: Label, detail: Option<String>) {
179 let start = self.starts.pop().unwrap(); 234 let frame = self.frames.pop().unwrap();
180 let duration = start.elapsed(); 235 let duration = frame.t.elapsed();
236
237 if self.heartbeats {
238 self.heartbeat(frame.heartbeats);
239 let avg_span = duration / (frame.heartbeats + 1);
240 if avg_span > self.filter.heartbeat_longer_than {
241 eprintln!("Too few heartbeats {} ({}/{:?})?", label, frame.heartbeats, duration)
242 }
243 }
244
181 self.messages.finish(Message { duration, label, detail }); 245 self.messages.finish(Message { duration, label, detail });
182 if self.starts.is_empty() { 246 if self.frames.is_empty() {
183 let longer_than = self.filter.longer_than; 247 let longer_than = self.filter.longer_than;
184 // Convert to millis for comparison to avoid problems with rounding 248 // Convert to millis for comparison to avoid problems with rounding
185 // (otherwise we could print `0ms` despite user's `>0` filter when 249 // (otherwise we could print `0ms` despite user's `>0` filter when
@@ -192,6 +256,15 @@ impl ProfileStack {
192 self.messages.clear(); 256 self.messages.clear();
193 } 257 }
194 } 258 }
259
260 fn heartbeats(&mut self, yes: bool) {
261 self.heartbeats = yes;
262 }
263 fn heartbeat(&mut self, n: u32) {
264 if let Some(frame) = self.frames.last_mut() {
265 frame.heartbeats += n;
266 }
267 }
195} 268}
196 269
197fn print( 270fn print(
diff --git a/crates/profile/src/lib.rs b/crates/profile/src/lib.rs
index 79dba47d5..a31fb8f43 100644
--- a/crates/profile/src/lib.rs
+++ b/crates/profile/src/lib.rs
@@ -10,7 +10,7 @@ mod tree;
10use std::cell::RefCell; 10use std::cell::RefCell;
11 11
12pub use crate::{ 12pub use crate::{
13 hprof::{init, init_from, span}, 13 hprof::{heartbeat, heartbeat_span, init, init_from, span},
14 memory_usage::{Bytes, MemoryUsage}, 14 memory_usage::{Bytes, MemoryUsage},
15 stop_watch::{StopWatch, StopWatchSpan}, 15 stop_watch::{StopWatch, StopWatchSpan},
16}; 16};
@@ -52,7 +52,7 @@ impl Drop for Scope {
52/// Usage: 52/// Usage:
53/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro. 53/// 1. Install gpref_tools (https://github.com/gperftools/gperftools), probably packaged with your Linux distro.
54/// 2. Build with `cpu_profiler` feature. 54/// 2. Build with `cpu_profiler` feature.
55/// 3. Tun the code, the *raw* output would be in the `./out.profile` file. 55/// 3. Run the code, the *raw* output would be in the `./out.profile` file.
56/// 4. Install pprof for visualization (https://github.com/google/pprof). 56/// 4. Install pprof for visualization (https://github.com/google/pprof).
57/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000` 57/// 5. Bump sampling frequency to once per ms: `export CPUPROFILE_FREQUENCY=1000`
58/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results. 58/// 6. Use something like `pprof -svg target/release/rust-analyzer ./out.profile` to see the results.
@@ -60,8 +60,17 @@ impl Drop for Scope {
60/// For example, here's how I run profiling on NixOS: 60/// For example, here's how I run profiling on NixOS:
61/// 61///
62/// ```bash 62/// ```bash
63/// $ nix-shell -p gperftools --run \ 63/// $ bat -p shell.nix
64/// 'cargo run --release -p rust-analyzer -- parse < ~/projects/rustbench/parser.rs > /dev/null' 64/// with import <nixpkgs> {};
65/// mkShell {
66/// buildInputs = [ gperftools ];
67/// shellHook = ''
68/// export LD_LIBRARY_PATH="${gperftools}/lib:"
69/// '';
70/// }
71/// $ set -x CPUPROFILE_FREQUENCY 1000
72/// $ nix-shell --run 'cargo test --release --package rust-analyzer --lib -- benchmarks::benchmark_integrated_highlighting --exact --nocapture'
73/// $ pprof -svg target/release/deps/rust_analyzer-8739592dc93d63cb crates/rust-analyzer/out.profile > profile.svg
65/// ``` 74/// ```
66/// 75///
67/// See this diff for how to profile completions: 76/// See this diff for how to profile completions:
@@ -81,7 +90,9 @@ pub fn cpu_span() -> CpuSpan {
81 90
82 #[cfg(not(feature = "cpu_profiler"))] 91 #[cfg(not(feature = "cpu_profiler"))]
83 { 92 {
84 eprintln!("cpu_profiler feature is disabled") 93 eprintln!(
94 r#"cpu profiling is disabled, uncomment `default = [ "cpu_profiler" ]` in Cargo.toml to enable."#
95 )
85 } 96 }
86 97
87 CpuSpan { _private: () } 98 CpuSpan { _private: () }
@@ -91,7 +102,23 @@ impl Drop for CpuSpan {
91 fn drop(&mut self) { 102 fn drop(&mut self) {
92 #[cfg(feature = "cpu_profiler")] 103 #[cfg(feature = "cpu_profiler")]
93 { 104 {
94 google_cpu_profiler::stop() 105 google_cpu_profiler::stop();
106 let profile_data = std::env::current_dir().unwrap().join("out.profile");
107 eprintln!("Profile data saved to:\n\n {}\n", profile_data.display());
108 let mut cmd = std::process::Command::new("pprof");
109 cmd.arg("-svg").arg(std::env::current_exe().unwrap()).arg(&profile_data);
110 let out = cmd.output();
111
112 match out {
113 Ok(out) if out.status.success() => {
114 let svg = profile_data.with_extension("svg");
115 std::fs::write(&svg, &out.stdout).unwrap();
116 eprintln!("Profile rendered to:\n\n {}\n", svg.display());
117 }
118 _ => {
119 eprintln!("Failed to run:\n\n {:?}\n", cmd);
120 }
121 }
95 } 122 }
96 } 123 }
97} 124}
diff --git a/crates/project_model/src/build_data.rs b/crates/project_model/src/build_data.rs
index f7050be4e..ab5cc8c49 100644
--- a/crates/project_model/src/build_data.rs
+++ b/crates/project_model/src/build_data.rs
@@ -13,12 +13,12 @@ use cargo_metadata::{BuildScript, Message};
13use itertools::Itertools; 13use itertools::Itertools;
14use paths::{AbsPath, AbsPathBuf}; 14use paths::{AbsPath, AbsPathBuf};
15use rustc_hash::FxHashMap; 15use rustc_hash::FxHashMap;
16use stdx::JodChild; 16use stdx::{format_to, JodChild};
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,137 @@ 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 }
145
146 cmd.args(&["check", "--workspace", "--message-format=json", "--manifest-path"])
147 .arg(cargo_toml.as_ref());
118 148
119 if cargo_features.all_features { 149 // --all-targets includes tests, benches and examples in addition to the
120 cmd.arg("--all-features"); 150 // default lib and bins. This is an independent concept from the --targets
121 } else { 151 // flag below.
122 if cargo_features.no_default_features { 152 cmd.arg("--all-targets");
123 // FIXME: `NoDefaultFeatures` is mutual exclusive with `SomeFeatures` 153
124 // https://github.com/oli-obk/cargo_metadata/issues/79 154 if let Some(target) = &cargo_features.target {
125 cmd.arg("--no-default-features"); 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 child = cmd.spawn().map(JodChild)?;
136 let child_stdout = child.stdout.take().unwrap(); 175 let child_stdout = child.stdout.take().unwrap();
137 let stdout = BufReader::new(child_stdout); 176 let stdout = BufReader::new(child_stdout);
138 177
139 let mut res = BuildDataMap::default(); 178 let mut res = WorkspaceBuildData::default();
140 for message in cargo_metadata::Message::parse_stream(stdout).flatten() { 179 for message in cargo_metadata::Message::parse_stream(stdout).flatten() {
141 match message { 180 match message {
142 Message::BuildScriptExecuted(BuildScript { 181 Message::BuildScriptExecuted(BuildScript {
143 package_id, out_dir, cfgs, env, .. 182 package_id,
144 }) => { 183 out_dir,
145 let cfgs = { 184 cfgs,
146 let mut acc = Vec::new(); 185 env,
147 for cfg in cfgs { 186 ..
148 match cfg.parse::<CfgFlag>() { 187 }) => {
149 Ok(it) => acc.push(it), 188 let cfgs = {
150 Err(err) => { 189 let mut acc = Vec::new();
151 anyhow::bail!("invalid cfg from cargo-metadata: {}", err) 190 for cfg in cfgs {
152 } 191 match cfg.parse::<CfgFlag>() {
153 }; 192 Ok(it) => acc.push(it),
193 Err(err) => {
194 anyhow::bail!("invalid cfg from cargo-metadata: {}", err)
195 }
196 };
197 }
198 acc
199 };
200 let package_build_data =
201 res.per_package.entry(package_id.repr.clone()).or_default();
202 // cargo_metadata crate returns default (empty) path for
203 // older cargos, which is not absolute, so work around that.
204 if !out_dir.as_str().is_empty() {
205 let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string()));
206 package_build_data.out_dir = Some(out_dir);
207 package_build_data.cfgs = cfgs;
154 } 208 }
155 acc
156 };
157 let res = res.entry(package_id.repr.clone()).or_default();
158 // cargo_metadata crate returns default (empty) path for
159 // older cargos, which is not absolute, so work around that.
160 if !out_dir.as_str().is_empty() {
161 let out_dir = AbsPathBuf::assert(PathBuf::from(out_dir.into_os_string()));
162 res.out_dir = Some(out_dir);
163 res.cfgs = cfgs;
164 }
165 209
166 res.envs = env; 210 package_build_data.envs = env;
167 } 211 }
168 Message::CompilerArtifact(message) => { 212 Message::CompilerArtifact(message) => {
169 progress(format!("metadata {}", message.target.name)); 213 progress(format!("metadata {}", message.target.name));
170 214
171 if message.target.kind.contains(&"proc-macro".to_string()) { 215 if message.target.kind.contains(&"proc-macro".to_string()) {
172 let package_id = message.package_id; 216 let package_id = message.package_id;
173 // Skip rmeta file 217 // Skip rmeta file
174 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name)) { 218 if let Some(filename) = message.filenames.iter().find(|name| is_dylib(name))
175 let filename = AbsPathBuf::assert(PathBuf::from(&filename)); 219 {
176 let res = res.entry(package_id.repr.clone()).or_default(); 220 let filename = AbsPathBuf::assert(PathBuf::from(&filename));
177 res.proc_macro_dylib_path = Some(filename); 221 let package_build_data =
222 res.per_package.entry(package_id.repr.clone()).or_default();
223 package_build_data.proc_macro_dylib_path = Some(filename);
224 }
178 } 225 }
179 } 226 }
227 Message::CompilerMessage(message) => {
228 progress(message.target.name.clone());
229 }
230 Message::BuildFinished(_) => {}
231 Message::TextLine(_) => {}
232 _ => {}
180 } 233 }
181 Message::CompilerMessage(message) => { 234 }
182 progress(message.target.name.clone()); 235
236 for package in packages {
237 let package_build_data = res.per_package.entry(package.id.repr.clone()).or_default();
238 inject_cargo_env(package, package_build_data);
239 if let Some(out_dir) = &package_build_data.out_dir {
240 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!()
241 if let Some(out_dir) = out_dir.to_str().map(|s| s.to_owned()) {
242 package_build_data.envs.push(("OUT_DIR".to_string(), out_dir));
243 }
183 } 244 }
184 Message::BuildFinished(_) => {}
185 Message::TextLine(_) => {}
186 _ => {}
187 } 245 }
188 }
189 246
190 for package in packages { 247 let output = child.into_inner().wait_with_output()?;
191 let build_data = res.entry(package.id.repr.clone()).or_default(); 248 if !output.status.success() {
192 inject_cargo_env(package, build_data); 249 let mut stderr = String::from_utf8(output.stderr).unwrap_or_default();
193 if let Some(out_dir) = &build_data.out_dir { 250 if stderr.is_empty() {
194 // NOTE: cargo and rustc seem to hide non-UTF-8 strings from env! and option_env!() 251 stderr = "cargo check failed".to_string();
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 } 252 }
253 res.error = Some(stderr)
198 } 254 }
199 }
200 255
201 Ok(res) 256 Ok(res)
257 }
202} 258}
203 259
204// FIXME: File a better way to know if it is a dylib 260// FIXME: File a better way to know if it is a dylib
@@ -212,7 +268,7 @@ fn is_dylib(path: &Utf8Path) -> bool {
212/// Recreates the compile-time environment variables that Cargo sets. 268/// Recreates the compile-time environment variables that Cargo sets.
213/// 269///
214/// Should be synced with <https://doc.rust-lang.org/cargo/reference/environment-variables.html#environment-variables-cargo-sets-for-crates> 270/// 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) { 271fn inject_cargo_env(package: &cargo_metadata::Package, build_data: &mut PackageBuildData) {
216 let env = &mut build_data.envs; 272 let env = &mut build_data.envs;
217 273
218 // FIXME: Missing variables: 274 // 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
new file mode 100644
index 000000000..bdd94b1c4
--- /dev/null
+++ b/crates/rust-analyzer/src/benchmarks.rs
@@ -0,0 +1,74 @@
1//! Fully integrated benchmarks for rust-analyzer, which load real cargo
2//! projects.
3//!
4//! The benchmark here is used to debug specific performance regressions. If you
5//! notice that, eg, completion is slow in some specific case, you can modify
6//! code here exercise this specific completion, and thus have a fast
7//! edit/compile/test cycle.
8//!
9//! Note that "Rust Analyzer: Run" action does not allow running a single test
10//! in release mode in VS Code. There's however "Rust Analyzer: Copy Run Command Line"
11//! which you can use to paste the command in terminal and add `--release` manually.
12
13use std::sync::Arc;
14
15use ide::Change;
16use test_utils::project_root;
17use vfs::{AbsPathBuf, VfsPath};
18
19use crate::cli::load_cargo::{load_workspace_at, LoadCargoConfig};
20
21#[test]
22fn benchmark_integrated_highlighting() {
23 // Don't run slow benchmark by default
24 if true {
25 return;
26 }
27
28 // Load rust-analyzer itself.
29 let workspace_to_load = project_root();
30 let file = "./crates/ide_db/src/apply_change.rs";
31
32 let cargo_config = Default::default();
33 let load_cargo_config = LoadCargoConfig {
34 load_out_dirs_from_check: true,
35 wrap_rustc: false,
36 with_proc_macro: false,
37 };
38
39 let (mut host, vfs, _proc_macro) = {
40 let _it = stdx::timeit("workspace loading");
41 load_workspace_at(&workspace_to_load, &cargo_config, &load_cargo_config, &|_| {}).unwrap()
42 };
43
44 let file_id = {
45 let file = workspace_to_load.join(file);
46 let path = VfsPath::from(AbsPathBuf::assert(file));
47 vfs.file_id(&path).unwrap_or_else(|| panic!("can't find virtual file for {}", path))
48 };
49
50 {
51 let _it = stdx::timeit("initial");
52 let analysis = host.analysis();
53 analysis.highlight_as_html(file_id, false).unwrap();
54 }
55
56 profile::init_from("*>100");
57 // let _s = profile::heartbeat_span();
58
59 {
60 let _it = stdx::timeit("change");
61 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
62 text.push_str("\npub fn _dummy() {}\n");
63 let mut change = Change::new();
64 change.change_file(file_id, Some(Arc::new(text)));
65 host.apply_change(change);
66 }
67
68 {
69 let _it = stdx::timeit("after change");
70 let _span = profile::cpu_span();
71 let analysis = host.analysis();
72 analysis.highlight_as_html(file_id, false).unwrap();
73 }
74}
diff --git a/crates/rust-analyzer/src/bin/flags.rs b/crates/rust-analyzer/src/bin/flags.rs
index d8987633d..63953098a 100644
--- a/crates/rust-analyzer/src/bin/flags.rs
+++ b/crates/rust-analyzer/src/bin/flags.rs
@@ -1,10 +1,9 @@
1//! Grammar for the command-line arguments. 1//! Grammar for the command-line arguments.
2#![allow(unreachable_pub)] 2#![allow(unreachable_pub)]
3use std::{env, path::PathBuf}; 3use std::path::PathBuf;
4 4
5use ide_ssr::{SsrPattern, SsrRule}; 5use ide_ssr::{SsrPattern, SsrRule};
6use rust_analyzer::cli::{BenchWhat, Position, Verbosity}; 6use rust_analyzer::cli::Verbosity;
7use vfs::AbsPathBuf;
8 7
9xflags::xflags! { 8xflags::xflags! {
10 src "./src/bin/flags.rs" 9 src "./src/bin/flags.rs"
@@ -72,27 +71,8 @@ xflags::xflags! {
72 optional --load-output-dirs 71 optional --load-output-dirs
73 /// Use proc-macro-srv for proc-macro expanding. 72 /// Use proc-macro-srv for proc-macro expanding.
74 optional --with-proc-macro 73 optional --with-proc-macro
75 } 74 /// Only resolve names, don't run type inference.
76 75 optional --skip-inference
77 /// Benchmark specific analysis operation
78 cmd analysis-bench
79 /// Directory with Cargo.toml.
80 required path: PathBuf
81 {
82 /// Collect memory usage statistics.
83 optional --memory-usage
84
85 /// Compute syntax highlighting for this file
86 optional --highlight path: PathBuf
87 /// Compute completions at file:line:column location.
88 optional --complete location: Position
89 /// Compute goto definition at file:line:column location.
90 optional --goto-def location: Position
91
92 /// Load OUT_DIR values by running `cargo check` before analysis.
93 optional --load-output-dirs
94 /// Use proc-macro-srv for proc-macro expanding.
95 optional --with-proc-macro
96 } 76 }
97 77
98 cmd diagnostics 78 cmd diagnostics
@@ -142,7 +122,6 @@ pub enum RustAnalyzerCmd {
142 Symbols(Symbols), 122 Symbols(Symbols),
143 Highlight(Highlight), 123 Highlight(Highlight),
144 AnalysisStats(AnalysisStats), 124 AnalysisStats(AnalysisStats),
145 AnalysisBench(AnalysisBench),
146 Diagnostics(Diagnostics), 125 Diagnostics(Diagnostics),
147 Ssr(Ssr), 126 Ssr(Ssr),
148 Search(Search), 127 Search(Search),
@@ -181,18 +160,7 @@ pub struct AnalysisStats {
181 pub no_sysroot: bool, 160 pub no_sysroot: bool,
182 pub load_output_dirs: bool, 161 pub load_output_dirs: bool,
183 pub with_proc_macro: bool, 162 pub with_proc_macro: bool,
184} 163 pub skip_inference: bool,
185
186#[derive(Debug)]
187pub struct AnalysisBench {
188 pub path: PathBuf,
189
190 pub memory_usage: bool,
191 pub highlight: Option<PathBuf>,
192 pub complete: Option<Position>,
193 pub goto_def: Option<Position>,
194 pub load_output_dirs: bool,
195 pub with_proc_macro: bool,
196} 164}
197 165
198#[derive(Debug)] 166#[derive(Debug)]
@@ -239,17 +207,3 @@ impl RustAnalyzer {
239 } 207 }
240 } 208 }
241} 209}
242
243impl AnalysisBench {
244 pub(crate) fn what(&self) -> BenchWhat {
245 match (&self.highlight, &self.complete, &self.goto_def) {
246 (Some(path), None, None) => {
247 let path = env::current_dir().unwrap().join(path);
248 BenchWhat::Highlight { path: AbsPathBuf::assert(path) }
249 }
250 (None, Some(position), None) => BenchWhat::Complete(position.clone()),
251 (None, None, Some(position)) => BenchWhat::GotoDef(position.clone()),
252 _ => panic!("exactly one of `--highlight`, `--complete` or `--goto-def` must be set"),
253 }
254 }
255}
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index a0b611bff..f0abb5b15 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -3,13 +3,14 @@
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
9use lsp_server::Connection; 10use lsp_server::Connection;
10use project_model::ProjectManifest; 11use project_model::ProjectManifest;
11use rust_analyzer::{ 12use rust_analyzer::{
12 cli::{self, AnalysisStatsCmd, BenchCmd}, 13 cli::{self, AnalysisStatsCmd},
13 config::Config, 14 config::Config,
14 from_json, 15 from_json,
15 lsp_ext::supports_utf8, 16 lsp_ext::supports_utf8,
@@ -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,19 +93,9 @@ 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 flags::RustAnalyzerCmd::AnalysisBench(cmd) => {
84 let what = cmd.what();
85 BenchCmd {
86 memory_usage: cmd.memory_usage,
87 path: cmd.path,
88 load_output_dirs: cmd.load_output_dirs,
89 with_proc_macro: cmd.with_proc_macro,
90 what,
91 }
92 .run(verbosity)?
93 }
94 99
95 flags::RustAnalyzerCmd::Diagnostics(cmd) => { 100 flags::RustAnalyzerCmd::Diagnostics(cmd) => {
96 cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)? 101 cli::diagnostics(&cmd.path, cmd.load_output_dirs, cmd.with_proc_macro)?
@@ -144,7 +149,7 @@ mod tracing_setup {
144} 149}
145 150
146fn run_server() -> Result<()> { 151fn run_server() -> Result<()> {
147 log::info!("server will start"); 152 log::info!("server version {} will start", env!("REV"));
148 153
149 let (connection, io_threads) = Connection::stdio(); 154 let (connection, io_threads) = Connection::stdio();
150 155
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/cargo_target_spec.rs b/crates/rust-analyzer/src/cargo_target_spec.rs
index 5af0802a2..909c21532 100644
--- a/crates/rust-analyzer/src/cargo_target_spec.rs
+++ b/crates/rust-analyzer/src/cargo_target_spec.rs
@@ -201,7 +201,7 @@ mod tests {
201 let cfg_expr = { 201 let cfg_expr = {
202 let source_file = ast::SourceFile::parse(cfg).ok().unwrap(); 202 let source_file = ast::SourceFile::parse(cfg).ok().unwrap();
203 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); 203 let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap();
204 let (tt, _) = ast_to_token_tree(&tt).unwrap(); 204 let (tt, _) = ast_to_token_tree(&tt);
205 CfgExpr::parse(&tt) 205 CfgExpr::parse(&tt)
206 }; 206 };
207 207
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index ed732eb38..76b666dc2 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -1,8 +1,7 @@
1//! Various batch processing tasks, intended primarily for debugging. 1//! Various batch processing tasks, intended primarily for debugging.
2 2
3mod load_cargo; 3pub(crate) mod load_cargo;
4mod analysis_stats; 4mod analysis_stats;
5mod analysis_bench;
6mod diagnostics; 5mod diagnostics;
7mod progress_report; 6mod progress_report;
8mod ssr; 7mod ssr;
@@ -15,7 +14,6 @@ use syntax::{AstNode, SourceFile};
15use vfs::Vfs; 14use vfs::Vfs;
16 15
17pub use self::{ 16pub use self::{
18 analysis_bench::{BenchCmd, BenchWhat, Position},
19 analysis_stats::AnalysisStatsCmd, 17 analysis_stats::AnalysisStatsCmd,
20 diagnostics::diagnostics, 18 diagnostics::diagnostics,
21 load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig}, 19 load_cargo::{load_workspace, load_workspace_at, LoadCargoConfig},
diff --git a/crates/rust-analyzer/src/cli/analysis_bench.rs b/crates/rust-analyzer/src/cli/analysis_bench.rs
deleted file mode 100644
index 49994824f..000000000
--- a/crates/rust-analyzer/src/cli/analysis_bench.rs
+++ /dev/null
@@ -1,196 +0,0 @@
1//! Benchmark operations like highlighting or goto definition.
2
3use std::{env, path::PathBuf, str::FromStr, sync::Arc, time::Instant};
4
5use anyhow::{bail, format_err, Result};
6use hir::PrefixKind;
7use ide::{
8 Analysis, AnalysisHost, Change, CompletionConfig, DiagnosticsConfig, FilePosition, LineCol,
9};
10use ide_db::{
11 base_db::{
12 salsa::{Database, Durability},
13 FileId,
14 },
15 helpers::{insert_use::InsertUseConfig, SnippetCap},
16};
17use vfs::AbsPathBuf;
18
19use crate::cli::{
20 load_cargo::{load_workspace_at, LoadCargoConfig},
21 print_memory_usage, Verbosity,
22};
23
24pub struct BenchCmd {
25 pub path: PathBuf,
26 pub what: BenchWhat,
27 pub memory_usage: bool,
28 pub load_output_dirs: bool,
29 pub with_proc_macro: bool,
30}
31
32pub enum BenchWhat {
33 Highlight { path: AbsPathBuf },
34 Complete(Position),
35 GotoDef(Position),
36}
37
38#[derive(Debug, Clone)]
39pub struct Position {
40 pub path: AbsPathBuf,
41 pub line: u32,
42 pub column: u32,
43}
44
45impl FromStr for Position {
46 type Err = anyhow::Error;
47 fn from_str(s: &str) -> Result<Self> {
48 let mut split = s.rsplitn(3, ':');
49 match (split.next(), split.next(), split.next()) {
50 (Some(column), Some(line), Some(path)) => {
51 let path = env::current_dir().unwrap().join(path);
52 let path = AbsPathBuf::assert(path);
53 Ok(Position { path, line: line.parse()?, column: column.parse()? })
54 }
55 _ => bail!("position should be in file:line:column format: {:?}", s),
56 }
57 }
58}
59
60impl BenchCmd {
61 pub fn run(self, verbosity: Verbosity) -> Result<()> {
62 profile::init();
63
64 let start = Instant::now();
65 eprint!("loading: ");
66
67 let cargo_config = Default::default();
68 let load_cargo_config = LoadCargoConfig {
69 load_out_dirs_from_check: self.load_output_dirs,
70 with_proc_macro: self.with_proc_macro,
71 };
72 let (mut host, vfs, _proc_macro) =
73 load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?;
74 eprintln!("{:?}\n", start.elapsed());
75
76 let file_id = {
77 let path = match &self.what {
78 BenchWhat::Highlight { path } => path,
79 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => &pos.path,
80 };
81 let path = path.clone().into();
82 vfs.file_id(&path).ok_or_else(|| format_err!("Can't find {}", path))?
83 };
84
85 match &self.what {
86 BenchWhat::Highlight { .. } => {
87 let res = do_work(&mut host, file_id, |analysis| {
88 analysis.diagnostics(&DiagnosticsConfig::default(), file_id).unwrap();
89 analysis.highlight_as_html(file_id, false).unwrap()
90 });
91 if verbosity.is_verbose() {
92 println!("\n{}", res);
93 }
94 }
95 BenchWhat::Complete(pos) | BenchWhat::GotoDef(pos) => {
96 let is_completion = matches!(self.what, BenchWhat::Complete(..));
97
98 let offset = host
99 .analysis()
100 .file_line_index(file_id)?
101 .offset(LineCol { line: pos.line - 1, col: pos.column });
102 let file_position = FilePosition { file_id, offset };
103
104 if is_completion {
105 let options = CompletionConfig {
106 enable_postfix_completions: true,
107 enable_imports_on_the_fly: true,
108 add_call_parenthesis: true,
109 add_call_argument_snippets: true,
110 snippet_cap: SnippetCap::new(true),
111 insert_use: InsertUseConfig {
112 merge: None,
113 prefix_kind: PrefixKind::Plain,
114 group: true,
115 },
116 };
117 let res = do_work(&mut host, file_id, |analysis| {
118 analysis.completions(&options, file_position)
119 });
120 if verbosity.is_verbose() {
121 println!("\n{:#?}", res);
122 }
123 } else {
124 let res = do_work(&mut host, file_id, |analysis| {
125 analysis.goto_definition(file_position)
126 });
127 if verbosity.is_verbose() {
128 println!("\n{:#?}", res);
129 }
130 }
131 }
132 }
133
134 if self.memory_usage {
135 print_memory_usage(host, vfs);
136 }
137
138 Ok(())
139 }
140}
141
142fn do_work<F: Fn(&Analysis) -> T, T>(host: &mut AnalysisHost, file_id: FileId, work: F) -> T {
143 {
144 let start = Instant::now();
145 eprint!("from scratch: ");
146 work(&host.analysis());
147 eprintln!("{:?}", start.elapsed());
148 }
149 {
150 let start = Instant::now();
151 eprint!("no change: ");
152 work(&host.analysis());
153 eprintln!("{:?}", start.elapsed());
154 }
155 {
156 let start = Instant::now();
157 eprint!("trivial change: ");
158 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::LOW);
159 work(&host.analysis());
160 eprintln!("{:?}", start.elapsed());
161 }
162 {
163 let start = Instant::now();
164 eprint!("comment change: ");
165 {
166 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
167 text.push_str("\n/* Hello world */\n");
168 let mut change = Change::new();
169 change.change_file(file_id, Some(Arc::new(text)));
170 host.apply_change(change);
171 }
172 work(&host.analysis());
173 eprintln!("{:?}", start.elapsed());
174 }
175 {
176 let start = Instant::now();
177 eprint!("item change: ");
178 {
179 let mut text = host.analysis().file_text(file_id).unwrap().to_string();
180 text.push_str("\npub fn _dummy() {}\n");
181 let mut change = Change::new();
182 change.change_file(file_id, Some(Arc::new(text)));
183 host.apply_change(change);
184 }
185 work(&host.analysis());
186 eprintln!("{:?}", start.elapsed());
187 }
188 {
189 let start = Instant::now();
190 eprint!("const change: ");
191 host.raw_database_mut().salsa_runtime_mut().synthetic_write(Durability::HIGH);
192 let res = work(&host.analysis());
193 eprintln!("{:?}", start.elapsed());
194 res
195 }
196}
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..1edaa394a 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -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).
@@ -445,8 +448,8 @@ impl Config {
445 pub fn hover_actions(&self) -> bool { 448 pub fn hover_actions(&self) -> bool {
446 self.experimental("hoverActions") 449 self.experimental("hoverActions")
447 } 450 }
448 pub fn status_notification(&self) -> bool { 451 pub fn server_status_notification(&self) -> bool {
449 self.experimental("statusNotification") 452 self.experimental("serverStatusNotification")
450 } 453 }
451 454
452 pub fn publish_diagnostics(&self) -> bool { 455 pub fn publish_diagnostics(&self) -> bool {
@@ -493,6 +496,9 @@ impl Config {
493 pub fn run_build_scripts(&self) -> bool { 496 pub fn run_build_scripts(&self) -> bool {
494 self.data.cargo_runBuildScripts || self.data.procMacro_enable 497 self.data.cargo_runBuildScripts || self.data.procMacro_enable
495 } 498 }
499 pub fn wrap_rustc(&self) -> bool {
500 self.data.cargo_useRustcWrapperForBuildScripts
501 }
496 pub fn cargo(&self) -> CargoConfig { 502 pub fn cargo(&self) -> CargoConfig {
497 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| { 503 let rustc_source = self.data.rustcSource.as_ref().map(|rustc_src| {
498 if rustc_src == "discover" { 504 if rustc_src == "discover" {
@@ -656,6 +662,19 @@ impl Config {
656 pub fn code_lens_refresh(&self) -> bool { 662 pub fn code_lens_refresh(&self) -> bool {
657 try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false) 663 try_or!(self.caps.workspace.as_ref()?.code_lens.as_ref()?.refresh_support?, false)
658 } 664 }
665 pub fn insert_replace_support(&self) -> bool {
666 try_or!(
667 self.caps
668 .text_document
669 .as_ref()?
670 .completion
671 .as_ref()?
672 .completion_item
673 .as_ref()?
674 .insert_replace_support?,
675 false
676 )
677 }
659} 678}
660 679
661#[derive(Deserialize, Debug, Clone)] 680#[derive(Deserialize, Debug, Clone)]
diff --git a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
index f999848a7..c847bbb35 100644
--- a/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
+++ b/crates/rust-analyzer/src/diagnostics/test_data/macro_compiler_error.txt
@@ -13,16 +13,16 @@
13 diagnostic: Diagnostic { 13 diagnostic: Diagnostic {
14 range: Range { 14 range: Range {
15 start: Position { 15 start: Position {
16 line: 264, 16 line: 271,
17 character: 8, 17 character: 8,
18 }, 18 },
19 end: Position { 19 end: Position {
20 line: 264, 20 line: 271,
21 character: 76, 21 character: 50,
22 }, 22 },
23 }, 23 },
24 severity: Some( 24 severity: Some(
25 Error, 25 Hint,
26 ), 26 ),
27 code: None, 27 code: None,
28 code_description: None, 28 code_description: None,
@@ -40,18 +40,18 @@
40 password: None, 40 password: None,
41 host: None, 41 host: None,
42 port: None, 42 port: None,
43 path: "/test/crates/hir_def/src/data.rs", 43 path: "/test/crates/hir_def/src/path.rs",
44 query: None, 44 query: None,
45 fragment: None, 45 fragment: None,
46 }, 46 },
47 range: Range { 47 range: Range {
48 start: Position { 48 start: Position {
49 line: 79, 49 line: 264,
50 character: 15, 50 character: 8,
51 }, 51 },
52 end: Position { 52 end: Position {
53 line: 79, 53 line: 264,
54 character: 41, 54 character: 76,
55 }, 55 },
56 }, 56 },
57 }, 57 },
@@ -87,6 +87,71 @@
87 }, 87 },
88 }, 88 },
89 severity: Some( 89 severity: Some(
90 Hint,
91 ),
92 code: None,
93 code_description: None,
94 source: Some(
95 "rustc",
96 ),
97 message: "Please register your known path in the path module",
98 related_information: Some(
99 [
100 DiagnosticRelatedInformation {
101 location: Location {
102 uri: Url {
103 scheme: "file",
104 username: "",
105 password: None,
106 host: None,
107 port: None,
108 path: "/test/crates/hir_def/src/path.rs",
109 query: None,
110 fragment: None,
111 },
112 range: Range {
113 start: Position {
114 line: 264,
115 character: 8,
116 },
117 end: Position {
118 line: 264,
119 character: 76,
120 },
121 },
122 },
123 message: "Exact error occurred here",
124 },
125 ],
126 ),
127 tags: None,
128 data: None,
129 },
130 fixes: [],
131 },
132 MappedRustDiagnostic {
133 url: Url {
134 scheme: "file",
135 username: "",
136 password: None,
137 host: None,
138 port: None,
139 path: "/test/crates/hir_def/src/path.rs",
140 query: None,
141 fragment: None,
142 },
143 diagnostic: Diagnostic {
144 range: Range {
145 start: Position {
146 line: 264,
147 character: 8,
148 },
149 end: Position {
150 line: 264,
151 character: 76,
152 },
153 },
154 severity: Some(
90 Error, 155 Error,
91 ), 156 ),
92 code: None, 157 code: None,
@@ -95,7 +160,60 @@
95 "rustc", 160 "rustc",
96 ), 161 ),
97 message: "Please register your known path in the path module", 162 message: "Please register your known path in the path module",
98 related_information: None, 163 related_information: Some(
164 [
165 DiagnosticRelatedInformation {
166 location: Location {
167 uri: Url {
168 scheme: "file",
169 username: "",
170 password: None,
171 host: None,
172 port: None,
173 path: "/test/crates/hir_def/src/path.rs",
174 query: None,
175 fragment: None,
176 },
177 range: Range {
178 start: Position {
179 line: 271,
180 character: 8,
181 },
182 end: Position {
183 line: 271,
184 character: 50,
185 },
186 },
187 },
188 message: "Error originated from macro call here",
189 },
190 DiagnosticRelatedInformation {
191 location: Location {
192 uri: Url {
193 scheme: "file",
194 username: "",
195 password: None,
196 host: None,
197 port: None,
198 path: "/test/crates/hir_def/src/data.rs",
199 query: None,
200 fragment: None,
201 },
202 range: Range {
203 start: Position {
204 line: 79,
205 character: 15,
206 },
207 end: Position {
208 line: 79,
209 character: 41,
210 },
211 },
212 },
213 message: "Error originated from macro call here",
214 },
215 ],
216 ),
99 tags: None, 217 tags: None,
100 data: None, 218 data: None,
101 }, 219 },
diff --git a/crates/rust-analyzer/src/diagnostics/to_proto.rs b/crates/rust-analyzer/src/diagnostics/to_proto.rs
index 76994de71..e2f319f6b 100644
--- a/crates/rust-analyzer/src/diagnostics/to_proto.rs
+++ b/crates/rust-analyzer/src/diagnostics/to_proto.rs
@@ -34,22 +34,14 @@ fn diagnostic_severity(
34 Some(res) 34 Some(res)
35} 35}
36 36
37/// Check whether a file name is from macro invocation 37/// Checks whether a file name is from macro invocation and does not refer to an actual file.
38fn is_from_macro(file_name: &str) -> bool { 38fn is_dummy_macro_file(file_name: &str) -> bool {
39 // FIXME: current rustc does not seem to emit `<macro file>` files anymore?
39 file_name.starts_with('<') && file_name.ends_with('>') 40 file_name.starts_with('<') && file_name.ends_with('>')
40} 41}
41 42
42/// Converts a Rust span to a LSP location, resolving macro expansion site if neccesary
43fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
44 let mut span = span.clone();
45 while let Some(expansion) = span.expansion {
46 span = expansion.span;
47 }
48 return location_naive(workspace_root, &span);
49}
50
51/// Converts a Rust span to a LSP location 43/// Converts a Rust span to a LSP location
52fn location_naive(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location { 44fn location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
53 let file_name = workspace_root.join(&span.file_name); 45 let file_name = workspace_root.join(&span.file_name);
54 let uri = url_from_abs_path(&file_name); 46 let uri = url_from_abs_path(&file_name);
55 47
@@ -62,7 +54,25 @@ fn location_naive(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Lo
62 lsp_types::Location { uri, range } 54 lsp_types::Location { uri, range }
63} 55}
64 56
65/// Converts a secondary Rust span to a LSP related inflocation(ormation 57/// Extracts a suitable "primary" location from a rustc diagnostic.
58///
59/// 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.
61fn primary_location(workspace_root: &Path, span: &DiagnosticSpan) -> lsp_types::Location {
62 let span_stack = std::iter::successors(Some(span), |span| Some(&span.expansion.as_ref()?.span));
63 for span in span_stack.clone() {
64 let abs_path = workspace_root.join(&span.file_name);
65 if !is_dummy_macro_file(&span.file_name) && abs_path.starts_with(workspace_root) {
66 return location(workspace_root, span);
67 }
68 }
69
70 // Fall back to the outermost macro invocation if no suitable span comes up.
71 let last_span = span_stack.last().unwrap();
72 location(workspace_root, last_span)
73}
74
75/// Converts a secondary Rust span to a LSP related information
66/// 76///
67/// If the span is unlabelled this will return `None`. 77/// If the span is unlabelled this will return `None`.
68fn diagnostic_related_information( 78fn diagnostic_related_information(
@@ -231,7 +241,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
231 primary_spans 241 primary_spans
232 .iter() 242 .iter()
233 .flat_map(|primary_span| { 243 .flat_map(|primary_span| {
234 let location = location(workspace_root, &primary_span); 244 let primary_location = primary_location(workspace_root, &primary_span);
235 245
236 let mut message = message.clone(); 246 let mut message = message.clone();
237 if needs_primary_span_label { 247 if needs_primary_span_label {
@@ -243,31 +253,47 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
243 // Each primary diagnostic span may result in multiple LSP diagnostics. 253 // Each primary diagnostic span may result in multiple LSP diagnostics.
244 let mut diagnostics = Vec::new(); 254 let mut diagnostics = Vec::new();
245 255
246 let mut related_macro_info = None; 256 let mut related_info_macro_calls = vec![];
247 257
248 // If error occurs from macro expansion, add related info pointing to 258 // If error occurs from macro expansion, add related info pointing to
249 // where the error originated 259 // where the error originated
250 // Also, we would generate an additional diagnostic, so that exact place of macro 260 // Also, we would generate an additional diagnostic, so that exact place of macro
251 // will be highlighted in the error origin place. 261 // will be highlighted in the error origin place.
252 if !is_from_macro(&primary_span.file_name) && primary_span.expansion.is_some() { 262 let span_stack = std::iter::successors(Some(*primary_span), |span| {
253 let in_macro_location = location_naive(workspace_root, &primary_span); 263 Some(&span.expansion.as_ref()?.span)
264 });
265 for (i, span) in span_stack.enumerate() {
266 if is_dummy_macro_file(&span.file_name) {
267 continue;
268 }
254 269
255 // Add related information for the main disagnostic. 270 // First span is the original diagnostic, others are macro call locations that
256 related_macro_info = Some(lsp_types::DiagnosticRelatedInformation { 271 // generated that code.
257 location: in_macro_location.clone(), 272 let is_in_macro_call = i != 0;
258 message: "Error originated from macro here".to_string(),
259 });
260 273
274 let secondary_location = location(workspace_root, &span);
275 if secondary_location == primary_location {
276 continue;
277 }
278 related_info_macro_calls.push(lsp_types::DiagnosticRelatedInformation {
279 location: secondary_location.clone(),
280 message: if is_in_macro_call {
281 "Error originated from macro call here".to_string()
282 } else {
283 "Actual error occurred here".to_string()
284 },
285 });
261 // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code. 286 // For the additional in-macro diagnostic we add the inverse message pointing to the error location in code.
262 let information_for_additional_diagnostic = 287 let information_for_additional_diagnostic =
263 vec![lsp_types::DiagnosticRelatedInformation { 288 vec![lsp_types::DiagnosticRelatedInformation {
264 location: location.clone(), 289 location: primary_location.clone(),
265 message: "Exact error occurred here".to_string(), 290 message: "Exact error occurred here".to_string(),
266 }]; 291 }];
267 292
268 let diagnostic = lsp_types::Diagnostic { 293 let diagnostic = lsp_types::Diagnostic {
269 range: in_macro_location.range, 294 range: secondary_location.range,
270 severity, 295 // downgrade to hint if we're pointing at the macro
296 severity: Some(lsp_types::DiagnosticSeverity::Hint),
271 code: code.clone().map(lsp_types::NumberOrString::String), 297 code: code.clone().map(lsp_types::NumberOrString::String),
272 code_description: code_description.clone(), 298 code_description: code_description.clone(),
273 source: Some(source.clone()), 299 source: Some(source.clone()),
@@ -276,9 +302,8 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
276 tags: if tags.is_empty() { None } else { Some(tags.clone()) }, 302 tags: if tags.is_empty() { None } else { Some(tags.clone()) },
277 data: None, 303 data: None,
278 }; 304 };
279
280 diagnostics.push(MappedRustDiagnostic { 305 diagnostics.push(MappedRustDiagnostic {
281 url: in_macro_location.uri, 306 url: secondary_location.uri,
282 diagnostic, 307 diagnostic,
283 fixes: Vec::new(), 308 fixes: Vec::new(),
284 }); 309 });
@@ -286,23 +311,25 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
286 311
287 // Emit the primary diagnostic. 312 // Emit the primary diagnostic.
288 diagnostics.push(MappedRustDiagnostic { 313 diagnostics.push(MappedRustDiagnostic {
289 url: location.uri.clone(), 314 url: primary_location.uri.clone(),
290 diagnostic: lsp_types::Diagnostic { 315 diagnostic: lsp_types::Diagnostic {
291 range: location.range, 316 range: primary_location.range,
292 severity, 317 severity,
293 code: code.clone().map(lsp_types::NumberOrString::String), 318 code: code.clone().map(lsp_types::NumberOrString::String),
294 code_description: code_description.clone(), 319 code_description: code_description.clone(),
295 source: Some(source.clone()), 320 source: Some(source.clone()),
296 message, 321 message,
297 related_information: if subdiagnostics.is_empty() { 322 related_information: {
298 None 323 let info = related_info_macro_calls
299 } else {
300 let mut related = subdiagnostics
301 .iter() 324 .iter()
302 .map(|sub| sub.related.clone()) 325 .cloned()
326 .chain(subdiagnostics.iter().map(|sub| sub.related.clone()))
303 .collect::<Vec<_>>(); 327 .collect::<Vec<_>>();
304 related.extend(related_macro_info); 328 if info.is_empty() {
305 Some(related) 329 None
330 } else {
331 Some(info)
332 }
306 }, 333 },
307 tags: if tags.is_empty() { None } else { Some(tags.clone()) }, 334 tags: if tags.is_empty() { None } else { Some(tags.clone()) },
308 data: None, 335 data: None,
@@ -314,7 +341,7 @@ pub(crate) fn map_rust_diagnostic_to_lsp(
314 // This is useful because they will show up in the user's editor, unlike 341 // This is useful because they will show up in the user's editor, unlike
315 // `related_information`, which just produces hard-to-read links, at least in VS Code. 342 // `related_information`, which just produces hard-to-read links, at least in VS Code.
316 let back_ref = lsp_types::DiagnosticRelatedInformation { 343 let back_ref = lsp_types::DiagnosticRelatedInformation {
317 location, 344 location: primary_location,
318 message: "original diagnostic".to_string(), 345 message: "original diagnostic".to_string(),
319 }; 346 };
320 for sub in &subdiagnostics { 347 for sub in &subdiagnostics {
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 85e67554c..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,
@@ -84,7 +84,8 @@ pub(crate) fn handle_analyzer_status(
84 84
85pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> { 85pub(crate) fn handle_memory_usage(state: &mut GlobalState, _: ()) -> Result<String> {
86 let _p = profile::span("handle_memory_usage"); 86 let _p = profile::span("handle_memory_usage");
87 let mem = state.analysis_host.per_query_memory_usage(); 87 let mut mem = state.analysis_host.per_query_memory_usage();
88 mem.push(("Remaining".into(), profile::memory_usage().allocated));
88 89
89 let mut out = String::new(); 90 let mut out = String::new();
90 for (name, bytes) in mem { 91 for (name, bytes) in mem {
@@ -230,7 +231,6 @@ pub(crate) fn handle_on_enter(
230 Ok(Some(edit)) 231 Ok(Some(edit))
231} 232}
232 233
233// Don't forget to add new trigger characters to `ServerCapabilities` in `caps.rs`.
234pub(crate) fn handle_on_type_formatting( 234pub(crate) fn handle_on_type_formatting(
235 snap: GlobalStateSnapshot, 235 snap: GlobalStateSnapshot,
236 params: lsp_types::DocumentOnTypeFormattingParams, 236 params: lsp_types::DocumentOnTypeFormattingParams,
@@ -664,10 +664,13 @@ pub(crate) fn handle_completion(
664 }; 664 };
665 let line_index = snap.file_line_index(position.file_id)?; 665 let line_index = snap.file_line_index(position.file_id)?;
666 666
667 let insert_replace_support =
668 snap.config.insert_replace_support().then(|| text_document_position.position);
667 let items: Vec<CompletionItem> = items 669 let items: Vec<CompletionItem> = items
668 .into_iter() 670 .into_iter()
669 .flat_map(|item| { 671 .flat_map(|item| {
670 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());
671 674
672 if completion_config.enable_imports_on_the_fly { 675 if completion_config.enable_imports_on_the_fly {
673 for new_item in &mut new_completion_items { 676 for new_item in &mut new_completion_items {
@@ -926,19 +929,22 @@ pub(crate) fn handle_formatting(
926 let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default(); 929 let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
927 930
928 if !output.status.success() { 931 if !output.status.success() {
929 match output.status.code() { 932 let rustfmt_not_installed =
930 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 => {
931 // 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
932 // 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
933 // 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
934 // syntax error diagnostics they're already receiving. This is especially jarring 940 // syntax error diagnostics they're already receiving. This is especially jarring
935 // if they have format on save enabled. 941 // if they have format on save enabled.
936 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");
937 return Ok(None); 943 Ok(None)
938 } 944 }
939 _ => { 945 _ => {
940 // 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
941 return Err(LspError::new( 947 Err(LspError::new(
942 -32900, 948 -32900,
943 format!( 949 format!(
944 r#"rustfmt exited with: 950 r#"rustfmt exited with:
@@ -948,9 +954,9 @@ pub(crate) fn handle_formatting(
948 output.status, captured_stdout, captured_stderr, 954 output.status, captured_stdout, captured_stderr,
949 ), 955 ),
950 ) 956 )
951 .into()); 957 .into())
952 } 958 }
953 } 959 };
954 } 960 }
955 961
956 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout); 962 let (new_text, new_line_endings) = LineEndings::normalize(captured_stdout);
@@ -976,84 +982,52 @@ pub(crate) fn handle_code_action(
976 params: lsp_types::CodeActionParams, 982 params: lsp_types::CodeActionParams,
977) -> Result<Option<Vec<lsp_ext::CodeAction>>> { 983) -> Result<Option<Vec<lsp_ext::CodeAction>>> {
978 let _p = profile::span("handle_code_action"); 984 let _p = profile::span("handle_code_action");
979 // We intentionally don't support command-based actions, as those either 985
980 // requires custom client-code anyway, or requires server-initiated edits.
981 // Server initiated edits break causality, so we avoid those as well.
982 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.
983 return Ok(None); 990 return Ok(None);
984 } 991 }
985 992
986 let file_id = from_proto::file_id(&snap, &params.text_document.uri)?; 993 let line_index =
987 let line_index = snap.file_line_index(file_id)?; 994 snap.file_line_index(from_proto::file_id(&snap, &params.text_document.uri)?)?;
988 let range = from_proto::text_range(&line_index, params.range); 995 let frange = from_proto::file_range(&snap, params.text_document.clone(), params.range)?;
989 let frange = FileRange { file_id, range };
990 996
991 let mut assists_config = snap.config.assist(); 997 let mut assists_config = snap.config.assist();
992 assists_config.allowed = params 998 assists_config.allowed = params
993 .clone()
994 .context 999 .context
995 .only 1000 .only
1001 .clone()
996 .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());
997 1003
998 let mut res: Vec<lsp_ext::CodeAction> = Vec::new(); 1004 let mut res: Vec<lsp_ext::CodeAction> = Vec::new();
999 1005
1000 let include_quick_fixes = match &params.context.only { 1006 let code_action_resolve_cap = snap.config.code_action_resolve();
1001 Some(v) => v.iter().any(|it| { 1007 let assists = snap.analysis.assists_with_fixes(
1002 it == &lsp_types::CodeActionKind::EMPTY || it == &lsp_types::CodeActionKind::QUICKFIX 1008 &assists_config,
1003 }), 1009 &snap.config.diagnostics(),
1004 None => true, 1010 !code_action_resolve_cap,
1005 }; 1011 frange,
1006 if include_quick_fixes { 1012 )?;
1007 add_quick_fixes(&snap, frange, &line_index, &mut res)?; 1013 for (index, assist) in assists.into_iter().enumerate() {
1008 } 1014 let resolve_data =
1009 1015 if code_action_resolve_cap { Some((index, params.clone())) } else { None };
1010 if snap.config.code_action_resolve() { 1016 let code_action = to_proto::code_action(&snap, assist, resolve_data)?;
1011 for (index, assist) in 1017 res.push(code_action)
1012 snap.analysis.assists(&assists_config, false, frange)?.into_iter().enumerate()
1013 {
1014 res.push(to_proto::unresolved_code_action(&snap, params.clone(), assist, index)?);
1015 }
1016 } else {
1017 for assist in snap.analysis.assists(&assists_config, true, frange)?.into_iter() {
1018 res.push(to_proto::resolved_code_action(&snap, assist)?);
1019 }
1020 }
1021
1022 Ok(Some(res))
1023}
1024
1025fn add_quick_fixes(
1026 snap: &GlobalStateSnapshot,
1027 frange: FileRange,
1028 line_index: &LineIndex,
1029 acc: &mut Vec<lsp_ext::CodeAction>,
1030) -> Result<()> {
1031 let diagnostics = snap.analysis.diagnostics(&snap.config.diagnostics(), frange.file_id)?;
1032
1033 for fix in diagnostics
1034 .into_iter()
1035 .filter_map(|d| d.fix)
1036 .filter(|fix| fix.fix_trigger_range.intersect(frange.range).is_some())
1037 {
1038 let edit = to_proto::snippet_workspace_edit(&snap, fix.source_change)?;
1039 let action = lsp_ext::CodeAction {
1040 title: fix.label.to_string(),
1041 group: None,
1042 kind: Some(CodeActionKind::QUICKFIX),
1043 edit: Some(edit),
1044 is_preferred: Some(false),
1045 data: None,
1046 };
1047 acc.push(action);
1048 } 1018 }
1049 1019
1020 // Fixes from `cargo check`.
1050 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.
1051 let fix_range = from_proto::text_range(&line_index, fix.range); 1024 let fix_range = from_proto::text_range(&line_index, fix.range);
1052 if fix_range.intersect(frange.range).is_some() { 1025 if fix_range.intersect(frange.range).is_some() {
1053 acc.push(fix.action.clone()); 1026 res.push(fix.action.clone());
1054 } 1027 }
1055 } 1028 }
1056 Ok(()) 1029
1030 Ok(Some(res))
1057} 1031}
1058 1032
1059pub(crate) fn handle_code_action_resolve( 1033pub(crate) fn handle_code_action_resolve(
@@ -1078,12 +1052,18 @@ pub(crate) fn handle_code_action_resolve(
1078 .only 1052 .only
1079 .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());
1080 1054
1081 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
1082 let (id, index) = split_once(&params.id, ':').unwrap(); 1062 let (id, index) = split_once(&params.id, ':').unwrap();
1083 let index = index.parse::<usize>().unwrap(); 1063 let index = index.parse::<usize>().unwrap();
1084 let assist = &assists[index]; 1064 let assist = &assists[index];
1085 assert!(assist.id.0 == id); 1065 assert!(assist.id.0 == id);
1086 let edit = to_proto::resolved_code_action(&snap, assist.clone())?.edit; 1066 let edit = to_proto::code_action(&snap, assist.clone(), None)?.edit;
1087 code_action.edit = edit; 1067 code_action.edit = edit;
1088 Ok(code_action) 1068 Ok(code_action)
1089} 1069}
@@ -1202,7 +1182,7 @@ pub(crate) fn publish_diagnostics(
1202 1182
1203 let diagnostics: Vec<Diagnostic> = snap 1183 let diagnostics: Vec<Diagnostic> = snap
1204 .analysis 1184 .analysis
1205 .diagnostics(&snap.config.diagnostics(), file_id)? 1185 .diagnostics(&snap.config.diagnostics(), false, file_id)?
1206 .into_iter() 1186 .into_iter()
1207 .map(|d| Diagnostic { 1187 .map(|d| Diagnostic {
1208 range: to_proto::range(&line_index, d.range), 1188 range: to_proto::range(&line_index, d.range),
@@ -1430,7 +1410,7 @@ pub(crate) fn handle_open_cargo_toml(
1430pub(crate) fn handle_move_item( 1410pub(crate) fn handle_move_item(
1431 snap: GlobalStateSnapshot, 1411 snap: GlobalStateSnapshot,
1432 params: lsp_ext::MoveItemParams, 1412 params: lsp_ext::MoveItemParams,
1433) -> Result<Option<lsp_types::TextDocumentEdit>> { 1413) -> Result<Vec<lsp_ext::SnippetTextEdit>> {
1434 let _p = profile::span("handle_move_item"); 1414 let _p = profile::span("handle_move_item");
1435 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)?;
1436 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)?;
@@ -1441,8 +1421,11 @@ pub(crate) fn handle_move_item(
1441 }; 1421 };
1442 1422
1443 match snap.analysis.move_item(range, direction)? { 1423 match snap.analysis.move_item(range, direction)? {
1444 Some(text_edit) => Ok(Some(to_proto::text_document_edit(&snap, file_id, text_edit)?)), 1424 Some(text_edit) => {
1445 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![]),
1446 } 1429 }
1447} 1430}
1448 1431
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index 8b874239c..d9a5030a0 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -39,6 +39,9 @@ mod op_queue;
39pub mod lsp_ext; 39pub mod lsp_ext;
40pub mod config; 40pub mod config;
41 41
42#[cfg(test)]
43mod benchmarks;
44
42use serde::de::DeserializeOwned; 45use serde::de::DeserializeOwned;
43use std::fmt; 46use std::fmt;
44 47
diff --git a/crates/rust-analyzer/src/lsp_ext.rs b/crates/rust-analyzer/src/lsp_ext.rs
index 0e1fec209..d648cda32 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 {}
@@ -407,7 +407,7 @@ pub enum MoveItem {}
407 407
408impl Request for MoveItem { 408impl Request for MoveItem {
409 type Params = MoveItemParams; 409 type Params = MoveItemParams;
410 type Result = Option<lsp_types::TextDocumentEdit>; 410 type Result = Vec<SnippetTextEdit>;
411 const METHOD: &'static str = "experimental/moveItem"; 411 const METHOD: &'static str = "experimental/moveItem";
412} 412}
413 413
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/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..e51532d88 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
@@ -337,14 +345,6 @@ impl GlobalState {
337 }; 345 };
338 change.set_crate_graph(crate_graph); 346 change.set_crate_graph(crate_graph);
339 347
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; 348 self.source_root_config = project_folders.source_root_config;
349 self.workspaces = Arc::new(workspaces); 349 self.workspaces = Arc::new(workspaces);
350 self.workspace_build_data = workspace_build_data; 350 self.workspace_build_data = workspace_build_data;
@@ -355,6 +355,32 @@ impl GlobalState {
355 log::info!("did switch workspaces"); 355 log::info!("did switch workspaces");
356 } 356 }
357 357
358 fn fetch_workspace_error(&self) -> Option<String> {
359 let mut buf = String::new();
360
361 for ws in self.fetch_workspaces_queue.last_op_result() {
362 if let Err(err) = ws {
363 stdx::format_to!(buf, "rust-analyzer failed to load workspace: {:#}\n", err);
364 }
365 }
366
367 if buf.is_empty() {
368 return None;
369 }
370
371 Some(buf)
372 }
373
374 fn build_data_error(&self) -> Option<String> {
375 match self.fetch_build_data_queue.last_op_result() {
376 Some(Err(err)) => {
377 Some(format!("rust-analyzer failed to fetch build data: {:#}\n", err))
378 }
379 Some(Ok(data)) => data.error(),
380 None => None,
381 }
382 }
383
358 fn reload_flycheck(&mut self) { 384 fn reload_flycheck(&mut self) {
359 let _p = profile::span("GlobalState::reload_flycheck"); 385 let _p = profile::span("GlobalState::reload_flycheck");
360 let config = match self.config.flycheck() { 386 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 a3c5e9ccf..adc059817 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 (COMPARISION, "comparision"),
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"),
@@ -88,6 +93,7 @@ define_semantic_token_modifiers![
88 (CONSUMING, "consuming"), 93 (CONSUMING, "consuming"),
89 (UNSAFE, "unsafe"), 94 (UNSAFE, "unsafe"),
90 (ATTRIBUTE_MODIFIER, "attribute"), 95 (ATTRIBUTE_MODIFIER, "attribute"),
96 (TRAIT_MODIFIER, "trait"),
91 (CALLABLE, "callable"), 97 (CALLABLE, "callable"),
92 (INTRA_DOC_LINK, "intraDocLink"), 98 (INTRA_DOC_LINK, "intraDocLink"),
93]; 99];
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 530c8a5a4..1a1f65f3b 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -7,9 +7,9 @@ use std::{
7use ide::{ 7use ide::{
8 Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind, 8 Annotation, AnnotationKind, Assist, AssistKind, CallInfo, CompletionItem, CompletionItemKind,
9 CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind, 9 CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit, Fold, FoldKind,
10 Highlight, HlMod, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind, InsertTextFormat, 10 Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint, InlayKind,
11 Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity, SourceChange, 11 InsertTextFormat, Markup, NavigationTarget, ReferenceAccess, RenameError, Runnable, Severity,
12 StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize, 12 SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
13}; 13};
14use itertools::Itertools; 14use itertools::Itertools;
15use serde_json::to_value; 15use serde_json::to_value;
@@ -145,6 +145,23 @@ pub(crate) fn text_edit(line_index: &LineIndex, indel: Indel) -> lsp_types::Text
145 lsp_types::TextEdit { range, new_text } 145 lsp_types::TextEdit { range, new_text }
146} 146}
147 147
148pub(crate) fn completion_text_edit(
149 line_index: &LineIndex,
150 insert_replace_support: Option<lsp_types::Position>,
151 indel: Indel,
152) -> lsp_types::CompletionTextEdit {
153 let text_edit = text_edit(line_index, indel);
154 match insert_replace_support {
155 Some(cursor_pos) => lsp_types::InsertReplaceEdit {
156 new_text: text_edit.new_text,
157 insert: lsp_types::Range { start: text_edit.range.start, end: cursor_pos },
158 replace: text_edit.range,
159 }
160 .into(),
161 None => text_edit.into(),
162 }
163}
164
148pub(crate) fn snippet_text_edit( 165pub(crate) fn snippet_text_edit(
149 line_index: &LineIndex, 166 line_index: &LineIndex,
150 is_snippet: bool, 167 is_snippet: bool,
@@ -179,6 +196,7 @@ pub(crate) fn snippet_text_edit_vec(
179} 196}
180 197
181pub(crate) fn completion_item( 198pub(crate) fn completion_item(
199 insert_replace_support: Option<lsp_types::Position>,
182 line_index: &LineIndex, 200 line_index: &LineIndex,
183 item: CompletionItem, 201 item: CompletionItem,
184) -> Vec<lsp_types::CompletionItem> { 202) -> Vec<lsp_types::CompletionItem> {
@@ -190,7 +208,7 @@ pub(crate) fn completion_item(
190 for indel in item.text_edit().iter() { 208 for indel in item.text_edit().iter() {
191 if indel.delete.contains_range(source_range) { 209 if indel.delete.contains_range(source_range) {
192 text_edit = Some(if indel.delete == source_range { 210 text_edit = Some(if indel.delete == source_range {
193 self::text_edit(line_index, indel.clone()) 211 self::completion_text_edit(line_index, insert_replace_support, indel.clone())
194 } else { 212 } else {
195 assert!(source_range.end() == indel.delete.end()); 213 assert!(source_range.end() == indel.delete.end());
196 let range1 = TextRange::new(indel.delete.start(), source_range.start()); 214 let range1 = TextRange::new(indel.delete.start(), source_range.start());
@@ -198,7 +216,7 @@ pub(crate) fn completion_item(
198 let indel1 = Indel::replace(range1, String::new()); 216 let indel1 = Indel::replace(range1, String::new());
199 let indel2 = Indel::replace(range2, indel.insert.clone()); 217 let indel2 = Indel::replace(range2, indel.insert.clone());
200 additional_text_edits.push(self::text_edit(line_index, indel1)); 218 additional_text_edits.push(self::text_edit(line_index, indel1));
201 self::text_edit(line_index, indel2) 219 self::completion_text_edit(line_index, insert_replace_support, indel2)
202 }) 220 })
203 } else { 221 } else {
204 assert!(source_range.intersect(indel.delete).is_none()); 222 assert!(source_range.intersect(indel.delete).is_none());
@@ -213,7 +231,7 @@ pub(crate) fn completion_item(
213 detail: item.detail().map(|it| it.to_string()), 231 detail: item.detail().map(|it| it.to_string()),
214 filter_text: Some(item.lookup().to_string()), 232 filter_text: Some(item.lookup().to_string()),
215 kind: item.kind().map(completion_item_kind), 233 kind: item.kind().map(completion_item_kind),
216 text_edit: Some(text_edit.into()), 234 text_edit: Some(text_edit),
217 additional_text_edits: Some(additional_text_edits), 235 additional_text_edits: Some(additional_text_edits),
218 documentation: item.documentation().map(documentation), 236 documentation: item.documentation().map(documentation),
219 deprecated: Some(item.deprecated()), 237 deprecated: Some(item.deprecated()),
@@ -445,7 +463,13 @@ fn semantic_token_type_and_modifiers(
445 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER, 463 HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
446 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD, 464 HlTag::Keyword => lsp_types::SemanticTokenType::KEYWORD,
447 HlTag::None => semantic_tokens::GENERIC, 465 HlTag::None => semantic_tokens::GENERIC,
448 HlTag::Operator => lsp_types::SemanticTokenType::OPERATOR, 466 HlTag::Operator(op) => match op {
467 HlOperator::Bitwise => semantic_tokens::BITWISE,
468 HlOperator::Arithmetic => semantic_tokens::ARITHMETIC,
469 HlOperator::Logical => semantic_tokens::LOGICAL,
470 HlOperator::Comparision => semantic_tokens::COMPARISION,
471 HlOperator::Other => semantic_tokens::OPERATOR,
472 },
449 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING, 473 HlTag::StringLiteral => lsp_types::SemanticTokenType::STRING,
450 HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE, 474 HlTag::UnresolvedReference => semantic_tokens::UNRESOLVED_REFERENCE,
451 HlTag::Punctuation(punct) => match punct { 475 HlTag::Punctuation(punct) => match punct {
@@ -474,6 +498,7 @@ fn semantic_token_type_and_modifiers(
474 HlMod::Callable => semantic_tokens::CALLABLE, 498 HlMod::Callable => semantic_tokens::CALLABLE,
475 HlMod::Static => lsp_types::SemanticTokenModifier::STATIC, 499 HlMod::Static => lsp_types::SemanticTokenModifier::STATIC,
476 HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK, 500 HlMod::IntraDocLink => semantic_tokens::INTRA_DOC_LINK,
501 HlMod::Trait => semantic_tokens::TRAIT_MODIFIER,
477 HlMod::Associated => continue, 502 HlMod::Associated => continue,
478 }; 503 };
479 mods |= modifier; 504 mods |= modifier;
@@ -492,7 +517,12 @@ pub(crate) fn folding_range(
492 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment), 517 FoldKind::Comment => Some(lsp_types::FoldingRangeKind::Comment),
493 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports), 518 FoldKind::Imports => Some(lsp_types::FoldingRangeKind::Imports),
494 FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region), 519 FoldKind::Region => Some(lsp_types::FoldingRangeKind::Region),
495 FoldKind::Mods | FoldKind::Block | FoldKind::ArgList => None, 520 FoldKind::Mods
521 | FoldKind::Block
522 | FoldKind::ArgList
523 | FoldKind::Consts
524 | FoldKind::Statics
525 | FoldKind::Array => None,
496 }; 526 };
497 527
498 let range = range(line_index, fold.range); 528 let range = range(line_index, fold.range);
@@ -658,18 +688,6 @@ pub(crate) fn goto_definition_response(
658 } 688 }
659} 689}
660 690
661pub(crate) fn text_document_edit(
662 snap: &GlobalStateSnapshot,
663 file_id: FileId,
664 edit: TextEdit,
665) -> Result<lsp_types::TextDocumentEdit> {
666 let text_document = optional_versioned_text_document_identifier(snap, file_id);
667 let line_index = snap.file_line_index(file_id)?;
668 let edits =
669 edit.into_iter().map(|it| lsp_types::OneOf::Left(text_edit(&line_index, it))).collect();
670 Ok(lsp_types::TextDocumentEdit { text_document, edits })
671}
672
673pub(crate) fn snippet_text_document_edit( 691pub(crate) fn snippet_text_document_edit(
674 snap: &GlobalStateSnapshot, 692 snap: &GlobalStateSnapshot,
675 is_snippet: bool, 693 is_snippet: bool,
@@ -819,40 +837,31 @@ pub(crate) fn code_action_kind(kind: AssistKind) -> lsp_types::CodeActionKind {
819 } 837 }
820} 838}
821 839
822pub(crate) fn unresolved_code_action( 840pub(crate) fn code_action(
823 snap: &GlobalStateSnapshot, 841 snap: &GlobalStateSnapshot,
824 code_action_params: lsp_types::CodeActionParams,
825 assist: Assist, 842 assist: Assist,
826 index: usize, 843 resolve_data: Option<(usize, lsp_types::CodeActionParams)>,
827) -> Result<lsp_ext::CodeAction> { 844) -> Result<lsp_ext::CodeAction> {
828 assert!(assist.source_change.is_none()); 845 let mut res = lsp_ext::CodeAction {
829 let res = lsp_ext::CodeAction {
830 title: assist.label.to_string(), 846 title: assist.label.to_string(),
831 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0), 847 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
832 kind: Some(code_action_kind(assist.id.1)), 848 kind: Some(code_action_kind(assist.id.1)),
833 edit: None, 849 edit: None,
834 is_preferred: None, 850 is_preferred: None,
835 data: Some(lsp_ext::CodeActionData {
836 id: format!("{}:{}", assist.id.0, index.to_string()),
837 code_action_params,
838 }),
839 };
840 Ok(res)
841}
842
843pub(crate) fn resolved_code_action(
844 snap: &GlobalStateSnapshot,
845 assist: Assist,
846) -> Result<lsp_ext::CodeAction> {
847 let change = assist.source_change.unwrap();
848 let res = lsp_ext::CodeAction {
849 edit: Some(snippet_workspace_edit(snap, change)?),
850 title: assist.label.to_string(),
851 group: assist.group.filter(|_| snap.config.code_action_group()).map(|gr| gr.0),
852 kind: Some(code_action_kind(assist.id.1)),
853 is_preferred: None,
854 data: None, 851 data: None,
855 }; 852 };
853 match (assist.source_change, resolve_data) {
854 (Some(it), _) => res.edit = Some(snippet_workspace_edit(snap, it)?),
855 (None, Some((index, code_action_params))) => {
856 res.data = Some(lsp_ext::CodeActionData {
857 id: format!("{}:{}", assist.id.0, index.to_string()),
858 code_action_params,
859 });
860 }
861 (None, None) => {
862 stdx::never!("assist should always be resolved if client can't do lazy resolving")
863 }
864 };
856 Ok(res) 865 Ok(res)
857} 866}
858 867
@@ -1130,7 +1139,7 @@ mod tests {
1130 .unwrap() 1139 .unwrap()
1131 .into_iter() 1140 .into_iter()
1132 .filter(|c| c.label().ends_with("arg")) 1141 .filter(|c| c.label().ends_with("arg"))
1133 .map(|c| completion_item(&line_index, c)) 1142 .map(|c| completion_item(None, &line_index, c))
1134 .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text))) 1143 .flat_map(|comps| comps.into_iter().map(|c| (c.label, c.sort_text)))
1135 .collect(); 1144 .collect();
1136 expect_test::expect![[r#" 1145 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..52a2674d5 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 }]),
@@ -527,7 +525,7 @@ version = \"0.0.0\"
527#[test] 525#[test]
528fn out_dirs_check() { 526fn out_dirs_check() {
529 if skip_slow_tests() { 527 if skip_slow_tests() {
530 return; 528 // return;
531 } 529 }
532 530
533 let server = Project::with_fixture( 531 let server = Project::with_fixture(
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/src/lib.rs b/crates/stdx/src/lib.rs
index d26be4853..b0a18d58d 100644
--- a/crates/stdx/src/lib.rs
+++ b/crates/stdx/src/lib.rs
@@ -178,6 +178,7 @@ where
178 start..start + len 178 start..start + len
179} 179}
180 180
181#[repr(transparent)]
181pub struct JodChild(pub process::Child); 182pub struct JodChild(pub process::Child);
182 183
183impl ops::Deref for JodChild { 184impl ops::Deref for JodChild {
@@ -200,6 +201,13 @@ impl Drop for JodChild {
200 } 201 }
201} 202}
202 203
204impl JodChild {
205 pub fn into_inner(self) -> process::Child {
206 // SAFETY: repr transparent
207 unsafe { std::mem::transmute::<JodChild, process::Child>(self) }
208 }
209}
210
203#[cfg(test)] 211#[cfg(test)]
204mod tests { 212mod tests {
205 use super::*; 213 use super::*;
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 9f01acc26..a8c1a8075 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 = "714.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/make.rs b/crates/syntax/src/ast/make.rs
index c6a7b99b7..94d4f2cf0 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
@@ -292,11 +296,13 @@ pub fn wildcard_pat() -> ast::WildcardPat {
292 296
293/// Creates a tuple of patterns from an iterator of patterns. 297/// Creates a tuple of patterns from an iterator of patterns.
294/// 298///
295/// Invariant: `pats` must be length > 1 299/// Invariant: `pats` must be length > 0
296///
297/// FIXME handle `pats` length == 1
298pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat { 300pub fn tuple_pat(pats: impl IntoIterator<Item = ast::Pat>) -> ast::TuplePat {
299 let pats_str = pats.into_iter().map(|p| p.to_string()).join(", "); 301 let mut count: usize = 0;
302 let mut pats_str = pats.into_iter().inspect(|_| count += 1).join(", ");
303 if count == 1 {
304 pats_str.push(',');
305 }
300 return from_text(&format!("({})", pats_str)); 306 return from_text(&format!("({})", pats_str));
301 307
302 fn from_text(text: &str) -> ast::TuplePat { 308 fn from_text(text: &str) -> ast::TuplePat {
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}