aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_def/src/adt.rs1
-rw-r--r--crates/ra_hir_def/src/body/lower.rs38
-rw-r--r--crates/ra_hir_def/src/expr.rs2
-rw-r--r--crates/ra_hir_ty/src/infer/pat.rs4
-rw-r--r--crates/ra_hir_ty/src/tests/patterns.rs46
-rw-r--r--crates/ra_ide/src/references/rename.rs106
-rw-r--r--crates/ra_mbe/src/subtree_source.rs5
-rw-r--r--crates/ra_mbe/src/tests.rs22
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)]
177pub enum StructKind { 178pub 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::{
15use test_utils::tested_by; 15use test_utils::tested_by;
16 16
17use crate::{ 17use 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
32pub(super) fn lower( 34pub(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)]
50pub enum Expr { 50pub 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 @@
1use super::infer; 1use super::{infer, infer_with_mismatches};
2use insta::assert_snapshot; 2use insta::assert_snapshot;
3use test_utils::covers; 3use 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]
241fn infer_const_pattern() {
242 assert_snapshot!(
243 infer_with_mismatches(r#"
244enum Option<T> { None }
245use Option::None;
246struct Foo;
247const Bar: usize = 1;
248
249fn 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
3use ra_parser::{Token, TokenSource}; 3use ra_parser::{Token, TokenSource};
4use ra_syntax::{lex_single_valid_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T}; 4use ra_syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T};
5use std::cell::{Cell, Ref, RefCell}; 5use std::cell::{Cell, Ref, RefCell};
6use tt::buffer::{Cursor, TokenBuffer}; 6use tt::buffer::{Cursor, TokenBuffer};
7 7
@@ -129,7 +129,8 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
129} 129}
130 130
131fn convert_literal(l: &tt::Literal) -> TtToken { 131fn 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
1375impl MacroFixture { 1375impl 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(&macro_invocation.token_tree().unwrap()).unwrap(); 1386 ast_to_token_tree(&macro_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]
1552fn 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}