7020: Implement const pat and expr inference r=flodiebold a=Veykril



Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
bors[bot] 2020-12-23 19:50:04 +00:00 committed by GitHub
commit a82c2445be
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 76 additions and 11 deletions

View file

@ -246,6 +246,10 @@ impl ExprCollector<'_> {
let body = self.collect_block_opt(e.block_expr()); let body = self.collect_block_opt(e.block_expr());
self.alloc_expr(Expr::Async { body }, syntax_ptr) 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::BlockExpr(e) => self.collect_block(e),
ast::Expr::LoopExpr(e) => { ast::Expr::LoopExpr(e) => {
@ -932,10 +936,16 @@ impl ExprCollector<'_> {
let inner = self.collect_pat_opt(boxpat.pat()); let inner = self.collect_pat_opt(boxpat.pat());
Pat::Box { inner } Pat::Box { inner }
} }
// FIXME: implement ast::Pat::ConstBlockPat(const_block_pat) => {
ast::Pat::RangePat(_) | ast::Pat::MacroPat(_) | ast::Pat::ConstBlockPat(_) => { if let Some(expr) = const_block_pat.block_expr() {
Pat::Missing 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); let ptr = AstPtr::new(&pat);
self.alloc_pat(pattern, Either::Left(ptr)) self.alloc_pat(pattern, Either::Left(ptr))

View file

@ -114,6 +114,9 @@ pub enum Expr {
Async { Async {
body: ExprId, body: ExprId,
}, },
Const {
body: ExprId,
},
Cast { Cast {
expr: ExprId, expr: ExprId,
type_ref: TypeRef, type_ref: TypeRef,
@ -253,7 +256,10 @@ impl Expr {
f(*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::Loop { body, .. } => f(*body),
Expr::While { condition, body, .. } => { Expr::While { condition, body, .. } => {
f(*condition); f(*condition);
@ -399,12 +405,18 @@ pub enum Pat {
TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> }, TupleStruct { path: Option<Path>, args: Vec<PatId>, ellipsis: Option<usize> },
Ref { pat: PatId, mutability: Mutability }, Ref { pat: PatId, mutability: Mutability },
Box { inner: PatId }, Box { inner: PatId },
ConstBlock(ExprId),
} }
impl Pat { impl Pat {
pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) { pub fn walk_child_pats(&self, mut f: impl FnMut(PatId)) {
match self { 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, .. } => { Pat::Bind { subpat, .. } => {
subpat.iter().copied().for_each(f); subpat.iter().copied().for_each(f);
} }

View file

@ -155,7 +155,7 @@ impl<'a> InferenceContext<'a> {
} }
None => self.infer_block(statements, *tail, expected), 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 } => { Expr::TryBlock { body } => {
let _inner = self.infer_expr(*body, expected); let _inner = self.infer_expr(*body, expected);
// FIXME should be std::result::Result<{inner}, _> // FIXME should be std::result::Result<{inner}, _>

View file

@ -243,6 +243,9 @@ impl<'a> InferenceContext<'a> {
} }
None => Ty::Unknown, None => Ty::Unknown,
}, },
Pat::ConstBlock(expr) => {
self.infer_expr(*expr, &Expectation::has_type(expected.clone()))
}
Pat::Missing => Ty::Unknown, Pat::Missing => Ty::Unknown,
}; };
// use a new type variable if we got Ty::Unknown here // 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::Range { .. }
| Pat::Slice { .. } => true, | Pat::Slice { .. } => true,
Pat::Or(pats) => pats.iter().all(|p| is_non_ref_pat(body, *p)), 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::Path(..) => true,
Pat::ConstBlock(..) => true,
Pat::Lit(expr) => match body[*expr] { Pat::Lit(expr) => match body[*expr] {
Expr::Literal(Literal::String(..)) => false, Expr::Literal(Literal::String(..)) => false,
_ => true, _ => true,

View file

@ -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 '{}': ()
"#]],
);
}

View file

@ -1894,6 +1894,7 @@ fn effects_smoke_test() {
let x = unsafe { 92 }; let x = unsafe { 92 };
let y = async { async { () }.await }; let y = async { async { () }.await };
let z = try { () }; let z = try { () };
let w = const { 92 };
let t = 'a: { 92 }; let t = 'a: { 92 };
} }
@ -1905,7 +1906,7 @@ fn effects_smoke_test() {
} }
"#, "#,
expect![[r#" expect![[r#"
16..136 '{ ...2 }; }': () 16..162 '{ ...2 }; }': ()
26..27 'x': i32 26..27 'x': i32
30..43 'unsafe { 92 }': i32 30..43 'unsafe { 92 }': i32
37..43 '{ 92 }': i32 37..43 '{ 92 }': i32
@ -1921,9 +1922,13 @@ fn effects_smoke_test() {
99..109 'try { () }': {unknown} 99..109 'try { () }': {unknown}
103..109 '{ () }': () 103..109 '{ () }': ()
105..107 '()': () 105..107 '()': ()
119..120 't': i32 119..120 'w': i32
127..133 '{ 92 }': i32 123..135 'const { 92 }': i32
129..131 '92': i32 129..135 '{ 92 }': i32
131..133 '92': i32
145..146 't': i32
153..159 '{ 92 }': i32
155..157 '92': i32
"#]], "#]],
) )
} }

View file

@ -358,6 +358,7 @@ pub enum Effect {
Async(SyntaxToken), Async(SyntaxToken),
Unsafe(SyntaxToken), Unsafe(SyntaxToken),
Try(SyntaxToken), Try(SyntaxToken),
Const(SyntaxToken),
// Very much not an effect, but we stuff it into this node anyway // Very much not an effect, but we stuff it into this node anyway
Label(ast::Label), Label(ast::Label),
} }
@ -373,6 +374,9 @@ impl ast::EffectExpr {
if let Some(token) = self.try_token() { if let Some(token) = self.try_token() {
return Effect::Try(token); return Effect::Try(token);
} }
if let Some(token) = self.const_token() {
return Effect::Const(token);
}
if let Some(label) = self.label() { if let Some(label) = self.label() {
return Effect::Label(label); return Effect::Label(label);
} }