]> git.lizzy.rs Git - rust.git/blobdiff - crates/hir_def/src/type_ref.rs
Add lowering of array lengths in types
[rust.git] / crates / hir_def / src / type_ref.rs
index ea29da5daae49f75677b08954fc810bd163b7db1..00c09a23dfcdca9efde0b72d5a6f741135164c27 100644 (file)
@@ -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<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*/),
@@ -140,7 +141,12 @@ pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
                 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 @@ fn go(type_ref: &TypeRef, f: &mut impl FnMut(&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 @@ pub fn as_path(&self) -> Option<&Path> {
         }
     }
 }
+
+/// 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)
+    }
+}