mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-30 13:51:31 +00:00
Auto merge of #12778 - Logarithmus:feature/fix-negative-const-generics, r=flodiebold
Support negative, `char` & `bool` const generics Before:  After:  I tried to implement stuff like `Const<{NUM1 + 3 + NUM2}>` by using already existing constant evaluation mechanism for ordinary constants, but turned out to be harder than I thought, maybe because I've never ever tinkered with compilers before
This commit is contained in:
commit
db6a85d358
11 changed files with 218 additions and 86 deletions
|
@ -347,17 +347,6 @@ pub fn eval_const(
|
|||
}
|
||||
}
|
||||
|
||||
pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
|
||||
if let Ok(ce) = eval_const(expr, &mut ctx) {
|
||||
match ce {
|
||||
ComputedExpr::Literal(Literal::Int(x, _)) => return x.try_into().ok(),
|
||||
ComputedExpr::Literal(Literal::Uint(x, _)) => return x.try_into().ok(),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub(crate) fn path_to_const(
|
||||
db: &dyn HirDatabase,
|
||||
resolver: &Resolver,
|
||||
|
@ -406,17 +395,14 @@ pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
|
|||
}
|
||||
|
||||
/// Interns a constant scalar with the given type
|
||||
pub fn intern_scalar_const(value: ConstScalar, ty: Ty) -> Const {
|
||||
pub fn intern_const_scalar(value: ConstScalar, ty: Ty) -> Const {
|
||||
ConstData { ty, value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: value }) }
|
||||
.intern(Interner)
|
||||
}
|
||||
|
||||
/// Interns a possibly-unknown target usize
|
||||
pub fn usize_const(value: Option<u64>) -> Const {
|
||||
intern_scalar_const(
|
||||
value.map(ConstScalar::Usize).unwrap_or(ConstScalar::Unknown),
|
||||
TyBuilder::usize(),
|
||||
)
|
||||
pub fn usize_const(value: Option<u128>) -> Const {
|
||||
intern_const_scalar(value.map_or(ConstScalar::Unknown, ConstScalar::UInt), TyBuilder::usize())
|
||||
}
|
||||
|
||||
pub(crate) fn const_eval_recover(
|
||||
|
@ -463,7 +449,7 @@ pub(crate) fn eval_to_const<'a>(
|
|||
}
|
||||
}
|
||||
let body = ctx.body.clone();
|
||||
let ctx = ConstEvalCtx {
|
||||
let mut ctx = ConstEvalCtx {
|
||||
db: ctx.db,
|
||||
owner: ctx.owner,
|
||||
exprs: &body.exprs,
|
||||
|
@ -471,7 +457,12 @@ pub(crate) fn eval_to_const<'a>(
|
|||
local_data: HashMap::default(),
|
||||
infer: &ctx.result,
|
||||
};
|
||||
usize_const(eval_usize(expr, ctx))
|
||||
let computed_expr = eval_const(expr, &mut ctx);
|
||||
let const_scalar = match computed_expr {
|
||||
Ok(ComputedExpr::Literal(literal)) => literal.into(),
|
||||
_ => ConstScalar::Unknown,
|
||||
};
|
||||
intern_const_scalar(const_scalar, TyBuilder::usize())
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
|
|
@ -605,10 +605,10 @@ impl<'a> InferenceContext<'a> {
|
|||
let data = c.data(Interner);
|
||||
match data.value {
|
||||
ConstValue::Concrete(cc) => match cc.interned {
|
||||
hir_def::type_ref::ConstScalar::Usize(_) => c,
|
||||
hir_def::type_ref::ConstScalar::Unknown => {
|
||||
self.table.new_const_var(data.ty.clone())
|
||||
}
|
||||
_ => c,
|
||||
},
|
||||
_ => c,
|
||||
}
|
||||
|
|
|
@ -729,7 +729,7 @@ impl<'a> InferenceContext<'a> {
|
|||
let cur_elem_ty = self.infer_expr_inner(expr, &expected);
|
||||
coerce.coerce(self, Some(expr), &cur_elem_ty);
|
||||
}
|
||||
consteval::usize_const(Some(items.len() as u64))
|
||||
consteval::usize_const(Some(items.len() as u128))
|
||||
}
|
||||
&Array::Repeat { initializer, repeat } => {
|
||||
self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
|
||||
|
@ -766,7 +766,7 @@ impl<'a> InferenceContext<'a> {
|
|||
Literal::ByteString(bs) => {
|
||||
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(Interner);
|
||||
|
||||
let len = consteval::usize_const(Some(bs.len() as u64));
|
||||
let len = consteval::usize_const(Some(bs.len() as u128));
|
||||
|
||||
let array_type = TyKind::Array(byte_type, len).intern(Interner);
|
||||
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(Interner)
|
||||
|
|
|
@ -11,6 +11,7 @@ use hir_def::{
|
|||
use hir_expand::name::Name;
|
||||
|
||||
use crate::{
|
||||
consteval::intern_const_scalar,
|
||||
infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
|
||||
lower::lower_to_chalk_mutability,
|
||||
static_lifetime, ConcreteConst, ConstValue, Interner, Substitution, Ty, TyBuilder, TyExt,
|
||||
|
@ -262,13 +263,19 @@ impl<'a> InferenceContext<'a> {
|
|||
if let &Some(slice_pat_id) = slice {
|
||||
let rest_pat_ty = match expected.kind(Interner) {
|
||||
TyKind::Array(_, length) => {
|
||||
let length = match length.data(Interner).value {
|
||||
let len = match length.data(Interner).value {
|
||||
ConstValue::Concrete(ConcreteConst {
|
||||
interned: ConstScalar::Usize(length),
|
||||
}) => length.checked_sub((prefix.len() + suffix.len()) as u64),
|
||||
interned: ConstScalar::UInt(len),
|
||||
}) => len.checked_sub((prefix.len() + suffix.len()) as u128),
|
||||
_ => None,
|
||||
};
|
||||
TyKind::Array(elem_ty.clone(), crate::consteval::usize_const(length))
|
||||
TyKind::Array(
|
||||
elem_ty.clone(),
|
||||
intern_const_scalar(
|
||||
len.map_or(ConstScalar::Unknown, |len| ConstScalar::UInt(len)),
|
||||
TyBuilder::usize(),
|
||||
),
|
||||
)
|
||||
}
|
||||
_ => TyKind::Slice(elem_ty.clone()),
|
||||
}
|
||||
|
|
|
@ -257,12 +257,7 @@ impl chalk_ir::interner::Interner for Interner {
|
|||
c1: &Self::InternedConcreteConst,
|
||||
c2: &Self::InternedConcreteConst,
|
||||
) -> bool {
|
||||
match (c1, c2) {
|
||||
(&ConstScalar::Usize(a), &ConstScalar::Usize(b)) => a == b,
|
||||
// we were previously assuming this to be true, I'm not whether true or false on
|
||||
// unknown values is safer.
|
||||
(_, _) => true,
|
||||
}
|
||||
(c1 == &ConstScalar::Unknown) || (c2 == &ConstScalar::Unknown) || (c1 == c2)
|
||||
}
|
||||
|
||||
fn intern_generic_arg(
|
||||
|
|
|
@ -44,7 +44,7 @@ use syntax::{ast, SmolStr};
|
|||
|
||||
use crate::{
|
||||
all_super_traits,
|
||||
consteval::{intern_scalar_const, path_to_const, unknown_const, unknown_const_as_generic},
|
||||
consteval::{intern_const_scalar, path_to_const, unknown_const, unknown_const_as_generic},
|
||||
db::HirDatabase,
|
||||
make_binders,
|
||||
mapping::ToChalk,
|
||||
|
@ -1743,7 +1743,7 @@ pub(crate) fn const_or_path_to_chalk(
|
|||
debruijn: DebruijnIndex,
|
||||
) -> Const {
|
||||
match value {
|
||||
ConstScalarOrPath::Scalar(s) => intern_scalar_const(s.clone(), expected_ty),
|
||||
ConstScalarOrPath::Scalar(s) => intern_const_scalar(s.clone(), expected_ty),
|
||||
ConstScalarOrPath::Path(n) => {
|
||||
let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
|
||||
path_to_const(db, resolver, &path, mode, args, debruijn)
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue