diff options
author | Jade <[email protected]> | 2021-05-12 12:39:48 +0100 |
---|---|---|
committer | Jade <[email protected]> | 2021-05-13 05:22:46 +0100 |
commit | 8b147624ff906a11134d2e18be071c6cb8ec4beb (patch) | |
tree | 28df73a940497bc170ec9f080329657f4b1370b8 /crates/hir_def/src | |
parent | 312f1fe20a6a0a8e69834c66f51b9abc9db5e0ce (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/src')
-rw-r--r-- | crates/hir_def/src/type_ref.rs | 53 |
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 | ||
4 | use hir_expand::{name::Name, AstId, InFile}; | 4 | use hir_expand::{name::Name, AstId, InFile}; |
5 | use std::convert::TryInto; | ||
5 | use syntax::ast; | 6 | use syntax::ast; |
6 | 7 | ||
7 | use crate::{body::LowerCtx, path::Path}; | 8 | use 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)] | ||
310 | pub 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 | |||
319 | impl 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 | |||
328 | impl 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 | } | ||