diff options
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/expr.rs | 103 | ||||
-rw-r--r-- | crates/ra_hir/src/marks.rs | 1 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 20 |
3 files changed, 80 insertions, 44 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 | }; |
14 | use test_utils::tested_by; | ||
14 | 15 | ||
15 | use crate::{ | 16 | use 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 | }; |
21 | use crate::{ | ||
22 | path::GenericArgs, | ||
23 | ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, | ||
24 | }; | ||
25 | 24 | ||
26 | pub use self::scope::ExprScopes; | 25 | pub 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] |
148 | fn infer_while_let() { | ||
149 | covers!(infer_while_let); | ||
150 | let (db, pos) = MockDatabase::with_position( | ||
151 | r#" | ||
152 | //- /main.rs | ||
153 | enum Option<T> { Some(T), None } | ||
154 | |||
155 | fn 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] | ||
148 | fn infer_basics() { | 168 | fn infer_basics() { |
149 | assert_snapshot_matches!( | 169 | assert_snapshot_matches!( |
150 | infer(r#" | 170 | infer(r#" |