From 0a780c0ab3869d92fb56ae3b2ddc7636fb169314 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 23 Dec 2020 12:15:38 +0100 Subject: Implement const pat inference --- crates/hir_def/src/body/lower.rs | 12 +++++++++--- crates/hir_def/src/expr.rs | 8 +++++++- crates/hir_ty/src/infer/pat.rs | 6 +++++- crates/hir_ty/src/tests/patterns.rs | 30 ++++++++++++++++++++++++++++++ 4 files changed, 51 insertions(+), 5 deletions(-) diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 978c3a324..4492a7d77 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -932,10 +932,16 @@ impl ExprCollector<'_> { let inner = self.collect_pat_opt(boxpat.pat()); Pat::Box { inner } } - // FIXME: implement - ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) | ast::Pat::ConstBlockPat(_) => { - Pat::Missing + ast::Pat::ConstBlockPat(const_block_pat) => { + if let Some(expr) = const_block_pat.block_expr() { + let expr_id = self.collect_block(expr); + Pat::ConstBlock(expr_id) + } else { + Pat::Missing + } } + // FIXME: implement + ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) => Pat::Missing, }; let ptr = AstPtr::new(&pat); self.alloc_pat(pattern, Either::Left(ptr)) diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index e5d740a36..b1e57c693 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs @@ -399,12 +399,18 @@ pub enum Pat { TupleStruct { path: Option, args: Vec, ellipsis: Option }, Ref { pat: PatId, mutability: Mutability }, Box { inner: PatId }, + ConstBlock(ExprId), } impl Pat { pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { match self { - Pat::Range { .. } | Pat::Lit(..) | Pat::Path(..) | Pat::Wild | Pat::Missing => {} + Pat::Range { .. } + | Pat::Lit(..) + | Pat::Path(..) + | Pat::ConstBlock(..) + | Pat::Wild + | Pat::Missing => {} Pat::Bind { subpat, .. } => { subpat.iter().copied().for_each(f); } diff --git a/crates/hir_ty/src/infer/pat.rs b/crates/hir_ty/src/infer/pat.rs index b70ec55eb..d974f805b 100644 --- a/crates/hir_ty/src/infer/pat.rs +++ b/crates/hir_ty/src/infer/pat.rs @@ -243,6 +243,9 @@ impl<'a> InferenceContext<'a> { } None => Ty::Unknown, }, + Pat::ConstBlock(expr) => { + self.infer_expr(*expr, &Expectation::has_type(expected.clone())) + } Pat::Missing => Ty::Unknown, }; // use a new type variable if we got Ty::Unknown here @@ -264,8 +267,9 @@ fn is_non_ref_pat(body: &hir_def::body::Body, pat: PatId) -> bool { | Pat::Range { .. } | Pat::Slice { .. } => true, Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), - // FIXME: Path/Lit might actually evaluate to ref, but inference is unimplemented. + // FIXME: ConstBlock/Path/Lit might actually evaluate to ref, but inference is unimplemented. Pat::Path(..) => true, + Pat::ConstBlock(..) => true, Pat::Lit(expr) => match body[*expr] { Expr::Literal(Literal::String(..)) => false, _ => true, diff --git a/crates/hir_ty/src/tests/patterns.rs b/crates/hir_ty/src/tests/patterns.rs index 5a5f48fd0..2053d8f56 100644 --- a/crates/hir_ty/src/tests/patterns.rs +++ b/crates/hir_ty/src/tests/patterns.rs @@ -774,3 +774,33 @@ fn foo(tuple: Tuple) { "#]], ); } + +#[test] +fn const_block_pattern() { + check_infer( + r#" +struct Foo(usize); +fn foo(foo: Foo) { + match foo { + const { Foo(15 + 32) } => {}, + _ => {} + } +}"#, + expect![[r#" + 26..29 'foo': Foo + 36..115 '{ ... } }': () + 42..113 'match ... }': () + 48..51 'foo': Foo + 62..84 'const ... 32) }': Foo + 68..84 '{ Foo(... 32) }': Foo + 70..73 'Foo': Foo(usize) -> Foo + 70..82 'Foo(15 + 32)': Foo + 74..76 '15': usize + 74..81 '15 + 32': usize + 79..81 '32': usize + 88..90 '{}': () + 100..101 '_': Foo + 105..107 '{}': () + "#]], + ); +} -- cgit v1.2.3 From a142beaf013a016a48eb9f193b55e0cbcb80b6a9 Mon Sep 17 00:00:00 2001 From: Lukas Wirth Date: Wed, 23 Dec 2020 12:24:24 +0100 Subject: Implement const block inference --- crates/hir_def/src/body/lower.rs | 4 ++++ crates/hir_def/src/expr.rs | 8 +++++++- crates/hir_ty/src/infer/expr.rs | 2 +- crates/hir_ty/src/tests/simple.rs | 13 +++++++++---- crates/syntax/src/ast/expr_ext.rs | 4 ++++ 5 files changed, 25 insertions(+), 6 deletions(-) diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs index 4492a7d77..1b98504bb 100644 --- a/crates/hir_def/src/body/lower.rs +++ b/crates/hir_def/src/body/lower.rs @@ -246,6 +246,10 @@ impl ExprCollector<'_> { let body = self.collect_block_opt(e.block_expr()); self.alloc_expr(Expr::Async { body }, syntax_ptr) } + ast::Effect::Const(_) => { + let body = self.collect_block_opt(e.block_expr()); + self.alloc_expr(Expr::Const { body }, syntax_ptr) + } }, ast::Expr::BlockExpr(e) => self.collect_block(e), ast::Expr::LoopExpr(e) => { diff --git a/crates/hir_def/src/expr.rs b/crates/hir_def/src/expr.rs index b1e57c693..3bba30397 100644 --- a/crates/hir_def/src/expr.rs +++ b/crates/hir_def/src/expr.rs @@ -114,6 +114,9 @@ pub enum Expr { Async { body: ExprId, }, + Const { + body: ExprId, + }, Cast { expr: ExprId, type_ref: TypeRef, @@ -253,7 +256,10 @@ impl Expr { f(*expr); } } - Expr::TryBlock { body } | Expr::Unsafe { body } | Expr::Async { body } => f(*body), + Expr::TryBlock { body } + | Expr::Unsafe { body } + | Expr::Async { body } + | Expr::Const { body } => f(*body), Expr::Loop { body, .. } => f(*body), Expr::While { condition, body, .. } => { f(*condition); diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs index 2cdce2cef..744569e6e 100644 --- a/crates/hir_ty/src/infer/expr.rs +++ b/crates/hir_ty/src/infer/expr.rs @@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> { } None => self.infer_block(statements, *tail, expected), }, - Expr::Unsafe { body } => self.infer_expr(*body, expected), + Expr::Unsafe { body } | Expr::Const { body } => self.infer_expr(*body, expected), Expr::TryBlock { body } => { let _inner = self.infer_expr(*body, expected); // FIXME should be std::result::Result<{inner}, _> diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs index a569223b4..a61282d5a 100644 --- a/crates/hir_ty/src/tests/simple.rs +++ b/crates/hir_ty/src/tests/simple.rs @@ -1894,6 +1894,7 @@ fn effects_smoke_test() { let x = unsafe { 92 }; let y = async { async { () }.await }; let z = try { () }; + let w = const { 92 }; let t = 'a: { 92 }; } @@ -1905,7 +1906,7 @@ fn effects_smoke_test() { } "#, expect![[r#" - 16..136 '{ ...2 }; }': () + 16..162 '{ ...2 }; }': () 26..27 'x': i32 30..43 'unsafe { 92 }': i32 37..43 '{ 92 }': i32 @@ -1921,9 +1922,13 @@ fn effects_smoke_test() { 99..109 'try { () }': {unknown} 103..109 '{ () }': () 105..107 '()': () - 119..120 't': i32 - 127..133 '{ 92 }': i32 - 129..131 '92': i32 + 119..120 'w': i32 + 123..135 'const { 92 }': i32 + 129..135 '{ 92 }': i32 + 131..133 '92': i32 + 145..146 't': i32 + 153..159 '{ 92 }': i32 + 155..157 '92': i32 "#]], ) } diff --git a/crates/syntax/src/ast/expr_ext.rs b/crates/syntax/src/ast/expr_ext.rs index e4a9b945c..636ce166d 100644 --- a/crates/syntax/src/ast/expr_ext.rs +++ b/crates/syntax/src/ast/expr_ext.rs @@ -358,6 +358,7 @@ pub enum Effect { Async(SyntaxToken), Unsafe(SyntaxToken), Try(SyntaxToken), + Const(SyntaxToken), // Very much not an effect, but we stuff it into this node anyway Label(ast::Label), } @@ -373,6 +374,9 @@ impl ast::EffectExpr { if let Some(token) = self.try_token() { return Effect::Try(token); } + if let Some(token) = self.const_token() { + return Effect::Const(token); + } if let Some(label) = self.label() { return Effect::Label(label); } -- cgit v1.2.3