Skip to content

Commit

Permalink
Add basic support for array lengths in types
Browse files Browse the repository at this point in the history
This recognizes `let a = [1u8, 2, 3]` as having type `[u8; 3]` instead
of the previous `[u8; _]`. Byte strings and `[0u8; 2]` kinds of range
array declarations are unsupported as before.

I don't know why a bunch of our rustc tests had single quotes inside
strings un-escaped by `UPDATE_EXPECT=1 cargo t`, but I don't think it's
bad? Maybe something in a nightly?
  • Loading branch information
lf- committed May 11, 2021
1 parent 77f0c92 commit dc63fea
Show file tree
Hide file tree
Showing 12 changed files with 155 additions and 110 deletions.
20 changes: 20 additions & 0 deletions crates/hir_ty/src/consts.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! Handling of concrete const values
/// A concrete constant value
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ConstScalar {
// for now, we only support the trivial case of constant evaluating the length of an array
Usize(usize),

/// Case of an unknown value that rustc might know but we don't
Unknown,
}

impl std::fmt::Display for ConstScalar {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ConstScalar::Usize(us) => write!(fmt, "{}", us),
ConstScalar::Unknown => write!(fmt, "_"),
}
}
}
2 changes: 1 addition & 1 deletion crates/hir_ty/src/display.rs
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,7 @@ impl HirDisplay for Const {
let param_data = &generics.params.consts[id.local_id];
write!(f, "{}", param_data.name)
}
ConstValue::Concrete(_) => write!(f, "_"),
ConstValue::Concrete(c) => write!(f, "{}", c.interned),
}
}
}
Expand Down
26 changes: 20 additions & 6 deletions crates/hir_ty/src/infer/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
use std::iter::{repeat, repeat_with};
use std::{mem, sync::Arc};

use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
use chalk_ir::{cast::Cast, fold::Shift, ConstData, Mutability, TyVariableKind};
use hir_def::{
expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
path::{GenericArg, GenericArgs},
Expand All @@ -15,15 +15,17 @@ use stdx::always;
use syntax::ast::RangeOp;

use crate::{
autoderef, dummy_usize_const,
autoderef,
consts::ConstScalar,
dummy_usize_const,
lower::lower_to_chalk_mutability,
mapping::from_chalk,
method_resolution, op,
primitive::{self, UintTy},
static_lifetime, to_chalk_trait_id,
traits::FnTrait,
utils::{generics, Generics},
AdtId, Binders, CallableDefId, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
AdtId, Binders, CallableDefId, ConstValue, FnPointer, FnSig, FnSubst, InEnvironment, Interner,
ProjectionTyExt, Rawness, Scalar, Substitution, TraitRef, Ty, TyBuilder, TyExt, TyKind,
};

Expand Down Expand Up @@ -717,11 +719,12 @@ impl<'a> InferenceContext<'a> {
_ => self.table.new_type_var(),
};

match array {
let len = match array {
Array::ElementList(items) => {
for expr in items.iter() {
self.infer_expr_coerce(*expr, &Expectation::has_type(elem_ty.clone()));
}
Some(items.len())
}
Array::Repeat { initializer, repeat } => {
self.infer_expr_coerce(
Expand All @@ -734,10 +737,20 @@ impl<'a> InferenceContext<'a> {
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
),
);
// FIXME: support length for Repeat array expressions
None
}
}
};

TyKind::Array(elem_ty, dummy_usize_const()).intern(&Interner)
let cd = ConstData {
ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
value: ConstValue::Concrete(chalk_ir::ConcreteConst {
interned: len
.map(|len| ConstScalar::Usize(len))
.unwrap_or(ConstScalar::Unknown),
}),
};
TyKind::Array(elem_ty, cd.intern(&Interner)).intern(&Interner)
}
Expr::Literal(lit) => match lit {
Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(&Interner),
Expand All @@ -747,6 +760,7 @@ impl<'a> InferenceContext<'a> {
}
Literal::ByteString(..) => {
let byte_type = TyKind::Scalar(Scalar::Uint(UintTy::U8)).intern(&Interner);

let array_type =
TyKind::Array(byte_type, dummy_usize_const()).intern(&Interner);
TyKind::Ref(Mutability::Not, static_lifetime(), array_type).intern(&Interner)
Expand Down
16 changes: 11 additions & 5 deletions crates/hir_ty/src/interner.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
//! Implementation of the Chalk `Interner` trait, which allows customizing the
//! representation of the various objects Chalk deals with (types, goals etc.).
use crate::{chalk_db, tls, GenericArg};
use crate::{chalk_db, consts::ConstScalar, tls, GenericArg};
use base_db::salsa::InternId;
use chalk_ir::{Goal, GoalData};
use hir_def::{
Expand Down Expand Up @@ -31,6 +31,7 @@ impl_internable!(
InternedWrapper<chalk_ir::TyData<Interner>>,
InternedWrapper<chalk_ir::LifetimeData<Interner>>,
InternedWrapper<chalk_ir::ConstData<Interner>>,
InternedWrapper<ConstScalar>,
InternedWrapper<Vec<chalk_ir::CanonicalVarKind<Interner>>>,
InternedWrapper<Vec<chalk_ir::ProgramClause<Interner>>>,
InternedWrapper<Vec<chalk_ir::QuantifiedWhereClause<Interner>>>,
Expand All @@ -41,7 +42,7 @@ impl chalk_ir::interner::Interner for Interner {
type InternedType = Interned<InternedWrapper<chalk_ir::TyData<Interner>>>;
type InternedLifetime = Interned<InternedWrapper<chalk_ir::LifetimeData<Self>>>;
type InternedConst = Interned<InternedWrapper<chalk_ir::ConstData<Self>>>;
type InternedConcreteConst = ();
type InternedConcreteConst = ConstScalar;
type InternedGenericArg = chalk_ir::GenericArgData<Self>;
type InternedGoal = Arc<GoalData<Self>>;
type InternedGoals = Vec<Goal<Self>>;
Expand Down Expand Up @@ -245,10 +246,15 @@ impl chalk_ir::interner::Interner for Interner {
fn const_eq(
&self,
_ty: &Self::InternedType,
_c1: &Self::InternedConcreteConst,
_c2: &Self::InternedConcreteConst,
c1: &Self::InternedConcreteConst,
c2: &Self::InternedConcreteConst,
) -> bool {
true
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,
}
}

fn intern_generic_arg(
Expand Down
7 changes: 5 additions & 2 deletions crates/hir_ty/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ mod chalk_db;
mod chalk_ext;
mod infer;
mod interner;
mod consts;
mod lower;
mod mapping;
mod op;
Expand Down Expand Up @@ -39,7 +40,7 @@ use chalk_ir::{
};
use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId};

use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
use crate::{consts::ConstScalar, db::HirDatabase, display::HirDisplay, utils::generics};

pub use autoderef::autoderef;
pub use builder::TyBuilder;
Expand Down Expand Up @@ -250,7 +251,9 @@ pub fn dummy_usize_const() -> Const {
let usize_ty = chalk_ir::TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner);
chalk_ir::ConstData {
ty: usize_ty,
value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: () }),
value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst {
interned: ConstScalar::Unknown,
}),
}
.intern(&Interner)
}
Expand Down
2 changes: 2 additions & 0 deletions crates/hir_ty/src/lower.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,8 @@ impl<'a> TyLoweringContext<'a> {
}
TypeRef::Array(inner) => {
let inner_ty = self.lower_ty(inner);
// FIXME: we don't have length info here because we don't store an expression for
// the length
TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner)
}
TypeRef::Slice(inner) => {
Expand Down
Loading

0 comments on commit dc63fea

Please sign in to comment.