fix AST for if expressions

then is not always a block...
This commit is contained in:
Aleksey Kladov 2019-01-27 00:23:07 +03:00
parent 2d337c88b0
commit 619af1e22c
6 changed files with 112 additions and 5 deletions

View file

@ -498,7 +498,13 @@ impl ExprCollector {
let then_branch = self.collect_block_opt(e.then_branch()); let then_branch = self.collect_block_opt(e.then_branch());
let else_branch = e let else_branch = e
.else_branch() .else_branch()
.map(|e| self.collect_block(e)) .map(|b| match b {
ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
ast::ElseBranchFlavor::IfExpr(elif) => {
let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
self.collect_expr(expr)
}
})
.unwrap_or_else(|| self.empty_block()); .unwrap_or_else(|| self.empty_block());
let placeholder_pat = self.pats.alloc(Pat::Missing); let placeholder_pat = self.pats.alloc(Pat::Missing);
let arms = vec![ let arms = vec![
@ -521,7 +527,13 @@ impl ExprCollector {
} else { } else {
let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr())); let condition = self.collect_expr_opt(e.condition().and_then(|c| c.expr()));
let then_branch = self.collect_block_opt(e.then_branch()); let then_branch = self.collect_block_opt(e.then_branch());
let else_branch = e.else_branch().map(|e| self.collect_block(e)); let else_branch = e.else_branch().map(|b| match b {
ast::ElseBranchFlavor::Block(it) => self.collect_block(it),
ast::ElseBranchFlavor::IfExpr(elif) => {
let expr: &ast::Expr = ast::Expr::cast(elif.syntax()).unwrap();
self.collect_expr(expr)
}
});
self.alloc_expr( self.alloc_expr(
Expr::If { Expr::If {
condition, condition,

View file

@ -0,0 +1,17 @@
---
created: "2019-01-26T21:36:52.714121185+00:00"
creator: insta@0.5.2
expression: "&result"
source: crates/ra_hir/src/ty/tests.rs
---
[35; 38) 'foo': Foo
[45; 109) '{ ... } }': ()
[51; 107) 'if tru... }': ()
[54; 58) 'true': bool
[59; 67) '{ }': ()
[73; 107) 'if fal... }': i32
[76; 81) 'false': bool
[82; 107) '{ ... }': i32
[92; 95) 'foo': Foo
[92; 101) 'foo.field': i32

View file

@ -284,6 +284,23 @@ fn test() {
); );
} }
#[test]
fn infer_in_elseif() {
check_inference(
"infer_in_elseif",
r#"
struct Foo { field: i32 }
fn main(foo: Foo) {
if true {
} else if false {
foo.field
}
}
"#,
)
}
#[test] #[test]
fn infer_inherent_method() { fn infer_inherent_method() {
check_inference( check_inference(

View file

@ -11,7 +11,10 @@ pub fn replace_if_let_with_match(ctx: AssistCtx) -> Option<Assist> {
let pat = cond.pat()?; let pat = cond.pat()?;
let expr = cond.expr()?; let expr = cond.expr()?;
let then_block = if_expr.then_branch()?; let then_block = if_expr.then_branch()?;
let else_block = if_expr.else_branch()?; let else_block = match if_expr.else_branch()? {
ast::ElseBranchFlavor::Block(it) => it,
ast::ElseBranchFlavor::IfExpr(_) => return None,
};
ctx.build("replace with match", |edit| { ctx.build("replace with match", |edit| {
let match_expr = build_match_expr(expr, pat, then_block, else_block); let match_expr = build_match_expr(expr, pat, then_block, else_block);

View file

@ -285,13 +285,27 @@ impl LetStmt {
} }
} }
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum ElseBranchFlavor<'a> {
Block(&'a Block),
IfExpr(&'a IfExpr),
}
impl IfExpr { impl IfExpr {
pub fn then_branch(&self) -> Option<&Block> { pub fn then_branch(&self) -> Option<&Block> {
self.blocks().nth(0) self.blocks().nth(0)
} }
pub fn else_branch(&self) -> Option<&Block> { pub fn else_branch(&self) -> Option<ElseBranchFlavor> {
self.blocks().nth(1) let res = match self.blocks().nth(1) {
Some(block) => ElseBranchFlavor::Block(block),
None => {
let elif: &IfExpr = child_opt(self)?;
ElseBranchFlavor::IfExpr(elif)
}
};
Some(res)
} }
fn blocks(&self) -> AstChildren<Block> { fn blocks(&self) -> AstChildren<Block> {
children(self) children(self)
} }

View file

@ -660,6 +660,50 @@ impl ToOwned for DynTraitType {
impl DynTraitType {} impl DynTraitType {}
// ElseBranch
#[derive(Debug, PartialEq, Eq, Hash)]
#[repr(transparent)]
pub struct ElseBranch {
pub(crate) syntax: SyntaxNode,
}
unsafe impl TransparentNewType for ElseBranch {
type Repr = rowan::SyntaxNode<RaTypes>;
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ElseBranchKind<'a> {
Block(&'a Block),
IfExpr(&'a IfExpr),
}
impl AstNode for ElseBranch {
fn cast(syntax: &SyntaxNode) -> Option<&Self> {
match syntax.kind() {
| BLOCK
| IF_EXPR => Some(ElseBranch::from_repr(syntax.into_repr())),
_ => None,
}
}
fn syntax(&self) -> &SyntaxNode { &self.syntax }
}
impl ToOwned for ElseBranch {
type Owned = TreeArc<ElseBranch>;
fn to_owned(&self) -> TreeArc<ElseBranch> { TreeArc::cast(self.syntax.to_owned()) }
}
impl ElseBranch {
pub fn kind(&self) -> ElseBranchKind {
match self.syntax.kind() {
BLOCK => ElseBranchKind::Block(Block::cast(&self.syntax).unwrap()),
IF_EXPR => ElseBranchKind::IfExpr(IfExpr::cast(&self.syntax).unwrap()),
_ => unreachable!(),
}
}
}
impl ElseBranch {}
// EnumDef // EnumDef
#[derive(Debug, PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
#[repr(transparent)] #[repr(transparent)]