mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 21:05:02 +00:00
Merge #11112
11112: Evaluate constants in array repeat expression r=HKalbasi a=HKalbasi cc #8655 Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com>
This commit is contained in:
commit
ac3ea3e81c
5 changed files with 94 additions and 27 deletions
|
@ -1540,11 +1540,11 @@ impl Const {
|
||||||
let infer = infer.as_ref();
|
let infer = infer.as_ref();
|
||||||
let result = eval_const(
|
let result = eval_const(
|
||||||
root,
|
root,
|
||||||
ConstEvalCtx {
|
&mut ConstEvalCtx {
|
||||||
exprs: &body.exprs,
|
exprs: &body.exprs,
|
||||||
pats: &body.pats,
|
pats: &body.pats,
|
||||||
local_data: HashMap::default(),
|
local_data: HashMap::default(),
|
||||||
infer,
|
infer: &mut |x| infer[x].clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
result
|
result
|
||||||
|
|
|
@ -4,14 +4,13 @@ use std::{collections::HashMap, convert::TryInto, fmt::Display};
|
||||||
|
|
||||||
use chalk_ir::{IntTy, Scalar};
|
use chalk_ir::{IntTy, Scalar};
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
builtin_type::BuiltinUint,
|
|
||||||
expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
|
expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
|
||||||
type_ref::ConstScalar,
|
type_ref::ConstScalar,
|
||||||
};
|
};
|
||||||
use hir_expand::name::Name;
|
use hir_expand::name::Name;
|
||||||
use la_arena::Arena;
|
use la_arena::{Arena, Idx};
|
||||||
|
|
||||||
use crate::{Const, ConstData, ConstValue, InferenceResult, Interner, TyKind};
|
use crate::{Const, ConstData, ConstValue, Interner, Ty, TyKind};
|
||||||
|
|
||||||
/// Extension trait for [`Const`]
|
/// Extension trait for [`Const`]
|
||||||
pub trait ConstExt {
|
pub trait ConstExt {
|
||||||
|
@ -41,12 +40,11 @@ impl ConstExt for Const {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
|
||||||
pub struct ConstEvalCtx<'a> {
|
pub struct ConstEvalCtx<'a> {
|
||||||
pub exprs: &'a Arena<Expr>,
|
pub exprs: &'a Arena<Expr>,
|
||||||
pub pats: &'a Arena<Pat>,
|
pub pats: &'a Arena<Pat>,
|
||||||
pub local_data: HashMap<Name, ComputedExpr>,
|
pub local_data: HashMap<Name, ComputedExpr>,
|
||||||
pub infer: &'a InferenceResult,
|
pub infer: &'a mut dyn FnMut(Idx<Expr>) -> Ty,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
@ -57,7 +55,7 @@ pub enum ConstEvalError {
|
||||||
Panic(String),
|
Panic(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum ComputedExpr {
|
pub enum ComputedExpr {
|
||||||
Literal(Literal),
|
Literal(Literal),
|
||||||
Tuple(Box<[ComputedExpr]>),
|
Tuple(Box<[ComputedExpr]>),
|
||||||
|
@ -130,11 +128,11 @@ fn is_valid(scalar: &Scalar, value: i128) -> bool {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr, ConstEvalError> {
|
pub fn eval_const(expr: &Expr, ctx: &mut ConstEvalCtx<'_>) -> Result<ComputedExpr, ConstEvalError> {
|
||||||
match expr {
|
match expr {
|
||||||
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
Expr::Literal(l) => Ok(ComputedExpr::Literal(l.clone())),
|
||||||
&Expr::UnaryOp { expr, op } => {
|
&Expr::UnaryOp { expr, op } => {
|
||||||
let ty = &ctx.infer[expr];
|
let ty = &(ctx.infer)(expr);
|
||||||
let ev = eval_const(&ctx.exprs[expr], ctx)?;
|
let ev = eval_const(&ctx.exprs[expr], ctx)?;
|
||||||
match op {
|
match op {
|
||||||
hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")),
|
hir_def::expr::UnaryOp::Deref => Err(ConstEvalError::NotSupported("deref")),
|
||||||
|
@ -190,9 +188,9 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
&Expr::BinaryOp { lhs, rhs, op } => {
|
&Expr::BinaryOp { lhs, rhs, op } => {
|
||||||
let ty = &ctx.infer[lhs];
|
let ty = &(ctx.infer)(lhs);
|
||||||
let lhs = eval_const(&ctx.exprs[lhs], ctx.clone())?;
|
let lhs = eval_const(&ctx.exprs[lhs], ctx)?;
|
||||||
let rhs = eval_const(&ctx.exprs[rhs], ctx.clone())?;
|
let rhs = eval_const(&ctx.exprs[rhs], ctx)?;
|
||||||
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
let op = op.ok_or(ConstEvalError::IncompleteExpr)?;
|
||||||
let v1 = match lhs {
|
let v1 = match lhs {
|
||||||
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
ComputedExpr::Literal(Literal::Int(v, _)) => v,
|
||||||
|
@ -241,6 +239,7 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Expr::Block { statements, tail, .. } => {
|
Expr::Block { statements, tail, .. } => {
|
||||||
|
let mut prev_values = HashMap::<Name, Option<ComputedExpr>>::default();
|
||||||
for statement in &**statements {
|
for statement in &**statements {
|
||||||
match statement {
|
match statement {
|
||||||
&hir_def::expr::Statement::Let { pat, initializer, .. } => {
|
&hir_def::expr::Statement::Let { pat, initializer, .. } => {
|
||||||
|
@ -252,21 +251,33 @@ pub fn eval_const(expr: &Expr, mut ctx: ConstEvalCtx<'_>) -> Result<ComputedExpr
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let value = match initializer {
|
let value = match initializer {
|
||||||
Some(x) => eval_const(&ctx.exprs[x], ctx.clone())?,
|
Some(x) => eval_const(&ctx.exprs[x], ctx)?,
|
||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
ctx.local_data.insert(name, value);
|
if !prev_values.contains_key(&name) {
|
||||||
|
let prev = ctx.local_data.insert(name.clone(), value);
|
||||||
|
prev_values.insert(name, prev);
|
||||||
|
} else {
|
||||||
|
ctx.local_data.insert(name, value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
&hir_def::expr::Statement::Expr { .. } => {
|
&hir_def::expr::Statement::Expr { .. } => {
|
||||||
return Err(ConstEvalError::NotSupported("this kind of statement"))
|
return Err(ConstEvalError::NotSupported("this kind of statement"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let tail_expr = match tail {
|
let r = match tail {
|
||||||
&Some(x) => &ctx.exprs[x],
|
&Some(x) => eval_const(&ctx.exprs[x], ctx),
|
||||||
None => return Ok(ComputedExpr::Tuple(Box::new([]))),
|
None => Ok(ComputedExpr::Tuple(Box::new([]))),
|
||||||
};
|
};
|
||||||
eval_const(tail_expr, ctx)
|
// clean up local data, so caller will receive the exact map that passed to us
|
||||||
|
for (name, val) in prev_values {
|
||||||
|
match val {
|
||||||
|
Some(x) => ctx.local_data.insert(name, x),
|
||||||
|
None => ctx.local_data.remove(&name),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
r
|
||||||
}
|
}
|
||||||
Expr::Path(p) => {
|
Expr::Path(p) => {
|
||||||
let name = p.mod_path().as_ident().ok_or(ConstEvalError::NotSupported("big paths"))?;
|
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
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: support more than just evaluating literals
|
pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
|
||||||
pub fn eval_usize(expr: &Expr) -> Option<u64> {
|
let expr = &ctx.exprs[expr];
|
||||||
match expr {
|
if let Ok(ce) = eval_const(&expr, &mut ctx) {
|
||||||
Expr::Literal(Literal::Uint(v, None | Some(BuiltinUint::Usize))) => (*v).try_into().ok(),
|
match ce {
|
||||||
_ => None,
|
ComputedExpr::Literal(Literal::Int(x, _)) => return x.try_into().ok(),
|
||||||
|
ComputedExpr::Literal(Literal::Uint(x, _)) => return x.try_into().ok(),
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interns a possibly-unknown target usize
|
/// Interns a possibly-unknown target usize
|
||||||
|
|
|
@ -799,8 +799,15 @@ impl<'a> InferenceContext<'a> {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let repeat_expr = &self.body.exprs[repeat];
|
consteval::eval_usize(
|
||||||
consteval::eval_usize(repeat_expr)
|
repeat,
|
||||||
|
consteval::ConstEvalCtx {
|
||||||
|
exprs: &body.exprs,
|
||||||
|
pats: &body.pats,
|
||||||
|
local_data: Default::default(),
|
||||||
|
infer: &mut |x| self.infer_expr(x, &expected),
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -3350,6 +3350,31 @@ const FOO$0: usize = 1 << 10;
|
||||||
check(
|
check(
|
||||||
r#"
|
r#"
|
||||||
/// This is a doc
|
/// This is a doc
|
||||||
|
const FOO$0: usize = {
|
||||||
|
let b = 4;
|
||||||
|
let a = { let b = 2; let a = b; a } + { let a = 1; a + b };
|
||||||
|
a
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*FOO*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
test
|
||||||
|
```
|
||||||
|
|
||||||
|
```rust
|
||||||
|
const FOO: usize = 7
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
This is a doc
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
/// This is a doc
|
||||||
const FOO$0: usize = 2 - 3;
|
const FOO$0: usize = 2 - 3;
|
||||||
"#,
|
"#,
|
||||||
expect![[r#"
|
expect![[r#"
|
||||||
|
@ -3443,6 +3468,24 @@ fn foo() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn array_repeat_exp() {
|
||||||
|
check(
|
||||||
|
r#"
|
||||||
|
fn main() {
|
||||||
|
let til$0e4 = [0_u32; (4 * 8 * 8) / 32];
|
||||||
|
}
|
||||||
|
"#,
|
||||||
|
expect![[r#"
|
||||||
|
*tile4*
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let tile4: [u32; 8]
|
||||||
|
```
|
||||||
|
"#]],
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn hover_mod_def() {
|
fn hover_mod_def() {
|
||||||
check(
|
check(
|
||||||
|
|
|
@ -208,8 +208,10 @@ fn main() {
|
||||||
check_assist_not_applicable(
|
check_assist_not_applicable(
|
||||||
add_explicit_type,
|
add_explicit_type,
|
||||||
r#"
|
r#"
|
||||||
|
//- minicore: option
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let $0l = [0.0; 2+2];
|
let $0l = [0.0; Some(2).unwrap()];
|
||||||
}
|
}
|
||||||
"#,
|
"#,
|
||||||
);
|
);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue