aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir/src/expr.rs103
-rw-r--r--crates/ra_hir/src/marks.rs1
-rw-r--r--crates/ra_hir/src/ty/tests.rs20
-rw-r--r--crates/ra_ide_api/src/inlay_hints.rs36
-rw-r--r--crates/ra_parser/src/grammar/type_args.rs7
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs1
-rw-r--r--crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt55
7 files changed, 172 insertions, 51 deletions
diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs
index 4dcea19a9..f33676655 100644
--- a/crates/ra_hir/src/expr.rs
+++ b/crates/ra_hir/src/expr.rs
@@ -11,17 +11,16 @@ use ra_syntax::{
11 }, 11 },
12 AstNode, AstPtr, SyntaxNodePtr, 12 AstNode, AstPtr, SyntaxNodePtr,
13}; 13};
14use test_utils::tested_by;
14 15
15use crate::{ 16use crate::{
16 name::{AsName, SELF_PARAM}, 17 name::{AsName, SELF_PARAM},
18 path::GenericArgs,
19 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
17 type_ref::{Mutability, TypeRef}, 20 type_ref::{Mutability, TypeRef},
18 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, 21 DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name,
19 Path, Resolver, 22 Path, Resolver,
20}; 23};
21use crate::{
22 path::GenericArgs,
23 ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy},
24};
25 24
26pub use self::scope::ExprScopes; 25pub use self::scope::ExprScopes;
27 26
@@ -558,37 +557,40 @@ where
558 let syntax_ptr = SyntaxNodePtr::new(expr.syntax()); 557 let syntax_ptr = SyntaxNodePtr::new(expr.syntax());
559 match expr.kind() { 558 match expr.kind() {
560 ast::ExprKind::IfExpr(e) => { 559 ast::ExprKind::IfExpr(e) => {
561 if let Some(pat) = e.condition().and_then(|c| c.pat()) { 560 let then_branch = self.collect_block_opt(e.then_branch());
562 // if let -- desugar to match 561
563 let pat = self.collect_pat(pat); 562 let else_branch = e.else_branch().map(|b| match b {
564 let match_expr = 563 ast::ElseBranch::Block(it) => self.collect_block(it),
565 self.collect_expr_opt(e.condition().expect("checked above").expr()); 564 ast::ElseBranch::IfExpr(elif) => {
566 let then_branch = self.collect_block_opt(e.then_branch()); 565 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap();
567 let else_branch = e 566 self.collect_expr(expr)
568 .else_branch() 567 }
569 .map(|b| match b { 568 });
570 ast::ElseBranch::Block(it) => self.collect_block(it), 569
571 ast::ElseBranch::IfExpr(elif) => self.collect_expr(elif.into()), 570 let condition = match e.condition() {
572 }) 571 None => self.exprs.alloc(Expr::Missing),
573 .unwrap_or_else(|| self.empty_block()); 572 Some(condition) => match condition.pat() {
574 let placeholder_pat = self.pats.alloc(Pat::Missing); 573 None => self.collect_expr_opt(condition.expr()),
575 let arms = vec![ 574 // if let -- desugar to match
576 MatchArm { pats: vec![pat], expr: then_branch, guard: None }, 575 Some(pat) => {
577 MatchArm { pats: vec![placeholder_pat], expr: else_branch, guard: None }, 576 let pat = self.collect_pat(pat);
578 ]; 577 let match_expr = self.collect_expr_opt(condition.expr());
579 self.alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr) 578 let placeholder_pat = self.pats.alloc(Pat::Missing);
580 } else { 579 let arms = vec![
581 let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); 580 MatchArm { pats: vec![pat], expr: then_branch, guard: None },
582 let then_branch = self.collect_block_opt(e.then_branch()); 581 MatchArm {
583 let else_branch = e.else_branch().map(|b| match b { 582 pats: vec![placeholder_pat],
584 ast::ElseBranch::Block(it) => self.collect_block(it), 583 expr: else_branch.unwrap_or_else(|| self.empty_block()),
585 ast::ElseBranch::IfExpr(elif) => { 584 guard: None,
586 let expr: ast::Expr = ast::Expr::cast(elif.syntax().clone()).unwrap(); 585 },
587 self.collect_expr(expr) 586 ];
587 return self
588 .alloc_expr(Expr::Match { expr: match_expr, arms }, syntax_ptr);
588 } 589 }
589 }); 590 },
590 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr) 591 };
591 } 592
593 self.alloc_expr(Expr::If { condition, then_branch, else_branch }, syntax_ptr)
592 } 594 }
593 ast::ExprKind::TryBlockExpr(e) => { 595 ast::ExprKind::TryBlockExpr(e) => {
594 let body = self.collect_block_opt(e.try_body()); 596 let body = self.collect_block_opt(e.try_body());
@@ -600,17 +602,30 @@ where
600 self.alloc_expr(Expr::Loop { body }, syntax_ptr) 602 self.alloc_expr(Expr::Loop { body }, syntax_ptr)
601 } 603 }
602 ast::ExprKind::WhileExpr(e) => { 604 ast::ExprKind::WhileExpr(e) => {
603 let condition = if let Some(condition) = e.condition() {
604 if condition.pat().is_none() {
605 self.collect_expr_opt(condition.expr())
606 } else {
607 // FIXME handle while let
608 return self.alloc_expr(Expr::Missing, syntax_ptr);
609 }
610 } else {
611 self.exprs.alloc(Expr::Missing)
612 };
613 let body = self.collect_block_opt(e.loop_body()); 605 let body = self.collect_block_opt(e.loop_body());
606
607 let condition = match e.condition() {
608 None => self.exprs.alloc(Expr::Missing),
609 Some(condition) => match condition.pat() {
610 None => self.collect_expr_opt(condition.expr()),
611 // if let -- desugar to match
612 Some(pat) => {
613 tested_by!(infer_while_let);
614 let pat = self.collect_pat(pat);
615 let match_expr = self.collect_expr_opt(condition.expr());
616 let placeholder_pat = self.pats.alloc(Pat::Missing);
617 let break_ = self.exprs.alloc(Expr::Break { expr: None });
618 let arms = vec![
619 MatchArm { pats: vec![pat], expr: body, guard: None },
620 MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None },
621 ];
622 let match_expr =
623 self.exprs.alloc(Expr::Match { expr: match_expr, arms });
624 return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr);
625 }
626 },
627 };
628
614 self.alloc_expr(Expr::While { condition, body }, syntax_ptr) 629 self.alloc_expr(Expr::While { condition, body }, syntax_ptr)
615 } 630 }
616 ast::ExprKind::ForExpr(e) => { 631 ast::ExprKind::ForExpr(e) => {
diff --git a/crates/ra_hir/src/marks.rs b/crates/ra_hir/src/marks.rs
index 2d831f0d8..5b15eee90 100644
--- a/crates/ra_hir/src/marks.rs
+++ b/crates/ra_hir/src/marks.rs
@@ -10,4 +10,5 @@ test_utils::marks!(
10 std_prelude 10 std_prelude
11 match_ergonomics_ref 11 match_ergonomics_ref
12 trait_resolution_on_fn_type 12 trait_resolution_on_fn_type
13 infer_while_let
13); 14);
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 36dea17a3..d5f7a4d25 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -145,6 +145,26 @@ mod collections {
145} 145}
146 146
147#[test] 147#[test]
148fn infer_while_let() {
149 covers!(infer_while_let);
150 let (db, pos) = MockDatabase::with_position(
151 r#"
152//- /main.rs
153enum Option<T> { Some(T), None }
154
155fn test() {
156 let foo: Option<f32> = None;
157 while let Option::Some(x) = foo {
158 <|>x
159 }
160}
161
162"#,
163 );
164 assert_eq!("f32", type_at_pos(&db, pos));
165}
166
167#[test]
148fn infer_basics() { 168fn infer_basics() {
149 assert_snapshot_matches!( 169 assert_snapshot_matches!(
150 infer(r#" 170 infer(r#"
diff --git a/crates/ra_ide_api/src/inlay_hints.rs b/crates/ra_ide_api/src/inlay_hints.rs
index 7b9190314..0b3c96d26 100644
--- a/crates/ra_ide_api/src/inlay_hints.rs
+++ b/crates/ra_ide_api/src/inlay_hints.rs
@@ -414,13 +414,35 @@ fn main() {
414}"#, 414}"#,
415 ); 415 );
416 416
417 assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ 417 assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r###"
418 InlayHint { 418 ⋮[
419 range: [166; 170), 419 ⋮ InlayHint {
420 kind: TypeHint, 420 ⋮ range: [166; 170),
421 label: "CustomOption<Test>", 421 ⋮ kind: TypeHint,
422 }, 422 ⋮ label: "CustomOption<Test>",
423]"# 423 ⋮ },
424 ⋮ InlayHint {
425 ⋮ range: [343; 347),
426 ⋮ kind: TypeHint,
427 ⋮ label: "&Test",
428 ⋮ },
429 ⋮ InlayHint {
430 ⋮ range: [401; 402),
431 ⋮ kind: TypeHint,
432 ⋮ label: "&CustomOption<u32>",
433 ⋮ },
434 ⋮ InlayHint {
435 ⋮ range: [404; 405),
436 ⋮ kind: TypeHint,
437 ⋮ label: "&u8",
438 ⋮ },
439 ⋮ InlayHint {
440 ⋮ range: [549; 550),
441 ⋮ kind: TypeHint,
442 ⋮ label: "&u32",
443 ⋮ },
444 ⋮]
445 "###
424 ); 446 );
425 } 447 }
426 448
diff --git a/crates/ra_parser/src/grammar/type_args.rs b/crates/ra_parser/src/grammar/type_args.rs
index f391b63db..3db08b280 100644
--- a/crates/ra_parser/src/grammar/type_args.rs
+++ b/crates/ra_parser/src/grammar/type_args.rs
@@ -35,6 +35,13 @@ fn type_arg(p: &mut Parser) {
35 p.bump(); 35 p.bump();
36 m.complete(p, LIFETIME_ARG); 36 m.complete(p, LIFETIME_ARG);
37 } 37 }
38 // test associated_type_bounds
39 // fn print_all<T: Iterator<Item: Display>>(printables: T) {}
40 IDENT if p.nth(1) == T![:] => {
41 name_ref(p);
42 type_params::bounds(p);
43 m.complete(p, ASSOC_TYPE_ARG);
44 }
38 IDENT if p.nth(1) == T![=] => { 45 IDENT if p.nth(1) == T![=] => {
39 name_ref(p); 46 name_ref(p);
40 p.bump(); 47 p.bump();
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs
new file mode 100644
index 000000000..eb21a657b
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.rs
@@ -0,0 +1 @@
fn print_all<T: Iterator<Item: Display>>(printables: T) {}
diff --git a/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt
new file mode 100644
index 000000000..33e75510d
--- /dev/null
+++ b/crates/ra_syntax/test_data/parser/inline/ok/0138_associated_type_bounds.txt
@@ -0,0 +1,55 @@
1SOURCE_FILE@[0; 59)
2 FN_DEF@[0; 58)
3 FN_KW@[0; 2) "fn"
4 WHITESPACE@[2; 3) " "
5 NAME@[3; 12)
6 IDENT@[3; 12) "print_all"
7 TYPE_PARAM_LIST@[12; 40)
8 L_ANGLE@[12; 13) "<"
9 TYPE_PARAM@[13; 39)
10 NAME@[13; 14)
11 IDENT@[13; 14) "T"
12 COLON@[14; 15) ":"
13 WHITESPACE@[15; 16) " "
14 TYPE_BOUND_LIST@[16; 39)
15 TYPE_BOUND@[16; 39)
16 PATH_TYPE@[16; 39)
17 PATH@[16; 39)
18 PATH_SEGMENT@[16; 39)
19 NAME_REF@[16; 24)
20 IDENT@[16; 24) "Iterator"
21 TYPE_ARG_LIST@[24; 39)
22 L_ANGLE@[24; 25) "<"
23 ASSOC_TYPE_ARG@[25; 38)
24 NAME_REF@[25; 29)
25 IDENT@[25; 29) "Item"
26 COLON@[29; 30) ":"
27 WHITESPACE@[30; 31) " "
28 TYPE_BOUND_LIST@[31; 38)
29 TYPE_BOUND@[31; 38)
30 PATH_TYPE@[31; 38)
31 PATH@[31; 38)
32 PATH_SEGMENT@[31; 38)
33 NAME_REF@[31; 38)
34 IDENT@[31; 38) "Display"
35 R_ANGLE@[38; 39) ">"
36 R_ANGLE@[39; 40) ">"
37 PARAM_LIST@[40; 55)
38 L_PAREN@[40; 41) "("
39 PARAM@[41; 54)
40 BIND_PAT@[41; 51)
41 NAME@[41; 51)
42 IDENT@[41; 51) "printables"
43 COLON@[51; 52) ":"
44 WHITESPACE@[52; 53) " "
45 PATH_TYPE@[53; 54)
46 PATH@[53; 54)
47 PATH_SEGMENT@[53; 54)
48 NAME_REF@[53; 54)
49 IDENT@[53; 54) "T"
50 R_PAREN@[54; 55) ")"
51 WHITESPACE@[55; 56) " "
52 BLOCK@[56; 58)
53 L_CURLY@[56; 57) "{"
54 R_CURLY@[57; 58) "}"
55 WHITESPACE@[58; 59) "\n"