mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-01 14:21:44 +00:00
Merge #7020
7020: Implement const pat and expr inference r=flodiebold a=Veykril Co-authored-by: Lukas Wirth <lukastw97@gmail.com>
This commit is contained in:
commit
a82c2445be
7 changed files with 76 additions and 11 deletions
|
@ -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))
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}, _>
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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 '{}': ()
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
"#]],
|
"#]],
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue