diff options
author | Benjamin Coenen <[email protected]> | 2020-05-02 19:27:02 +0100 |
---|---|---|
committer | Benjamin Coenen <[email protected]> | 2020-05-02 19:27:02 +0100 |
commit | 4613497a7714c6cd87166e6525d764d75f8acefd (patch) | |
tree | 2527ae2c0ef2ef100efee3fcb8899f8e34d0d573 /crates | |
parent | 19e28888aa41b2845b47adb7314aed99d3c48679 (diff) | |
parent | 89e1f97515c36ab97bd378d972cabec0feb6d77e (diff) |
Merge branch 'master' of github.com:rust-analyzer/rust-analyzer into fix_4202
Diffstat (limited to 'crates')
294 files changed, 13220 insertions, 11551 deletions
diff --git a/crates/ra_assists/src/ast_transform.rs b/crates/ra_assists/src/ast_transform.rs index 52b4c82db..9ac65ab39 100644 --- a/crates/ra_assists/src/ast_transform.rs +++ b/crates/ra_assists/src/ast_transform.rs | |||
@@ -85,6 +85,7 @@ impl<'a> SubstituteTypeParams<'a> { | |||
85 | ast::TypeRef::PathType(path_type) => path_type.path()?, | 85 | ast::TypeRef::PathType(path_type) => path_type.path()?, |
86 | _ => return None, | 86 | _ => return None, |
87 | }; | 87 | }; |
88 | // FIXME: use `hir::Path::from_src` instead. | ||
88 | let path = hir::Path::from_ast(path)?; | 89 | let path = hir::Path::from_ast(path)?; |
89 | let resolution = self.source_scope.resolve_hir_path(&path)?; | 90 | let resolution = self.source_scope.resolve_hir_path(&path)?; |
90 | match resolution { | 91 | match resolution { |
@@ -128,6 +129,7 @@ impl<'a> QualifyPaths<'a> { | |||
128 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway | 129 | // don't try to qualify `Fn(Foo) -> Bar` paths, they are in prelude anyway |
129 | return None; | 130 | return None; |
130 | } | 131 | } |
132 | // FIXME: use `hir::Path::from_src` instead. | ||
131 | let hir_path = hir::Path::from_ast(p.clone()); | 133 | let hir_path = hir::Path::from_ast(p.clone()); |
132 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; | 134 | let resolution = self.source_scope.resolve_hir_path(&hir_path?)?; |
133 | match resolution { | 135 | match resolution { |
diff --git a/crates/ra_assists/src/doc_tests/generated.rs b/crates/ra_assists/src/doc_tests/generated.rs index e4fa9ee36..6696cc832 100644 --- a/crates/ra_assists/src/doc_tests/generated.rs +++ b/crates/ra_assists/src/doc_tests/generated.rs | |||
@@ -180,7 +180,9 @@ trait Trait<T> { | |||
180 | } | 180 | } |
181 | 181 | ||
182 | impl Trait<u32> for () { | 182 | impl Trait<u32> for () { |
183 | fn foo(&self) -> u32 { todo!() } | 183 | fn foo(&self) -> u32 { |
184 | todo!() | ||
185 | } | ||
184 | 186 | ||
185 | } | 187 | } |
186 | "#####, | 188 | "#####, |
@@ -726,3 +728,22 @@ use std::{collections::HashMap}; | |||
726 | "#####, | 728 | "#####, |
727 | ) | 729 | ) |
728 | } | 730 | } |
731 | |||
732 | #[test] | ||
733 | fn doctest_unwrap_block() { | ||
734 | check( | ||
735 | "unwrap_block", | ||
736 | r#####" | ||
737 | fn foo() { | ||
738 | if true {<|> | ||
739 | println!("foo"); | ||
740 | } | ||
741 | } | ||
742 | "#####, | ||
743 | r#####" | ||
744 | fn foo() { | ||
745 | println!("foo"); | ||
746 | } | ||
747 | "#####, | ||
748 | ) | ||
749 | } | ||
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 03806724a..49deb6701 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 | |||
@@ -1,11 +1,12 @@ | |||
1 | use ra_ide_db::RootDatabase; | ||
1 | use ra_syntax::{ | 2 | use ra_syntax::{ |
2 | ast::{self, AstNode, NameOwner}, | 3 | ast::{self, AstNode, NameOwner}, |
3 | TextSize, | 4 | TextSize, |
4 | }; | 5 | }; |
5 | use stdx::format_to; | 6 | use stdx::format_to; |
6 | 7 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::FamousDefs, Assist, AssistCtx, AssistId}; |
8 | use ra_ide_db::RootDatabase; | 9 | use test_utils::tested_by; |
9 | 10 | ||
10 | // Assist add_from_impl_for_enum | 11 | // Assist add_from_impl_for_enum |
11 | // | 12 | // |
@@ -41,7 +42,8 @@ pub(crate) fn add_from_impl_for_enum(ctx: AssistCtx) -> Option<Assist> { | |||
41 | _ => return None, | 42 | _ => return None, |
42 | }; | 43 | }; |
43 | 44 | ||
44 | if already_has_from_impl(ctx.sema, &variant) { | 45 | if existing_from_impl(ctx.sema, &variant).is_some() { |
46 | tested_by!(test_add_from_impl_already_exists); | ||
45 | return None; | 47 | return None; |
46 | } | 48 | } |
47 | 49 | ||
@@ -70,41 +72,33 @@ impl From<{0}> for {1} {{ | |||
70 | ) | 72 | ) |
71 | } | 73 | } |
72 | 74 | ||
73 | fn already_has_from_impl( | 75 | fn existing_from_impl( |
74 | sema: &'_ hir::Semantics<'_, RootDatabase>, | 76 | sema: &'_ hir::Semantics<'_, RootDatabase>, |
75 | variant: &ast::EnumVariant, | 77 | variant: &ast::EnumVariant, |
76 | ) -> bool { | 78 | ) -> Option<()> { |
77 | let scope = sema.scope(&variant.syntax()); | 79 | let variant = sema.to_def(variant)?; |
80 | let enum_ = variant.parent_enum(sema.db); | ||
81 | let krate = enum_.module(sema.db).krate(); | ||
78 | 82 | ||
79 | let from_path = ast::make::path_from_text("From"); | 83 | let from_trait = FamousDefs(sema, krate).core_convert_From()?; |
80 | let from_hir_path = match hir::Path::from_ast(from_path) { | ||
81 | Some(p) => p, | ||
82 | None => return false, | ||
83 | }; | ||
84 | let from_trait = match scope.resolve_hir_path(&from_hir_path) { | ||
85 | Some(hir::PathResolution::Def(hir::ModuleDef::Trait(t))) => t, | ||
86 | _ => return false, | ||
87 | }; | ||
88 | 84 | ||
89 | let e: hir::Enum = match sema.to_def(&variant.parent_enum()) { | 85 | let enum_type = enum_.ty(sema.db); |
90 | Some(e) => e, | ||
91 | None => return false, | ||
92 | }; | ||
93 | let e_ty = e.ty(sema.db); | ||
94 | 86 | ||
95 | let hir_enum_var: hir::EnumVariant = match sema.to_def(variant) { | 87 | let wrapped_type = variant.fields(sema.db).get(0)?.signature_ty(sema.db); |
96 | Some(ev) => ev, | ||
97 | None => return false, | ||
98 | }; | ||
99 | let var_ty = hir_enum_var.fields(sema.db)[0].signature_ty(sema.db); | ||
100 | 88 | ||
101 | e_ty.impls_trait(sema.db, from_trait, &[var_ty]) | 89 | if enum_type.impls_trait(sema.db, from_trait, &[wrapped_type]) { |
90 | Some(()) | ||
91 | } else { | ||
92 | None | ||
93 | } | ||
102 | } | 94 | } |
103 | 95 | ||
104 | #[cfg(test)] | 96 | #[cfg(test)] |
105 | mod tests { | 97 | mod tests { |
106 | use super::*; | 98 | use super::*; |
99 | |||
107 | use crate::helpers::{check_assist, check_assist_not_applicable}; | 100 | use crate::helpers::{check_assist, check_assist_not_applicable}; |
101 | use test_utils::covers; | ||
108 | 102 | ||
109 | #[test] | 103 | #[test] |
110 | fn test_add_from_impl_for_enum() { | 104 | fn test_add_from_impl_for_enum() { |
@@ -136,36 +130,40 @@ mod tests { | |||
136 | ); | 130 | ); |
137 | } | 131 | } |
138 | 132 | ||
133 | fn check_not_applicable(ra_fixture: &str) { | ||
134 | let fixture = | ||
135 | format!("//- main.rs crate:main deps:core\n{}\n{}", ra_fixture, FamousDefs::FIXTURE); | ||
136 | check_assist_not_applicable(add_from_impl_for_enum, &fixture) | ||
137 | } | ||
138 | |||
139 | #[test] | 139 | #[test] |
140 | fn test_add_from_impl_no_element() { | 140 | fn test_add_from_impl_no_element() { |
141 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One }"); | 141 | check_not_applicable("enum A { <|>One }"); |
142 | } | 142 | } |
143 | 143 | ||
144 | #[test] | 144 | #[test] |
145 | fn test_add_from_impl_more_than_one_element_in_tuple() { | 145 | fn test_add_from_impl_more_than_one_element_in_tuple() { |
146 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One(u32, String) }"); | 146 | check_not_applicable("enum A { <|>One(u32, String) }"); |
147 | } | 147 | } |
148 | 148 | ||
149 | #[test] | 149 | #[test] |
150 | fn test_add_from_impl_struct_variant() { | 150 | fn test_add_from_impl_struct_variant() { |
151 | check_assist_not_applicable(add_from_impl_for_enum, "enum A { <|>One { x: u32 } }"); | 151 | check_not_applicable("enum A { <|>One { x: u32 } }"); |
152 | } | 152 | } |
153 | 153 | ||
154 | #[test] | 154 | #[test] |
155 | fn test_add_from_impl_already_exists() { | 155 | fn test_add_from_impl_already_exists() { |
156 | check_assist_not_applicable( | 156 | covers!(test_add_from_impl_already_exists); |
157 | add_from_impl_for_enum, | 157 | check_not_applicable( |
158 | r#"enum A { <|>One(u32), } | 158 | r#" |
159 | enum A { <|>One(u32), } | ||
159 | 160 | ||
160 | impl From<u32> for A { | 161 | impl From<u32> for A { |
161 | fn from(v: u32) -> Self { | 162 | fn from(v: u32) -> Self { |
162 | A::One(v) | 163 | A::One(v) |
163 | } | 164 | } |
164 | } | 165 | } |
165 | 166 | "#, | |
166 | pub trait From<T> { | ||
167 | fn from(T) -> Self; | ||
168 | }"#, | ||
169 | ); | 167 | ); |
170 | } | 168 | } |
171 | 169 | ||
diff --git a/crates/ra_assists/src/handlers/add_missing_impl_members.rs b/crates/ra_assists/src/handlers/add_missing_impl_members.rs index 2d6d44980..e466c9a86 100644 --- a/crates/ra_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ra_assists/src/handlers/add_missing_impl_members.rs | |||
@@ -1,6 +1,10 @@ | |||
1 | use hir::HasSource; | 1 | use hir::HasSource; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, edit, make, AstNode, NameOwner}, | 3 | ast::{ |
4 | self, | ||
5 | edit::{self, IndentLevel}, | ||
6 | make, AstNode, NameOwner, | ||
7 | }, | ||
4 | SmolStr, | 8 | SmolStr, |
5 | }; | 9 | }; |
6 | 10 | ||
@@ -40,7 +44,9 @@ enum AddMissingImplMembersMode { | |||
40 | // } | 44 | // } |
41 | // | 45 | // |
42 | // impl Trait<u32> for () { | 46 | // impl Trait<u32> for () { |
43 | // fn foo(&self) -> u32 { todo!() } | 47 | // fn foo(&self) -> u32 { |
48 | // todo!() | ||
49 | // } | ||
44 | // | 50 | // |
45 | // } | 51 | // } |
46 | // ``` | 52 | // ``` |
@@ -165,7 +171,9 @@ fn add_missing_impl_members_inner( | |||
165 | 171 | ||
166 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { | 172 | fn add_body(fn_def: ast::FnDef) -> ast::FnDef { |
167 | if fn_def.body().is_none() { | 173 | if fn_def.body().is_none() { |
168 | fn_def.with_body(make::block_from_expr(make::expr_todo())) | 174 | let body = make::block_expr(None, Some(make::expr_todo())); |
175 | let body = IndentLevel(1).increase_indent(body); | ||
176 | fn_def.with_body(body) | ||
169 | } else { | 177 | } else { |
170 | fn_def | 178 | fn_def |
171 | } | 179 | } |
@@ -181,7 +189,7 @@ mod tests { | |||
181 | fn test_add_missing_impl_members() { | 189 | fn test_add_missing_impl_members() { |
182 | check_assist( | 190 | check_assist( |
183 | add_missing_impl_members, | 191 | add_missing_impl_members, |
184 | " | 192 | r#" |
185 | trait Foo { | 193 | trait Foo { |
186 | type Output; | 194 | type Output; |
187 | 195 | ||
@@ -197,8 +205,8 @@ struct S; | |||
197 | impl Foo for S { | 205 | impl Foo for S { |
198 | fn bar(&self) {} | 206 | fn bar(&self) {} |
199 | <|> | 207 | <|> |
200 | }", | 208 | }"#, |
201 | " | 209 | r#" |
202 | trait Foo { | 210 | trait Foo { |
203 | type Output; | 211 | type Output; |
204 | 212 | ||
@@ -215,10 +223,14 @@ impl Foo for S { | |||
215 | fn bar(&self) {} | 223 | fn bar(&self) {} |
216 | <|>type Output; | 224 | <|>type Output; |
217 | const CONST: usize = 42; | 225 | const CONST: usize = 42; |
218 | fn foo(&self) { todo!() } | 226 | fn foo(&self) { |
219 | fn baz(&self) { todo!() } | 227 | todo!() |
228 | } | ||
229 | fn baz(&self) { | ||
230 | todo!() | ||
231 | } | ||
220 | 232 | ||
221 | }", | 233 | }"#, |
222 | ); | 234 | ); |
223 | } | 235 | } |
224 | 236 | ||
@@ -226,7 +238,7 @@ impl Foo for S { | |||
226 | fn test_copied_overriden_members() { | 238 | fn test_copied_overriden_members() { |
227 | check_assist( | 239 | check_assist( |
228 | add_missing_impl_members, | 240 | add_missing_impl_members, |
229 | " | 241 | r#" |
230 | trait Foo { | 242 | trait Foo { |
231 | fn foo(&self); | 243 | fn foo(&self); |
232 | fn bar(&self) -> bool { true } | 244 | fn bar(&self) -> bool { true } |
@@ -238,8 +250,8 @@ struct S; | |||
238 | impl Foo for S { | 250 | impl Foo for S { |
239 | fn bar(&self) {} | 251 | fn bar(&self) {} |
240 | <|> | 252 | <|> |
241 | }", | 253 | }"#, |
242 | " | 254 | r#" |
243 | trait Foo { | 255 | trait Foo { |
244 | fn foo(&self); | 256 | fn foo(&self); |
245 | fn bar(&self) -> bool { true } | 257 | fn bar(&self) -> bool { true } |
@@ -250,9 +262,11 @@ struct S; | |||
250 | 262 | ||
251 | impl Foo for S { | 263 | impl Foo for S { |
252 | fn bar(&self) {} | 264 | fn bar(&self) {} |
253 | <|>fn foo(&self) { todo!() } | 265 | <|>fn foo(&self) { |
266 | todo!() | ||
267 | } | ||
254 | 268 | ||
255 | }", | 269 | }"#, |
256 | ); | 270 | ); |
257 | } | 271 | } |
258 | 272 | ||
@@ -260,16 +274,18 @@ impl Foo for S { | |||
260 | fn test_empty_impl_def() { | 274 | fn test_empty_impl_def() { |
261 | check_assist( | 275 | check_assist( |
262 | add_missing_impl_members, | 276 | add_missing_impl_members, |
263 | " | 277 | r#" |
264 | trait Foo { fn foo(&self); } | 278 | trait Foo { fn foo(&self); } |
265 | struct S; | 279 | struct S; |
266 | impl Foo for S { <|> }", | 280 | impl Foo for S { <|> }"#, |
267 | " | 281 | r#" |
268 | trait Foo { fn foo(&self); } | 282 | trait Foo { fn foo(&self); } |
269 | struct S; | 283 | struct S; |
270 | impl Foo for S { | 284 | impl Foo for S { |
271 | <|>fn foo(&self) { todo!() } | 285 | <|>fn foo(&self) { |
272 | }", | 286 | todo!() |
287 | } | ||
288 | }"#, | ||
273 | ); | 289 | ); |
274 | } | 290 | } |
275 | 291 | ||
@@ -277,16 +293,18 @@ impl Foo for S { | |||
277 | fn fill_in_type_params_1() { | 293 | fn fill_in_type_params_1() { |
278 | check_assist( | 294 | check_assist( |
279 | add_missing_impl_members, | 295 | add_missing_impl_members, |
280 | " | 296 | r#" |
281 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 297 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
282 | struct S; | 298 | struct S; |
283 | impl Foo<u32> for S { <|> }", | 299 | impl Foo<u32> for S { <|> }"#, |
284 | " | 300 | r#" |
285 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 301 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
286 | struct S; | 302 | struct S; |
287 | impl Foo<u32> for S { | 303 | impl Foo<u32> for S { |
288 | <|>fn foo(&self, t: u32) -> &u32 { todo!() } | 304 | <|>fn foo(&self, t: u32) -> &u32 { |
289 | }", | 305 | todo!() |
306 | } | ||
307 | }"#, | ||
290 | ); | 308 | ); |
291 | } | 309 | } |
292 | 310 | ||
@@ -294,16 +312,18 @@ impl Foo<u32> for S { | |||
294 | fn fill_in_type_params_2() { | 312 | fn fill_in_type_params_2() { |
295 | check_assist( | 313 | check_assist( |
296 | add_missing_impl_members, | 314 | add_missing_impl_members, |
297 | " | 315 | r#" |
298 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 316 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
299 | struct S; | 317 | struct S; |
300 | impl<U> Foo<U> for S { <|> }", | 318 | impl<U> Foo<U> for S { <|> }"#, |
301 | " | 319 | r#" |
302 | trait Foo<T> { fn foo(&self, t: T) -> &T; } | 320 | trait Foo<T> { fn foo(&self, t: T) -> &T; } |
303 | struct S; | 321 | struct S; |
304 | impl<U> Foo<U> for S { | 322 | impl<U> Foo<U> for S { |
305 | <|>fn foo(&self, t: U) -> &U { todo!() } | 323 | <|>fn foo(&self, t: U) -> &U { |
306 | }", | 324 | todo!() |
325 | } | ||
326 | }"#, | ||
307 | ); | 327 | ); |
308 | } | 328 | } |
309 | 329 | ||
@@ -311,16 +331,18 @@ impl<U> Foo<U> for S { | |||
311 | fn test_cursor_after_empty_impl_def() { | 331 | fn test_cursor_after_empty_impl_def() { |
312 | check_assist( | 332 | check_assist( |
313 | add_missing_impl_members, | 333 | add_missing_impl_members, |
314 | " | 334 | r#" |
315 | trait Foo { fn foo(&self); } | 335 | trait Foo { fn foo(&self); } |
316 | struct S; | 336 | struct S; |
317 | impl Foo for S {}<|>", | 337 | impl Foo for S {}<|>"#, |
318 | " | 338 | r#" |
319 | trait Foo { fn foo(&self); } | 339 | trait Foo { fn foo(&self); } |
320 | struct S; | 340 | struct S; |
321 | impl Foo for S { | 341 | impl Foo for S { |
322 | <|>fn foo(&self) { todo!() } | 342 | <|>fn foo(&self) { |
323 | }", | 343 | todo!() |
344 | } | ||
345 | }"#, | ||
324 | ) | 346 | ) |
325 | } | 347 | } |
326 | 348 | ||
@@ -328,22 +350,24 @@ impl Foo for S { | |||
328 | fn test_qualify_path_1() { | 350 | fn test_qualify_path_1() { |
329 | check_assist( | 351 | check_assist( |
330 | add_missing_impl_members, | 352 | add_missing_impl_members, |
331 | " | 353 | r#" |
332 | mod foo { | 354 | mod foo { |
333 | pub struct Bar; | 355 | pub struct Bar; |
334 | trait Foo { fn foo(&self, bar: Bar); } | 356 | trait Foo { fn foo(&self, bar: Bar); } |
335 | } | 357 | } |
336 | struct S; | 358 | struct S; |
337 | impl foo::Foo for S { <|> }", | 359 | impl foo::Foo for S { <|> }"#, |
338 | " | 360 | r#" |
339 | mod foo { | 361 | mod foo { |
340 | pub struct Bar; | 362 | pub struct Bar; |
341 | trait Foo { fn foo(&self, bar: Bar); } | 363 | trait Foo { fn foo(&self, bar: Bar); } |
342 | } | 364 | } |
343 | struct S; | 365 | struct S; |
344 | impl foo::Foo for S { | 366 | impl foo::Foo for S { |
345 | <|>fn foo(&self, bar: foo::Bar) { todo!() } | 367 | <|>fn foo(&self, bar: foo::Bar) { |
346 | }", | 368 | todo!() |
369 | } | ||
370 | }"#, | ||
347 | ); | 371 | ); |
348 | } | 372 | } |
349 | 373 | ||
@@ -351,22 +375,24 @@ impl foo::Foo for S { | |||
351 | fn test_qualify_path_generic() { | 375 | fn test_qualify_path_generic() { |
352 | check_assist( | 376 | check_assist( |
353 | add_missing_impl_members, | 377 | add_missing_impl_members, |
354 | " | 378 | r#" |
355 | mod foo { | 379 | mod foo { |
356 | pub struct Bar<T>; | 380 | pub struct Bar<T>; |
357 | trait Foo { fn foo(&self, bar: Bar<u32>); } | 381 | trait Foo { fn foo(&self, bar: Bar<u32>); } |
358 | } | 382 | } |
359 | struct S; | 383 | struct S; |
360 | impl foo::Foo for S { <|> }", | 384 | impl foo::Foo for S { <|> }"#, |
361 | " | 385 | r#" |
362 | mod foo { | 386 | mod foo { |
363 | pub struct Bar<T>; | 387 | pub struct Bar<T>; |
364 | trait Foo { fn foo(&self, bar: Bar<u32>); } | 388 | trait Foo { fn foo(&self, bar: Bar<u32>); } |
365 | } | 389 | } |
366 | struct S; | 390 | struct S; |
367 | impl foo::Foo for S { | 391 | impl foo::Foo for S { |
368 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } | 392 | <|>fn foo(&self, bar: foo::Bar<u32>) { |
369 | }", | 393 | todo!() |
394 | } | ||
395 | }"#, | ||
370 | ); | 396 | ); |
371 | } | 397 | } |
372 | 398 | ||
@@ -374,22 +400,24 @@ impl foo::Foo for S { | |||
374 | fn test_qualify_path_and_substitute_param() { | 400 | fn test_qualify_path_and_substitute_param() { |
375 | check_assist( | 401 | check_assist( |
376 | add_missing_impl_members, | 402 | add_missing_impl_members, |
377 | " | 403 | r#" |
378 | mod foo { | 404 | mod foo { |
379 | pub struct Bar<T>; | 405 | pub struct Bar<T>; |
380 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | 406 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } |
381 | } | 407 | } |
382 | struct S; | 408 | struct S; |
383 | impl foo::Foo<u32> for S { <|> }", | 409 | impl foo::Foo<u32> for S { <|> }"#, |
384 | " | 410 | r#" |
385 | mod foo { | 411 | mod foo { |
386 | pub struct Bar<T>; | 412 | pub struct Bar<T>; |
387 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } | 413 | trait Foo<T> { fn foo(&self, bar: Bar<T>); } |
388 | } | 414 | } |
389 | struct S; | 415 | struct S; |
390 | impl foo::Foo<u32> for S { | 416 | impl foo::Foo<u32> for S { |
391 | <|>fn foo(&self, bar: foo::Bar<u32>) { todo!() } | 417 | <|>fn foo(&self, bar: foo::Bar<u32>) { |
392 | }", | 418 | todo!() |
419 | } | ||
420 | }"#, | ||
393 | ); | 421 | ); |
394 | } | 422 | } |
395 | 423 | ||
@@ -398,15 +426,15 @@ impl foo::Foo<u32> for S { | |||
398 | // when substituting params, the substituted param should not be qualified! | 426 | // when substituting params, the substituted param should not be qualified! |
399 | check_assist( | 427 | check_assist( |
400 | add_missing_impl_members, | 428 | add_missing_impl_members, |
401 | " | 429 | r#" |
402 | mod foo { | 430 | mod foo { |
403 | trait Foo<T> { fn foo(&self, bar: T); } | 431 | trait Foo<T> { fn foo(&self, bar: T); } |
404 | pub struct Param; | 432 | pub struct Param; |
405 | } | 433 | } |
406 | struct Param; | 434 | struct Param; |
407 | struct S; | 435 | struct S; |
408 | impl foo::Foo<Param> for S { <|> }", | 436 | impl foo::Foo<Param> for S { <|> }"#, |
409 | " | 437 | r#" |
410 | mod foo { | 438 | mod foo { |
411 | trait Foo<T> { fn foo(&self, bar: T); } | 439 | trait Foo<T> { fn foo(&self, bar: T); } |
412 | pub struct Param; | 440 | pub struct Param; |
@@ -414,8 +442,10 @@ mod foo { | |||
414 | struct Param; | 442 | struct Param; |
415 | struct S; | 443 | struct S; |
416 | impl foo::Foo<Param> for S { | 444 | impl foo::Foo<Param> for S { |
417 | <|>fn foo(&self, bar: Param) { todo!() } | 445 | <|>fn foo(&self, bar: Param) { |
418 | }", | 446 | todo!() |
447 | } | ||
448 | }"#, | ||
419 | ); | 449 | ); |
420 | } | 450 | } |
421 | 451 | ||
@@ -423,15 +453,15 @@ impl foo::Foo<Param> for S { | |||
423 | fn test_qualify_path_associated_item() { | 453 | fn test_qualify_path_associated_item() { |
424 | check_assist( | 454 | check_assist( |
425 | add_missing_impl_members, | 455 | add_missing_impl_members, |
426 | " | 456 | r#" |
427 | mod foo { | 457 | mod foo { |
428 | pub struct Bar<T>; | 458 | pub struct Bar<T>; |
429 | impl Bar<T> { type Assoc = u32; } | 459 | impl Bar<T> { type Assoc = u32; } |
430 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } | 460 | trait Foo { fn foo(&self, bar: Bar<u32>::Assoc); } |
431 | } | 461 | } |
432 | struct S; | 462 | struct S; |
433 | impl foo::Foo for S { <|> }", | 463 | impl foo::Foo for S { <|> }"#, |
434 | " | 464 | r#" |
435 | mod foo { | 465 | mod foo { |
436 | pub struct Bar<T>; | 466 | pub struct Bar<T>; |
437 | impl Bar<T> { type Assoc = u32; } | 467 | impl Bar<T> { type Assoc = u32; } |
@@ -439,8 +469,10 @@ mod foo { | |||
439 | } | 469 | } |
440 | struct S; | 470 | struct S; |
441 | impl foo::Foo for S { | 471 | impl foo::Foo for S { |
442 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { todo!() } | 472 | <|>fn foo(&self, bar: foo::Bar<u32>::Assoc) { |
443 | }", | 473 | todo!() |
474 | } | ||
475 | }"#, | ||
444 | ); | 476 | ); |
445 | } | 477 | } |
446 | 478 | ||
@@ -448,15 +480,15 @@ impl foo::Foo for S { | |||
448 | fn test_qualify_path_nested() { | 480 | fn test_qualify_path_nested() { |
449 | check_assist( | 481 | check_assist( |
450 | add_missing_impl_members, | 482 | add_missing_impl_members, |
451 | " | 483 | r#" |
452 | mod foo { | 484 | mod foo { |
453 | pub struct Bar<T>; | 485 | pub struct Bar<T>; |
454 | pub struct Baz; | 486 | pub struct Baz; |
455 | trait Foo { fn foo(&self, bar: Bar<Baz>); } | 487 | trait Foo { fn foo(&self, bar: Bar<Baz>); } |
456 | } | 488 | } |
457 | struct S; | 489 | struct S; |
458 | impl foo::Foo for S { <|> }", | 490 | impl foo::Foo for S { <|> }"#, |
459 | " | 491 | r#" |
460 | mod foo { | 492 | mod foo { |
461 | pub struct Bar<T>; | 493 | pub struct Bar<T>; |
462 | pub struct Baz; | 494 | pub struct Baz; |
@@ -464,8 +496,10 @@ mod foo { | |||
464 | } | 496 | } |
465 | struct S; | 497 | struct S; |
466 | impl foo::Foo for S { | 498 | impl foo::Foo for S { |
467 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { todo!() } | 499 | <|>fn foo(&self, bar: foo::Bar<foo::Baz>) { |
468 | }", | 500 | todo!() |
501 | } | ||
502 | }"#, | ||
469 | ); | 503 | ); |
470 | } | 504 | } |
471 | 505 | ||
@@ -473,22 +507,24 @@ impl foo::Foo for S { | |||
473 | fn test_qualify_path_fn_trait_notation() { | 507 | fn test_qualify_path_fn_trait_notation() { |
474 | check_assist( | 508 | check_assist( |
475 | add_missing_impl_members, | 509 | add_missing_impl_members, |
476 | " | 510 | r#" |
477 | mod foo { | 511 | mod foo { |
478 | pub trait Fn<Args> { type Output; } | 512 | pub trait Fn<Args> { type Output; } |
479 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | 513 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } |
480 | } | 514 | } |
481 | struct S; | 515 | struct S; |
482 | impl foo::Foo for S { <|> }", | 516 | impl foo::Foo for S { <|> }"#, |
483 | " | 517 | r#" |
484 | mod foo { | 518 | mod foo { |
485 | pub trait Fn<Args> { type Output; } | 519 | pub trait Fn<Args> { type Output; } |
486 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } | 520 | trait Foo { fn foo(&self, bar: dyn Fn(u32) -> i32); } |
487 | } | 521 | } |
488 | struct S; | 522 | struct S; |
489 | impl foo::Foo for S { | 523 | impl foo::Foo for S { |
490 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { todo!() } | 524 | <|>fn foo(&self, bar: dyn Fn(u32) -> i32) { |
491 | }", | 525 | todo!() |
526 | } | ||
527 | }"#, | ||
492 | ); | 528 | ); |
493 | } | 529 | } |
494 | 530 | ||
@@ -496,10 +532,10 @@ impl foo::Foo for S { | |||
496 | fn test_empty_trait() { | 532 | fn test_empty_trait() { |
497 | check_assist_not_applicable( | 533 | check_assist_not_applicable( |
498 | add_missing_impl_members, | 534 | add_missing_impl_members, |
499 | " | 535 | r#" |
500 | trait Foo; | 536 | trait Foo; |
501 | struct S; | 537 | struct S; |
502 | impl Foo for S { <|> }", | 538 | impl Foo for S { <|> }"#, |
503 | ) | 539 | ) |
504 | } | 540 | } |
505 | 541 | ||
@@ -507,13 +543,13 @@ impl Foo for S { <|> }", | |||
507 | fn test_ignore_unnamed_trait_members_and_default_methods() { | 543 | fn test_ignore_unnamed_trait_members_and_default_methods() { |
508 | check_assist_not_applicable( | 544 | check_assist_not_applicable( |
509 | add_missing_impl_members, | 545 | add_missing_impl_members, |
510 | " | 546 | r#" |
511 | trait Foo { | 547 | trait Foo { |
512 | fn (arg: u32); | 548 | fn (arg: u32); |
513 | fn valid(some: u32) -> bool { false } | 549 | fn valid(some: u32) -> bool { false } |
514 | } | 550 | } |
515 | struct S; | 551 | struct S; |
516 | impl Foo for S { <|> }", | 552 | impl Foo for S { <|> }"#, |
517 | ) | 553 | ) |
518 | } | 554 | } |
519 | 555 | ||
@@ -544,7 +580,9 @@ trait Foo { | |||
544 | struct S; | 580 | struct S; |
545 | impl Foo for S { | 581 | impl Foo for S { |
546 | <|>type Output; | 582 | <|>type Output; |
547 | fn foo(&self) { todo!() } | 583 | fn foo(&self) { |
584 | todo!() | ||
585 | } | ||
548 | }"#, | 586 | }"#, |
549 | ) | 587 | ) |
550 | } | 588 | } |
@@ -553,7 +591,7 @@ impl Foo for S { | |||
553 | fn test_default_methods() { | 591 | fn test_default_methods() { |
554 | check_assist( | 592 | check_assist( |
555 | add_missing_default_members, | 593 | add_missing_default_members, |
556 | " | 594 | r#" |
557 | trait Foo { | 595 | trait Foo { |
558 | type Output; | 596 | type Output; |
559 | 597 | ||
@@ -563,8 +601,8 @@ trait Foo { | |||
563 | fn foo(some: u32) -> bool; | 601 | fn foo(some: u32) -> bool; |
564 | } | 602 | } |
565 | struct S; | 603 | struct S; |
566 | impl Foo for S { <|> }", | 604 | impl Foo for S { <|> }"#, |
567 | " | 605 | r#" |
568 | trait Foo { | 606 | trait Foo { |
569 | type Output; | 607 | type Output; |
570 | 608 | ||
@@ -576,7 +614,7 @@ trait Foo { | |||
576 | struct S; | 614 | struct S; |
577 | impl Foo for S { | 615 | impl Foo for S { |
578 | <|>fn valid(some: u32) -> bool { false } | 616 | <|>fn valid(some: u32) -> bool { false } |
579 | }", | 617 | }"#, |
580 | ) | 618 | ) |
581 | } | 619 | } |
582 | } | 620 | } |
diff --git a/crates/ra_assists/src/handlers/early_return.rs b/crates/ra_assists/src/handlers/early_return.rs index ea6c56f8c..eede2fe91 100644 --- a/crates/ra_assists/src/handlers/early_return.rs +++ b/crates/ra_assists/src/handlers/early_return.rs | |||
@@ -2,7 +2,7 @@ use std::{iter::once, ops::RangeInclusive}; | |||
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | algo::replace_children, | 4 | algo::replace_children, |
5 | ast::{self, edit::IndentLevel, make, Block, Pat::TupleStructPat}, | 5 | ast::{self, edit::IndentLevel, make}, |
6 | AstNode, | 6 | AstNode, |
7 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, | 7 | SyntaxKind::{FN_DEF, LOOP_EXPR, L_CURLY, R_CURLY, WHILE_EXPR, WHITESPACE}, |
8 | SyntaxNode, | 8 | SyntaxNode, |
@@ -47,7 +47,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
47 | // Check if there is an IfLet that we can handle. | 47 | // Check if there is an IfLet that we can handle. |
48 | let if_let_pat = match cond.pat() { | 48 | let if_let_pat = match cond.pat() { |
49 | None => None, // No IfLet, supported. | 49 | None => None, // No IfLet, supported. |
50 | Some(TupleStructPat(pat)) if pat.args().count() == 1 => { | 50 | Some(ast::Pat::TupleStructPat(pat)) if pat.args().count() == 1 => { |
51 | let path = pat.path()?; | 51 | let path = pat.path()?; |
52 | match path.qualifier() { | 52 | match path.qualifier() { |
53 | None => { | 53 | None => { |
@@ -61,9 +61,9 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
61 | }; | 61 | }; |
62 | 62 | ||
63 | let cond_expr = cond.expr()?; | 63 | let cond_expr = cond.expr()?; |
64 | let then_block = if_expr.then_branch()?.block()?; | 64 | let then_block = if_expr.then_branch()?; |
65 | 65 | ||
66 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::Block::cast)?; | 66 | let parent_block = if_expr.syntax().parent()?.ancestors().find_map(ast::BlockExpr::cast)?; |
67 | 67 | ||
68 | if parent_block.expr()? != if_expr.clone().into() { | 68 | if parent_block.expr()? != if_expr.clone().into() { |
69 | return None; | 69 | return None; |
@@ -80,7 +80,7 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
80 | return None; | 80 | return None; |
81 | } | 81 | } |
82 | 82 | ||
83 | let parent_container = parent_block.syntax().parent()?.parent()?; | 83 | let parent_container = parent_block.syntax().parent()?; |
84 | 84 | ||
85 | let early_expression: ast::Expr = match parent_container.kind() { | 85 | let early_expression: ast::Expr = match parent_container.kind() { |
86 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), | 86 | WHILE_EXPR | LOOP_EXPR => make::expr_continue(), |
@@ -144,13 +144,13 @@ pub(crate) fn convert_to_guarded_return(ctx: AssistCtx) -> Option<Assist> { | |||
144 | } | 144 | } |
145 | }; | 145 | }; |
146 | edit.target(if_expr.syntax().text_range()); | 146 | edit.target(if_expr.syntax().text_range()); |
147 | edit.replace_ast(parent_block, ast::Block::cast(new_block).unwrap()); | 147 | edit.replace_ast(parent_block, ast::BlockExpr::cast(new_block).unwrap()); |
148 | edit.set_cursor(cursor_position); | 148 | edit.set_cursor(cursor_position); |
149 | 149 | ||
150 | fn replace( | 150 | fn replace( |
151 | new_expr: &SyntaxNode, | 151 | new_expr: &SyntaxNode, |
152 | then_block: &Block, | 152 | then_block: &ast::BlockExpr, |
153 | parent_block: &Block, | 153 | parent_block: &ast::BlockExpr, |
154 | if_expr: &ast::IfExpr, | 154 | if_expr: &ast::IfExpr, |
155 | ) -> SyntaxNode { | 155 | ) -> SyntaxNode { |
156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); | 156 | let then_block_items = IndentLevel::from(1).decrease_indent(then_block.clone()); |
diff --git a/crates/ra_assists/src/handlers/inline_local_variable.rs b/crates/ra_assists/src/handlers/inline_local_variable.rs index f5702f6e0..60ec536a7 100644 --- a/crates/ra_assists/src/handlers/inline_local_variable.rs +++ b/crates/ra_assists/src/handlers/inline_local_variable.rs | |||
@@ -89,6 +89,7 @@ pub(crate) fn inline_local_variable(ctx: AssistCtx) -> Option<Assist> { | |||
89 | | (ast::Expr::ParenExpr(_), _) | 89 | | (ast::Expr::ParenExpr(_), _) |
90 | | (ast::Expr::PathExpr(_), _) | 90 | | (ast::Expr::PathExpr(_), _) |
91 | | (ast::Expr::BlockExpr(_), _) | 91 | | (ast::Expr::BlockExpr(_), _) |
92 | | (ast::Expr::EffectExpr(_), _) | ||
92 | | (_, ast::Expr::CallExpr(_)) | 93 | | (_, ast::Expr::CallExpr(_)) |
93 | | (_, ast::Expr::TupleExpr(_)) | 94 | | (_, ast::Expr::TupleExpr(_)) |
94 | | (_, ast::Expr::ArrayExpr(_)) | 95 | | (_, ast::Expr::ArrayExpr(_)) |
diff --git a/crates/ra_assists/src/handlers/introduce_variable.rs b/crates/ra_assists/src/handlers/introduce_variable.rs index eda9ac296..39c656305 100644 --- a/crates/ra_assists/src/handlers/introduce_variable.rs +++ b/crates/ra_assists/src/handlers/introduce_variable.rs | |||
@@ -111,7 +111,7 @@ fn valid_target_expr(node: SyntaxNode) -> Option<ast::Expr> { | |||
111 | /// expression like a lambda or match arm. | 111 | /// expression like a lambda or match arm. |
112 | fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { | 112 | fn anchor_stmt(expr: ast::Expr) -> Option<(SyntaxNode, bool)> { |
113 | expr.syntax().ancestors().find_map(|node| { | 113 | expr.syntax().ancestors().find_map(|node| { |
114 | if let Some(expr) = node.parent().and_then(ast::Block::cast).and_then(|it| it.expr()) { | 114 | if let Some(expr) = node.parent().and_then(ast::BlockExpr::cast).and_then(|it| it.expr()) { |
115 | if expr.syntax() == &node { | 115 | if expr.syntax() == &node { |
116 | tested_by!(test_introduce_var_last_expr); | 116 | tested_by!(test_introduce_var_last_expr); |
117 | return Some((node, false)); | 117 | return Some((node, false)); |
diff --git a/crates/ra_assists/src/handlers/move_guard.rs b/crates/ra_assists/src/handlers/move_guard.rs index d5ccdd91c..b084dd9ee 100644 --- a/crates/ra_assists/src/handlers/move_guard.rs +++ b/crates/ra_assists/src/handlers/move_guard.rs | |||
@@ -113,9 +113,9 @@ pub(crate) fn move_arm_cond_to_match_guard(ctx: AssistCtx) -> Option<Assist> { | |||
113 | "Move condition to match guard", | 113 | "Move condition to match guard", |
114 | |edit| { | 114 | |edit| { |
115 | edit.target(if_expr.syntax().text_range()); | 115 | edit.target(if_expr.syntax().text_range()); |
116 | let then_only_expr = then_block.block().and_then(|it| it.statements().next()).is_none(); | 116 | let then_only_expr = then_block.statements().next().is_none(); |
117 | 117 | ||
118 | match &then_block.block().and_then(|it| it.expr()) { | 118 | match &then_block.expr() { |
119 | Some(then_expr) if then_only_expr => { | 119 | Some(then_expr) if then_only_expr => { |
120 | edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) | 120 | edit.replace(if_expr.syntax().text_range(), then_expr.syntax().text()) |
121 | } | 121 | } |
diff --git a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs index 0a0a88f3d..9841f6980 100644 --- a/crates/ra_assists/src/handlers/replace_if_let_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_if_let_with_match.rs | |||
@@ -1,11 +1,10 @@ | |||
1 | use ra_fmt::unwrap_trivial_block; | 1 | use ra_fmt::unwrap_trivial_block; |
2 | use ra_syntax::{ | 2 | use ra_syntax::{ |
3 | ast::{self, make}, | 3 | ast::{self, edit::IndentLevel, make}, |
4 | AstNode, | 4 | AstNode, |
5 | }; | 5 | }; |
6 | 6 | ||
7 | use crate::{Assist, AssistCtx, AssistId}; | 7 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; |
8 | use ast::edit::IndentLevel; | ||
9 | 8 | ||
10 | // Assist: replace_if_let_with_match | 9 | // Assist: replace_if_let_with_match |
11 | // | 10 | // |
@@ -44,15 +43,21 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
44 | ast::ElseBranch::IfExpr(_) => return None, | 43 | ast::ElseBranch::IfExpr(_) => return None, |
45 | }; | 44 | }; |
46 | 45 | ||
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", |edit| { | 46 | let sema = ctx.sema; |
47 | ctx.add_assist(AssistId("replace_if_let_with_match"), "Replace with match", move |edit| { | ||
48 | let match_expr = { | 48 | let match_expr = { |
49 | let then_arm = { | 49 | let then_arm = { |
50 | let then_expr = unwrap_trivial_block(then_block); | 50 | let then_expr = unwrap_trivial_block(then_block); |
51 | make::match_arm(vec![pat], then_expr) | 51 | make::match_arm(vec![pat.clone()], then_expr) |
52 | }; | 52 | }; |
53 | let else_arm = { | 53 | let else_arm = { |
54 | let pattern = sema | ||
55 | .type_of_pat(&pat) | ||
56 | .and_then(|ty| TryEnum::from_ty(sema, &ty)) | ||
57 | .map(|it| it.sad_pattern()) | ||
58 | .unwrap_or_else(|| make::placeholder_pat().into()); | ||
54 | let else_expr = unwrap_trivial_block(else_block); | 59 | let else_expr = unwrap_trivial_block(else_block); |
55 | make::match_arm(vec![make::placeholder_pat().into()], else_expr) | 60 | make::match_arm(vec![pattern], else_expr) |
56 | }; | 61 | }; |
57 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) | 62 | make::expr_match(expr, make::match_arm_list(vec![then_arm, else_arm])) |
58 | }; | 63 | }; |
@@ -68,6 +73,7 @@ pub(crate) fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
68 | #[cfg(test)] | 73 | #[cfg(test)] |
69 | mod tests { | 74 | mod tests { |
70 | use super::*; | 75 | use super::*; |
76 | |||
71 | use crate::helpers::{check_assist, check_assist_target}; | 77 | use crate::helpers::{check_assist, check_assist_target}; |
72 | 78 | ||
73 | #[test] | 79 | #[test] |
@@ -145,4 +151,64 @@ impl VariantData { | |||
145 | }", | 151 | }", |
146 | ); | 152 | ); |
147 | } | 153 | } |
154 | |||
155 | #[test] | ||
156 | fn special_case_option() { | ||
157 | check_assist( | ||
158 | replace_if_let_with_match, | ||
159 | r#" | ||
160 | enum Option<T> { Some(T), None } | ||
161 | use Option::*; | ||
162 | |||
163 | fn foo(x: Option<i32>) { | ||
164 | <|>if let Some(x) = x { | ||
165 | println!("{}", x) | ||
166 | } else { | ||
167 | println!("none") | ||
168 | } | ||
169 | } | ||
170 | "#, | ||
171 | r#" | ||
172 | enum Option<T> { Some(T), None } | ||
173 | use Option::*; | ||
174 | |||
175 | fn foo(x: Option<i32>) { | ||
176 | <|>match x { | ||
177 | Some(x) => println!("{}", x), | ||
178 | None => println!("none"), | ||
179 | } | ||
180 | } | ||
181 | "#, | ||
182 | ); | ||
183 | } | ||
184 | |||
185 | #[test] | ||
186 | fn special_case_result() { | ||
187 | check_assist( | ||
188 | replace_if_let_with_match, | ||
189 | r#" | ||
190 | enum Result<T, E> { Ok(T), Err(E) } | ||
191 | use Result::*; | ||
192 | |||
193 | fn foo(x: Result<i32, ()>) { | ||
194 | <|>if let Ok(x) = x { | ||
195 | println!("{}", x) | ||
196 | } else { | ||
197 | println!("none") | ||
198 | } | ||
199 | } | ||
200 | "#, | ||
201 | r#" | ||
202 | enum Result<T, E> { Ok(T), Err(E) } | ||
203 | use Result::*; | ||
204 | |||
205 | fn foo(x: Result<i32, ()>) { | ||
206 | <|>match x { | ||
207 | Ok(x) => println!("{}", x), | ||
208 | Err(_) => println!("none"), | ||
209 | } | ||
210 | } | ||
211 | "#, | ||
212 | ); | ||
213 | } | ||
148 | } | 214 | } |
diff --git a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs index bdbaae389..0cf23b754 100644 --- a/crates/ra_assists/src/handlers/replace_let_with_if_let.rs +++ b/crates/ra_assists/src/handlers/replace_let_with_if_let.rs | |||
@@ -1,6 +1,5 @@ | |||
1 | use std::iter::once; | 1 | use std::iter::once; |
2 | 2 | ||
3 | use hir::Adt; | ||
4 | use ra_syntax::{ | 3 | use ra_syntax::{ |
5 | ast::{ | 4 | ast::{ |
6 | self, | 5 | self, |
@@ -12,6 +11,7 @@ use ra_syntax::{ | |||
12 | 11 | ||
13 | use crate::{ | 12 | use crate::{ |
14 | assist_ctx::{Assist, AssistCtx}, | 13 | assist_ctx::{Assist, AssistCtx}, |
14 | utils::TryEnum, | ||
15 | AssistId, | 15 | AssistId, |
16 | }; | 16 | }; |
17 | 17 | ||
@@ -45,20 +45,10 @@ pub(crate) fn replace_let_with_if_let(ctx: AssistCtx) -> Option<Assist> { | |||
45 | let init = let_stmt.initializer()?; | 45 | let init = let_stmt.initializer()?; |
46 | let original_pat = let_stmt.pat()?; | 46 | let original_pat = let_stmt.pat()?; |
47 | let ty = ctx.sema.type_of_expr(&init)?; | 47 | let ty = ctx.sema.type_of_expr(&init)?; |
48 | let enum_ = match ty.as_adt() { | 48 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty).map(|it| it.happy_case()); |
49 | Some(Adt::Enum(it)) => it, | ||
50 | _ => return None, | ||
51 | }; | ||
52 | let happy_case = | ||
53 | [("Result", "Ok"), ("Option", "Some")].iter().find_map(|(known_type, happy_case)| { | ||
54 | if &enum_.name(ctx.db).to_string() == known_type { | ||
55 | return Some(happy_case); | ||
56 | } | ||
57 | None | ||
58 | }); | ||
59 | 49 | ||
60 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { | 50 | ctx.add_assist(AssistId("replace_let_with_if_let"), "Replace with if-let", |edit| { |
61 | let with_placeholder: ast::Pat = match happy_case { | 51 | let with_placeholder: ast::Pat = match happy_variant { |
62 | None => make::placeholder_pat().into(), | 52 | None => make::placeholder_pat().into(), |
63 | Some(var_name) => make::tuple_struct_pat( | 53 | Some(var_name) => make::tuple_struct_pat( |
64 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), | 54 | make::path_unqualified(make::path_segment(make::name_ref(var_name))), |
diff --git a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs index 2f02df303..918e8dd8d 100644 --- a/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs +++ b/crates/ra_assists/src/handlers/replace_qualified_name_with_use.rs | |||
@@ -27,7 +27,7 @@ pub(crate) fn replace_qualified_name_with_use(ctx: AssistCtx) -> Option<Assist> | |||
27 | return None; | 27 | return None; |
28 | } | 28 | } |
29 | 29 | ||
30 | let hir_path = hir::Path::from_ast(path.clone())?; | 30 | let hir_path = ctx.sema.lower_path(&path)?; |
31 | let segments = collect_hir_path_segments(&hir_path)?; | 31 | let segments = collect_hir_path_segments(&hir_path)?; |
32 | if segments.len() < 2 { | 32 | if segments.len() < 2 { |
33 | return None; | 33 | return None; |
diff --git a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs index 62cb7a763..62d4ea522 100644 --- a/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs +++ b/crates/ra_assists/src/handlers/replace_unwrap_with_match.rs | |||
@@ -1,12 +1,11 @@ | |||
1 | use std::iter; | 1 | use std::iter; |
2 | 2 | ||
3 | use ra_syntax::{ | 3 | use ra_syntax::{ |
4 | ast::{self, make}, | 4 | ast::{self, edit::IndentLevel, make}, |
5 | AstNode, | 5 | AstNode, |
6 | }; | 6 | }; |
7 | 7 | ||
8 | use crate::{Assist, AssistCtx, AssistId}; | 8 | use crate::{utils::TryEnum, Assist, AssistCtx, AssistId}; |
9 | use ast::edit::IndentLevel; | ||
10 | 9 | ||
11 | // Assist: replace_unwrap_with_match | 10 | // Assist: replace_unwrap_with_match |
12 | // | 11 | // |
@@ -38,42 +37,27 @@ pub(crate) fn replace_unwrap_with_match(ctx: AssistCtx) -> Option<Assist> { | |||
38 | } | 37 | } |
39 | let caller = method_call.expr()?; | 38 | let caller = method_call.expr()?; |
40 | let ty = ctx.sema.type_of_expr(&caller)?; | 39 | let ty = ctx.sema.type_of_expr(&caller)?; |
40 | let happy_variant = TryEnum::from_ty(ctx.sema, &ty)?.happy_case(); | ||
41 | 41 | ||
42 | let type_name = ty.as_adt()?.name(ctx.sema.db).to_string(); | 42 | ctx.add_assist(AssistId("replace_unwrap_with_match"), "Replace unwrap with match", |edit| { |
43 | let ok_path = make::path_unqualified(make::path_segment(make::name_ref(happy_variant))); | ||
44 | let it = make::bind_pat(make::name("a")).into(); | ||
45 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
43 | 46 | ||
44 | for (unwrap_type, variant_name) in [("Result", "Ok"), ("Option", "Some")].iter() { | 47 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); |
45 | if &type_name == unwrap_type { | 48 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); |
46 | return ctx.add_assist( | ||
47 | AssistId("replace_unwrap_with_match"), | ||
48 | "Replace unwrap with match", | ||
49 | |edit| { | ||
50 | let ok_path = | ||
51 | make::path_unqualified(make::path_segment(make::name_ref(variant_name))); | ||
52 | let it = make::bind_pat(make::name("a")).into(); | ||
53 | let ok_tuple = make::tuple_struct_pat(ok_path, iter::once(it)).into(); | ||
54 | 49 | ||
55 | let bind_path = make::path_unqualified(make::path_segment(make::name_ref("a"))); | 50 | let unreachable_call = make::unreachable_macro_call().into(); |
56 | let ok_arm = make::match_arm(iter::once(ok_tuple), make::expr_path(bind_path)); | 51 | let err_arm = make::match_arm(iter::once(make::placeholder_pat().into()), unreachable_call); |
57 | 52 | ||
58 | let unreachable_call = make::unreachable_macro_call().into(); | 53 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); |
59 | let err_arm = make::match_arm( | 54 | let match_expr = make::expr_match(caller.clone(), match_arm_list); |
60 | iter::once(make::placeholder_pat().into()), | 55 | let match_expr = IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); |
61 | unreachable_call, | ||
62 | ); | ||
63 | 56 | ||
64 | let match_arm_list = make::match_arm_list(vec![ok_arm, err_arm]); | 57 | edit.target(method_call.syntax().text_range()); |
65 | let match_expr = make::expr_match(caller.clone(), match_arm_list); | 58 | edit.set_cursor(caller.syntax().text_range().start()); |
66 | let match_expr = | 59 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); |
67 | IndentLevel::from_node(method_call.syntax()).increase_indent(match_expr); | 60 | }) |
68 | |||
69 | edit.target(method_call.syntax().text_range()); | ||
70 | edit.set_cursor(caller.syntax().text_range().start()); | ||
71 | edit.replace_ast::<ast::Expr>(method_call.into(), match_expr); | ||
72 | }, | ||
73 | ); | ||
74 | } | ||
75 | } | ||
76 | None | ||
77 | } | 61 | } |
78 | 62 | ||
79 | #[cfg(test)] | 63 | #[cfg(test)] |
diff --git a/crates/ra_assists/src/handlers/unwrap_block.rs b/crates/ra_assists/src/handlers/unwrap_block.rs new file mode 100644 index 000000000..58649c47e --- /dev/null +++ b/crates/ra_assists/src/handlers/unwrap_block.rs | |||
@@ -0,0 +1,348 @@ | |||
1 | use crate::{Assist, AssistCtx, AssistId}; | ||
2 | |||
3 | use ast::{BlockExpr, Expr, ForExpr, IfExpr, LoopBodyOwner, LoopExpr, WhileExpr}; | ||
4 | use ra_fmt::unwrap_trivial_block; | ||
5 | use ra_syntax::{ast, AstNode, TextRange, T}; | ||
6 | |||
7 | // Assist: unwrap_block | ||
8 | // | ||
9 | // This assist removes if...else, for, while and loop control statements to just keep the body. | ||
10 | // | ||
11 | // ``` | ||
12 | // fn foo() { | ||
13 | // if true {<|> | ||
14 | // println!("foo"); | ||
15 | // } | ||
16 | // } | ||
17 | // ``` | ||
18 | // -> | ||
19 | // ``` | ||
20 | // fn foo() { | ||
21 | // println!("foo"); | ||
22 | // } | ||
23 | // ``` | ||
24 | pub(crate) fn unwrap_block(ctx: AssistCtx) -> Option<Assist> { | ||
25 | let l_curly_token = ctx.find_token_at_offset(T!['{'])?; | ||
26 | |||
27 | let res = if let Some(if_expr) = l_curly_token.ancestors().find_map(IfExpr::cast) { | ||
28 | // if expression | ||
29 | let expr_to_unwrap = if_expr.blocks().find_map(|expr| extract_expr(ctx.frange.range, expr)); | ||
30 | let expr_to_unwrap = expr_to_unwrap?; | ||
31 | // Find if we are in a else if block | ||
32 | let ancestor = if_expr.syntax().ancestors().skip(1).find_map(ast::IfExpr::cast); | ||
33 | |||
34 | if let Some(ancestor) = ancestor { | ||
35 | Some((ast::Expr::IfExpr(ancestor), expr_to_unwrap)) | ||
36 | } else { | ||
37 | Some((ast::Expr::IfExpr(if_expr), expr_to_unwrap)) | ||
38 | } | ||
39 | } else if let Some(for_expr) = l_curly_token.ancestors().find_map(ForExpr::cast) { | ||
40 | // for expression | ||
41 | let block_expr = for_expr.loop_body()?; | ||
42 | extract_expr(ctx.frange.range, block_expr) | ||
43 | .map(|expr_to_unwrap| (ast::Expr::ForExpr(for_expr), expr_to_unwrap)) | ||
44 | } else if let Some(while_expr) = l_curly_token.ancestors().find_map(WhileExpr::cast) { | ||
45 | // while expression | ||
46 | let block_expr = while_expr.loop_body()?; | ||
47 | extract_expr(ctx.frange.range, block_expr) | ||
48 | .map(|expr_to_unwrap| (ast::Expr::WhileExpr(while_expr), expr_to_unwrap)) | ||
49 | } else if let Some(loop_expr) = l_curly_token.ancestors().find_map(LoopExpr::cast) { | ||
50 | // loop expression | ||
51 | let block_expr = loop_expr.loop_body()?; | ||
52 | extract_expr(ctx.frange.range, block_expr) | ||
53 | .map(|expr_to_unwrap| (ast::Expr::LoopExpr(loop_expr), expr_to_unwrap)) | ||
54 | } else { | ||
55 | None | ||
56 | }; | ||
57 | |||
58 | let (expr, expr_to_unwrap) = res?; | ||
59 | ctx.add_assist(AssistId("unwrap_block"), "Unwrap block", |edit| { | ||
60 | edit.set_cursor(expr.syntax().text_range().start()); | ||
61 | edit.target(expr_to_unwrap.syntax().text_range()); | ||
62 | |||
63 | let pat_start: &[_] = &[' ', '{', '\n']; | ||
64 | let expr_to_unwrap = expr_to_unwrap.to_string(); | ||
65 | let expr_string = expr_to_unwrap.trim_start_matches(pat_start); | ||
66 | let mut expr_string_lines: Vec<&str> = expr_string.lines().collect(); | ||
67 | expr_string_lines.pop(); // Delete last line | ||
68 | |||
69 | let expr_string = expr_string_lines | ||
70 | .into_iter() | ||
71 | .map(|line| line.replacen(" ", "", 1)) // Delete indentation | ||
72 | .collect::<Vec<String>>() | ||
73 | .join("\n"); | ||
74 | |||
75 | edit.replace(expr.syntax().text_range(), expr_string); | ||
76 | }) | ||
77 | } | ||
78 | |||
79 | fn extract_expr(cursor_range: TextRange, block: BlockExpr) -> Option<Expr> { | ||
80 | let cursor_in_range = block.l_curly_token()?.text_range().contains_range(cursor_range); | ||
81 | |||
82 | if cursor_in_range { | ||
83 | Some(unwrap_trivial_block(block)) | ||
84 | } else { | ||
85 | None | ||
86 | } | ||
87 | } | ||
88 | |||
89 | #[cfg(test)] | ||
90 | mod tests { | ||
91 | use crate::helpers::{check_assist, check_assist_not_applicable}; | ||
92 | |||
93 | use super::*; | ||
94 | |||
95 | #[test] | ||
96 | fn simple_if() { | ||
97 | check_assist( | ||
98 | unwrap_block, | ||
99 | r#" | ||
100 | fn main() { | ||
101 | bar(); | ||
102 | if true {<|> | ||
103 | foo(); | ||
104 | |||
105 | //comment | ||
106 | bar(); | ||
107 | } else { | ||
108 | println!("bar"); | ||
109 | } | ||
110 | } | ||
111 | "#, | ||
112 | r#" | ||
113 | fn main() { | ||
114 | bar(); | ||
115 | <|>foo(); | ||
116 | |||
117 | //comment | ||
118 | bar(); | ||
119 | } | ||
120 | "#, | ||
121 | ); | ||
122 | } | ||
123 | |||
124 | #[test] | ||
125 | fn simple_if_else() { | ||
126 | check_assist( | ||
127 | unwrap_block, | ||
128 | r#" | ||
129 | fn main() { | ||
130 | bar(); | ||
131 | if true { | ||
132 | foo(); | ||
133 | |||
134 | //comment | ||
135 | bar(); | ||
136 | } else {<|> | ||
137 | println!("bar"); | ||
138 | } | ||
139 | } | ||
140 | "#, | ||
141 | r#" | ||
142 | fn main() { | ||
143 | bar(); | ||
144 | <|>println!("bar"); | ||
145 | } | ||
146 | "#, | ||
147 | ); | ||
148 | } | ||
149 | |||
150 | #[test] | ||
151 | fn simple_if_else_if() { | ||
152 | check_assist( | ||
153 | unwrap_block, | ||
154 | r#" | ||
155 | fn main() { | ||
156 | //bar(); | ||
157 | if true { | ||
158 | println!("true"); | ||
159 | |||
160 | //comment | ||
161 | //bar(); | ||
162 | } else if false {<|> | ||
163 | println!("bar"); | ||
164 | } else { | ||
165 | println!("foo"); | ||
166 | } | ||
167 | } | ||
168 | "#, | ||
169 | r#" | ||
170 | fn main() { | ||
171 | //bar(); | ||
172 | <|>println!("bar"); | ||
173 | } | ||
174 | "#, | ||
175 | ); | ||
176 | } | ||
177 | |||
178 | #[test] | ||
179 | fn simple_if_bad_cursor_position() { | ||
180 | check_assist_not_applicable( | ||
181 | unwrap_block, | ||
182 | r#" | ||
183 | fn main() { | ||
184 | bar();<|> | ||
185 | if true { | ||
186 | foo(); | ||
187 | |||
188 | //comment | ||
189 | bar(); | ||
190 | } else { | ||
191 | println!("bar"); | ||
192 | } | ||
193 | } | ||
194 | "#, | ||
195 | ); | ||
196 | } | ||
197 | |||
198 | #[test] | ||
199 | fn simple_for() { | ||
200 | check_assist( | ||
201 | unwrap_block, | ||
202 | r#" | ||
203 | fn main() { | ||
204 | for i in 0..5 {<|> | ||
205 | if true { | ||
206 | foo(); | ||
207 | |||
208 | //comment | ||
209 | bar(); | ||
210 | } else { | ||
211 | println!("bar"); | ||
212 | } | ||
213 | } | ||
214 | } | ||
215 | "#, | ||
216 | r#" | ||
217 | fn main() { | ||
218 | <|>if true { | ||
219 | foo(); | ||
220 | |||
221 | //comment | ||
222 | bar(); | ||
223 | } else { | ||
224 | println!("bar"); | ||
225 | } | ||
226 | } | ||
227 | "#, | ||
228 | ); | ||
229 | } | ||
230 | |||
231 | #[test] | ||
232 | fn simple_if_in_for() { | ||
233 | check_assist( | ||
234 | unwrap_block, | ||
235 | r#" | ||
236 | fn main() { | ||
237 | for i in 0..5 { | ||
238 | if true {<|> | ||
239 | foo(); | ||
240 | |||
241 | //comment | ||
242 | bar(); | ||
243 | } else { | ||
244 | println!("bar"); | ||
245 | } | ||
246 | } | ||
247 | } | ||
248 | "#, | ||
249 | r#" | ||
250 | fn main() { | ||
251 | for i in 0..5 { | ||
252 | <|>foo(); | ||
253 | |||
254 | //comment | ||
255 | bar(); | ||
256 | } | ||
257 | } | ||
258 | "#, | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | #[test] | ||
263 | fn simple_loop() { | ||
264 | check_assist( | ||
265 | unwrap_block, | ||
266 | r#" | ||
267 | fn main() { | ||
268 | loop {<|> | ||
269 | if true { | ||
270 | foo(); | ||
271 | |||
272 | //comment | ||
273 | bar(); | ||
274 | } else { | ||
275 | println!("bar"); | ||
276 | } | ||
277 | } | ||
278 | } | ||
279 | "#, | ||
280 | r#" | ||
281 | fn main() { | ||
282 | <|>if true { | ||
283 | foo(); | ||
284 | |||
285 | //comment | ||
286 | bar(); | ||
287 | } else { | ||
288 | println!("bar"); | ||
289 | } | ||
290 | } | ||
291 | "#, | ||
292 | ); | ||
293 | } | ||
294 | |||
295 | #[test] | ||
296 | fn simple_while() { | ||
297 | check_assist( | ||
298 | unwrap_block, | ||
299 | r#" | ||
300 | fn main() { | ||
301 | while true {<|> | ||
302 | if true { | ||
303 | foo(); | ||
304 | |||
305 | //comment | ||
306 | bar(); | ||
307 | } else { | ||
308 | println!("bar"); | ||
309 | } | ||
310 | } | ||
311 | } | ||
312 | "#, | ||
313 | r#" | ||
314 | fn main() { | ||
315 | <|>if true { | ||
316 | foo(); | ||
317 | |||
318 | //comment | ||
319 | bar(); | ||
320 | } else { | ||
321 | println!("bar"); | ||
322 | } | ||
323 | } | ||
324 | "#, | ||
325 | ); | ||
326 | } | ||
327 | |||
328 | #[test] | ||
329 | fn simple_if_in_while_bad_cursor_position() { | ||
330 | check_assist_not_applicable( | ||
331 | unwrap_block, | ||
332 | r#" | ||
333 | fn main() { | ||
334 | while true { | ||
335 | if true { | ||
336 | foo();<|> | ||
337 | |||
338 | //comment | ||
339 | bar(); | ||
340 | } else { | ||
341 | println!("bar"); | ||
342 | } | ||
343 | } | ||
344 | } | ||
345 | "#, | ||
346 | ); | ||
347 | } | ||
348 | } | ||
diff --git a/crates/ra_assists/src/lib.rs b/crates/ra_assists/src/lib.rs index 64bd87afb..c5df86600 100644 --- a/crates/ra_assists/src/lib.rs +++ b/crates/ra_assists/src/lib.rs | |||
@@ -143,6 +143,7 @@ mod handlers { | |||
143 | mod split_import; | 143 | mod split_import; |
144 | mod add_from_impl_for_enum; | 144 | mod add_from_impl_for_enum; |
145 | mod reorder_fields; | 145 | mod reorder_fields; |
146 | mod unwrap_block; | ||
146 | 147 | ||
147 | pub(crate) fn all() -> &'static [AssistHandler] { | 148 | pub(crate) fn all() -> &'static [AssistHandler] { |
148 | &[ | 149 | &[ |
@@ -181,6 +182,7 @@ mod handlers { | |||
181 | replace_unwrap_with_match::replace_unwrap_with_match, | 182 | replace_unwrap_with_match::replace_unwrap_with_match, |
182 | split_import::split_import, | 183 | split_import::split_import, |
183 | add_from_impl_for_enum::add_from_impl_for_enum, | 184 | add_from_impl_for_enum::add_from_impl_for_enum, |
185 | unwrap_block::unwrap_block, | ||
184 | // These are manually sorted for better priorities | 186 | // These are manually sorted for better priorities |
185 | add_missing_impl_members::add_missing_impl_members, | 187 | add_missing_impl_members::add_missing_impl_members, |
186 | add_missing_impl_members::add_missing_default_members, | 188 | add_missing_impl_members::add_missing_default_members, |
diff --git a/crates/ra_assists/src/marks.rs b/crates/ra_assists/src/marks.rs index 6c2a2b8b6..8d910205f 100644 --- a/crates/ra_assists/src/marks.rs +++ b/crates/ra_assists/src/marks.rs | |||
@@ -8,4 +8,5 @@ test_utils::marks![ | |||
8 | test_not_inline_mut_variable | 8 | test_not_inline_mut_variable |
9 | test_not_applicable_if_variable_unused | 9 | test_not_applicable_if_variable_unused |
10 | change_visibility_field_false_positive | 10 | change_visibility_field_false_positive |
11 | test_add_from_impl_already_exists | ||
11 | ]; | 12 | ]; |
diff --git a/crates/ra_assists/src/utils.rs b/crates/ra_assists/src/utils.rs index 3d6c59bda..efd988697 100644 --- a/crates/ra_assists/src/utils.rs +++ b/crates/ra_assists/src/utils.rs | |||
@@ -1,7 +1,9 @@ | |||
1 | //! Assorted functions shared by several assists. | 1 | //! Assorted functions shared by several assists. |
2 | pub(crate) mod insert_use; | 2 | pub(crate) mod insert_use; |
3 | 3 | ||
4 | use hir::Semantics; | 4 | use std::iter; |
5 | |||
6 | use hir::{Adt, Crate, Semantics, Trait, Type}; | ||
5 | use ra_ide_db::RootDatabase; | 7 | use ra_ide_db::RootDatabase; |
6 | use ra_syntax::{ | 8 | use ra_syntax::{ |
7 | ast::{self, make, NameOwner}, | 9 | ast::{self, make, NameOwner}, |
@@ -99,3 +101,109 @@ fn invert_special_case(expr: &ast::Expr) -> Option<ast::Expr> { | |||
99 | _ => None, | 101 | _ => None, |
100 | } | 102 | } |
101 | } | 103 | } |
104 | |||
105 | #[derive(Clone, Copy)] | ||
106 | pub(crate) enum TryEnum { | ||
107 | Result, | ||
108 | Option, | ||
109 | } | ||
110 | |||
111 | impl TryEnum { | ||
112 | const ALL: [TryEnum; 2] = [TryEnum::Option, TryEnum::Result]; | ||
113 | |||
114 | pub(crate) fn from_ty(sema: &Semantics<RootDatabase>, ty: &Type) -> Option<TryEnum> { | ||
115 | let enum_ = match ty.as_adt() { | ||
116 | Some(Adt::Enum(it)) => it, | ||
117 | _ => return None, | ||
118 | }; | ||
119 | TryEnum::ALL.iter().find_map(|&var| { | ||
120 | if &enum_.name(sema.db).to_string() == var.type_name() { | ||
121 | return Some(var); | ||
122 | } | ||
123 | None | ||
124 | }) | ||
125 | } | ||
126 | |||
127 | pub(crate) fn happy_case(self) -> &'static str { | ||
128 | match self { | ||
129 | TryEnum::Result => "Ok", | ||
130 | TryEnum::Option => "Some", | ||
131 | } | ||
132 | } | ||
133 | |||
134 | pub(crate) fn sad_pattern(self) -> ast::Pat { | ||
135 | match self { | ||
136 | TryEnum::Result => make::tuple_struct_pat( | ||
137 | make::path_unqualified(make::path_segment(make::name_ref("Err"))), | ||
138 | iter::once(make::placeholder_pat().into()), | ||
139 | ) | ||
140 | .into(), | ||
141 | TryEnum::Option => make::bind_pat(make::name("None")).into(), | ||
142 | } | ||
143 | } | ||
144 | |||
145 | fn type_name(self) -> &'static str { | ||
146 | match self { | ||
147 | TryEnum::Result => "Result", | ||
148 | TryEnum::Option => "Option", | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
153 | /// Helps with finding well-know things inside the standard library. This is | ||
154 | /// somewhat similar to the known paths infra inside hir, but it different; We | ||
155 | /// want to make sure that IDE specific paths don't become interesting inside | ||
156 | /// the compiler itself as well. | ||
157 | pub(crate) struct FamousDefs<'a, 'b>(pub(crate) &'a Semantics<'b, RootDatabase>, pub(crate) Crate); | ||
158 | |||
159 | #[allow(non_snake_case)] | ||
160 | impl FamousDefs<'_, '_> { | ||
161 | #[cfg(test)] | ||
162 | pub(crate) const FIXTURE: &'static str = r#" | ||
163 | //- /libcore.rs crate:core | ||
164 | pub mod convert{ | ||
165 | pub trait From<T> { | ||
166 | fn from(T) -> Self; | ||
167 | } | ||
168 | } | ||
169 | |||
170 | pub mod prelude { pub use crate::convert::From } | ||
171 | #[prelude_import] | ||
172 | pub use prelude::*; | ||
173 | "#; | ||
174 | |||
175 | pub(crate) fn core_convert_From(&self) -> Option<Trait> { | ||
176 | self.find_trait("core:convert:From") | ||
177 | } | ||
178 | |||
179 | fn find_trait(&self, path: &str) -> Option<Trait> { | ||
180 | let db = self.0.db; | ||
181 | let mut path = path.split(':'); | ||
182 | let trait_ = path.next_back()?; | ||
183 | let std_crate = path.next()?; | ||
184 | let std_crate = self | ||
185 | .1 | ||
186 | .dependencies(db) | ||
187 | .into_iter() | ||
188 | .find(|dep| &dep.name.to_string() == std_crate)? | ||
189 | .krate; | ||
190 | |||
191 | let mut module = std_crate.root_module(db)?; | ||
192 | for segment in path { | ||
193 | module = module.children(db).find_map(|child| { | ||
194 | let name = child.name(db)?; | ||
195 | if &name.to_string() == segment { | ||
196 | Some(child) | ||
197 | } else { | ||
198 | None | ||
199 | } | ||
200 | })?; | ||
201 | } | ||
202 | let def = | ||
203 | module.scope(db, None).into_iter().find(|(name, _def)| &name.to_string() == trait_)?.1; | ||
204 | match def { | ||
205 | hir::ScopeDef::ModuleDef(hir::ModuleDef::Trait(it)) => Some(it), | ||
206 | _ => None, | ||
207 | } | ||
208 | } | ||
209 | } | ||
diff --git a/crates/ra_flycheck/Cargo.toml b/crates/ra_flycheck/Cargo.toml index 76e5cada4..324c33d9d 100644 --- a/crates/ra_flycheck/Cargo.toml +++ b/crates/ra_flycheck/Cargo.toml | |||
@@ -6,7 +6,7 @@ authors = ["rust-analyzer developers"] | |||
6 | 6 | ||
7 | [dependencies] | 7 | [dependencies] |
8 | crossbeam-channel = "0.4.0" | 8 | crossbeam-channel = "0.4.0" |
9 | lsp-types = { version = "0.73.0", features = ["proposed"] } | 9 | lsp-types = { version = "0.74.0", features = ["proposed"] } |
10 | log = "0.4.8" | 10 | log = "0.4.8" |
11 | cargo_metadata = "0.9.1" | 11 | cargo_metadata = "0.9.1" |
12 | serde_json = "1.0.48" | 12 | serde_json = "1.0.48" |
diff --git a/crates/ra_fmt/src/lib.rs b/crates/ra_fmt/src/lib.rs index 0b4ba1bbe..f910ded9d 100644 --- a/crates/ra_fmt/src/lib.rs +++ b/crates/ra_fmt/src/lib.rs | |||
@@ -42,7 +42,6 @@ pub fn unwrap_trivial_block(block: ast::BlockExpr) -> ast::Expr { | |||
42 | } | 42 | } |
43 | 43 | ||
44 | pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | 44 | pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { |
45 | let block = block.block()?; | ||
46 | let has_anything_else = |thing: &SyntaxNode| -> bool { | 45 | let has_anything_else = |thing: &SyntaxNode| -> bool { |
47 | let mut non_trivial_children = | 46 | let mut non_trivial_children = |
48 | block.syntax().children_with_tokens().filter(|it| match it.kind() { | 47 | block.syntax().children_with_tokens().filter(|it| match it.kind() { |
@@ -57,18 +56,17 @@ pub fn extract_trivial_expression(block: &ast::BlockExpr) -> Option<ast::Expr> { | |||
57 | return None; | 56 | return None; |
58 | } | 57 | } |
59 | return Some(expr); | 58 | return Some(expr); |
60 | } else { | 59 | } |
61 | // Unwrap `{ continue; }` | 60 | // Unwrap `{ continue; }` |
62 | let (stmt,) = block.statements().next_tuple()?; | 61 | let (stmt,) = block.statements().next_tuple()?; |
63 | if let ast::Stmt::ExprStmt(expr_stmt) = stmt { | 62 | if let ast::Stmt::ExprStmt(expr_stmt) = stmt { |
64 | if has_anything_else(expr_stmt.syntax()) { | 63 | if has_anything_else(expr_stmt.syntax()) { |
65 | return None; | 64 | return None; |
66 | } | 65 | } |
67 | let expr = expr_stmt.expr()?; | 66 | let expr = expr_stmt.expr()?; |
68 | match expr.syntax().kind() { | 67 | match expr.syntax().kind() { |
69 | CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), | 68 | CONTINUE_EXPR | BREAK_EXPR | RETURN_EXPR => return Some(expr), |
70 | _ => (), | 69 | _ => (), |
71 | } | ||
72 | } | 70 | } |
73 | } | 71 | } |
74 | None | 72 | None |
diff --git a/crates/ra_hir/src/code_model.rs b/crates/ra_hir/src/code_model.rs index fb788736d..af59aa1b6 100644 --- a/crates/ra_hir/src/code_model.rs +++ b/crates/ra_hir/src/code_model.rs | |||
@@ -953,6 +953,16 @@ impl TypeParam { | |||
953 | pub fn module(self, db: &dyn HirDatabase) -> Module { | 953 | pub fn module(self, db: &dyn HirDatabase) -> Module { |
954 | self.id.parent.module(db.upcast()).into() | 954 | self.id.parent.module(db.upcast()).into() |
955 | } | 955 | } |
956 | |||
957 | pub fn ty(self, db: &dyn HirDatabase) -> Type { | ||
958 | let resolver = self.id.parent.resolver(db.upcast()); | ||
959 | let environment = TraitEnvironment::lower(db, &resolver); | ||
960 | let ty = Ty::Placeholder(self.id); | ||
961 | Type { | ||
962 | krate: self.id.parent.module(db.upcast()).krate, | ||
963 | ty: InEnvironment { value: ty, environment }, | ||
964 | } | ||
965 | } | ||
956 | } | 966 | } |
957 | 967 | ||
958 | // FIXME: rename from `ImplDef` to `Impl` | 968 | // FIXME: rename from `ImplDef` to `Impl` |
@@ -1157,18 +1167,21 @@ impl Type { | |||
1157 | 1167 | ||
1158 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { | 1168 | pub fn fields(&self, db: &dyn HirDatabase) -> Vec<(Field, Type)> { |
1159 | if let Ty::Apply(a_ty) = &self.ty.value { | 1169 | if let Ty::Apply(a_ty) = &self.ty.value { |
1160 | if let TypeCtor::Adt(AdtId::StructId(s)) = a_ty.ctor { | 1170 | let variant_id = match a_ty.ctor { |
1161 | let var_def = s.into(); | 1171 | TypeCtor::Adt(AdtId::StructId(s)) => s.into(), |
1162 | return db | 1172 | TypeCtor::Adt(AdtId::UnionId(u)) => u.into(), |
1163 | .field_types(var_def) | 1173 | _ => return Vec::new(), |
1164 | .iter() | 1174 | }; |
1165 | .map(|(local_id, ty)| { | 1175 | |
1166 | let def = Field { parent: var_def.into(), id: local_id }; | 1176 | return db |
1167 | let ty = ty.clone().subst(&a_ty.parameters); | 1177 | .field_types(variant_id) |
1168 | (def, self.derived(ty)) | 1178 | .iter() |
1169 | }) | 1179 | .map(|(local_id, ty)| { |
1170 | .collect(); | 1180 | let def = Field { parent: variant_id.into(), id: local_id }; |
1171 | } | 1181 | let ty = ty.clone().subst(&a_ty.parameters); |
1182 | (def, self.derived(ty)) | ||
1183 | }) | ||
1184 | .collect(); | ||
1172 | }; | 1185 | }; |
1173 | Vec::new() | 1186 | Vec::new() |
1174 | } | 1187 | } |
diff --git a/crates/ra_hir/src/lib.rs b/crates/ra_hir/src/lib.rs index 312ef3814..c5df4ac24 100644 --- a/crates/ra_hir/src/lib.rs +++ b/crates/ra_hir/src/lib.rs | |||
@@ -70,6 +70,7 @@ pub use hir_def::{ | |||
70 | type_ref::Mutability, | 70 | type_ref::Mutability, |
71 | }; | 71 | }; |
72 | pub use hir_expand::{ | 72 | pub use hir_expand::{ |
73 | name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, MacroFile, Origin, | 73 | hygiene::Hygiene, name::Name, HirFileId, InFile, MacroCallId, MacroCallLoc, MacroDefId, |
74 | MacroFile, Origin, | ||
74 | }; | 75 | }; |
75 | pub use hir_ty::{display::HirDisplay, CallableDef}; | 76 | pub use hir_ty::{display::HirDisplay, CallableDef}; |
diff --git a/crates/ra_hir/src/semantics.rs b/crates/ra_hir/src/semantics.rs index 86bfb416c..515e5eb17 100644 --- a/crates/ra_hir/src/semantics.rs +++ b/crates/ra_hir/src/semantics.rs | |||
@@ -8,7 +8,8 @@ use hir_def::{ | |||
8 | resolver::{self, HasResolver, Resolver}, | 8 | resolver::{self, HasResolver, Resolver}, |
9 | AsMacroCall, TraitId, | 9 | AsMacroCall, TraitId, |
10 | }; | 10 | }; |
11 | use hir_expand::ExpansionInfo; | 11 | use hir_expand::{hygiene::Hygiene, ExpansionInfo}; |
12 | use hir_ty::associated_type_shorthand_candidates; | ||
12 | use itertools::Itertools; | 13 | use itertools::Itertools; |
13 | use ra_db::{FileId, FileRange}; | 14 | use ra_db::{FileId, FileRange}; |
14 | use ra_prof::profile; | 15 | use ra_prof::profile; |
@@ -24,8 +25,9 @@ use crate::{ | |||
24 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, | 25 | semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx}, |
25 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, | 26 | source_analyzer::{resolve_hir_path, SourceAnalyzer}, |
26 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, | 27 | AssocItem, Field, Function, HirFileId, ImplDef, InFile, Local, MacroDef, Module, ModuleDef, |
27 | Name, Origin, Path, ScopeDef, Trait, Type, TypeParam, | 28 | Name, Origin, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam, |
28 | }; | 29 | }; |
30 | use resolver::TypeNs; | ||
29 | 31 | ||
30 | #[derive(Debug, Clone, PartialEq, Eq)] | 32 | #[derive(Debug, Clone, PartialEq, Eq)] |
31 | pub enum PathResolution { | 33 | pub enum PathResolution { |
@@ -40,6 +42,44 @@ pub enum PathResolution { | |||
40 | AssocItem(AssocItem), | 42 | AssocItem(AssocItem), |
41 | } | 43 | } |
42 | 44 | ||
45 | impl PathResolution { | ||
46 | fn in_type_ns(&self) -> Option<TypeNs> { | ||
47 | match self { | ||
48 | PathResolution::Def(ModuleDef::Adt(adt)) => Some(TypeNs::AdtId((*adt).into())), | ||
49 | PathResolution::Def(ModuleDef::BuiltinType(builtin)) => { | ||
50 | Some(TypeNs::BuiltinType(*builtin)) | ||
51 | } | ||
52 | PathResolution::Def(ModuleDef::Const(_)) | ||
53 | | PathResolution::Def(ModuleDef::EnumVariant(_)) | ||
54 | | PathResolution::Def(ModuleDef::Function(_)) | ||
55 | | PathResolution::Def(ModuleDef::Module(_)) | ||
56 | | PathResolution::Def(ModuleDef::Static(_)) | ||
57 | | PathResolution::Def(ModuleDef::Trait(_)) => None, | ||
58 | PathResolution::Def(ModuleDef::TypeAlias(alias)) => { | ||
59 | Some(TypeNs::TypeAliasId((*alias).into())) | ||
60 | } | ||
61 | PathResolution::Local(_) | PathResolution::Macro(_) => None, | ||
62 | PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())), | ||
63 | PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())), | ||
64 | PathResolution::AssocItem(AssocItem::Const(_)) | ||
65 | | PathResolution::AssocItem(AssocItem::Function(_)) => None, | ||
66 | PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => { | ||
67 | Some(TypeNs::TypeAliasId((*alias).into())) | ||
68 | } | ||
69 | } | ||
70 | } | ||
71 | |||
72 | /// Returns an iterator over associated types that may be specified after this path (using | ||
73 | /// `Ty::Assoc` syntax). | ||
74 | pub fn assoc_type_shorthand_candidates<R>( | ||
75 | &self, | ||
76 | db: &dyn HirDatabase, | ||
77 | mut cb: impl FnMut(TypeAlias) -> Option<R>, | ||
78 | ) -> Option<R> { | ||
79 | associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into())) | ||
80 | } | ||
81 | } | ||
82 | |||
43 | /// Primary API to get semantic information, like types, from syntax trees. | 83 | /// Primary API to get semantic information, like types, from syntax trees. |
44 | pub struct Semantics<'db, DB> { | 84 | pub struct Semantics<'db, DB> { |
45 | pub db: &'db DB, | 85 | pub db: &'db DB, |
@@ -206,6 +246,11 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> { | |||
206 | self.analyze(path.syntax()).resolve_path(self.db, path) | 246 | self.analyze(path.syntax()).resolve_path(self.db, path) |
207 | } | 247 | } |
208 | 248 | ||
249 | pub fn lower_path(&self, path: &ast::Path) -> Option<Path> { | ||
250 | let src = self.find_file(path.syntax().clone()); | ||
251 | Path::from_src(path.clone(), &Hygiene::new(self.db.upcast(), src.file_id.into())) | ||
252 | } | ||
253 | |||
209 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { | 254 | pub fn resolve_bind_pat_to_const(&self, pat: &ast::BindPat) -> Option<ModuleDef> { |
210 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) | 255 | self.analyze(pat.syntax()).resolve_bind_pat_to_const(self.db, pat) |
211 | } | 256 | } |
diff --git a/crates/ra_hir/src/semantics/source_to_def.rs b/crates/ra_hir/src/semantics/source_to_def.rs index 6f3b5b2da..8af64fdc1 100644 --- a/crates/ra_hir/src/semantics/source_to_def.rs +++ b/crates/ra_hir/src/semantics/source_to_def.rs | |||
@@ -151,7 +151,7 @@ impl SourceToDefCtx<'_, '_> { | |||
151 | let krate = self.file_to_def(file_id)?.krate; | 151 | let krate = self.file_to_def(file_id)?.krate; |
152 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); | 152 | let file_ast_id = self.db.ast_id_map(src.file_id).ast_id(&src.value); |
153 | let ast_id = Some(AstId::new(src.file_id, file_ast_id)); | 153 | let ast_id = Some(AstId::new(src.file_id, file_ast_id)); |
154 | Some(MacroDefId { krate: Some(krate), ast_id, kind }) | 154 | Some(MacroDefId { krate: Some(krate), ast_id, kind, local_inner: false }) |
155 | } | 155 | } |
156 | 156 | ||
157 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { | 157 | pub(super) fn find_container(&mut self, src: InFile<&SyntaxNode>) -> Option<ChildContainer> { |
diff --git a/crates/ra_hir/src/source_analyzer.rs b/crates/ra_hir/src/source_analyzer.rs index 74d64c97d..c63d1b847 100644 --- a/crates/ra_hir/src/source_analyzer.rs +++ b/crates/ra_hir/src/source_analyzer.rs | |||
@@ -224,7 +224,8 @@ impl SourceAnalyzer { | |||
224 | } | 224 | } |
225 | } | 225 | } |
226 | // This must be a normal source file rather than macro file. | 226 | // This must be a normal source file rather than macro file. |
227 | let hir_path = crate::Path::from_ast(path.clone())?; | 227 | let hir_path = |
228 | crate::Path::from_src(path.clone(), &Hygiene::new(db.upcast(), self.file_id))?; | ||
228 | resolve_hir_path(db, &self.resolver, &hir_path) | 229 | resolve_hir_path(db, &self.resolver, &hir_path) |
229 | } | 230 | } |
230 | 231 | ||
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 753becc3d..8eef51828 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -12,9 +12,15 @@ use ra_prof::profile; | |||
12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; | 12 | use ra_syntax::ast::{self, NameOwner, TypeAscriptionOwner, VisibilityOwner}; |
13 | 13 | ||
14 | use crate::{ | 14 | use crate::{ |
15 | body::CfgExpander, db::DefDatabase, src::HasChildSource, src::HasSource, trace::Trace, | 15 | body::{CfgExpander, LowerCtx}, |
16 | type_ref::TypeRef, visibility::RawVisibility, EnumId, HasModule, LocalEnumVariantId, | 16 | db::DefDatabase, |
17 | LocalFieldId, Lookup, ModuleId, StructId, UnionId, VariantId, | 17 | src::HasChildSource, |
18 | src::HasSource, | ||
19 | trace::Trace, | ||
20 | type_ref::TypeRef, | ||
21 | visibility::RawVisibility, | ||
22 | EnumId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StructId, UnionId, | ||
23 | VariantId, | ||
18 | }; | 24 | }; |
19 | 25 | ||
20 | /// Note that we use `StructData` for unions as well! | 26 | /// Note that we use `StructData` for unions as well! |
@@ -198,6 +204,8 @@ fn lower_struct( | |||
198 | trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, | 204 | trace: &mut Trace<FieldData, Either<ast::TupleFieldDef, ast::RecordFieldDef>>, |
199 | ast: &InFile<ast::StructKind>, | 205 | ast: &InFile<ast::StructKind>, |
200 | ) -> StructKind { | 206 | ) -> StructKind { |
207 | let ctx = LowerCtx::new(db, ast.file_id); | ||
208 | |||
201 | match &ast.value { | 209 | match &ast.value { |
202 | ast::StructKind::Tuple(fl) => { | 210 | ast::StructKind::Tuple(fl) => { |
203 | for (i, fd) in fl.fields().enumerate() { | 211 | for (i, fd) in fl.fields().enumerate() { |
@@ -210,7 +218,7 @@ fn lower_struct( | |||
210 | || Either::Left(fd.clone()), | 218 | || Either::Left(fd.clone()), |
211 | || FieldData { | 219 | || FieldData { |
212 | name: Name::new_tuple_field(i), | 220 | name: Name::new_tuple_field(i), |
213 | type_ref: TypeRef::from_ast_opt(fd.type_ref()), | 221 | type_ref: TypeRef::from_ast_opt(&ctx, fd.type_ref()), |
214 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 222 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
215 | }, | 223 | }, |
216 | ); | 224 | ); |
@@ -228,7 +236,7 @@ fn lower_struct( | |||
228 | || Either::Right(fd.clone()), | 236 | || Either::Right(fd.clone()), |
229 | || FieldData { | 237 | || FieldData { |
230 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), | 238 | name: fd.name().map(|n| n.as_name()).unwrap_or_else(Name::missing), |
231 | type_ref: TypeRef::from_ast_opt(fd.ascribed_type()), | 239 | type_ref: TypeRef::from_ast_opt(&ctx, fd.ascribed_type()), |
232 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), | 240 | visibility: RawVisibility::from_ast(db, ast.with_value(fd.visibility())), |
233 | }, | 241 | }, |
234 | ); | 242 | ); |
diff --git a/crates/ra_hir_def/src/attr.rs b/crates/ra_hir_def/src/attr.rs index 5a86af8ba..576cd0c65 100644 --- a/crates/ra_hir_def/src/attr.rs +++ b/crates/ra_hir_def/src/attr.rs | |||
@@ -140,6 +140,7 @@ impl Attr { | |||
140 | } | 140 | } |
141 | } | 141 | } |
142 | 142 | ||
143 | #[derive(Debug, Clone, Copy)] | ||
143 | pub struct AttrQuery<'a> { | 144 | pub struct AttrQuery<'a> { |
144 | attrs: &'a Attrs, | 145 | attrs: &'a Attrs, |
145 | key: &'static str, | 146 | key: &'static str, |
diff --git a/crates/ra_hir_def/src/body.rs b/crates/ra_hir_def/src/body.rs index 890cefcaf..4edaad960 100644 --- a/crates/ra_hir_def/src/body.rs +++ b/crates/ra_hir_def/src/body.rs | |||
@@ -15,6 +15,8 @@ use ra_prof::profile; | |||
15 | use ra_syntax::{ast, AstNode, AstPtr}; | 15 | use ra_syntax::{ast, AstNode, AstPtr}; |
16 | use rustc_hash::FxHashMap; | 16 | use rustc_hash::FxHashMap; |
17 | 17 | ||
18 | pub(crate) use lower::LowerCtx; | ||
19 | |||
18 | use crate::{ | 20 | use crate::{ |
19 | attr::Attrs, | 21 | attr::Attrs, |
20 | db::DefDatabase, | 22 | db::DefDatabase, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index 571603854..687216dc3 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -3,8 +3,9 @@ | |||
3 | 3 | ||
4 | use either::Either; | 4 | use either::Either; |
5 | use hir_expand::{ | 5 | use hir_expand::{ |
6 | hygiene::Hygiene, | ||
6 | name::{name, AsName, Name}, | 7 | name::{name, AsName, Name}, |
7 | MacroDefId, MacroDefKind, | 8 | HirFileId, MacroDefId, MacroDefKind, |
8 | }; | 9 | }; |
9 | use ra_arena::Arena; | 10 | use ra_arena::Arena; |
10 | use ra_syntax::{ | 11 | use ra_syntax::{ |
@@ -26,7 +27,7 @@ use crate::{ | |||
26 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 27 | LogicOp, MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
27 | }, | 28 | }, |
28 | item_scope::BuiltinShadowMode, | 29 | item_scope::BuiltinShadowMode, |
29 | path::GenericArgs, | 30 | path::{GenericArgs, Path}, |
30 | type_ref::{Mutability, TypeRef}, | 31 | type_ref::{Mutability, TypeRef}, |
31 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, | 32 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
32 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 33 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
@@ -35,6 +36,23 @@ use crate::{ | |||
35 | use super::{ExprSource, PatSource}; | 36 | use super::{ExprSource, PatSource}; |
36 | use ast::AstChildren; | 37 | use ast::AstChildren; |
37 | 38 | ||
39 | pub(crate) struct LowerCtx { | ||
40 | hygiene: Hygiene, | ||
41 | } | ||
42 | |||
43 | impl LowerCtx { | ||
44 | pub fn new(db: &dyn DefDatabase, file_id: HirFileId) -> Self { | ||
45 | LowerCtx { hygiene: Hygiene::new(db.upcast(), file_id) } | ||
46 | } | ||
47 | pub fn with_hygiene(hygiene: &Hygiene) -> Self { | ||
48 | LowerCtx { hygiene: hygiene.clone() } | ||
49 | } | ||
50 | |||
51 | pub fn lower_path(&self, ast: ast::Path) -> Option<Path> { | ||
52 | Path::from_src(ast, &self.hygiene) | ||
53 | } | ||
54 | } | ||
55 | |||
38 | pub(super) fn lower( | 56 | pub(super) fn lower( |
39 | db: &dyn DefDatabase, | 57 | db: &dyn DefDatabase, |
40 | def: DefWithBodyId, | 58 | def: DefWithBodyId, |
@@ -42,10 +60,13 @@ pub(super) fn lower( | |||
42 | params: Option<ast::ParamList>, | 60 | params: Option<ast::ParamList>, |
43 | body: Option<ast::Expr>, | 61 | body: Option<ast::Expr>, |
44 | ) -> (Body, BodySourceMap) { | 62 | ) -> (Body, BodySourceMap) { |
63 | let ctx = LowerCtx::new(db, expander.current_file_id.clone()); | ||
64 | |||
45 | ExprCollector { | 65 | ExprCollector { |
46 | db, | 66 | db, |
47 | def, | 67 | def, |
48 | expander, | 68 | expander, |
69 | ctx, | ||
49 | source_map: BodySourceMap::default(), | 70 | source_map: BodySourceMap::default(), |
50 | body: Body { | 71 | body: Body { |
51 | exprs: Arena::default(), | 72 | exprs: Arena::default(), |
@@ -62,7 +83,7 @@ struct ExprCollector<'a> { | |||
62 | db: &'a dyn DefDatabase, | 83 | db: &'a dyn DefDatabase, |
63 | def: DefWithBodyId, | 84 | def: DefWithBodyId, |
64 | expander: Expander, | 85 | expander: Expander, |
65 | 86 | ctx: LowerCtx, | |
66 | body: Body, | 87 | body: Body, |
67 | source_map: BodySourceMap, | 88 | source_map: BodySourceMap, |
68 | } | 89 | } |
@@ -182,10 +203,16 @@ impl ExprCollector<'_> { | |||
182 | 203 | ||
183 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) | 204 | self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) |
184 | } | 205 | } |
185 | ast::Expr::TryBlockExpr(e) => { | 206 | ast::Expr::EffectExpr(e) => match e.effect() { |
186 | let body = self.collect_block_opt(e.body()); | 207 | ast::Effect::Try(_) => { |
187 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) | 208 | let body = self.collect_block_opt(e.block_expr()); |
188 | } | 209 | self.alloc_expr(Expr::TryBlock { body }, syntax_ptr) |
210 | } | ||
211 | // FIXME: we need to record these effects somewhere... | ||
212 | ast::Effect::Async(_) | ast::Effect::Label(_) | ast::Effect::Unsafe(_) => { | ||
213 | self.collect_block_opt(e.block_expr()) | ||
214 | } | ||
215 | }, | ||
189 | ast::Expr::BlockExpr(e) => self.collect_block(e), | 216 | ast::Expr::BlockExpr(e) => self.collect_block(e), |
190 | ast::Expr::LoopExpr(e) => { | 217 | ast::Expr::LoopExpr(e) => { |
191 | let body = self.collect_block_opt(e.loop_body()); | 218 | let body = self.collect_block_opt(e.loop_body()); |
@@ -241,7 +268,8 @@ impl ExprCollector<'_> { | |||
241 | Vec::new() | 268 | Vec::new() |
242 | }; | 269 | }; |
243 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 270 | let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
244 | let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast); | 271 | let generic_args = |
272 | e.type_arg_list().and_then(|it| GenericArgs::from_ast(&self.ctx, it)); | ||
245 | self.alloc_expr( | 273 | self.alloc_expr( |
246 | Expr::MethodCall { receiver, method_name, args, generic_args }, | 274 | Expr::MethodCall { receiver, method_name, args, generic_args }, |
247 | syntax_ptr, | 275 | syntax_ptr, |
@@ -347,7 +375,7 @@ impl ExprCollector<'_> { | |||
347 | } | 375 | } |
348 | ast::Expr::CastExpr(e) => { | 376 | ast::Expr::CastExpr(e) => { |
349 | let expr = self.collect_expr_opt(e.expr()); | 377 | let expr = self.collect_expr_opt(e.expr()); |
350 | let type_ref = TypeRef::from_ast_opt(e.type_ref()); | 378 | let type_ref = TypeRef::from_ast_opt(&self.ctx, e.type_ref()); |
351 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) | 379 | self.alloc_expr(Expr::Cast { expr, type_ref }, syntax_ptr) |
352 | } | 380 | } |
353 | ast::Expr::RefExpr(e) => { | 381 | ast::Expr::RefExpr(e) => { |
@@ -369,12 +397,16 @@ impl ExprCollector<'_> { | |||
369 | if let Some(pl) = e.param_list() { | 397 | if let Some(pl) = e.param_list() { |
370 | for param in pl.params() { | 398 | for param in pl.params() { |
371 | let pat = self.collect_pat_opt(param.pat()); | 399 | let pat = self.collect_pat_opt(param.pat()); |
372 | let type_ref = param.ascribed_type().map(TypeRef::from_ast); | 400 | let type_ref = |
401 | param.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx, it)); | ||
373 | args.push(pat); | 402 | args.push(pat); |
374 | arg_types.push(type_ref); | 403 | arg_types.push(type_ref); |
375 | } | 404 | } |
376 | } | 405 | } |
377 | let ret_type = e.ret_type().and_then(|r| r.type_ref()).map(TypeRef::from_ast); | 406 | let ret_type = e |
407 | .ret_type() | ||
408 | .and_then(|r| r.type_ref()) | ||
409 | .map(|it| TypeRef::from_ast(&self.ctx, it)); | ||
378 | let body = self.collect_expr_opt(e.body()); | 410 | let body = self.collect_expr_opt(e.body()); |
379 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) | 411 | self.alloc_expr(Expr::Lambda { args, arg_types, ret_type, body }, syntax_ptr) |
380 | } | 412 | } |
@@ -434,6 +466,7 @@ impl ExprCollector<'_> { | |||
434 | krate: Some(self.expander.module.krate), | 466 | krate: Some(self.expander.module.krate), |
435 | ast_id: Some(self.expander.ast_id(&e)), | 467 | ast_id: Some(self.expander.ast_id(&e)), |
436 | kind: MacroDefKind::Declarative, | 468 | kind: MacroDefKind::Declarative, |
469 | local_inner: false, | ||
437 | }; | 470 | }; |
438 | self.body.item_scope.define_legacy_macro(name, mac); | 471 | self.body.item_scope.define_legacy_macro(name, mac); |
439 | 472 | ||
@@ -468,19 +501,15 @@ impl ExprCollector<'_> { | |||
468 | } | 501 | } |
469 | } | 502 | } |
470 | 503 | ||
471 | fn collect_block(&mut self, expr: ast::BlockExpr) -> ExprId { | 504 | fn collect_block(&mut self, block: ast::BlockExpr) -> ExprId { |
472 | let syntax_node_ptr = AstPtr::new(&expr.clone().into()); | 505 | let syntax_node_ptr = AstPtr::new(&block.clone().into()); |
473 | let block = match expr.block() { | ||
474 | Some(block) => block, | ||
475 | None => return self.alloc_expr(Expr::Missing, syntax_node_ptr), | ||
476 | }; | ||
477 | self.collect_block_items(&block); | 506 | self.collect_block_items(&block); |
478 | let statements = block | 507 | let statements = block |
479 | .statements() | 508 | .statements() |
480 | .map(|s| match s { | 509 | .map(|s| match s { |
481 | ast::Stmt::LetStmt(stmt) => { | 510 | ast::Stmt::LetStmt(stmt) => { |
482 | let pat = self.collect_pat_opt(stmt.pat()); | 511 | let pat = self.collect_pat_opt(stmt.pat()); |
483 | let type_ref = stmt.ascribed_type().map(TypeRef::from_ast); | 512 | let type_ref = stmt.ascribed_type().map(|it| TypeRef::from_ast(&self.ctx, it)); |
484 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); | 513 | let initializer = stmt.initializer().map(|e| self.collect_expr(e)); |
485 | Statement::Let { pat, type_ref, initializer } | 514 | Statement::Let { pat, type_ref, initializer } |
486 | } | 515 | } |
@@ -491,7 +520,7 @@ impl ExprCollector<'_> { | |||
491 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) | 520 | self.alloc_expr(Expr::Block { statements, tail }, syntax_node_ptr) |
492 | } | 521 | } |
493 | 522 | ||
494 | fn collect_block_items(&mut self, block: &ast::Block) { | 523 | fn collect_block_items(&mut self, block: &ast::BlockExpr) { |
495 | let container = ContainerId::DefWithBodyId(self.def); | 524 | let container = ContainerId::DefWithBodyId(self.def); |
496 | for item in block.items() { | 525 | for item in block.items() { |
497 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { | 526 | let (def, name): (ModuleDefId, Option<ast::Name>) = match item { |
diff --git a/crates/ra_hir_def/src/data.rs b/crates/ra_hir_def/src/data.rs index ccb682f9a..7a2067e49 100644 --- a/crates/ra_hir_def/src/data.rs +++ b/crates/ra_hir_def/src/data.rs | |||
@@ -15,6 +15,7 @@ use ra_syntax::ast::{ | |||
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | attr::Attrs, | 17 | attr::Attrs, |
18 | body::LowerCtx, | ||
18 | db::DefDatabase, | 19 | db::DefDatabase, |
19 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, | 20 | path::{path, AssociatedTypeBinding, GenericArgs, Path}, |
20 | src::HasSource, | 21 | src::HasSource, |
@@ -40,13 +41,14 @@ impl FunctionData { | |||
40 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { | 41 | pub(crate) fn fn_data_query(db: &impl DefDatabase, func: FunctionId) -> Arc<FunctionData> { |
41 | let loc = func.lookup(db); | 42 | let loc = func.lookup(db); |
42 | let src = loc.source(db); | 43 | let src = loc.source(db); |
44 | let ctx = LowerCtx::new(db, src.file_id); | ||
43 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); | 45 | let name = src.value.name().map(|n| n.as_name()).unwrap_or_else(Name::missing); |
44 | let mut params = Vec::new(); | 46 | let mut params = Vec::new(); |
45 | let mut has_self_param = false; | 47 | let mut has_self_param = false; |
46 | if let Some(param_list) = src.value.param_list() { | 48 | if let Some(param_list) = src.value.param_list() { |
47 | if let Some(self_param) = param_list.self_param() { | 49 | if let Some(self_param) = param_list.self_param() { |
48 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { | 50 | let self_type = if let Some(type_ref) = self_param.ascribed_type() { |
49 | TypeRef::from_ast(type_ref) | 51 | TypeRef::from_ast(&ctx, type_ref) |
50 | } else { | 52 | } else { |
51 | let self_type = TypeRef::Path(name![Self].into()); | 53 | let self_type = TypeRef::Path(name![Self].into()); |
52 | match self_param.kind() { | 54 | match self_param.kind() { |
@@ -63,14 +65,14 @@ impl FunctionData { | |||
63 | has_self_param = true; | 65 | has_self_param = true; |
64 | } | 66 | } |
65 | for param in param_list.params() { | 67 | for param in param_list.params() { |
66 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | 68 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); |
67 | params.push(type_ref); | 69 | params.push(type_ref); |
68 | } | 70 | } |
69 | } | 71 | } |
70 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); | 72 | let attrs = Attrs::new(&src.value, &Hygiene::new(db.upcast(), src.file_id)); |
71 | 73 | ||
72 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { | 74 | let ret_type = if let Some(type_ref) = src.value.ret_type().and_then(|rt| rt.type_ref()) { |
73 | TypeRef::from_ast(type_ref) | 75 | TypeRef::from_ast(&ctx, type_ref) |
74 | } else { | 76 | } else { |
75 | TypeRef::unit() | 77 | TypeRef::unit() |
76 | }; | 78 | }; |
@@ -122,7 +124,8 @@ impl TypeAliasData { | |||
122 | let loc = typ.lookup(db); | 124 | let loc = typ.lookup(db); |
123 | let node = loc.source(db); | 125 | let node = loc.source(db); |
124 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); | 126 | let name = node.value.name().map_or_else(Name::missing, |n| n.as_name()); |
125 | let type_ref = node.value.type_ref().map(TypeRef::from_ast); | 127 | let lower_ctx = LowerCtx::new(db, node.file_id); |
128 | let type_ref = node.value.type_ref().map(|it| TypeRef::from_ast(&lower_ctx, it)); | ||
126 | let vis_default = RawVisibility::default_for_container(loc.container); | 129 | let vis_default = RawVisibility::default_for_container(loc.container); |
127 | let visibility = RawVisibility::from_ast_with_default( | 130 | let visibility = RawVisibility::from_ast_with_default( |
128 | db, | 131 | db, |
@@ -130,7 +133,7 @@ impl TypeAliasData { | |||
130 | node.as_ref().map(|n| n.visibility()), | 133 | node.as_ref().map(|n| n.visibility()), |
131 | ); | 134 | ); |
132 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { | 135 | let bounds = if let Some(bound_list) = node.value.type_bound_list() { |
133 | bound_list.bounds().map(TypeBound::from_ast).collect() | 136 | bound_list.bounds().map(|it| TypeBound::from_ast(&lower_ctx, it)).collect() |
134 | } else { | 137 | } else { |
135 | Vec::new() | 138 | Vec::new() |
136 | }; | 139 | }; |
@@ -223,9 +226,10 @@ impl ImplData { | |||
223 | let _p = profile("impl_data_query"); | 226 | let _p = profile("impl_data_query"); |
224 | let impl_loc = id.lookup(db); | 227 | let impl_loc = id.lookup(db); |
225 | let src = impl_loc.source(db); | 228 | let src = impl_loc.source(db); |
229 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
226 | 230 | ||
227 | let target_trait = src.value.target_trait().map(TypeRef::from_ast); | 231 | let target_trait = src.value.target_trait().map(|it| TypeRef::from_ast(&lower_ctx, it)); |
228 | let target_type = TypeRef::from_ast_opt(src.value.target_type()); | 232 | let target_type = TypeRef::from_ast_opt(&lower_ctx, src.value.target_type()); |
229 | let is_negative = src.value.excl_token().is_some(); | 233 | let is_negative = src.value.excl_token().is_some(); |
230 | let module_id = impl_loc.container.module(db); | 234 | let module_id = impl_loc.container.module(db); |
231 | 235 | ||
@@ -279,8 +283,9 @@ impl ConstData { | |||
279 | vis_default: RawVisibility, | 283 | vis_default: RawVisibility, |
280 | node: InFile<N>, | 284 | node: InFile<N>, |
281 | ) -> ConstData { | 285 | ) -> ConstData { |
286 | let ctx = LowerCtx::new(db, node.file_id); | ||
282 | let name = node.value.name().map(|n| n.as_name()); | 287 | let name = node.value.name().map(|n| n.as_name()); |
283 | let type_ref = TypeRef::from_ast_opt(node.value.ascribed_type()); | 288 | let type_ref = TypeRef::from_ast_opt(&ctx, node.value.ascribed_type()); |
284 | let visibility = | 289 | let visibility = |
285 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); | 290 | RawVisibility::from_ast_with_default(db, vis_default, node.map(|n| n.visibility())); |
286 | ConstData { name, type_ref, visibility } | 291 | ConstData { name, type_ref, visibility } |
diff --git a/crates/ra_hir_def/src/generics.rs b/crates/ra_hir_def/src/generics.rs index d850244c4..09a5241f7 100644 --- a/crates/ra_hir_def/src/generics.rs +++ b/crates/ra_hir_def/src/generics.rs | |||
@@ -15,6 +15,7 @@ use ra_prof::profile; | |||
15 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; | 15 | use ra_syntax::ast::{self, NameOwner, TypeBoundsOwner, TypeParamsOwner}; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | body::LowerCtx, | ||
18 | child_by_source::ChildBySource, | 19 | child_by_source::ChildBySource, |
19 | db::DefDatabase, | 20 | db::DefDatabase, |
20 | dyn_map::DynMap, | 21 | dyn_map::DynMap, |
@@ -80,11 +81,13 @@ impl GenericParams { | |||
80 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { | 81 | fn new(db: &dyn DefDatabase, def: GenericDefId) -> (GenericParams, InFile<SourceMap>) { |
81 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; | 82 | let mut generics = GenericParams { types: Arena::default(), where_predicates: Vec::new() }; |
82 | let mut sm = ArenaMap::default(); | 83 | let mut sm = ArenaMap::default(); |
84 | |||
83 | // FIXME: add `: Sized` bound for everything except for `Self` in traits | 85 | // FIXME: add `: Sized` bound for everything except for `Self` in traits |
84 | let file_id = match def { | 86 | let file_id = match def { |
85 | GenericDefId::FunctionId(it) => { | 87 | GenericDefId::FunctionId(it) => { |
86 | let src = it.lookup(db).source(db); | 88 | let src = it.lookup(db).source(db); |
87 | generics.fill(&mut sm, &src.value); | 89 | let lower_ctx = LowerCtx::new(db, src.file_id); |
90 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
88 | // lower `impl Trait` in arguments | 91 | // lower `impl Trait` in arguments |
89 | let data = db.function_data(it); | 92 | let data = db.function_data(it); |
90 | for param in &data.params { | 93 | for param in &data.params { |
@@ -94,21 +97,25 @@ impl GenericParams { | |||
94 | } | 97 | } |
95 | GenericDefId::AdtId(AdtId::StructId(it)) => { | 98 | GenericDefId::AdtId(AdtId::StructId(it)) => { |
96 | let src = it.lookup(db).source(db); | 99 | let src = it.lookup(db).source(db); |
97 | generics.fill(&mut sm, &src.value); | 100 | let lower_ctx = LowerCtx::new(db, src.file_id); |
101 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
98 | src.file_id | 102 | src.file_id |
99 | } | 103 | } |
100 | GenericDefId::AdtId(AdtId::UnionId(it)) => { | 104 | GenericDefId::AdtId(AdtId::UnionId(it)) => { |
101 | let src = it.lookup(db).source(db); | 105 | let src = it.lookup(db).source(db); |
102 | generics.fill(&mut sm, &src.value); | 106 | let lower_ctx = LowerCtx::new(db, src.file_id); |
107 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
103 | src.file_id | 108 | src.file_id |
104 | } | 109 | } |
105 | GenericDefId::AdtId(AdtId::EnumId(it)) => { | 110 | GenericDefId::AdtId(AdtId::EnumId(it)) => { |
106 | let src = it.lookup(db).source(db); | 111 | let src = it.lookup(db).source(db); |
107 | generics.fill(&mut sm, &src.value); | 112 | let lower_ctx = LowerCtx::new(db, src.file_id); |
113 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
108 | src.file_id | 114 | src.file_id |
109 | } | 115 | } |
110 | GenericDefId::TraitId(it) => { | 116 | GenericDefId::TraitId(it) => { |
111 | let src = it.lookup(db).source(db); | 117 | let src = it.lookup(db).source(db); |
118 | let lower_ctx = LowerCtx::new(db, src.file_id); | ||
112 | 119 | ||
113 | // traits get the Self type as an implicit first type parameter | 120 | // traits get the Self type as an implicit first type parameter |
114 | let self_param_id = generics.types.alloc(TypeParamData { | 121 | let self_param_id = generics.types.alloc(TypeParamData { |
@@ -120,14 +127,16 @@ impl GenericParams { | |||
120 | // add super traits as bounds on Self | 127 | // add super traits as bounds on Self |
121 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar | 128 | // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar |
122 | let self_param = TypeRef::Path(name![Self].into()); | 129 | let self_param = TypeRef::Path(name![Self].into()); |
123 | generics.fill_bounds(&src.value, self_param); | 130 | generics.fill_bounds(&lower_ctx, &src.value, self_param); |
124 | 131 | ||
125 | generics.fill(&mut sm, &src.value); | 132 | generics.fill(&lower_ctx, &mut sm, &src.value); |
126 | src.file_id | 133 | src.file_id |
127 | } | 134 | } |
128 | GenericDefId::TypeAliasId(it) => { | 135 | GenericDefId::TypeAliasId(it) => { |
129 | let src = it.lookup(db).source(db); | 136 | let src = it.lookup(db).source(db); |
130 | generics.fill(&mut sm, &src.value); | 137 | let lower_ctx = LowerCtx::new(db, src.file_id); |
138 | |||
139 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
131 | src.file_id | 140 | src.file_id |
132 | } | 141 | } |
133 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a | 142 | // Note that we don't add `Self` here: in `impl`s, `Self` is not a |
@@ -135,7 +144,9 @@ impl GenericParams { | |||
135 | // type, so this is handled by the resolver. | 144 | // type, so this is handled by the resolver. |
136 | GenericDefId::ImplId(it) => { | 145 | GenericDefId::ImplId(it) => { |
137 | let src = it.lookup(db).source(db); | 146 | let src = it.lookup(db).source(db); |
138 | generics.fill(&mut sm, &src.value); | 147 | let lower_ctx = LowerCtx::new(db, src.file_id); |
148 | |||
149 | generics.fill(&lower_ctx, &mut sm, &src.value); | ||
139 | src.file_id | 150 | src.file_id |
140 | } | 151 | } |
141 | // We won't be using this ID anyway | 152 | // We won't be using this ID anyway |
@@ -145,28 +156,38 @@ impl GenericParams { | |||
145 | (generics, InFile::new(file_id, sm)) | 156 | (generics, InFile::new(file_id, sm)) |
146 | } | 157 | } |
147 | 158 | ||
148 | fn fill(&mut self, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { | 159 | fn fill(&mut self, lower_ctx: &LowerCtx, sm: &mut SourceMap, node: &dyn TypeParamsOwner) { |
149 | if let Some(params) = node.type_param_list() { | 160 | if let Some(params) = node.type_param_list() { |
150 | self.fill_params(sm, params) | 161 | self.fill_params(lower_ctx, sm, params) |
151 | } | 162 | } |
152 | if let Some(where_clause) = node.where_clause() { | 163 | if let Some(where_clause) = node.where_clause() { |
153 | self.fill_where_predicates(where_clause); | 164 | self.fill_where_predicates(lower_ctx, where_clause); |
154 | } | 165 | } |
155 | } | 166 | } |
156 | 167 | ||
157 | fn fill_bounds(&mut self, node: &dyn ast::TypeBoundsOwner, type_ref: TypeRef) { | 168 | fn fill_bounds( |
169 | &mut self, | ||
170 | lower_ctx: &LowerCtx, | ||
171 | node: &dyn ast::TypeBoundsOwner, | ||
172 | type_ref: TypeRef, | ||
173 | ) { | ||
158 | for bound in | 174 | for bound in |
159 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) | 175 | node.type_bound_list().iter().flat_map(|type_bound_list| type_bound_list.bounds()) |
160 | { | 176 | { |
161 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | 177 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); |
162 | } | 178 | } |
163 | } | 179 | } |
164 | 180 | ||
165 | fn fill_params(&mut self, sm: &mut SourceMap, params: ast::TypeParamList) { | 181 | fn fill_params( |
182 | &mut self, | ||
183 | lower_ctx: &LowerCtx, | ||
184 | sm: &mut SourceMap, | ||
185 | params: ast::TypeParamList, | ||
186 | ) { | ||
166 | for type_param in params.type_params() { | 187 | for type_param in params.type_params() { |
167 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); | 188 | let name = type_param.name().map_or_else(Name::missing, |it| it.as_name()); |
168 | // FIXME: Use `Path::from_src` | 189 | // FIXME: Use `Path::from_src` |
169 | let default = type_param.default_type().map(TypeRef::from_ast); | 190 | let default = type_param.default_type().map(|it| TypeRef::from_ast(lower_ctx, it)); |
170 | let param = TypeParamData { | 191 | let param = TypeParamData { |
171 | name: Some(name.clone()), | 192 | name: Some(name.clone()), |
172 | default, | 193 | default, |
@@ -176,29 +197,34 @@ impl GenericParams { | |||
176 | sm.insert(param_id, Either::Right(type_param.clone())); | 197 | sm.insert(param_id, Either::Right(type_param.clone())); |
177 | 198 | ||
178 | let type_ref = TypeRef::Path(name.into()); | 199 | let type_ref = TypeRef::Path(name.into()); |
179 | self.fill_bounds(&type_param, type_ref); | 200 | self.fill_bounds(&lower_ctx, &type_param, type_ref); |
180 | } | 201 | } |
181 | } | 202 | } |
182 | 203 | ||
183 | fn fill_where_predicates(&mut self, where_clause: ast::WhereClause) { | 204 | fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) { |
184 | for pred in where_clause.predicates() { | 205 | for pred in where_clause.predicates() { |
185 | let type_ref = match pred.type_ref() { | 206 | let type_ref = match pred.type_ref() { |
186 | Some(type_ref) => type_ref, | 207 | Some(type_ref) => type_ref, |
187 | None => continue, | 208 | None => continue, |
188 | }; | 209 | }; |
189 | let type_ref = TypeRef::from_ast(type_ref); | 210 | let type_ref = TypeRef::from_ast(lower_ctx, type_ref); |
190 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { | 211 | for bound in pred.type_bound_list().iter().flat_map(|l| l.bounds()) { |
191 | self.add_where_predicate_from_bound(bound, type_ref.clone()); | 212 | self.add_where_predicate_from_bound(lower_ctx, bound, type_ref.clone()); |
192 | } | 213 | } |
193 | } | 214 | } |
194 | } | 215 | } |
195 | 216 | ||
196 | fn add_where_predicate_from_bound(&mut self, bound: ast::TypeBound, type_ref: TypeRef) { | 217 | fn add_where_predicate_from_bound( |
218 | &mut self, | ||
219 | lower_ctx: &LowerCtx, | ||
220 | bound: ast::TypeBound, | ||
221 | type_ref: TypeRef, | ||
222 | ) { | ||
197 | if bound.question_token().is_some() { | 223 | if bound.question_token().is_some() { |
198 | // FIXME: remove this bound | 224 | // FIXME: remove this bound |
199 | return; | 225 | return; |
200 | } | 226 | } |
201 | let bound = TypeBound::from_ast(bound); | 227 | let bound = TypeBound::from_ast(lower_ctx, bound); |
202 | self.where_predicates | 228 | self.where_predicates |
203 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); | 229 | .push(WherePredicate { target: WherePredicateTarget::TypeRef(type_ref), bound }); |
204 | } | 230 | } |
diff --git a/crates/ra_hir_def/src/nameres/collector.rs b/crates/ra_hir_def/src/nameres/collector.rs index 98c74fe25..bf3968bd6 100644 --- a/crates/ra_hir_def/src/nameres/collector.rs +++ b/crates/ra_hir_def/src/nameres/collector.rs | |||
@@ -204,6 +204,7 @@ impl DefCollector<'_> { | |||
204 | ast_id: None, | 204 | ast_id: None, |
205 | krate: Some(krate), | 205 | krate: Some(krate), |
206 | kind: MacroDefKind::CustomDerive(expander), | 206 | kind: MacroDefKind::CustomDerive(expander), |
207 | local_inner: false, | ||
207 | }; | 208 | }; |
208 | 209 | ||
209 | self.define_proc_macro(name.clone(), macro_id); | 210 | self.define_proc_macro(name.clone(), macro_id); |
@@ -941,6 +942,7 @@ impl ModCollector<'_, '_> { | |||
941 | ast_id: Some(ast_id.ast_id), | 942 | ast_id: Some(ast_id.ast_id), |
942 | krate: Some(self.def_collector.def_map.krate), | 943 | krate: Some(self.def_collector.def_map.krate), |
943 | kind: MacroDefKind::Declarative, | 944 | kind: MacroDefKind::Declarative, |
945 | local_inner: mac.local_inner, | ||
944 | }; | 946 | }; |
945 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); | 947 | self.def_collector.define_macro(self.module_id, name.clone(), macro_id, mac.export); |
946 | } | 948 | } |
diff --git a/crates/ra_hir_def/src/nameres/raw.rs b/crates/ra_hir_def/src/nameres/raw.rs index 39b011ad7..a71503c76 100644 --- a/crates/ra_hir_def/src/nameres/raw.rs +++ b/crates/ra_hir_def/src/nameres/raw.rs | |||
@@ -188,6 +188,7 @@ pub(super) struct MacroData { | |||
188 | pub(super) path: ModPath, | 188 | pub(super) path: ModPath, |
189 | pub(super) name: Option<Name>, | 189 | pub(super) name: Option<Name>, |
190 | pub(super) export: bool, | 190 | pub(super) export: bool, |
191 | pub(super) local_inner: bool, | ||
191 | pub(super) builtin: bool, | 192 | pub(super) builtin: bool, |
192 | } | 193 | } |
193 | 194 | ||
@@ -401,14 +402,32 @@ impl RawItemsCollector { | |||
401 | 402 | ||
402 | let name = m.name().map(|it| it.as_name()); | 403 | let name = m.name().map(|it| it.as_name()); |
403 | let ast_id = self.source_ast_id_map.ast_id(&m); | 404 | let ast_id = self.source_ast_id_map.ast_id(&m); |
404 | // FIXME: cfg_attr | ||
405 | let export = m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "macro_export"); | ||
406 | 405 | ||
407 | // FIXME: cfg_attr | 406 | // FIXME: cfg_attr |
408 | let builtin = | 407 | let export_attr = attrs.by_key("macro_export"); |
409 | m.attrs().filter_map(|x| x.simple_name()).any(|name| name == "rustc_builtin_macro"); | 408 | |
409 | let export = export_attr.exists(); | ||
410 | let local_inner = if export { | ||
411 | export_attr.tt_values().map(|it| &it.token_trees).flatten().any(|it| match it { | ||
412 | tt::TokenTree::Leaf(tt::Leaf::Ident(ident)) => { | ||
413 | ident.text.contains("local_inner_macros") | ||
414 | } | ||
415 | _ => false, | ||
416 | }) | ||
417 | } else { | ||
418 | false | ||
419 | }; | ||
420 | |||
421 | let builtin = attrs.by_key("rustc_builtin_macro").exists(); | ||
410 | 422 | ||
411 | let m = self.raw_items.macros.alloc(MacroData { ast_id, path, name, export, builtin }); | 423 | let m = self.raw_items.macros.alloc(MacroData { |
424 | ast_id, | ||
425 | path, | ||
426 | name, | ||
427 | export, | ||
428 | local_inner, | ||
429 | builtin, | ||
430 | }); | ||
412 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); | 431 | self.push_item(current_module, attrs, RawItemKind::Macro(m)); |
413 | } | 432 | } |
414 | 433 | ||
diff --git a/crates/ra_hir_def/src/nameres/tests/macros.rs b/crates/ra_hir_def/src/nameres/tests/macros.rs index b0befdfbd..9bc0e6287 100644 --- a/crates/ra_hir_def/src/nameres/tests/macros.rs +++ b/crates/ra_hir_def/src/nameres/tests/macros.rs | |||
@@ -136,6 +136,43 @@ fn macro_rules_export_with_local_inner_macros_are_visible() { | |||
136 | } | 136 | } |
137 | 137 | ||
138 | #[test] | 138 | #[test] |
139 | fn local_inner_macros_makes_local_macros_usable() { | ||
140 | let map = def_map( | ||
141 | " | ||
142 | //- /main.rs crate:main deps:foo | ||
143 | foo::structs!(Foo, Bar); | ||
144 | mod bar; | ||
145 | //- /bar.rs | ||
146 | use crate::*; | ||
147 | //- /lib.rs crate:foo | ||
148 | #[macro_export(local_inner_macros)] | ||
149 | macro_rules! structs { | ||
150 | ($($i:ident),*) => { | ||
151 | inner!($($i),*); | ||
152 | } | ||
153 | } | ||
154 | #[macro_export] | ||
155 | macro_rules! inner { | ||
156 | ($($i:ident),*) => { | ||
157 | $(struct $i { field: u32 } )* | ||
158 | } | ||
159 | } | ||
160 | ", | ||
161 | ); | ||
162 | assert_snapshot!(map, @r###" | ||
163 | â‹®crate | ||
164 | â‹®Bar: t v | ||
165 | â‹®Foo: t v | ||
166 | â‹®bar: t | ||
167 | â‹® | ||
168 | â‹®crate::bar | ||
169 | â‹®Bar: t v | ||
170 | â‹®Foo: t v | ||
171 | â‹®bar: t | ||
172 | "###); | ||
173 | } | ||
174 | |||
175 | #[test] | ||
139 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { | 176 | fn unexpanded_macro_should_expand_by_fixedpoint_loop() { |
140 | let map = def_map( | 177 | let map = def_map( |
141 | " | 178 | " |
diff --git a/crates/ra_hir_def/src/path.rs b/crates/ra_hir_def/src/path.rs index 162b3c8c7..e84efe2ab 100644 --- a/crates/ra_hir_def/src/path.rs +++ b/crates/ra_hir_def/src/path.rs | |||
@@ -7,6 +7,7 @@ use std::{ | |||
7 | sync::Arc, | 7 | sync::Arc, |
8 | }; | 8 | }; |
9 | 9 | ||
10 | use crate::body::LowerCtx; | ||
10 | use hir_expand::{ | 11 | use hir_expand::{ |
11 | hygiene::Hygiene, | 12 | hygiene::Hygiene, |
12 | name::{AsName, Name}, | 13 | name::{AsName, Name}, |
@@ -244,8 +245,8 @@ impl<'a> PathSegments<'a> { | |||
244 | } | 245 | } |
245 | 246 | ||
246 | impl GenericArgs { | 247 | impl GenericArgs { |
247 | pub(crate) fn from_ast(node: ast::TypeArgList) -> Option<GenericArgs> { | 248 | pub(crate) fn from_ast(lower_ctx: &LowerCtx, node: ast::TypeArgList) -> Option<GenericArgs> { |
248 | lower::lower_generic_args(node) | 249 | lower::lower_generic_args(lower_ctx, node) |
249 | } | 250 | } |
250 | 251 | ||
251 | pub(crate) fn empty() -> GenericArgs { | 252 | pub(crate) fn empty() -> GenericArgs { |
diff --git a/crates/ra_hir_def/src/path/lower.rs b/crates/ra_hir_def/src/path/lower.rs index 9ec2e0dcd..6a0c019fd 100644 --- a/crates/ra_hir_def/src/path/lower.rs +++ b/crates/ra_hir_def/src/path/lower.rs | |||
@@ -13,6 +13,7 @@ use ra_syntax::ast::{self, AstNode, TypeAscriptionOwner, TypeBoundsOwner}; | |||
13 | 13 | ||
14 | use super::AssociatedTypeBinding; | 14 | use super::AssociatedTypeBinding; |
15 | use crate::{ | 15 | use crate::{ |
16 | body::LowerCtx, | ||
16 | path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, | 17 | path::{GenericArg, GenericArgs, ModPath, Path, PathKind}, |
17 | type_ref::{TypeBound, TypeRef}, | 18 | type_ref::{TypeBound, TypeRef}, |
18 | }; | 19 | }; |
@@ -26,6 +27,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
26 | let mut type_anchor = None; | 27 | let mut type_anchor = None; |
27 | let mut segments = Vec::new(); | 28 | let mut segments = Vec::new(); |
28 | let mut generic_args = Vec::new(); | 29 | let mut generic_args = Vec::new(); |
30 | let ctx = LowerCtx::with_hygiene(hygiene); | ||
29 | loop { | 31 | loop { |
30 | let segment = path.segment()?; | 32 | let segment = path.segment()?; |
31 | 33 | ||
@@ -40,9 +42,10 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
40 | Either::Left(name) => { | 42 | Either::Left(name) => { |
41 | let args = segment | 43 | let args = segment |
42 | .type_arg_list() | 44 | .type_arg_list() |
43 | .and_then(lower_generic_args) | 45 | .and_then(|it| lower_generic_args(&ctx, it)) |
44 | .or_else(|| { | 46 | .or_else(|| { |
45 | lower_generic_args_from_fn_path( | 47 | lower_generic_args_from_fn_path( |
48 | &ctx, | ||
46 | segment.param_list(), | 49 | segment.param_list(), |
47 | segment.ret_type(), | 50 | segment.ret_type(), |
48 | ) | 51 | ) |
@@ -60,7 +63,7 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
60 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { | 63 | ast::PathSegmentKind::Type { type_ref, trait_ref } => { |
61 | assert!(path.qualifier().is_none()); // this can only occur at the first segment | 64 | assert!(path.qualifier().is_none()); // this can only occur at the first segment |
62 | 65 | ||
63 | let self_type = TypeRef::from_ast(type_ref?); | 66 | let self_type = TypeRef::from_ast(&ctx, type_ref?); |
64 | 67 | ||
65 | match trait_ref { | 68 | match trait_ref { |
66 | // <T>::foo | 69 | // <T>::foo |
@@ -113,6 +116,21 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
113 | } | 116 | } |
114 | segments.reverse(); | 117 | segments.reverse(); |
115 | generic_args.reverse(); | 118 | generic_args.reverse(); |
119 | |||
120 | // handle local_inner_macros : | ||
121 | // Basically, even in rustc it is quite hacky: | ||
122 | // https://github.com/rust-lang/rust/blob/614f273e9388ddd7804d5cbc80b8865068a3744e/src/librustc_resolve/macros.rs#L456 | ||
123 | // We follow what it did anyway :) | ||
124 | if segments.len() == 1 && kind == PathKind::Plain { | ||
125 | if let Some(macro_call) = path.syntax().parent().and_then(ast::MacroCall::cast) { | ||
126 | if macro_call.is_bang() { | ||
127 | if let Some(crate_id) = hygiene.local_inner_macros() { | ||
128 | kind = PathKind::DollarCrate(crate_id); | ||
129 | } | ||
130 | } | ||
131 | } | ||
132 | } | ||
133 | |||
116 | let mod_path = ModPath { kind, segments }; | 134 | let mod_path = ModPath { kind, segments }; |
117 | return Some(Path { type_anchor, mod_path, generic_args }); | 135 | return Some(Path { type_anchor, mod_path, generic_args }); |
118 | 136 | ||
@@ -128,10 +146,13 @@ pub(super) fn lower_path(mut path: ast::Path, hygiene: &Hygiene) -> Option<Path> | |||
128 | } | 146 | } |
129 | } | 147 | } |
130 | 148 | ||
131 | pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> { | 149 | pub(super) fn lower_generic_args( |
150 | lower_ctx: &LowerCtx, | ||
151 | node: ast::TypeArgList, | ||
152 | ) -> Option<GenericArgs> { | ||
132 | let mut args = Vec::new(); | 153 | let mut args = Vec::new(); |
133 | for type_arg in node.type_args() { | 154 | for type_arg in node.type_args() { |
134 | let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); | 155 | let type_ref = TypeRef::from_ast_opt(lower_ctx, type_arg.type_ref()); |
135 | args.push(GenericArg::Type(type_ref)); | 156 | args.push(GenericArg::Type(type_ref)); |
136 | } | 157 | } |
137 | // lifetimes ignored for now | 158 | // lifetimes ignored for now |
@@ -140,9 +161,9 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> | |||
140 | let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; | 161 | let assoc_type_arg: ast::AssocTypeArg = assoc_type_arg; |
141 | if let Some(name_ref) = assoc_type_arg.name_ref() { | 162 | if let Some(name_ref) = assoc_type_arg.name_ref() { |
142 | let name = name_ref.as_name(); | 163 | let name = name_ref.as_name(); |
143 | let type_ref = assoc_type_arg.type_ref().map(TypeRef::from_ast); | 164 | let type_ref = assoc_type_arg.type_ref().map(|it| TypeRef::from_ast(lower_ctx, it)); |
144 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { | 165 | let bounds = if let Some(l) = assoc_type_arg.type_bound_list() { |
145 | l.bounds().map(TypeBound::from_ast).collect() | 166 | l.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() |
146 | } else { | 167 | } else { |
147 | Vec::new() | 168 | Vec::new() |
148 | }; | 169 | }; |
@@ -159,6 +180,7 @@ pub(super) fn lower_generic_args(node: ast::TypeArgList) -> Option<GenericArgs> | |||
159 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) | 180 | /// Collect `GenericArgs` from the parts of a fn-like path, i.e. `Fn(X, Y) |
160 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). | 181 | /// -> Z` (which desugars to `Fn<(X, Y), Output=Z>`). |
161 | fn lower_generic_args_from_fn_path( | 182 | fn lower_generic_args_from_fn_path( |
183 | ctx: &LowerCtx, | ||
162 | params: Option<ast::ParamList>, | 184 | params: Option<ast::ParamList>, |
163 | ret_type: Option<ast::RetType>, | 185 | ret_type: Option<ast::RetType>, |
164 | ) -> Option<GenericArgs> { | 186 | ) -> Option<GenericArgs> { |
@@ -167,14 +189,14 @@ fn lower_generic_args_from_fn_path( | |||
167 | if let Some(params) = params { | 189 | if let Some(params) = params { |
168 | let mut param_types = Vec::new(); | 190 | let mut param_types = Vec::new(); |
169 | for param in params.params() { | 191 | for param in params.params() { |
170 | let type_ref = TypeRef::from_ast_opt(param.ascribed_type()); | 192 | let type_ref = TypeRef::from_ast_opt(&ctx, param.ascribed_type()); |
171 | param_types.push(type_ref); | 193 | param_types.push(type_ref); |
172 | } | 194 | } |
173 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); | 195 | let arg = GenericArg::Type(TypeRef::Tuple(param_types)); |
174 | args.push(arg); | 196 | args.push(arg); |
175 | } | 197 | } |
176 | if let Some(ret_type) = ret_type { | 198 | if let Some(ret_type) = ret_type { |
177 | let type_ref = TypeRef::from_ast_opt(ret_type.type_ref()); | 199 | let type_ref = TypeRef::from_ast_opt(&ctx, ret_type.type_ref()); |
178 | bindings.push(AssociatedTypeBinding { | 200 | bindings.push(AssociatedTypeBinding { |
179 | name: name![Output], | 201 | name: name![Output], |
180 | type_ref: Some(type_ref), | 202 | type_ref: Some(type_ref), |
diff --git a/crates/ra_hir_def/src/type_ref.rs b/crates/ra_hir_def/src/type_ref.rs index f308c6bdf..5bdad9efd 100644 --- a/crates/ra_hir_def/src/type_ref.rs +++ b/crates/ra_hir_def/src/type_ref.rs | |||
@@ -3,7 +3,7 @@ | |||
3 | 3 | ||
4 | use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; | 4 | use ra_syntax::ast::{self, TypeAscriptionOwner, TypeBoundsOwner}; |
5 | 5 | ||
6 | use crate::path::Path; | 6 | use crate::{body::LowerCtx, path::Path}; |
7 | 7 | ||
8 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] | 8 | #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] |
9 | pub enum Mutability { | 9 | pub enum Mutability { |
@@ -64,30 +64,34 @@ pub enum TypeBound { | |||
64 | 64 | ||
65 | impl TypeRef { | 65 | impl TypeRef { |
66 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. | 66 | /// Converts an `ast::TypeRef` to a `hir::TypeRef`. |
67 | pub(crate) fn from_ast(node: ast::TypeRef) -> Self { | 67 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeRef) -> Self { |
68 | match node { | 68 | match node { |
69 | ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | 69 | ast::TypeRef::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), |
70 | ast::TypeRef::TupleType(inner) => { | 70 | ast::TypeRef::TupleType(inner) => { |
71 | TypeRef::Tuple(inner.fields().map(TypeRef::from_ast).collect()) | 71 | TypeRef::Tuple(inner.fields().map(|it| TypeRef::from_ast(ctx, it)).collect()) |
72 | } | 72 | } |
73 | ast::TypeRef::NeverType(..) => TypeRef::Never, | 73 | ast::TypeRef::NeverType(..) => TypeRef::Never, |
74 | ast::TypeRef::PathType(inner) => { | 74 | ast::TypeRef::PathType(inner) => { |
75 | // FIXME: Use `Path::from_src` | 75 | // FIXME: Use `Path::from_src` |
76 | inner.path().and_then(Path::from_ast).map(TypeRef::Path).unwrap_or(TypeRef::Error) | 76 | inner |
77 | .path() | ||
78 | .and_then(|it| ctx.lower_path(it)) | ||
79 | .map(TypeRef::Path) | ||
80 | .unwrap_or(TypeRef::Error) | ||
77 | } | 81 | } |
78 | ast::TypeRef::PointerType(inner) => { | 82 | ast::TypeRef::PointerType(inner) => { |
79 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 83 | let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); |
80 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); | 84 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
81 | TypeRef::RawPtr(Box::new(inner_ty), mutability) | 85 | TypeRef::RawPtr(Box::new(inner_ty), mutability) |
82 | } | 86 | } |
83 | ast::TypeRef::ArrayType(inner) => { | 87 | ast::TypeRef::ArrayType(inner) => { |
84 | TypeRef::Array(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | 88 | TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) |
85 | } | 89 | } |
86 | ast::TypeRef::SliceType(inner) => { | 90 | ast::TypeRef::SliceType(inner) => { |
87 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(inner.type_ref()))) | 91 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.type_ref()))) |
88 | } | 92 | } |
89 | ast::TypeRef::ReferenceType(inner) => { | 93 | ast::TypeRef::ReferenceType(inner) => { |
90 | let inner_ty = TypeRef::from_ast_opt(inner.type_ref()); | 94 | let inner_ty = TypeRef::from_ast_opt(&ctx, inner.type_ref()); |
91 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); | 95 | let mutability = Mutability::from_mutable(inner.mut_token().is_some()); |
92 | TypeRef::Reference(Box::new(inner_ty), mutability) | 96 | TypeRef::Reference(Box::new(inner_ty), mutability) |
93 | } | 97 | } |
@@ -96,10 +100,13 @@ impl TypeRef { | |||
96 | let ret_ty = inner | 100 | let ret_ty = inner |
97 | .ret_type() | 101 | .ret_type() |
98 | .and_then(|rt| rt.type_ref()) | 102 | .and_then(|rt| rt.type_ref()) |
99 | .map(TypeRef::from_ast) | 103 | .map(|it| TypeRef::from_ast(ctx, it)) |
100 | .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); | 104 | .unwrap_or_else(|| TypeRef::Tuple(Vec::new())); |
101 | let mut params = if let Some(pl) = inner.param_list() { | 105 | let mut params = if let Some(pl) = inner.param_list() { |
102 | pl.params().map(|p| p.ascribed_type()).map(TypeRef::from_ast_opt).collect() | 106 | pl.params() |
107 | .map(|p| p.ascribed_type()) | ||
108 | .map(|it| TypeRef::from_ast_opt(&ctx, it)) | ||
109 | .collect() | ||
103 | } else { | 110 | } else { |
104 | Vec::new() | 111 | Vec::new() |
105 | }; | 112 | }; |
@@ -107,19 +114,19 @@ impl TypeRef { | |||
107 | TypeRef::Fn(params) | 114 | TypeRef::Fn(params) |
108 | } | 115 | } |
109 | // for types are close enough for our purposes to the inner type for now... | 116 | // for types are close enough for our purposes to the inner type for now... |
110 | ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(inner.type_ref()), | 117 | ast::TypeRef::ForType(inner) => TypeRef::from_ast_opt(&ctx, inner.type_ref()), |
111 | ast::TypeRef::ImplTraitType(inner) => { | 118 | ast::TypeRef::ImplTraitType(inner) => { |
112 | TypeRef::ImplTrait(type_bounds_from_ast(inner.type_bound_list())) | 119 | TypeRef::ImplTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
113 | } | 120 | } |
114 | ast::TypeRef::DynTraitType(inner) => { | 121 | ast::TypeRef::DynTraitType(inner) => { |
115 | TypeRef::DynTrait(type_bounds_from_ast(inner.type_bound_list())) | 122 | TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list())) |
116 | } | 123 | } |
117 | } | 124 | } |
118 | } | 125 | } |
119 | 126 | ||
120 | pub(crate) fn from_ast_opt(node: Option<ast::TypeRef>) -> Self { | 127 | pub(crate) fn from_ast_opt(ctx: &LowerCtx, node: Option<ast::TypeRef>) -> Self { |
121 | if let Some(node) = node { | 128 | if let Some(node) = node { |
122 | TypeRef::from_ast(node) | 129 | TypeRef::from_ast(ctx, node) |
123 | } else { | 130 | } else { |
124 | TypeRef::Error | 131 | TypeRef::Error |
125 | } | 132 | } |
@@ -180,24 +187,27 @@ impl TypeRef { | |||
180 | } | 187 | } |
181 | } | 188 | } |
182 | 189 | ||
183 | pub(crate) fn type_bounds_from_ast(type_bounds_opt: Option<ast::TypeBoundList>) -> Vec<TypeBound> { | 190 | pub(crate) fn type_bounds_from_ast( |
191 | lower_ctx: &LowerCtx, | ||
192 | type_bounds_opt: Option<ast::TypeBoundList>, | ||
193 | ) -> Vec<TypeBound> { | ||
184 | if let Some(type_bounds) = type_bounds_opt { | 194 | if let Some(type_bounds) = type_bounds_opt { |
185 | type_bounds.bounds().map(TypeBound::from_ast).collect() | 195 | type_bounds.bounds().map(|it| TypeBound::from_ast(lower_ctx, it)).collect() |
186 | } else { | 196 | } else { |
187 | vec![] | 197 | vec![] |
188 | } | 198 | } |
189 | } | 199 | } |
190 | 200 | ||
191 | impl TypeBound { | 201 | impl TypeBound { |
192 | pub(crate) fn from_ast(node: ast::TypeBound) -> Self { | 202 | pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self { |
193 | match node.kind() { | 203 | match node.kind() { |
194 | ast::TypeBoundKind::PathType(path_type) => { | 204 | ast::TypeBoundKind::PathType(path_type) => { |
195 | let path = match path_type.path() { | 205 | let path = match path_type.path() { |
196 | Some(p) => p, | 206 | Some(p) => p, |
197 | None => return TypeBound::Error, | 207 | None => return TypeBound::Error, |
198 | }; | 208 | }; |
199 | // FIXME: Use `Path::from_src` | 209 | |
200 | let path = match Path::from_ast(path) { | 210 | let path = match ctx.lower_path(path) { |
201 | Some(p) => p, | 211 | Some(p) => p, |
202 | None => return TypeBound::Error, | 212 | None => return TypeBound::Error, |
203 | }; | 213 | }; |
diff --git a/crates/ra_hir_expand/src/builtin_derive.rs b/crates/ra_hir_expand/src/builtin_derive.rs index e60f879a3..1dc9cac66 100644 --- a/crates/ra_hir_expand/src/builtin_derive.rs +++ b/crates/ra_hir_expand/src/builtin_derive.rs | |||
@@ -38,7 +38,7 @@ macro_rules! register_builtin { | |||
38 | _ => return None, | 38 | _ => return None, |
39 | }; | 39 | }; |
40 | 40 | ||
41 | Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind) }) | 41 | Some(MacroDefId { krate: None, ast_id: None, kind: MacroDefKind::BuiltInDerive(kind), local_inner: false }) |
42 | } | 42 | } |
43 | }; | 43 | }; |
44 | } | 44 | } |
diff --git a/crates/ra_hir_expand/src/builtin_macro.rs b/crates/ra_hir_expand/src/builtin_macro.rs index e0fef613d..d8b3d342c 100644 --- a/crates/ra_hir_expand/src/builtin_macro.rs +++ b/crates/ra_hir_expand/src/builtin_macro.rs | |||
@@ -73,11 +73,13 @@ pub fn find_builtin_macro( | |||
73 | krate: Some(krate), | 73 | krate: Some(krate), |
74 | ast_id: Some(ast_id), | 74 | ast_id: Some(ast_id), |
75 | kind: MacroDefKind::BuiltIn(kind), | 75 | kind: MacroDefKind::BuiltIn(kind), |
76 | local_inner: false, | ||
76 | }), | 77 | }), |
77 | Either::Right(kind) => Some(MacroDefId { | 78 | Either::Right(kind) => Some(MacroDefId { |
78 | krate: Some(krate), | 79 | krate: Some(krate), |
79 | ast_id: Some(ast_id), | 80 | ast_id: Some(ast_id), |
80 | kind: MacroDefKind::BuiltInEager(kind), | 81 | kind: MacroDefKind::BuiltInEager(kind), |
82 | local_inner: false, | ||
81 | }), | 83 | }), |
82 | } | 84 | } |
83 | } | 85 | } |
@@ -406,6 +408,7 @@ mod tests { | |||
406 | krate: Some(CrateId(0)), | 408 | krate: Some(CrateId(0)), |
407 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), | 409 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(¯o_calls[0]))), |
408 | kind: MacroDefKind::BuiltIn(expander), | 410 | kind: MacroDefKind::BuiltIn(expander), |
411 | local_inner: false, | ||
409 | }; | 412 | }; |
410 | 413 | ||
411 | let loc = MacroCallLoc { | 414 | let loc = MacroCallLoc { |
@@ -425,6 +428,7 @@ mod tests { | |||
425 | krate: Some(CrateId(0)), | 428 | krate: Some(CrateId(0)), |
426 | ast_id: Some(AstId::new(file_id.into(), ast_id_map.ast_id(&am |