Skip to content

Commit ac3ea3e

Browse files
bors[bot]HKalbasi
andauthored
Merge #11112
11112: Evaluate constants in array repeat expression r=HKalbasi a=HKalbasi cc #8655 Co-authored-by: hkalbasi <[email protected]>
2 parents 67f3b51 + 75c2aca commit ac3ea3e

File tree

5 files changed

+94
-27
lines changed

5 files changed

+94
-27
lines changed

crates/hir/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -1540,11 +1540,11 @@ impl Const {
15401540
let infer = infer.as_ref();
15411541
let result = eval_const(
15421542
root,
1543-
ConstEvalCtx {
1543+
&mut ConstEvalCtx {
15441544
exprs: &body.exprs,
15451545
pats: &body.pats,
15461546
local_data: HashMap::default(),
1547-
infer,
1547+
infer: &mut |x| infer[x].clone(),
15481548
},
15491549
);
15501550
result

crates/hir_ty/src/consteval.rs

+37-22
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,13 @@ use std::{collections::HashMap, convert::TryInto, fmt::Display};
44

55
use chalk_ir::{IntTy, Scalar};
66
use hir_def::{
7-
builtin_type::BuiltinUint,
87
expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
98
type_ref::ConstScalar,
109
};
1110
use hir_expand::name::Name;
12-
use la_arena::Arena;
11+
use la_arena::{Arena, Idx};
1312

14-
use crate::{Const, ConstData, ConstValue, InferenceResult, Interner, TyKind};
13+
use crate::{Const, ConstData, ConstValue, Interner, Ty, TyKind};
1514

1615
/// Extension trait for [`Const`]
1716
pub trait ConstExt {
@@ -41,12 +40,11 @@ impl ConstExt for Const {
4140
}
4241
}
4342

44-
#[derive(Clone)]
4543
pub struct ConstEvalCtx<'a> {
4644
pub exprs: &'a Arena<Expr>,
4745
pub pats: &'a Arena<Pat>,
4846
pub local_data: HashMap<Name, ComputedExpr>,
49-
pub infer: &'a InferenceResult,
47+
pub infer: &'a mut dyn FnMut(Idx<Expr>) -> Ty,
5048
}
5149

5250
#[derive(Debug, Clone)]
@@ -57,7 +55,7 @@ pub enum ConstEvalError {
5755
Panic(String),
5856
}
5957

60-
#[derive(Clone)]
58+
#[derive(Debug, Clone)]
6159
pub enum ComputedExpr {
6260
Literal(Literal),
6361
Tuple(Box<[ComputedExpr]>),
@@ -130,11 +128,11 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
130128
}
131129
}
132130

133-
pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr, ConstEvalError> {
131+
pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExpr, ConstEvalError> {
134132
match expr {
135133
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
136134
&Expr::UnaryOp { expr, op } => {
137-
let ty = &ctx.infer[expr];
135+
let ty = &(ctx.infer)(expr);
138136
let ev = eval_const(&ctx.exprs[expr], ctx)?;
139137
match op {
140138
hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")),
@@ -190,9 +188,9 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
190188
}
191189
}
192190
&Expr::BinaryOp { lhs, rhs, op } => {
193-
let ty = &ctx.infer[lhs];
194-
let lhs = eval_const(&ctx.exprs[lhs], ctx.clone())?;
195-
let rhs = eval_const(&ctx.exprs[rhs], ctx.clone())?;
191+
let ty = &(ctx.infer)(lhs);
192+
let lhs = eval_const(&ctx.exprs[lhs], ctx)?;
193+
let rhs = eval_const(&ctx.exprs[rhs], ctx)?;
196194
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
197195
let v1 = match lhs {
198196
ComputedExpr::Literal(Literal::Int(v, _)) => v,
@@ -241,6 +239,7 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
241239
}
242240
}
243241
Expr::Block { statements, tail, .. } => {
242+
let mut prev_values = HashMap::<Name, Option<ComputedExpr>>::default();
244243
for statement in &**statements {
245244
match statement {
246245
&hir_def::expr::Statement::Let { pat, initializer, .. } => {
@@ -252,21 +251,33 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
252251
}
253252
};
254253
let value = match initializer {
255-
Some(x) => eval_const(&ctx.exprs[x], ctx.clone())?,
254+
Some(x) => eval_const(&ctx.exprs[x], ctx)?,
256255
None => continue,
257256
};
258-
ctx.local_data.insert(name, value);
257+
if !prev_values.contains_key(&name) {
258+
let prev = ctx.local_data.insert(name.clone(), value);
259+
prev_values.insert(name, prev);
260+
} else {
261+
ctx.local_data.insert(name, value);
262+
}
259263
}
260264
&hir_def::expr::Statement::Expr { .. } => {
261265
return Err(ConstEvalError::NotSupported("this kind of statement"))
262266
}
263267
}
264268
}
265-
let tail_expr = match tail {
266-
&Some(x) => &ctx.exprs[x],
267-
None => return Ok(ComputedExpr::Tuple(Box::new([]))),
269+
let r = match tail {
270+
&Some(x) => eval_const(&ctx.exprs[x], ctx),
271+
None => Ok(ComputedExpr::Tuple(Box::new([]))),
268272
};
269-
eval_const(tail_expr, ctx)
273+
// clean up local data, so caller will receive the exact map that passed to us
274+
for (name, val) in prev_values {
275+
match val {
276+
Some(x) => ctx.local_data.insert(name, x),
277+
None => ctx.local_data.remove(&name),
278+
};
279+
}
280+
r
270281
}
271282
Expr::Path(p) => {
272283
let name = p.mod_path().as_ident().ok_or(ConstEvalError::NotSupported("big paths"))?;
@@ -280,12 +291,16 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
280291
}
281292
}
282293

283-
// FIXME: support more than just evaluating literals
284-
pub fn eval_usize(expr: &Expr) -> Option<u64> {
285-
match expr {
286-
Expr::Literal(Literal::Uint(v, None | Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
287-
_ => None,
294+
pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
295+
let expr = &ctx.exprs[expr];
296+
if let Ok(ce) = eval_const(&expr, &mut ctx) {
297+
match ce {
298+
ComputedExpr::Literal(Literal::Int(x, _)) => return x.try_into().ok(),
299+
ComputedExpr::Literal(Literal::Uint(x, _)) => return x.try_into().ok(),
300+
_ => {}
301+
}
288302
}
303+
None
289304
}
290305

291306
/// Interns a possibly-unknown target usize

crates/hir_ty/src/infer/expr.rs

+9-2
Original file line numberDiff line numberDiff line change
@@ -799,8 +799,15 @@ impl<'a> InferenceContext<'a> {
799799
),
800800
);
801801

802-
let repeat_expr = &self.body.exprs[repeat];
803-
consteval::eval_usize(repeat_expr)
802+
consteval::eval_usize(
803+
repeat,
804+
consteval::ConstEvalCtx {
805+
exprs: &body.exprs,
806+
pats: &body.pats,
807+
local_data: Default::default(),
808+
infer: &mut |x| self.infer_expr(x, &expected),
809+
},
810+
)
804811
}
805812
};
806813

crates/ide/src/hover/tests.rs

+43
Original file line numberDiff line numberDiff line change
@@ -3350,6 +3350,31 @@ const FOO$0: usize = 1 << 10;
33503350
check(
33513351
r#"
33523352
/// This is a doc
3353+
const FOO$0: usize = {
3354+
let b = 4;
3355+
let a = { let b = 2; let a = b; a } + { let a = 1; a + b };
3356+
a
3357+
};
3358+
"#,
3359+
expect![[r#"
3360+
*FOO*
3361+
3362+
```rust
3363+
test
3364+
```
3365+
3366+
```rust
3367+
const FOO: usize = 7
3368+
```
3369+
3370+
---
3371+
3372+
This is a doc
3373+
"#]],
3374+
);
3375+
check(
3376+
r#"
3377+
/// This is a doc
33533378
const FOO$0: usize = 2 - 3;
33543379
"#,
33553380
expect![[r#"
@@ -3443,6 +3468,24 @@ fn foo() {
34433468
);
34443469
}
34453470

3471+
#[test]
3472+
fn array_repeat_exp() {
3473+
check(
3474+
r#"
3475+
fn main() {
3476+
let til$0e4 = [0_u32; (4 * 8 * 8) / 32];
3477+
}
3478+
"#,
3479+
expect![[r#"
3480+
*tile4*
3481+
3482+
```rust
3483+
let tile4: [u32; 8]
3484+
```
3485+
"#]],
3486+
);
3487+
}
3488+
34463489
#[test]
34473490
fn hover_mod_def() {
34483491
check(

crates/ide_assists/src/handlers/add_explicit_type.rs

+3-1
Original file line numberDiff line numberDiff line change
@@ -208,8 +208,10 @@ fn main() {
208208
check_assist_not_applicable(
209209
add_explicit_type,
210210
r#"
211+
//- minicore: option
212+
211213
fn main() {
212-
let $0l = [0.0; 2+2];
214+
let $0l = [0.0; Some(2).unwrap()];
213215
}
214216
"#,
215217
);

0 commit comments

Comments
 (0)