diff options
Diffstat (limited to 'crates')
114 files changed, 5010 insertions, 2634 deletions
diff --git a/crates/paths/Cargo.toml b/crates/paths/Cargo.toml new file mode 100644 index 000000000..646ee7fd5 --- /dev/null +++ b/crates/paths/Cargo.toml | |||
@@ -0,0 +1,8 @@ | |||
1 | [package] | ||
2 | name = "paths" | ||
3 | version = "0.1.0" | ||
4 | authors = ["rust-analyzer developers"] | ||
5 | edition = "2018" | ||
6 | |||
7 | [lib] | ||
8 | doctest = false | ||
diff --git a/crates/paths/src/lib.rs b/crates/paths/src/lib.rs new file mode 100644 index 000000000..c7ce0c42f --- /dev/null +++ b/crates/paths/src/lib.rs | |||
@@ -0,0 +1,123 @@ | |||
1 | //! Thin wrappers around `std::path`, distinguishing between absolute and | ||
2 | //! relative paths. | ||
3 | use std::{ | ||
4 | convert::{TryFrom, TryInto}, | ||
5 | ops, | ||
6 | path::{Component, Path, PathBuf}, | ||
7 | }; | ||
8 | |||
9 | #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)] | ||
10 | pub struct AbsPathBuf(PathBuf); | ||
11 | |||
12 | impl From<AbsPathBuf> for PathBuf { | ||
13 | fn from(AbsPathBuf(path_buf): AbsPathBuf) -> PathBuf { | ||
14 | path_buf | ||
15 | } | ||
16 | } | ||
17 | |||
18 | impl ops::Deref for AbsPathBuf { | ||
19 | type Target = AbsPath; | ||
20 | fn deref(&self) -> &AbsPath { | ||
21 | self.as_path() | ||
22 | } | ||
23 | } | ||
24 | |||
25 | impl AsRef<Path> for AbsPathBuf { | ||
26 | fn as_ref(&self) -> &Path { | ||
27 | self.0.as_path() | ||
28 | } | ||
29 | } | ||
30 | |||
31 | impl TryFrom<PathBuf> for AbsPathBuf { | ||
32 | type Error = PathBuf; | ||
33 | fn try_from(path_buf: PathBuf) -> Result<AbsPathBuf, PathBuf> { | ||
34 | if !path_buf.is_absolute() { | ||
35 | return Err(path_buf); | ||
36 | } | ||
37 | Ok(AbsPathBuf(path_buf)) | ||
38 | } | ||
39 | } | ||
40 | |||
41 | impl TryFrom<&str> for AbsPathBuf { | ||
42 | type Error = PathBuf; | ||
43 | fn try_from(path: &str) -> Result<AbsPathBuf, PathBuf> { | ||
44 | AbsPathBuf::try_from(PathBuf::from(path)) | ||
45 | } | ||
46 | } | ||
47 | |||
48 | impl AbsPathBuf { | ||
49 | pub fn as_path(&self) -> &AbsPath { | ||
50 | AbsPath::new_unchecked(self.0.as_path()) | ||
51 | } | ||
52 | pub fn pop(&mut self) -> bool { | ||
53 | self.0.pop() | ||
54 | } | ||
55 | } | ||
56 | |||
57 | #[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Hash)] | ||
58 | #[repr(transparent)] | ||
59 | pub struct AbsPath(Path); | ||
60 | |||
61 | impl ops::Deref for AbsPath { | ||
62 | type Target = Path; | ||
63 | fn deref(&self) -> &Path { | ||
64 | &self.0 | ||
65 | } | ||
66 | } | ||
67 | |||
68 | impl AsRef<Path> for AbsPath { | ||
69 | fn as_ref(&self) -> &Path { | ||
70 | &self.0 | ||
71 | } | ||
72 | } | ||
73 | |||
74 | impl<'a> TryFrom<&'a Path> for &'a AbsPath { | ||
75 | type Error = &'a Path; | ||
76 | fn try_from(path: &'a Path) -> Result<&'a AbsPath, &'a Path> { | ||
77 | if !path.is_absolute() { | ||
78 | return Err(path); | ||
79 | } | ||
80 | Ok(AbsPath::new_unchecked(path)) | ||
81 | } | ||
82 | } | ||
83 | |||
84 | impl AbsPath { | ||
85 | fn new_unchecked(path: &Path) -> &AbsPath { | ||
86 | unsafe { &*(path as *const Path as *const AbsPath) } | ||
87 | } | ||
88 | |||
89 | pub fn join(&self, path: impl AsRef<Path>) -> AbsPathBuf { | ||
90 | self.as_ref().join(path).try_into().unwrap() | ||
91 | } | ||
92 | pub fn normalize(&self) -> AbsPathBuf { | ||
93 | AbsPathBuf(normalize_path(&self.0)) | ||
94 | } | ||
95 | } | ||
96 | |||
97 | // https://github.com/rust-lang/cargo/blob/79c769c3d7b4c2cf6a93781575b7f592ef974255/src/cargo/util/paths.rs#L60-L85 | ||
98 | fn normalize_path(path: &Path) -> PathBuf { | ||
99 | let mut components = path.components().peekable(); | ||
100 | let mut ret = if let Some(c @ Component::Prefix(..)) = components.peek().cloned() { | ||
101 | components.next(); | ||
102 | PathBuf::from(c.as_os_str()) | ||
103 | } else { | ||
104 | PathBuf::new() | ||
105 | }; | ||
106 | |||
107 | for component in components { | ||
108 | match component { | ||
109 | Component::Prefix(..) => unreachable!(), | ||
110 | Component::RootDir => { | ||
111 | ret.push(component.as_os_str()); | ||
112 | } | ||
113 | Component::CurDir => {} | ||
114 | Component::ParentDir => { | ||
115 | ret.pop(); | ||
116 | } | ||
117 | Component::Normal(c) => { | ||
118 | ret.push(c); | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | ret | ||
123 | } | ||
diff --git a/crates/ra_assists/src/assist_context.rs b/crates/ra_assists/src/assist_context.rs index edd8255f4..ee614de72 100644 --- a/crates/ra_assists/src/assist_context.rs +++ b/crates/ra_assists/src/assist_context.rs | |||
@@ -252,7 +252,7 @@ impl AssistBuilder { | |||
252 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { | 252 | pub(crate) fn rewrite(&mut self, rewriter: SyntaxRewriter) { |
253 | let node = rewriter.rewrite_root().unwrap(); | 253 | let node = rewriter.rewrite_root().unwrap(); |
254 | let new = rewriter.rewrite(&node); | 254 | let new = rewriter.rewrite(&node); |
255 | algo::diff(&node, &new).into_text_edit(&mut self.edit) | 255 | algo::diff(&node, &new).into_text_edit(&mut self.edit); |
256 | } | 256 | } |
257 | 257 | ||
258 | // FIXME: kill this API | 258 | // FIXME: kill this API |
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 3079a02a2..00fa95b6c 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -106,6 +106,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
106 | _ => return None, | 106 | _ => return None, |
107 | }; | 107 | }; |
108 | // FIXME: use `hir::Path::from_src` instead. | 108 | // FIXME: use `hir::Path::from_src` instead. |
109 | #[allow(deprecated)] | ||
109 | let path = hir::Path::from_ast(path)?; | 110 | let path = hir::Path::from_ast(path)?; |
110 | let resolution = self.source_scope.resolve_hir_path(&path)?; | 111 | let resolution = self.source_scope.resolve_hir_path(&path)?; |
111 | match resolution { | 112 | match resolution { |
@@ -150,6 +151,7 @@ impl<'a> QualifyPaths<'a> { | |||
150 | return None; | 151 | return None; |
151 | } | 152 | } |
152 | // FIXME: use `hir::Path::from_src` instead. | 153 | // FIXME: use `hir::Path::from_src` instead. |
154 | #[allow(deprecated)] | ||
153 | let hir_path = hir::Path::from_ast(p.clone()); | 155 | let hir_path = hir::Path::from_ast(p.clone()); |
154 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 156 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
155 | match resolution { | 157 | match resolution { |
diff --git a/crates/ra_assists/src/handlers/auto_import.rs b/crates/ra_assists/src/handlers/auto_import.rs index edf96d50e..5092bf336 100644 --- a/crates/ra_assists/src/handlers/auto_import.rs +++ b/crates/ra_assists/src/handlers/auto_import.rs | |||
@@ -130,7 +130,7 @@ impl AutoImportAssets { | |||
130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { | 130 | fn search_for_imports(&self, db: &RootDatabase) -> BTreeSet<ModPath> { |
131 | let _p = profile("auto_import::search_for_imports"); | 131 | let _p = profile("auto_import::search_for_imports"); |
132 | let current_crate = self.module_with_name_to_import.krate(); | 132 | let current_crate = self.module_with_name_to_import.krate(); |
133 | ImportsLocator::new(db) | 133 | ImportsLocator::new(db, current_crate) |
134 | .find_imports(&self.get_search_query()) | 134 | .find_imports(&self.get_search_query()) |
135 | .into_iter() | 135 | .into_iter() |
136 | .filter_map(|candidate| match &self.import_candidate { | 136 | .filter_map(|candidate| match &self.import_candidate { |
@@ -841,4 +841,105 @@ fn main() { | |||
841 | ", | 841 | ", |
842 | ) | 842 | ) |
843 | } | 843 | } |
844 | |||
845 | #[test] | ||
846 | fn dep_import() { | ||
847 | check_assist( | ||
848 | auto_import, | ||
849 | r" | ||
850 | //- /lib.rs crate:dep | ||
851 | pub struct Struct; | ||
852 | |||
853 | //- /main.rs crate:main deps:dep | ||
854 | fn main() { | ||
855 | Struct<|> | ||
856 | }", | ||
857 | r"use dep::Struct; | ||
858 | |||
859 | fn main() { | ||
860 | Struct | ||
861 | } | ||
862 | ", | ||
863 | ); | ||
864 | } | ||
865 | |||
866 | #[test] | ||
867 | fn whole_segment() { | ||
868 | // Tests that only imports whose last segment matches the identifier get suggested. | ||
869 | check_assist( | ||
870 | auto_import, | ||
871 | r" | ||
872 | //- /lib.rs crate:dep | ||
873 | pub mod fmt { | ||
874 | pub trait Display {} | ||
875 | } | ||
876 | |||
877 | pub fn panic_fmt() {} | ||
878 | |||
879 | //- /main.rs crate:main deps:dep | ||
880 | struct S; | ||
881 | |||
882 | impl f<|>mt::Display for S {}", | ||
883 | r"use dep::fmt; | ||
884 | |||
885 | struct S; | ||
886 | impl fmt::Display for S {} | ||
887 | ", | ||
888 | ); | ||
889 | } | ||
890 | |||
891 | #[test] | ||
892 | fn macro_generated() { | ||
893 | // Tests that macro-generated items are suggested from external crates. | ||
894 | check_assist( | ||
895 | auto_import, | ||
896 | r" | ||
897 | //- /lib.rs crate:dep | ||
898 | |||
899 | macro_rules! mac { | ||
900 | () => { | ||
901 | pub struct Cheese; | ||
902 | }; | ||
903 | } | ||
904 | |||
905 | mac!(); | ||
906 | |||
907 | //- /main.rs crate:main deps:dep | ||
908 | |||
909 | fn main() { | ||
910 | Cheese<|>; | ||
911 | }", | ||
912 | r"use dep::Cheese; | ||
913 | |||
914 | fn main() { | ||
915 | Cheese; | ||
916 | } | ||
917 | ", | ||
918 | ); | ||
919 | } | ||
920 | |||
921 | #[test] | ||
922 | fn casing() { | ||
923 | // Tests that differently cased names don't interfere and we only suggest the matching one. | ||
924 | check_assist( | ||
925 | auto_import, | ||
926 | r" | ||
927 | //- /lib.rs crate:dep | ||
928 | |||
929 | pub struct FMT; | ||
930 | pub struct fmt; | ||
931 | |||
932 | //- /main.rs crate:main deps:dep | ||
933 | |||
934 | fn main() { | ||
935 | FMT<|>; | ||
936 | }", | ||
937 | r"use dep::FMT; | ||
938 | |||
939 | fn main() { | ||
940 | FMT; | ||
941 | } | ||
942 | ", | ||
943 | ); | ||
944 | } | ||
844 | } | 945 | } |
diff --git a/crates/ra_assists/src/handlers/fill_match_arms.rs b/crates/ra_assists/src/handlers/fill_match_arms.rs index cc303285b..569efb768 100644 --- a/crates/ra_assists/src/handlers/fill_match_arms.rs +++ b/crates/ra_assists/src/handlers/fill_match_arms.rs | |||
@@ -136,8 +136,20 @@ fn is_variant_missing(existing_arms: &mut Vec<MatchArm>, var: &Pat) -> bool { | |||
136 | } | 136 | } |
137 | 137 | ||
138 | fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { | 138 | fn does_pat_match_variant(pat: &Pat, var: &Pat) -> bool { |
139 | let pat_head = pat.syntax().first_child().map(|node| node.text()); | 139 | let first_node_text = |pat: &Pat| pat.syntax().first_child().map(|node| node.text()); |
140 | let var_head = var.syntax().first_child().map(|node| node.text()); | 140 | |
141 | let pat_head = match pat { | ||
142 | Pat::BindPat(bind_pat) => { | ||
143 | if let Some(p) = bind_pat.pat() { | ||
144 | first_node_text(&p) | ||
145 | } else { | ||
146 | return false; | ||
147 | } | ||
148 | } | ||
149 | pat => first_node_text(pat), | ||
150 | }; | ||
151 | |||
152 | let var_head = first_node_text(var); | ||
141 | 153 | ||
142 | pat_head == var_head | 154 | pat_head == var_head |
143 | } | 155 | } |
@@ -351,6 +363,40 @@ mod tests { | |||
351 | } | 363 | } |
352 | 364 | ||
353 | #[test] | 365 | #[test] |
366 | fn partial_fill_bind_pat() { | ||
367 | check_assist( | ||
368 | fill_match_arms, | ||
369 | r#" | ||
370 | enum A { | ||
371 | As, | ||
372 | Bs, | ||
373 | Cs(Option<i32>), | ||
374 | } | ||
375 | fn main() { | ||
376 | match A::As<|> { | ||
377 | A::As(_) => {} | ||
378 | a @ A::Bs(_) => {} | ||
379 | } | ||
380 | } | ||
381 | "#, | ||
382 | r#" | ||
383 | enum A { | ||
384 | As, | ||
385 | Bs, | ||
386 | Cs(Option<i32>), | ||
387 | } | ||
388 | fn main() { | ||
389 | match A::As { | ||
390 | A::As(_) => {} | ||
391 | a @ A::Bs(_) => {} | ||
392 | $0A::Cs(_) => {} | ||
393 | } | ||
394 | } | ||
395 | "#, | ||
396 | ); | ||
397 | } | ||
398 | |||
399 | #[test] | ||
354 | fn fill_match_arms_empty_body() { | 400 | fn fill_match_arms_empty_body() { |
355 | check_assist( | 401 | check_assist( |
356 | fill_match_arms, | 402 | fill_match_arms, |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 0197a8cf0..b4784c333 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -1,7 +1,10 @@ | |||
1 | use hir; | 1 | use hir; |
2 | use ra_syntax::{ast, AstNode, SmolStr, TextRange}; | 2 | use ra_syntax::{algo::SyntaxRewriter, ast, match_ast, AstNode, SmolStr, SyntaxNode}; |
3 | 3 | ||
4 | use crate::{utils::insert_use_statement, AssistContext, AssistId, Assists}; | 4 | use crate::{ |
5 | utils::{find_insert_use_container, insert_use_statement}, | ||
6 | AssistContext, AssistId, Assists, | ||
7 | }; | ||
5 | 8 | ||
6 | // Assist: replace_qualified_name_with_use | 9 | // Assist: replace_qualified_name_with_use |
7 | // | 10 | // |
@@ -39,16 +42,18 @@ pub(crate) fn replace_qualified_name_with_use( | |||
39 | target, | 42 | target, |
40 | |builder| { | 43 | |builder| { |
41 | let path_to_import = hir_path.mod_path().clone(); | 44 | let path_to_import = hir_path.mod_path().clone(); |
45 | let container = match find_insert_use_container(path.syntax(), ctx) { | ||
46 | Some(c) => c, | ||
47 | None => return, | ||
48 | }; | ||
42 | insert_use_statement(path.syntax(), &path_to_import, ctx, builder.text_edit_builder()); | 49 | insert_use_statement(path.syntax(), &path_to_import, ctx, builder.text_edit_builder()); |
43 | 50 | ||
44 | if let Some(last) = path.segment() { | 51 | // Now that we've brought the name into scope, re-qualify all paths that could be |
45 | // Here we are assuming the assist will provide a correct use statement | 52 | // affected (that is, all paths inside the node we added the `use` to). |
46 | // so we can delete the path qualifier | 53 | let mut rewriter = SyntaxRewriter::default(); |
47 | builder.delete(TextRange::new( | 54 | let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone()); |
48 | path.syntax().text_range().start(), | 55 | shorten_paths(&mut rewriter, syntax, path); |
49 | last.syntax().text_range().start(), | 56 | builder.rewrite(rewriter); |
50 | )); | ||
51 | } | ||
52 | }, | 57 | }, |
53 | ) | 58 | ) |
54 | } | 59 | } |
@@ -73,6 +78,69 @@ fn collect_hir_path_segments(path: &hir::Path) -> Option<Vec<SmolStr>> { | |||
73 | Some(ps) | 78 | Some(ps) |
74 | } | 79 | } |
75 | 80 | ||
81 | /// Adds replacements to `re` that shorten `path` in all descendants of `node`. | ||
82 | fn shorten_paths(rewriter: &mut SyntaxRewriter<'static>, node: SyntaxNode, path: ast::Path) { | ||
83 | for child in node.children() { | ||
84 | match_ast! { | ||
85 | match child { | ||
86 | // Don't modify `use` items, as this can break the `use` item when injecting a new | ||
87 | // import into the use tree. | ||
88 | ast::UseItem(_it) => continue, | ||
89 | // Don't descend into submodules, they don't have the same `use` items in scope. | ||
90 | ast::Module(_it) => continue, | ||
91 | |||
92 | ast::Path(p) => { | ||
93 | match maybe_replace_path(rewriter, p.clone(), path.clone()) { | ||
94 | Some(()) => {}, | ||
95 | None => shorten_paths(rewriter, p.syntax().clone(), path.clone()), | ||
96 | } | ||
97 | }, | ||
98 | _ => shorten_paths(rewriter, child, path.clone()), | ||
99 | } | ||
100 | } | ||
101 | } | ||
102 | } | ||
103 | |||
104 | fn maybe_replace_path( | ||
105 | rewriter: &mut SyntaxRewriter<'static>, | ||
106 | path: ast::Path, | ||
107 | target: ast::Path, | ||
108 | ) -> Option<()> { | ||
109 | if !path_eq(path.clone(), target.clone()) { | ||
110 | return None; | ||
111 | } | ||
112 | |||
113 | // Shorten `path`, leaving only its last segment. | ||
114 | if let Some(parent) = path.qualifier() { | ||
115 | rewriter.delete(parent.syntax()); | ||
116 | } | ||
117 | if let Some(double_colon) = path.coloncolon_token() { | ||
118 | rewriter.delete(&double_colon); | ||
119 | } | ||
120 | |||
121 | Some(()) | ||
122 | } | ||
123 | |||
124 | fn path_eq(lhs: ast::Path, rhs: ast::Path) -> bool { | ||
125 | let mut lhs_curr = lhs; | ||
126 | let mut rhs_curr = rhs; | ||
127 | loop { | ||
128 | match (lhs_curr.segment(), rhs_curr.segment()) { | ||
129 | (Some(lhs), Some(rhs)) if lhs.syntax().text() == rhs.syntax().text() => (), | ||
130 | _ => return false, | ||
131 | } | ||
132 | |||
133 | match (lhs_curr.qualifier(), rhs_curr.qualifier()) { | ||
134 | (Some(lhs), Some(rhs)) => { | ||
135 | lhs_curr = lhs; | ||
136 | rhs_curr = rhs; | ||
137 | } | ||
138 | (None, None) => return true, | ||
139 | _ => return false, | ||
140 | } | ||
141 | } | ||
142 | } | ||
143 | |||
76 | #[cfg(test)] | 144 | #[cfg(test)] |
77 | mod tests { | 145 | mod tests { |
78 | use crate::tests::{check_assist, check_assist_not_applicable}; | 146 | use crate::tests::{check_assist, check_assist_not_applicable}; |
@@ -83,10 +151,10 @@ mod tests { | |||
83 | fn test_replace_add_use_no_anchor() { | 151 | fn test_replace_add_use_no_anchor() { |
84 | check_assist( | 152 | check_assist( |
85 | replace_qualified_name_with_use, | 153 | replace_qualified_name_with_use, |
86 | " | 154 | r" |
87 | std::fmt::Debug<|> | 155 | std::fmt::Debug<|> |
88 | ", | 156 | ", |
89 | " | 157 | r" |
90 | use std::fmt::Debug; | 158 | use std::fmt::Debug; |
91 | 159 | ||
92 | Debug | 160 | Debug |
@@ -97,13 +165,13 @@ Debug | |||
97 | fn test_replace_add_use_no_anchor_with_item_below() { | 165 | fn test_replace_add_use_no_anchor_with_item_below() { |
98 | check_assist( | 166 | check_assist( |
99 | replace_qualified_name_with_use, | 167 | replace_qualified_name_with_use, |
100 | " | 168 | r" |
101 | std::fmt::Debug<|> | 169 | std::fmt::Debug<|> |
102 | 170 | ||
103 | fn main() { | 171 | fn main() { |
104 | } | 172 | } |
105 | ", | 173 | ", |
106 | " | 174 | r" |
107 | use std::fmt::Debug; | 175 | use std::fmt::Debug; |
108 | 176 | ||
109 | Debug | 177 | Debug |
@@ -118,13 +186,13 @@ fn main() { | |||
118 | fn test_replace_add_use_no_anchor_with_item_above() { | 186 | fn test_replace_add_use_no_anchor_with_item_above() { |
119 | check_assist( | 187 | check_assist( |
120 | replace_qualified_name_with_use, | 188 | replace_qualified_name_with_use, |
121 | " | 189 | r" |
122 | fn main() { | 190 | fn main() { |
123 | } | 191 | } |
124 | 192 | ||
125 | std::fmt::Debug<|> | 193 | std::fmt::Debug<|> |
126 | ", | 194 | ", |
127 | " | 195 | r" |
128 | use std::fmt::Debug; | 196 | use std::fmt::Debug; |
129 | 197 | ||
130 | fn main() { | 198 | fn main() { |
@@ -139,10 +207,10 @@ Debug | |||
139 | fn test_replace_add_use_no_anchor_2seg() { | 207 | fn test_replace_add_use_no_anchor_2seg() { |
140 | check_assist( | 208 | check_assist( |
141 | replace_qualified_name_with_use, | 209 | replace_qualified_name_with_use, |
142 | " | 210 | r" |
143 | std::fmt<|>::Debug | 211 | std::fmt<|>::Debug |
144 | ", | 212 | ", |
145 | " | 213 | r" |
146 | use std::fmt; | 214 | use std::fmt; |
147 | 215 | ||
148 | fmt::Debug | 216 | fmt::Debug |
@@ -154,13 +222,13 @@ fmt::Debug | |||
154 | fn test_replace_add_use() { | 222 | fn test_replace_add_use() { |
155 | check_assist( | 223 | check_assist( |
156 | replace_qualified_name_with_use, | 224 | replace_qualified_name_with_use, |
157 | " | 225 | r" |
158 | use stdx; | 226 | use stdx; |
159 | 227 | ||
160 | impl std::fmt::Debug<|> for Foo { | 228 | impl std::fmt::Debug<|> for Foo { |
161 | } | 229 | } |
162 | ", | 230 | ", |
163 | " | 231 | r" |
164 | use stdx; | 232 | use stdx; |
165 | use std::fmt::Debug; | 233 | use std::fmt::Debug; |
166 | 234 | ||
@@ -174,11 +242,11 @@ impl Debug for Foo { | |||
174 | fn test_replace_file_use_other_anchor() { | 242 | fn test_replace_file_use_other_anchor() { |
175 | check_assist( | 243 | check_assist( |
176 | replace_qualified_name_with_use, | 244 | replace_qualified_name_with_use, |
177 | " | 245 | r" |
178 | impl std::fmt::Debug<|> for Foo { | 246 | impl std::fmt::Debug<|> for Foo { |
179 | } | 247 | } |
180 | ", | 248 | ", |
181 | " | 249 | r" |
182 | use std::fmt::Debug; | 250 | use std::fmt::Debug; |
183 | 251 | ||
184 | impl Debug for Foo { | 252 | impl Debug for Foo { |
@@ -191,11 +259,11 @@ impl Debug for Foo { | |||
191 | fn test_replace_add_use_other_anchor_indent() { | 259 | fn test_replace_add_use_other_anchor_indent() { |
192 | check_assist( | 260 | check_assist( |
193 | replace_qualified_name_with_use, | 261 | replace_qualified_name_with_use, |
194 | " | 262 | r" |
195 | impl std::fmt::Debug<|> for Foo { | 263 | impl std::fmt::Debug<|> for Foo { |
196 | } | 264 | } |
197 | ", | 265 | ", |
198 | " | 266 | r" |
199 | use std::fmt::Debug; | 267 | use std::fmt::Debug; |
200 | 268 | ||
201 | impl Debug for Foo { | 269 | impl Debug for Foo { |
@@ -208,13 +276,13 @@ impl Debug for Foo { | |||
208 | fn test_replace_split_different() { | 276 | fn test_replace_split_different() { |
209 | check_assist( | 277 | check_assist( |
210 | replace_qualified_name_with_use, | 278 | replace_qualified_name_with_use, |
211 | " | 279 | r" |
212 | use std::fmt; | 280 | use std::fmt; |
213 | 281 | ||
214 | impl std::io<|> for Foo { | 282 | impl std::io<|> for Foo { |
215 | } | 283 | } |
216 | ", | 284 | ", |
217 | " | 285 | r" |
218 | use std::{io, fmt}; | 286 | use std::{io, fmt}; |
219 | 287 | ||
220 | impl io for Foo { | 288 | impl io for Foo { |
@@ -227,13 +295,13 @@ impl io for Foo { | |||
227 | fn test_replace_split_self_for_use() { | 295 | fn test_replace_split_self_for_use() { |
228 | check_assist( | 296 | check_assist( |
229 | replace_qualified_name_with_use, | 297 | replace_qualified_name_with_use, |
230 | " | 298 | r" |
231 | use std::fmt; | 299 | use std::fmt; |
232 | 300 | ||
233 | impl std::fmt::Debug<|> for Foo { | 301 | impl std::fmt::Debug<|> for Foo { |
234 | } | 302 | } |
235 | ", | 303 | ", |
236 | " | 304 | r" |
237 | use std::fmt::{self, Debug, }; | 305 | use std::fmt::{self, Debug, }; |
238 | 306 | ||
239 | impl Debug for Foo { | 307 | impl Debug for Foo { |
@@ -246,13 +314,13 @@ impl Debug for Foo { | |||
246 | fn test_replace_split_self_for_target() { | 314 | fn test_replace_split_self_for_target() { |
247 | check_assist( | 315 | check_assist( |
248 | replace_qualified_name_with_use, | 316 | replace_qualified_name_with_use, |
249 | " | 317 | r" |
250 | use std::fmt::Debug; | 318 | use std::fmt::Debug; |
251 | 319 | ||
252 | impl std::fmt<|> for Foo { | 320 | impl std::fmt<|> for Foo { |
253 | } | 321 | } |
254 | ", | 322 | ", |
255 | " | 323 | r" |
256 | use std::fmt::{self, Debug}; | 324 | use std::fmt::{self, Debug}; |
257 | 325 | ||
258 | impl fmt for Foo { | 326 | impl fmt for Foo { |
@@ -265,13 +333,13 @@ impl fmt for Foo { | |||
265 | fn test_replace_add_to_nested_self_nested() { | 333 | fn test_replace_add_to_nested_self_nested() { |
266 | check_assist( | 334 | check_assist( |
267 | replace_qualified_name_with_use, | 335 | replace_qualified_name_with_use, |
268 | " | 336 | r" |
269 | use std::fmt::{Debug, nested::{Display}}; | 337 | use std::fmt::{Debug, nested::{Display}}; |
270 | 338 | ||
271 | impl std::fmt::nested<|> for Foo { | 339 | impl std::fmt::nested<|> for Foo { |
272 | } | 340 | } |
273 | ", | 341 | ", |
274 | " | 342 | r" |
275 | use std::fmt::{Debug, nested::{Display, self}}; | 343 | use std::fmt::{Debug, nested::{Display, self}}; |
276 | 344 | ||
277 | impl nested for Foo { | 345 | impl nested for Foo { |
@@ -284,13 +352,13 @@ impl nested for Foo { | |||
284 | fn test_replace_add_to_nested_self_already_included() { | 352 | fn test_replace_add_to_nested_self_already_included() { |
285 | check_assist( | 353 | check_assist( |
286 | replace_qualified_name_with_use, | 354 | replace_qualified_name_with_use, |
287 | " | 355 | r" |
288 | use std::fmt::{Debug, nested::{self, Display}}; | 356 | use std::fmt::{Debug, nested::{self, Display}}; |
289 | 357 | ||
290 | impl std::fmt::nested<|> for Foo { | 358 | impl std::fmt::nested<|> for Foo { |
291 | } | 359 | } |
292 | ", | 360 | ", |
293 | " | 361 | r" |
294 | use std::fmt::{Debug, nested::{self, Display}}; | 362 | use std::fmt::{Debug, nested::{self, Display}}; |
295 | 363 | ||
296 | impl nested for Foo { | 364 | impl nested for Foo { |
@@ -303,13 +371,13 @@ impl nested for Foo { | |||
303 | fn test_replace_add_to_nested_nested() { | 371 | fn test_replace_add_to_nested_nested() { |
304 | check_assist( | 372 | check_assist( |
305 | replace_qualified_name_with_use, | 373 | replace_qualified_name_with_use, |
306 | " | 374 | r" |
307 | use std::fmt::{Debug, nested::{Display}}; | 375 | use std::fmt::{Debug, nested::{Display}}; |
308 | 376 | ||
309 | impl std::fmt::nested::Debug<|> for Foo { | 377 | impl std::fmt::nested::Debug<|> for Foo { |
310 | } | 378 | } |
311 | ", | 379 | ", |
312 | " | 380 | r" |
313 | use std::fmt::{Debug, nested::{Display, Debug}}; | 381 | use std::fmt::{Debug, nested::{Display, Debug}}; |
314 | 382 | ||
315 | impl Debug for Foo { | 383 | impl Debug for Foo { |
@@ -322,13 +390,13 @@ impl Debug for Foo { | |||
322 | fn test_replace_split_common_target_longer() { | 390 | fn test_replace_split_common_target_longer() { |
323 | check_assist( | 391 | check_assist( |
324 | replace_qualified_name_with_use, | 392 | replace_qualified_name_with_use, |
325 | " | 393 | r" |
326 | use std::fmt::Debug; | 394 | use std::fmt::Debug; |
327 | 395 | ||
328 | impl std::fmt::nested::Display<|> for Foo { | 396 | impl std::fmt::nested::Display<|> for Foo { |
329 | } | 397 | } |
330 | ", | 398 | ", |
331 | " | 399 | r" |
332 | use std::fmt::{nested::Display, Debug}; | 400 | use std::fmt::{nested::Display, Debug}; |
333 | 401 | ||
334 | impl Display for Foo { | 402 | impl Display for Foo { |
@@ -341,13 +409,13 @@ impl Display for Foo { | |||
341 | fn test_replace_split_common_use_longer() { | 409 | fn test_replace_split_common_use_longer() { |
342 | check_assist( | 410 | check_assist( |
343 | replace_qualified_name_with_use, | 411 | replace_qualified_name_with_use, |
344 | " | 412 | r" |
345 | use std::fmt::nested::Debug; | 413 | use std::fmt::nested::Debug; |
346 | 414 | ||
347 | impl std::fmt::Display<|> for Foo { | 415 | impl std::fmt::Display<|> for Foo { |
348 | } | 416 | } |
349 | ", | 417 | ", |
350 | " | 418 | r" |
351 | use std::fmt::{Display, nested::Debug}; | 419 | use std::fmt::{Display, nested::Debug}; |
352 | 420 | ||
353 | impl Display for Foo { | 421 | impl Display for Foo { |
@@ -360,7 +428,7 @@ impl Display for Foo { | |||
360 | fn test_replace_use_nested_import() { | 428 | fn test_replace_use_nested_import() { |
361 | check_assist( | 429 | check_assist( |
362 | replace_qualified_name_with_use, | 430 | replace_qualified_name_with_use, |
363 | " | 431 | r" |
364 | use crate::{ | 432 | use crate::{ |
365 | ty::{Substs, Ty}, | 433 | ty::{Substs, Ty}, |
366 | AssocItem, | 434 | AssocItem, |
@@ -368,7 +436,7 @@ use crate::{ | |||
368 | 436 | ||
369 | fn foo() { crate::ty::lower<|>::trait_env() } | 437 | fn foo() { crate::ty::lower<|>::trait_env() } |
370 | ", | 438 | ", |
371 | " | 439 | r" |
372 | use crate::{ | 440 | use crate::{ |
373 | ty::{Substs, Ty, lower}, | 441 | ty::{Substs, Ty, lower}, |
374 | AssocItem, | 442 | AssocItem, |
@@ -383,13 +451,13 @@ fn foo() { lower::trait_env() } | |||
383 | fn test_replace_alias() { | 451 | fn test_replace_alias() { |
384 | check_assist( | 452 | check_assist( |
385 | replace_qualified_name_with_use, | 453 | replace_qualified_name_with_use, |
386 | " | 454 | r" |
387 | use std::fmt as foo; | 455 | use std::fmt as foo; |
388 | 456 | ||
389 | impl foo::Debug<|> for Foo { | 457 | impl foo::Debug<|> for Foo { |
390 | } | 458 | } |
391 | ", | 459 | ", |
392 | " | 460 | r" |
393 | use std::fmt as foo; | 461 | use std::fmt as foo; |
394 | 462 | ||
395 | impl Debug for Foo { | 463 | impl Debug for Foo { |
@@ -402,7 +470,7 @@ impl Debug for Foo { | |||
402 | fn test_replace_not_applicable_one_segment() { | 470 | fn test_replace_not_applicable_one_segment() { |
403 | check_assist_not_applicable( | 471 | check_assist_not_applicable( |
404 | replace_qualified_name_with_use, | 472 | replace_qualified_name_with_use, |
405 | " | 473 | r" |
406 | impl foo<|> for Foo { | 474 | impl foo<|> for Foo { |
407 | } | 475 | } |
408 | ", | 476 | ", |
@@ -413,7 +481,7 @@ impl foo<|> for Foo { | |||
413 | fn test_replace_not_applicable_in_use() { | 481 | fn test_replace_not_applicable_in_use() { |
414 | check_assist_not_applicable( | 482 | check_assist_not_applicable( |
415 | replace_qualified_name_with_use, | 483 | replace_qualified_name_with_use, |
416 | " | 484 | r" |
417 | use std::fmt<|>; | 485 | use std::fmt<|>; |
418 | ", | 486 | ", |
419 | ); | 487 | ); |
@@ -423,14 +491,14 @@ use std::fmt<|>; | |||
423 | fn test_replace_add_use_no_anchor_in_mod_mod() { | 491 | fn test_replace_add_use_no_anchor_in_mod_mod() { |
424 | check_assist( | 492 | check_assist( |
425 | replace_qualified_name_with_use, | 493 | replace_qualified_name_with_use, |
426 | " | 494 | r" |
427 | mod foo { | 495 | mod foo { |
428 | mod bar { | 496 | mod bar { |
429 | std::fmt::Debug<|> | 497 | std::fmt::Debug<|> |
430 | } | 498 | } |
431 | } | 499 | } |
432 | ", | 500 | ", |
433 | " | 501 | r" |
434 | mod foo { | 502 | mod foo { |
435 | mod bar { | 503 | mod bar { |
436 | use std::fmt::Debug; | 504 | use std::fmt::Debug; |
@@ -446,14 +514,14 @@ mod foo { | |||
446 | fn inserts_imports_after_inner_attributes() { | 514 | fn inserts_imports_after_inner_attributes() { |
447 | check_assist( | 515 | check_assist( |
448 | replace_qualified_name_with_use, | 516 | replace_qualified_name_with_use, |
449 | " | 517 | r" |
450 | #![allow(dead_code)] | 518 | #![allow(dead_code)] |
451 | 519 | ||
452 | fn main() { | 520 | fn main() { |
453 | std::fmt::Debug<|> | 521 | std::fmt::Debug<|> |
454 | } | 522 | } |
455 | ", | 523 | ", |
456 | " | 524 | r" |
457 | #![allow(dead_code)] | 525 | #![allow(dead_code)] |
458 | use std::fmt::Debug; | 526 | use std::fmt::Debug; |
459 | 527 | ||
@@ -463,4 +531,116 @@ fn main() { | |||
463 | ", | 531 | ", |
464 | ); | 532 | ); |
465 | } | 533 | } |
534 | |||
535 | #[test] | ||
536 | fn replaces_all_affected_paths() { | ||
537 | check_assist( | ||
538 | replace_qualified_name_with_use, | ||
539 | r" | ||
540 | fn main() { | ||
541 | std::fmt::Debug<|>; | ||
542 | let x: std::fmt::Debug = std::fmt::Debug; | ||
543 | } | ||
544 | ", | ||
545 | r" | ||
546 | use std::fmt::Debug; | ||
547 | |||
548 | fn main() { | ||
549 | Debug; | ||
550 | let x: Debug = Debug; | ||
551 | } | ||
552 | ", | ||
553 | ); | ||
554 | } | ||
555 | |||
556 | #[test] | ||
557 | fn replaces_all_affected_paths_mod() { | ||
558 | check_assist( | ||
559 | replace_qualified_name_with_use, | ||
560 | r" | ||
561 | mod m { | ||
562 | fn f() { | ||
563 | std::fmt::Debug<|>; | ||
564 | let x: std::fmt::Debug = std::fmt::Debug; | ||
565 | } | ||
566 | fn g() { | ||
567 | std::fmt::Debug; | ||
568 | } | ||
569 | } | ||
570 | |||
571 | fn f() { | ||
572 | std::fmt::Debug; | ||
573 | } | ||
574 | ", | ||
575 | r" | ||
576 | mod m { | ||
577 | use std::fmt::Debug; | ||
578 | |||
579 | fn f() { | ||
580 | Debug; | ||
581 | let x: Debug = Debug; | ||
582 | } | ||
583 | fn g() { | ||
584 | Debug; | ||
585 | } | ||
586 | } | ||
587 | |||
588 | fn f() { | ||
589 | std::fmt::Debug; | ||
590 | } | ||
591 | ", | ||
592 | ); | ||
593 | } | ||
594 | |||
595 | #[test] | ||
596 | fn does_not_replace_in_submodules() { | ||
597 | check_assist( | ||
598 | replace_qualified_name_with_use, | ||
599 | r" | ||
600 | fn main() { | ||
601 | std::fmt::Debug<|>; | ||
602 | } | ||
603 | |||
604 | mod sub { | ||
605 | fn f() { | ||
606 | std::fmt::Debug; | ||
607 | } | ||
608 | } | ||
609 | ", | ||
610 | r" | ||
611 | use std::fmt::Debug; | ||
612 | |||
613 | fn main() { | ||
614 | Debug; | ||
615 | } | ||
616 | |||
617 | mod sub { | ||
618 | fn f() { | ||
619 | std::fmt::Debug; | ||
620 | } | ||
621 | } | ||
622 | ", | ||
623 | ); | ||
624 | } | ||
625 | |||
626 | #[test] | ||
627 | fn does_not_replace_in_use() { | ||
628 | check_assist( | ||
629 | replace_qualified_name_with_use, | ||
630 | r" | ||
631 | use std::fmt::Display; | ||
632 | |||
633 | fn main() { | ||
634 | std::fmt<|>; | ||
635 | } | ||
636 | ", | ||
637 | r" | ||
638 | use std::fmt::{self, Display}; | ||
639 | |||
640 | fn main() { | ||
641 | fmt; | ||
642 | } | ||
643 | ", | ||
644 | ); | ||
645 | } | ||
466 | } | 646 | } |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 0038a9764..c1ff0de7b 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -13,7 +13,7 @@ use rustc_hash::FxHashSet; | |||
13 | 13 | ||
14 | use crate::assist_config::SnippetCap; | 14 | use crate::assist_config::SnippetCap; |
15 | 15 | ||
16 | pub(crate) use insert_use::insert_use_statement; | 16 | pub(crate) use insert_use::{find_insert_use_container, insert_use_statement}; |
17 | 17 | ||
18 | #[derive(Clone, Copy, Debug)] | 18 | #[derive(Clone, Copy, Debug)] |
19 | pub(crate) enum Cursor<'a> { | 19 | pub(crate) enum Cursor<'a> { |
diff --git a/crates/ra_assists/src/utils/insert_use.rs b/crates/ra_assists/src/utils/insert_use.rs index 0ee43482f..8c4f33e59 100644 --- a/crates/ra_assists/src/utils/insert_use.rs +++ b/crates/ra_assists/src/utils/insert_use.rs | |||
@@ -12,6 +12,20 @@ use ra_syntax::{ | |||
12 | use ra_text_edit::TextEditBuilder; | 12 | use ra_text_edit::TextEditBuilder; |
13 | 13 | ||
14 | use crate::assist_context::AssistContext; | 14 | use crate::assist_context::AssistContext; |
15 | use either::Either; | ||
16 | |||
17 | /// Determines the containing syntax node in which to insert a `use` statement affecting `position`. | ||
18 | pub(crate) fn find_insert_use_container( | ||
19 | position: &SyntaxNode, | ||
20 | ctx: &AssistContext, | ||
21 | ) -> Option<Either<ast::ItemList, ast::SourceFile>> { | ||
22 | ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { | ||
23 | if let Some(module) = ast::Module::cast(n.clone()) { | ||
24 | return module.item_list().map(|it| Either::Left(it)); | ||
25 | } | ||
26 | Some(Either::Right(ast::SourceFile::cast(n)?)) | ||
27 | }) | ||
28 | } | ||
15 | 29 | ||
16 | /// Creates and inserts a use statement for the given path to import. | 30 | /// Creates and inserts a use statement for the given path to import. |
17 | /// The use statement is inserted in the scope most appropriate to the | 31 | /// The use statement is inserted in the scope most appropriate to the |
@@ -24,15 +38,11 @@ pub(crate) fn insert_use_statement( | |||
24 | builder: &mut TextEditBuilder, | 38 | builder: &mut TextEditBuilder, |
25 | ) { | 39 | ) { |
26 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); | 40 | let target = path_to_import.to_string().split("::").map(SmolStr::new).collect::<Vec<_>>(); |
27 | let container = ctx.sema.ancestors_with_macros(position.clone()).find_map(|n| { | 41 | let container = find_insert_use_container(position, ctx); |
28 | if let Some(module) = ast::Module::cast(n.clone()) { | ||
29 | return module.item_list().map(|it| it.syntax().clone()); | ||
30 | } | ||
31 | ast::SourceFile::cast(n).map(|it| it.syntax().clone()) | ||
32 | }); | ||
33 | 42 | ||
34 | if let Some(container) = container { | 43 | if let Some(container) = container { |
35 | let action = best_action_for_target(container, position.clone(), &target); | 44 | let syntax = container.either(|l| l.syntax().clone(), |r| r.syntax().clone()); |
45 | let action = best_action_for_target(syntax, position.clone(), &target); | ||
36 | make_assist(&action, &target, builder); | 46 | make_assist(&action, &target, builder); |
37 | } | 47 | } |
38 | } | 48 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index a8d6466ea..bf26048f2 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -15,12 +15,10 @@ use std::{ | |||
15 | 15 | ||
16 | use ra_cfg::CfgOptions; | 16 | use ra_cfg::CfgOptions; |
17 | use ra_syntax::SmolStr; | 17 | use ra_syntax::SmolStr; |
18 | use rustc_hash::FxHashMap; | 18 | use ra_tt::TokenExpander; |
19 | use rustc_hash::FxHashSet; | 19 | use rustc_hash::{FxHashMap, FxHashSet}; |
20 | 20 | ||
21 | use crate::{RelativePath, RelativePathBuf}; | 21 | use crate::{RelativePath, RelativePathBuf}; |
22 | use fmt::Display; | ||
23 | use ra_tt::TokenExpander; | ||
24 | 22 | ||
25 | /// `FileId` is an integer which uniquely identifies a file. File paths are | 23 | /// `FileId` is an integer which uniquely identifies a file. File paths are |
26 | /// messy and system-dependent, so most of the code should work directly with | 24 | /// messy and system-dependent, so most of the code should work directly with |
@@ -111,7 +109,7 @@ impl CrateName { | |||
111 | } | 109 | } |
112 | } | 110 | } |
113 | 111 | ||
114 | impl Display for CrateName { | 112 | impl fmt::Display for CrateName { |
115 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { | 113 | fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { |
116 | write!(f, "{}", self.0) | 114 | write!(f, "{}", self.0) |
117 | } | 115 | } |
diff --git a/crates/ra_db/src/lib.rs b/crates/ra_db/src/lib.rs index 2ab314884..80ddb6058 100644 --- a/crates/ra_db/src/lib.rs +++ b/crates/ra_db/src/lib.rs | |||
@@ -7,6 +7,7 @@ use std::{panic, sync::Arc}; | |||
7 | 7 | ||
8 | use ra_prof::profile; | 8 | use ra_prof::profile; |
9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; | 9 | use ra_syntax::{ast, Parse, SourceFile, TextRange, TextSize}; |
10 | use rustc_hash::FxHashSet; | ||
10 | 11 | ||
11 | pub use crate::{ | 12 | pub use crate::{ |
12 | cancellation::Canceled, | 13 | cancellation::Canceled, |
@@ -95,7 +96,7 @@ pub trait FileLoader { | |||
95 | /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we | 96 | /// `struct StrPath(str)` for clarity some day, but it's a bit messy, so we |
96 | /// get by with a `&str` for the time being. | 97 | /// get by with a `&str` for the time being. |
97 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; | 98 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId>; |
98 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>>; | 99 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>>; |
99 | } | 100 | } |
100 | 101 | ||
101 | /// Database which stores all significant input facts: source code and project | 102 | /// Database which stores all significant input facts: source code and project |
@@ -133,16 +134,21 @@ pub trait SourceDatabaseExt: SourceDatabase { | |||
133 | #[salsa::input] | 134 | #[salsa::input] |
134 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; | 135 | fn source_root(&self, id: SourceRootId) -> Arc<SourceRoot>; |
135 | 136 | ||
136 | fn source_root_crates(&self, id: SourceRootId) -> Arc<Vec<CrateId>>; | 137 | fn source_root_crates(&self, id: SourceRootId) -> Arc<FxHashSet<CrateId>>; |
137 | } | 138 | } |
138 | 139 | ||
139 | fn source_root_crates( | 140 | fn source_root_crates( |
140 | db: &(impl SourceDatabaseExt + SourceDatabase), | 141 | db: &(impl SourceDatabaseExt + SourceDatabase), |
141 | id: SourceRootId, | 142 | id: SourceRootId, |
142 | ) -> Arc<Vec<CrateId>> { | 143 | ) -> Arc<FxHashSet<CrateId>> { |
143 | let root = db.source_root(id); | ||
144 | let graph = db.crate_graph(); | 144 | let graph = db.crate_graph(); |
145 | let res = root.walk().filter_map(|it| graph.crate_id_for_crate_root(it)).collect::<Vec<_>>(); | 145 | let res = graph |
146 | .iter() | ||
147 | .filter(|&krate| { | ||
148 | let root_file = graph[krate].root_file_id; | ||
149 | db.file_source_root(root_file) == id | ||
150 | }) | ||
151 | .collect::<FxHashSet<_>>(); | ||
146 | Arc::new(res) | 152 | Arc::new(res) |
147 | } | 153 | } |
148 | 154 | ||
@@ -156,7 +162,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
156 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 162 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
157 | // FIXME: this *somehow* should be platform agnostic... | 163 | // FIXME: this *somehow* should be platform agnostic... |
158 | if std::path::Path::new(path).is_absolute() { | 164 | if std::path::Path::new(path).is_absolute() { |
159 | let krate = *self.relevant_crates(anchor).get(0)?; | 165 | let krate = *self.relevant_crates(anchor).iter().next()?; |
160 | let (extern_source_id, relative_file) = | 166 | let (extern_source_id, relative_file) = |
161 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; | 167 | self.0.crate_graph()[krate].extern_source.extern_path(path.as_ref())?; |
162 | 168 | ||
@@ -175,7 +181,7 @@ impl<T: SourceDatabaseExt> FileLoader for FileLoaderDelegate<&'_ T> { | |||
175 | } | 181 | } |
176 | } | 182 | } |
177 | 183 | ||
178 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 184 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
179 | let source_root = self.0.file_source_root(file_id); | 185 | let source_root = self.0.file_source_root(file_id); |
180 | self.0.source_root_crates(source_root) | 186 | self.0.source_root_crates(source_root) |
181 | } | 187 | } |
diff --git a/crates/ra_flycheck/src/lib.rs b/crates/ra_flycheck/src/lib.rs index 041e38a9f..6c4170529 100644 --- a/crates/ra_flycheck/src/lib.rs +++ b/crates/ra_flycheck/src/lib.rs | |||
@@ -18,8 +18,17 @@ pub use cargo_metadata::diagnostic::{ | |||
18 | 18 | ||
19 | #[derive(Clone, Debug, PartialEq, Eq)] | 19 | #[derive(Clone, Debug, PartialEq, Eq)] |
20 | pub enum FlycheckConfig { | 20 | pub enum FlycheckConfig { |
21 | CargoCommand { command: String, all_targets: bool, all_features: bool, extra_args: Vec<String> }, | 21 | CargoCommand { |
22 | CustomCommand { command: String, args: Vec<String> }, | 22 | command: String, |
23 | all_targets: bool, | ||
24 | all_features: bool, | ||
25 | features: Vec<String>, | ||
26 | extra_args: Vec<String>, | ||
27 | }, | ||
28 | CustomCommand { | ||
29 | command: String, | ||
30 | args: Vec<String>, | ||
31 | }, | ||
23 | } | 32 | } |
24 | 33 | ||
25 | /// Flycheck wraps the shared state and communication machinery used for | 34 | /// Flycheck wraps the shared state and communication machinery used for |
@@ -188,7 +197,13 @@ impl FlycheckThread { | |||
188 | self.check_process = None; | 197 | self.check_process = None; |
189 | 198 | ||
190 | let mut cmd = match &self.config { | 199 | let mut cmd = match &self.config { |
191 | FlycheckConfig::CargoCommand { command, all_targets, all_features, extra_args } => { | 200 | FlycheckConfig::CargoCommand { |
201 | command, | ||
202 | all_targets, | ||
203 | all_features, | ||
204 | extra_args, | ||
205 | features, | ||
206 | } => { | ||
192 | let mut cmd = Command::new(ra_toolchain::cargo()); | 207 | let mut cmd = Command::new(ra_toolchain::cargo()); |
193 | cmd.arg(command); | 208 | cmd.arg(command); |
194 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) | 209 | cmd.args(&["--workspace", "--message-format=json", "--manifest-path"]) |
@@ -198,6 +213,9 @@ impl FlycheckThread { | |||
198 | } | 213 | } |
199 | if *all_features { | 214 | if *all_features { |
200 | cmd.arg("--all-features"); | 215 | cmd.arg("--all-features"); |
216 | } else if !features.is_empty() { | ||
217 | cmd.arg("--features"); | ||
218 | cmd.arg(features.join(" ")); | ||
201 | } | 219 | } |
202 | cmd.args(extra_args); | 220 | cmd.args(extra_args); |
203 | cmd | 221 | cmd |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 4a06f3bcd..1a9f6cc76 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -9,6 +9,7 @@ use hir_def::{ | |||
9 | builtin_type::BuiltinType, | 9 | builtin_type::BuiltinType, |
10 | docs::Documentation, | 10 | docs::Documentation, |
11 | expr::{BindingAnnotation, Pat, PatId}, | 11 | expr::{BindingAnnotation, Pat, PatId}, |
12 | import_map, | ||
12 | per_ns::PerNs, | 13 | per_ns::PerNs, |
13 | resolver::{HasResolver, Resolver}, | 14 | resolver::{HasResolver, Resolver}, |
14 | type_ref::{Mutability, TypeRef}, | 15 | type_ref::{Mutability, TypeRef}, |
@@ -98,6 +99,23 @@ impl Crate { | |||
98 | db.crate_graph()[self.id].display_name.as_ref().cloned() | 99 | db.crate_graph()[self.id].display_name.as_ref().cloned() |
99 | } | 100 | } |
100 | 101 | ||
102 | pub fn query_external_importables( | ||
103 | self, | ||
104 | db: &dyn DefDatabase, | ||
105 | query: &str, | ||
106 | ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> { | ||
107 | import_map::search_dependencies( | ||
108 | db, | ||
109 | self.into(), | ||
110 | import_map::Query::new(query).anchor_end().case_sensitive().limit(40), | ||
111 | ) | ||
112 | .into_iter() | ||
113 | .map(|item| match item { | ||
114 | ItemInNs::Types(mod_id) | ItemInNs::Values(mod_id) => Either::Left(mod_id.into()), | ||
115 | ItemInNs::Macros(mac_id) => Either::Right(mac_id.into()), | ||
116 | }) | ||
117 | } | ||
118 | |||
101 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { | 119 | pub fn all(db: &dyn HirDatabase) -> Vec<Crate> { |
102 | db.crate_graph().iter().map(|id| Crate { id }).collect() | 120 | db.crate_graph().iter().map(|id| Crate { id }).collect() |
103 | } | 121 | } |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 7c1f79f27..a232a5856 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -122,8 +122,9 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
122 | let macro_call = | 122 | let macro_call = |
123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); | 123 | self.find_file(actual_macro_call.syntax().clone()).with_value(actual_macro_call); |
124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); | 124 | let sa = self.analyze2(macro_call.map(|it| it.syntax()), None); |
125 | let krate = sa.resolver.krate()?; | ||
125 | let macro_call_id = macro_call | 126 | let macro_call_id = macro_call |
126 | .as_call_id(self.db, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; | 127 | .as_call_id(self.db, krate, |path| sa.resolver.resolve_path_as_macro(self.db, &path))?; |
127 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) | 128 | hir_expand::db::expand_hypothetical(self.db, macro_call_id, hypothetical_args, token_to_map) |
128 | } | 129 | } |
129 | 130 | ||
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 4b509f07c..7c6bbea13 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -307,7 +307,8 @@ impl SourceAnalyzer { | |||
307 | db: &dyn HirDatabase, | 307 | db: &dyn HirDatabase, |
308 | macro_call: InFile<&ast::MacroCall>, | 308 | macro_call: InFile<&ast::MacroCall>, |
309 | ) -> Option<HirFileId> { | 309 | ) -> Option<HirFileId> { |
310 | let macro_call_id = macro_call.as_call_id(db.upcast(), |path| { | 310 | let krate = self.resolver.krate()?; |
311 | let macro_call_id = macro_call.as_call_id(db.upcast(), krate, |path| { | ||
311 | self.resolver.resolve_path_as_macro(db.upcast(), &path) | 312 | self.resolver.resolve_path_as_macro(db.upcast(), &path) |
312 | })?; | 313 | })?; |
313 | Some(macro_call_id.as_file()) | 314 | Some(macro_call_id.as_file()) |
diff --git a/crates/ra_hir_def/Cargo.toml b/crates/ra_hir_def/Cargo.toml index b85358308..ef1f65ee0 100644 --- a/crates/ra_hir_def/Cargo.toml +++ b/crates/ra_hir_def/Cargo.toml | |||
@@ -14,6 +14,9 @@ rustc-hash = "1.1.0" | |||
14 | either = "1.5.3" | 14 | either = "1.5.3" |
15 | anymap = "0.12.1" | 15 | anymap = "0.12.1" |
16 | drop_bomb = "0.1.4" | 16 | drop_bomb = "0.1.4" |
17 | fst = { version = "0.4", default-features = false } | ||
18 | itertools = "0.9.0" | ||
19 | indexmap = "1.4.0" | ||
17 | 20 | ||
18 | stdx = { path = "../stdx" } | 21 | stdx = { path = "../stdx" } |
19 | 22 | ||
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 273036cee..4f2350915 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -97,7 +97,7 @@ impl Expander { | |||
97 | 97 | ||
98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); | 98 | let macro_call = InFile::new(self.current_file_id, ¯o_call); |
99 | 99 | ||
100 | if let Some(call_id) = macro_call.as_call_id(db, |path| { | 100 | if let Some(call_id) = macro_call.as_call_id(db, self.crate_def_map.krate, |path| { |
101 | if let Some(local_scope) = local_scope { | 101 | if let Some(local_scope) = local_scope { |
102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { | 102 | if let Some(def) = path.as_ident().and_then(|n| local_scope.get_legacy_macro(n)) { |
103 | return Some(def); | 103 | return Some(def); |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index 807195d25..53599e74a 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -99,7 +99,7 @@ impl FunctionData { | |||
99 | } | 99 | } |
100 | 100 | ||
101 | fn desugar_future_path(orig: TypeRef) -> Path { | 101 | fn desugar_future_path(orig: TypeRef) -> Path { |
102 | let path = path![std::future::Future]; | 102 | let path = path![core::future::Future]; |
103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); | 103 | let mut generic_args: Vec<_> = std::iter::repeat(None).take(path.segments.len() - 1).collect(); |
104 | let mut last = GenericArgs::empty(); | 104 | let mut last = GenericArgs::empty(); |
105 | last.bindings.push(AssociatedTypeBinding { | 105 | last.bindings.push(AssociatedTypeBinding { |
diff --git a/crates/ra_hir_def/src/diagnostics.rs b/crates/ra_hir_def/src/diagnostics.rs index 510c5e064..30db48f86 100644 --- a/crates/ra_hir_def/src/diagnostics.rs +++ b/crates/ra_hir_def/src/diagnostics.rs | |||
@@ -3,7 +3,6 @@ | |||
3 | use std::any::Any; | 3 | use std::any::Any; |
4 | 4 | ||
5 | use hir_expand::diagnostics::Diagnostic; | 5 | use hir_expand::diagnostics::Diagnostic; |
6 | use ra_db::RelativePathBuf; | ||
7 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; | 6 | use ra_syntax::{ast, AstPtr, SyntaxNodePtr}; |
8 | 7 | ||
9 | use hir_expand::{HirFileId, InFile}; | 8 | use hir_expand::{HirFileId, InFile}; |
@@ -12,7 +11,7 @@ use hir_expand::{HirFileId, InFile}; | |||
12 | pub struct UnresolvedModule { | 11 | pub struct UnresolvedModule { |
13 | pub file: HirFileId, | 12 | pub file: HirFileId, |
14 | pub decl: AstPtr<ast::Module>, | 13 | pub decl: AstPtr<ast::Module>, |
15 | pub candidate: RelativePathBuf, | 14 | pub candidate: String, |
16 | } | 15 | } |
17 | 16 | ||
18 | impl Diagnostic for UnresolvedModule { | 17 | impl Diagnostic for UnresolvedModule { |
diff --git a/crates/ra_hir_def/src/find_path.rs b/crates/ra_hir_def/src/find_path.rs index a7f59e028..06701a830 100644 --- a/crates/ra_hir_def/src/find_path.rs +++ b/crates/ra_hir_def/src/find_path.rs | |||
@@ -159,10 +159,16 @@ fn find_path_inner( | |||
159 | let crate_graph = db.crate_graph(); | 159 | let crate_graph = db.crate_graph(); |
160 | let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { | 160 | let extern_paths = crate_graph[from.krate].dependencies.iter().filter_map(|dep| { |
161 | let import_map = db.import_map(dep.crate_id); | 161 | let import_map = db.import_map(dep.crate_id); |
162 | import_map.path_of(item).map(|modpath| { | 162 | import_map.import_info_for(item).and_then(|info| { |
163 | let mut modpath = modpath.clone(); | 163 | // Determine best path for containing module and append last segment from `info`. |
164 | modpath.segments.insert(0, dep.as_name()); | 164 | let mut path = find_path_inner( |
165 | modpath | 165 | db, |
166 | ItemInNs::Types(ModuleDefId::ModuleId(info.container)), | ||
167 | from, | ||
168 | best_path_len - 1, | ||
169 | )?; | ||
170 | path.segments.push(info.path.segments.last().unwrap().clone()); | ||
171 | Some(path) | ||
166 | }) | 172 | }) |
167 | }); | 173 | }); |
168 | 174 | ||
@@ -299,8 +305,8 @@ mod tests { | |||
299 | /// `code` needs to contain a cursor marker; checks that `find_path` for the | 305 | /// `code` needs to contain a cursor marker; checks that `find_path` for the |
300 | /// item the `path` refers to returns that same path when called from the | 306 | /// item the `path` refers to returns that same path when called from the |
301 | /// module the cursor is in. | 307 | /// module the cursor is in. |
302 | fn check_found_path(code: &str, path: &str) { | 308 | fn check_found_path(ra_fixture: &str, path: &str) { |
303 | let (db, pos) = TestDB::with_position(code); | 309 | let (db, pos) = TestDB::with_position(ra_fixture); |
304 | let module = db.module_for_file(pos.file_id); | 310 | let module = db.module_for_file(pos.file_id); |
305 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); | 311 | let parsed_path_file = ra_syntax::SourceFile::parse(&format!("use {};", path)); |
306 | let ast_path = parsed_path_file | 312 | let ast_path = parsed_path_file |
@@ -420,7 +426,6 @@ mod tests { | |||
420 | 426 | ||
421 | #[test] | 427 | #[test] |
422 | fn different_crate_renamed() { | 428 | fn different_crate_renamed() { |
423 | // Even if a local path exists, if the item is defined externally, prefer an external path. | ||
424 | let code = r#" | 429 | let code = r#" |
425 | //- /main.rs crate:main deps:std | 430 | //- /main.rs crate:main deps:std |
426 | extern crate std as std_renamed; | 431 | extern crate std as std_renamed; |
@@ -428,7 +433,45 @@ mod tests { | |||
428 | //- /std.rs crate:std | 433 | //- /std.rs crate:std |
429 | pub struct S; | 434 | pub struct S; |
430 | "#; | 435 | "#; |
431 | check_found_path(code, "std::S"); | 436 | check_found_path(code, "std_renamed::S"); |
437 | } | ||
438 | |||
439 | #[test] | ||
440 | fn partially_imported() { | ||
441 | // Tests that short paths are used even for external items, when parts of the path are | ||
442 | // already in scope. | ||
443 | check_found_path( | ||
444 | r#" | ||
445 | //- /main.rs crate:main deps:ra_syntax | ||
446 | |||
447 | use ra_syntax::ast; | ||
448 | <|> | ||
449 | |||
450 | //- /lib.rs crate:ra_syntax | ||
451 | pub mod ast { | ||
452 | pub enum ModuleItem { | ||
453 | A, B, C, | ||
454 | } | ||
455 | } | ||
456 | "#, | ||
457 | "ast::ModuleItem", | ||
458 | ); | ||
459 | |||
460 | check_found_path( | ||
461 | r#" | ||
462 | //- /main.rs crate:main deps:ra_syntax | ||
463 | |||
464 | <|> | ||
465 | |||
466 | //- /lib.rs crate:ra_syntax | ||
467 | pub mod ast { | ||
468 | pub enum ModuleItem { | ||
469 | A, B, C, | ||
470 | } | ||
471 | } | ||
472 | "#, | ||
473 | "ra_syntax::ast::ModuleItem", | ||
474 | ); | ||
432 | } | 475 | } |
433 | 476 | ||
434 | #[test] | 477 | #[test] |
diff --git a/crates/ra_hir_def/src/import_map.rs b/crates/ra_hir_def/src/import_map.rs index 4284a0a91..68e20d06b 100644 --- a/crates/ra_hir_def/src/import_map.rs +++ b/crates/ra_hir_def/src/import_map.rs | |||
@@ -1,9 +1,11 @@ | |||
1 | //! A map of all publicly exported items in a crate. | 1 | //! A map of all publicly exported items in a crate. |
2 | 2 | ||
3 | use std::{collections::hash_map::Entry, fmt, sync::Arc}; | 3 | use std::{cmp::Ordering, fmt, hash::BuildHasherDefault, sync::Arc}; |
4 | 4 | ||
5 | use fst::{self, Streamer}; | ||
6 | use indexmap::{map::Entry, IndexMap}; | ||
5 | use ra_db::CrateId; | 7 | use ra_db::CrateId; |
6 | use rustc_hash::FxHashMap; | 8 | use rustc_hash::FxHasher; |
7 | 9 | ||
8 | use crate::{ | 10 | use crate::{ |
9 | db::DefDatabase, | 11 | db::DefDatabase, |
@@ -13,6 +15,17 @@ use crate::{ | |||
13 | ModuleDefId, ModuleId, | 15 | ModuleDefId, ModuleId, |
14 | }; | 16 | }; |
15 | 17 | ||
18 | type FxIndexMap<K, V> = IndexMap<K, V, BuildHasherDefault<FxHasher>>; | ||
19 | |||
20 | /// Item import details stored in the `ImportMap`. | ||
21 | #[derive(Debug, Clone, Eq, PartialEq)] | ||
22 | pub struct ImportInfo { | ||
23 | /// A path that can be used to import the item, relative to the crate's root. | ||
24 | pub path: ModPath, | ||
25 | /// The module containing this item. | ||
26 | pub container: ModuleId, | ||
27 | } | ||
28 | |||
16 | /// A map from publicly exported items to the path needed to import/name them from a downstream | 29 | /// A map from publicly exported items to the path needed to import/name them from a downstream |
17 | /// crate. | 30 | /// crate. |
18 | /// | 31 | /// |
@@ -21,16 +34,24 @@ use crate::{ | |||
21 | /// | 34 | /// |
22 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs | 35 | /// Note that all paths are relative to the containing crate's root, so the crate name still needs |
23 | /// to be prepended to the `ModPath` before the path is valid. | 36 | /// to be prepended to the `ModPath` before the path is valid. |
24 | #[derive(Eq, PartialEq)] | ||
25 | pub struct ImportMap { | 37 | pub struct ImportMap { |
26 | map: FxHashMap<ItemInNs, ModPath>, | 38 | map: FxIndexMap<ItemInNs, ImportInfo>, |
39 | |||
40 | /// List of keys stored in `map`, sorted lexicographically by their `ModPath`. Indexed by the | ||
41 | /// values returned by running `fst`. | ||
42 | /// | ||
43 | /// Since a path can refer to multiple items due to namespacing, we store all items with the | ||
44 | /// same path right after each other. This allows us to find all items after the FST gives us | ||
45 | /// the index of the first one. | ||
46 | importables: Vec<ItemInNs>, | ||
47 | fst: fst::Map<Vec<u8>>, | ||
27 | } | 48 | } |
28 | 49 | ||
29 | impl ImportMap { | 50 | impl ImportMap { |
30 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { | 51 | pub fn import_map_query(db: &dyn DefDatabase, krate: CrateId) -> Arc<Self> { |
31 | let _p = ra_prof::profile("import_map_query"); | 52 | let _p = ra_prof::profile("import_map_query"); |
32 | let def_map = db.crate_def_map(krate); | 53 | let def_map = db.crate_def_map(krate); |
33 | let mut import_map = FxHashMap::with_capacity_and_hasher(64, Default::default()); | 54 | let mut import_map = FxIndexMap::with_capacity_and_hasher(64, Default::default()); |
34 | 55 | ||
35 | // We look only into modules that are public(ly reexported), starting with the crate root. | 56 | // We look only into modules that are public(ly reexported), starting with the crate root. |
36 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; | 57 | let empty = ModPath { kind: PathKind::Plain, segments: vec![] }; |
@@ -66,12 +87,12 @@ impl ImportMap { | |||
66 | let path = mk_path(); | 87 | let path = mk_path(); |
67 | match import_map.entry(item) { | 88 | match import_map.entry(item) { |
68 | Entry::Vacant(entry) => { | 89 | Entry::Vacant(entry) => { |
69 | entry.insert(path); | 90 | entry.insert(ImportInfo { path, container: module }); |
70 | } | 91 | } |
71 | Entry::Occupied(mut entry) => { | 92 | Entry::Occupied(mut entry) => { |
72 | // If the new path is shorter, prefer that one. | 93 | // If the new path is shorter, prefer that one. |
73 | if path.len() < entry.get().len() { | 94 | if path.len() < entry.get().path.len() { |
74 | *entry.get_mut() = path; | 95 | *entry.get_mut() = ImportInfo { path, container: module }; |
75 | } else { | 96 | } else { |
76 | continue; | 97 | continue; |
77 | } | 98 | } |
@@ -88,27 +109,67 @@ impl ImportMap { | |||
88 | } | 109 | } |
89 | } | 110 | } |
90 | 111 | ||
91 | Arc::new(Self { map: import_map }) | 112 | let mut importables = import_map.iter().collect::<Vec<_>>(); |
113 | |||
114 | importables.sort_by(cmp); | ||
115 | |||
116 | // Build the FST, taking care not to insert duplicate values. | ||
117 | |||
118 | let mut builder = fst::MapBuilder::memory(); | ||
119 | let mut last_batch_start = 0; | ||
120 | |||
121 | for idx in 0..importables.len() { | ||
122 | if let Some(next_item) = importables.get(idx + 1) { | ||
123 | if cmp(&importables[last_batch_start], next_item) == Ordering::Equal { | ||
124 | continue; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | let start = last_batch_start; | ||
129 | last_batch_start = idx + 1; | ||
130 | |||
131 | let key = fst_path(&importables[start].1.path); | ||
132 | |||
133 | builder.insert(key, start as u64).unwrap(); | ||
134 | } | ||
135 | |||
136 | let fst = fst::Map::new(builder.into_inner().unwrap()).unwrap(); | ||
137 | let importables = importables.iter().map(|(item, _)| **item).collect(); | ||
138 | |||
139 | Arc::new(Self { map: import_map, fst, importables }) | ||
92 | } | 140 | } |
93 | 141 | ||
94 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. | 142 | /// Returns the `ModPath` needed to import/mention `item`, relative to this crate's root. |
95 | pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { | 143 | pub fn path_of(&self, item: ItemInNs) -> Option<&ModPath> { |
144 | Some(&self.map.get(&item)?.path) | ||
145 | } | ||
146 | |||
147 | pub fn import_info_for(&self, item: ItemInNs) -> Option<&ImportInfo> { | ||
96 | self.map.get(&item) | 148 | self.map.get(&item) |
97 | } | 149 | } |
98 | } | 150 | } |
99 | 151 | ||
152 | impl PartialEq for ImportMap { | ||
153 | fn eq(&self, other: &Self) -> bool { | ||
154 | // `fst` and `importables` are built from `map`, so we don't need to compare them. | ||
155 | self.map == other.map | ||
156 | } | ||
157 | } | ||
158 | |||
159 | impl Eq for ImportMap {} | ||
160 | |||
100 | impl fmt::Debug for ImportMap { | 161 | impl fmt::Debug for ImportMap { |
101 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { | 162 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
102 | let mut importable_paths: Vec<_> = self | 163 | let mut importable_paths: Vec<_> = self |
103 | .map | 164 | .map |
104 | .iter() | 165 | .iter() |
105 | .map(|(item, modpath)| { | 166 | .map(|(item, info)| { |
106 | let ns = match item { | 167 | let ns = match item { |
107 | ItemInNs::Types(_) => "t", | 168 | ItemInNs::Types(_) => "t", |
108 | ItemInNs::Values(_) => "v", | 169 | ItemInNs::Values(_) => "v", |
109 | ItemInNs::Macros(_) => "m", | 170 | ItemInNs::Macros(_) => "m", |
110 | }; | 171 | }; |
111 | format!("- {} ({})", modpath, ns) | 172 | format!("- {} ({})", info.path, ns) |
112 | }) | 173 | }) |
113 | .collect(); | 174 | .collect(); |
114 | 175 | ||
@@ -117,19 +178,135 @@ impl fmt::Debug for ImportMap { | |||
117 | } | 178 | } |
118 | } | 179 | } |
119 | 180 | ||
181 | fn fst_path(path: &ModPath) -> String { | ||
182 | let mut s = path.to_string(); | ||
183 | s.make_ascii_lowercase(); | ||
184 | s | ||
185 | } | ||
186 | |||
187 | fn cmp((_, lhs): &(&ItemInNs, &ImportInfo), (_, rhs): &(&ItemInNs, &ImportInfo)) -> Ordering { | ||
188 | let lhs_str = fst_path(&lhs.path); | ||
189 | let rhs_str = fst_path(&rhs.path); | ||
190 | lhs_str.cmp(&rhs_str) | ||
191 | } | ||
192 | |||
193 | #[derive(Debug)] | ||
194 | pub struct Query { | ||
195 | query: String, | ||
196 | lowercased: String, | ||
197 | anchor_end: bool, | ||
198 | case_sensitive: bool, | ||
199 | limit: usize, | ||
200 | } | ||
201 | |||
202 | impl Query { | ||
203 | pub fn new(query: &str) -> Self { | ||
204 | Self { | ||
205 | lowercased: query.to_lowercase(), | ||
206 | query: query.to_string(), | ||
207 | anchor_end: false, | ||
208 | case_sensitive: false, | ||
209 | limit: usize::max_value(), | ||
210 | } | ||
211 | } | ||
212 | |||
213 | /// Only returns items whose paths end with the (case-insensitive) query string as their last | ||
214 | /// segment. | ||
215 | pub fn anchor_end(self) -> Self { | ||
216 | Self { anchor_end: true, ..self } | ||
217 | } | ||
218 | |||
219 | /// Limits the returned number of items to `limit`. | ||
220 | pub fn limit(self, limit: usize) -> Self { | ||
221 | Self { limit, ..self } | ||
222 | } | ||
223 | |||
224 | /// Respect casing of the query string when matching. | ||
225 | pub fn case_sensitive(self) -> Self { | ||
226 | Self { case_sensitive: true, ..self } | ||
227 | } | ||
228 | } | ||
229 | |||
230 | /// Searches dependencies of `krate` for an importable path matching `query`. | ||
231 | /// | ||
232 | /// This returns a list of items that could be imported from dependencies of `krate`. | ||
233 | pub fn search_dependencies<'a>( | ||
234 | db: &'a dyn DefDatabase, | ||
235 | krate: CrateId, | ||
236 | query: Query, | ||
237 | ) -> Vec<ItemInNs> { | ||
238 | let _p = ra_prof::profile("search_dependencies").detail(|| format!("{:?}", query)); | ||
239 | |||
240 | let graph = db.crate_graph(); | ||
241 | let import_maps: Vec<_> = | ||
242 | graph[krate].dependencies.iter().map(|dep| db.import_map(dep.crate_id)).collect(); | ||
243 | |||
244 | let automaton = fst::automaton::Subsequence::new(&query.lowercased); | ||
245 | |||
246 | let mut op = fst::map::OpBuilder::new(); | ||
247 | for map in &import_maps { | ||
248 | op = op.add(map.fst.search(&automaton)); | ||
249 | } | ||
250 | |||
251 | let mut stream = op.union(); | ||
252 | let mut res = Vec::new(); | ||
253 | while let Some((_, indexed_values)) = stream.next() { | ||
254 | for indexed_value in indexed_values { | ||
255 | let import_map = &import_maps[indexed_value.index]; | ||
256 | let importables = &import_map.importables[indexed_value.value as usize..]; | ||
257 | |||
258 | // Path shared by the importable items in this group. | ||
259 | let path = &import_map.map[&importables[0]].path; | ||
260 | |||
261 | if query.anchor_end { | ||
262 | // Last segment must match query. | ||
263 | let last = path.segments.last().unwrap().to_string(); | ||
264 | if last.to_lowercase() != query.lowercased { | ||
265 | continue; | ||
266 | } | ||
267 | } | ||
268 | |||
269 | // Add the items from this `ModPath` group. Those are all subsequent items in | ||
270 | // `importables` whose paths match `path`. | ||
271 | let iter = importables.iter().copied().take_while(|item| { | ||
272 | let item_path = &import_map.map[item].path; | ||
273 | fst_path(item_path) == fst_path(path) | ||
274 | }); | ||
275 | |||
276 | if query.case_sensitive { | ||
277 | // FIXME: This does not do a subsequence match. | ||
278 | res.extend(iter.filter(|item| { | ||
279 | let item_path = &import_map.map[item].path; | ||
280 | item_path.to_string().contains(&query.query) | ||
281 | })); | ||
282 | } else { | ||
283 | res.extend(iter); | ||
284 | } | ||
285 | |||
286 | if res.len() >= query.limit { | ||
287 | res.truncate(query.limit); | ||
288 | return res; | ||
289 | } | ||
290 | } | ||
291 | } | ||
292 | |||
293 | res | ||
294 | } | ||
295 | |||
120 | #[cfg(test)] | 296 | #[cfg(test)] |
121 | mod tests { | 297 | mod tests { |
122 | use super::*; | 298 | use super::*; |
123 | use crate::test_db::TestDB; | 299 | use crate::test_db::TestDB; |
124 | use insta::assert_snapshot; | 300 | use insta::assert_snapshot; |
301 | use itertools::Itertools; | ||
125 | use ra_db::fixture::WithFixture; | 302 | use ra_db::fixture::WithFixture; |
126 | use ra_db::SourceDatabase; | 303 | use ra_db::{SourceDatabase, Upcast}; |
127 | 304 | ||
128 | fn import_map(ra_fixture: &str) -> String { | 305 | fn import_map(ra_fixture: &str) -> String { |
129 | let db = TestDB::with_files(ra_fixture); | 306 | let db = TestDB::with_files(ra_fixture); |
130 | let crate_graph = db.crate_graph(); | 307 | let crate_graph = db.crate_graph(); |
131 | 308 | ||
132 | let import_maps: Vec<_> = crate_graph | 309 | let s = crate_graph |
133 | .iter() | 310 | .iter() |
134 | .filter_map(|krate| { | 311 | .filter_map(|krate| { |
135 | let cdata = &crate_graph[krate]; | 312 | let cdata = &crate_graph[krate]; |
@@ -139,9 +316,41 @@ mod tests { | |||
139 | 316 | ||
140 | Some(format!("{}:\n{:?}", name, map)) | 317 | Some(format!("{}:\n{:?}", name, map)) |
141 | }) | 318 | }) |
142 | .collect(); | 319 | .join("\n"); |
320 | s | ||
321 | } | ||
143 | 322 | ||
144 | import_maps.join("\n") | 323 | fn search_dependencies_of(ra_fixture: &str, krate_name: &str, query: Query) -> String { |
324 | let db = TestDB::with_files(ra_fixture); | ||
325 | let crate_graph = db.crate_graph(); | ||
326 | let krate = crate_graph | ||
327 | .iter() | ||
328 | .find(|krate| { | ||
329 | crate_graph[*krate].display_name.as_ref().map(|n| n.to_string()) | ||
330 | == Some(krate_name.to_string()) | ||
331 | }) | ||
332 | .unwrap(); | ||
333 | |||
334 | search_dependencies(db.upcast(), krate, query) | ||
335 | .into_iter() | ||
336 | .filter_map(|item| { | ||
337 | let mark = match item { | ||
338 | ItemInNs::Types(_) => "t", | ||
339 | ItemInNs::Values(_) => "v", | ||
340 | ItemInNs::Macros(_) => "m", | ||
341 | }; | ||
342 | item.krate(db.upcast()).map(|krate| { | ||
343 | let map = db.import_map(krate); | ||
344 | let path = map.path_of(item).unwrap(); | ||
345 | format!( | ||
346 | "{}::{} ({})", | ||
347 | crate_graph[krate].display_name.as_ref().unwrap(), | ||
348 | path, | ||
349 | mark | ||
350 | ) | ||
351 | }) | ||
352 | }) | ||
353 | .join("\n") | ||
145 | } | 354 | } |
146 | 355 | ||
147 | #[test] | 356 | #[test] |
@@ -328,4 +537,143 @@ mod tests { | |||
328 | lib: | 537 | lib: |
329 | "###); | 538 | "###); |
330 | } | 539 | } |
540 | |||
541 | #[test] | ||
542 | fn namespacing() { | ||
543 | let map = import_map( | ||
544 | r" | ||
545 | //- /lib.rs crate:lib | ||
546 | pub struct Thing; // t + v | ||
547 | #[macro_export] | ||
548 | macro_rules! Thing { // m | ||
549 | () => {}; | ||
550 | } | ||
551 | ", | ||
552 | ); | ||
553 | |||
554 | assert_snapshot!(map, @r###" | ||
555 | lib: | ||
556 | - Thing (m) | ||
557 | - Thing (t) | ||
558 | - Thing (v) | ||
559 | "###); | ||
560 | |||
561 | let map = import_map( | ||
562 | r" | ||
563 | //- /lib.rs crate:lib | ||
564 | pub mod Thing {} // t | ||
565 | #[macro_export] | ||
566 | macro_rules! Thing { // m | ||
567 | () => {}; | ||
568 | } | ||
569 | ", | ||
570 | ); | ||
571 | |||
572 | assert_snapshot!(map, @r###" | ||
573 | lib: | ||
574 | - Thing (m) | ||
575 | - Thing (t) | ||
576 | "###); | ||
577 | } | ||
578 | |||
579 | #[test] | ||
580 | fn search() { | ||
581 | let ra_fixture = r#" | ||
582 | //- /main.rs crate:main deps:dep | ||
583 | //- /dep.rs crate:dep deps:tdep | ||
584 | use tdep::fmt as fmt_dep; | ||
585 | pub mod fmt { | ||
586 | pub trait Display { | ||
587 | fn fmt(); | ||
588 | } | ||
589 | } | ||
590 | #[macro_export] | ||
591 | macro_rules! Fmt { | ||
592 | () => {}; | ||
593 | } | ||
594 | pub struct Fmt; | ||
595 | |||
596 | pub fn format() {} | ||
597 | pub fn no() {} | ||
598 | |||
599 | //- /tdep.rs crate:tdep | ||
600 | pub mod fmt { | ||
601 | pub struct NotImportableFromMain; | ||
602 | } | ||
603 | "#; | ||
604 | |||
605 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt")); | ||
606 | assert_snapshot!(res, @r###" | ||
607 | dep::fmt (t) | ||
608 | dep::Fmt (t) | ||
609 | dep::Fmt (v) | ||
610 | dep::Fmt (m) | ||
611 | dep::fmt::Display (t) | ||
612 | dep::format (v) | ||
613 | "###); | ||
614 | |||
615 | let res = search_dependencies_of(ra_fixture, "main", Query::new("fmt").anchor_end()); | ||
616 | assert_snapshot!(res, @r###" | ||
617 | dep::fmt (t) | ||
618 | dep::Fmt (t) | ||
619 | dep::Fmt (v) | ||
620 | dep::Fmt (m) | ||
621 | "###); | ||
622 | } | ||
623 | |||
624 | #[test] | ||
625 | fn search_casing() { | ||
626 | let ra_fixture = r#" | ||
627 | //- /main.rs crate:main deps:dep | ||
628 | //- /dep.rs crate:dep | ||
629 | |||
630 | pub struct fmt; | ||
631 | pub struct FMT; | ||
632 | "#; | ||
633 | |||
634 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT")); | ||
635 | |||
636 | assert_snapshot!(res, @r###" | ||
637 | dep::fmt (t) | ||
638 | dep::fmt (v) | ||
639 | dep::FMT (t) | ||
640 | dep::FMT (v) | ||
641 | "###); | ||
642 | |||
643 | let res = search_dependencies_of(ra_fixture, "main", Query::new("FMT").case_sensitive()); | ||
644 | |||
645 | assert_snapshot!(res, @r###" | ||
646 | dep::FMT (t) | ||
647 | dep::FMT (v) | ||
648 | "###); | ||
649 | } | ||
650 | |||
651 | #[test] | ||
652 | fn search_limit() { | ||
653 | let res = search_dependencies_of( | ||
654 | r#" | ||
655 | //- /main.rs crate:main deps:dep | ||
656 | //- /dep.rs crate:dep | ||
657 | pub mod fmt { | ||
658 | pub trait Display { | ||
659 | fn fmt(); | ||
660 | } | ||
661 | } | ||
662 | #[macro_export] | ||
663 | macro_rules! Fmt { | ||
664 | () => {}; | ||
665 | } | ||
666 | pub struct Fmt; | ||
667 | |||
668 | pub fn format() {} | ||
669 | pub fn no() {} | ||
670 | "#, | ||
671 | "main", | ||
672 | Query::new("").limit(2), | ||
673 | ); | ||
674 | assert_snapshot!(res, @r###" | ||
675 | dep::fmt (t) | ||
676 | dep::Fmt (t) | ||
677 | "###); | ||
678 | } | ||
331 | } | 679 | } |
diff --git a/crates/ra_hir_def/src/lib.rs b/crates/ra_hir_def/src/lib.rs index de490fcc5..edc59e5a8 100644 --- a/crates/ra_hir_def/src/lib.rs +++ b/crates/ra_hir_def/src/lib.rs | |||
@@ -417,6 +417,7 @@ pub trait AsMacroCall { | |||
417 | fn as_call_id( | 417 | fn as_call_id( |
418 | &self, | 418 | &self, |
419 | db: &dyn db::DefDatabase, | 419 | db: &dyn db::DefDatabase, |
420 | krate: CrateId, | ||
420 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 421 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
421 | ) -> Option<MacroCallId>; | 422 | ) -> Option<MacroCallId>; |
422 | } | 423 | } |
@@ -425,13 +426,14 @@ impl AsMacroCall for InFile<&ast::MacroCall> { | |||
425 | fn as_call_id( | 426 | fn as_call_id( |
426 | &self, | 427 | &self, |
427 | db: &dyn db::DefDatabase, | 428 | db: &dyn db::DefDatabase, |
429 | krate: CrateId, | ||
428 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 430 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
429 | ) -> Option<MacroCallId> { | 431 | ) -> Option<MacroCallId> { |
430 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); | 432 | let ast_id = AstId::new(self.file_id, db.ast_id_map(self.file_id).ast_id(self.value)); |
431 | let h = Hygiene::new(db.upcast(), self.file_id); | 433 | let h = Hygiene::new(db.upcast(), self.file_id); |
432 | let path = path::ModPath::from_src(self.value.path()?, &h)?; | 434 | let path = path::ModPath::from_src(self.value.path()?, &h)?; |
433 | 435 | ||
434 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, resolver) | 436 | AstIdWithPath::new(ast_id.file_id, ast_id.value, path).as_call_id(db, krate, resolver) |
435 | } | 437 | } |
436 | } | 438 | } |
437 | 439 | ||
@@ -452,6 +454,7 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
452 | fn as_call_id( | 454 | fn as_call_id( |
453 | &self, | 455 | &self, |
454 | db: &dyn db::DefDatabase, | 456 | db: &dyn db::DefDatabase, |
457 | krate: CrateId, | ||
455 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 458 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
456 | ) -> Option<MacroCallId> { | 459 | ) -> Option<MacroCallId> { |
457 | let def: MacroDefId = resolver(self.path.clone())?; | 460 | let def: MacroDefId = resolver(self.path.clone())?; |
@@ -461,13 +464,13 @@ impl AsMacroCall for AstIdWithPath<ast::MacroCall> { | |||
461 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); | 464 | let hygiene = Hygiene::new(db.upcast(), self.ast_id.file_id); |
462 | 465 | ||
463 | Some( | 466 | Some( |
464 | expand_eager_macro(db.upcast(), macro_call, def, &|path: ast::Path| { | 467 | expand_eager_macro(db.upcast(), krate, macro_call, def, &|path: ast::Path| { |
465 | resolver(path::ModPath::from_src(path, &hygiene)?) | 468 | resolver(path::ModPath::from_src(path, &hygiene)?) |
466 | })? | 469 | })? |
467 | .into(), | 470 | .into(), |
468 | ) | 471 | ) |
469 | } else { | 472 | } else { |
470 | Some(def.as_lazy_macro(db.upcast(), MacroCallKind::FnLike(self.ast_id)).into()) | 473 | Some(def.as_lazy_macro(db.upcast(), krate, MacroCallKind::FnLike(self.ast_id)).into()) |
471 | } | 474 | } |
472 | } | 475 | } |
473 | } | 476 | } |
@@ -476,12 +479,14 @@ impl AsMacroCall for AstIdWithPath<ast::ModuleItem> { | |||
476 | fn as_call_id( | 479 | fn as_call_id( |
477 | &self, | 480 | &self, |
478 | db: &dyn db::DefDatabase, | 481 | db: &dyn db::DefDatabase, |
482 | krate: CrateId, | ||
479 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, | 483 | resolver: impl Fn(path::ModPath) -> Option<MacroDefId>, |
480 | ) -> Option<MacroCallId> { | 484 | ) -> Option<MacroCallId> { |
481 | let def = resolver(self.path.clone())?; | 485 | let def = resolver(self.path.clone())?; |
482 | Some( | 486 | Some( |
483 | def.as_lazy_macro( | 487 | def.as_lazy_macro( |
484 | db.upcast(), | 488 | db.upcast(), |
489 | krate, | ||
485 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), | 490 | MacroCallKind::Attr(self.ast_id, self.path.segments.last()?.to_string()), |
486 | ) | 491 | ) |
487 | .into(), | 492 | .into(), |
diff --git a/crates/ra_hir_def/src/nameres.rs b/crates/ra_hir_def/src/nameres.rs index f279c2ad4..b3e5f491a 100644 --- a/crates/ra_hir_def/src/nameres.rs +++ b/crates/ra_hir_def/src/nameres.rs | |||
@@ -296,7 +296,6 @@ pub enum ModuleSource { | |||
296 | 296 | ||
297 | mod diagnostics { | 297 | mod diagnostics { |
298 | use hir_expand::diagnostics::DiagnosticSink; | 298 | use hir_expand::diagnostics::DiagnosticSink; |
299 | use ra_db::RelativePathBuf; | ||
300 | use ra_syntax::{ast, AstPtr}; | 299 | use ra_syntax::{ast, AstPtr}; |
301 | 300 | ||
302 | use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId}; | 301 | use crate::{db::DefDatabase, diagnostics::UnresolvedModule, nameres::LocalModuleId, AstId}; |
@@ -306,7 +305,7 @@ mod diagnostics { | |||
306 | UnresolvedModule { | 305 | UnresolvedModule { |
307 | module: LocalModuleId, | 306 | module: LocalModuleId, |
308 | declaration: AstId<ast::Module>, | 307 | declaration: AstId<ast::Module>, |
309 | candidate: RelativePathBuf, | 308 | candidate: String, |
310 | }, | 309 | }, |
311 | } | 310 | } |
312 | 311 | ||
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 353a31ad4..976e5e585 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -571,16 +571,18 @@ impl DefCollector<'_> { | |||
571 | return false; | 571 | return false; |
572 | } | 572 | } |
573 | 573 | ||
574 | if let Some(call_id) = directive.ast_id.as_call_id(self.db, |path| { | 574 | if let Some(call_id) = |
575 | let resolved_res = self.def_map.resolve_path_fp_with_macro( | 575 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
576 | self.db, | 576 | let resolved_res = self.def_map.resolve_path_fp_with_macro( |
577 | ResolveMode::Other, | 577 | self.db, |
578 | directive.module_id, | 578 | ResolveMode::Other, |
579 | &path, | 579 | directive.module_id, |
580 | BuiltinShadowMode::Module, | 580 | &path, |
581 | ); | 581 | BuiltinShadowMode::Module, |
582 | resolved_res.resolved_def.take_macros() | 582 | ); |
583 | }) { | 583 | resolved_res.resolved_def.take_macros() |
584 | }) | ||
585 | { | ||
584 | resolved.push((directive.module_id, call_id, directive.depth)); | 586 | resolved.push((directive.module_id, call_id, directive.depth)); |
585 | res = ReachedFixedPoint::No; | 587 | res = ReachedFixedPoint::No; |
586 | return false; | 588 | return false; |
@@ -589,9 +591,10 @@ impl DefCollector<'_> { | |||
589 | true | 591 | true |
590 | }); | 592 | }); |
591 | attribute_macros.retain(|directive| { | 593 | attribute_macros.retain(|directive| { |
592 | if let Some(call_id) = directive | 594 | if let Some(call_id) = |
593 | .ast_id | 595 | directive.ast_id.as_call_id(self.db, self.def_map.krate, |path| { |
594 | .as_call_id(self.db, |path| self.resolve_attribute_macro(&directive, &path)) | 596 | self.resolve_attribute_macro(&directive, &path) |
597 | }) | ||
595 | { | 598 | { |
596 | resolved.push((directive.module_id, call_id, 0)); | 599 | resolved.push((directive.module_id, call_id, 0)); |
597 | res = ReachedFixedPoint::No; | 600 | res = ReachedFixedPoint::No; |
@@ -957,11 +960,13 @@ impl ModCollector<'_, '_> { | |||
957 | } | 960 | } |
958 | 961 | ||
959 | // Case 2: try to resolve in legacy scope and expand macro_rules | 962 | // Case 2: try to resolve in legacy scope and expand macro_rules |
960 | if let Some(macro_call_id) = ast_id.as_call_id(self.def_collector.db, |path| { | 963 | if let Some(macro_call_id) = |
961 | path.as_ident().and_then(|name| { | 964 | ast_id.as_call_id(self.def_collector.db, self.def_collector.def_map.krate, |path| { |
962 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | 965 | path.as_ident().and_then(|name| { |
966 | self.def_collector.def_map[self.module_id].scope.get_legacy_macro(&name) | ||
967 | }) | ||
963 | }) | 968 | }) |
964 | }) { | 969 | { |
965 | self.def_collector.unexpanded_macros.push(MacroDirective { | 970 | self.def_collector.unexpanded_macros.push(MacroDirective { |
966 | module_id: self.module_id, | 971 | module_id: self.module_id, |
967 | ast_id, | 972 | ast_id, |
diff --git a/crates/ra_hir_def/src/nameres/mod_resolution.rs b/crates/ra_hir_def/src/nameres/mod_resolution.rs index cede4a6fc..19fe0615a 100644 --- a/crates/ra_hir_def/src/nameres/mod_resolution.rs +++ b/crates/ra_hir_def/src/nameres/mod_resolution.rs | |||
@@ -44,7 +44,7 @@ impl ModDir { | |||
44 | file_id: HirFileId, | 44 | file_id: HirFileId, |
45 | name: &Name, | 45 | name: &Name, |
46 | attr_path: Option<&SmolStr>, | 46 | attr_path: Option<&SmolStr>, |
47 | ) -> Result<(FileId, ModDir), RelativePathBuf> { | 47 | ) -> Result<(FileId, ModDir), String> { |
48 | let file_id = file_id.original_file(db.upcast()); | 48 | let file_id = file_id.original_file(db.upcast()); |
49 | 49 | ||
50 | let mut candidate_files = Vec::new(); | 50 | let mut candidate_files = Vec::new(); |
@@ -52,11 +52,11 @@ impl ModDir { | |||
52 | Some(attr_path) => { | 52 | Some(attr_path) => { |
53 | let base = | 53 | let base = |
54 | if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path }; | 54 | if self.root_non_dir_owner { self.path.parent().unwrap() } else { &self.path }; |
55 | candidate_files.push(base.join(attr_path)) | 55 | candidate_files.push(base.join(attr_path).to_string()) |
56 | } | 56 | } |
57 | None => { | 57 | None => { |
58 | candidate_files.push(self.path.join(&format!("{}.rs", name))); | 58 | candidate_files.push(self.path.join(&format!("{}.rs", name)).to_string()); |
59 | candidate_files.push(self.path.join(&format!("{}/mod.rs", name))); | 59 | candidate_files.push(self.path.join(&format!("{}/mod.rs", name)).to_string()); |
60 | } | 60 | } |
61 | }; | 61 | }; |
62 | 62 | ||
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index bfa921de2..190d6d98d 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -154,7 +154,7 @@ pub enum GenericArg { | |||
154 | 154 | ||
155 | impl Path { | 155 | impl Path { |
156 | /// Converts an `ast::Path` to `Path`. Works with use trees. | 156 | /// Converts an `ast::Path` to `Path`. Works with use trees. |
157 | /// DEPRECATED: It does not handle `$crate` from macro call. | 157 | #[deprecated = "Doesn't handle hygiene, don't add new calls, remove old ones"] |
158 | pub fn from_ast(path: ast::Path) -> Option<Path> { | 158 | pub fn from_ast(path: ast::Path) -> Option<Path> { |
159 | lower::lower_path(path, &Hygiene::new_unhygienic()) | 159 | lower::lower_path(path, &Hygiene::new_unhygienic()) |
160 | } | 160 | } |
@@ -323,16 +323,16 @@ pub use hir_expand::name as __name; | |||
323 | 323 | ||
324 | #[macro_export] | 324 | #[macro_export] |
325 | macro_rules! __known_path { | 325 | macro_rules! __known_path { |
326 | (std::iter::IntoIterator) => {}; | 326 | (core::iter::IntoIterator) => {}; |
327 | (std::result::Result) => {}; | 327 | (core::result::Result) => {}; |
328 | (std::ops::Range) => {}; | 328 | (core::ops::Range) => {}; |
329 | (std::ops::RangeFrom) => {}; | 329 | (core::ops::RangeFrom) => {}; |
330 | (std::ops::RangeFull) => {}; | 330 | (core::ops::RangeFull) => {}; |
331 | (std::ops::RangeTo) => {}; | 331 | (core::ops::RangeTo) => {}; |
332 | (std::ops::RangeToInclusive) => {}; | 332 | (core::ops::RangeToInclusive) => {}; |
333 | (std::ops::RangeInclusive) => {}; | 333 | (core::ops::RangeInclusive) => {}; |
334 | (std::future::Future) => {}; | 334 | (core::future::Future) => {}; |
335 | (std::ops::Try) => {}; | 335 | (core::ops::Try) => {}; |
336 | ($path:path) => { | 336 | ($path:path) => { |
337 | compile_error!("Please register your known path in the path module") | 337 | compile_error!("Please register your known path in the path module") |
338 | }; | 338 | }; |
diff --git a/crates/ra_hir_def/src/test_db.rs b/crates/ra_hir_def/src/test_db.rs index bcfa66ac9..4581d8745 100644 --- a/crates/ra_hir_def/src/test_db.rs +++ b/crates/ra_hir_def/src/test_db.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | 7 | ||
8 | use hir_expand::db::AstDatabase; | 8 | use hir_expand::db::AstDatabase; |
9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; | 9 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, Upcast}; |
10 | use rustc_hash::FxHashSet; | ||
10 | 11 | ||
11 | use crate::db::DefDatabase; | 12 | use crate::db::DefDatabase; |
12 | 13 | ||
@@ -59,7 +60,7 @@ impl FileLoader for TestDB { | |||
59 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 60 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
60 | FileLoaderDelegate(self).resolve_path(anchor, path) | 61 | FileLoaderDelegate(self).resolve_path(anchor, path) |
61 | } | 62 | } |
62 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 63 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
63 | FileLoaderDelegate(self).relevant_crates(file_id) | 64 | FileLoaderDelegate(self).relevant_crates(file_id) |
64 | } | 65 | } |
65 | } | 66 | } |
diff --git a/crates/ra_hir_expand/Cargo.toml b/crates/ra_hir_expand/Cargo.toml index 2cd522766..e5c9f3e99 100644 --- a/crates/ra_hir_expand/Cargo.toml +++ b/crates/ra_hir_expand/Cargo.toml | |||
@@ -10,6 +10,7 @@ doctest = false | |||
10 | [dependencies] | 10 | [dependencies] |
11 | log = "0.4.8" | 11 | log = "0.4.8" |
12 | either = "1.5.3" | 12 | either = "1.5.3" |
13 | rustc-hash = "1.0.0" | ||
13 | 14 | ||
14 | ra_arena = { path = "../ra_arena" } | 15 | ra_arena = { path = "../ra_arena" } |
15 | ra_db = { path = "../ra_db" } | 16 | ra_db = { path = "../ra_db" } |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index 1dc9cac66..26b667b55 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -8,8 +8,7 @@ use ra_syntax::{ | |||
8 | match_ast, | 8 | match_ast, |
9 | }; | 9 | }; |
10 | 10 | ||
11 | use crate::db::AstDatabase; | 11 | use crate::{db::AstDatabase, name, quote, LazyMacroId, MacroDefId, MacroDefKind}; |
12 | use crate::{name, quote, LazyMacroId, MacroCallId, MacroDefId, MacroDefKind}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( $($trait:ident => $expand:ident),* ) => { | 14 | ( $($trait:ident => $expand:ident),* ) => { |
@@ -156,23 +155,13 @@ fn expand_simple_derive( | |||
156 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { | 155 | fn find_builtin_crate(db: &dyn AstDatabase, id: LazyMacroId) -> tt::TokenTree { |
157 | // FIXME: make hygiene works for builtin derive macro | 156 | // FIXME: make hygiene works for builtin derive macro |
158 | // such that $crate can be used here. | 157 | // such that $crate can be used here. |
159 | |||
160 | let m: MacroCallId = id.into(); | ||
161 | let file_id = m.as_file().original_file(db); | ||
162 | let cg = db.crate_graph(); | 158 | let cg = db.crate_graph(); |
163 | let krates = db.relevant_crates(file_id); | 159 | let krate = db.lookup_intern_macro(id).krate; |
164 | let krate = match krates.get(0) { | ||
165 | Some(krate) => krate, | ||
166 | None => { | ||
167 | let tt = quote! { core }; | ||
168 | return tt.token_trees[0].clone(); | ||
169 | } | ||
170 | }; | ||
171 | 160 | ||
172 | // XXX | 161 | // XXX |
173 | // All crates except core itself should have a dependency on core, | 162 | // All crates except core itself should have a dependency on core, |
174 | // We detect `core` by seeing whether it doesn't have such a dependency. | 163 | // We detect `core` by seeing whether it doesn't have such a dependency. |
175 | let tt = if cg[*krate].dependencies.iter().any(|dep| dep.name == "core") { | 164 | let tt = if cg[krate].dependencies.iter().any(|dep| dep.name == "core") { |
176 | quote! { core } | 165 | quote! { core } |
177 | } else { | 166 | } else { |
178 | quote! { crate } | 167 | quote! { crate } |
@@ -264,10 +253,12 @@ fn partial_ord_expand( | |||
264 | 253 | ||
265 | #[cfg(test)] | 254 | #[cfg(test)] |
266 | mod tests { | 255 | mod tests { |
267 | use super::*; | ||
268 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
269 | use name::{known, Name}; | 256 | use name::{known, Name}; |
270 | use ra_db::{fixture::WithFixture, SourceDatabase}; | 257 | use ra_db::{fixture::WithFixture, CrateId, SourceDatabase}; |
258 | |||
259 | use crate::{test_db::TestDB, AstId, MacroCallId, MacroCallKind, MacroCallLoc}; | ||
260 | |||
261 | use super::*; | ||
271 | 262 | ||
272 | fn expand_builtin_derive(s: &str, name: Name) -> String { | 263 | fn expand_builtin_derive(s: &str, name: Name) -> String { |
273 | let def = find_builtin_derive(&name).unwrap(); | 264 | let def = find_builtin_derive(&name).unwrap(); |
@@ -291,7 +282,11 @@ mod tests { | |||
291 | 282 | ||
292 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); | 283 | let attr_id = AstId::new(file_id.into(), ast_id_map.ast_id(&items[0])); |
293 | 284 | ||
294 | let loc = MacroCallLoc { def, kind: MacroCallKind::Attr(attr_id, name.to_string()) }; | 285 | let loc = MacroCallLoc { |
286 | def, | ||
287 | krate: CrateId(0), | ||
288 | kind: MacroCallKind::Attr(attr_id, name.to_string()), | ||
289 | }; | ||
295 | 290 | ||
296 | let id: MacroCallId = db.intern_macro(loc).into(); | 291 | let id: MacroCallId = db.intern_macro(loc).into(); |
297 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); | 292 | let parsed = db.parse_or_expand(id.as_file()).unwrap(); |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index 7579546d2..b50eb347c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -1,15 +1,14 @@ | |||
1 | //! Builtin macro | 1 | //! Builtin macro |
2 | use crate::db::AstDatabase; | ||
3 | use crate::{ | 2 | use crate::{ |
4 | ast::{self, AstToken, HasStringValue}, | 3 | db::AstDatabase, name, quote, AstId, CrateId, EagerMacroId, LazyMacroId, MacroCallId, |
5 | name, AstId, CrateId, MacroDefId, MacroDefKind, TextSize, | 4 | MacroDefId, MacroDefKind, TextSize, |
6 | }; | 5 | }; |
7 | 6 | ||
8 | use crate::{quote, EagerMacroId, LazyMacroId, MacroCallId}; | ||
9 | use either::Either; | 7 | use either::Either; |
10 | use mbe::parse_to_token_tree; | 8 | use mbe::parse_to_token_tree; |
11 | use ra_db::FileId; | 9 | use ra_db::FileId; |
12 | use ra_parser::FragmentKind; | 10 | use ra_parser::FragmentKind; |
11 | use ra_syntax::ast::{self, AstToken, HasStringValue}; | ||
13 | 12 | ||
14 | macro_rules! register_builtin { | 13 | macro_rules! register_builtin { |
15 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { | 14 | ( LAZY: $(($name:ident, $kind: ident) => $expand:ident),* , EAGER: $(($e_name:ident, $e_kind: ident) => $e_expand:ident),* ) => { |
@@ -333,10 +332,7 @@ fn include_expand( | |||
333 | } | 332 | } |
334 | 333 | ||
335 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { | 334 | fn get_env_inner(db: &dyn AstDatabase, arg_id: EagerMacroId, key: &str) -> Option<String> { |
336 | let call_id: MacroCallId = arg_id.into(); | 335 | let krate = db.lookup_intern_eager_expansion(arg_id).krate; |
337 | let original_file = call_id.as_file().original_file(db); | ||
338 | |||
339 | let krate = *db.relevant_crates(original_file).get(0)?; | ||
340 | db.crate_graph()[krate].env.get(key) | 336 | db.crate_graph()[krate].env.get(key) |
341 | } | 337 | } |
342 | 338 | ||
@@ -395,6 +391,7 @@ mod tests { | |||
395 | 391 | ||
396 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); | 392 | let expander = find_by_name(¯o_calls[0].name().unwrap().as_name()).unwrap(); |
397 | 393 | ||
394 | let krate = CrateId(0); | ||
398 | let file_id = match expander { | 395 | let file_id = match expander { |
399 | Either::Left(expander) => { | 396 | Either::Left(expander) => { |
400 | // the first one should be a macro_rules | 397 | // the first one should be a macro_rules |
@@ -407,6 +404,7 @@ mod tests { | |||
407 | 404 | ||
408 | let loc = MacroCallLoc { | 405 | let loc = MacroCallLoc { |
409 | def, | 406 | def, |
407 | krate, | ||
410 | kind: MacroCallKind::FnLike(AstId::new( | 408 | kind: MacroCallKind::FnLike(AstId::new( |
411 | file_id.into(), | 409 | file_id.into(), |
412 | ast_id_map.ast_id(¯o_calls[1]), | 410 | ast_id_map.ast_id(¯o_calls[1]), |
@@ -419,7 +417,7 @@ mod tests { | |||
419 | Either::Right(expander) => { | 417 | Either::Right(expander) => { |
420 | // the first one should be a macro_rules | 418 | // the first one should be a macro_rules |
421 | let def = MacroDefId { | 419 | let def = MacroDefId { |
422 | krate: Some(CrateId(0)), | 420 | krate: Some(krate), |
423 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 421 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
424 | kind: MacroDefKind::BuiltInEager(expander), | 422 | kind: MacroDefKind::BuiltInEager(expander), |
425 | local_inner: false, | 423 | local_inner: false, |
@@ -433,6 +431,7 @@ mod tests { | |||
433 | def, | 431 | def, |
434 | fragment: FragmentKind::Expr, | 432 | fragment: FragmentKind::Expr, |
435 | subtree: Arc::new(parsed_args.clone()), | 433 | subtree: Arc::new(parsed_args.clone()), |
434 | krate, | ||
436 | file_id: file_id.into(), | 435 | file_id: file_id.into(), |
437 | } | 436 | } |
438 | }); | 437 | }); |
@@ -442,6 +441,7 @@ mod tests { | |||
442 | def, | 441 | def, |
443 | fragment, | 442 | fragment, |
444 | subtree: Arc::new(subtree), | 443 | subtree: Arc::new(subtree), |
444 | krate, | ||
445 | file_id: file_id.into(), | 445 | file_id: file_id.into(), |
446 | }; | 446 | }; |
447 | 447 | ||
diff --git a/crates/ra_hir_expand/src/eager.rs b/crates/ra_hir_expand/src/eager.rs index 932f47c30..302d2b3e0 100644 --- a/crates/ra_hir_expand/src/eager.rs +++ b/crates/ra_hir_expand/src/eager.rs | |||
@@ -25,12 +25,14 @@ use crate::{ | |||
25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, | 25 | EagerCallLoc, EagerMacroId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind, |
26 | }; | 26 | }; |
27 | 27 | ||
28 | use ra_db::CrateId; | ||
28 | use ra_parser::FragmentKind; | 29 | use ra_parser::FragmentKind; |
29 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; | 30 | use ra_syntax::{algo::SyntaxRewriter, SyntaxNode}; |
30 | use std::sync::Arc; | 31 | use std::sync::Arc; |
31 | 32 | ||
32 | pub fn expand_eager_macro( | 33 | pub fn expand_eager_macro( |
33 | db: &dyn AstDatabase, | 34 | db: &dyn AstDatabase, |
35 | krate: CrateId, | ||
34 | macro_call: InFile<ast::MacroCall>, | 36 | macro_call: InFile<ast::MacroCall>, |
35 | def: MacroDefId, | 37 | def: MacroDefId, |
36 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 38 | resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
@@ -47,6 +49,7 @@ pub fn expand_eager_macro( | |||
47 | def, | 49 | def, |
48 | fragment: FragmentKind::Expr, | 50 | fragment: FragmentKind::Expr, |
49 | subtree: Arc::new(parsed_args.clone()), | 51 | subtree: Arc::new(parsed_args.clone()), |
52 | krate, | ||
50 | file_id: macro_call.file_id, | 53 | file_id: macro_call.file_id, |
51 | } | 54 | } |
52 | }); | 55 | }); |
@@ -56,14 +59,20 @@ pub fn expand_eager_macro( | |||
56 | let result = eager_macro_recur( | 59 | let result = eager_macro_recur( |
57 | db, | 60 | db, |
58 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), | 61 | InFile::new(arg_file_id.as_file(), parsed_args.syntax_node()), |
62 | krate, | ||
59 | resolver, | 63 | resolver, |
60 | )?; | 64 | )?; |
61 | let subtree = to_subtree(&result)?; | 65 | let subtree = to_subtree(&result)?; |
62 | 66 | ||
63 | if let MacroDefKind::BuiltInEager(eager) = def.kind { | 67 | if let MacroDefKind::BuiltInEager(eager) = def.kind { |
64 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; | 68 | let (subtree, fragment) = eager.expand(db, arg_id, &subtree).ok()?; |
65 | let eager = | 69 | let eager = EagerCallLoc { |
66 | EagerCallLoc { def, fragment, subtree: Arc::new(subtree), file_id: macro_call.file_id }; | 70 | def, |
71 | fragment, | ||
72 | subtree: Arc::new(subtree), | ||
73 | krate, | ||
74 | file_id: macro_call.file_id, | ||
75 | }; | ||
67 | 76 | ||
68 | Some(db.intern_eager_expansion(eager)) | 77 | Some(db.intern_eager_expansion(eager)) |
69 | } else { | 78 | } else { |
@@ -81,11 +90,12 @@ fn lazy_expand( | |||
81 | db: &dyn AstDatabase, | 90 | db: &dyn AstDatabase, |
82 | def: &MacroDefId, | 91 | def: &MacroDefId, |
83 | macro_call: InFile<ast::MacroCall>, | 92 | macro_call: InFile<ast::MacroCall>, |
93 | krate: CrateId, | ||
84 | ) -> Option<InFile<SyntaxNode>> { | 94 | ) -> Option<InFile<SyntaxNode>> { |
85 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); | 95 | let ast_id = db.ast_id_map(macro_call.file_id).ast_id(¯o_call.value); |
86 | 96 | ||
87 | let id: MacroCallId = | 97 | let id: MacroCallId = |
88 | def.as_lazy_macro(db, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); | 98 | def.as_lazy_macro(db, krate, MacroCallKind::FnLike(macro_call.with_value(ast_id))).into(); |
89 | 99 | ||
90 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) | 100 | db.parse_or_expand(id.as_file()).map(|node| InFile::new(id.as_file(), node)) |
91 | } | 101 | } |
@@ -93,6 +103,7 @@ fn lazy_expand( | |||
93 | fn eager_macro_recur( | 103 | fn eager_macro_recur( |
94 | db: &dyn AstDatabase, | 104 | db: &dyn AstDatabase, |
95 | curr: InFile<SyntaxNode>, | 105 | curr: InFile<SyntaxNode>, |
106 | krate: CrateId, | ||
96 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, | 107 | macro_resolver: &dyn Fn(ast::Path) -> Option<MacroDefId>, |
97 | ) -> Option<SyntaxNode> { | 108 | ) -> Option<SyntaxNode> { |
98 | let original = curr.value.clone(); | 109 | let original = curr.value.clone(); |
@@ -105,18 +116,23 @@ fn eager_macro_recur( | |||
105 | let def: MacroDefId = macro_resolver(child.path()?)?; | 116 | let def: MacroDefId = macro_resolver(child.path()?)?; |
106 | let insert = match def.kind { | 117 | let insert = match def.kind { |
107 | MacroDefKind::BuiltInEager(_) => { | 118 | MacroDefKind::BuiltInEager(_) => { |
108 | let id: MacroCallId = | 119 | let id: MacroCallId = expand_eager_macro( |
109 | expand_eager_macro(db, curr.with_value(child.clone()), def, macro_resolver)? | 120 | db, |
110 | .into(); | 121 | krate, |
122 | curr.with_value(child.clone()), | ||
123 | def, | ||
124 | macro_resolver, | ||
125 | )? | ||
126 | .into(); | ||
111 | db.parse_or_expand(id.as_file())? | 127 | db.parse_or_expand(id.as_file())? |
112 | } | 128 | } |
113 | MacroDefKind::Declarative | 129 | MacroDefKind::Declarative |
114 | | MacroDefKind::BuiltIn(_) | 130 | | MacroDefKind::BuiltIn(_) |
115 | | MacroDefKind::BuiltInDerive(_) | 131 | | MacroDefKind::BuiltInDerive(_) |
116 | | MacroDefKind::CustomDerive(_) => { | 132 | | MacroDefKind::CustomDerive(_) => { |
117 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()))?; | 133 | let expanded = lazy_expand(db, &def, curr.with_value(child.clone()), krate)?; |
118 | // replace macro inside | 134 | // replace macro inside |
119 | eager_macro_recur(db, expanded, macro_resolver)? | 135 | eager_macro_recur(db, expanded, krate, macro_resolver)? |
120 | } | 136 | } |
121 | }; | 137 | }; |
122 | 138 | ||
diff --git a/crates/ra_hir_expand/src/lib.rs b/crates/ra_hir_expand/src/lib.rs index f440c073b..5eac2605b 100644 --- a/crates/ra_hir_expand/src/lib.rs +++ b/crates/ra_hir_expand/src/lib.rs | |||
@@ -209,8 +209,13 @@ pub struct MacroDefId { | |||
209 | } | 209 | } |
210 | 210 | ||
211 | impl MacroDefId { | 211 | impl MacroDefId { |
212 | pub fn as_lazy_macro(self, db: &dyn db::AstDatabase, kind: MacroCallKind) -> LazyMacroId { | 212 | pub fn as_lazy_macro( |
213 | db.intern_macro(MacroCallLoc { def: self, kind }) | 213 | self, |
214 | db: &dyn db::AstDatabase, | ||
215 | krate: CrateId, | ||
216 | kind: MacroCallKind, | ||
217 | ) -> LazyMacroId { | ||
218 | db.intern_macro(MacroCallLoc { def: self, krate, kind }) | ||
214 | } | 219 | } |
215 | } | 220 | } |
216 | 221 | ||
@@ -227,6 +232,7 @@ pub enum MacroDefKind { | |||
227 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] | 232 | #[derive(Debug, Clone, PartialEq, Eq, Hash)] |
228 | pub struct MacroCallLoc { | 233 | pub struct MacroCallLoc { |
229 | pub(crate) def: MacroDefId, | 234 | pub(crate) def: MacroDefId, |
235 | pub(crate) krate: CrateId, | ||
230 | pub(crate) kind: MacroCallKind, | 236 | pub(crate) kind: MacroCallKind, |
231 | } | 237 | } |
232 | 238 | ||
@@ -274,6 +280,7 @@ pub struct EagerCallLoc { | |||
274 | pub(crate) def: MacroDefId, | 280 | pub(crate) def: MacroDefId, |
275 | pub(crate) fragment: FragmentKind, | 281 | pub(crate) fragment: FragmentKind, |
276 | pub(crate) subtree: Arc<tt::Subtree>, | 282 | pub(crate) subtree: Arc<tt::Subtree>, |
283 | pub(crate) krate: CrateId, | ||
277 | pub(crate) file_id: HirFileId, | 284 | pub(crate) file_id: HirFileId, |
278 | } | 285 | } |
279 | 286 | ||
diff --git a/crates/ra_hir_expand/src/test_db.rs b/crates/ra_hir_expand/src/test_db.rs index fdf225f55..09fc18c36 100644 --- a/crates/ra_hir_expand/src/test_db.rs +++ b/crates/ra_hir_expand/src/test_db.rs | |||
@@ -6,6 +6,7 @@ use std::{ | |||
6 | }; | 6 | }; |
7 | 7 | ||
8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; | 8 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate}; |
9 | use rustc_hash::FxHashSet; | ||
9 | 10 | ||
10 | #[salsa::database( | 11 | #[salsa::database( |
11 | ra_db::SourceDatabaseExtStorage, | 12 | ra_db::SourceDatabaseExtStorage, |
@@ -44,7 +45,7 @@ impl FileLoader for TestDB { | |||
44 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 45 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
45 | FileLoaderDelegate(self).resolve_path(anchor, path) | 46 | FileLoaderDelegate(self).resolve_path(anchor, path) |
46 | } | 47 | } |
47 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 48 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
48 | FileLoaderDelegate(self).relevant_crates(file_id) | 49 | FileLoaderDelegate(self).relevant_crates(file_id) |
49 | } | 50 | } |
50 | } | 51 | } |
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs index 3e6e1e333..02a7a61f1 100644 --- a/crates/ra_hir_ty/src/_match.rs +++ b/crates/ra_hir_ty/src/_match.rs | |||
@@ -8,11 +8,11 @@ | |||
8 | //! This file includes the logic for exhaustiveness and usefulness checking for | 8 | //! This file includes the logic for exhaustiveness and usefulness checking for |
9 | //! pattern-matching. Specifically, given a list of patterns for a type, we can | 9 | //! pattern-matching. Specifically, given a list of patterns for a type, we can |
10 | //! tell whether: | 10 | //! tell whether: |
11 | //! (a) the patterns cover every possible constructor for the type [exhaustiveness] | 11 | //! - (a) the patterns cover every possible constructor for the type (exhaustiveness). |
12 | //! (b) each pattern is necessary [usefulness] | 12 | //! - (b) each pattern is necessary (usefulness). |
13 | //! | 13 | //! |
14 | //! The algorithm implemented here is a modified version of the one described in: | 14 | //! The algorithm implemented here is a modified version of the one described in |
15 | //! http://moscova.inria.fr/~maranget/papers/warn/index.html | 15 | //! <http://moscova.inria.fr/~maranget/papers/warn/index.html>. |
16 | //! However, to save future implementors from reading the original paper, we | 16 | //! However, to save future implementors from reading the original paper, we |
17 | //! summarise the algorithm here to hopefully save time and be a little clearer | 17 | //! summarise the algorithm here to hopefully save time and be a little clearer |
18 | //! (without being so rigorous). | 18 | //! (without being so rigorous). |
@@ -37,20 +37,26 @@ | |||
37 | //! new pattern `p`. | 37 | //! new pattern `p`. |
38 | //! | 38 | //! |
39 | //! For example, say we have the following: | 39 | //! For example, say we have the following: |
40 | //! | ||
41 | //! ```ignore | ||
42 | //! // x: (Option<bool>, Result<()>) | ||
43 | //! match x { | ||
44 | //! (Some(true), _) => {} | ||
45 | //! (None, Err(())) => {} | ||
46 | //! (None, Err(_)) => {} | ||
47 | //! } | ||
40 | //! ``` | 48 | //! ``` |
41 | //! // x: (Option<bool>, Result<()>) | 49 | //! |
42 | //! match x { | ||
43 | //! (Some(true), _) => {} | ||
44 | //! (None, Err(())) => {} | ||
45 | //! (None, Err(_)) => {} | ||
46 | //! } | ||
47 | //! ``` | ||
48 | //! Here, the matrix `P` starts as: | 50 | //! Here, the matrix `P` starts as: |
51 | //! | ||
52 | //! ```text | ||
49 | //! [ | 53 | //! [ |
50 | //! [(Some(true), _)], | 54 | //! [(Some(true), _)], |
51 | //! [(None, Err(()))], | 55 | //! [(None, Err(()))], |
52 | //! [(None, Err(_))], | 56 | //! [(None, Err(_))], |
53 | //! ] | 57 | //! ] |
58 | //! ``` | ||
59 | //! | ||
54 | //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering | 60 | //! We can tell it's not exhaustive, because `U(P, _)` is true (we're not covering |
55 | //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because | 61 | //! `[(Some(false), _)]`, for instance). In addition, row 3 is not useful, because |
56 | //! all the values it covers are already covered by row 2. | 62 | //! all the values it covers are already covered by row 2. |
@@ -60,53 +66,61 @@ | |||
60 | //! To match the paper, the top of the stack is at the beginning / on the left. | 66 | //! To match the paper, the top of the stack is at the beginning / on the left. |
61 | //! | 67 | //! |
62 | //! There are two important operations on pattern-stacks necessary to understand the algorithm: | 68 | //! There are two important operations on pattern-stacks necessary to understand the algorithm: |
63 | //! 1. We can pop a given constructor off the top of a stack. This operation is called | ||
64 | //! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or | ||
65 | //! `None`) and `p` a pattern-stack. | ||
66 | //! If the pattern on top of the stack can cover `c`, this removes the constructor and | ||
67 | //! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. | ||
68 | //! Otherwise the pattern-stack is discarded. | ||
69 | //! This essentially filters those pattern-stacks whose top covers the constructor `c` and | ||
70 | //! discards the others. | ||
71 | //! | 69 | //! |
72 | //! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we | 70 | //! 1. We can pop a given constructor off the top of a stack. This operation is called |
73 | //! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the | 71 | //! `specialize`, and is denoted `S(c, p)` where `c` is a constructor (like `Some` or |
74 | //! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get | 72 | //! `None`) and `p` a pattern-stack. |
75 | //! nothing back. | 73 | //! If the pattern on top of the stack can cover `c`, this removes the constructor and |
74 | //! pushes its arguments onto the stack. It also expands OR-patterns into distinct patterns. | ||
75 | //! Otherwise the pattern-stack is discarded. | ||
76 | //! This essentially filters those pattern-stacks whose top covers the constructor `c` and | ||
77 | //! discards the others. | ||
78 | //! | ||
79 | //! For example, the first pattern above initially gives a stack `[(Some(true), _)]`. If we | ||
80 | //! pop the tuple constructor, we are left with `[Some(true), _]`, and if we then pop the | ||
81 | //! `Some` constructor we get `[true, _]`. If we had popped `None` instead, we would get | ||
82 | //! nothing back. | ||
83 | //! | ||
84 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` | ||
85 | //! on top of the stack, and we have four cases: | ||
86 | //! | ||
87 | //! * 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We push onto | ||
88 | //! the stack the arguments of this constructor, and return the result: | ||
76 | //! | 89 | //! |
77 | //! This returns zero or more new pattern-stacks, as follows. We look at the pattern `p_1` | 90 | //! r_1, .., r_a, p_2, .., p_n |
78 | //! on top of the stack, and we have four cases: | ||
79 | //! 1.1. `p_1 = c(r_1, .., r_a)`, i.e. the top of the stack has constructor `c`. We | ||
80 | //! push onto the stack the arguments of this constructor, and return the result: | ||
81 | //! r_1, .., r_a, p_2, .., p_n | ||
82 | //! 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and | ||
83 | //! return nothing. | ||
84 | //! 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has | ||
85 | //! arguments (its arity), and return the resulting stack: | ||
86 | //! _, .., _, p_2, .., p_n | ||
87 | //! 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting | ||
88 | //! stack: | ||
89 | //! S(c, (r_1, p_2, .., p_n)) | ||
90 | //! S(c, (r_2, p_2, .., p_n)) | ||
91 | //! | 91 | //! |
92 | //! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is | 92 | //! * 1.2. `p_1 = c'(r_1, .., r_a')` where `c ≠c'`. We discard the current stack and return |
93 | //! a pattern-stack. | 93 | //! nothing. |
94 | //! This is used when we know there are missing constructor cases, but there might be | 94 | //! * 1.3. `p_1 = _`. We push onto the stack as many wildcards as the constructor `c` has |
95 | //! existing wildcard patterns, so to check the usefulness of the matrix, we have to check | 95 | //! arguments (its arity), and return the resulting stack: |
96 | //! all its *other* components. | ||
97 | //! | 96 | //! |
98 | //! It is computed as follows. We look at the pattern `p_1` on top of the stack, | 97 | //! _, .., _, p_2, .., p_n |
99 | //! and we have three cases: | ||
100 | //! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. | ||
101 | //! 1.2. `p_1 = _`. We return the rest of the stack: | ||
102 | //! p_2, .., p_n | ||
103 | //! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting | ||
104 | //! stack. | ||
105 | //! D((r_1, p_2, .., p_n)) | ||
106 | //! D((r_2, p_2, .., p_n)) | ||
107 | //! | 98 | //! |
108 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the | 99 | //! * 1.4. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: |
109 | //! exhaustive integer matching rules, so they're written here for posterity. | 100 | //! |
101 | //! S(c, (r_1, p_2, .., p_n)) | ||
102 | //! S(c, (r_2, p_2, .., p_n)) | ||
103 | //! | ||
104 | //! 2. We can pop a wildcard off the top of the stack. This is called `D(p)`, where `p` is | ||
105 | //! a pattern-stack. | ||
106 | //! This is used when we know there are missing constructor cases, but there might be | ||
107 | //! existing wildcard patterns, so to check the usefulness of the matrix, we have to check | ||
108 | //! all its *other* components. | ||
109 | //! | ||
110 | //! It is computed as follows. We look at the pattern `p_1` on top of the stack, | ||
111 | //! and we have three cases: | ||
112 | //! * 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. | ||
113 | //! * 1.2. `p_1 = _`. We return the rest of the stack: | ||
114 | //! | ||
115 | //! p_2, .., p_n | ||
116 | //! | ||
117 | //! * 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting stack: | ||
118 | //! | ||
119 | //! D((r_1, p_2, .., p_n)) | ||
120 | //! D((r_2, p_2, .., p_n)) | ||
121 | //! | ||
122 | //! Note that the OR-patterns are not always used directly in Rust, but are used to derive the | ||
123 | //! exhaustive integer matching rules, so they're written here for posterity. | ||
110 | //! | 124 | //! |
111 | //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by | 125 | //! Both those operations extend straightforwardly to a list or pattern-stacks, i.e. a matrix, by |
112 | //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with | 126 | //! working row-by-row. Popping a constructor ends up keeping only the matrix rows that start with |
@@ -120,73 +134,88 @@ | |||
120 | //! operates principally on the first component of the matrix and new pattern-stack `p`. | 134 | //! operates principally on the first component of the matrix and new pattern-stack `p`. |
121 | //! This algorithm is realised in the `is_useful` function. | 135 | //! This algorithm is realised in the `is_useful` function. |
122 | //! | 136 | //! |
123 | //! Base case. (`n = 0`, i.e., an empty tuple pattern) | 137 | //! Base case (`n = 0`, i.e., an empty tuple pattern): |
124 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), | 138 | //! - If `P` already contains an empty pattern (i.e., if the number of patterns `m > 0`), then |
125 | //! then `U(P, p)` is false. | 139 | //! `U(P, p)` is false. |
126 | //! - Otherwise, `P` must be empty, so `U(P, p)` is true. | 140 | //! - Otherwise, `P` must be empty, so `U(P, p)` is true. |
141 | //! | ||
142 | //! Inductive step (`n > 0`, i.e., whether there's at least one column [which may then be expanded | ||
143 | //! into further columns later]). We're going to match on the top of the new pattern-stack, `p_1`: | ||
144 | //! | ||
145 | //! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. | ||
146 | //! Then, the usefulness of `p_1` can be reduced to whether it is useful when | ||
147 | //! we ignore all the patterns in the first column of `P` that involve other constructors. | ||
148 | //! This is where `S(c, P)` comes in: | ||
127 | //! | 149 | //! |
128 | //! Inductive step. (`n > 0`, i.e., whether there's at least one column | 150 | //! ```text |
129 | //! [which may then be expanded into further columns later]) | 151 | //! U(P, p) := U(S(c, P), S(c, p)) |
130 | //! We're going to match on the top of the new pattern-stack, `p_1`. | 152 | //! ``` |
131 | //! - If `p_1 == c(r_1, .., r_a)`, i.e. we have a constructor pattern. | ||
132 | //! Then, the usefulness of `p_1` can be reduced to whether it is useful when | ||
133 | //! we ignore all the patterns in the first column of `P` that involve other constructors. | ||
134 | //! This is where `S(c, P)` comes in: | ||
135 | //! `U(P, p) := U(S(c, P), S(c, p))` | ||
136 | //! This special case is handled in `is_useful_specialized`. | ||
137 | //! | 153 | //! |
138 | //! For example, if `P` is: | 154 | //! This special case is handled in `is_useful_specialized`. |
139 | //! [ | ||
140 | //! [Some(true), _], | ||
141 | //! [None, 0], | ||
142 | //! ] | ||
143 | //! and `p` is [Some(false), 0], then we don't care about row 2 since we know `p` only | ||
144 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the | ||
145 | //! arguments of `Some` to know whether some new value is covered. So we compute | ||
146 | //! `U([[true, _]], [false, 0])`. | ||
147 | //! | 155 | //! |
148 | //! - If `p_1 == _`, then we look at the list of constructors that appear in the first | 156 | //! For example, if `P` is: |
149 | //! component of the rows of `P`: | ||
150 | //! + If there are some constructors that aren't present, then we might think that the | ||
151 | //! wildcard `_` is useful, since it covers those constructors that weren't covered | ||
152 | //! before. | ||
153 | //! That's almost correct, but only works if there were no wildcards in those first | ||
154 | //! components. So we need to check that `p` is useful with respect to the rows that | ||
155 | //! start with a wildcard, if there are any. This is where `D` comes in: | ||
156 | //! `U(P, p) := U(D(P), D(p))` | ||
157 | //! | 157 | //! |
158 | //! For example, if `P` is: | 158 | //! ```text |
159 | //! [ | 159 | //! [ |
160 | //! [_, true, _], | 160 | //! [Some(true), _], |
161 | //! [None, false, 1], | 161 | //! [None, 0], |
162 | //! ] | 162 | //! ] |
163 | //! and `p` is [_, false, _], the `Some` constructor doesn't appear in `P`. So if we | 163 | //! ``` |
164 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a | ||
165 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. | ||
166 | //! | 164 | //! |
167 | //! + Otherwise, all possible constructors (for the relevant type) are present. In this | 165 | //! and `p` is `[Some(false), 0]`, then we don't care about row 2 since we know `p` only |
168 | //! case we must check whether the wildcard pattern covers any unmatched value. For | 166 | //! matches values that row 2 doesn't. For row 1 however, we need to dig into the |
169 | //! that, we can think of the `_` pattern as a big OR-pattern that covers all | 167 | //! arguments of `Some` to know whether some new value is covered. So we compute |
170 | //! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for | 168 | //! `U([[true, _]], [false, 0])`. |
171 | //! example. The wildcard pattern is useful in this case if it is useful when | ||
172 | //! specialized to one of the possible constructors. So we compute: | ||
173 | //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` | ||
174 | //! | 169 | //! |
175 | //! For example, if `P` is: | 170 | //! - If `p_1 == _`, then we look at the list of constructors that appear in the first component of |
176 | //! [ | 171 | //! the rows of `P`: |
177 | //! [Some(true), _], | 172 | //! - If there are some constructors that aren't present, then we might think that the |
178 | //! [None, false], | 173 | //! wildcard `_` is useful, since it covers those constructors that weren't covered |
179 | //! ] | 174 | //! before. |
180 | //! and `p` is [_, false], both `None` and `Some` constructors appear in the first | 175 | //! That's almost correct, but only works if there were no wildcards in those first |
181 | //! components of `P`. We will therefore try popping both constructors in turn: we | 176 | //! components. So we need to check that `p` is useful with respect to the rows that |
182 | //! compute U([[true, _]], [_, false]) for the `Some` constructor, and U([[false]], | 177 | //! start with a wildcard, if there are any. This is where `D` comes in: |
183 | //! [false]) for the `None` constructor. The first case returns true, so we know that | 178 | //! `U(P, p) := U(D(P), D(p))` |
184 | //! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched | ||
185 | //! before. | ||
186 | //! | 179 | //! |
187 | //! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: | 180 | //! For example, if `P` is: |
188 | //! `U(P, p) := U(P, (r_1, p_2, .., p_n)) | 181 | //! ```text |
189 | //! || U(P, (r_2, p_2, .., p_n))` | 182 | //! [ |
183 | //! [_, true, _], | ||
184 | //! [None, false, 1], | ||
185 | //! ] | ||
186 | //! ``` | ||
187 | //! and `p` is `[_, false, _]`, the `Some` constructor doesn't appear in `P`. So if we | ||
188 | //! only had row 2, we'd know that `p` is useful. However row 1 starts with a | ||
189 | //! wildcard, so we need to check whether `U([[true, _]], [false, 1])`. | ||
190 | //! | ||
191 | //! - Otherwise, all possible constructors (for the relevant type) are present. In this | ||
192 | //! case we must check whether the wildcard pattern covers any unmatched value. For | ||
193 | //! that, we can think of the `_` pattern as a big OR-pattern that covers all | ||
194 | //! possible constructors. For `Option`, that would mean `_ = None | Some(_)` for | ||
195 | //! example. The wildcard pattern is useful in this case if it is useful when | ||
196 | //! specialized to one of the possible constructors. So we compute: | ||
197 | //! `U(P, p) := ∃(k ϵ constructors) U(S(k, P), S(k, p))` | ||
198 | //! | ||
199 | //! For example, if `P` is: | ||
200 | //! ```text | ||
201 | //! [ | ||
202 | //! [Some(true), _], | ||
203 | //! [None, false], | ||
204 | //! ] | ||
205 | //! ``` | ||
206 | //! and `p` is `[_, false]`, both `None` and `Some` constructors appear in the first | ||
207 | //! components of `P`. We will therefore try popping both constructors in turn: we | ||
208 | //! compute `U([[true, _]], [_, false])` for the `Some` constructor, and `U([[false]], | ||
209 | //! [false])` for the `None` constructor. The first case returns true, so we know that | ||
210 | //! `p` is useful for `P`. Indeed, it matches `[Some(false), _]` that wasn't matched | ||
211 | //! before. | ||
212 | //! | ||
213 | //! - If `p_1 == r_1 | r_2`, then the usefulness depends on each `r_i` separately: | ||
214 | //! | ||
215 | //! ```text | ||
216 | //! U(P, p) := U(P, (r_1, p_2, .., p_n)) | ||
217 | //! || U(P, (r_2, p_2, .., p_n)) | ||
218 | //! ``` | ||
190 | use std::sync::Arc; | 219 | use std::sync::Arc; |
191 | 220 | ||
192 | use smallvec::{smallvec, SmallVec}; | 221 | use smallvec::{smallvec, SmallVec}; |
@@ -333,7 +362,12 @@ impl PatStack { | |||
333 | cx: &MatchCheckCtx, | 362 | cx: &MatchCheckCtx, |
334 | constructor: &Constructor, | 363 | constructor: &Constructor, |
335 | ) -> MatchCheckResult<Option<PatStack>> { | 364 | ) -> MatchCheckResult<Option<PatStack>> { |
336 | let result = match (self.head().as_pat(cx), constructor) { | 365 | if self.is_empty() { |
366 | return Ok(None); | ||
367 | } | ||
368 | |||
369 | let head_pat = self.head().as_pat(cx); | ||
370 | let result = match (head_pat, constructor) { | ||
337 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { | 371 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { |
338 | if ellipsis.is_some() { | 372 | if ellipsis.is_some() { |
339 | // If there are ellipsis here, we should add the correct number of | 373 | // If there are ellipsis here, we should add the correct number of |
@@ -502,7 +536,7 @@ impl Matrix { | |||
502 | } | 536 | } |
503 | 537 | ||
504 | fn heads(&self) -> Vec<PatIdOrWild> { | 538 | fn heads(&self) -> Vec<PatIdOrWild> { |
505 | self.0.iter().map(|p| p.head()).collect() | 539 | self.0.iter().flat_map(|p| p.get_head()).collect() |
506 | } | 540 | } |
507 | 541 | ||
508 | /// Computes `D(self)` for each contained PatStack. | 542 | /// Computes `D(self)` for each contained PatStack. |
@@ -808,194 +842,193 @@ mod tests { | |||
808 | 842 | ||
809 | pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; | 843 | pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; |
810 | 844 | ||
811 | pub(super) fn check_diagnostic_message(content: &str) -> String { | 845 | pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String { |
812 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().0 | 846 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0 |
813 | } | 847 | } |
814 | 848 | ||
815 | pub(super) fn check_diagnostic(content: &str) { | 849 | pub(super) fn check_diagnostic(ra_fixture: &str) { |
816 | let diagnostic_count = | 850 | let diagnostic_count = |
817 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; | 851 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1; |
818 | 852 | ||
819 | assert_eq!(1, diagnostic_count, "no diagnostic reported"); | 853 | assert_eq!(1, diagnostic_count, "no diagnostic reported"); |
820 | } | 854 | } |
821 | 855 | ||
822 | pub(super) fn check_no_diagnostic(content: &str) { | 856 | pub(super) fn check_no_diagnostic(ra_fixture: &str) { |
823 | let diagnostic_count = | 857 | let diagnostic_count = |
824 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; | 858 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1; |
825 | 859 | ||
826 | assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); | 860 | assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); |
827 | } | 861 | } |
828 | 862 | ||
829 | #[test] | 863 | #[test] |
830 | fn empty_tuple_no_arms_diagnostic_message() { | 864 | fn empty_tuple_no_arms_diagnostic_message() { |
831 | let content = r" | ||
832 | fn test_fn() { | ||
833 | match () { | ||
834 | } | ||
835 | } | ||
836 | "; | ||
837 | |||
838 | assert_snapshot!( | 865 | assert_snapshot!( |
839 | check_diagnostic_message(content), | 866 | check_diagnostic_message(r" |
867 | fn test_fn() { | ||
868 | match () { | ||
869 | } | ||
870 | } | ||
871 | "), | ||
840 | @"\"()\": Missing match arm\n" | 872 | @"\"()\": Missing match arm\n" |
841 | ); | 873 | ); |
842 | } | 874 | } |
843 | 875 | ||
844 | #[test] | 876 | #[test] |
845 | fn empty_tuple_no_arms() { | 877 | fn empty_tuple_no_arms() { |
846 | let content = r" | 878 | check_diagnostic( |
879 | r" | ||
847 | fn test_fn() { | 880 | fn test_fn() { |
848 | match () { | 881 | match () { |
849 | } | 882 | } |
850 | } | 883 | } |
851 | "; | 884 | ", |
852 | 885 | ); | |
853 | check_diagnostic(content); | ||
854 | } | 886 | } |
855 | 887 | ||
856 | #[test] | 888 | #[test] |
857 | fn empty_tuple_wild() { | 889 | fn empty_tuple_wild() { |
858 | let content = r" | 890 | check_no_diagnostic( |
891 | r" | ||
859 | fn test_fn() { | 892 | fn test_fn() { |
860 | match () { | 893 | match () { |
861 | _ => {} | 894 | _ => {} |
862 | } | 895 | } |
863 | } | 896 | } |
864 | "; | 897 | ", |
865 | 898 | ); | |
866 | check_no_diagnostic(content); | ||
867 | } | 899 | } |
868 | 900 | ||
869 | #[test] | 901 | #[test] |
870 | fn empty_tuple_no_diagnostic() { | 902 | fn empty_tuple_no_diagnostic() { |
871 | let content = r" | 903 | check_no_diagnostic( |
904 | r" | ||
872 | fn test_fn() { | 905 | fn test_fn() { |
873 | match () { | 906 | match () { |
874 | () => {} | 907 | () => {} |
875 | } | 908 | } |
876 | } | 909 | } |
877 | "; | 910 | ", |
878 | 911 | ); | |
879 | check_no_diagnostic(content); | ||
880 | } | 912 | } |
881 | 913 | ||
882 | #[test] | 914 | #[test] |
883 | fn tuple_of_empty_tuple_no_arms() { | 915 | fn tuple_of_empty_tuple_no_arms() { |
884 | let content = r" | 916 | check_diagnostic( |
917 | r" | ||
885 | fn test_fn() { | 918 | fn test_fn() { |
886 | match (()) { | 919 | match (()) { |
887 | } | 920 | } |
888 | } | 921 | } |
889 | "; | 922 | ", |
890 | 923 | ); | |
891 | check_diagnostic(content); | ||
892 | } | 924 | } |
893 | 925 | ||
894 | #[test] | 926 | #[test] |
895 | fn tuple_of_empty_tuple_no_diagnostic() { | 927 | fn tuple_of_empty_tuple_no_diagnostic() { |
896 | let content = r" | 928 | check_no_diagnostic( |
929 | r" | ||
897 | fn test_fn() { | 930 | fn test_fn() { |
898 | match (()) { | 931 | match (()) { |
899 | (()) => {} | 932 | (()) => {} |
900 | } | 933 | } |
901 | } | 934 | } |
902 | "; | 935 | ", |
903 | 936 | ); | |
904 | check_no_diagnostic(content); | ||
905 | } | 937 | } |
906 | 938 | ||
907 | #[test] | 939 | #[test] |
908 | fn tuple_of_two_empty_tuple_no_arms() { | 940 | fn tuple_of_two_empty_tuple_no_arms() { |
909 | let content = r" | 941 | check_diagnostic( |
942 | r" | ||
910 | fn test_fn() { | 943 | fn test_fn() { |
911 | match ((), ()) { | 944 | match ((), ()) { |
912 | } | 945 | } |
913 | } | 946 | } |
914 | "; | 947 | ", |
915 | 948 | ); | |
916 | check_diagnostic(content); | ||
917 | } | 949 | } |
918 | 950 | ||
919 | #[test] | 951 | #[test] |
920 | fn tuple_of_two_empty_tuple_no_diagnostic() { | 952 | fn tuple_of_two_empty_tuple_no_diagnostic() { |
921 | let content = r" | 953 | check_no_diagnostic( |
954 | r" | ||
922 | fn test_fn() { | 955 | fn test_fn() { |
923 | match ((), ()) { | 956 | match ((), ()) { |
924 | ((), ()) => {} | 957 | ((), ()) => {} |
925 | } | 958 | } |
926 | } | 959 | } |
927 | "; | 960 | ", |
928 | 961 | ); | |
929 | check_no_diagnostic(content); | ||
930 | } | 962 | } |
931 | 963 | ||
932 | #[test] | 964 | #[test] |
933 | fn bool_no_arms() { | 965 | fn bool_no_arms() { |
934 | let content = r" | 966 | check_diagnostic( |
967 | r" | ||
935 | fn test_fn() { | 968 | fn test_fn() { |
936 | match false { | 969 | match false { |
937 | } | 970 | } |
938 | } | 971 | } |
939 | "; | 972 | ", |
940 | 973 | ); | |
941 | check_diagnostic(content); | ||
942 | } | 974 | } |
943 | 975 | ||
944 | #[test] | 976 | #[test] |
945 | fn bool_missing_arm() { | 977 | fn bool_missing_arm() { |
946 | let content = r" | 978 | check_diagnostic( |
979 | r" | ||
947 | fn test_fn() { | 980 | fn test_fn() { |
948 | match false { | 981 | match false { |
949 | true => {} | 982 | true => {} |
950 | } | 983 | } |
951 | } | 984 | } |
952 | "; | 985 | ", |
953 | 986 | ); | |
954 | check_diagnostic(content); | ||
955 | } | 987 | } |
956 | 988 | ||
957 | #[test] | 989 | #[test] |
958 | fn bool_no_diagnostic() { | 990 | fn bool_no_diagnostic() { |
959 | let content = r" | 991 | check_no_diagnostic( |
992 | r" | ||
960 | fn test_fn() { | 993 | fn test_fn() { |
961 | match false { | 994 | match false { |
962 | true => {} | 995 | true => {} |
963 | false => {} | 996 | false => {} |
964 | } | 997 | } |
965 | } | 998 | } |
966 | "; | 999 | ", |
967 | 1000 | ); | |
968 | check_no_diagnostic(content); | ||
969 | } | 1001 | } |
970 | 1002 | ||
971 | #[test] | 1003 | #[test] |
972 | fn tuple_of_bools_no_arms() { | 1004 | fn tuple_of_bools_no_arms() { |
973 | let content = r" | 1005 | check_diagnostic( |
1006 | r" | ||
974 | fn test_fn() { | 1007 | fn test_fn() { |
975 | match (false, true) { | 1008 | match (false, true) { |
976 | } | 1009 | } |
977 | } | 1010 | } |
978 | "; | 1011 | ", |
979 | 1012 | ); | |
980 | check_diagnostic(content); | ||
981 | } | 1013 | } |
982 | 1014 | ||
983 | #[test] | 1015 | #[test] |
984 | fn tuple_of_bools_missing_arms() { | 1016 | fn tuple_of_bools_missing_arms() { |
985 | let content = r" | 1017 | check_diagnostic( |
1018 | r" | ||
986 | fn test_fn() { | 1019 | fn test_fn() { |
987 | match (false, true) { | 1020 | match (false, true) { |
988 | (true, true) => {}, | 1021 | (true, true) => {}, |
989 | } | 1022 | } |
990 | } | 1023 | } |
991 | "; | 1024 | ", |
992 | 1025 | ); | |
993 | check_diagnostic(content); | ||
994 | } | 1026 | } |
995 | 1027 | ||
996 | #[test] | 1028 | #[test] |
997 | fn tuple_of_bools_missing_arm() { | 1029 | fn tuple_of_bools_missing_arm() { |
998 | let content = r" | 1030 | check_diagnostic( |
1031 | r" | ||
999 | fn test_fn() { | 1032 | fn test_fn() { |
1000 | match (false, true) { | 1033 | match (false, true) { |
1001 | (false, true) => {}, | 1034 | (false, true) => {}, |
@@ -1003,14 +1036,14 @@ mod tests { | |||
1003 | (true, false) => {}, | 1036 | (true, false) => {}, |
1004 | } | 1037 | } |
1005 | } | 1038 | } |
1006 | "; | 1039 | ", |
1007 | 1040 | ); | |
1008 | check_diagnostic(content); | ||
1009 | } | 1041 | } |
1010 | 1042 | ||
1011 | #[test] | 1043 | #[test] |
1012 | fn tuple_of_bools_with_wilds() { | 1044 | fn tuple_of_bools_with_wilds() { |
1013 | let content = r" | 1045 | check_no_diagnostic( |
1046 | r" | ||
1014 | fn test_fn() { | 1047 | fn test_fn() { |
1015 | match (false, true) { | 1048 | match (false, true) { |
1016 | (false, _) => {}, | 1049 | (false, _) => {}, |
@@ -1018,14 +1051,14 @@ mod tests { | |||
1018 | (_, true) => {}, | 1051 | (_, true) => {}, |
1019 | } | 1052 | } |
1020 | } | 1053 | } |
1021 | "; | 1054 | ", |
1022 | 1055 | ); | |
1023 | check_no_diagnostic(content); | ||
1024 | } | 1056 | } |
1025 | 1057 | ||
1026 | #[test] | 1058 | #[test] |
1027 | fn tuple_of_bools_no_diagnostic() { | 1059 | fn tuple_of_bools_no_diagnostic() { |
1028 | let content = r" | 1060 | check_no_diagnostic( |
1061 | r" | ||
1029 | fn test_fn() { | 1062 | fn test_fn() { |
1030 | match (false, true) { | 1063 | match (false, true) { |
1031 | (true, true) => {}, | 1064 | (true, true) => {}, |
@@ -1034,27 +1067,27 @@ mod tests { | |||
1034 | (false, false) => {}, | 1067 | (false, false) => {}, |
1035 | } | 1068 | } |
1036 | } | 1069 | } |
1037 | "; | 1070 | ", |
1038 | 1071 | ); | |
1039 | check_no_diagnostic(content); | ||
1040 | } | 1072 | } |
1041 | 1073 | ||
1042 | #[test] | 1074 | #[test] |
1043 | fn tuple_of_bools_binding_missing_arms() { | 1075 | fn tuple_of_bools_binding_missing_arms() { |
1044 | let content = r" | 1076 | check_diagnostic( |
1077 | r" | ||
1045 | fn test_fn() { | 1078 | fn test_fn() { |
1046 | match (false, true) { | 1079 | match (false, true) { |
1047 | (true, _x) => {}, | 1080 | (true, _x) => {}, |
1048 | } | 1081 | } |
1049 | } | 1082 | } |
1050 | "; | 1083 | ", |
1051 | 1084 | ); | |
1052 | check_diagnostic(content); | ||
1053 | } | 1085 | } |
1054 | 1086 | ||
1055 | #[test] | 1087 | #[test] |
1056 | fn tuple_of_bools_binding_no_diagnostic() { | 1088 | fn tuple_of_bools_binding_no_diagnostic() { |
1057 | let content = r" | 1089 | check_no_diagnostic( |
1090 | r" | ||
1058 | fn test_fn() { | 1091 | fn test_fn() { |
1059 | match (false, true) { | 1092 | match (false, true) { |
1060 | (true, _x) => {}, | 1093 | (true, _x) => {}, |
@@ -1062,80 +1095,80 @@ mod tests { | |||
1062 | (false, false) => {}, | 1095 | (false, false) => {}, |
1063 | } | 1096 | } |
1064 | } | 1097 | } |
1065 | "; | 1098 | ", |
1066 | 1099 | ); | |
1067 | check_no_diagnostic(content); | ||
1068 | } | 1100 | } |
1069 | 1101 | ||
1070 | #[test] | 1102 | #[test] |
1071 | fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { | 1103 | fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { |
1072 | let content = r" | 1104 | check_no_diagnostic( |
1105 | r" | ||
1073 | fn test_fn() { | 1106 | fn test_fn() { |
1074 | match (false, true, false) { | 1107 | match (false, true, false) { |
1075 | (false, ..) => {}, | 1108 | (false, ..) => {}, |
1076 | (true, ..) => {}, | 1109 | (true, ..) => {}, |
1077 | } | 1110 | } |
1078 | } | 1111 | } |
1079 | "; | 1112 | ", |
1080 | 1113 | ); | |
1081 | check_no_diagnostic(content); | ||
1082 | } | 1114 | } |
1083 | 1115 | ||
1084 | #[test] | 1116 | #[test] |
1085 | fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { | 1117 | fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { |
1086 | let content = r" | 1118 | check_no_diagnostic( |
1119 | r" | ||
1087 | fn test_fn() { | 1120 | fn test_fn() { |
1088 | match (false, true, false) { | 1121 | match (false, true, false) { |
1089 | (.., false) => {}, | 1122 | (.., false) => {}, |
1090 | (.., true) => {}, | 1123 | (.., true) => {}, |
1091 | } | 1124 | } |
1092 | } | 1125 | } |
1093 | "; | 1126 | ", |
1094 | 1127 | ); | |
1095 | check_no_diagnostic(content); | ||
1096 | } | 1128 | } |
1097 | 1129 | ||
1098 | #[test] | 1130 | #[test] |
1099 | fn tuple_of_bools_with_ellipsis_no_diagnostic() { | 1131 | fn tuple_of_bools_with_ellipsis_no_diagnostic() { |
1100 | let content = r" | 1132 | check_no_diagnostic( |
1133 | r" | ||
1101 | fn test_fn() { | 1134 | fn test_fn() { |
1102 | match (false, true, false) { | 1135 | match (false, true, false) { |
1103 | (..) => {}, | 1136 | (..) => {}, |
1104 | } | 1137 | } |
1105 | } | 1138 | } |
1106 | "; | 1139 | ", |
1107 | 1140 | ); | |
1108 | check_no_diagnostic(content); | ||
1109 | } | 1141 | } |
1110 | 1142 | ||
1111 | #[test] | 1143 | #[test] |
1112 | fn tuple_of_tuple_and_bools_no_arms() { | 1144 | fn tuple_of_tuple_and_bools_no_arms() { |
1113 | let content = r" | 1145 | check_diagnostic( |
1146 | r" | ||
1114 | fn test_fn() { | 1147 | fn test_fn() { |
1115 | match (false, ((), false)) { | 1148 | match (false, ((), false)) { |
1116 | } | 1149 | } |
1117 | } | 1150 | } |
1118 | "; | 1151 | ", |
1119 | 1152 | ); | |
1120 | check_diagnostic(content); | ||
1121 | } | 1153 | } |
1122 | 1154 | ||
1123 | #[test] | 1155 | #[test] |
1124 | fn tuple_of_tuple_and_bools_missing_arms() { | 1156 | fn tuple_of_tuple_and_bools_missing_arms() { |
1125 | let content = r" | 1157 | check_diagnostic( |
1158 | r" | ||
1126 | fn test_fn() { | 1159 | fn test_fn() { |
1127 | match (false, ((), false)) { | 1160 | match (false, ((), false)) { |
1128 | (true, ((), true)) => {}, | 1161 | (true, ((), true)) => {}, |
1129 | } | 1162 | } |
1130 | } | 1163 | } |
1131 | "; | 1164 | ", |
1132 | 1165 | ); | |
1133 | check_diagnostic(content); | ||
1134 | } | 1166 | } |
1135 | 1167 | ||
1136 | #[test] | 1168 | #[test] |
1137 | fn tuple_of_tuple_and_bools_no_diagnostic() { | 1169 | fn tuple_of_tuple_and_bools_no_diagnostic() { |
1138 | let content = r" | 1170 | check_no_diagnostic( |
1171 | r" | ||
1139 | fn test_fn() { | 1172 | fn test_fn() { |
1140 | match (false, ((), false)) { | 1173 | match (false, ((), false)) { |
1141 | (true, ((), true)) => {}, | 1174 | (true, ((), true)) => {}, |
@@ -1144,27 +1177,27 @@ mod tests { | |||
1144 | (false, ((), false)) => {}, | 1177 | (false, ((), false)) => {}, |
1145 | } | 1178 | } |
1146 | } | 1179 | } |
1147 | "; | 1180 | ", |
1148 | 1181 | ); | |
1149 | check_no_diagnostic(content); | ||
1150 | } | 1182 | } |
1151 | 1183 | ||
1152 | #[test] | 1184 | #[test] |
1153 | fn tuple_of_tuple_and_bools_wildcard_missing_arms() { | 1185 | fn tuple_of_tuple_and_bools_wildcard_missing_arms() { |
1154 | let content = r" | 1186 | check_diagnostic( |
1187 | r" | ||
1155 | fn test_fn() { | 1188 | fn test_fn() { |
1156 | match (false, ((), false)) { | 1189 | match (false, ((), false)) { |
1157 | (true, _) => {}, | 1190 | (true, _) => {}, |
1158 | } | 1191 | } |
1159 | } | 1192 | } |
1160 | "; | 1193 | ", |
1161 | 1194 | ); | |
1162 | check_diagnostic(content); | ||
1163 | } | 1195 | } |
1164 | 1196 | ||
1165 | #[test] | 1197 | #[test] |
1166 | fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { | 1198 | fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { |
1167 | let content = r" | 1199 | check_no_diagnostic( |
1200 | r" | ||
1168 | fn test_fn() { | 1201 | fn test_fn() { |
1169 | match (false, ((), false)) { | 1202 | match (false, ((), false)) { |
1170 | (true, ((), true)) => {}, | 1203 | (true, ((), true)) => {}, |
@@ -1172,14 +1205,14 @@ mod tests { | |||
1172 | (false, _) => {}, | 1205 | (false, _) => {}, |
1173 | } | 1206 | } |
1174 | } | 1207 | } |
1175 | "; | 1208 | ", |
1176 | 1209 | ); | |
1177 | check_no_diagnostic(content); | ||
1178 | } | 1210 | } |
1179 | 1211 | ||
1180 | #[test] | 1212 | #[test] |
1181 | fn enum_no_arms() { | 1213 | fn enum_no_arms() { |
1182 | let content = r" | 1214 | check_diagnostic( |
1215 | r" | ||
1183 | enum Either { | 1216 | enum Either { |
1184 | A, | 1217 | A, |
1185 | B, | 1218 | B, |
@@ -1188,14 +1221,14 @@ mod tests { | |||
1188 | match Either::A { | 1221 | match Either::A { |
1189 | } | 1222 | } |
1190 | } | 1223 | } |
1191 | "; | 1224 | ", |
1192 | 1225 | ); | |
1193 | check_diagnostic(content); | ||
1194 | } | 1226 | } |
1195 | 1227 | ||
1196 | #[test] | 1228 | #[test] |
1197 | fn enum_missing_arms() { | 1229 | fn enum_missing_arms() { |
1198 | let content = r" | 1230 | check_diagnostic( |
1231 | r" | ||
1199 | enum Either { | 1232 | enum Either { |
1200 | A, | 1233 | A, |
1201 | B, | 1234 | B, |
@@ -1205,14 +1238,14 @@ mod tests { | |||
1205 | Either::A => {}, | 1238 | Either::A => {}, |
1206 | } | 1239 | } |
1207 | } | 1240 | } |
1208 | "; | 1241 | ", |
1209 | 1242 | ); | |
1210 | check_diagnostic(content); | ||
1211 | } | 1243 | } |
1212 | 1244 | ||
1213 | #[test] | 1245 | #[test] |
1214 | fn enum_no_diagnostic() { | 1246 | fn enum_no_diagnostic() { |
1215 | let content = r" | 1247 | check_no_diagnostic( |
1248 | r" | ||
1216 | enum Either { | 1249 | enum Either { |
1217 | A, | 1250 | A, |
1218 | B, | 1251 | B, |
@@ -1223,14 +1256,14 @@ mod tests { | |||
1223 | Either::B => {}, | 1256 | Either::B => {}, |
1224 | } | 1257 | } |
1225 | } | 1258 | } |
1226 | "; | 1259 | ", |
1227 | 1260 | ); | |
1228 | check_no_diagnostic(content); | ||
1229 | } | 1261 | } |
1230 | 1262 | ||
1231 | #[test] | 1263 | #[test] |
1232 | fn enum_ref_missing_arms() { | 1264 | fn enum_ref_missing_arms() { |
1233 | let content = r" | 1265 | check_diagnostic( |
1266 | r" | ||
1234 | enum Either { | 1267 | enum Either { |
1235 | A, | 1268 | A, |
1236 | B, | 1269 | B, |
@@ -1240,14 +1273,14 @@ mod tests { | |||
1240 | Either::A => {}, | 1273 | Either::A => {}, |
1241 | } | 1274 | } |
1242 | } | 1275 | } |
1243 | "; | 1276 | ", |
1244 | 1277 | ); | |
1245 | check_diagnostic(content); | ||
1246 | } | 1278 | } |
1247 | 1279 | ||
1248 | #[test] | 1280 | #[test] |
1249 | fn enum_ref_no_diagnostic() { | 1281 | fn enum_ref_no_diagnostic() { |
1250 | let content = r" | 1282 | check_no_diagnostic( |
1283 | r" | ||
1251 | enum Either { | 1284 | enum Either { |
1252 | A, | 1285 | A, |
1253 | B, | 1286 | B, |
@@ -1258,14 +1291,14 @@ mod tests { | |||
1258 | Either::B => {}, | 1291 | Either::B => {}, |
1259 | } | 1292 | } |
1260 | } | 1293 | } |
1261 | "; | 1294 | ", |
1262 | 1295 | ); | |
1263 | check_no_diagnostic(content); | ||
1264 | } | 1296 | } |
1265 | 1297 | ||
1266 | #[test] | 1298 | #[test] |
1267 | fn enum_containing_bool_no_arms() { | 1299 | fn enum_containing_bool_no_arms() { |
1268 | let content = r" | 1300 | check_diagnostic( |
1301 | r" | ||
1269 | enum Either { | 1302 | enum Either { |
1270 | A(bool), | 1303 | A(bool), |
1271 | B, | 1304 | B, |
@@ -1274,14 +1307,14 @@ mod tests { | |||
1274 | match Either::B { | 1307 | match Either::B { |
1275 | } | 1308 | } |
1276 | } | 1309 | } |
1277 | "; | 1310 | ", |
1278 | 1311 | ); | |
1279 | check_diagnostic(content); | ||
1280 | } | 1312 | } |
1281 | 1313 | ||
1282 | #[test] | 1314 | #[test] |
1283 | fn enum_containing_bool_missing_arms() { | 1315 | fn enum_containing_bool_missing_arms() { |
1284 | let content = r" | 1316 | check_diagnostic( |
1317 | r" | ||
1285 | enum Either { | 1318 | enum Either { |
1286 | A(bool), | 1319 | A(bool), |
1287 | B, | 1320 | B, |
@@ -1292,14 +1325,14 @@ mod tests { | |||
1292 | Either::B => (), | 1325 | Either::B => (), |
1293 | } | 1326 | } |
1294 | } | 1327 | } |
1295 | "; | 1328 | ", |
1296 | 1329 | ); | |
1297 | check_diagnostic(content); | ||
1298 | } | 1330 | } |
1299 | 1331 | ||
1300 | #[test] | 1332 | #[test] |
1301 | fn enum_containing_bool_no_diagnostic() { | 1333 | fn enum_containing_bool_no_diagnostic() { |
1302 | let content = r" | 1334 | check_no_diagnostic( |
1335 | r" | ||
1303 | enum Either { | 1336 | enum Either { |
1304 | A(bool), | 1337 | A(bool), |
1305 | B, | 1338 | B, |
@@ -1311,14 +1344,14 @@ mod tests { | |||
1311 | Either::B => (), | 1344 | Either::B => (), |
1312 | } | 1345 | } |
1313 | } | 1346 | } |
1314 | "; | 1347 | ", |
1315 | 1348 | ); | |
1316 | check_no_diagnostic(content); | ||
1317 | } | 1349 | } |
1318 | 1350 | ||
1319 | #[test] | 1351 | #[test] |
1320 | fn enum_containing_bool_with_wild_no_diagnostic() { | 1352 | fn enum_containing_bool_with_wild_no_diagnostic() { |
1321 | let content = r" | 1353 | check_no_diagnostic( |
1354 | r" | ||
1322 | enum Either { | 1355 | enum Either { |
1323 | A(bool), | 1356 | A(bool), |
1324 | B, | 1357 | B, |
@@ -1329,14 +1362,14 @@ mod tests { | |||
1329 | _ => (), | 1362 | _ => (), |
1330 | } | 1363 | } |
1331 | } | 1364 | } |
1332 | "; | 1365 | ", |
1333 | 1366 | ); | |
1334 | check_no_diagnostic(content); | ||
1335 | } | 1367 | } |
1336 | 1368 | ||
1337 | #[test] | 1369 | #[test] |
1338 | fn enum_containing_bool_with_wild_2_no_diagnostic() { | 1370 | fn enum_containing_bool_with_wild_2_no_diagnostic() { |
1339 | let content = r" | 1371 | check_no_diagnostic( |
1372 | r" | ||
1340 | enum Either { | 1373 | enum Either { |
1341 | A(bool), | 1374 | A(bool), |
1342 | B, | 1375 | B, |
@@ -1347,14 +1380,14 @@ mod tests { | |||
1347 | Either::B => (), | 1380 | Either::B => (), |
1348 | } | 1381 | } |
1349 | } | 1382 | } |
1350 | "; | 1383 | ", |
1351 | 1384 | ); | |
1352 | check_no_diagnostic(content); | ||
1353 | } | 1385 | } |
1354 | 1386 | ||
1355 | #[test] | 1387 | #[test] |
1356 | fn enum_different_sizes_missing_arms() { | 1388 | fn enum_different_sizes_missing_arms() { |
1357 | let content = r" | 1389 | check_diagnostic( |
1390 | r" | ||
1358 | enum Either { | 1391 | enum Either { |
1359 | A(bool), | 1392 | A(bool), |
1360 | B(bool, bool), | 1393 | B(bool, bool), |
@@ -1365,14 +1398,14 @@ mod tests { | |||
1365 | Either::B(false, _) => (), | 1398 | Either::B(false, _) => (), |
1366 | } | 1399 | } |
1367 | } | 1400 | } |
1368 | "; | 1401 | ", |
1369 | 1402 | ); | |
1370 | check_diagnostic(content); | ||
1371 | } | 1403 | } |
1372 | 1404 | ||
1373 | #[test] | 1405 | #[test] |
1374 | fn enum_different_sizes_no_diagnostic() { | 1406 | fn enum_different_sizes_no_diagnostic() { |
1375 | let content = r" | 1407 | check_no_diagnostic( |
1408 | r" | ||
1376 | enum Either { | 1409 | enum Either { |
1377 | A(bool), | 1410 | A(bool), |
1378 | B(bool, bool), | 1411 | B(bool, bool), |
@@ -1384,14 +1417,14 @@ mod tests { | |||
1384 | Either::B(false, _) => (), | 1417 | Either::B(false, _) => (), |
1385 | } | 1418 | } |
1386 | } | 1419 | } |
1387 | "; | 1420 | ", |
1388 | 1421 | ); | |
1389 | check_no_diagnostic(content); | ||
1390 | } | 1422 | } |
1391 | 1423 | ||
1392 | #[test] | 1424 | #[test] |
1393 | fn or_no_diagnostic() { | 1425 | fn or_no_diagnostic() { |
1394 | let content = r" | 1426 | check_no_diagnostic( |
1427 | r" | ||
1395 | enum Either { | 1428 | enum Either { |
1396 | A(bool), | 1429 | A(bool), |
1397 | B(bool, bool), | 1430 | B(bool, bool), |
@@ -1403,14 +1436,14 @@ mod tests { | |||
1403 | Either::B(false, _) => (), | 1436 | Either::B(false, _) => (), |
1404 | } | 1437 | } |
1405 | } | 1438 | } |
1406 | "; | 1439 | ", |
1407 | 1440 | ); | |
1408 | check_no_diagnostic(content); | ||
1409 | } | 1441 | } |
1410 | 1442 | ||
1411 | #[test] | 1443 | #[test] |
1412 | fn tuple_of_enum_no_diagnostic() { | 1444 | fn tuple_of_enum_no_diagnostic() { |
1413 | let content = r" | 1445 | check_no_diagnostic( |
1446 | r" | ||
1414 | enum Either { | 1447 | enum Either { |
1415 | A(bool), | 1448 | A(bool), |
1416 | B(bool, bool), | 1449 | B(bool, bool), |
@@ -1427,14 +1460,16 @@ mod tests { | |||
1427 | (Either::B(_, _), Either2::D) => (), | 1460 | (Either::B(_, _), Either2::D) => (), |
1428 | } | 1461 | } |
1429 | } | 1462 | } |
1430 | "; | 1463 | ", |
1431 | 1464 | ); | |
1432 | check_no_diagnostic(content); | ||
1433 | } | 1465 | } |
1434 | 1466 | ||
1435 | #[test] | 1467 | #[test] |
1436 | fn mismatched_types() { | 1468 | fn mismatched_types() { |
1437 | let content = r" | 1469 | // Match statements with arms that don't match the |
1470 | // expression pattern do not fire this diagnostic. | ||
1471 | check_no_diagnostic( | ||
1472 | r" | ||
1438 | enum Either { | 1473 | enum Either { |
1439 | A, | 1474 | A, |
1440 | B, | 1475 | B, |
@@ -1449,47 +1484,47 @@ mod tests { | |||
1449 | Either2::D => (), | 1484 | Either2::D => (), |
1450 | } | 1485 | } |
1451 | } | 1486 | } |
1452 | "; | 1487 | ", |
1453 | 1488 | ); | |
1454 | // Match statements with arms that don't match the | ||
1455 | // expression pattern do not fire this diagnostic. | ||
1456 | check_no_diagnostic(content); | ||
1457 | } | 1489 | } |
1458 | 1490 | ||
1459 | #[test] | 1491 | #[test] |
1460 | fn mismatched_types_with_different_arity() { | 1492 | fn mismatched_types_with_different_arity() { |
1461 | let content = r" | 1493 | // Match statements with arms that don't match the |
1494 | // expression pattern do not fire this diagnostic. | ||
1495 | check_no_diagnostic( | ||
1496 | r" | ||
1462 | fn test_fn() { | 1497 | fn test_fn() { |
1463 | match (true, false) { | 1498 | match (true, false) { |
1464 | (true, false, true) => (), | 1499 | (true, false, true) => (), |
1465 | (true) => (), | 1500 | (true) => (), |
1466 | } | 1501 | } |
1467 | } | 1502 | } |
1468 | "; | 1503 | ", |
1469 | 1504 | ); | |
1470 | // Match statements with arms that don't match the | ||
1471 | // expression pattern do not fire this diagnostic. | ||
1472 | check_no_diagnostic(content); | ||
1473 | } | 1505 | } |
1474 | 1506 | ||
1475 | #[test] | 1507 | #[test] |
1476 | fn malformed_match_arm_tuple_missing_pattern() { | 1508 | fn malformed_match_arm_tuple_missing_pattern() { |
1477 | let content = r" | 1509 | // Match statements with arms that don't match the |
1510 | // expression pattern do not fire this diagnostic. | ||
1511 | check_no_diagnostic( | ||
1512 | r" | ||
1478 | fn test_fn() { | 1513 | fn test_fn() { |
1479 | match (0) { | 1514 | match (0) { |
1480 | () => (), | 1515 | () => (), |
1481 | } | 1516 | } |
1482 | } | 1517 | } |
1483 | "; | 1518 | ", |
1484 | 1519 | ); | |
1485 | // Match statements with arms that don't match the | ||
1486 | // expression pattern do not fire this diagnostic. | ||
1487 | check_no_diagnostic(content); | ||
1488 | } | 1520 | } |
1489 | 1521 | ||
1490 | #[test] | 1522 | #[test] |
1491 | fn malformed_match_arm_tuple_enum_missing_pattern() { | 1523 | fn malformed_match_arm_tuple_enum_missing_pattern() { |
1492 | let content = r" | 1524 | // We are testing to be sure we don't panic here when the match |
1525 | // arm `Either::B` is missing its pattern. | ||
1526 | check_no_diagnostic( | ||
1527 | r" | ||
1493 | enum Either { | 1528 | enum Either { |
1494 | A, | 1529 | A, |
1495 | B(u32), | 1530 | B(u32), |
@@ -1500,32 +1535,30 @@ mod tests { | |||
1500 | Either::B() => (), | 1535 | Either::B() => (), |
1501 | } | 1536 | } |
1502 | } | 1537 | } |
1503 | "; | 1538 | ", |
1504 | 1539 | ); | |
1505 | // We are testing to be sure we don't panic here when the match | ||
1506 | // arm `Either::B` is missing its pattern. | ||
1507 | check_no_diagnostic(content); | ||
1508 | } | 1540 | } |
1509 | 1541 | ||
1510 | #[test] | 1542 | #[test] |
1511 | fn enum_not_in_scope() { | 1543 | fn enum_not_in_scope() { |
1512 | let content = r" | 1544 | // The enum is not in scope so we don't perform exhaustiveness |
1545 | // checking, but we want to be sure we don't panic here (and | ||
1546 | // we don't create a diagnostic). | ||
1547 | check_no_diagnostic( | ||
1548 | r" | ||
1513 | fn test_fn() { | 1549 | fn test_fn() { |
1514 | match Foo::Bar { | 1550 | match Foo::Bar { |
1515 | Foo::Baz => (), | 1551 | Foo::Baz => (), |
1516 | } | 1552 | } |
1517 | } | 1553 | } |
1518 | "; | 1554 | ", |
1519 | 1555 | ); | |
1520 | // The enum is not in scope so we don't perform exhaustiveness | ||
1521 | // checking, but we want to be sure we don't panic here (and | ||
1522 | // we don't create a diagnostic). | ||
1523 | check_no_diagnostic(content); | ||
1524 | } | 1556 | } |
1525 | 1557 | ||
1526 | #[test] | 1558 | #[test] |
1527 | fn expr_diverges() { | 1559 | fn expr_diverges() { |
1528 | let content = r" | 1560 | check_no_diagnostic( |
1561 | r" | ||
1529 | enum Either { | 1562 | enum Either { |
1530 | A, | 1563 | A, |
1531 | B, | 1564 | B, |
@@ -1536,14 +1569,14 @@ mod tests { | |||
1536 | Either::B => (), | 1569 | Either::B => (), |
1537 | } | 1570 | } |
1538 | } | 1571 | } |
1539 | "; | 1572 | ", |
1540 | 1573 | ); | |
1541 | check_no_diagnostic(content); | ||
1542 | } | 1574 | } |
1543 | 1575 | ||
1544 | #[test] | 1576 | #[test] |
1545 | fn expr_loop_with_break() { | 1577 | fn expr_loop_with_break() { |
1546 | let content = r" | 1578 | check_no_diagnostic( |
1579 | r" | ||
1547 | enum Either { | 1580 | enum Either { |
1548 | A, | 1581 | A, |
1549 | B, | 1582 | B, |
@@ -1554,14 +1587,14 @@ mod tests { | |||
1554 | Either::B => (), | 1587 | Either::B => (), |
1555 | } | 1588 | } |
1556 | } | 1589 | } |
1557 | "; | 1590 | ", |
1558 | 1591 | ); | |
1559 | check_no_diagnostic(content); | ||
1560 | } | 1592 | } |
1561 | 1593 | ||
1562 | #[test] | 1594 | #[test] |
1563 | fn expr_partially_diverges() { | 1595 | fn expr_partially_diverges() { |
1564 | let content = r" | 1596 | check_no_diagnostic( |
1597 | r" | ||
1565 | enum Either<T> { | 1598 | enum Either<T> { |
1566 | A(T), | 1599 | A(T), |
1567 | B, | 1600 | B, |
@@ -1575,14 +1608,14 @@ mod tests { | |||
1575 | Either::B => 0, | 1608 | Either::B => 0, |
1576 | } | 1609 | } |
1577 | } | 1610 | } |
1578 | "; | 1611 | ", |
1579 | 1612 | ); | |
1580 | check_no_diagnostic(content); | ||
1581 | } | 1613 | } |
1582 | 1614 | ||
1583 | #[test] | 1615 | #[test] |
1584 | fn enum_record_no_arms() { | 1616 | fn enum_record_no_arms() { |
1585 | let content = r" | 1617 | check_diagnostic( |
1618 | r" | ||
1586 | enum Either { | 1619 | enum Either { |
1587 | A { foo: bool }, | 1620 | A { foo: bool }, |
1588 | B, | 1621 | B, |
@@ -1592,14 +1625,14 @@ mod tests { | |||
1592 | match a { | 1625 | match a { |
1593 | } | 1626 | } |
1594 | } | 1627 | } |
1595 | "; | 1628 | ", |
1596 | 1629 | ); | |
1597 | check_diagnostic(content); | ||
1598 | } | 1630 | } |
1599 | 1631 | ||
1600 | #[test] | 1632 | #[test] |
1601 | fn enum_record_missing_arms() { | 1633 | fn enum_record_missing_arms() { |
1602 | let content = r" | 1634 | check_diagnostic( |
1635 | r" | ||
1603 | enum Either { | 1636 | enum Either { |
1604 | A { foo: bool }, | 1637 | A { foo: bool }, |
1605 | B, | 1638 | B, |
@@ -1610,14 +1643,14 @@ mod tests { | |||
1610 | Either::A { foo: true } => (), | 1643 | Either::A { foo: true } => (), |
1611 | } | 1644 | } |
1612 | } | 1645 | } |
1613 | "; | 1646 | ", |
1614 | 1647 | ); | |
1615 | check_diagnostic(content); | ||
1616 | } | 1648 | } |
1617 | 1649 | ||
1618 | #[test] | 1650 | #[test] |
1619 | fn enum_record_no_diagnostic() { | 1651 | fn enum_record_no_diagnostic() { |
1620 | let content = r" | 1652 | check_no_diagnostic( |
1653 | r" | ||
1621 | enum Either { | 1654 | enum Either { |
1622 | A { foo: bool }, | 1655 | A { foo: bool }, |
1623 | B, | 1656 | B, |
@@ -1630,14 +1663,17 @@ mod tests { | |||
1630 | Either::B => (), | 1663 | Either::B => (), |
1631 | } | 1664 | } |
1632 | } | 1665 | } |
1633 | "; | 1666 | ", |
1634 | 1667 | ); | |
1635 | check_no_diagnostic(content); | ||
1636 | } | 1668 | } |
1637 | 1669 | ||
1638 | #[test] | 1670 | #[test] |
1639 | fn enum_record_missing_field_no_diagnostic() { | 1671 | fn enum_record_missing_field_no_diagnostic() { |
1640 | let content = r" | 1672 | // When `Either::A` is missing a struct member, we don't want |
1673 | // to fire the missing match arm diagnostic. This should fire | ||
1674 | // some other diagnostic. | ||
1675 | check_no_diagnostic( | ||
1676 | r" | ||
1641 | enum Either { | 1677 | enum Either { |
1642 | A { foo: bool }, | 1678 | A { foo: bool }, |
1643 | B, | 1679 | B, |
@@ -1649,17 +1685,16 @@ mod tests { | |||
1649 | Either::B => (), | 1685 | Either::B => (), |
1650 | } | 1686 | } |
1651 | } | 1687 | } |
1652 | "; | 1688 | ", |
1653 | 1689 | ); | |
1654 | // When `Either::A` is missing a struct member, we don't want | ||
1655 | // to fire the missing match arm diagnostic. This should fire | ||
1656 | // some other diagnostic. | ||
1657 | check_no_diagnostic(content); | ||
1658 | } | 1690 | } |
1659 | 1691 | ||
1660 | #[test] | 1692 | #[test] |
1661 | fn enum_record_missing_field_missing_match_arm() { | 1693 | fn enum_record_missing_field_missing_match_arm() { |
1662 | let content = r" | 1694 | // Even though `Either::A` is missing fields, we still want to fire |
1695 | // the missing arm diagnostic here, since we know `Either::B` is missing. | ||
1696 | check_diagnostic( | ||
1697 | r" | ||
1663 | enum Either { | 1698 | enum Either { |
1664 | A { foo: bool }, | 1699 | A { foo: bool }, |
1665 | B, | 1700 | B, |
@@ -1670,16 +1705,14 @@ mod tests { | |||
1670 | Either::A { } => (), | 1705 | Either::A { } => (), |
1671 | } | 1706 | } |
1672 | } | 1707 | } |
1673 | "; | 1708 | ", |
1674 | 1709 | ); | |
1675 | // Even though `Either::A` is missing fields, we still want to fire | ||
1676 | // the missing arm diagnostic here, since we know `Either::B` is missing. | ||
1677 | check_diagnostic(content); | ||
1678 | } | 1710 | } |
1679 | 1711 | ||
1680 | #[test] | 1712 | #[test] |
1681 | fn enum_record_no_diagnostic_wild() { | 1713 | fn enum_record_no_diagnostic_wild() { |
1682 | let content = r" | 1714 | check_no_diagnostic( |
1715 | r" | ||
1683 | enum Either { | 1716 | enum Either { |
1684 | A { foo: bool }, | 1717 | A { foo: bool }, |
1685 | B, | 1718 | B, |
@@ -1691,14 +1724,14 @@ mod tests { | |||
1691 | Either::B => (), | 1724 | Either::B => (), |
1692 | } | 1725 | } |
1693 | } | 1726 | } |
1694 | "; | 1727 | ", |
1695 | 1728 | ); | |
1696 | check_no_diagnostic(content); | ||
1697 | } | 1729 | } |
1698 | 1730 | ||
1699 | #[test] | 1731 | #[test] |
1700 | fn enum_record_fields_out_of_order_missing_arm() { | 1732 | fn enum_record_fields_out_of_order_missing_arm() { |
1701 | let content = r" | 1733 | check_diagnostic( |
1734 | r" | ||
1702 | enum Either { | 1735 | enum Either { |
1703 | A { foo: bool, bar: () }, | 1736 | A { foo: bool, bar: () }, |
1704 | B, | 1737 | B, |
@@ -1710,14 +1743,14 @@ mod tests { | |||
1710 | Either::A { foo: true, bar: () } => (), | 1743 | Either::A { foo: true, bar: () } => (), |
1711 | } | 1744 | } |
1712 | } | 1745 | } |
1713 | "; | 1746 | ", |
1714 | 1747 | ); | |
1715 | check_diagnostic(content); | ||
1716 | } | 1748 | } |
1717 | 1749 | ||
1718 | #[test] | 1750 | #[test] |
1719 | fn enum_record_fields_out_of_order_no_diagnostic() { | 1751 | fn enum_record_fields_out_of_order_no_diagnostic() { |
1720 | let content = r" | 1752 | check_no_diagnostic( |
1753 | r" | ||
1721 | enum Either { | 1754 | enum Either { |
1722 | A { foo: bool, bar: () }, | 1755 | A { foo: bool, bar: () }, |
1723 | B, | 1756 | B, |
@@ -1730,89 +1763,89 @@ mod tests { | |||
1730 | Either::B => (), | 1763 | Either::B => (), |
1731 | } | 1764 | } |
1732 | } | 1765 | } |
1733 | "; | 1766 | ", |
1734 | 1767 | ); | |
1735 | check_no_diagnostic(content); | ||
1736 | } | 1768 | } |
1737 | 1769 | ||
1738 | #[test] | 1770 | #[test] |
1739 | fn enum_record_ellipsis_missing_arm() { | 1771 | fn enum_record_ellipsis_missing_arm() { |
1740 | let content = r" | 1772 | check_diagnostic( |
1741 | enum Either { | 1773 | r" |
1742 | A { foo: bool, bar: bool }, | 1774 | enum Either { |
1743 | B, | 1775 | A { foo: bool, bar: bool }, |
1744 | } | 1776 | B, |
1745 | fn test_fn() { | 1777 | } |
1746 | match Either::B { | 1778 | fn test_fn() { |
1747 | Either::A { foo: true, .. } => (), | 1779 | match Either::B { |
1748 | Either::B => (), | 1780 | Either::A { foo: true, .. } => (), |
1749 | } | 1781 | Either::B => (), |
1750 | } | 1782 | } |
1751 | "; | 1783 | } |
1752 | 1784 | ", | |
1753 | check_diagnostic(content); | 1785 | ); |
1754 | } | 1786 | } |
1755 | 1787 | ||
1756 | #[test] | 1788 | #[test] |
1757 | fn enum_record_ellipsis_no_diagnostic() { | 1789 | fn enum_record_ellipsis_no_diagnostic() { |
1758 | let content = r" | 1790 | check_no_diagnostic( |
1759 | enum Either { | 1791 | r" |
1760 | A { foo: bool, bar: bool }, | 1792 | enum Either { |
1761 | B, | 1793 | A { foo: bool, bar: bool }, |
1762 | } | 1794 | B, |
1763 | fn test_fn() { | 1795 | } |
1764 | let a = Either::A { foo: true }; | 1796 | fn test_fn() { |
1765 | match a { | 1797 | let a = Either::A { foo: true }; |
1766 | Either::A { foo: true, .. } => (), | 1798 | match a { |
1767 | Either::A { foo: false, .. } => (), | 1799 | Either::A { foo: true, .. } => (), |
1768 | Either::B => (), | 1800 | Either::A { foo: false, .. } => (), |
1769 | } | 1801 | Either::B => (), |
1770 | } | 1802 | } |
1771 | "; | 1803 | } |
1772 | 1804 | ", | |
1773 | check_no_diagnostic(content); | 1805 | ); |
1774 | } | 1806 | } |
1775 | 1807 | ||
1776 | #[test] | 1808 | #[test] |
1777 | fn enum_record_ellipsis_all_fields_missing_arm() { | 1809 | fn enum_record_ellipsis_all_fields_missing_arm() { |
1778 | let content = r" | 1810 | check_diagnostic( |
1779 | enum Either { | 1811 | r" |
1780 | A { foo: bool, bar: bool }, | 1812 | enum Either { |
1781 | B, | 1813 | A { foo: bool, bar: bool }, |
1782 | } | 1814 | B, |
1783 | fn test_fn() { | 1815 | } |
1784 | let a = Either::B; | 1816 | fn test_fn() { |
1785 | match a { | 1817 | let a = Either::B; |
1786 | Either::A { .. } => (), | 1818 | match a { |
1787 | } | 1819 | Either::A { .. } => (), |
1788 | } | 1820 | } |
1789 | "; | 1821 | } |
1790 | 1822 | ", | |
1791 | check_diagnostic(content); | 1823 | ); |
1792 | } | 1824 | } |
1793 | 1825 | ||
1794 | #[test] | 1826 | #[test] |
1795 | fn enum_record_ellipsis_all_fields_no_diagnostic() { | 1827 | fn enum_record_ellipsis_all_fields_no_diagnostic() { |
1796 | let content = r" | 1828 | check_no_diagnostic( |
1797 | enum Either { | 1829 | r" |
1798 | A { foo: bool, bar: bool }, | 1830 | enum Either { |
1799 | B, | 1831 | A { foo: bool, bar: bool }, |
1800 | } | 1832 | B, |
1801 | fn test_fn() { | 1833 | } |
1802 | let a = Either::B; | 1834 | fn test_fn() { |
1803 | match a { | 1835 | let a = Either::B; |
1804 | Either::A { .. } => (), | 1836 | match a { |
1805 | Either::B => (), | 1837 | Either::A { .. } => (), |
1806 | } | 1838 | Either::B => (), |
1807 | } | 1839 | } |
1808 | "; | 1840 | } |
1809 | 1841 | ", | |
1810 | check_no_diagnostic(content); | 1842 | ); |
1811 | } | 1843 | } |
1812 | 1844 | ||
1813 | #[test] | 1845 | #[test] |
1814 | fn enum_tuple_partial_ellipsis_no_diagnostic() { | 1846 | fn enum_tuple_partial_ellipsis_no_diagnostic() { |
1815 | let content = r" | 1847 | check_no_diagnostic( |
1848 | r" | ||
1816 | enum Either { | 1849 | enum Either { |
1817 | A(bool, bool, bool, bool), | 1850 | A(bool, bool, bool, bool), |
1818 | B, | 1851 | B, |
@@ -1826,14 +1859,14 @@ mod tests { | |||
1826 | Either::B => {}, | 1859 | Either::B => {}, |
1827 | } | 1860 | } |
1828 | } | 1861 | } |
1829 | "; | 1862 | ", |
1830 | 1863 | ); | |
1831 | check_no_diagnostic(content); | ||
1832 | } | 1864 | } |
1833 | 1865 | ||
1834 | #[test] | 1866 | #[test] |
1835 | fn enum_tuple_partial_ellipsis_2_no_diagnostic() { | 1867 | fn enum_tuple_partial_ellipsis_2_no_diagnostic() { |
1836 | let content = r" | 1868 | check_no_diagnostic( |
1869 | r" | ||
1837 | enum Either { | 1870 | enum Either { |
1838 | A(bool, bool, bool, bool), | 1871 | A(bool, bool, bool, bool), |
1839 | B, | 1872 | B, |
@@ -1847,14 +1880,14 @@ mod tests { | |||
1847 | Either::B => {}, | 1880 | Either::B => {}, |
1848 | } | 1881 | } |
1849 | } | 1882 | } |
1850 | "; | 1883 | ", |
1851 | 1884 | ); | |
1852 | check_no_diagnostic(content); | ||
1853 | } | 1885 | } |
1854 | 1886 | ||
1855 | #[test] | 1887 | #[test] |
1856 | fn enum_tuple_partial_ellipsis_missing_arm() { | 1888 | fn enum_tuple_partial_ellipsis_missing_arm() { |
1857 | let content = r" | 1889 | check_diagnostic( |
1890 | r" | ||
1858 | enum Either { | 1891 | enum Either { |
1859 | A(bool, bool, bool, bool), | 1892 | A(bool, bool, bool, bool), |
1860 | B, | 1893 | B, |
@@ -1867,14 +1900,14 @@ mod tests { | |||
1867 | Either::B => {}, | 1900 | Either::B => {}, |
1868 | } | 1901 | } |
1869 | } | 1902 | } |
1870 | "; | 1903 | ", |
1871 | 1904 | ); | |
1872 | check_diagnostic(content); | ||
1873 | } | 1905 | } |
1874 | 1906 | ||
1875 | #[test] | 1907 | #[test] |
1876 | fn enum_tuple_partial_ellipsis_2_missing_arm() { | 1908 | fn enum_tuple_partial_ellipsis_2_missing_arm() { |
1877 | let content = r" | 1909 | check_diagnostic( |
1910 | r" | ||
1878 | enum Either { | 1911 | enum Either { |
1879 | A(bool, bool, bool, bool), | 1912 | A(bool, bool, bool, bool), |
1880 | B, | 1913 | B, |
@@ -1887,14 +1920,14 @@ mod tests { | |||
1887 | Either::B => {}, | 1920 | Either::B => {}, |
1888 | } | 1921 | } |
1889 | } | 1922 | } |
1890 | "; | 1923 | ", |
1891 | 1924 | ); | |
1892 | check_diagnostic(content); | ||
1893 | } | 1925 | } |
1894 | 1926 | ||
1895 | #[test] | 1927 | #[test] |
1896 | fn enum_tuple_ellipsis_no_diagnostic() { | 1928 | fn enum_tuple_ellipsis_no_diagnostic() { |
1897 | let content = r" | 1929 | check_no_diagnostic( |
1930 | r" | ||
1898 | enum Either { | 1931 | enum Either { |
1899 | A(bool, bool, bool, bool), | 1932 | A(bool, bool, bool, bool), |
1900 | B, | 1933 | B, |
@@ -1905,51 +1938,51 @@ mod tests { | |||
1905 | Either::B => {}, | 1938 | Either::B => {}, |
1906 | } | 1939 | } |
1907 | } | 1940 | } |
1908 | "; | 1941 | ", |
1909 | 1942 | ); | |
1910 | check_no_diagnostic(content); | ||
1911 | } | 1943 | } |
1912 | 1944 | ||
1913 | #[test] | 1945 | #[test] |
1914 | fn enum_never() { | 1946 | fn enum_never() { |
1915 | let content = r" | 1947 | check_no_diagnostic( |
1948 | r" | ||
1916 | enum Never {} | 1949 | enum Never {} |
1917 | 1950 | ||
1918 | fn test_fn(never: Never) { | 1951 | fn test_fn(never: Never) { |
1919 | match never {} | 1952 | match never {} |
1920 | } | 1953 | } |
1921 | "; | 1954 | ", |
1922 | 1955 | ); | |
1923 | check_no_diagnostic(content); | ||
1924 | } | 1956 | } |
1925 | 1957 | ||
1926 | #[test] | 1958 | #[test] |
1927 | fn type_never() { | 1959 | fn type_never() { |
1928 | let content = r" | 1960 | check_no_diagnostic( |
1961 | r" | ||
1929 | fn test_fn(never: !) { | 1962 | fn test_fn(never: !) { |
1930 | match never {} | 1963 | match never {} |
1931 | } | 1964 | } |
1932 | "; | 1965 | ", |
1933 | 1966 | ); | |
1934 | check_no_diagnostic(content); | ||
1935 | } | 1967 | } |
1936 | 1968 | ||
1937 | #[test] | 1969 | #[test] |
1938 | fn enum_never_ref() { | 1970 | fn enum_never_ref() { |
1939 | let content = r" | 1971 | check_no_diagnostic( |
1972 | r" | ||
1940 | enum Never {} | 1973 | enum Never {} |
1941 | 1974 | ||
1942 | fn test_fn(never: &Never) { | 1975 | fn test_fn(never: &Never) { |
1943 | match never {} | 1976 | match never {} |
1944 | } | 1977 | } |
1945 | "; | 1978 | ", |
1946 | 1979 | ); | |
1947 | check_no_diagnostic(content); | ||
1948 | } | 1980 | } |
1949 | 1981 | ||
1950 | #[test] | 1982 | #[test] |
1951 | fn expr_diverges_missing_arm() { | 1983 | fn expr_diverges_missing_arm() { |
1952 | let content = r" | 1984 | check_no_diagnostic( |
1985 | r" | ||
1953 | enum Either { | 1986 | enum Either { |
1954 | A, | 1987 | A, |
1955 | B, | 1988 | B, |
@@ -1959,9 +1992,27 @@ mod tests { | |||
1959 | Either::A => (), | 1992 | Either::A => (), |
1960 | } | 1993 | } |
1961 | } | 1994 | } |
1962 | "; | 1995 | ", |
1996 | ); | ||
1997 | } | ||
1963 | 1998 | ||
1964 | check_no_diagnostic(content); | 1999 | #[test] |
2000 | fn or_pattern_panic() { | ||
2001 | check_no_diagnostic( | ||
2002 | r" | ||
2003 | pub enum Category { | ||
2004 | Infinity, | ||
2005 | Zero, | ||
2006 | } | ||
2007 | |||
2008 | fn panic(a: Category, b: Category) { | ||
2009 | match (a, b) { | ||
2010 | (Category::Zero | Category::Infinity, _) => {} | ||
2011 | (_, Category::Zero | Category::Infinity) => {} | ||
2012 | } | ||
2013 | } | ||
2014 | ", | ||
2015 | ); | ||
1965 | } | 2016 | } |
1966 | } | 2017 | } |
1967 | 2018 | ||
@@ -1981,23 +2032,26 @@ mod false_negatives { | |||
1981 | 2032 | ||
1982 | #[test] | 2033 | #[test] |
1983 | fn integers() { | 2034 | fn integers() { |
1984 | let content = r" | 2035 | // This is a false negative. |
2036 | // We don't currently check integer exhaustiveness. | ||
2037 | check_no_diagnostic( | ||
2038 | r" | ||
1985 | fn test_fn() { | 2039 | fn test_fn() { |
1986 | match 5 { | 2040 | match 5 { |
1987 | 10 => (), | 2041 | 10 => (), |
1988 | 11..20 => (), | 2042 | 11..20 => (), |
1989 | } | 2043 | } |
1990 | } | 2044 | } |
1991 | "; | 2045 | ", |
1992 | 2046 | ); | |
1993 | // This is a false negative. | ||
1994 | // We don't currently check integer exhaustiveness. | ||
1995 | check_no_diagnostic(content); | ||
1996 | } | 2047 | } |
1997 | 2048 | ||
1998 | #[test] | 2049 | #[test] |
1999 | fn internal_or() { | 2050 | fn internal_or() { |
2000 | let content = r" | 2051 | // This is a false negative. |
2052 | // We do not currently handle patterns with internal `or`s. | ||
2053 | check_no_diagnostic( | ||
2054 | r" | ||
2001 | fn test_fn() { | 2055 | fn test_fn() { |
2002 | enum Either { | 2056 | enum Either { |
2003 | A(bool), | 2057 | A(bool), |
@@ -2007,16 +2061,18 @@ mod false_negatives { | |||
2007 | Either::A(true | false) => (), | 2061 | Either::A(true | false) => (), |
2008 | } | 2062 | } |
2009 | } | 2063 | } |
2010 | "; | 2064 | ", |
2011 | 2065 | ); | |
2012 | // This is a false negative. | ||
2013 | // We do not currently handle patterns with internal `or`s. | ||
2014 | check_no_diagnostic(content); | ||
2015 | } | 2066 | } |
2016 | 2067 | ||
2017 | #[test] | 2068 | #[test] |
2018 | fn expr_loop_missing_arm() { | 2069 | fn expr_loop_missing_arm() { |
2019 | let content = r" | 2070 | // This is a false negative. |
2071 | // We currently infer the type of `loop { break Foo::A }` to `!`, which | ||
2072 | // causes us to skip the diagnostic since `Either::A` doesn't type check | ||
2073 | // with `!`. | ||
2074 | check_diagnostic( | ||
2075 | r" | ||
2020 | enum Either { | 2076 | enum Either { |
2021 | A, | 2077 | A, |
2022 | B, | 2078 | B, |
@@ -2026,48 +2082,46 @@ mod false_negatives { | |||
2026 | Either::A => (), | 2082 | Either::A => (), |
2027 | } | 2083 | } |
2028 | } | 2084 | } |
2029 | "; | 2085 | ", |
2030 | 2086 | ); | |
2031 | // This is a false negative. | ||
2032 | // We currently infer the type of `loop { break Foo::A }` to `!`, which | ||
2033 | // causes us to skip the diagnostic since `Either::A` doesn't type check | ||
2034 | // with `!`. | ||
2035 | check_diagnostic(content); | ||
2036 | } | 2087 | } |
2037 | 2088 | ||
2038 | #[test] | 2089 | #[test] |
2039 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | 2090 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { |
2040 | let content = r" | 2091 | // This is a false negative. |
2092 | // We don't currently handle tuple patterns with ellipsis. | ||
2093 | check_no_diagnostic( | ||
2094 | r" | ||
2041 | fn test_fn() { | 2095 | fn test_fn() { |
2042 | match (false, true, false) { | 2096 | match (false, true, false) { |
2043 | (false, ..) => {}, | 2097 | (false, ..) => {}, |
2044 | } | 2098 | } |
2045 | } | 2099 | } |
2046 | "; | 2100 | ", |
2047 | 2101 | ); | |
2048 | // This is a false negative. | ||
2049 | // We don't currently handle tuple patterns with ellipsis. | ||
2050 | check_no_diagnostic(content); | ||
2051 | } | 2102 | } |
2052 | 2103 | ||
2053 | #[test] | 2104 | #[test] |
2054 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | 2105 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { |
2055 | let content = r" | 2106 | // This is a false negative. |
2107 | // We don't currently handle tuple patterns with ellipsis. | ||
2108 | check_no_diagnostic( | ||
2109 | r" | ||
2056 | fn test_fn() { | 2110 | fn test_fn() { |
2057 | match (false, true, false) { | 2111 | match (false, true, false) { |
2058 | (.., false) => {}, | 2112 | (.., false) => {}, |
2059 | } | 2113 | } |
2060 | } | 2114 | } |
2061 | "; | 2115 | ", |
2062 | 2116 | ); | |
2063 | // This is a false negative. | ||
2064 | // We don't currently handle tuple patterns with ellipsis. | ||
2065 | check_no_diagnostic(content); | ||
2066 | } | 2117 | } |
2067 | 2118 | ||
2068 | #[test] | 2119 | #[test] |
2069 | fn struct_missing_arm() { | 2120 | fn struct_missing_arm() { |
2070 | let content = r" | 2121 | // This is a false negative. |
2122 | // We don't currently handle structs. | ||
2123 | check_no_diagnostic( | ||
2124 | r" | ||
2071 | struct Foo { | 2125 | struct Foo { |
2072 | a: bool, | 2126 | a: bool, |
2073 | } | 2127 | } |
@@ -2076,10 +2130,7 @@ mod false_negatives { | |||
2076 | Foo { a: true } => {}, | 2130 | Foo { a: true } => {}, |
2077 | } | 2131 | } |
2078 | } | 2132 | } |
2079 | "; | 2133 | ", |
2080 | 2134 | ); | |
2081 | // This is a false negative. | ||
2082 | // We don't currently handle structs. | ||
2083 | check_no_diagnostic(content); | ||
2084 | } | 2135 | } |
2085 | } | 2136 | } |
diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index f04968e14..7db928dde 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs | |||
@@ -226,17 +226,19 @@ impl<'a, 'b> ExprValidator<'a, 'b> { | |||
226 | None => return, | 226 | None => return, |
227 | }; | 227 | }; |
228 | 228 | ||
229 | let std_result_path = path![std::result::Result]; | 229 | let core_result_path = path![core::result::Result]; |
230 | 230 | ||
231 | let resolver = self.func.resolver(db.upcast()); | 231 | let resolver = self.func.resolver(db.upcast()); |
232 | let std_result_enum = match resolver.resolve_known_enum(db.upcast(), &std_result_path) { | 232 | let core_result_enum = match resolver.resolve_known_enum(db.upcast(), &core_result_path) { |
233 | Some(it) => it, | 233 | Some(it) => it, |
234 | _ => return, | 234 | _ => return, |
235 | }; | 235 | }; |
236 | 236 | ||
237 | let std_result_ctor = TypeCtor::Adt(AdtId::EnumId(std_result_enum)); | 237 | let core_result_ctor = TypeCtor::Adt(AdtId::EnumId(core_result_enum)); |
238 | let params = match &mismatch.expected { | 238 | let params = match &mismatch.expected { |
239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &std_result_ctor => parameters, | 239 | Ty::Apply(ApplicationTy { ctor, parameters }) if ctor == &core_result_ctor => { |
240 | parameters | ||
241 | } | ||
240 | _ => return, | 242 | _ => return, |
241 | }; | 243 | }; |
242 | 244 | ||
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index f965eb2b5..3719f76a6 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -555,13 +555,13 @@ impl<'a> InferenceContext<'a> { | |||
555 | } | 555 | } |
556 | 556 | ||
557 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { | 557 | fn resolve_into_iter_item(&self) -> Option<TypeAliasId> { |
558 | let path = path![std::iter::IntoIterator]; | 558 | let path = path![core::iter::IntoIterator]; |
559 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 559 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
560 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) | 560 | self.db.trait_data(trait_).associated_type_by_name(&name![Item]) |
561 | } | 561 | } |
562 | 562 | ||
563 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { | 563 | fn resolve_ops_try_ok(&self) -> Option<TypeAliasId> { |
564 | let path = path![std::ops::Try]; | 564 | let path = path![core::ops::Try]; |
565 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; | 565 | let trait_ = self.resolver.resolve_known_trait(self.db.upcast(), &path)?; |
566 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) | 566 | self.db.trait_data(trait_).associated_type_by_name(&name![Ok]) |
567 | } | 567 | } |
@@ -587,37 +587,37 @@ impl<'a> InferenceContext<'a> { | |||
587 | } | 587 | } |
588 | 588 | ||
589 | fn resolve_range_full(&self) -> Option<AdtId> { | 589 | fn resolve_range_full(&self) -> Option<AdtId> { |
590 | let path = path![std::ops::RangeFull]; | 590 | let path = path![core::ops::RangeFull]; |
591 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 591 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
592 | Some(struct_.into()) | 592 | Some(struct_.into()) |
593 | } | 593 | } |
594 | 594 | ||
595 | fn resolve_range(&self) -> Option<AdtId> { | 595 | fn resolve_range(&self) -> Option<AdtId> { |
596 | let path = path![std::ops::Range]; | 596 | let path = path![core::ops::Range]; |
597 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 597 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
598 | Some(struct_.into()) | 598 | Some(struct_.into()) |
599 | } | 599 | } |
600 | 600 | ||
601 | fn resolve_range_inclusive(&self) -> Option<AdtId> { | 601 | fn resolve_range_inclusive(&self) -> Option<AdtId> { |
602 | let path = path![std::ops::RangeInclusive]; | 602 | let path = path![core::ops::RangeInclusive]; |
603 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 603 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
604 | Some(struct_.into()) | 604 | Some(struct_.into()) |
605 | } | 605 | } |
606 | 606 | ||
607 | fn resolve_range_from(&self) -> Option<AdtId> { | 607 | fn resolve_range_from(&self) -> Option<AdtId> { |
608 | let path = path![std::ops::RangeFrom]; | 608 | let path = path![core::ops::RangeFrom]; |
609 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 609 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
610 | Some(struct_.into()) | 610 | Some(struct_.into()) |
611 | } | 611 | } |
612 | 612 | ||
613 | fn resolve_range_to(&self) -> Option<AdtId> { | 613 | fn resolve_range_to(&self) -> Option<AdtId> { |
614 | let path = path![std::ops::RangeTo]; | 614 | let path = path![core::ops::RangeTo]; |
615 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 615 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
616 | Some(struct_.into()) | 616 | Some(struct_.into()) |
617 | } | 617 | } |
618 | 618 | ||
619 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { | 619 | fn resolve_range_to_inclusive(&self) -> Option<AdtId> { |
620 | let path = path![std::ops::RangeToInclusive]; | 620 | let path = path![core::ops::RangeToInclusive]; |
621 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; | 621 | let struct_ = self.resolver.resolve_known_struct(self.db.upcast(), &path)?; |
622 | Some(struct_.into()) | 622 | Some(struct_.into()) |
623 | } | 623 | } |
diff --git a/crates/ra_hir_ty/src/test_db.rs b/crates/ra_hir_ty/src/test_db.rs index e484968a0..ad04e3e0f 100644 --- a/crates/ra_hir_ty/src/test_db.rs +++ b/crates/ra_hir_ty/src/test_db.rs | |||
@@ -8,6 +8,7 @@ use std::{ | |||
8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; | 8 | use hir_def::{db::DefDatabase, AssocItemId, ModuleDefId, ModuleId}; |
9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; | 9 | use hir_expand::{db::AstDatabase, diagnostics::DiagnosticSink}; |
10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; | 10 | use ra_db::{salsa, CrateId, FileId, FileLoader, FileLoaderDelegate, SourceDatabase, Upcast}; |
11 | use rustc_hash::FxHashSet; | ||
11 | use stdx::format_to; | 12 | use stdx::format_to; |
12 | 13 | ||
13 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; | 14 | use crate::{db::HirDatabase, diagnostics::Diagnostic, expr::ExprValidator}; |
@@ -73,7 +74,7 @@ impl FileLoader for TestDB { | |||
73 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { | 74 | fn resolve_path(&self, anchor: FileId, path: &str) -> Option<FileId> { |
74 | FileLoaderDelegate(self).resolve_path(anchor, path) | 75 | FileLoaderDelegate(self).resolve_path(anchor, path) |
75 | } | 76 | } |
76 | fn relevant_crates(&self, file_id: FileId) -> Arc<Vec<CrateId>> { | 77 | fn relevant_crates(&self, file_id: FileId) -> Arc<FxHashSet<CrateId>> { |
77 | FileLoaderDelegate(self).relevant_crates(file_id) | 78 | FileLoaderDelegate(self).relevant_crates(file_id) |
78 | } | 79 | } |
79 | } | 80 | } |
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index 8a5031756..37659cd02 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -95,7 +95,7 @@ fn foo() { | |||
95 | fn infer_ranges() { | 95 | fn infer_ranges() { |
96 | let (db, pos) = TestDB::with_position( | 96 | let (db, pos) = TestDB::with_position( |
97 | r#" | 97 | r#" |
98 | //- /main.rs crate:main deps:std | 98 | //- /main.rs crate:main deps:core |
99 | fn test() { | 99 | fn test() { |
100 | let a = ..; | 100 | let a = ..; |
101 | let b = 1..; | 101 | let b = 1..; |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | t<|>; | 108 | t<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | #[prelude_import] use prelude::*; | 112 | #[prelude_import] use prelude::*; |
113 | mod prelude {} | 113 | mod prelude {} |
114 | 114 | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 133fb5f39..e81193a3c 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -10,7 +10,7 @@ use super::{infer, infer_with_mismatches, type_at, type_at_pos}; | |||
10 | fn infer_await() { | 10 | fn infer_await() { |
11 | let (db, pos) = TestDB::with_position( | 11 | let (db, pos) = TestDB::with_position( |
12 | r#" | 12 | r#" |
13 | //- /main.rs crate:main deps:std | 13 | //- /main.rs crate:main deps:core |
14 | 14 | ||
15 | struct IntFuture; | 15 | struct IntFuture; |
16 | 16 | ||
@@ -24,7 +24,7 @@ fn test() { | |||
24 | v<|>; | 24 | v<|>; |
25 | } | 25 | } |
26 | 26 | ||
27 | //- /std.rs crate:std | 27 | //- /core.rs crate:core |
28 | #[prelude_import] use future::*; | 28 | #[prelude_import] use future::*; |
29 | mod future { | 29 | mod future { |
30 | #[lang = "future_trait"] | 30 | #[lang = "future_trait"] |
@@ -42,7 +42,7 @@ mod future { | |||
42 | fn infer_async() { | 42 | fn infer_async() { |
43 | let (db, pos) = TestDB::with_position( | 43 | let (db, pos) = TestDB::with_position( |
44 | r#" | 44 | r#" |
45 | //- /main.rs crate:main deps:std | 45 | //- /main.rs crate:main deps:core |
46 | 46 | ||
47 | async fn foo() -> u64 { | 47 | async fn foo() -> u64 { |
48 | 128 | 48 | 128 |
@@ -54,7 +54,7 @@ fn test() { | |||
54 | v<|>; | 54 | v<|>; |
55 | } | 55 | } |
56 | 56 | ||
57 | //- /std.rs crate:std | 57 | //- /core.rs crate:core |
58 | #[prelude_import] use future::*; | 58 | #[prelude_import] use future::*; |
59 | mod future { | 59 | mod future { |
60 | #[lang = "future_trait"] | 60 | #[lang = "future_trait"] |
@@ -72,7 +72,7 @@ mod future { | |||
72 | fn infer_desugar_async() { | 72 | fn infer_desugar_async() { |
73 | let (db, pos) = TestDB::with_position( | 73 | let (db, pos) = TestDB::with_position( |
74 | r#" | 74 | r#" |
75 | //- /main.rs crate:main deps:std | 75 | //- /main.rs crate:main deps:core |
76 | 76 | ||
77 | async fn foo() -> u64 { | 77 | async fn foo() -> u64 { |
78 | 128 | 78 | 128 |
@@ -83,7 +83,7 @@ fn test() { | |||
83 | r<|>; | 83 | r<|>; |
84 | } | 84 | } |
85 | 85 | ||
86 | //- /std.rs crate:std | 86 | //- /core.rs crate:core |
87 | #[prelude_import] use future::*; | 87 | #[prelude_import] use future::*; |
88 | mod future { | 88 | mod future { |
89 | trait Future { | 89 | trait Future { |
@@ -100,7 +100,7 @@ mod future { | |||
100 | fn infer_try() { | 100 | fn infer_try() { |
101 | let (db, pos) = TestDB::with_position( | 101 | let (db, pos) = TestDB::with_position( |
102 | r#" | 102 | r#" |
103 | //- /main.rs crate:main deps:std | 103 | //- /main.rs crate:main deps:core |
104 | 104 | ||
105 | fn test() { | 105 | fn test() { |
106 | let r: Result<i32, u64> = Result::Ok(1); | 106 | let r: Result<i32, u64> = Result::Ok(1); |
@@ -108,7 +108,7 @@ fn test() { | |||
108 | v<|>; | 108 | v<|>; |
109 | } | 109 | } |
110 | 110 | ||
111 | //- /std.rs crate:std | 111 | //- /core.rs crate:core |
112 | 112 | ||
113 | #[prelude_import] use ops::*; | 113 | #[prelude_import] use ops::*; |
114 | mod ops { | 114 | mod ops { |