From 8b147624ff906a11134d2e18be071c6cb8ec4beb Mon Sep 17 00:00:00 2001 From: Jade Date: Wed, 12 May 2021 04:39:48 -0700 Subject: Add lowering of array lengths in types Now e.g. ```rust fn a(b: [u8; 2]) { } ``` will know about the length of b. --- crates/hir_def/src/type_ref.rs | 53 +++++++++++++++++++++++++++++++++++++++--- 1 file changed, 50 insertions(+), 3 deletions(-) (limited to 'crates/hir_def/src') diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs index ea29da5da..00c09a23d 100644 --- a/crates/hir_def/src/type_ref.rs +++ b/crates/hir_def/src/type_ref.rs @@ -2,6 +2,7 @@ //! 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}; @@ -79,7 +80,7 @@ pub enum TypeRef { Path(Path), RawPtr(Box, Mutability), Reference(Box, Option, Mutability), - Array(Box /*, Expr*/), + Array(Box, ConstScalar), Slice(Box), /// A fn pointer. Last element of the vector is the return type. Fn(Vec, bool /*varargs*/), @@ -140,7 +141,12 @@ impl TypeRef { 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()))) @@ -212,7 +218,7 @@ impl TypeRef { } 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 { @@ -298,3 +304,44 @@ impl TypeBound { } } } + +/// 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) + } +} -- cgit v1.2.3