aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_def
diff options
context:
space:
mode:
authorJade <[email protected]>2021-05-12 12:39:48 +0100
committerJade <[email protected]>2021-05-13 05:22:46 +0100
commit8b147624ff906a11134d2e18be071c6cb8ec4beb (patch)
tree28df73a940497bc170ec9f080329657f4b1370b8 /crates/hir_def
parent312f1fe20a6a0a8e69834c66f51b9abc9db5e0ce (diff)
Add lowering of array lengths in types
Now e.g. ```rust fn a(b: [u8; 2]) { } ``` will know about the length of b.
Diffstat (limited to 'crates/hir_def')
-rw-r--r--crates/hir_def/src/type_ref.rs53
1 files changed, 50 insertions, 3 deletions
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 @@
2//! be directly created from an ast::TypeRef, without further queries. 2//! be directly created from an ast::TypeRef, without further queries.
3 3
4use hir_expand::{name::Name, AstId, InFile}; 4use hir_expand::{name::Name, AstId, InFile};
5use std::convert::TryInto;
5use syntax::ast; 6use syntax::ast;
6 7
7use crate::{body::LowerCtx, path::Path}; 8use crate::{body::LowerCtx, path::Path};
@@ -79,7 +80,7 @@ pub enum TypeRef {
79 Path(Path), 80 Path(Path),
80 RawPtr(Box<TypeRef>, Mutability), 81 RawPtr(Box<TypeRef>, Mutability),
81 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), 82 Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
82 Array(Box<TypeRef> /*, Expr*/), 83 Array(Box<TypeRef>, ConstScalar),
83 Slice(Box<TypeRef>), 84 Slice(Box<TypeRef>),
84 /// A fn pointer. Last element of the vector is the return type. 85 /// A fn pointer. Last element of the vector is the return type.
85 Fn(Vec<TypeRef>, bool /*varargs*/), 86 Fn(Vec<TypeRef>, bool /*varargs*/),
@@ -140,7 +141,12 @@ impl TypeRef {
140 TypeRef::RawPtr(Box::new(inner_ty), mutability) 141 TypeRef::RawPtr(Box::new(inner_ty), mutability)
141 } 142 }
142 ast::Type::ArrayType(inner) => { 143 ast::Type::ArrayType(inner) => {
143 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 144 let len = inner
145 .expr()
146 .map(ConstScalar::usize_from_literal_expr)
147 .unwrap_or(ConstScalar::Unknown);
148
149 TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len)
144 } 150 }
145 ast::Type::SliceType(inner) => { 151 ast::Type::SliceType(inner) => {
146 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 152 TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
@@ -212,7 +218,7 @@ impl TypeRef {
212 } 218 }
213 TypeRef::RawPtr(type_ref, _) 219 TypeRef::RawPtr(type_ref, _)
214 | TypeRef::Reference(type_ref, ..) 220 | TypeRef::Reference(type_ref, ..)
215 | TypeRef::Array(type_ref) 221 | TypeRef::Array(type_ref, _)
216 | TypeRef::Slice(type_ref) => go(&type_ref, f), 222 | TypeRef::Slice(type_ref) => go(&type_ref, f),
217 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { 223 TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
218 for bound in bounds { 224 for bound in bounds {
@@ -298,3 +304,44 @@ impl TypeBound {
298 } 304 }
299 } 305 }
300} 306}
307
308/// A concrete constant value
309#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
310pub enum ConstScalar {
311 // for now, we only support the trivial case of constant evaluating the length of an array
312 // Note that this is u64 because the target usize may be bigger than our usize
313 Usize(u64),
314
315 /// Case of an unknown value that rustc might know but we don't
316 Unknown,
317}
318
319impl std::fmt::Display for ConstScalar {
320 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
321 match self {
322 ConstScalar::Usize(us) => write!(fmt, "{}", us),
323 ConstScalar::Unknown => write!(fmt, "_"),
324 }
325 }
326}
327
328impl ConstScalar {
329 fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
330 match expr {
331 ast::Expr::Literal(lit) => {
332 let lkind = lit.kind();
333 match lkind {
334 ast::LiteralKind::IntNumber(num)
335 if num.suffix() == None || num.suffix() == Some("usize") =>
336 {
337 num.value().and_then(|v| v.try_into().ok())
338 }
339 _ => None,
340 }
341 }
342 _ => None,
343 }
344 .map(ConstScalar::Usize)
345 .unwrap_or(ConstScalar::Unknown)
346 }
347}