diff options
Diffstat (limited to 'crates')
118 files changed, 3844 insertions, 1320 deletions
diff --git a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs index 6a675e812..776bddf91 100644 --- a/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs +++ b/crates/ra_assists/src/handlers/add_from_impl_for_enum.rs | |||
@@ -4,9 +4,9 @@ use test_utils::mark; | |||
4 | 4 | ||
5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; | 5 | use crate::{utils::FamousDefs, AssistContext, AssistId, Assists}; |
6 | 6 | ||
7 | // Assist add_from_impl_for_enum | 7 | // Assist: add_from_impl_for_enum |
8 | // | 8 | // |
9 | // Adds a From impl for an enum variant with one tuple field | 9 | // Adds a From impl for an enum variant with one tuple field. |
10 | // | 10 | // |
11 | // ``` | 11 | // ``` |
12 | // enum A { <|>One(u32) } | 12 | // enum A { <|>One(u32) } |
diff --git a/crates/ra_assists/src/handlers/introduce_named_lifetime.rs b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs new file mode 100644 index 000000000..beb5b7366 --- /dev/null +++ b/crates/ra_assists/src/handlers/introduce_named_lifetime.rs | |||
@@ -0,0 +1,303 @@ | |||
1 | use ra_syntax::{ | ||
2 | ast::{self, NameOwner, TypeAscriptionOwner, TypeParamsOwner}, | ||
3 | AstNode, SyntaxKind, TextRange, TextSize, | ||
4 | }; | ||
5 | use rustc_hash::FxHashSet; | ||
6 | |||
7 | use crate::{assist_context::AssistBuilder, AssistContext, AssistId, Assists}; | ||
8 | |||
9 | static ASSIST_NAME: &str = "introduce_named_lifetime"; | ||
10 | static ASSIST_LABEL: &str = "Introduce named lifetime"; | ||
11 | |||
12 | // Assist: introduce_named_lifetime | ||
13 | // | ||
14 | // Change an anonymous lifetime to a named lifetime. | ||
15 | // | ||
16 | // ``` | ||
17 | // impl Cursor<'_<|>> { | ||
18 | // fn node(self) -> &SyntaxNode { | ||
19 | // match self { | ||
20 | // Cursor::Replace(node) | Cursor::Before(node) => node, | ||
21 | // } | ||
22 | // } | ||
23 | // } | ||
24 | // ``` | ||
25 | // -> | ||
26 | // ``` | ||
27 | // impl<'a> Cursor<'a> { | ||
28 | // fn node(self) -> &SyntaxNode { | ||
29 | // match self { | ||
30 | // Cursor::Replace(node) | Cursor::Before(node) => node, | ||
31 | // } | ||
32 | // } | ||
33 | // } | ||
34 | // ``` | ||
35 | // FIXME: How can we handle renaming any one of multiple anonymous lifetimes? | ||
36 | // FIXME: should also add support for the case fun(f: &Foo) -> &<|>Foo | ||
37 | pub(crate) fn introduce_named_lifetime(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | ||
38 | let lifetime_token = ctx | ||
39 | .find_token_at_offset(SyntaxKind::LIFETIME) | ||
40 | .filter(|lifetime| lifetime.text() == "'_")?; | ||
41 | if let Some(fn_def) = lifetime_token.ancestors().find_map(ast::FnDef::cast) { | ||
42 | generate_fn_def_assist(acc, &fn_def, lifetime_token.text_range()) | ||
43 | } else if let Some(impl_def) = lifetime_token.ancestors().find_map(ast::ImplDef::cast) { | ||
44 | // only allow naming the last anonymous lifetime | ||
45 | lifetime_token.next_token().filter(|tok| tok.kind() == SyntaxKind::R_ANGLE)?; | ||
46 | generate_impl_def_assist(acc, &impl_def, lifetime_token.text_range()) | ||
47 | } else { | ||
48 | None | ||
49 | } | ||
50 | } | ||
51 | |||
52 | /// Generate the assist for the fn def case | ||
53 | fn generate_fn_def_assist( | ||
54 | acc: &mut Assists, | ||
55 | fn_def: &ast::FnDef, | ||
56 | lifetime_loc: TextRange, | ||
57 | ) -> Option<()> { | ||
58 | let param_list: ast::ParamList = fn_def.param_list()?; | ||
59 | let new_lifetime_param = generate_unique_lifetime_param_name(&fn_def.type_param_list())?; | ||
60 | let end_of_fn_ident = fn_def.name()?.ident_token()?.text_range().end(); | ||
61 | let self_param = | ||
62 | // use the self if it's a reference and has no explicit lifetime | ||
63 | param_list.self_param().filter(|p| p.lifetime_token().is_none() && p.amp_token().is_some()); | ||
64 | // compute the location which implicitly has the same lifetime as the anonymous lifetime | ||
65 | let loc_needing_lifetime = if let Some(self_param) = self_param { | ||
66 | // if we have a self reference, use that | ||
67 | Some(self_param.self_token()?.text_range().start()) | ||
68 | } else { | ||
69 | // otherwise, if there's a single reference parameter without a named liftime, use that | ||
70 | let fn_params_without_lifetime: Vec<_> = param_list | ||
71 | .params() | ||
72 | .filter_map(|param| match param.ascribed_type() { | ||
73 | Some(ast::TypeRef::ReferenceType(ascribed_type)) | ||
74 | if ascribed_type.lifetime_token() == None => | ||
75 | { | ||
76 | Some(ascribed_type.amp_token()?.text_range().end()) | ||
77 | } | ||
78 | _ => None, | ||
79 | }) | ||
80 | .collect(); | ||
81 | match fn_params_without_lifetime.len() { | ||
82 | 1 => Some(fn_params_without_lifetime.into_iter().nth(0)?), | ||
83 | 0 => None, | ||
84 | // multiple unnnamed is invalid. assist is not applicable | ||
85 | _ => return None, | ||
86 | } | ||
87 | }; | ||
88 | acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { | ||
89 | add_lifetime_param(fn_def, builder, end_of_fn_ident, new_lifetime_param); | ||
90 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | ||
91 | loc_needing_lifetime.map(|loc| builder.insert(loc, format!("'{} ", new_lifetime_param))); | ||
92 | }) | ||
93 | } | ||
94 | |||
95 | /// Generate the assist for the impl def case | ||
96 | fn generate_impl_def_assist( | ||
97 | acc: &mut Assists, | ||
98 | impl_def: &ast::ImplDef, | ||
99 | lifetime_loc: TextRange, | ||
100 | ) -> Option<()> { | ||
101 | let new_lifetime_param = generate_unique_lifetime_param_name(&impl_def.type_param_list())?; | ||
102 | let end_of_impl_kw = impl_def.impl_token()?.text_range().end(); | ||
103 | acc.add(AssistId(ASSIST_NAME), ASSIST_LABEL, lifetime_loc, |builder| { | ||
104 | add_lifetime_param(impl_def, builder, end_of_impl_kw, new_lifetime_param); | ||
105 | builder.replace(lifetime_loc, format!("'{}", new_lifetime_param)); | ||
106 | }) | ||
107 | } | ||
108 | |||
109 | /// Given a type parameter list, generate a unique lifetime parameter name | ||
110 | /// which is not in the list | ||
111 | fn generate_unique_lifetime_param_name( | ||
112 | existing_type_param_list: &Option<ast::TypeParamList>, | ||
113 | ) -> Option<char> { | ||
114 | match existing_type_param_list { | ||
115 | Some(type_params) => { | ||
116 | let used_lifetime_params: FxHashSet<_> = type_params | ||
117 | .lifetime_params() | ||
118 | .map(|p| p.syntax().text().to_string()[1..].to_owned()) | ||
119 | .collect(); | ||
120 | (b'a'..=b'z').map(char::from).find(|c| !used_lifetime_params.contains(&c.to_string())) | ||
121 | } | ||
122 | None => Some('a'), | ||
123 | } | ||
124 | } | ||
125 | |||
126 | /// Add the lifetime param to `builder`. If there are type parameters in `type_params_owner`, add it to the end. Otherwise | ||
127 | /// add new type params brackets with the lifetime parameter at `new_type_params_loc`. | ||
128 | fn add_lifetime_param<TypeParamsOwner: ast::TypeParamsOwner>( | ||
129 | type_params_owner: &TypeParamsOwner, | ||
130 | builder: &mut AssistBuilder, | ||
131 | new_type_params_loc: TextSize, | ||
132 | new_lifetime_param: char, | ||
133 | ) { | ||
134 | match type_params_owner.type_param_list() { | ||
135 | // add the new lifetime parameter to an existing type param list | ||
136 | Some(type_params) => { | ||
137 | builder.insert( | ||
138 | (u32::from(type_params.syntax().text_range().end()) - 1).into(), | ||
139 | format!(", '{}", new_lifetime_param), | ||
140 | ); | ||
141 | } | ||
142 | // create a new type param list containing only the new lifetime parameter | ||
143 | None => { | ||
144 | builder.insert(new_type_params_loc, format!("<'{}>", new_lifetime_param)); | ||
145 | } | ||
146 | } | ||
147 | } | ||
148 | |||
149 | #[cfg(test)] | ||
150 | mod tests { | ||
151 | use super::*; | ||
152 | use crate::tests::{check_assist, check_assist_not_applicable}; | ||
153 | |||
154 | #[test] | ||
155 | fn test_example_case() { | ||
156 | check_assist( | ||
157 | introduce_named_lifetime, | ||
158 | r#"impl Cursor<'_<|>> { | ||
159 | fn node(self) -> &SyntaxNode { | ||
160 | match self { | ||
161 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
162 | } | ||
163 | } | ||
164 | }"#, | ||
165 | r#"impl<'a> Cursor<'a> { | ||
166 | fn node(self) -> &SyntaxNode { | ||
167 | match self { | ||
168 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
169 | } | ||
170 | } | ||
171 | }"#, | ||
172 | ); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
176 | fn test_example_case_simplified() { | ||
177 | check_assist( | ||
178 | introduce_named_lifetime, | ||
179 | r#"impl Cursor<'_<|>> {"#, | ||
180 | r#"impl<'a> Cursor<'a> {"#, | ||
181 | ); | ||
182 | } | ||
183 | |||
184 | #[test] | ||
185 | fn test_example_case_cursor_after_tick() { | ||
186 | check_assist( | ||
187 | introduce_named_lifetime, | ||
188 | r#"impl Cursor<'<|>_> {"#, | ||
189 | r#"impl<'a> Cursor<'a> {"#, | ||
190 | ); | ||
191 | } | ||
192 | |||
193 | #[test] | ||
194 | fn test_example_case_cursor_before_tick() { | ||
195 | check_assist( | ||
196 | introduce_named_lifetime, | ||
197 | r#"impl Cursor<<|>'_> {"#, | ||
198 | r#"impl<'a> Cursor<'a> {"#, | ||
199 | ); | ||
200 | } | ||
201 | |||
202 | #[test] | ||
203 | fn test_not_applicable_cursor_position() { | ||
204 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'_><|> {"#); | ||
205 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<|><'_> {"#); | ||
206 | } | ||
207 | |||
208 | #[test] | ||
209 | fn test_not_applicable_lifetime_already_name() { | ||
210 | check_assist_not_applicable(introduce_named_lifetime, r#"impl Cursor<'a<|>> {"#); | ||
211 | check_assist_not_applicable(introduce_named_lifetime, r#"fn my_fun<'a>() -> X<'a<|>>"#); | ||
212 | } | ||
213 | |||
214 | #[test] | ||
215 | fn test_with_type_parameter() { | ||
216 | check_assist( | ||
217 | introduce_named_lifetime, | ||
218 | r#"impl<T> Cursor<T, '_<|>>"#, | ||
219 | r#"impl<T, 'a> Cursor<T, 'a>"#, | ||
220 | ); | ||
221 | } | ||
222 | |||
223 | #[test] | ||
224 | fn test_with_existing_lifetime_name_conflict() { | ||
225 | check_assist( | ||
226 | introduce_named_lifetime, | ||
227 | r#"impl<'a, 'b> Cursor<'a, 'b, '_<|>>"#, | ||
228 | r#"impl<'a, 'b, 'c> Cursor<'a, 'b, 'c>"#, | ||
229 | ); | ||
230 | } | ||
231 | |||
232 | #[test] | ||
233 | fn test_function_return_value_anon_lifetime_param() { | ||
234 | check_assist( | ||
235 | introduce_named_lifetime, | ||
236 | r#"fn my_fun() -> X<'_<|>>"#, | ||
237 | r#"fn my_fun<'a>() -> X<'a>"#, | ||
238 | ); | ||
239 | } | ||
240 | |||
241 | #[test] | ||
242 | fn test_function_return_value_anon_reference_lifetime() { | ||
243 | check_assist( | ||
244 | introduce_named_lifetime, | ||
245 | r#"fn my_fun() -> &'_<|> X"#, | ||
246 | r#"fn my_fun<'a>() -> &'a X"#, | ||
247 | ); | ||
248 | } | ||
249 | |||
250 | #[test] | ||
251 | fn test_function_param_anon_lifetime() { | ||
252 | check_assist( | ||
253 | introduce_named_lifetime, | ||
254 | r#"fn my_fun(x: X<'_<|>>)"#, | ||
255 | r#"fn my_fun<'a>(x: X<'a>)"#, | ||
256 | ); | ||
257 | } | ||
258 | |||
259 | #[test] | ||
260 | fn test_function_add_lifetime_to_params() { | ||
261 | check_assist( | ||
262 | introduce_named_lifetime, | ||
263 | r#"fn my_fun(f: &Foo) -> X<'_<|>>"#, | ||
264 | r#"fn my_fun<'a>(f: &'a Foo) -> X<'a>"#, | ||
265 | ); | ||
266 | } | ||
267 | |||
268 | #[test] | ||
269 | fn test_function_add_lifetime_to_params_in_presence_of_other_lifetime() { | ||
270 | check_assist( | ||
271 | introduce_named_lifetime, | ||
272 | r#"fn my_fun<'other>(f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | ||
273 | r#"fn my_fun<'other, 'a>(f: &'a Foo, b: &'other Bar) -> X<'a>"#, | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
278 | fn test_function_not_applicable_without_self_and_multiple_unnamed_param_lifetimes() { | ||
279 | // this is not permitted under lifetime elision rules | ||
280 | check_assist_not_applicable( | ||
281 | introduce_named_lifetime, | ||
282 | r#"fn my_fun(f: &Foo, b: &Bar) -> X<'_<|>>"#, | ||
283 | ); | ||
284 | } | ||
285 | |||
286 | #[test] | ||
287 | fn test_function_add_lifetime_to_self_ref_param() { | ||
288 | check_assist( | ||
289 | introduce_named_lifetime, | ||
290 | r#"fn my_fun<'other>(&self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | ||
291 | r#"fn my_fun<'other, 'a>(&'a self, f: &Foo, b: &'other Bar) -> X<'a>"#, | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn test_function_add_lifetime_to_param_with_non_ref_self() { | ||
297 | check_assist( | ||
298 | introduce_named_lifetime, | ||
299 | r#"fn my_fun<'other>(self, f: &Foo, b: &'other Bar) -> X<'_<|>>"#, | ||
300 | r#"fn my_fun<'other, 'a>(self, f: &'a Foo, b: &'other Bar) -> X<'a>"#, | ||
301 | ); | ||
302 | } | ||
303 | } | ||
diff --git a/crates/ra_assists/src/handlers/reorder_fields.rs b/crates/ra_assists/src/handlers/reorder_fields.rs index 30229edc2..897da2832 100644 --- a/crates/ra_assists/src/handlers/reorder_fields.rs +++ b/crates/ra_assists/src/handlers/reorder_fields.rs | |||
@@ -23,7 +23,7 @@ use crate::{AssistContext, AssistId, Assists}; | |||
23 | // ``` | 23 | // ``` |
24 | // | 24 | // |
25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 25 | pub(crate) fn reorder_fields(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
26 | reorder::<ast::RecordLit>(acc, ctx.clone()).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) | 26 | reorder::<ast::RecordLit>(acc, ctx).or_else(|| reorder::<ast::RecordPat>(acc, ctx)) |
27 | } | 27 | } |
28 | 28 | ||
29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { | 29 | fn reorder<R: AstNode>(acc: &mut Assists, ctx: &AssistContext) -> Option<()> { |
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 9933f7a50..88ce9b62e 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -122,6 +122,7 @@ mod handlers { | |||
122 | mod flip_comma; | 122 | mod flip_comma; |
123 | mod flip_trait_bound; | 123 | mod flip_trait_bound; |
124 | mod inline_local_variable; | 124 | mod inline_local_variable; |
125 | mod introduce_named_lifetime; | ||
125 | mod introduce_variable; | 126 | mod introduce_variable; |
126 | mod invert_if; | 127 | mod invert_if; |
127 | mod merge_imports; | 128 | mod merge_imports; |
@@ -162,6 +163,7 @@ mod handlers { | |||
162 | flip_comma::flip_comma, | 163 | flip_comma::flip_comma, |
163 | flip_trait_bound::flip_trait_bound, | 164 | flip_trait_bound::flip_trait_bound, |
164 | inline_local_variable::inline_local_variable, | 165 | inline_local_variable::inline_local_variable, |
166 | introduce_named_lifetime::introduce_named_lifetime, | ||
165 | introduce_variable::introduce_variable, | 167 | introduce_variable::introduce_variable, |
166 | invert_if::invert_if, | 168 | invert_if::invert_if, |
167 | merge_imports::merge_imports, | 169 | merge_imports::merge_imports, |
diff --git a/crates/ra_assists/src/tests/generated.rs b/crates/ra_assists/src/tests/generated.rs index 250e56a69..d17504529 100644 --- a/crates/ra_assists/src/tests/generated.rs +++ b/crates/ra_assists/src/tests/generated.rs | |||
@@ -59,6 +59,25 @@ fn main() { | |||
59 | } | 59 | } |
60 | 60 | ||
61 | #[test] | 61 | #[test] |
62 | fn doctest_add_from_impl_for_enum() { | ||
63 | check_doc_test( | ||
64 | "add_from_impl_for_enum", | ||
65 | r#####" | ||
66 | enum A { <|>One(u32) } | ||
67 | "#####, | ||
68 | r#####" | ||
69 | enum A { One(u32) } | ||
70 | |||
71 | impl From<u32> for A { | ||
72 | fn from(v: u32) -> Self { | ||
73 | A::One(v) | ||
74 | } | ||
75 | } | ||
76 | "#####, | ||
77 | ) | ||
78 | } | ||
79 | |||
80 | #[test] | ||
62 | fn doctest_add_function() { | 81 | fn doctest_add_function() { |
63 | check_doc_test( | 82 | check_doc_test( |
64 | "add_function", | 83 | "add_function", |
@@ -433,6 +452,31 @@ fn main() { | |||
433 | } | 452 | } |
434 | 453 | ||
435 | #[test] | 454 | #[test] |
455 | fn doctest_introduce_named_lifetime() { | ||
456 | check_doc_test( | ||
457 | "introduce_named_lifetime", | ||
458 | r#####" | ||
459 | impl Cursor<'_<|>> { | ||
460 | fn node(self) -> &SyntaxNode { | ||
461 | match self { | ||
462 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
463 | } | ||
464 | } | ||
465 | } | ||
466 | "#####, | ||
467 | r#####" | ||
468 | impl<'a> Cursor<'a> { | ||
469 | fn node(self) -> &SyntaxNode { | ||
470 | match self { | ||
471 | Cursor::Replace(node) | Cursor::Before(node) => node, | ||
472 | } | ||
473 | } | ||
474 | } | ||
475 | "#####, | ||
476 | ) | ||
477 | } | ||
478 | |||
479 | #[test] | ||
436 | fn doctest_introduce_variable() { | 480 | fn doctest_introduce_variable() { |
437 | check_doc_test( | 481 | check_doc_test( |
438 | "introduce_variable", | 482 | "introduce_variable", |
diff --git a/crates/ra_cfg/src/cfg_expr.rs b/crates/ra_cfg/src/cfg_expr.rs index 39d71851c..85b100c6a 100644 --- a/crates/ra_cfg/src/cfg_expr.rs +++ b/crates/ra_cfg/src/cfg_expr.rs | |||
@@ -88,13 +88,17 @@ fn next_cfg_expr(it: &mut SliceIter<tt::TokenTree>) -> Option<CfgExpr> { | |||
88 | mod tests { | 88 | mod tests { |
89 | use super::*; | 89 | use super::*; |
90 | 90 | ||
91 | use mbe::ast_to_token_tree; | 91 | use mbe::{ast_to_token_tree, TokenMap}; |
92 | use ra_syntax::ast::{self, AstNode}; | 92 | use ra_syntax::ast::{self, AstNode}; |
93 | 93 | ||
94 | fn assert_parse_result(input: &str, expected: CfgExpr) { | 94 | fn get_token_tree_generated(input: &str) -> (tt::Subtree, TokenMap) { |
95 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); | 95 | let source_file = ast::SourceFile::parse(input).ok().unwrap(); |
96 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | 96 | let tt = source_file.syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); |
97 | let (tt, _) = ast_to_token_tree(&tt).unwrap(); | 97 | ast_to_token_tree(&tt).unwrap() |
98 | } | ||
99 | |||
100 | fn assert_parse_result(input: &str, expected: CfgExpr) { | ||
101 | let (tt, _) = get_token_tree_generated(input); | ||
98 | assert_eq!(parse_cfg(&tt), expected); | 102 | assert_eq!(parse_cfg(&tt), expected); |
99 | } | 103 | } |
100 | 104 | ||
diff --git a/crates/ra_db/src/fixture.rs b/crates/ra_db/src/fixture.rs index f8f767091..482a2f3e6 100644 --- a/crates/ra_db/src/fixture.rs +++ b/crates/ra_db/src/fixture.rs | |||
@@ -63,7 +63,7 @@ use std::sync::Arc; | |||
63 | 63 | ||
64 | use ra_cfg::CfgOptions; | 64 | use ra_cfg::CfgOptions; |
65 | use rustc_hash::FxHashMap; | 65 | use rustc_hash::FxHashMap; |
66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, CURSOR_MARKER}; | 66 | use test_utils::{extract_offset, parse_fixture, parse_single_fixture, FixtureMeta, CURSOR_MARKER}; |
67 | 67 | ||
68 | use crate::{ | 68 | use crate::{ |
69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, | 69 | input::CrateName, CrateGraph, CrateId, Edition, Env, FileId, FilePosition, RelativePathBuf, |
@@ -113,7 +113,7 @@ fn with_single_file(db: &mut dyn SourceDatabaseExt, ra_fixture: &str) -> FileId | |||
113 | let fixture = parse_single_fixture(ra_fixture); | 113 | let fixture = parse_single_fixture(ra_fixture); |
114 | 114 | ||
115 | let crate_graph = if let Some(entry) = fixture { | 115 | let crate_graph = if let Some(entry) = fixture { |
116 | let meta = match parse_meta(&entry.meta) { | 116 | let meta = match ParsedMeta::from(&entry.meta) { |
117 | ParsedMeta::File(it) => it, | 117 | ParsedMeta::File(it) => it, |
118 | _ => panic!("with_single_file only support file meta"), | 118 | _ => panic!("with_single_file only support file meta"), |
119 | }; | 119 | }; |
@@ -170,7 +170,7 @@ fn with_files(db: &mut dyn SourceDatabaseExt, fixture: &str) -> Option<FilePosit | |||
170 | let mut file_position = None; | 170 | let mut file_position = None; |
171 | 171 | ||
172 | for entry in fixture.iter() { | 172 | for entry in fixture.iter() { |
173 | let meta = match parse_meta(&entry.meta) { | 173 | let meta = match ParsedMeta::from(&entry.meta) { |
174 | ParsedMeta::Root { path } => { | 174 | ParsedMeta::Root { path } => { |
175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); | 175 | let source_root = std::mem::replace(&mut source_root, SourceRoot::new_local()); |
176 | db.set_source_root(source_root_id, Arc::new(source_root)); | 176 | db.set_source_root(source_root_id, Arc::new(source_root)); |
@@ -258,53 +258,25 @@ struct FileMeta { | |||
258 | env: Env, | 258 | env: Env, |
259 | } | 259 | } |
260 | 260 | ||
261 | //- /lib.rs crate:foo deps:bar,baz cfg:foo=a,bar=b env:OUTDIR=path/to,OTHER=foo) | 261 | impl From<&FixtureMeta> for ParsedMeta { |
262 | fn parse_meta(meta: &str) -> ParsedMeta { | 262 | fn from(meta: &FixtureMeta) -> Self { |
263 | let components = meta.split_ascii_whitespace().collect::<Vec<_>>(); | 263 | match meta { |
264 | 264 | FixtureMeta::Root { path } => { | |
265 | if components[0] == "root" { | 265 | // `Self::Root` causes a false warning: 'variant is never constructed: `Root` ' |
266 | let path: RelativePathBuf = components[1].into(); | 266 | // see https://github.com/rust-lang/rust/issues/69018 |
267 | assert!(path.starts_with("/") && path.ends_with("/")); | 267 | ParsedMeta::Root { path: path.to_owned() } |
268 | return ParsedMeta::Root { path }; | ||
269 | } | ||
270 | |||
271 | let path: RelativePathBuf = components[0].into(); | ||
272 | assert!(path.starts_with("/")); | ||
273 | |||
274 | let mut krate = None; | ||
275 | let mut deps = Vec::new(); | ||
276 | let mut edition = Edition::Edition2018; | ||
277 | let mut cfg = CfgOptions::default(); | ||
278 | let mut env = Env::default(); | ||
279 | for component in components[1..].iter() { | ||
280 | let (key, value) = split1(component, ':').unwrap(); | ||
281 | match key { | ||
282 | "crate" => krate = Some(value.to_string()), | ||
283 | "deps" => deps = value.split(',').map(|it| it.to_string()).collect(), | ||
284 | "edition" => edition = Edition::from_str(&value).unwrap(), | ||
285 | "cfg" => { | ||
286 | for key in value.split(',') { | ||
287 | match split1(key, '=') { | ||
288 | None => cfg.insert_atom(key.into()), | ||
289 | Some((k, v)) => cfg.insert_key_value(k.into(), v.into()), | ||
290 | } | ||
291 | } | ||
292 | } | ||
293 | "env" => { | ||
294 | for key in value.split(',') { | ||
295 | if let Some((k, v)) = split1(key, '=') { | ||
296 | env.set(k, v.into()); | ||
297 | } | ||
298 | } | ||
299 | } | 268 | } |
300 | _ => panic!("bad component: {:?}", component), | 269 | FixtureMeta::File(f) => Self::File(FileMeta { |
270 | path: f.path.to_owned(), | ||
271 | krate: f.crate_name.to_owned(), | ||
272 | deps: f.deps.to_owned(), | ||
273 | cfg: f.cfg.to_owned(), | ||
274 | edition: f | ||
275 | .edition | ||
276 | .as_ref() | ||
277 | .map_or(Edition::Edition2018, |v| Edition::from_str(&v).unwrap()), | ||
278 | env: Env::from(f.env.iter()), | ||
279 | }), | ||
301 | } | 280 | } |
302 | } | 281 | } |
303 | |||
304 | ParsedMeta::File(FileMeta { path, krate, deps, edition, cfg, env }) | ||
305 | } | ||
306 | |||
307 | fn split1(haystack: &str, delim: char) -> Option<(&str, &str)> { | ||
308 | let idx = haystack.find(delim)?; | ||
309 | Some((&haystack[..idx], &haystack[idx + delim.len_utf8()..])) | ||
310 | } | 282 | } |
diff --git a/crates/ra_db/src/input.rs b/crates/ra_db/src/input.rs index ab14e2d5e..4d2d3b48a 100644 --- a/crates/ra_db/src/input.rs +++ b/crates/ra_db/src/input.rs | |||
@@ -311,6 +311,21 @@ impl fmt::Display for Edition { | |||
311 | } | 311 | } |
312 | } | 312 | } |
313 | 313 | ||
314 | impl<'a, T> From<T> for Env | ||
315 | where | ||
316 | T: Iterator<Item = (&'a String, &'a String)>, | ||
317 | { | ||
318 | fn from(iter: T) -> Self { | ||
319 | let mut result = Self::default(); | ||
320 | |||
321 | for (k, v) in iter { | ||
322 | result.entries.insert(k.to_owned(), v.to_owned()); | ||
323 | } | ||
324 | |||
325 | result | ||
326 | } | ||
327 | } | ||
328 | |||
314 | impl Env { | 329 | impl Env { |
315 | pub fn set(&mut self, env: &str, value: String) { | 330 | pub fn set(&mut self, env: &str, value: String) { |
316 | self.entries.insert(env.to_owned(), value); | 331 | self.entries.insert(env.to_owned(), value); |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index 840cfdfc8..4a06f3bcd 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -532,7 +532,7 @@ impl Adt { | |||
532 | Some(self.module(db).krate()) | 532 | Some(self.module(db).krate()) |
533 | } | 533 | } |
534 | 534 | ||
535 | pub fn name(&self, db: &dyn HirDatabase) -> Name { | 535 | pub fn name(self, db: &dyn HirDatabase) -> Name { |
536 | match self { | 536 | match self { |
537 | Adt::Struct(s) => s.name(db), | 537 | Adt::Struct(s) => s.name(db), |
538 | Adt::Union(u) => u.name(db), | 538 | Adt::Union(u) => u.name(db), |
@@ -637,6 +637,10 @@ impl Function { | |||
637 | db.function_data(self.id).params.clone() | 637 | db.function_data(self.id).params.clone() |
638 | } | 638 | } |
639 | 639 | ||
640 | pub fn is_unsafe(self, db: &dyn HirDatabase) -> bool { | ||
641 | db.function_data(self.id).is_unsafe | ||
642 | } | ||
643 | |||
640 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { | 644 | pub fn diagnostics(self, db: &dyn HirDatabase, sink: &mut DiagnosticSink) { |
641 | let _p = profile("Function::diagnostics"); | 645 | let _p = profile("Function::diagnostics"); |
642 | let infer = db.infer(self.id.into()); | 646 | let infer = db.infer(self.id.into()); |
@@ -1018,15 +1022,15 @@ impl ImplDef { | |||
1018 | impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect() | 1022 | impls.lookup_impl_defs_for_trait(trait_.id).map(Self::from).collect() |
1019 | } | 1023 | } |
1020 | 1024 | ||
1021 | pub fn target_trait(&self, db: &dyn HirDatabase) -> Option<TypeRef> { | 1025 | pub fn target_trait(self, db: &dyn HirDatabase) -> Option<TypeRef> { |
1022 | db.impl_data(self.id).target_trait.clone() | 1026 | db.impl_data(self.id).target_trait.clone() |
1023 | } | 1027 | } |
1024 | 1028 | ||
1025 | pub fn target_type(&self, db: &dyn HirDatabase) -> TypeRef { | 1029 | pub fn target_type(self, db: &dyn HirDatabase) -> TypeRef { |
1026 | db.impl_data(self.id).target_type.clone() | 1030 | db.impl_data(self.id).target_type.clone() |
1027 | } | 1031 | } |
1028 | 1032 | ||
1029 | pub fn target_ty(&self, db: &dyn HirDatabase) -> Type { | 1033 | pub fn target_ty(self, db: &dyn HirDatabase) -> Type { |
1030 | let impl_data = db.impl_data(self.id); | 1034 | let impl_data = db.impl_data(self.id); |
1031 | let resolver = self.id.resolver(db.upcast()); | 1035 | let resolver = self.id.resolver(db.upcast()); |
1032 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); | 1036 | let ctx = hir_ty::TyLoweringContext::new(db, &resolver); |
@@ -1038,23 +1042,23 @@ impl ImplDef { | |||
1038 | } | 1042 | } |
1039 | } | 1043 | } |
1040 | 1044 | ||
1041 | pub fn items(&self, db: &dyn HirDatabase) -> Vec<AssocItem> { | 1045 | pub fn items(self, db: &dyn HirDatabase) -> Vec<AssocItem> { |
1042 | db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() | 1046 | db.impl_data(self.id).items.iter().map(|it| (*it).into()).collect() |
1043 | } | 1047 | } |
1044 | 1048 | ||
1045 | pub fn is_negative(&self, db: &dyn HirDatabase) -> bool { | 1049 | pub fn is_negative(self, db: &dyn HirDatabase) -> bool { |
1046 | db.impl_data(self.id).is_negative | 1050 | db.impl_data(self.id).is_negative |
1047 | } | 1051 | } |
1048 | 1052 | ||
1049 | pub fn module(&self, db: &dyn HirDatabase) -> Module { | 1053 | pub fn module(self, db: &dyn HirDatabase) -> Module { |
1050 | self.id.lookup(db.upcast()).container.module(db.upcast()).into() | 1054 | self.id.lookup(db.upcast()).container.module(db.upcast()).into() |
1051 | } | 1055 | } |
1052 | 1056 | ||
1053 | pub fn krate(&self, db: &dyn HirDatabase) -> Crate { | 1057 | pub fn krate(self, db: &dyn HirDatabase) -> Crate { |
1054 | Crate { id: self.module(db).id.krate } | 1058 | Crate { id: self.module(db).id.krate } |
1055 | } | 1059 | } |
1056 | 1060 | ||
1057 | pub fn is_builtin_derive(&self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { | 1061 | pub fn is_builtin_derive(self, db: &dyn HirDatabase) -> Option<InFile<ast::Attr>> { |
1058 | let src = self.source(db); | 1062 | let src = self.source(db); |
1059 | let item = src.file_id.is_builtin_derive(db.upcast())?; | 1063 | let item = src.file_id.is_builtin_derive(db.upcast())?; |
1060 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); | 1064 | let hygenic = hir_expand::hygiene::Hygiene::new(db.upcast(), item.file_id); |
@@ -1190,6 +1194,10 @@ impl Type { | |||
1190 | ) | 1194 | ) |
1191 | } | 1195 | } |
1192 | 1196 | ||
1197 | pub fn is_raw_ptr(&self) -> bool { | ||
1198 | matches!(&self.ty.value, Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(..), .. })) | ||
1199 | } | ||
1200 | |||
1193 | pub fn contains_unknown(&self) -> bool { | 1201 | pub fn contains_unknown(&self) -> bool { |
1194 | return go(&self.ty.value); | 1202 | return go(&self.ty.value); |
1195 | 1203 | ||
@@ -1363,6 +1371,7 @@ impl HirDisplay for Type { | |||
1363 | } | 1371 | } |
1364 | 1372 | ||
1365 | /// For IDE only | 1373 | /// For IDE only |
1374 | #[derive(Debug)] | ||
1366 | pub enum ScopeDef { | 1375 | pub enum ScopeDef { |
1367 | ModuleDef(ModuleDef), | 1376 | ModuleDef(ModuleDef), |
1368 | MacroDef(MacroDef), | 1377 | MacroDef(MacroDef), |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 4af0f046a..f4a6b0503 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -62,6 +62,7 @@ pub use crate::{ | |||
62 | 62 | ||
63 | pub use hir_def::{ | 63 | pub use hir_def::{ |
64 | adt::StructKind, | 64 | adt::StructKind, |
65 | attr::Attrs, | ||
65 | body::scope::ExprScopes, | 66 | body::scope::ExprScopes, |
66 | builtin_type::BuiltinType, | 67 | builtin_type::BuiltinType, |
67 | docs::Documentation, | 68 | docs::Documentation, |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 576cd0c65..2eeba0572 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -81,18 +81,24 @@ impl Attrs { | |||
81 | } | 81 | } |
82 | } | 82 | } |
83 | 83 | ||
84 | fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { | 84 | pub fn from_attrs_owner(db: &dyn DefDatabase, owner: InFile<&dyn AttrsOwner>) -> Attrs { |
85 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); | 85 | let hygiene = Hygiene::new(db.upcast(), owner.file_id); |
86 | Attrs::new(owner.value, &hygiene) | 86 | Attrs::new(owner.value, &hygiene) |
87 | } | 87 | } |
88 | 88 | ||
89 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { | 89 | pub(crate) fn new(owner: &dyn AttrsOwner, hygiene: &Hygiene) -> Attrs { |
90 | let docs = ast::CommentIter::from_syntax_node(owner.syntax()).doc_comment_text().map( | ||
91 | |docs_text| Attr { | ||
92 | input: Some(AttrInput::Literal(SmolStr::new(docs_text))), | ||
93 | path: ModPath::from(hir_expand::name!(doc)), | ||
94 | }, | ||
95 | ); | ||
90 | let mut attrs = owner.attrs().peekable(); | 96 | let mut attrs = owner.attrs().peekable(); |
91 | let entries = if attrs.peek().is_none() { | 97 | let entries = if attrs.peek().is_none() { |
92 | // Avoid heap allocation | 98 | // Avoid heap allocation |
93 | None | 99 | None |
94 | } else { | 100 | } else { |
95 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).collect()) | 101 | Some(attrs.flat_map(|ast| Attr::from_src(ast, hygiene)).chain(docs).collect()) |
96 | }; | 102 | }; |
97 | Attrs { entries } | 103 | Attrs { entries } |
98 | } | 104 | } |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index f5a7305dc..273036cee 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -29,7 +29,7 @@ use crate::{ | |||
29 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, | 29 | AsMacroCall, DefWithBodyId, HasModule, Lookup, ModuleId, |
30 | }; | 30 | }; |
31 | 31 | ||
32 | /// A subset of Exander that only deals with cfg attributes. We only need it to | 32 | /// A subset of Expander that only deals with cfg attributes. We only need it to |
33 | /// avoid cyclic queries in crate def map during enum processing. | 33 | /// avoid cyclic queries in crate def map during enum processing. |
34 | pub(crate) struct CfgExpander { | 34 | pub(crate) struct CfgExpander { |
35 | cfg_options: CfgOptions, | 35 | cfg_options: CfgOptions, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index e08d62dd6..f159f80af 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -28,7 +28,7 @@ use crate::{ | |||
28 | }, | 28 | }, |
29 | item_scope::BuiltinShadowMode, | 29 | item_scope::BuiltinShadowMode, |
30 | path::{GenericArgs, Path}, | 30 | path::{GenericArgs, Path}, |
31 | type_ref::{Mutability, TypeRef}, | 31 | type_ref::{Mutability, Rawness, TypeRef}, |
32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
33 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 33 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
34 | }; | 34 | }; |
@@ -134,7 +134,7 @@ impl ExprCollector<'_> { | |||
134 | self.make_expr(expr, Err(SyntheticSyntax)) | 134 | self.make_expr(expr, Err(SyntheticSyntax)) |
135 | } | 135 | } |
136 | fn empty_block(&mut self) -> ExprId { | 136 | fn empty_block(&mut self) -> ExprId { |
137 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None }) | 137 | self.alloc_expr_desugared(Expr::Block { statements: Vec::new(), tail: None, label: None }) |
138 | } | 138 | } |
139 | fn missing_expr(&mut self) -> ExprId { | 139 | fn missing_expr(&mut self) -> ExprId { |
140 | self.alloc_expr_desugared(Expr::Missing) | 140 | self.alloc_expr_desugared(Expr::Missing) |
@@ -215,7 +215,16 @@ impl ExprCollector<'_> { | |||
215 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 215 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
216 | ast::Expr::LoopExpr(e) => { | 216 | ast::Expr::LoopExpr(e) => { |
217 | let body = self.collect_block_opt(e.loop_body()); | 217 | let body = self.collect_block_opt(e.loop_body()); |
218 | self.alloc_expr(Expr::Loop { body }, syntax_ptr) | 218 | self.alloc_expr( |
219 | Expr::Loop { | ||
220 | body, | ||
221 | label: e | ||
222 | .label() | ||
223 | .and_then(|l| l.lifetime_token()) | ||
224 | .map(|l| Name::new_lifetime(&l)), | ||
225 | }, | ||
226 | syntax_ptr, | ||
227 | ) | ||
219 | } | 228 | } |
220 | ast::Expr::WhileExpr(e) => { | 229 | ast::Expr::WhileExpr(e) => { |
221 | let body = self.collect_block_opt(e.loop_body()); | 230 | let body = self.collect_block_opt(e.loop_body()); |
@@ -230,25 +239,56 @@ impl ExprCollector<'_> { | |||
230 | let pat = self.collect_pat(pat); | 239 | let pat = self.collect_pat(pat); |
231 | let match_expr = self.collect_expr_opt(condition.expr()); | 240 | let match_expr = self.collect_expr_opt(condition.expr()); |
232 | let placeholder_pat = self.missing_pat(); | 241 | let placeholder_pat = self.missing_pat(); |
233 | let break_ = self.alloc_expr_desugared(Expr::Break { expr: None }); | 242 | let break_ = |
243 | self.alloc_expr_desugared(Expr::Break { expr: None, label: None }); | ||
234 | let arms = vec![ | 244 | let arms = vec![ |
235 | MatchArm { pat, expr: body, guard: None }, | 245 | MatchArm { pat, expr: body, guard: None }, |
236 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, | 246 | MatchArm { pat: placeholder_pat, expr: break_, guard: None }, |
237 | ]; | 247 | ]; |
238 | let match_expr = | 248 | let match_expr = |
239 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); | 249 | self.alloc_expr_desugared(Expr::Match { expr: match_expr, arms }); |
240 | return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); | 250 | return self.alloc_expr( |
251 | Expr::Loop { | ||
252 | body: match_expr, | ||
253 | label: e | ||
254 | .label() | ||
255 | .and_then(|l| l.lifetime_token()) | ||
256 | .map(|l| Name::new_lifetime(&l)), | ||
257 | }, | ||
258 | syntax_ptr, | ||
259 | ); | ||
241 | } | 260 | } |
242 | }, | 261 | }, |
243 | }; | 262 | }; |
244 | 263 | ||
245 | self.alloc_expr(Expr::While { condition, body }, syntax_ptr) | 264 | self.alloc_expr( |
265 | Expr::While { | ||
266 | condition, | ||
267 | body, | ||
268 | label: e | ||
269 | .label() | ||
270 | .and_then(|l| l.lifetime_token()) | ||
271 | .map(|l| Name::new_lifetime(&l)), | ||
272 | }, | ||
273 | syntax_ptr, | ||
274 | ) | ||
246 | } | 275 | } |
247 | ast::Expr::ForExpr(e) => { | 276 | ast::Expr::ForExpr(e) => { |
248 | let iterable = self.collect_expr_opt(e.iterable()); | 277 | let iterable = self.collect_expr_opt(e.iterable()); |
249 | let pat = self.collect_pat_opt(e.pat()); | 278 | let pat = self.collect_pat_opt(e.pat()); |
250 | let body = self.collect_block_opt(e.loop_body()); | 279 | let body = self.collect_block_opt(e.loop_body()); |
251 | self.alloc_expr(Expr::For { iterable, pat, body }, syntax_ptr) | 280 | self.alloc_expr( |
281 | Expr::For { | ||
282 | iterable, | ||
283 | pat, | ||
284 | body, | ||
285 | label: e | ||
286 | .label() | ||
287 | .and_then(|l| l.lifetime_token()) | ||
288 | .map(|l| Name::new_lifetime(&l)), | ||
289 | }, | ||
290 | syntax_ptr, | ||
291 | ) | ||
252 | } | 292 | } |
253 | ast::Expr::CallExpr(e) => { | 293 | ast::Expr::CallExpr(e) => { |
254 | let callee = self.collect_expr_opt(e.expr()); | 294 | let callee = self.collect_expr_opt(e.expr()); |
@@ -301,13 +341,16 @@ impl ExprCollector<'_> { | |||
301 | .unwrap_or(Expr::Missing); | 341 | .unwrap_or(Expr::Missing); |
302 | self.alloc_expr(path, syntax_ptr) | 342 | self.alloc_expr(path, syntax_ptr) |
303 | } | 343 | } |
304 | ast::Expr::ContinueExpr(_e) => { | 344 | ast::Expr::ContinueExpr(e) => self.alloc_expr( |
305 | // FIXME: labels | 345 | Expr::Continue { label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, |
306 | self.alloc_expr(Expr::Continue, syntax_ptr) | 346 | syntax_ptr, |
307 | } | 347 | ), |
308 | ast::Expr::BreakExpr(e) => { | 348 | ast::Expr::BreakExpr(e) => { |
309 | let expr = e.expr().map(|e| self.collect_expr(e)); | 349 | let expr = e.expr().map(|e| self.collect_expr(e)); |
310 | self.alloc_expr(Expr::Break { expr }, syntax_ptr) | 350 | self.alloc_expr( |
351 | Expr::Break { expr, label: e.lifetime_token().map(|l| Name::new_lifetime(&l)) }, | ||
352 | syntax_ptr, | ||
353 | ) | ||
311 | } | 354 | } |
312 | ast::Expr::ParenExpr(e) => { | 355 | ast::Expr::ParenExpr(e) => { |
313 | let inner = self.collect_expr_opt(e.expr()); | 356 | let inner = self.collect_expr_opt(e.expr()); |
@@ -378,8 +421,21 @@ impl ExprCollector<'_> { | |||
378 | } | 421 | } |
379 | ast::Expr::RefExpr(e) => { | 422 | ast::Expr::RefExpr(e) => { |
380 | let expr = self.collect_expr_opt(e.expr()); | 423 | let expr = self.collect_expr_opt(e.expr()); |
381 | let mutability = Mutability::from_mutable(e.mut_token().is_some()); | 424 | let raw_tok = e.raw_token().is_some(); |
382 | self.alloc_expr(Expr::Ref { expr, mutability }, syntax_ptr) | 425 | let mutability = if raw_tok { |
426 | if e.mut_token().is_some() { | ||
427 | Mutability::Mut | ||
428 | } else if e.const_token().is_some() { | ||
429 | Mutability::Shared | ||
430 | } else { | ||
431 | unreachable!("parser only remaps to raw_token() if matching mutability token follows") | ||
432 | } | ||
433 | } else { | ||
434 | Mutability::from_mutable(e.mut_token().is_some()) | ||
435 | }; | ||
436 | let rawness = Rawness::from_raw(raw_tok); | ||
437 | |||
438 | self.alloc_expr(Expr::Ref { expr, rawness, mutability }, syntax_ptr) | ||
383 | } | 439 | } |
384 | ast::Expr::PrefixExpr(e) => { | 440 | ast::Expr::PrefixExpr(e) => { |
385 | let expr = self.collect_expr_opt(e.expr()); | 441 | let expr = self.collect_expr_opt(e.expr()); |
@@ -516,7 +572,8 @@ impl ExprCollector<'_> { | |||
516 | }) | 572 | }) |
517 | .collect(); | 573 | .collect(); |
518 | let tail = block.expr().map(|e| self.collect_expr(e)); | 574 | let tail = block.expr().map(|e| self.collect_expr(e)); |
519 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) | 575 | let label = block.label().and_then(|l| l.lifetime_token()).map(|t| Name::new_lifetime(&t)); |
576 | self.alloc_expr(Expr::Block { statements, tail, label }, syntax_node_ptr) | ||
520 | } | 577 | } |
521 | 578 | ||
522 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { | 579 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
diff --git a/crates/ra_hir_def/src/body/scope.rs b/crates/ra_hir_def/src/body/scope.rs index 09e92b74e..e48ff38f9 100644 --- a/crates/ra_hir_def/src/body/scope.rs +++ b/crates/ra_hir_def/src/body/scope.rs | |||
@@ -138,10 +138,10 @@ fn compute_block_scopes( | |||
138 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { | 138 | fn compute_expr_scopes(expr: ExprId, body: &Body, scopes: &mut ExprScopes, scope: ScopeId) { |
139 | scopes.set_scope(expr, scope); | 139 | scopes.set_scope(expr, scope); |
140 | match &body[expr] { | 140 | match &body[expr] { |
141 | Expr::Block { statements, tail } => { | 141 | Expr::Block { statements, tail, .. } => { |
142 | compute_block_scopes(&statements, *tail, body, scopes, scope); | 142 | compute_block_scopes(&statements, *tail, body, scopes, scope); |
143 | } | 143 | } |
144 | Expr::For { iterable, pat, body: body_expr } => { | 144 | Expr::For { iterable, pat, body: body_expr, .. } => { |
145 | compute_expr_scopes(*iterable, body, scopes, scope); | 145 | compute_expr_scopes(*iterable, body, scopes, scope); |
146 | let scope = scopes.new_scope(scope); | 146 | let scope = scopes.new_scope(scope); |
147 | scopes.add_bindings(body, scope, *pat); | 147 | scopes.add_bindings(body, scope, *pat); |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index e2130d931..807195d25 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -34,6 +34,7 @@ pub struct FunctionData { | |||
34 | /// True if the first param is `self`. This is relevant to decide whether this | 34 | /// True if the first param is `self`. This is relevant to decide whether this |
35 | /// can be called as a method. | 35 | /// can be called as a method. |
36 | pub has_self_param: bool, | 36 | pub has_self_param: bool, |
37 | pub is_unsafe: bool, | ||
37 | pub visibility: RawVisibility, | 38 | pub visibility: RawVisibility, |
38 | } | 39 | } |
39 | 40 | ||
@@ -85,11 +86,14 @@ impl FunctionData { | |||
85 | ret_type | 86 | ret_type |
86 | }; | 87 | }; |
87 | 88 | ||
89 | let is_unsafe = src.value.unsafe_token().is_some(); | ||
90 | |||
88 | let vis_default = RawVisibility::default_for_container(loc.container); | 91 | let vis_default = RawVisibility::default_for_container(loc.container); |
89 | let visibility = | 92 | let visibility = |
90 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); | 93 | RawVisibility::from_ast_with_default(db, vis_default, src.map(|s| s.visibility())); |
91 | 94 | ||
92 | let sig = FunctionData { name, params, ret_type, has_self_param, visibility, attrs }; | 95 | let sig = |
96 | FunctionData { name, params, ret_type, has_self_param, is_unsafe, visibility, attrs }; | ||
93 | Arc::new(sig) | 97 | Arc::new(sig) |
94 | } | 98 | } |
95 | } | 99 | } |
diff --git a/crates/ra_hir_def/src/docs.rs b/crates/ra_hir_def/src/docs.rs index b221ae1ce..2630b3d89 100644 --- a/crates/ra_hir_def/src/docs.rs +++ b/crates/ra_hir_def/src/docs.rs | |||
@@ -29,6 +29,13 @@ impl Documentation { | |||
29 | Documentation(s.into()) | 29 | Documentation(s.into()) |
30 | } | 30 | } |
31 | 31 | ||
32 | pub fn from_ast<N>(node: &N) -> Option<Documentation> | ||
33 | where | ||
34 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
35 | { | ||
36 | docs_from_ast(node) | ||
37 | } | ||
38 | |||
32 | pub fn as_str(&self) -> &str { | 39 | pub fn as_str(&self) -> &str { |
33 | &*self.0 | 40 | &*self.0 |
34 | } | 41 | } |
@@ -70,6 +77,45 @@ impl Documentation { | |||
70 | } | 77 | } |
71 | } | 78 | } |
72 | 79 | ||
73 | pub(crate) fn docs_from_ast(node: &impl ast::DocCommentsOwner) -> Option<Documentation> { | 80 | pub(crate) fn docs_from_ast<N>(node: &N) -> Option<Documentation> |
74 | node.doc_comment_text().map(|it| Documentation::new(&it)) | 81 | where |
82 | N: ast::DocCommentsOwner + ast::AttrsOwner, | ||
83 | { | ||
84 | let doc_comment_text = node.doc_comment_text(); | ||
85 | let doc_attr_text = expand_doc_attrs(node); | ||
86 | let docs = merge_doc_comments_and_attrs(doc_comment_text, doc_attr_text); | ||
87 | docs.map(|it| Documentation::new(&it)) | ||
88 | } | ||
89 | |||
90 | fn merge_doc_comments_and_attrs( | ||
91 | doc_comment_text: Option<String>, | ||
92 | doc_attr_text: Option<String>, | ||
93 | ) -> Option<String> { | ||
94 | match (doc_comment_text, doc_attr_text) { | ||
95 | (Some(mut comment_text), Some(attr_text)) => { | ||
96 | comment_text.push_str("\n\n"); | ||
97 | comment_text.push_str(&attr_text); | ||
98 | Some(comment_text) | ||
99 | } | ||
100 | (Some(comment_text), None) => Some(comment_text), | ||
101 | (None, Some(attr_text)) => Some(attr_text), | ||
102 | (None, None) => None, | ||
103 | } | ||
104 | } | ||
105 | |||
106 | fn expand_doc_attrs(owner: &dyn ast::AttrsOwner) -> Option<String> { | ||
107 | let mut docs = String::new(); | ||
108 | for attr in owner.attrs() { | ||
109 | if let Some(("doc", value)) = | ||
110 | attr.as_simple_key_value().as_ref().map(|(k, v)| (k.as_str(), v.as_str())) | ||
111 | { | ||
112 | docs.push_str(value); | ||
113 | docs.push_str("\n\n"); | ||
114 | } | ||
115 | } | ||
116 | if docs.is_empty() { | ||
117 | None | ||
118 | } else { | ||
119 | Some(docs.trim_end_matches("\n\n").to_owned()) | ||
120 | } | ||
75 | } | 121 | } |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index a0cdad529..ca49b26d1 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -19,7 +19,7 @@ use ra_syntax::ast::RangeOp; | |||
19 | use crate::{ | 19 | use crate::{ |
20 | builtin_type::{BuiltinFloat, BuiltinInt}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
21 | path::{GenericArgs, Path}, | 21 | path::{GenericArgs, Path}, |
22 | type_ref::{Mutability, TypeRef}, | 22 | type_ref::{Mutability, Rawness, TypeRef}, |
23 | }; | 23 | }; |
24 | 24 | ||
25 | pub type ExprId = Idx<Expr>; | 25 | pub type ExprId = Idx<Expr>; |
@@ -52,18 +52,22 @@ pub enum Expr { | |||
52 | Block { | 52 | Block { |
53 | statements: Vec<Statement>, | 53 | statements: Vec<Statement>, |
54 | tail: Option<ExprId>, | 54 | tail: Option<ExprId>, |
55 | label: Option<Name>, | ||
55 | }, | 56 | }, |
56 | Loop { | 57 | Loop { |
57 | body: ExprId, | 58 | body: ExprId, |
59 | label: Option<Name>, | ||
58 | }, | 60 | }, |
59 | While { | 61 | While { |
60 | condition: ExprId, | 62 | condition: ExprId, |
61 | body: ExprId, | 63 | body: ExprId, |
64 | label: Option<Name>, | ||
62 | }, | 65 | }, |
63 | For { | 66 | For { |
64 | iterable: ExprId, | 67 | iterable: ExprId, |
65 | pat: PatId, | 68 | pat: PatId, |
66 | body: ExprId, | 69 | body: ExprId, |
70 | label: Option<Name>, | ||
67 | }, | 71 | }, |
68 | Call { | 72 | Call { |
69 | callee: ExprId, | 73 | callee: ExprId, |
@@ -79,9 +83,12 @@ pub enum Expr { | |||
79 | expr: ExprId, | 83 | expr: ExprId, |
80 | arms: Vec<MatchArm>, | 84 | arms: Vec<MatchArm>, |
81 | }, | 85 | }, |
82 | Continue, | 86 | Continue { |
87 | label: Option<Name>, | ||
88 | }, | ||
83 | Break { | 89 | Break { |
84 | expr: Option<ExprId>, | 90 | expr: Option<ExprId>, |
91 | label: Option<Name>, | ||
85 | }, | 92 | }, |
86 | Return { | 93 | Return { |
87 | expr: Option<ExprId>, | 94 | expr: Option<ExprId>, |
@@ -110,6 +117,7 @@ pub enum Expr { | |||
110 | }, | 117 | }, |
111 | Ref { | 118 | Ref { |
112 | expr: ExprId, | 119 | expr: ExprId, |
120 | rawness: Rawness, | ||
113 | mutability: Mutability, | 121 | mutability: Mutability, |
114 | }, | 122 | }, |
115 | Box { | 123 | Box { |
@@ -224,7 +232,7 @@ impl Expr { | |||
224 | f(*else_branch); | 232 | f(*else_branch); |
225 | } | 233 | } |
226 | } | 234 | } |
227 | Expr::Block { statements, tail } => { | 235 | Expr::Block { statements, tail, .. } => { |
228 | for stmt in statements { | 236 | for stmt in statements { |
229 | match stmt { | 237 | match stmt { |
230 | Statement::Let { initializer, .. } => { | 238 | Statement::Let { initializer, .. } => { |
@@ -240,8 +248,8 @@ impl Expr { | |||
240 | } | 248 | } |
241 | } | 249 | } |
242 | Expr::TryBlock { body } => f(*body), | 250 | Expr::TryBlock { body } => f(*body), |
243 | Expr::Loop { body } => f(*body), | 251 | Expr::Loop { body, .. } => f(*body), |
244 | Expr::While { condition, body } => { | 252 | Expr::While { condition, body, .. } => { |
245 | f(*condition); | 253 | f(*condition); |
246 | f(*body); | 254 | f(*body); |
247 | } | 255 | } |
@@ -267,8 +275,8 @@ impl Expr { | |||
267 | f(arm.expr); | 275 | f(arm.expr); |
268 | } | 276 | } |
269 | } | 277 | } |
270 | Expr::Continue => {} | 278 | Expr::Continue { .. } => {} |
271 | Expr::Break { expr } | Expr::Return { expr } => { | 279 | Expr::Break { expr, .. } | Expr::Return { expr } => { |
272 | if let Some(expr) = expr { | 280 | if let Some(expr) = expr { |
273 | f(*expr); | 281 | f(*expr); |
274 | } | 282 | } |
diff --git a/crates/ra_hir_def/src/lang_item.rs b/crates/ra_hir_def/src/lang_item.rs index d962db3cc..3516784b8 100644 --- a/crates/ra_hir_def/src/lang_item.rs +++ b/crates/ra_hir_def/src/lang_item.rs | |||
@@ -164,7 +164,7 @@ impl LangItems { | |||
164 | T: Into<AttrDefId> + Copy, | 164 | T: Into<AttrDefId> + Copy, |
165 | { | 165 | { |
166 | if let Some(lang_item_name) = lang_attr(db, item) { | 166 | if let Some(lang_item_name) = lang_attr(db, item) { |
167 | self.items.entry(lang_item_name.clone()).or_insert_with(|| constructor(item)); | 167 | self.items.entry(lang_item_name).or_insert_with(|| constructor(item)); |
168 | } | 168 | } |
169 | } | 169 | } |
170 | } | 170 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 4e628b14d..f44baa579 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -175,7 +175,7 @@ pub(super) enum DefKind { | |||
175 | } | 175 | } |
176 | 176 | ||
177 | impl DefKind { | 177 | impl DefKind { |
178 | pub fn ast_id(&self) -> FileAstId<ast::ModuleItem> { | 178 | pub fn ast_id(self) -> FileAstId<ast::ModuleItem> { |
179 | match self { | 179 | match self { |
180 | DefKind::Function(it) => it.upcast(), | 180 | DefKind::Function(it) => it.upcast(), |
181 | DefKind::Struct(it, _) => it.upcast(), | 181 | DefKind::Struct(it, _) => it.upcast(), |
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index 5bdad9efd..86a77b704 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs | |||
@@ -35,6 +35,22 @@ impl Mutability { | |||
35 | } | 35 | } |
36 | } | 36 | } |
37 | 37 | ||
38 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | ||
39 | pub enum Rawness { | ||
40 | RawPtr, | ||
41 | Ref, | ||
42 | } | ||
43 | |||
44 | impl Rawness { | ||
45 | pub fn from_raw(is_raw: bool) -> Rawness { | ||
46 | if is_raw { | ||
47 | Rawness::RawPtr | ||
48 | } else { | ||
49 | Rawness::Ref | ||
50 | } | ||
51 | } | ||
52 | } | ||
53 | |||
38 | /// Compare ty::Ty | 54 | /// Compare ty::Ty |
39 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] | 55 | #[derive(Clone, PartialEq, Eq, Hash, Debug)] |
40 | pub enum TypeRef { | 56 | pub enum TypeRef { |
diff --git a/crates/ra_hir_expand/src/name.rs b/crates/ra_hir_expand/src/name.rs index fecce224e..660bdfe33 100644 --- a/crates/ra_hir_expand/src/name.rs +++ b/crates/ra_hir_expand/src/name.rs | |||
@@ -37,6 +37,11 @@ impl Name { | |||
37 | Name(Repr::TupleField(idx)) | 37 | Name(Repr::TupleField(idx)) |
38 | } | 38 | } |
39 | 39 | ||
40 | pub fn new_lifetime(lt: &ra_syntax::SyntaxToken) -> Name { | ||
41 | assert!(lt.kind() == ra_syntax::SyntaxKind::LIFETIME); | ||
42 | Name(Repr::Text(lt.text().clone())) | ||
43 | } | ||
44 | |||
40 | /// Shortcut to create inline plain text name | 45 | /// Shortcut to create inline plain text name |
41 | const fn new_inline_ascii(text: &[u8]) -> Name { | 46 | const fn new_inline_ascii(text: &[u8]) -> Name { |
42 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) | 47 | Name::new_text(SmolStr::new_inline_from_ascii(text.len(), text)) |
@@ -148,6 +153,7 @@ pub mod known { | |||
148 | str, | 153 | str, |
149 | // Special names | 154 | // Special names |
150 | macro_rules, | 155 | macro_rules, |
156 | doc, | ||
151 | // Components of known path (value or mod name) | 157 | // Components of known path (value or mod name) |
152 | std, | 158 | std, |
153 | core, | 159 | core, |
diff --git a/crates/ra_hir_expand/src/proc_macro.rs b/crates/ra_hir_expand/src/proc_macro.rs index 4e0e069c8..04c026004 100644 --- a/crates/ra_hir_expand/src/proc_macro.rs +++ b/crates/ra_hir_expand/src/proc_macro.rs | |||
@@ -25,7 +25,7 @@ impl ProcMacroExpander { | |||
25 | } | 25 | } |
26 | 26 | ||
27 | pub fn expand( | 27 | pub fn expand( |
28 | &self, | 28 | self, |
29 | db: &dyn AstDatabase, | 29 | db: &dyn AstDatabase, |
30 | _id: LazyMacroId, | 30 | _id: LazyMacroId, |
31 | tt: &tt::Subtree, | 31 | tt: &tt::Subtree, |
diff --git a/crates/ra_hir_ty/Cargo.toml b/crates/ra_hir_ty/Cargo.toml index b2de7fa34..4b8dcdc07 100644 --- a/crates/ra_hir_ty/Cargo.toml +++ b/crates/ra_hir_ty/Cargo.toml | |||
@@ -27,9 +27,8 @@ test_utils = { path = "../test_utils" } | |||
27 | 27 | ||
28 | scoped-tls = "1" | 28 | scoped-tls = "1" |
29 | 29 | ||
30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } | 30 | chalk-solve = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } |
31 | chalk-rust-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } | 31 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "329b7f3fdd2431ed6f6778cde53f22374c7d094c" } |
32 | chalk-ir = { git = "https://github.com/rust-lang/chalk.git", rev = "eaab84b394007d1bed15f5470409a6ea02900a96" } | ||
33 | 32 | ||
34 | [dev-dependencies] | 33 | [dev-dependencies] |
35 | insta = "0.16.0" | 34 | insta = "0.16.0" |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index dfc6c7dd6..0a8bb24ac 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -76,6 +76,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
76 | #[salsa::interned] | 76 | #[salsa::interned] |
77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; | 77 | fn intern_type_ctor(&self, type_ctor: TypeCtor) -> crate::TypeCtorId; |
78 | #[salsa::interned] | 78 | #[salsa::interned] |
79 | fn intern_callable_def(&self, callable_def: CallableDef) -> crate::CallableDefId; | ||
80 | #[salsa::interned] | ||
79 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; | 81 | fn intern_type_param_id(&self, param_id: TypeParamId) -> GlobalTypeParamId; |
80 | #[salsa::interned] | 82 | #[salsa::interned] |
81 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; | 83 | fn intern_chalk_impl(&self, impl_: Impl) -> crate::traits::GlobalImplId; |
@@ -94,6 +96,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
94 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] | 96 | #[salsa::invoke(crate::traits::chalk::impl_datum_query)] |
95 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; | 97 | fn impl_datum(&self, krate: CrateId, impl_id: chalk::ImplId) -> Arc<chalk::ImplDatum>; |
96 | 98 | ||
99 | #[salsa::invoke(crate::traits::chalk::fn_def_datum_query)] | ||
100 | fn fn_def_datum(&self, krate: CrateId, fn_def_id: chalk::FnDefId) -> Arc<chalk::FnDefDatum>; | ||
101 | |||
97 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] | 102 | #[salsa::invoke(crate::traits::chalk::associated_ty_value_query)] |
98 | fn associated_ty_value( | 103 | fn associated_ty_value( |
99 | &self, | 104 | &self, |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 41ac70272..2c7298714 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -40,7 +40,7 @@ impl Diagnostic for MissingFields { | |||
40 | fn message(&self) -> String { | 40 | fn message(&self) -> String { |
41 | let mut buf = String::from("Missing structure fields:\n"); | 41 | let mut buf = String::from("Missing structure fields:\n"); |
42 | for field in &self.missed_fields { | 42 | for field in &self.missed_fields { |
43 | format_to!(buf, "- {}", field); | 43 | format_to!(buf, "- {}\n", field); |
44 | } | 44 | } |
45 | buf | 45 | buf |
46 | } | 46 | } |
@@ -73,7 +73,7 @@ impl Diagnostic for MissingPatFields { | |||
73 | fn message(&self) -> String { | 73 | fn message(&self) -> String { |
74 | let mut buf = String::from("Missing structure fields:\n"); | 74 | let mut buf = String::from("Missing structure fields:\n"); |
75 | for field in &self.missed_fields { | 75 | for field in &self.missed_fields { |
76 | format_to!(buf, "- {}", field); | 76 | format_to!(buf, "- {}\n", field); |
77 | } | 77 | } |
78 | buf | 78 | buf |
79 | } | 79 | } |
diff --git a/crates/ra_hir_ty/src/infer.rs b/crates/ra_hir_ty/src/infer.rs index 957d6e0b5..dc77e88e5 100644 --- a/crates/ra_hir_ty/src/infer.rs +++ b/crates/ra_hir_ty/src/infer.rs | |||
@@ -219,6 +219,17 @@ struct InferenceContext<'a> { | |||
219 | struct BreakableContext { | 219 | struct BreakableContext { |
220 | pub may_break: bool, | 220 | pub may_break: bool, |
221 | pub break_ty: Ty, | 221 | pub break_ty: Ty, |
222 | pub label: Option<name::Name>, | ||
223 | } | ||
224 | |||
225 | fn find_breakable<'c>( | ||
226 | ctxs: &'c mut [BreakableContext], | ||
227 | label: Option<&name::Name>, | ||
228 | ) -> Option<&'c mut BreakableContext> { | ||
229 | match label { | ||
230 | Some(_) => ctxs.iter_mut().rev().find(|ctx| ctx.label.as_ref() == label), | ||
231 | None => ctxs.last_mut(), | ||
232 | } | ||
222 | } | 233 | } |
223 | 234 | ||
224 | impl<'a> InferenceContext<'a> { | 235 | impl<'a> InferenceContext<'a> { |
diff --git a/crates/ra_hir_ty/src/infer/coerce.rs b/crates/ra_hir_ty/src/infer/coerce.rs index 2ee9adb16..32c7c57cd 100644 --- a/crates/ra_hir_ty/src/infer/coerce.rs +++ b/crates/ra_hir_ty/src/infer/coerce.rs | |||
@@ -45,9 +45,7 @@ impl<'a> InferenceContext<'a> { | |||
45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) | 45 | self.coerce_merge_branch(&ptr_ty1, &ptr_ty2) |
46 | } else { | 46 | } else { |
47 | mark::hit!(coerce_merge_fail_fallback); | 47 | mark::hit!(coerce_merge_fail_fallback); |
48 | // For incompatible types, we use the latter one as result | 48 | ty1.clone() |
49 | // to be better recovery for `if` without `else`. | ||
50 | ty2.clone() | ||
51 | } | 49 | } |
52 | } | 50 | } |
53 | } | 51 | } |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index b28724f0e..4a98e2deb 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -17,13 +17,13 @@ use crate::{ | |||
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::InEnvironment, | 18 | traits::InEnvironment, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Substs, TraitRef, | 20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | Ty, TypeCtor, Uncertain, | 21 | TraitRef, Ty, TypeCtor, Uncertain, |
22 | }; | 22 | }; |
23 | 23 | ||
24 | use super::{ | 24 | use super::{ |
25 | BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, InferenceDiagnostic, | 25 | find_breakable, BindingMode, BreakableContext, Diverges, Expectation, InferenceContext, |
26 | TypeMismatch, | 26 | InferenceDiagnostic, TypeMismatch, |
27 | }; | 27 | }; |
28 | 28 | ||
29 | impl<'a> InferenceContext<'a> { | 29 | impl<'a> InferenceContext<'a> { |
@@ -86,16 +86,20 @@ impl<'a> InferenceContext<'a> { | |||
86 | 86 | ||
87 | self.coerce_merge_branch(&then_ty, &else_ty) | 87 | self.coerce_merge_branch(&then_ty, &else_ty) |
88 | } | 88 | } |
89 | Expr::Block { statements, tail } => self.infer_block(statements, *tail, expected), | 89 | Expr::Block { statements, tail, .. } => { |
90 | // FIXME: Breakable block inference | ||
91 | self.infer_block(statements, *tail, expected) | ||
92 | } | ||
90 | Expr::TryBlock { body } => { | 93 | Expr::TryBlock { body } => { |
91 | let _inner = self.infer_expr(*body, expected); | 94 | let _inner = self.infer_expr(*body, expected); |
92 | // FIXME should be std::result::Result<{inner}, _> | 95 | // FIXME should be std::result::Result<{inner}, _> |
93 | Ty::Unknown | 96 | Ty::Unknown |
94 | } | 97 | } |
95 | Expr::Loop { body } => { | 98 | Expr::Loop { body, label } => { |
96 | self.breakables.push(BreakableContext { | 99 | self.breakables.push(BreakableContext { |
97 | may_break: false, | 100 | may_break: false, |
98 | break_ty: self.table.new_type_var(), | 101 | break_ty: self.table.new_type_var(), |
102 | label: label.clone(), | ||
99 | }); | 103 | }); |
100 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 104 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
101 | 105 | ||
@@ -110,8 +114,12 @@ impl<'a> InferenceContext<'a> { | |||
110 | Ty::simple(TypeCtor::Never) | 114 | Ty::simple(TypeCtor::Never) |
111 | } | 115 | } |
112 | } | 116 | } |
113 | Expr::While { condition, body } => { | 117 | Expr::While { condition, body, label } => { |
114 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 118 | self.breakables.push(BreakableContext { |
119 | may_break: false, | ||
120 | break_ty: Ty::Unknown, | ||
121 | label: label.clone(), | ||
122 | }); | ||
115 | // while let is desugared to a match loop, so this is always simple while | 123 | // while let is desugared to a match loop, so this is always simple while |
116 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); | 124 | self.infer_expr(*condition, &Expectation::has_type(Ty::simple(TypeCtor::Bool))); |
117 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); | 125 | self.infer_expr(*body, &Expectation::has_type(Ty::unit())); |
@@ -120,10 +128,14 @@ impl<'a> InferenceContext<'a> { | |||
120 | self.diverges = Diverges::Maybe; | 128 | self.diverges = Diverges::Maybe; |
121 | Ty::unit() | 129 | Ty::unit() |
122 | } | 130 | } |
123 | Expr::For { iterable, body, pat } => { | 131 | Expr::For { iterable, body, pat, label } => { |
124 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); | 132 | let iterable_ty = self.infer_expr(*iterable, &Expectation::none()); |
125 | 133 | ||
126 | self.breakables.push(BreakableContext { may_break: false, break_ty: Ty::Unknown }); | 134 | self.breakables.push(BreakableContext { |
135 | may_break: false, | ||
136 | break_ty: Ty::Unknown, | ||
137 | label: label.clone(), | ||
138 | }); | ||
127 | let pat_ty = | 139 | let pat_ty = |
128 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); | 140 | self.resolve_associated_type(iterable_ty, self.resolve_into_iter_item()); |
129 | 141 | ||
@@ -140,13 +152,13 @@ impl<'a> InferenceContext<'a> { | |||
140 | 152 | ||
141 | let mut sig_tys = Vec::new(); | 153 | let mut sig_tys = Vec::new(); |
142 | 154 | ||
143 | for (arg_pat, arg_type) in args.iter().zip(arg_types.iter()) { | 155 | // collect explicitly written argument types |
144 | let expected = if let Some(type_ref) = arg_type { | 156 | for arg_type in arg_types.iter() { |
157 | let arg_ty = if let Some(type_ref) = arg_type { | ||
145 | self.make_ty(type_ref) | 158 | self.make_ty(type_ref) |
146 | } else { | 159 | } else { |
147 | Ty::Unknown | 160 | self.table.new_type_var() |
148 | }; | 161 | }; |
149 | let arg_ty = self.infer_pat(*arg_pat, &expected, BindingMode::default()); | ||
150 | sig_tys.push(arg_ty); | 162 | sig_tys.push(arg_ty); |
151 | } | 163 | } |
152 | 164 | ||
@@ -158,7 +170,7 @@ impl<'a> InferenceContext<'a> { | |||
158 | sig_tys.push(ret_ty.clone()); | 170 | sig_tys.push(ret_ty.clone()); |
159 | let sig_ty = Ty::apply( | 171 | let sig_ty = Ty::apply( |
160 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, | 172 | TypeCtor::FnPtr { num_args: sig_tys.len() as u16 - 1 }, |
161 | Substs(sig_tys.into()), | 173 | Substs(sig_tys.clone().into()), |
162 | ); | 174 | ); |
163 | let closure_ty = | 175 | let closure_ty = |
164 | Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); | 176 | Ty::apply_one(TypeCtor::Closure { def: self.owner, expr: tgt_expr }, sig_ty); |
@@ -168,6 +180,12 @@ impl<'a> InferenceContext<'a> { | |||
168 | // infer the body. | 180 | // infer the body. |
169 | self.coerce(&closure_ty, &expected.ty); | 181 | self.coerce(&closure_ty, &expected.ty); |
170 | 182 | ||
183 | // Now go through the argument patterns | ||
184 | for (arg_pat, arg_ty) in args.iter().zip(sig_tys) { | ||
185 | let resolved = self.resolve_ty_as_possible(arg_ty); | ||
186 | self.infer_pat(*arg_pat, &resolved, BindingMode::default()); | ||
187 | } | ||
188 | |||
171 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); | 189 | let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe); |
172 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); | 190 | let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone()); |
173 | 191 | ||
@@ -230,23 +248,24 @@ impl<'a> InferenceContext<'a> { | |||
230 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); | 248 | let resolver = resolver_for_expr(self.db.upcast(), self.owner, tgt_expr); |
231 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) | 249 | self.infer_path(&resolver, p, tgt_expr.into()).unwrap_or(Ty::Unknown) |
232 | } | 250 | } |
233 | Expr::Continue => Ty::simple(TypeCtor::Never), | 251 | Expr::Continue { .. } => Ty::simple(TypeCtor::Never), |
234 | Expr::Break { expr } => { | 252 | Expr::Break { expr, label } => { |
235 | let val_ty = if let Some(expr) = expr { | 253 | let val_ty = if let Some(expr) = expr { |
236 | self.infer_expr(*expr, &Expectation::none()) | 254 | self.infer_expr(*expr, &Expectation::none()) |
237 | } else { | 255 | } else { |
238 | Ty::unit() | 256 | Ty::unit() |
239 | }; | 257 | }; |
240 | 258 | ||
241 | let last_ty = if let Some(ctxt) = self.breakables.last() { | 259 | let last_ty = |
242 | ctxt.break_ty.clone() | 260 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
243 | } else { | 261 | ctxt.break_ty.clone() |
244 | Ty::Unknown | 262 | } else { |
245 | }; | 263 | Ty::Unknown |
264 | }; | ||
246 | 265 | ||
247 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); | 266 | let merged_type = self.coerce_merge_branch(&last_ty, &val_ty); |
248 | 267 | ||
249 | if let Some(ctxt) = self.breakables.last_mut() { | 268 | if let Some(ctxt) = find_breakable(&mut self.breakables, label.as_ref()) { |
250 | ctxt.break_ty = merged_type; | 269 | ctxt.break_ty = merged_type; |
251 | ctxt.may_break = true; | 270 | ctxt.may_break = true; |
252 | } else { | 271 | } else { |
@@ -350,19 +369,28 @@ impl<'a> InferenceContext<'a> { | |||
350 | // FIXME check the cast... | 369 | // FIXME check the cast... |
351 | cast_ty | 370 | cast_ty |
352 | } | 371 | } |
353 | Expr::Ref { expr, mutability } => { | 372 | Expr::Ref { expr, rawness, mutability } => { |
354 | let expectation = | 373 | let expectation = if let Some((exp_inner, exp_rawness, exp_mutability)) = |
355 | if let Some((exp_inner, exp_mutability)) = &expected.ty.as_reference() { | 374 | &expected.ty.as_reference_or_ptr() |
356 | if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { | 375 | { |
357 | // FIXME: throw type error - expected mut reference but found shared ref, | 376 | if *exp_mutability == Mutability::Mut && *mutability == Mutability::Shared { |
358 | // which cannot be coerced | 377 | // FIXME: throw type error - expected mut reference but found shared ref, |
359 | } | 378 | // which cannot be coerced |
360 | Expectation::rvalue_hint(Ty::clone(exp_inner)) | 379 | } |
361 | } else { | 380 | if *exp_rawness == Rawness::Ref && *rawness == Rawness::RawPtr { |
362 | Expectation::none() | 381 | // FIXME: throw type error - expected reference but found ptr, |
363 | }; | 382 | // which cannot be coerced |
383 | } | ||
384 | Expectation::rvalue_hint(Ty::clone(exp_inner)) | ||
385 | } else { | ||
386 | Expectation::none() | ||
387 | }; | ||
364 | let inner_ty = self.infer_expr_inner(*expr, &expectation); | 388 | let inner_ty = self.infer_expr_inner(*expr, &expectation); |
365 | Ty::apply_one(TypeCtor::Ref(*mutability), inner_ty) | 389 | let ty = match rawness { |
390 | Rawness::RawPtr => TypeCtor::RawPtr(*mutability), | ||
391 | Rawness::Ref => TypeCtor::Ref(*mutability), | ||
392 | }; | ||
393 | Ty::apply_one(ty, inner_ty) | ||
366 | } | 394 | } |
367 | Expr::Box { expr } => { | 395 | Expr::Box { expr } => { |
368 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); | 396 | let inner_ty = self.infer_expr_inner(*expr, &Expectation::none()); |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index e91c9be04..9fa8d3bdc 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -49,8 +49,10 @@ use std::sync::Arc; | |||
49 | use std::{iter, mem}; | 49 | use std::{iter, mem}; |
50 | 50 | ||
51 | use hir_def::{ | 51 | use hir_def::{ |
52 | expr::ExprId, type_ref::Mutability, AdtId, AssocContainerId, DefWithBodyId, GenericDefId, | 52 | expr::ExprId, |
53 | HasModule, Lookup, TraitId, TypeAliasId, TypeParamId, | 53 | type_ref::{Mutability, Rawness}, |
54 | AdtId, AssocContainerId, DefWithBodyId, GenericDefId, HasModule, Lookup, TraitId, TypeAliasId, | ||
55 | TypeParamId, | ||
54 | }; | 56 | }; |
55 | use ra_db::{impl_intern_key, salsa, CrateId}; | 57 | use ra_db::{impl_intern_key, salsa, CrateId}; |
56 | 58 | ||
@@ -159,6 +161,12 @@ pub enum TypeCtor { | |||
159 | pub struct TypeCtorId(salsa::InternId); | 161 | pub struct TypeCtorId(salsa::InternId); |
160 | impl_intern_key!(TypeCtorId); | 162 | impl_intern_key!(TypeCtorId); |
161 | 163 | ||
164 | /// This exists just for Chalk, because Chalk just has a single `FnDefId` where | ||
165 | /// we have different IDs for struct and enum variant constructors. | ||
166 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)] | ||
167 | pub struct CallableDefId(salsa::InternId); | ||
168 | impl_intern_key!(CallableDefId); | ||
169 | |||
162 | impl TypeCtor { | 170 | impl TypeCtor { |
163 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { | 171 | pub fn num_ty_params(self, db: &dyn HirDatabase) -> usize { |
164 | match self { | 172 | match self { |
@@ -703,6 +711,18 @@ impl Ty { | |||
703 | } | 711 | } |
704 | } | 712 | } |
705 | 713 | ||
714 | pub fn as_reference_or_ptr(&self) -> Option<(&Ty, Rawness, Mutability)> { | ||
715 | match self { | ||
716 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(mutability), parameters }) => { | ||
717 | Some((parameters.as_single(), Rawness::Ref, *mutability)) | ||
718 | } | ||
719 | Ty::Apply(ApplicationTy { ctor: TypeCtor::RawPtr(mutability), parameters }) => { | ||
720 | Some((parameters.as_single(), Rawness::RawPtr, *mutability)) | ||
721 | } | ||
722 | _ => None, | ||
723 | } | ||
724 | } | ||
725 | |||
706 | pub fn strip_references(&self) -> &Ty { | 726 | pub fn strip_references(&self) -> &Ty { |
707 | let mut t: &Ty = self; | 727 | let mut t: &Ty = self; |
708 | 728 | ||
diff --git a/crates/ra_hir_ty/src/tests/coercion.rs b/crates/ra_hir_ty/src/tests/coercion.rs index 2cc4f4bf9..6f777ed8c 100644 --- a/crates/ra_hir_ty/src/tests/coercion.rs +++ b/crates/ra_hir_ty/src/tests/coercion.rs | |||
@@ -116,15 +116,20 @@ fn infer_let_stmt_coerce() { | |||
116 | assert_snapshot!( | 116 | assert_snapshot!( |
117 | infer(r#" | 117 | infer(r#" |
118 | fn test() { | 118 | fn test() { |
119 | let x: &[i32] = &[1]; | 119 | let x: &[isize] = &[1]; |
120 | let x: *const [isize] = &[1]; | ||
120 | } | 121 | } |
121 | "#), | 122 | "#), |
122 | @r###" | 123 | @r###" |
123 | 11..40 '{ ...[1]; }': () | 124 | 11..76 '{ ...[1]; }': () |
124 | 21..22 'x': &[i32] | 125 | 21..22 'x': &[isize] |
125 | 33..37 '&[1]': &[i32; _] | 126 | 35..39 '&[1]': &[isize; _] |
126 | 34..37 '[1]': [i32; _] | 127 | 36..39 '[1]': [isize; _] |
127 | 35..36 '1': i32 | 128 | 37..38 '1': isize |
129 | 49..50 'x': *const [isize] | ||
130 | 69..73 '&[1]': &[isize; _] | ||
131 | 70..73 '[1]': [isize; _] | ||
132 | 71..72 '1': isize | ||
128 | "###); | 133 | "###); |
129 | } | 134 | } |
130 | 135 | ||
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index 0c5f972a2..fe62587c0 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs | |||
@@ -520,3 +520,53 @@ fn main() { | |||
520 | 105..107 '()': () | 520 | 105..107 '()': () |
521 | ") | 521 | ") |
522 | } | 522 | } |
523 | |||
524 | #[test] | ||
525 | fn match_ergonomics_in_closure_params() { | ||
526 | assert_snapshot!( | ||
527 | infer(r#" | ||
528 | #[lang = "fn_once"] | ||
529 | trait FnOnce<Args> { | ||
530 | type Output; | ||
531 | } | ||
532 | |||
533 | fn foo<T, U, F: FnOnce(T) -> U>(t: T, f: F) -> U { loop {} } | ||
534 | |||
535 | fn test() { | ||
536 | foo(&(1, "a"), |&(x, y)| x); // normal, no match ergonomics | ||
537 | foo(&(1, "a"), |(x, y)| x); | ||
538 | } | ||
539 | "#), | ||
540 | @r###" | ||
541 | 94..95 't': T | ||
542 | 100..101 'f': F | ||
543 | 111..122 '{ loop {} }': U | ||
544 | 113..120 'loop {}': ! | ||
545 | 118..120 '{}': () | ||
546 | 134..233 '{ ... x); }': () | ||
547 | 140..143 'foo': fn foo<&(i32, &str), i32, |&(i32, &str)| -> i32>(&(i32, &str), |&(i32, &str)| -> i32) -> i32 | ||
548 | 140..167 'foo(&(...y)| x)': i32 | ||
549 | 144..153 '&(1, "a")': &(i32, &str) | ||
550 | 145..153 '(1, "a")': (i32, &str) | ||
551 | 146..147 '1': i32 | ||
552 | 149..152 '"a"': &str | ||
553 | 155..166 '|&(x, y)| x': |&(i32, &str)| -> i32 | ||
554 | 156..163 '&(x, y)': &(i32, &str) | ||
555 | 157..163 '(x, y)': (i32, &str) | ||
556 | 158..159 'x': i32 | ||
557 | 161..162 'y': &str | ||
558 | 165..166 'x': i32 | ||
559 | 204..207 'foo': fn foo<&(i32, &str), &i32, |&(i32, &str)| -> &i32>(&(i32, &str), |&(i32, &str)| -> &i32) -> &i32 | ||
560 | 204..230 'foo(&(...y)| x)': &i32 | ||
561 | 208..217 '&(1, "a")': &(i32, &str) | ||
562 | 209..217 '(1, "a")': (i32, &str) | ||
563 | 210..211 '1': i32 | ||
564 | 213..216 '"a"': &str | ||
565 | 219..229 '|(x, y)| x': |&(i32, &str)| -> &i32 | ||
566 | 220..226 '(x, y)': (i32, &str) | ||
567 | 221..222 'x': &i32 | ||
568 | 224..225 'y': &&str | ||
569 | 228..229 'x': &i32 | ||
570 | "### | ||
571 | ); | ||
572 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/simple.rs b/crates/ra_hir_ty/src/tests/simple.rs index fd2208af2..88309157b 100644 --- a/crates/ra_hir_ty/src/tests/simple.rs +++ b/crates/ra_hir_ty/src/tests/simple.rs | |||
@@ -385,6 +385,26 @@ fn test(a: &u32, b: &mut u32, c: *const u32, d: *mut u32) { | |||
385 | } | 385 | } |
386 | 386 | ||
387 | #[test] | 387 | #[test] |
388 | fn infer_raw_ref() { | ||
389 | assert_snapshot!( | ||
390 | infer(r#" | ||
391 | fn test(a: i32) { | ||
392 | &raw mut a; | ||
393 | &raw const a; | ||
394 | } | ||
395 | "#), | ||
396 | @r###" | ||
397 | 9..10 'a': i32 | ||
398 | 17..54 '{ ...t a; }': () | ||
399 | 23..33 '&raw mut a': *mut i32 | ||
400 | 32..33 'a': i32 | ||
401 | 39..51 '&raw const a': *const i32 | ||
402 | 50..51 'a': i32 | ||
403 | "### | ||
404 | ); | ||
405 | } | ||
406 | |||
407 | #[test] | ||
388 | fn infer_literals() { | 408 | fn infer_literals() { |
389 | assert_snapshot!( | 409 | assert_snapshot!( |
390 | infer(r##" | 410 | infer(r##" |
@@ -937,7 +957,7 @@ fn main(foo: Foo) { | |||
937 | 51..107 'if tru... }': () | 957 | 51..107 'if tru... }': () |
938 | 54..58 'true': bool | 958 | 54..58 'true': bool |
939 | 59..67 '{ }': () | 959 | 59..67 '{ }': () |
940 | 73..107 'if fal... }': () | 960 | 73..107 'if fal... }': i32 |
941 | 76..81 'false': bool | 961 | 76..81 'false': bool |
942 | 82..107 '{ ... }': i32 | 962 | 82..107 '{ ... }': i32 |
943 | 92..95 'foo': Foo | 963 | 92..95 'foo': Foo |
@@ -1923,3 +1943,57 @@ fn test() { | |||
1923 | "### | 1943 | "### |
1924 | ); | 1944 | ); |
1925 | } | 1945 | } |
1946 | |||
1947 | #[test] | ||
1948 | fn infer_labelled_break_with_val() { | ||
1949 | assert_snapshot!( | ||
1950 | infer(r#" | ||
1951 | fn foo() { | ||
1952 | let _x = || 'outer: loop { | ||
1953 | let inner = 'inner: loop { | ||
1954 | let i = Default::default(); | ||
1955 | if (break 'outer i) { | ||
1956 | loop { break 'inner 5i8; }; | ||
1957 | } else if true { | ||
1958 | break 'inner 6; | ||
1959 | } | ||
1960 | break 7; | ||
1961 | }; | ||
1962 | break inner < 8; | ||
1963 | }; | ||
1964 | } | ||
1965 | "#), | ||
1966 | @r###" | ||
1967 | 10..336 '{ ... }; }': () | ||
1968 | 20..22 '_x': || -> bool | ||
1969 | 25..333 '|| 'ou... }': || -> bool | ||
1970 | 28..333 ''outer... }': bool | ||
1971 | 41..333 '{ ... }': () | ||
1972 | 55..60 'inner': i8 | ||
1973 | 63..301 ''inner... }': i8 | ||
1974 | 76..301 '{ ... }': () | ||
1975 | 94..95 'i': bool | ||
1976 | 98..114 'Defaul...efault': {unknown} | ||
1977 | 98..116 'Defaul...ault()': bool | ||
1978 | 130..270 'if (br... }': () | ||
1979 | 134..148 'break 'outer i': ! | ||
1980 | 147..148 'i': bool | ||
1981 | 150..209 '{ ... }': () | ||
1982 | 168..194 'loop {...5i8; }': ! | ||
1983 | 173..194 '{ brea...5i8; }': () | ||
1984 | 175..191 'break ...er 5i8': ! | ||
1985 | 188..191 '5i8': i8 | ||
1986 | 215..270 'if tru... }': () | ||
1987 | 218..222 'true': bool | ||
1988 | 223..270 '{ ... }': () | ||
1989 | 241..255 'break 'inner 6': ! | ||
1990 | 254..255 '6': i8 | ||
1991 | 283..290 'break 7': ! | ||
1992 | 289..290 '7': i8 | ||
1993 | 311..326 'break inner < 8': ! | ||
1994 | 317..322 'inner': i8 | ||
1995 | 317..326 'inner < 8': bool | ||
1996 | 325..326 '8': i8 | ||
1997 | "### | ||
1998 | ); | ||
1999 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index 6826610cb..e8778d419 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2644,6 +2644,79 @@ fn test() { | |||
2644 | } | 2644 | } |
2645 | 2645 | ||
2646 | #[test] | 2646 | #[test] |
2647 | fn builtin_fn_def_copy() { | ||
2648 | assert_snapshot!( | ||
2649 | infer_with_mismatches(r#" | ||
2650 | #[lang = "copy"] | ||
2651 | trait Copy {} | ||
2652 | |||
2653 | fn foo() {} | ||
2654 | fn bar<T: Copy>(T) -> T {} | ||
2655 | struct Struct(usize); | ||
2656 | enum Enum { Variant(usize) } | ||
2657 | |||
2658 | trait Test { fn test(&self) -> bool; } | ||
2659 | impl<T: Copy> Test for T {} | ||
2660 | |||
2661 | fn test() { | ||
2662 | foo.test(); | ||
2663 | bar.test(); | ||
2664 | Struct.test(); | ||
2665 | Enum::Variant.test(); | ||
2666 | } | ||
2667 | "#, true), | ||
2668 | @r###" | ||
2669 | 42..44 '{}': () | ||
2670 | 61..62 'T': {unknown} | ||
2671 | 69..71 '{}': () | ||
2672 | 69..71: expected T, got () | ||
2673 | 146..150 'self': &Self | ||
2674 | 202..282 '{ ...t(); }': () | ||
2675 | 208..211 'foo': fn foo() | ||
2676 | 208..218 'foo.test()': bool | ||
2677 | 224..227 'bar': fn bar<{unknown}>({unknown}) -> {unknown} | ||
2678 | 224..234 'bar.test()': bool | ||
2679 | 240..246 'Struct': Struct(usize) -> Struct | ||
2680 | 240..253 'Struct.test()': bool | ||
2681 | 259..272 'Enum::Variant': Variant(usize) -> Enum | ||
2682 | 259..279 'Enum::...test()': bool | ||
2683 | "### | ||
2684 | ); | ||
2685 | } | ||
2686 | |||
2687 | #[test] | ||
2688 | fn builtin_fn_ptr_copy() { | ||
2689 | assert_snapshot!( | ||
2690 | infer_with_mismatches(r#" | ||
2691 | #[lang = "copy"] | ||
2692 | trait Copy {} | ||
2693 | |||
2694 | trait Test { fn test(&self) -> bool; } | ||
2695 | impl<T: Copy> Test for T {} | ||
2696 | |||
2697 | fn test(f1: fn(), f2: fn(usize) -> u8, f3: fn(u8, u8) -> &u8) { | ||
2698 | f1.test(); | ||
2699 | f2.test(); | ||
2700 | f3.test(); | ||
2701 | } | ||
2702 | "#, true), | ||
2703 | @r###" | ||
2704 | 55..59 'self': &Self | ||
2705 | 109..111 'f1': fn() | ||
2706 | 119..121 'f2': fn(usize) -> u8 | ||
2707 | 140..142 'f3': fn(u8, u8) -> &u8 | ||
2708 | 163..211 '{ ...t(); }': () | ||
2709 | 169..171 'f1': fn() | ||
2710 | 169..178 'f1.test()': bool | ||
2711 | 184..186 'f2': fn(usize) -> u8 | ||
2712 | 184..193 'f2.test()': bool | ||
2713 | 199..201 'f3': fn(u8, u8) -> &u8 | ||
2714 | 199..208 'f3.test()': bool | ||
2715 | "### | ||
2716 | ); | ||
2717 | } | ||
2718 | |||
2719 | #[test] | ||
2647 | fn builtin_sized() { | 2720 | fn builtin_sized() { |
2648 | assert_snapshot!( | 2721 | assert_snapshot!( |
2649 | infer_with_mismatches(r#" | 2722 | infer_with_mismatches(r#" |
@@ -2680,3 +2753,48 @@ fn test() { | |||
2680 | "### | 2753 | "### |
2681 | ); | 2754 | ); |
2682 | } | 2755 | } |
2756 | |||
2757 | #[test] | ||
2758 | fn integer_range_iterate() { | ||
2759 | let t = type_at( | ||
2760 | r#" | ||
2761 | //- /main.rs crate:main deps:std | ||
2762 | fn test() { | ||
2763 | for x in 0..100 { x<|>; } | ||
2764 | } | ||
2765 | |||
2766 | //- /std.rs crate:std | ||
2767 | pub mod ops { | ||
2768 | pub struct Range<Idx> { | ||
2769 | pub start: Idx, | ||
2770 | pub end: Idx, | ||
2771 | } | ||
2772 | } | ||
2773 | |||
2774 | pub mod iter { | ||
2775 | pub trait Iterator { | ||
2776 | type Item; | ||
2777 | } | ||
2778 | |||
2779 | pub trait IntoIterator { | ||
2780 | type Item; | ||
2781 | type IntoIter: Iterator<Item = Self::Item>; | ||
2782 | } | ||
2783 | |||
2784 | impl<T> IntoIterator for T where T: Iterator { | ||
2785 | type Item = <T as Iterator>::Item; | ||
2786 | type IntoIter = Self; | ||
2787 | } | ||
2788 | } | ||
2789 | |||
2790 | trait Step {} | ||
2791 | impl Step for i32 {} | ||
2792 | impl Step for i64 {} | ||
2793 | |||
2794 | impl<A: Step> iter::Iterator for ops::Range<A> { | ||
2795 | type Item = A; | ||
2796 | } | ||
2797 | "#, | ||
2798 | ); | ||
2799 | assert_eq!(t, "i32"); | ||
2800 | } | ||
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index ccab246bf..88a422d2c 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -290,8 +290,7 @@ fn trait_object_unsize_impl_datum( | |||
290 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; | 290 | let self_trait_ref = TraitRef { trait_, substs: self_substs }; |
291 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; | 291 | let where_clauses = vec![GenericPredicate::Implemented(self_trait_ref)]; |
292 | 292 | ||
293 | let impl_substs = | 293 | let impl_substs = Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.into())).build(); |
294 | Substs::builder(2).push(self_ty).push(Ty::Dyn(target_bounds.clone().into())).build(); | ||
295 | 294 | ||
296 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; | 295 | let trait_ref = TraitRef { trait_: unsize_trait, substs: impl_substs }; |
297 | 296 | ||
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index e2f2a9ccb..61de3cc30 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -4,6 +4,7 @@ use std::sync::Arc; | |||
4 | use log::debug; | 4 | use log::debug; |
5 | 5 | ||
6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; | 6 | use chalk_ir::{fold::shift::Shift, GenericArg, TypeName}; |
7 | use chalk_solve::rust_ir::{self, WellKnownTrait}; | ||
7 | 8 | ||
8 | use hir_def::{ | 9 | use hir_def::{ |
9 | lang_item::{lang_attr, LangItemTarget}, | 10 | lang_item::{lang_attr, LangItemTarget}, |
@@ -14,9 +15,8 @@ use ra_db::{salsa::InternKey, CrateId}; | |||
14 | use super::{builtin, AssocTyValue, ChalkContext, Impl}; | 15 | use super::{builtin, AssocTyValue, ChalkContext, Impl}; |
15 | use crate::{ | 16 | use crate::{ |
16 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, | 17 | db::HirDatabase, display::HirDisplay, method_resolution::TyFingerprint, utils::generics, |
17 | DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, | 18 | CallableDef, DebruijnIndex, GenericPredicate, Substs, Ty, TypeCtor, |
18 | }; | 19 | }; |
19 | use chalk_rust_ir::WellKnownTrait; | ||
20 | use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; | 20 | use mapping::{convert_where_clauses, generic_predicate_to_inline_bound, make_binders}; |
21 | 21 | ||
22 | pub use self::interner::*; | 22 | pub use self::interner::*; |
@@ -54,10 +54,9 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
54 | 54 | ||
55 | fn fn_def_datum( | 55 | fn fn_def_datum( |
56 | &self, | 56 | &self, |
57 | _fn_def_id: chalk_ir::FnDefId<Interner>, | 57 | fn_def_id: chalk_ir::FnDefId<Interner>, |
58 | ) -> Arc<chalk_rust_ir::FnDefDatum<Interner>> { | 58 | ) -> Arc<rust_ir::FnDefDatum<Interner>> { |
59 | // We don't yet provide any FnDefs to Chalk | 59 | self.db.fn_def_datum(self.krate, fn_def_id) |
60 | unimplemented!() | ||
61 | } | 60 | } |
62 | 61 | ||
63 | fn impls_for_trait( | 62 | fn impls_for_trait( |
@@ -113,7 +112,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
113 | } | 112 | } |
114 | fn well_known_trait_id( | 113 | fn well_known_trait_id( |
115 | &self, | 114 | &self, |
116 | well_known_trait: chalk_rust_ir::WellKnownTrait, | 115 | well_known_trait: rust_ir::WellKnownTrait, |
117 | ) -> Option<chalk_ir::TraitId<Interner>> { | 116 | ) -> Option<chalk_ir::TraitId<Interner>> { |
118 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); | 117 | let lang_attr = lang_attr_from_well_known_trait(well_known_trait); |
119 | let lang_items = self.db.crate_lang_items(self.krate); | 118 | let lang_items = self.db.crate_lang_items(self.krate); |
@@ -134,13 +133,13 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
134 | fn opaque_ty_data( | 133 | fn opaque_ty_data( |
135 | &self, | 134 | &self, |
136 | _id: chalk_ir::OpaqueTyId<Interner>, | 135 | _id: chalk_ir::OpaqueTyId<Interner>, |
137 | ) -> Arc<chalk_rust_ir::OpaqueTyDatum<Interner>> { | 136 | ) -> Arc<rust_ir::OpaqueTyDatum<Interner>> { |
138 | unimplemented!() | 137 | unimplemented!() |
139 | } | 138 | } |
140 | 139 | ||
141 | fn force_impl_for( | 140 | fn force_impl_for( |
142 | &self, | 141 | &self, |
143 | _well_known: chalk_rust_ir::WellKnownTrait, | 142 | _well_known: rust_ir::WellKnownTrait, |
144 | _ty: &chalk_ir::TyData<Interner>, | 143 | _ty: &chalk_ir::TyData<Interner>, |
145 | ) -> Option<bool> { | 144 | ) -> Option<bool> { |
146 | // this method is mostly for rustc | 145 | // this method is mostly for rustc |
@@ -151,6 +150,10 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
151 | // FIXME: implement actual object safety | 150 | // FIXME: implement actual object safety |
152 | true | 151 | true |
153 | } | 152 | } |
153 | |||
154 | fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId<Interner>) -> chalk_ir::Ty<Interner> { | ||
155 | Ty::Unknown.to_chalk(self.db) | ||
156 | } | ||
154 | } | 157 | } |
155 | 158 | ||
156 | pub(crate) fn program_clauses_for_chalk_env_query( | 159 | pub(crate) fn program_clauses_for_chalk_env_query( |
@@ -189,7 +192,7 @@ pub(crate) fn associated_ty_data_query( | |||
189 | .collect(); | 192 | .collect(); |
190 | 193 | ||
191 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); | 194 | let where_clauses = convert_where_clauses(db, type_alias.into(), &bound_vars); |
192 | let bound_data = chalk_rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; | 195 | let bound_data = rust_ir::AssociatedTyDatumBound { bounds, where_clauses }; |
193 | let datum = AssociatedTyDatum { | 196 | let datum = AssociatedTyDatum { |
194 | trait_id: trait_.to_chalk(db), | 197 | trait_id: trait_.to_chalk(db), |
195 | id, | 198 | id, |
@@ -210,7 +213,7 @@ pub(crate) fn trait_datum_query( | |||
210 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); | 213 | debug!("trait {:?} = {:?}", trait_id, trait_data.name); |
211 | let generic_params = generics(db.upcast(), trait_.into()); | 214 | let generic_params = generics(db.upcast(), trait_.into()); |
212 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 215 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); |
213 | let flags = chalk_rust_ir::TraitFlags { | 216 | let flags = rust_ir::TraitFlags { |
214 | auto: trait_data.auto, | 217 | auto: trait_data.auto, |
215 | upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, | 218 | upstream: trait_.lookup(db.upcast()).container.module(db.upcast()).krate != krate, |
216 | non_enumerable: true, | 219 | non_enumerable: true, |
@@ -222,7 +225,7 @@ pub(crate) fn trait_datum_query( | |||
222 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); | 225 | let where_clauses = convert_where_clauses(db, trait_.into(), &bound_vars); |
223 | let associated_ty_ids = | 226 | let associated_ty_ids = |
224 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); | 227 | trait_data.associated_types().map(|type_alias| type_alias.to_chalk(db)).collect(); |
225 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { where_clauses }; | 228 | let trait_datum_bound = rust_ir::TraitDatumBound { where_clauses }; |
226 | let well_known = | 229 | let well_known = |
227 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); | 230 | lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name)); |
228 | let trait_datum = TraitDatum { | 231 | let trait_datum = TraitDatum { |
@@ -272,12 +275,12 @@ pub(crate) fn struct_datum_query( | |||
272 | convert_where_clauses(db, generic_def, &bound_vars) | 275 | convert_where_clauses(db, generic_def, &bound_vars) |
273 | }) | 276 | }) |
274 | .unwrap_or_else(Vec::new); | 277 | .unwrap_or_else(Vec::new); |
275 | let flags = chalk_rust_ir::AdtFlags { | 278 | let flags = rust_ir::AdtFlags { |
276 | upstream, | 279 | upstream, |
277 | // FIXME set fundamental flag correctly | 280 | // FIXME set fundamental flag correctly |
278 | fundamental: false, | 281 | fundamental: false, |
279 | }; | 282 | }; |
280 | let struct_datum_bound = chalk_rust_ir::AdtDatumBound { | 283 | let struct_datum_bound = rust_ir::AdtDatumBound { |
281 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) | 284 | fields: Vec::new(), // FIXME add fields (only relevant for auto traits) |
282 | where_clauses, | 285 | where_clauses, |
283 | }; | 286 | }; |
@@ -317,9 +320,9 @@ fn impl_def_datum( | |||
317 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | 320 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); |
318 | let trait_ = trait_ref.trait_; | 321 | let trait_ = trait_ref.trait_; |
319 | let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { | 322 | let impl_type = if impl_id.lookup(db.upcast()).container.module(db.upcast()).krate == krate { |
320 | chalk_rust_ir::ImplType::Local | 323 | rust_ir::ImplType::Local |
321 | } else { | 324 | } else { |
322 | chalk_rust_ir::ImplType::External | 325 | rust_ir::ImplType::External |
323 | }; | 326 | }; |
324 | let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); | 327 | let where_clauses = convert_where_clauses(db, impl_id.into(), &bound_vars); |
325 | let negative = impl_data.is_negative; | 328 | let negative = impl_data.is_negative; |
@@ -332,13 +335,9 @@ fn impl_def_datum( | |||
332 | ); | 335 | ); |
333 | let trait_ref = trait_ref.to_chalk(db); | 336 | let trait_ref = trait_ref.to_chalk(db); |
334 | 337 | ||
335 | let polarity = if negative { | 338 | let polarity = if negative { rust_ir::Polarity::Negative } else { rust_ir::Polarity::Positive }; |
336 | chalk_rust_ir::Polarity::Negative | ||
337 | } else { | ||
338 | chalk_rust_ir::Polarity::Positive | ||
339 | }; | ||
340 | 339 | ||
341 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { trait_ref, where_clauses }; | 340 | let impl_datum_bound = rust_ir::ImplDatumBound { trait_ref, where_clauses }; |
342 | let trait_data = db.trait_data(trait_); | 341 | let trait_data = db.trait_data(trait_); |
343 | let associated_ty_value_ids = impl_data | 342 | let associated_ty_value_ids = impl_data |
344 | .items | 343 | .items |
@@ -396,8 +395,8 @@ fn type_alias_associated_ty_value( | |||
396 | .associated_type_by_name(&type_alias_data.name) | 395 | .associated_type_by_name(&type_alias_data.name) |
397 | .expect("assoc ty value should not exist"); // validated when building the impl data as well | 396 | .expect("assoc ty value should not exist"); // validated when building the impl data as well |
398 | let ty = db.ty(type_alias.into()); | 397 | let ty = db.ty(type_alias.into()); |
399 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; | 398 | let value_bound = rust_ir::AssociatedTyValueBound { ty: ty.value.to_chalk(db) }; |
400 | let value = chalk_rust_ir::AssociatedTyValue { | 399 | let value = rust_ir::AssociatedTyValue { |
401 | impl_id: Impl::ImplDef(impl_id).to_chalk(db), | 400 | impl_id: Impl::ImplDef(impl_id).to_chalk(db), |
402 | associated_ty_id: assoc_ty.to_chalk(db), | 401 | associated_ty_id: assoc_ty.to_chalk(db), |
403 | value: make_binders(value_bound, ty.num_binders), | 402 | value: make_binders(value_bound, ty.num_binders), |
@@ -405,6 +404,26 @@ fn type_alias_associated_ty_value( | |||
405 | Arc::new(value) | 404 | Arc::new(value) |
406 | } | 405 | } |
407 | 406 | ||
407 | pub(crate) fn fn_def_datum_query( | ||
408 | db: &dyn HirDatabase, | ||
409 | _krate: CrateId, | ||
410 | fn_def_id: FnDefId, | ||
411 | ) -> Arc<FnDefDatum> { | ||
412 | let callable_def: CallableDef = from_chalk(db, fn_def_id); | ||
413 | let generic_params = generics(db.upcast(), callable_def.into()); | ||
414 | let sig = db.callable_item_signature(callable_def); | ||
415 | let bound_vars = Substs::bound_vars(&generic_params, DebruijnIndex::INNERMOST); | ||
416 | let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars); | ||
417 | let bound = rust_ir::FnDefDatumBound { | ||
418 | // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway | ||
419 | argument_types: sig.value.params().iter().map(|ty| ty.clone().to_chalk(db)).collect(), | ||
420 | return_type: sig.value.ret().clone().to_chalk(db), | ||
421 | where_clauses, | ||
422 | }; | ||
423 | let datum = FnDefDatum { id: fn_def_id, binders: make_binders(bound, sig.num_binders) }; | ||
424 | Arc::new(datum) | ||
425 | } | ||
426 | |||
408 | impl From<AdtId> for crate::TypeCtorId { | 427 | impl From<AdtId> for crate::TypeCtorId { |
409 | fn from(struct_id: AdtId) -> Self { | 428 | fn from(struct_id: AdtId) -> Self { |
410 | struct_id.0 | 429 | struct_id.0 |
@@ -417,6 +436,18 @@ impl From<crate::TypeCtorId> for AdtId { | |||
417 | } | 436 | } |
418 | } | 437 | } |
419 | 438 | ||
439 | impl From<FnDefId> for crate::CallableDefId { | ||
440 | fn from(fn_def_id: FnDefId) -> Self { | ||
441 | InternKey::from_intern_id(fn_def_id.0) | ||
442 | } | ||
443 | } | ||
444 | |||
445 | impl From<crate::CallableDefId> for FnDefId { | ||
446 | fn from(callable_def_id: crate::CallableDefId) -> Self { | ||
447 | chalk_ir::FnDefId(callable_def_id.as_intern_id()) | ||
448 | } | ||
449 | } | ||
450 | |||
420 | impl From<ImplId> for crate::traits::GlobalImplId { | 451 | impl From<ImplId> for crate::traits::GlobalImplId { |
421 | fn from(impl_id: ImplId) -> Self { | 452 | fn from(impl_id: ImplId) -> Self { |
422 | InternKey::from_intern_id(impl_id.0) | 453 | InternKey::from_intern_id(impl_id.0) |
@@ -429,14 +460,14 @@ impl From<crate::traits::GlobalImplId> for ImplId { | |||
429 | } | 460 | } |
430 | } | 461 | } |
431 | 462 | ||
432 | impl From<chalk_rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { | 463 | impl From<rust_ir::AssociatedTyValueId<Interner>> for crate::traits::AssocTyValueId { |
433 | fn from(id: chalk_rust_ir::AssociatedTyValueId<Interner>) -> Self { | 464 | fn from(id: rust_ir::AssociatedTyValueId<Interner>) -> Self { |
434 | Self::from_intern_id(id.0) | 465 | Self::from_intern_id(id.0) |
435 | } | 466 | } |
436 | } | 467 | } |
437 | 468 | ||
438 | impl From<crate::traits::AssocTyValueId> for chalk_rust_ir::AssociatedTyValueId<Interner> { | 469 | impl From<crate::traits::AssocTyValueId> for rust_ir::AssociatedTyValueId<Interner> { |
439 | fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { | 470 | fn from(assoc_ty_value_id: crate::traits::AssocTyValueId) -> Self { |
440 | chalk_rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) | 471 | rust_ir::AssociatedTyValueId(assoc_ty_value_id.as_intern_id()) |
441 | } | 472 | } |
442 | } | 473 | } |
diff --git a/crates/ra_hir_ty/src/traits/chalk/interner.rs b/crates/ra_hir_ty/src/traits/chalk/interner.rs index 060372819..e27074ba6 100644 --- a/crates/ra_hir_ty/src/traits/chalk/interner.rs +++ b/crates/ra_hir_ty/src/traits/chalk/interner.rs | |||
@@ -11,15 +11,17 @@ use std::{fmt, sync::Arc}; | |||
11 | pub struct Interner; | 11 | pub struct Interner; |
12 | 12 | ||
13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; | 13 | pub type AssocTypeId = chalk_ir::AssocTypeId<Interner>; |
14 | pub type AssociatedTyDatum = chalk_rust_ir::AssociatedTyDatum<Interner>; | 14 | pub type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>; |
15 | pub type TraitId = chalk_ir::TraitId<Interner>; | 15 | pub type TraitId = chalk_ir::TraitId<Interner>; |
16 | pub type TraitDatum = chalk_rust_ir::TraitDatum<Interner>; | 16 | pub type TraitDatum = chalk_solve::rust_ir::TraitDatum<Interner>; |
17 | pub type AdtId = chalk_ir::AdtId<Interner>; | 17 | pub type AdtId = chalk_ir::AdtId<Interner>; |
18 | pub type StructDatum = chalk_rust_ir::AdtDatum<Interner>; | 18 | pub type StructDatum = chalk_solve::rust_ir::AdtDatum<Interner>; |
19 | pub type ImplId = chalk_ir::ImplId<Interner>; | 19 | pub type ImplId = chalk_ir::ImplId<Interner>; |
20 | pub type ImplDatum = chalk_rust_ir::ImplDatum<Interner>; | 20 | pub type ImplDatum = chalk_solve::rust_ir::ImplDatum<Interner>; |
21 | pub type AssociatedTyValueId = chalk_rust_ir::AssociatedTyValueId<Interner>; | 21 | pub type AssociatedTyValueId = chalk_solve::rust_ir::AssociatedTyValueId<Interner>; |
22 | pub type AssociatedTyValue = chalk_rust_ir::AssociatedTyValue<Interner>; | 22 | pub type AssociatedTyValue = chalk_solve::rust_ir::AssociatedTyValue<Interner>; |
23 | pub type FnDefId = chalk_ir::FnDefId<Interner>; | ||
24 | pub type FnDefDatum = chalk_solve::rust_ir::FnDefDatum<Interner>; | ||
23 | 25 | ||
24 | impl chalk_ir::interner::Interner for Interner { | 26 | impl chalk_ir::interner::Interner for Interner { |
25 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? | 27 | type InternedType = Box<chalk_ir::TyData<Self>>; // FIXME use Arc? |
diff --git a/crates/ra_hir_ty/src/traits/chalk/mapping.rs b/crates/ra_hir_ty/src/traits/chalk/mapping.rs index a83d82fd8..5f6daf842 100644 --- a/crates/ra_hir_ty/src/traits/chalk/mapping.rs +++ b/crates/ra_hir_ty/src/traits/chalk/mapping.rs | |||
@@ -7,6 +7,7 @@ use chalk_ir::{ | |||
7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, | 7 | cast::Cast, fold::shift::Shift, interner::HasInterner, PlaceholderIndex, Scalar, TypeName, |
8 | UniverseIndex, | 8 | UniverseIndex, |
9 | }; | 9 | }; |
10 | use chalk_solve::rust_ir; | ||
10 | 11 | ||
11 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; | 12 | use hir_def::{type_ref::Mutability, AssocContainerId, GenericDefId, Lookup, TypeAliasId}; |
12 | use ra_db::salsa::InternKey; | 13 | use ra_db::salsa::InternKey; |
@@ -15,8 +16,8 @@ use crate::{ | |||
15 | db::HirDatabase, | 16 | db::HirDatabase, |
16 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, | 17 | primitive::{FloatBitness, FloatTy, IntBitness, IntTy, Signedness, Uncertain}, |
17 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, | 18 | traits::{builtin, AssocTyValue, Canonical, Impl, Obligation}, |
18 | ApplicationTy, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, Substs, | 19 | ApplicationTy, CallableDef, GenericPredicate, InEnvironment, ProjectionPredicate, ProjectionTy, |
19 | TraitEnvironment, TraitRef, Ty, TypeCtor, | 20 | Substs, TraitEnvironment, TraitRef, Ty, TypeCtor, |
20 | }; | 21 | }; |
21 | 22 | ||
22 | use super::interner::*; | 23 | use super::interner::*; |
@@ -26,14 +27,19 @@ impl ToChalk for Ty { | |||
26 | type Chalk = chalk_ir::Ty<Interner>; | 27 | type Chalk = chalk_ir::Ty<Interner>; |
27 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { | 28 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> { |
28 | match self { | 29 | match self { |
29 | Ty::Apply(apply_ty) => { | 30 | Ty::Apply(apply_ty) => match apply_ty.ctor { |
30 | if let TypeCtor::Ref(m) = apply_ty.ctor { | 31 | TypeCtor::Ref(m) => ref_to_chalk(db, m, apply_ty.parameters), |
31 | return ref_to_chalk(db, m, apply_ty.parameters); | 32 | TypeCtor::FnPtr { num_args: _ } => { |
33 | let substitution = apply_ty.parameters.to_chalk(db).shifted_in(&Interner); | ||
34 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: 0, substitution }) | ||
35 | .intern(&Interner) | ||
32 | } | 36 | } |
33 | let name = apply_ty.ctor.to_chalk(db); | 37 | _ => { |
34 | let substitution = apply_ty.parameters.to_chalk(db); | 38 | let name = apply_ty.ctor.to_chalk(db); |
35 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) | 39 | let substitution = apply_ty.parameters.to_chalk(db); |
36 | } | 40 | chalk_ir::ApplicationTy { name, substitution }.cast(&Interner).intern(&Interner) |
41 | } | ||
42 | }, | ||
37 | Ty::Projection(proj_ty) => { | 43 | Ty::Projection(proj_ty) => { |
38 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); | 44 | let associated_ty_id = proj_ty.associated_ty.to_chalk(db); |
39 | let substitution = proj_ty.parameters.to_chalk(db); | 45 | let substitution = proj_ty.parameters.to_chalk(db); |
@@ -93,9 +99,15 @@ impl ToChalk for Ty { | |||
93 | Ty::Projection(ProjectionTy { associated_ty, parameters }) | 99 | Ty::Projection(ProjectionTy { associated_ty, parameters }) |
94 | } | 100 | } |
95 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), | 101 | chalk_ir::TyData::Alias(chalk_ir::AliasTy::Opaque(_)) => unimplemented!(), |
96 | chalk_ir::TyData::Function(_) => unimplemented!(), | 102 | chalk_ir::TyData::Function(chalk_ir::Fn { num_binders: _, substitution }) => { |
103 | let parameters: Substs = from_chalk(db, substitution); | ||
104 | Ty::Apply(ApplicationTy { | ||
105 | ctor: TypeCtor::FnPtr { num_args: (parameters.len() - 1) as u16 }, | ||
106 | parameters, | ||
107 | }) | ||
108 | } | ||
97 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), | 109 | chalk_ir::TyData::BoundVar(idx) => Ty::Bound(idx), |
98 | chalk_ir::TyData::InferenceVar(_iv) => Ty::Unknown, | 110 | chalk_ir::TyData::InferenceVar(_iv, _kind) => Ty::Unknown, |
99 | chalk_ir::TyData::Dyn(where_clauses) => { | 111 | chalk_ir::TyData::Dyn(where_clauses) => { |
100 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); | 112 | assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); |
101 | let predicates = where_clauses | 113 | let predicates = where_clauses |
@@ -217,13 +229,17 @@ impl ToChalk for TypeCtor { | |||
217 | TypeCtor::Slice => TypeName::Slice, | 229 | TypeCtor::Slice => TypeName::Slice, |
218 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), | 230 | TypeCtor::Ref(mutability) => TypeName::Ref(mutability.to_chalk(db)), |
219 | TypeCtor::Str => TypeName::Str, | 231 | TypeCtor::Str => TypeName::Str, |
232 | TypeCtor::FnDef(callable_def) => { | ||
233 | let id = callable_def.to_chalk(db); | ||
234 | TypeName::FnDef(id) | ||
235 | } | ||
236 | TypeCtor::Never => TypeName::Never, | ||
237 | |||
220 | TypeCtor::Int(Uncertain::Unknown) | 238 | TypeCtor::Int(Uncertain::Unknown) |
221 | | TypeCtor::Float(Uncertain::Unknown) | 239 | | TypeCtor::Float(Uncertain::Unknown) |
222 | | TypeCtor::Adt(_) | 240 | | TypeCtor::Adt(_) |
223 | | TypeCtor::Array | 241 | | TypeCtor::Array |
224 | | TypeCtor::FnDef(_) | ||
225 | | TypeCtor::FnPtr { .. } | 242 | | TypeCtor::FnPtr { .. } |
226 | | TypeCtor::Never | ||
227 | | TypeCtor::Closure { .. } => { | 243 | | TypeCtor::Closure { .. } => { |
228 | // other TypeCtors get interned and turned into a chalk StructId | 244 | // other TypeCtors get interned and turned into a chalk StructId |
229 | let struct_id = db.intern_type_ctor(self).into(); | 245 | let struct_id = db.intern_type_ctor(self).into(); |
@@ -259,10 +275,14 @@ impl ToChalk for TypeCtor { | |||
259 | TypeName::Slice => TypeCtor::Slice, | 275 | TypeName::Slice => TypeCtor::Slice, |
260 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), | 276 | TypeName::Ref(mutability) => TypeCtor::Ref(from_chalk(db, mutability)), |
261 | TypeName::Str => TypeCtor::Str, | 277 | TypeName::Str => TypeCtor::Str, |
278 | TypeName::Never => TypeCtor::Never, | ||
262 | 279 | ||
263 | TypeName::FnDef(_) => unreachable!(), | 280 | TypeName::FnDef(fn_def_id) => { |
281 | let callable_def = from_chalk(db, fn_def_id); | ||
282 | TypeCtor::FnDef(callable_def) | ||
283 | } | ||
264 | 284 | ||
265 | TypeName::Error => { | 285 | TypeName::Array | TypeName::Error => { |
266 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor | 286 | // this should not be reached, since we don't represent TypeName::Error with TypeCtor |
267 | unreachable!() | 287 | unreachable!() |
268 | } | 288 | } |
@@ -347,6 +367,18 @@ impl ToChalk for Impl { | |||
347 | } | 367 | } |
348 | } | 368 | } |
349 | 369 | ||
370 | impl ToChalk for CallableDef { | ||
371 | type Chalk = FnDefId; | ||
372 | |||
373 | fn to_chalk(self, db: &dyn HirDatabase) -> FnDefId { | ||
374 | db.intern_callable_def(self).into() | ||
375 | } | ||
376 | |||
377 | fn from_chalk(db: &dyn HirDatabase, fn_def_id: FnDefId) -> CallableDef { | ||
378 | db.lookup_intern_callable_def(fn_def_id.into()) | ||
379 | } | ||
380 | } | ||
381 | |||
350 | impl ToChalk for TypeAliasId { | 382 | impl ToChalk for TypeAliasId { |
351 | type Chalk = AssocTypeId; | 383 | type Chalk = AssocTypeId; |
352 | 384 | ||
@@ -479,7 +511,7 @@ where | |||
479 | 511 | ||
480 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { | 512 | fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { |
481 | let parameter = chalk_ir::CanonicalVarKind::new( | 513 | let parameter = chalk_ir::CanonicalVarKind::new( |
482 | chalk_ir::VariableKind::Ty, | 514 | chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), |
483 | chalk_ir::UniverseIndex::ROOT, | 515 | chalk_ir::UniverseIndex::ROOT, |
484 | ); | 516 | ); |
485 | let value = self.value.to_chalk(db); | 517 | let value = self.value.to_chalk(db); |
@@ -550,17 +582,17 @@ impl ToChalk for builtin::BuiltinImplData { | |||
550 | type Chalk = ImplDatum; | 582 | type Chalk = ImplDatum; |
551 | 583 | ||
552 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { | 584 | fn to_chalk(self, db: &dyn HirDatabase) -> ImplDatum { |
553 | let impl_type = chalk_rust_ir::ImplType::External; | 585 | let impl_type = rust_ir::ImplType::External; |
554 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); | 586 | let where_clauses = self.where_clauses.into_iter().map(|w| w.to_chalk(db)).collect(); |
555 | 587 | ||
556 | let impl_datum_bound = | 588 | let impl_datum_bound = |
557 | chalk_rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; | 589 | rust_ir::ImplDatumBound { trait_ref: self.trait_ref.to_chalk(db), where_clauses }; |
558 | let associated_ty_value_ids = | 590 | let associated_ty_value_ids = |
559 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); | 591 | self.assoc_ty_values.into_iter().map(|v| v.to_chalk(db)).collect(); |
560 | chalk_rust_ir::ImplDatum { | 592 | rust_ir::ImplDatum { |
561 | binders: make_binders(impl_datum_bound, self.num_vars), | 593 | binders: make_binders(impl_datum_bound, self.num_vars), |
562 | impl_type, | 594 | impl_type, |
563 | polarity: chalk_rust_ir::Polarity::Positive, | 595 | polarity: rust_ir::Polarity::Positive, |
564 | associated_ty_value_ids, | 596 | associated_ty_value_ids, |
565 | } | 597 | } |
566 | } | 598 | } |
@@ -575,9 +607,9 @@ impl ToChalk for builtin::BuiltinImplAssocTyValueData { | |||
575 | 607 | ||
576 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { | 608 | fn to_chalk(self, db: &dyn HirDatabase) -> AssociatedTyValue { |
577 | let ty = self.value.to_chalk(db); | 609 | let ty = self.value.to_chalk(db); |
578 | let value_bound = chalk_rust_ir::AssociatedTyValueBound { ty }; | 610 | let value_bound = rust_ir::AssociatedTyValueBound { ty }; |
579 | 611 | ||
580 | chalk_rust_ir::AssociatedTyValue { | 612 | rust_ir::AssociatedTyValue { |
581 | associated_ty_id: self.assoc_ty_id.to_chalk(db), | 613 | associated_ty_id: self.assoc_ty_id.to_chalk(db), |
582 | impl_id: self.impl_.to_chalk(db), | 614 | impl_id: self.impl_.to_chalk(db), |
583 | value: make_binders(value_bound, self.num_vars), | 615 | value: make_binders(value_bound, self.num_vars), |
@@ -599,7 +631,7 @@ where | |||
599 | chalk_ir::Binders::new( | 631 | chalk_ir::Binders::new( |
600 | chalk_ir::VariableKinds::from( | 632 | chalk_ir::VariableKinds::from( |
601 | &Interner, | 633 | &Interner, |
602 | std::iter::repeat(chalk_ir::VariableKind::Ty).take(num_vars), | 634 | std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General)).take(num_vars), |
603 | ), | 635 | ), |
604 | value, | 636 | value, |
605 | ) | 637 | ) |
@@ -626,7 +658,7 @@ pub(super) fn generic_predicate_to_inline_bound( | |||
626 | db: &dyn HirDatabase, | 658 | db: &dyn HirDatabase, |
627 | pred: &GenericPredicate, | 659 | pred: &GenericPredicate, |
628 | self_ty: &Ty, | 660 | self_ty: &Ty, |
629 | ) -> Option<chalk_rust_ir::InlineBound<Interner>> { | 661 | ) -> Option<rust_ir::InlineBound<Interner>> { |
630 | // An InlineBound is like a GenericPredicate, except the self type is left out. | 662 | // An InlineBound is like a GenericPredicate, except the self type is left out. |
631 | // We don't have a special type for this, but Chalk does. | 663 | // We don't have a special type for this, but Chalk does. |
632 | match pred { | 664 | match pred { |
@@ -641,8 +673,8 @@ pub(super) fn generic_predicate_to_inline_bound( | |||
641 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | 673 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) |
642 | .collect(); | 674 | .collect(); |
643 | let trait_bound = | 675 | let trait_bound = |
644 | chalk_rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; | 676 | rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; |
645 | Some(chalk_rust_ir::InlineBound::TraitBound(trait_bound)) | 677 | Some(rust_ir::InlineBound::TraitBound(trait_bound)) |
646 | } | 678 | } |
647 | GenericPredicate::Projection(proj) => { | 679 | GenericPredicate::Projection(proj) => { |
648 | if &proj.projection_ty.parameters[0] != self_ty { | 680 | if &proj.projection_ty.parameters[0] != self_ty { |
@@ -656,16 +688,13 @@ pub(super) fn generic_predicate_to_inline_bound( | |||
656 | .iter() | 688 | .iter() |
657 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) | 689 | .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) |
658 | .collect(); | 690 | .collect(); |
659 | let alias_eq_bound = chalk_rust_ir::AliasEqBound { | 691 | let alias_eq_bound = rust_ir::AliasEqBound { |
660 | value: proj.ty.clone().to_chalk(db), | 692 | value: proj.ty.clone().to_chalk(db), |
661 | trait_bound: chalk_rust_ir::TraitBound { | 693 | trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, |
662 | trait_id: trait_.to_chalk(db), | ||
663 | args_no_self, | ||
664 | }, | ||
665 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), | 694 | associated_ty_id: proj.projection_ty.associated_ty.to_chalk(db), |
666 | parameters: Vec::new(), // FIXME we don't support generic associated types yet | 695 | parameters: Vec::new(), // FIXME we don't support generic associated types yet |
667 | }; | 696 | }; |
668 | Some(chalk_rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) | 697 | Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) |
669 | } | 698 | } |
670 | GenericPredicate::Error => None, | 699 | GenericPredicate::Error => None, |
671 | } | 700 | } |
diff --git a/crates/ra_hir_ty/src/traits/chalk/tls.rs b/crates/ra_hir_ty/src/traits/chalk/tls.rs index ebf402a07..d88828c7c 100644 --- a/crates/ra_hir_ty/src/traits/chalk/tls.rs +++ b/crates/ra_hir_ty/src/traits/chalk/tls.rs | |||
@@ -247,10 +247,24 @@ impl DebugContext<'_> { | |||
247 | 247 | ||
248 | pub fn debug_fn_def_id( | 248 | pub fn debug_fn_def_id( |
249 | &self, | 249 | &self, |
250 | _fn_def_id: chalk_ir::FnDefId<Interner>, | 250 | fn_def_id: chalk_ir::FnDefId<Interner>, |
251 | fmt: &mut fmt::Formatter<'_>, | 251 | fmt: &mut fmt::Formatter<'_>, |
252 | ) -> Result<(), fmt::Error> { | 252 | ) -> Result<(), fmt::Error> { |
253 | write!(fmt, "fn") | 253 | let def: CallableDef = from_chalk(self.0, fn_def_id); |
254 | let name = match def { | ||
255 | CallableDef::FunctionId(ff) => self.0.function_data(ff).name.clone(), | ||
256 | CallableDef::StructId(s) => self.0.struct_data(s).name.clone(), | ||
257 | CallableDef::EnumVariantId(e) => { | ||
258 | let enum_data = self.0.enum_data(e.parent); | ||
259 | enum_data.variants[e.local_id].name.clone() | ||
260 | } | ||
261 | }; | ||
262 | match def { | ||
263 | CallableDef::FunctionId(_) => write!(fmt, "{{fn {}}}", name), | ||
264 | CallableDef::StructId(_) | CallableDef::EnumVariantId(_) => { | ||
265 | write!(fmt, "{{ctor {}}}", name) | ||
266 | } | ||
267 | } | ||
254 | } | 268 | } |
255 | 269 | ||
256 | pub fn debug_const( | 270 | pub fn debug_const( |
diff --git a/crates/ra_ide/src/call_hierarchy.rs b/crates/ra_ide/src/call_hierarchy.rs index 85d1f0cb1..defd8176f 100644 --- a/crates/ra_ide/src/call_hierarchy.rs +++ b/crates/ra_ide/src/call_hierarchy.rs | |||
@@ -246,6 +246,35 @@ mod tests { | |||
246 | } | 246 | } |
247 | 247 | ||
248 | #[test] | 248 | #[test] |
249 | fn test_call_hierarchy_in_tests_mod() { | ||
250 | check_hierarchy( | ||
251 | r#" | ||
252 | //- /lib.rs cfg:test | ||
253 | fn callee() {} | ||
254 | fn caller1() { | ||
255 | call<|>ee(); | ||
256 | } | ||
257 | |||
258 | #[cfg(test)] | ||
259 | mod tests { | ||
260 | use super::*; | ||
261 | |||
262 | #[test] | ||
263 | fn test_caller() { | ||
264 | callee(); | ||
265 | } | ||
266 | } | ||
267 | "#, | ||
268 | "callee FN_DEF FileId(1) 0..14 3..9", | ||
269 | &[ | ||
270 | "caller1 FN_DEF FileId(1) 15..45 18..25 : [34..40]", | ||
271 | "test_caller FN_DEF FileId(1) 93..147 108..119 : [132..138]", | ||
272 | ], | ||
273 | &[], | ||
274 | ); | ||
275 | } | ||
276 | |||
277 | #[test] | ||
249 | fn test_call_hierarchy_in_different_files() { | 278 | fn test_call_hierarchy_in_different_files() { |
250 | check_hierarchy( | 279 | check_hierarchy( |
251 | r#" | 280 | r#" |
diff --git a/crates/ra_ide/src/completion.rs b/crates/ra_ide/src/completion.rs index 191300704..a721e23c6 100644 --- a/crates/ra_ide/src/completion.rs +++ b/crates/ra_ide/src/completion.rs | |||
@@ -1,5 +1,3 @@ | |||
1 | //! FIXME: write short doc here | ||
2 | |||
3 | mod completion_config; | 1 | mod completion_config; |
4 | mod completion_item; | 2 | mod completion_item; |
5 | mod completion_context; | 3 | mod completion_context; |
@@ -35,6 +33,51 @@ pub use crate::completion::{ | |||
35 | completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat}, | 33 | completion_item::{CompletionItem, CompletionItemKind, CompletionScore, InsertTextFormat}, |
36 | }; | 34 | }; |
37 | 35 | ||
36 | //FIXME: split the following feature into fine-grained features. | ||
37 | |||
38 | // Feature: Magic Completions | ||
39 | // | ||
40 | // In addition to usual reference completion, rust-analyzer provides some ✨magic✨ | ||
41 | // completions as well: | ||
42 | // | ||
43 | // Keywords like `if`, `else` `while`, `loop` are completed with braces, and cursor | ||
44 | // is placed at the appropriate position. Even though `if` is easy to type, you | ||
45 | // still want to complete it, to get ` { }` for free! `return` is inserted with a | ||
46 | // space or `;` depending on the return type of the function. | ||
47 | // | ||
48 | // When completing a function call, `()` are automatically inserted. If a function | ||
49 | // takes arguments, the cursor is positioned inside the parenthesis. | ||
50 | // | ||
51 | // There are postfix completions, which can be triggered by typing something like | ||
52 | // `foo().if`. The word after `.` determines postfix completion. Possible variants are: | ||
53 | // | ||
54 | // - `expr.if` -> `if expr {}` or `if let ... {}` for `Option` or `Result` | ||
55 | // - `expr.match` -> `match expr {}` | ||
56 | // - `expr.while` -> `while expr {}` or `while let ... {}` for `Option` or `Result` | ||
57 | // - `expr.ref` -> `&expr` | ||
58 | // - `expr.refm` -> `&mut expr` | ||
59 | // - `expr.not` -> `!expr` | ||
60 | // - `expr.dbg` -> `dbg!(expr)` | ||
61 | // | ||
62 | // There also snippet completions: | ||
63 | // | ||
64 | // .Expressions | ||
65 | // - `pd` -> `println!("{:?}")` | ||
66 | // - `ppd` -> `println!("{:#?}")` | ||
67 | // | ||
68 | // .Items | ||
69 | // - `tfn` -> `#[test] fn f(){}` | ||
70 | // - `tmod` -> | ||
71 | // ```rust | ||
72 | // #[cfg(test)] | ||
73 | // mod tests { | ||
74 | // use super::*; | ||
75 | // | ||
76 | // #[test] | ||
77 | // fn test_fn() {} | ||
78 | // } | ||
79 | // ``` | ||
80 | |||
38 | /// Main entry point for completion. We run completion as a two-phase process. | 81 | /// Main entry point for completion. We run completion as a two-phase process. |
39 | /// | 82 | /// |
40 | /// First, we look at the position and collect a so-called `CompletionContext. | 83 | /// First, we look at the position and collect a so-called `CompletionContext. |
@@ -82,3 +125,81 @@ pub(crate) fn completions( | |||
82 | 125 | ||
83 | Some(acc) | 126 | Some(acc) |
84 | } | 127 | } |
128 | |||
129 | #[cfg(test)] | ||
130 | mod tests { | ||
131 | use crate::completion::completion_config::CompletionConfig; | ||
132 | use crate::mock_analysis::analysis_and_position; | ||
133 | |||
134 | struct DetailAndDocumentation<'a> { | ||
135 | detail: &'a str, | ||
136 | documentation: &'a str, | ||
137 | } | ||
138 | |||
139 | fn check_detail_and_documentation(fixture: &str, expected: DetailAndDocumentation) { | ||
140 | let (analysis, position) = analysis_and_position(fixture); | ||
141 | let config = CompletionConfig::default(); | ||
142 | let completions = analysis.completions(&config, position).unwrap().unwrap(); | ||
143 | for item in completions { | ||
144 | if item.detail() == Some(expected.detail) { | ||
145 | let opt = item.documentation(); | ||
146 | let doc = opt.as_ref().map(|it| it.as_str()); | ||
147 | assert_eq!(doc, Some(expected.documentation)); | ||
148 | return; | ||
149 | } | ||
150 | } | ||
151 | panic!("completion detail not found: {}", expected.detail) | ||
152 | } | ||
153 | |||
154 | #[test] | ||
155 | fn test_completion_detail_from_macro_generated_struct_fn_doc_attr() { | ||
156 | check_detail_and_documentation( | ||
157 | r#" | ||
158 | //- /lib.rs | ||
159 | macro_rules! bar { | ||
160 | () => { | ||
161 | struct Bar; | ||
162 | impl Bar { | ||
163 | #[doc = "Do the foo"] | ||
164 | fn foo(&self) {} | ||
165 | } | ||
166 | } | ||
167 | } | ||
168 | |||
169 | bar!(); | ||
170 | |||
171 | fn foo() { | ||
172 | let bar = Bar; | ||
173 | bar.fo<|>; | ||
174 | } | ||
175 | "#, | ||
176 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: "Do the foo" }, | ||
177 | ); | ||
178 | } | ||
179 | |||
180 | #[test] | ||
181 | fn test_completion_detail_from_macro_generated_struct_fn_doc_comment() { | ||
182 | check_detail_and_documentation( | ||
183 | r#" | ||
184 | //- /lib.rs | ||
185 | macro_rules! bar { | ||
186 | () => { | ||
187 | struct Bar; | ||
188 | impl Bar { | ||
189 | /// Do the foo | ||
190 | fn foo(&self) {} | ||
191 | } | ||
192 | } | ||
193 | } | ||
194 | |||
195 | bar!(); | ||
196 | |||
197 | fn foo() { | ||
198 | let bar = Bar; | ||
199 | bar.fo<|>; | ||
200 | } | ||
201 | "#, | ||
202 | DetailAndDocumentation { detail: "fn foo(&self)", documentation: " Do the foo" }, | ||
203 | ); | ||
204 | } | ||
205 | } | ||
diff --git a/crates/ra_ide/src/completion/complete_attribute.rs b/crates/ra_ide/src/completion/complete_attribute.rs index f17266221..fb3f0b743 100644 --- a/crates/ra_ide/src/completion/complete_attribute.rs +++ b/crates/ra_ide/src/completion/complete_attribute.rs | |||
@@ -112,7 +112,7 @@ const ATTRIBUTES: &[AttrCompletion] = &[ | |||
112 | AttrCompletion { label: "repr", snippet: Some("repr(${0:C})"), should_be_inner: false }, | 112 | AttrCompletion { label: "repr", snippet: Some("repr(${0:C})"), should_be_inner: false }, |
113 | AttrCompletion { | 113 | AttrCompletion { |
114 | label: "should_panic", | 114 | label: "should_panic", |
115 | snippet: Some(r#"expected = "${0:reason}""#), | 115 | snippet: Some(r#"should_panic(expected = "${0:reason}")"#), |
116 | should_be_inner: false, | 116 | should_be_inner: false, |
117 | }, | 117 | }, |
118 | AttrCompletion { | 118 | AttrCompletion { |
@@ -571,7 +571,7 @@ mod tests { | |||
571 | label: "should_panic", | 571 | label: "should_panic", |
572 | source_range: 19..19, | 572 | source_range: 19..19, |
573 | delete: 19..19, | 573 | delete: 19..19, |
574 | insert: "expected = \"${0:reason}\"", | 574 | insert: "should_panic(expected = \"${0:reason}\")", |
575 | kind: Attribute, | 575 | kind: Attribute, |
576 | }, | 576 | }, |
577 | CompletionItem { | 577 | CompletionItem { |
@@ -810,7 +810,7 @@ mod tests { | |||
810 | label: "should_panic", | 810 | label: "should_panic", |
811 | source_range: 20..20, | 811 | source_range: 20..20, |
812 | delete: 20..20, | 812 | delete: 20..20, |
813 | insert: "expected = \"${0:reason}\"", | 813 | insert: "should_panic(expected = \"${0:reason}\")", |
814 | kind: Attribute, | 814 | kind: Attribute, |
815 | }, | 815 | }, |
816 | CompletionItem { | 816 | CompletionItem { |
diff --git a/crates/ra_ide/src/completion/complete_postfix.rs b/crates/ra_ide/src/completion/complete_postfix.rs index f2a52a407..59b58bf98 100644 --- a/crates/ra_ide/src/completion/complete_postfix.rs +++ b/crates/ra_ide/src/completion/complete_postfix.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | use ra_assists::utils::TryEnum; | |
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, AstNode}, | 4 | ast::{self, AstNode}, |
5 | TextRange, TextSize, | 5 | TextRange, TextSize, |
6 | }; | 6 | }; |
7 | use ra_text_edit::TextEdit; | 7 | use ra_text_edit::TextEdit; |
8 | 8 | ||
9 | use super::completion_config::SnippetCap; | ||
10 | use crate::{ | 9 | use crate::{ |
11 | completion::{ | 10 | completion::{ |
12 | completion_context::CompletionContext, | 11 | completion_context::CompletionContext, |
@@ -14,7 +13,8 @@ use crate::{ | |||
14 | }, | 13 | }, |
15 | CompletionItem, | 14 | CompletionItem, |
16 | }; | 15 | }; |
17 | use ra_assists::utils::TryEnum; | 16 | |
17 | use super::completion_config::SnippetCap; | ||
18 | 18 | ||
19 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | 19 | pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { |
20 | if !ctx.config.enable_postfix_completions { | 20 | if !ctx.config.enable_postfix_completions { |
@@ -184,6 +184,16 @@ pub(super) fn complete_postfix(acc: &mut Completions, ctx: &CompletionContext) { | |||
184 | &format!("dbg!({})", receiver_text), | 184 | &format!("dbg!({})", receiver_text), |
185 | ) | 185 | ) |
186 | .add_to(acc); | 186 | .add_to(acc); |
187 | |||
188 | postfix_snippet( | ||
189 | ctx, | ||
190 | cap, | ||
191 | &dot_receiver, | ||
192 | "call", | ||
193 | "function(expr)", | ||
194 | &format!("${{1}}({})", receiver_text), | ||
195 | ) | ||
196 | .add_to(acc); | ||
187 | } | 197 | } |
188 | 198 | ||
189 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { | 199 | fn get_receiver_text(receiver: &ast::Expr, receiver_is_ambiguous_float_literal: bool) -> String { |
@@ -256,6 +266,13 @@ mod tests { | |||
256 | detail: "Box::new(expr)", | 266 | detail: "Box::new(expr)", |
257 | }, | 267 | }, |
258 | CompletionItem { | 268 | CompletionItem { |
269 | label: "call", | ||
270 | source_range: 89..89, | ||
271 | delete: 85..89, | ||
272 | insert: "${1}(bar)", | ||
273 | detail: "function(expr)", | ||
274 | }, | ||
275 | CompletionItem { | ||
259 | label: "dbg", | 276 | label: "dbg", |
260 | source_range: 89..89, | 277 | source_range: 89..89, |
261 | delete: 85..89, | 278 | delete: 85..89, |
@@ -335,6 +352,13 @@ mod tests { | |||
335 | detail: "Box::new(expr)", | 352 | detail: "Box::new(expr)", |
336 | }, | 353 | }, |
337 | CompletionItem { | 354 | CompletionItem { |
355 | label: "call", | ||
356 | source_range: 210..210, | ||
357 | delete: 206..210, | ||
358 | insert: "${1}(bar)", | ||
359 | detail: "function(expr)", | ||
360 | }, | ||
361 | CompletionItem { | ||
338 | label: "dbg", | 362 | label: "dbg", |
339 | source_range: 210..210, | 363 | source_range: 210..210, |
340 | delete: 206..210, | 364 | delete: 206..210, |
@@ -414,6 +438,13 @@ mod tests { | |||
414 | detail: "Box::new(expr)", | 438 | detail: "Box::new(expr)", |
415 | }, | 439 | }, |
416 | CompletionItem { | 440 | CompletionItem { |
441 | label: "call", | ||
442 | source_range: 211..211, | ||
443 | delete: 207..211, | ||
444 | insert: "${1}(bar)", | ||
445 | detail: "function(expr)", | ||
446 | }, | ||
447 | CompletionItem { | ||
417 | label: "dbg", | 448 | label: "dbg", |
418 | source_range: 211..211, | 449 | source_range: 211..211, |
419 | delete: 207..211, | 450 | delete: 207..211, |
@@ -488,6 +519,13 @@ mod tests { | |||
488 | detail: "Box::new(expr)", | 519 | detail: "Box::new(expr)", |
489 | }, | 520 | }, |
490 | CompletionItem { | 521 | CompletionItem { |
522 | label: "call", | ||
523 | source_range: 91..91, | ||
524 | delete: 87..91, | ||
525 | insert: "${1}(bar)", | ||
526 | detail: "function(expr)", | ||
527 | }, | ||
528 | CompletionItem { | ||
491 | label: "dbg", | 529 | label: "dbg", |
492 | source_range: 91..91, | 530 | source_range: 91..91, |
493 | delete: 87..91, | 531 | delete: 87..91, |
@@ -547,6 +585,13 @@ mod tests { | |||
547 | detail: "Box::new(expr)", | 585 | detail: "Box::new(expr)", |
548 | }, | 586 | }, |
549 | CompletionItem { | 587 | CompletionItem { |
588 | label: "call", | ||
589 | source_range: 52..52, | ||
590 | delete: 49..52, | ||
591 | insert: "${1}(42)", | ||
592 | detail: "function(expr)", | ||
593 | }, | ||
594 | CompletionItem { | ||
550 | label: "dbg", | 595 | label: "dbg", |
551 | source_range: 52..52, | 596 | source_range: 52..52, |
552 | delete: 49..52, | 597 | delete: 49..52, |
@@ -608,6 +653,13 @@ mod tests { | |||
608 | detail: "Box::new(expr)", | 653 | detail: "Box::new(expr)", |
609 | }, | 654 | }, |
610 | CompletionItem { | 655 | CompletionItem { |
656 | label: "call", | ||
657 | source_range: 149..150, | ||
658 | delete: 145..150, | ||
659 | insert: "${1}(bar)", | ||
660 | detail: "function(expr)", | ||
661 | }, | ||
662 | CompletionItem { | ||
611 | label: "dbg", | 663 | label: "dbg", |
612 | source_range: 149..150, | 664 | source_range: 149..150, |
613 | delete: 145..150, | 665 | delete: 145..150, |
@@ -667,6 +719,13 @@ mod tests { | |||
667 | detail: "Box::new(expr)", | 719 | detail: "Box::new(expr)", |
668 | }, | 720 | }, |
669 | CompletionItem { | 721 | CompletionItem { |
722 | label: "call", | ||
723 | source_range: 56..56, | ||
724 | delete: 49..56, | ||
725 | insert: "${1}(&&&&42)", | ||
726 | detail: "function(expr)", | ||
727 | }, | ||
728 | CompletionItem { | ||
670 | label: "dbg", | 729 | label: "dbg", |
671 | source_range: 56..56, | 730 | source_range: 56..56, |
672 | delete: 49..56, | 731 | delete: 49..56, |
diff --git a/crates/ra_ide/src/completion/complete_trait_impl.rs b/crates/ra_ide/src/completion/complete_trait_impl.rs index 039df03e0..21c9316e6 100644 --- a/crates/ra_ide/src/completion/complete_trait_impl.rs +++ b/crates/ra_ide/src/completion/complete_trait_impl.rs | |||
@@ -49,56 +49,53 @@ use crate::{ | |||
49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { | 49 | pub(crate) fn complete_trait_impl(acc: &mut Completions, ctx: &CompletionContext) { |
50 | if let Some((trigger, impl_def)) = completion_match(ctx) { | 50 | if let Some((trigger, impl_def)) = completion_match(ctx) { |
51 | match trigger.kind() { | 51 | match trigger.kind() { |
52 | SyntaxKind::NAME_REF => { | 52 | SyntaxKind::NAME_REF => get_missing_assoc_items(&ctx.sema, &impl_def) |
53 | get_missing_assoc_items(&ctx.sema, &impl_def).iter().for_each(|item| match item { | 53 | .into_iter() |
54 | .for_each(|item| match item { | ||
54 | hir::AssocItem::Function(fn_item) => { | 55 | hir::AssocItem::Function(fn_item) => { |
55 | add_function_impl(&trigger, acc, ctx, &fn_item) | 56 | add_function_impl(&trigger, acc, ctx, fn_item) |
56 | } | 57 | } |
57 | hir::AssocItem::TypeAlias(type_item) => { | 58 | hir::AssocItem::TypeAlias(type_item) => { |
58 | add_type_alias_impl(&trigger, acc, ctx, &type_item) | 59 | add_type_alias_impl(&trigger, acc, ctx, type_item) |
59 | } | 60 | } |
60 | hir::AssocItem::Const(const_item) => { | 61 | hir::AssocItem::Const(const_item) => { |
61 | add_const_impl(&trigger, acc, ctx, &const_item) | 62 | add_const_impl(&trigger, acc, ctx, const_item) |
62 | } | 63 | } |
63 | }) | 64 | }), |
64 | } | ||
65 | 65 | ||
66 | SyntaxKind::FN_DEF => { | 66 | SyntaxKind::FN_DEF => { |
67 | for missing_fn in | 67 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) |
68 | get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { | 68 | .into_iter() |
69 | match item { | 69 | .filter_map(|item| match item { |
70 | hir::AssocItem::Function(fn_item) => Some(fn_item), | 70 | hir::AssocItem::Function(fn_item) => Some(fn_item), |
71 | _ => None, | 71 | _ => None, |
72 | } | ||
73 | }) | 72 | }) |
74 | { | 73 | { |
75 | add_function_impl(&trigger, acc, ctx, &missing_fn); | 74 | add_function_impl(&trigger, acc, ctx, missing_fn); |
76 | } | 75 | } |
77 | } | 76 | } |
78 | 77 | ||
79 | SyntaxKind::TYPE_ALIAS_DEF => { | 78 | SyntaxKind::TYPE_ALIAS_DEF => { |
80 | for missing_fn in | 79 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) |
81 | get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { | 80 | .into_iter() |
82 | match item { | 81 | .filter_map(|item| match item { |
83 | hir::AssocItem::TypeAlias(type_item) => Some(type_item), | 82 | hir::AssocItem::TypeAlias(type_item) => Some(type_item), |
84 | _ => None, | 83 | _ => None, |
85 | } | ||
86 | }) | 84 | }) |
87 | { | 85 | { |
88 | add_type_alias_impl(&trigger, acc, ctx, &missing_fn); | 86 | add_type_alias_impl(&trigger, acc, ctx, missing_fn); |
89 | } | 87 | } |
90 | } | 88 | } |
91 | 89 | ||
92 | SyntaxKind::CONST_DEF => { | 90 | SyntaxKind::CONST_DEF => { |
93 | for missing_fn in | 91 | for missing_fn in get_missing_assoc_items(&ctx.sema, &impl_def) |
94 | get_missing_assoc_items(&ctx.sema, &impl_def).iter().filter_map(|item| { | 92 | .into_iter() |
95 | match item { | 93 | .filter_map(|item| match item { |
96 | hir::AssocItem::Const(const_item) => Some(const_item), | 94 | hir::AssocItem::Const(const_item) => Some(const_item), |
97 | _ => None, | 95 | _ => None, |
98 | } | ||
99 | }) | 96 | }) |
100 | { | 97 | { |
101 | add_const_impl(&trigger, acc, ctx, &missing_fn); | 98 | add_const_impl(&trigger, acc, ctx, missing_fn); |
102 | } | 99 | } |
103 | } | 100 | } |
104 | 101 | ||
@@ -126,9 +123,9 @@ fn add_function_impl( | |||
126 | fn_def_node: &SyntaxNode, | 123 | fn_def_node: &SyntaxNode, |
127 | acc: &mut Completions, | 124 | acc: &mut Completions, |
128 | ctx: &CompletionContext, | 125 | ctx: &CompletionContext, |
129 | func: &hir::Function, | 126 | func: hir::Function, |
130 | ) { | 127 | ) { |
131 | let signature = FunctionSignature::from_hir(ctx.db, *func); | 128 | let signature = FunctionSignature::from_hir(ctx.db, func); |
132 | 129 | ||
133 | let fn_name = func.name(ctx.db).to_string(); | 130 | let fn_name = func.name(ctx.db).to_string(); |
134 | 131 | ||
@@ -167,7 +164,7 @@ fn add_type_alias_impl( | |||
167 | type_def_node: &SyntaxNode, | 164 | type_def_node: &SyntaxNode, |
168 | acc: &mut Completions, | 165 | acc: &mut Completions, |
169 | ctx: &CompletionContext, | 166 | ctx: &CompletionContext, |
170 | type_alias: &hir::TypeAlias, | 167 | type_alias: hir::TypeAlias, |
171 | ) { | 168 | ) { |
172 | let alias_name = type_alias.name(ctx.db).to_string(); | 169 | let alias_name = type_alias.name(ctx.db).to_string(); |
173 | 170 | ||
@@ -187,7 +184,7 @@ fn add_const_impl( | |||
187 | const_def_node: &SyntaxNode, | 184 | const_def_node: &SyntaxNode, |
188 | acc: &mut Completions, | 185 | acc: &mut Completions, |
189 | ctx: &CompletionContext, | 186 | ctx: &CompletionContext, |
190 | const_: &hir::Const, | 187 | const_: hir::Const, |
191 | ) { | 188 | ) { |
192 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); | 189 | let const_name = const_.name(ctx.db).map(|n| n.to_string()); |
193 | 190 | ||
diff --git a/crates/ra_ide/src/completion/complete_unqualified_path.rs b/crates/ra_ide/src/completion/complete_unqualified_path.rs index db791660a..68032c37e 100644 --- a/crates/ra_ide/src/completion/complete_unqualified_path.rs +++ b/crates/ra_ide/src/completion/complete_unqualified_path.rs | |||
@@ -298,6 +298,42 @@ mod tests { | |||
298 | } | 298 | } |
299 | 299 | ||
300 | #[test] | 300 | #[test] |
301 | fn completes_bindings_from_for_with_in_prefix() { | ||
302 | mark::check!(completes_bindings_from_for_with_in_prefix); | ||
303 | assert_debug_snapshot!( | ||
304 | do_reference_completion( | ||
305 | r" | ||
306 | fn test() { | ||
307 | for index in &[1, 2, 3] { | ||
308 | let t = in<|> | ||
309 | } | ||
310 | } | ||
311 | " | ||
312 | ), | ||
313 | @r###" | ||
314 | [ | ||
315 | CompletionItem { | ||
316 | label: "index", | ||
317 | source_range: 107..107, | ||
318 | delete: 107..107, | ||
319 | insert: "index", | ||
320 | kind: Binding, | ||
321 | }, | ||
322 | CompletionItem { | ||
323 | label: "test()", | ||
324 | source_range: 107..107, | ||
325 | delete: 107..107, | ||
326 | insert: "test()$0", | ||
327 | kind: Function, | ||
328 | lookup: "test", | ||
329 | detail: "fn test()", | ||
330 | }, | ||
331 | ] | ||
332 | "### | ||
333 | ); | ||
334 | } | ||
335 | |||
336 | #[test] | ||
301 | fn completes_generic_params() { | 337 | fn completes_generic_params() { |
302 | assert_debug_snapshot!( | 338 | assert_debug_snapshot!( |
303 | do_reference_completion( | 339 | do_reference_completion( |
diff --git a/crates/ra_ide/src/completion/completion_context.rs b/crates/ra_ide/src/completion/completion_context.rs index da336973c..c4646b727 100644 --- a/crates/ra_ide/src/completion/completion_context.rs +++ b/crates/ra_ide/src/completion/completion_context.rs | |||
@@ -12,6 +12,7 @@ use ra_syntax::{ | |||
12 | use ra_text_edit::Indel; | 12 | use ra_text_edit::Indel; |
13 | 13 | ||
14 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; | 14 | use crate::{call_info::ActiveParameter, completion::CompletionConfig, FilePosition}; |
15 | use test_utils::mark; | ||
15 | 16 | ||
16 | /// `CompletionContext` is created early during completion to figure out, where | 17 | /// `CompletionContext` is created early during completion to figure out, where |
17 | /// exactly is the cursor, syntax-wise. | 18 | /// exactly is the cursor, syntax-wise. |
@@ -169,7 +170,17 @@ impl<'a> CompletionContext<'a> { | |||
169 | match self.token.kind() { | 170 | match self.token.kind() { |
170 | // workaroud when completion is triggered by trigger characters. | 171 | // workaroud when completion is triggered by trigger characters. |
171 | IDENT => self.original_token.text_range(), | 172 | IDENT => self.original_token.text_range(), |
172 | _ => TextRange::empty(self.offset), | 173 | _ => { |
174 | // If we haven't characters between keyword and our cursor we take the keyword start range to edit | ||
175 | if self.token.kind().is_keyword() | ||
176 | && self.offset == self.original_token.text_range().end() | ||
177 | { | ||