//! be directly created from an ast::TypeRef, without further queries.
use hir_expand::{name::Name, AstId, InFile};
+use std::convert::TryInto;
use syntax::ast;
use crate::{body::LowerCtx, path::Path};
Path(Path),
RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
- Array(Box<TypeRef> /*, Expr*/),
+ Array(Box<TypeRef>, ConstScalar),
Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type.
Fn(Vec<TypeRef>, bool /*varargs*/),
TypeRef::RawPtr(Box::new(inner_ty), mutability)
}
ast::Type::ArrayType(inner) => {
- TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
+ let len = inner
+ .expr()
+ .map(ConstScalar::usize_from_literal_expr)
+ .unwrap_or(ConstScalar::Unknown);
+
+ TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len)
}
ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
}
TypeRef::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..)
- | TypeRef::Array(type_ref)
+ | TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(&type_ref, f),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in bounds {
}
}
}
+
+/// 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
+ // Note that this is u64 because the target usize may be bigger than our usize
+ Usize(u64),
+
+ /// 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, "_"),
+ }
+ }
+}
+
+impl ConstScalar {
+ fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
+ match expr {
+ ast::Expr::Literal(lit) => {
+ let lkind = lit.kind();
+ match lkind {
+ ast::LiteralKind::IntNumber(num)
+ if num.suffix() == None || num.suffix() == Some("usize") =>
+ {
+ num.value().and_then(|v| v.try_into().ok())
+ }
+ _ => None,
+ }
+ }
+ _ => None,
+ }
+ .map(ConstScalar::Usize)
+ .unwrap_or(ConstScalar::Unknown)
+ }
+}