From 6efc79b89d50b1b2ad9127afb2073bebe4b35290 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Wed, 7 Aug 2019 15:14:22 +0200 Subject: implement while let desugaring --- crates/ra_hir/src/expr.rs | 40 +++++++++++++++++++++++------------- crates/ra_hir/src/marks.rs | 1 + crates/ra_hir/src/ty/tests.rs | 20 ++++++++++++++++++ crates/ra_ide_api/src/inlay_hints.rs | 36 +++++++++++++++++++++++++------- 4 files changed, 76 insertions(+), 21 deletions(-) diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index b59787a83..f33676655 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -11,17 +11,16 @@ use ra_syntax::{ }, AstNode, AstPtr, SyntaxNodePtr, }; +use test_utils::tested_by; use crate::{ name::{AsName, SELF_PARAM}, + path::GenericArgs, + ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, type_ref::{Mutability, TypeRef}, DefWithBody, Either, HasSource, HirDatabase, HirFileId, MacroCallLoc, MacroFileKind, Name, Path, Resolver, }; -use crate::{ - path::GenericArgs, - ty::primitive::{FloatTy, IntTy, UncertainFloatTy, UncertainIntTy}, -}; pub use self::scope::ExprScopes; @@ -603,17 +602,30 @@ where self.alloc_expr(Expr::Loop { body }, syntax_ptr) } ast::ExprKind::WhileExpr(e) => { - let condition = if let Some(condition) = e.condition() { - if condition.pat().is_none() { - self.collect_expr_opt(condition.expr()) - } else { - // FIXME handle while let - return self.alloc_expr(Expr::Missing, syntax_ptr); - } - } else { - self.exprs.alloc(Expr::Missing) - }; let body = self.collect_block_opt(e.loop_body()); + + let condition = match e.condition() { + None => self.exprs.alloc(Expr::Missing), + Some(condition) => match condition.pat() { + None => self.collect_expr_opt(condition.expr()), + // if let -- desugar to match + Some(pat) => { + tested_by!(infer_while_let); + let pat = self.collect_pat(pat); + let match_expr = self.collect_expr_opt(condition.expr()); + let placeholder_pat = self.pats.alloc(Pat::Missing); + let break_ = self.exprs.alloc(Expr::Break { expr: None }); + let arms = vec![ + MatchArm { pats: vec![pat], expr: body, guard: None }, + MatchArm { pats: vec![placeholder_pat], expr: break_, guard: None }, + ]; + let match_expr = + self.exprs.alloc(Expr::Match { expr: match_expr, arms }); + return self.alloc_expr(Expr::Loop { body: match_expr }, syntax_ptr); + } + }, + }; + self.alloc_expr(Expr::While { condition, body }, syntax_ptr) } 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!( std_prelude match_ergonomics_ref trait_resolution_on_fn_type + infer_while_let ); 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 @@ -144,6 +144,26 @@ mod collections { assert_eq!("&str", type_at_pos(&db, pos)); } +#[test] +fn infer_while_let() { + covers!(infer_while_let); + let (db, pos) = MockDatabase::with_position( + r#" +//- /main.rs +enum Option { Some(T), None } + +fn test() { + let foo: Option = None; + while let Option::Some(x) = foo { + <|>x + } +} + +"#, + ); + assert_eq!("f32", type_at_pos(&db, pos)); +} + #[test] fn infer_basics() { assert_snapshot_matches!( 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() { }"#, ); - assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r#"[ - InlayHint { - range: [166; 170), - kind: TypeHint, - label: "CustomOption", - }, -]"# + assert_debug_snapshot_matches!(analysis.inlay_hints(file_id).unwrap(), @r###" + ⋮[ + ⋮ InlayHint { + ⋮ range: [166; 170), + ⋮ kind: TypeHint, + ⋮ label: "CustomOption", + ⋮ }, + ⋮ InlayHint { + ⋮ range: [343; 347), + ⋮ kind: TypeHint, + ⋮ label: "&Test", + ⋮ }, + ⋮ InlayHint { + ⋮ range: [401; 402), + ⋮ kind: TypeHint, + ⋮ label: "&CustomOption", + ⋮ }, + ⋮ InlayHint { + ⋮ range: [404; 405), + ⋮ kind: TypeHint, + ⋮ label: "&u8", + ⋮ }, + ⋮ InlayHint { + ⋮ range: [549; 550), + ⋮ kind: TypeHint, + ⋮ label: "&u32", + ⋮ }, + ⋮] + "### ); } -- cgit v1.2.3