diff options
Diffstat (limited to 'crates')
-rw-r--r-- | crates/ra_hir_def/src/adt.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir_def/src/body/lower.rs | 38 | ||||
-rw-r--r-- | crates/ra_hir_def/src/expr.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/pat.rs | 4 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/patterns.rs | 46 | ||||
-rw-r--r-- | crates/ra_ide/src/references/rename.rs | 106 | ||||
-rw-r--r-- | crates/ra_mbe/src/subtree_source.rs | 5 | ||||
-rw-r--r-- | crates/ra_mbe/src/tests.rs | 22 |
8 files changed, 214 insertions, 10 deletions
diff --git a/crates/ra_hir_def/src/adt.rs b/crates/ra_hir_def/src/adt.rs index 985f409e8..2bdfc2b8d 100644 --- a/crates/ra_hir_def/src/adt.rs +++ b/crates/ra_hir_def/src/adt.rs | |||
@@ -174,6 +174,7 @@ impl HasChildSource for VariantId { | |||
174 | } | 174 | } |
175 | } | 175 | } |
176 | 176 | ||
177 | #[derive(Debug, Copy, Clone, PartialEq, Eq)] | ||
177 | pub enum StructKind { | 178 | pub enum StructKind { |
178 | Tuple, | 179 | Tuple, |
179 | Record, | 180 | Record, |
diff --git a/crates/ra_hir_def/src/body/lower.rs b/crates/ra_hir_def/src/body/lower.rs index b1626fa11..b3fb6d452 100644 --- a/crates/ra_hir_def/src/body/lower.rs +++ b/crates/ra_hir_def/src/body/lower.rs | |||
@@ -15,6 +15,7 @@ use ra_syntax::{ | |||
15 | use test_utils::tested_by; | 15 | use test_utils::tested_by; |
16 | 16 | ||
17 | use crate::{ | 17 | use crate::{ |
18 | adt::StructKind, | ||
18 | body::{Body, BodySourceMap, Expander, PatPtr}, | 19 | body::{Body, BodySourceMap, Expander, PatPtr}, |
19 | builtin_type::{BuiltinFloat, BuiltinInt}, | 20 | builtin_type::{BuiltinFloat, BuiltinInt}, |
20 | db::DefDatabase, | 21 | db::DefDatabase, |
@@ -22,11 +23,12 @@ use crate::{ | |||
22 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, | 23 | ArithOp, Array, BinaryOp, BindingAnnotation, CmpOp, Expr, ExprId, Literal, LogicOp, |
23 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, | 24 | MatchArm, Ordering, Pat, PatId, RecordFieldPat, RecordLitField, Statement, |
24 | }, | 25 | }, |
26 | item_scope::BuiltinShadowMode, | ||
25 | path::GenericArgs, | 27 | path::GenericArgs, |
26 | path::Path, | 28 | path::Path, |
27 | type_ref::{Mutability, TypeRef}, | 29 | type_ref::{Mutability, TypeRef}, |
28 | ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, StaticLoc, | 30 | AdtId, ConstLoc, ContainerId, DefWithBodyId, EnumLoc, FunctionLoc, Intern, ModuleDefId, |
29 | StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, | 31 | StaticLoc, StructLoc, TraitLoc, TypeAliasLoc, UnionLoc, |
30 | }; | 32 | }; |
31 | 33 | ||
32 | pub(super) fn lower( | 34 | pub(super) fn lower( |
@@ -571,7 +573,37 @@ where | |||
571 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); | 573 | let name = bp.name().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); |
572 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); | 574 | let annotation = BindingAnnotation::new(bp.is_mutable(), bp.is_ref()); |
573 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); | 575 | let subpat = bp.pat().map(|subpat| self.collect_pat(subpat)); |
574 | Pat::Bind { name, mode: annotation, subpat } | 576 | if annotation == BindingAnnotation::Unannotated && subpat.is_none() { |
577 | // This could also be a single-segment path pattern. To | ||
578 | // decide that, we need to try resolving the name. | ||
579 | let (resolved, _) = self.expander.crate_def_map.resolve_path( | ||
580 | self.db, | ||
581 | self.expander.module.local_id, | ||
582 | &name.clone().into(), | ||
583 | BuiltinShadowMode::Other, | ||
584 | ); | ||
585 | match resolved.take_values() { | ||
586 | Some(ModuleDefId::ConstId(_)) => Pat::Path(name.into()), | ||
587 | Some(ModuleDefId::EnumVariantId(_)) => { | ||
588 | // this is only really valid for unit variants, but | ||
589 | // shadowing other enum variants with a pattern is | ||
590 | // an error anyway | ||
591 | Pat::Path(name.into()) | ||
592 | } | ||
593 | Some(ModuleDefId::AdtId(AdtId::StructId(s))) | ||
594 | if self.db.struct_data(s).variant_data.kind() != StructKind::Record => | ||
595 | { | ||
596 | // Funnily enough, record structs *can* be shadowed | ||
597 | // by pattern bindings (but unit or tuple structs | ||
598 | // can't). | ||
599 | Pat::Path(name.into()) | ||
600 | } | ||
601 | // shadowing statics is an error as well, so we just ignore that case here | ||
602 | _ => Pat::Bind { name, mode: annotation, subpat }, | ||
603 | } | ||
604 | } else { | ||
605 | Pat::Bind { name, mode: annotation, subpat } | ||
606 | } | ||
575 | } | 607 | } |
576 | ast::Pat::TupleStructPat(p) => { | 608 | ast::Pat::TupleStructPat(p) => { |
577 | let path = p.path().and_then(|path| self.expander.parse_path(path)); | 609 | let path = p.path().and_then(|path| self.expander.parse_path(path)); |
diff --git a/crates/ra_hir_def/src/expr.rs b/crates/ra_hir_def/src/expr.rs index 9707c5527..66d004717 100644 --- a/crates/ra_hir_def/src/expr.rs +++ b/crates/ra_hir_def/src/expr.rs | |||
@@ -48,7 +48,7 @@ pub enum Literal { | |||
48 | 48 | ||
49 | #[derive(Debug, Clone, Eq, PartialEq)] | 49 | #[derive(Debug, Clone, Eq, PartialEq)] |
50 | pub enum Expr { | 50 | pub enum Expr { |
51 | /// This is produced if syntax tree does not have a required expression piece. | 51 | /// This is produced if the syntax tree does not have a required expression piece. |
52 | Missing, | 52 | Missing, |
53 | Path(Path), | 53 | Path(Path), |
54 | If { | 54 | If { |
diff --git a/crates/ra_hir_ty/src/infer/pat.rs b/crates/ra_hir_ty/src/infer/pat.rs index a495ecbfe..bf8ea192b 100644 --- a/crates/ra_hir_ty/src/infer/pat.rs +++ b/crates/ra_hir_ty/src/infer/pat.rs | |||
@@ -189,7 +189,9 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> { | |||
189 | }; | 189 | }; |
190 | // use a new type variable if we got Ty::Unknown here | 190 | // use a new type variable if we got Ty::Unknown here |
191 | let ty = self.insert_type_vars_shallow(ty); | 191 | let ty = self.insert_type_vars_shallow(ty); |
192 | self.unify(&ty, expected); | 192 | if !self.unify(&ty, expected) { |
193 | // FIXME record mismatch, we need to change the type of self.type_mismatches for that | ||
194 | } | ||
193 | let ty = self.resolve_ty_as_possible(ty); | 195 | let ty = self.resolve_ty_as_possible(ty); |
194 | self.write_pat_ty(pat, ty.clone()); | 196 | self.write_pat_ty(pat, ty.clone()); |
195 | ty | 197 | ty |
diff --git a/crates/ra_hir_ty/src/tests/patterns.rs b/crates/ra_hir_ty/src/tests/patterns.rs index e25d6dbc4..81d00c2af 100644 --- a/crates/ra_hir_ty/src/tests/patterns.rs +++ b/crates/ra_hir_ty/src/tests/patterns.rs | |||
@@ -1,4 +1,4 @@ | |||
1 | use super::infer; | 1 | use super::{infer, infer_with_mismatches}; |
2 | use insta::assert_snapshot; | 2 | use insta::assert_snapshot; |
3 | use test_utils::covers; | 3 | use test_utils::covers; |
4 | 4 | ||
@@ -236,3 +236,47 @@ fn test(a1: A<u32>, o: Option<u64>) { | |||
236 | "### | 236 | "### |
237 | ); | 237 | ); |
238 | } | 238 | } |
239 | |||
240 | #[test] | ||
241 | fn infer_const_pattern() { | ||
242 | assert_snapshot!( | ||
243 | infer_with_mismatches(r#" | ||
244 | enum Option<T> { None } | ||
245 | use Option::None; | ||
246 | struct Foo; | ||
247 | const Bar: usize = 1; | ||
248 | |||
249 | fn test() { | ||
250 | let a: Option<u32> = None; | ||
251 | let b: Option<i64> = match a { | ||
252 | None => None, | ||
253 | }; | ||
254 | let _: () = match () { Foo => Foo }; // Expected mismatch | ||
255 | let _: () = match () { Bar => Bar }; // Expected mismatch | ||
256 | } | ||
257 | "#, true), | ||
258 | @r###" | ||
259 | [74; 75) '1': usize | ||
260 | [88; 310) '{ ...atch }': () | ||
261 | [98; 99) 'a': Option<u32> | ||
262 | [115; 119) 'None': Option<u32> | ||
263 | [129; 130) 'b': Option<i64> | ||
264 | [146; 183) 'match ... }': Option<i64> | ||
265 | [152; 153) 'a': Option<u32> | ||
266 | [164; 168) 'None': Option<u32> | ||
267 | [172; 176) 'None': Option<i64> | ||
268 | [193; 194) '_': () | ||
269 | [201; 224) 'match ... Foo }': Foo | ||
270 | [207; 209) '()': () | ||
271 | [212; 215) 'Foo': Foo | ||
272 | [219; 222) 'Foo': Foo | ||
273 | [255; 256) '_': () | ||
274 | [263; 286) 'match ... Bar }': usize | ||
275 | [269; 271) '()': () | ||
276 | [274; 277) 'Bar': usize | ||
277 | [281; 284) 'Bar': usize | ||
278 | [201; 224): expected (), got Foo | ||
279 | [263; 286): expected (), got usize | ||
280 | "### | ||
281 | ); | ||
282 | } | ||
diff --git a/crates/ra_ide/src/references/rename.rs b/crates/ra_ide/src/references/rename.rs index c46b78cb6..bdb90020b 100644 --- a/crates/ra_ide/src/references/rename.rs +++ b/crates/ra_ide/src/references/rename.rs | |||
@@ -98,6 +98,17 @@ fn rename_mod( | |||
98 | }; | 98 | }; |
99 | source_file_edits.push(edit); | 99 | source_file_edits.push(edit); |
100 | 100 | ||
101 | if let Some(RangeInfo { range: _, info: refs }) = find_all_refs(db, position, None) { | ||
102 | let ref_edits = refs.references.into_iter().map(|reference| { | ||
103 | source_edit_from_file_id_range( | ||
104 | reference.file_range.file_id, | ||
105 | reference.file_range.range, | ||
106 | new_name, | ||
107 | ) | ||
108 | }); | ||
109 | source_file_edits.extend(ref_edits); | ||
110 | } | ||
111 | |||
101 | Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits)) | 112 | Some(SourceChange::from_edits("rename", source_file_edits, file_system_edits)) |
102 | } | 113 | } |
103 | 114 | ||
@@ -383,6 +394,101 @@ mod tests { | |||
383 | ); | 394 | ); |
384 | } | 395 | } |
385 | 396 | ||
397 | #[test] | ||
398 | fn test_module_rename_in_path() { | ||
399 | test_rename( | ||
400 | r#" | ||
401 | mod <|>foo { | ||
402 | pub fn bar() {} | ||
403 | } | ||
404 | |||
405 | fn main() { | ||
406 | foo::bar(); | ||
407 | }"#, | ||
408 | "baz", | ||
409 | r#" | ||
410 | mod baz { | ||
411 | pub fn bar() {} | ||
412 | } | ||
413 | |||
414 | fn main() { | ||
415 | baz::bar(); | ||
416 | }"#, | ||
417 | ); | ||
418 | } | ||
419 | |||
420 | #[test] | ||
421 | fn test_rename_mod_filename_and_path() { | ||
422 | let (analysis, position) = analysis_and_position( | ||
423 | " | ||
424 | //- /lib.rs | ||
425 | mod bar; | ||
426 | fn f() { | ||
427 | bar::foo::fun() | ||
428 | } | ||
429 | |||
430 | //- /bar.rs | ||
431 | pub mod foo<|>; | ||
432 | |||
433 | //- /bar/foo.rs | ||
434 | // pub fn fun() {} | ||
435 | ", | ||
436 | ); | ||
437 | let new_name = "foo2"; | ||
438 | let source_change = analysis.rename(position, new_name).unwrap(); | ||
439 | assert_debug_snapshot!(&source_change, | ||
440 | @r###" | ||
441 | Some( | ||
442 | RangeInfo { | ||
443 | range: [8; 11), | ||
444 | info: SourceChange { | ||
445 | label: "rename", | ||
446 | source_file_edits: [ | ||
447 | SourceFileEdit { | ||
448 | file_id: FileId( | ||
449 | 2, | ||
450 | ), | ||
451 | edit: TextEdit { | ||
452 | atoms: [ | ||
453 | AtomTextEdit { | ||
454 | delete: [8; 11), | ||
455 | insert: "foo2", | ||
456 | }, | ||
457 | ], | ||
458 | }, | ||
459 | }, | ||
460 | SourceFileEdit { | ||
461 | file_id: FileId( | ||
462 | 1, | ||
463 | ), | ||
464 | edit: TextEdit { | ||
465 | atoms: [ | ||
466 | AtomTextEdit { | ||
467 | delete: [27; 30), | ||
468 | insert: "foo2", | ||
469 | }, | ||
470 | ], | ||
471 | }, | ||
472 | }, | ||
473 | ], | ||
474 | file_system_edits: [ | ||
475 | MoveFile { | ||
476 | src: FileId( | ||
477 | 3, | ||
478 | ), | ||
479 | dst_source_root: SourceRootId( | ||
480 | 0, | ||
481 | ), | ||
482 | dst_path: "bar/foo2.rs", | ||
483 | }, | ||
484 | ], | ||
485 | cursor_position: None, | ||
486 | }, | ||
487 | }, | ||
488 | ) | ||
489 | "###); | ||
490 | } | ||
491 | |||
386 | fn test_rename(text: &str, new_name: &str, expected: &str) { | 492 | fn test_rename(text: &str, new_name: &str, expected: &str) { |
387 | let (analysis, position) = single_file_with_position(text); | 493 | let (analysis, position) = single_file_with_position(text); |
388 | let source_change = analysis.rename(position, new_name).unwrap(); | 494 | let source_change = analysis.rename(position, new_name).unwrap(); |
diff --git a/crates/ra_mbe/src/subtree_source.rs b/crates/ra_mbe/src/subtree_source.rs index dacca8279..91e324db9 100644 --- a/crates/ra_mbe/src/subtree_source.rs +++ b/crates/ra_mbe/src/subtree_source.rs | |||
@@ -1,7 +1,7 @@ | |||
1 | //! FIXME: write short doc here | 1 | //! FIXME: write short doc here |
2 | 2 | ||
3 | use ra_parser::{Token, TokenSource}; | 3 | use ra_parser::{Token, TokenSource}; |
4 | use ra_syntax::{lex_single_valid_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; | 4 | use ra_syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; |
5 | use std::cell::{Cell, Ref, RefCell}; | 5 | use std::cell::{Cell, Ref, RefCell}; |
6 | use tt::buffer::{Cursor, TokenBuffer}; | 6 | use tt::buffer::{Cursor, TokenBuffer}; |
7 | 7 | ||
@@ -129,7 +129,8 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken { | |||
129 | } | 129 | } |
130 | 130 | ||
131 | fn convert_literal(l: &tt::Literal) -> TtToken { | 131 | fn convert_literal(l: &tt::Literal) -> TtToken { |
132 | let kind = lex_single_valid_syntax_kind(&l.text) | 132 | let kind = lex_single_syntax_kind(&l.text) |
133 | .map(|(kind, _error)| kind) | ||
133 | .filter(|kind| kind.is_literal()) | 134 | .filter(|kind| kind.is_literal()) |
134 | .unwrap_or_else(|| match l.text.as_ref() { | 135 | .unwrap_or_else(|| match l.text.as_ref() { |
135 | "true" => T![true], | 136 | "true" => T![true], |
diff --git a/crates/ra_mbe/src/tests.rs b/crates/ra_mbe/src/tests.rs index e0d689704..cb228702f 100644 --- a/crates/ra_mbe/src/tests.rs +++ b/crates/ra_mbe/src/tests.rs | |||
@@ -1374,14 +1374,22 @@ pub(crate) struct MacroFixture { | |||
1374 | 1374 | ||
1375 | impl MacroFixture { | 1375 | impl MacroFixture { |
1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | 1376 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { |
1377 | let source_file = ast::SourceFile::parse(invocation).ok().unwrap(); | 1377 | self.try_expand_tt(invocation).unwrap() |
1378 | } | ||
1379 | |||
1380 | fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> { | ||
1381 | let source_file = ast::SourceFile::parse(invocation).tree(); | ||
1378 | let macro_invocation = | 1382 | let macro_invocation = |
1379 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | 1383 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); |
1380 | 1384 | ||
1381 | let (invocation_tt, _) = | 1385 | let (invocation_tt, _) = |
1382 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); | 1386 | ast_to_token_tree(¯o_invocation.token_tree().unwrap()).unwrap(); |
1383 | 1387 | ||
1384 | self.rules.expand(&invocation_tt).unwrap() | 1388 | self.rules.expand(&invocation_tt) |
1389 | } | ||
1390 | |||
1391 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { | ||
1392 | assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); | ||
1385 | } | 1393 | } |
1386 | 1394 | ||
1387 | fn expand_items(&self, invocation: &str) -> SyntaxNode { | 1395 | fn expand_items(&self, invocation: &str) -> SyntaxNode { |
@@ -1539,3 +1547,13 @@ fn test_repeat_bad_var() { | |||
1539 | ) | 1547 | ) |
1540 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); | 1548 | .assert_expand_items("foo!(b0 b1);", "b0 b1"); |
1541 | } | 1549 | } |
1550 | |||
1551 | #[test] | ||
1552 | fn test_expand_bad_literal() { | ||
1553 | parse_macro( | ||
1554 | r#" | ||
1555 | macro_rules! foo { ($i:literal) => {}; } | ||
1556 | "#, | ||
1557 | ) | ||
1558 | .assert_expand_err(r#"foo!(&k");"#, &ExpandError::NoMatchingRule); | ||
1559 | } | ||