]> 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 347ceabb9b03c745eabcfa7cdb3f87bbb03df2bb..00c09a23dfcdca9efde0b72d5a6f741135164c27 100644 (file)
@@ -1,7 +1,9 @@
 //! HIR for references to types. Paths in these are not yet resolved. They can
 //! be directly created from an ast::TypeRef, without further queries.
-use hir_expand::name::Name;
-use syntax::{ast, SyntaxToken};
+
+use hir_expand::{name::Name, AstId, InFile};
+use std::convert::TryInto;
+use syntax::ast;
 
 use crate::{body::LowerCtx, path::Path};
 
@@ -51,6 +53,24 @@ pub fn from_raw(is_raw: bool) -> Rawness {
     }
 }
 
+#[derive(Clone, PartialEq, Eq, Hash, Debug)]
+pub struct TraitRef {
+    pub path: Path,
+}
+
+impl TraitRef {
+    /// Converts an `ast::PathType` to a `hir::TraitRef`.
+    pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Option<Self> {
+        // FIXME: Use `Path::from_src`
+        match node {
+            ast::Type::PathType(path) => {
+                path.path().and_then(|it| ctx.lower_path(it)).map(|path| TraitRef { path })
+            }
+            _ => None,
+        }
+    }
+}
+
 /// Compare ty::Ty
 #[derive(Clone, PartialEq, Eq, Hash, Debug)]
 pub enum TypeRef {
@@ -60,13 +80,14 @@ 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*/),
     // For
     ImplTrait(Vec<TypeBound>),
     DynTrait(Vec<TypeBound>),
+    Macro(AstId<ast::MacroCall>),
     Error,
 }
 
@@ -80,8 +101,8 @@ pub(crate) fn new_name(name: Name) -> Self {
         LifetimeRef { name }
     }
 
-    pub(crate) fn from_token(token: SyntaxToken) -> Self {
-        LifetimeRef { name: Name::new_lifetime(&token) }
+    pub(crate) fn new(lifetime: &ast::Lifetime) -> Self {
+        LifetimeRef { name: Name::new_lifetime(lifetime) }
     }
 
     pub fn missing() -> LifetimeRef {
@@ -99,7 +120,7 @@ pub enum TypeBound {
 
 impl TypeRef {
     /// Converts an `ast::TypeRef` to a `hir::TypeRef`.
-    pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
+    pub fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
         match node {
             ast::Type::ParenType(inner) => TypeRef::from_ast_opt(&ctx, inner.ty()),
             ast::Type::TupleType(inner) => {
@@ -120,14 +141,19 @@ pub(crate) 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())))
             }
             ast::Type::RefType(inner) => {
                 let inner_ty = TypeRef::from_ast_opt(&ctx, inner.ty());
-                let lifetime = inner.lifetime_token().map(|t| LifetimeRef::from_token(t));
+                let lifetime = inner.lifetime().map(|lt| LifetimeRef::new(&lt));
                 let mutability = Mutability::from_mutable(inner.mut_token().is_some());
                 TypeRef::Reference(Box::new(inner_ty), lifetime, mutability)
             }
@@ -159,6 +185,13 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::Type) -> Self {
             ast::Type::DynTraitType(inner) => {
                 TypeRef::DynTrait(type_bounds_from_ast(ctx, inner.type_bound_list()))
             }
+            ast::Type::MacroType(mt) => match mt.macro_call() {
+                Some(mc) => ctx
+                    .ast_id(&mc)
+                    .map(|mc| TypeRef::Macro(InFile::new(ctx.file_id(), mc)))
+                    .unwrap_or(TypeRef::Error),
+                None => TypeRef::Error,
+            },
         }
     }
 
@@ -185,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 {
@@ -196,7 +229,7 @@ fn go(type_ref: &TypeRef, f: &mut impl FnMut(&TypeRef)) {
                     }
                 }
                 TypeRef::Path(path) => go_path(path, f),
-                TypeRef::Never | TypeRef::Placeholder | TypeRef::Error => {}
+                TypeRef::Never | TypeRef::Placeholder | TypeRef::Macro(_) | TypeRef::Error => {}
             };
         }
 
@@ -259,7 +292,7 @@ pub(crate) fn from_ast(ctx: &LowerCtx, node: ast::TypeBound) -> Self {
             }
             ast::TypeBoundKind::ForType(_) => TypeBound::Error, // FIXME ForType
             ast::TypeBoundKind::Lifetime(lifetime) => {
-                TypeBound::Lifetime(LifetimeRef::from_token(lifetime))
+                TypeBound::Lifetime(LifetimeRef::new(&lifetime))
             }
         }
     }
@@ -271,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)
+    }
+}