feat: support negative const generic parameters

* feat: support `bool` & `char` const generics
This commit is contained in:
Artur Sinila 2022-07-17 04:18:53 +03:00
parent b9b42e8670
commit a96f0aa7cd
No known key found for this signature in database
GPG key ID: 770E69D690735C61
15 changed files with 153 additions and 126 deletions

View file

@ -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,19 +395,24 @@ 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_with_type(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),
pub fn usize_const(value: Option<u128>) -> Const {
intern_const_scalar_with_type(
value.map(ConstScalar::UInt).unwrap_or(ConstScalar::Unknown),
TyBuilder::usize(),
)
}
/// Interns a constant scalar with the default type
pub fn intern_const_scalar(value: ConstScalar) -> Const {
intern_const_scalar_with_type(value, TyBuilder::builtin(value.builtin_type()))
}
pub(crate) fn const_eval_recover(
_: &dyn HirDatabase,
_: &[String],
@ -463,7 +457,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 +465,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_with_type(const_scalar, TyBuilder::usize())
}
#[cfg(test)]

View file

@ -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,
}

View file

@ -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)

View file

@ -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,18 @@ 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)),
),
)
}
_ => TyKind::Slice(elem_ty.clone()),
}

View file

@ -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 == c2
}
fn intern_generic_arg(

View file

@ -44,7 +44,9 @@ 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_with_type, path_to_const, unknown_const, unknown_const_as_generic,
},
db::HirDatabase,
make_binders,
mapping::ToChalk,
@ -1742,7 +1744,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_with_type(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)

View file

@ -3011,14 +3011,14 @@ struct TS(usize);
fn main() {
let x;
[x,] = &[1,];
//^^^^expected &[i32; 1], got [{unknown}; _]
//^^^^expected &[i32; 1], got [{unknown}; {unknown}]
// FIXME we only want the outermost error, but this matches the current
// behavior of slice patterns
let x;
[(x,),] = &[(1,),];
// ^^^^expected {unknown}, got ({unknown},)
//^^^^^^^expected &[(i32,); 1], got [{unknown}; _]
//^^^^^^^expected &[(i32,); 1], got [{unknown}; {unknown}]
let x;
((x,),) = &((1,),);