|
2 | 2 | //! be directly created from an ast::TypeRef, without further queries.
|
3 | 3 |
|
4 | 4 | use hir_expand::{name::Name, AstId, InFile};
|
| 5 | +use std::convert::TryInto; |
5 | 6 | use syntax::ast;
|
6 | 7 |
|
7 | 8 | use crate::{body::LowerCtx, path::Path};
|
@@ -79,7 +80,9 @@ pub enum TypeRef {
|
79 | 80 | Path(Path),
|
80 | 81 | RawPtr(Box<TypeRef>, Mutability),
|
81 | 82 | Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
|
82 |
| - Array(Box<TypeRef> /*, Expr*/), |
| 83 | + // FIXME: for full const generics, the latter element (length) here is going to have to be an |
| 84 | + // expression that is further lowered later in hir_ty. |
| 85 | + Array(Box<TypeRef>, ConstScalar), |
83 | 86 | Slice(Box<TypeRef>),
|
84 | 87 | /// A fn pointer. Last element of the vector is the return type.
|
85 | 88 | Fn(Vec<TypeRef>, bool /*varargs*/),
|
@@ -140,7 +143,16 @@ impl TypeRef {
|
140 | 143 | TypeRef::RawPtr(Box::new(inner_ty), mutability)
|
141 | 144 | }
|
142 | 145 | ast::Type::ArrayType(inner) => {
|
143 |
| - TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) |
| 146 | + // FIXME: This is a hack. We should probably reuse the machinery of |
| 147 | + // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the |
| 148 | + // `hir_ty` level, which would allow knowing the type of: |
| 149 | + // let v: [u8; 2 + 2] = [0u8; 4]; |
| 150 | + let len = inner |
| 151 | + .expr() |
| 152 | + .map(ConstScalar::usize_from_literal_expr) |
| 153 | + .unwrap_or(ConstScalar::Unknown); |
| 154 | + |
| 155 | + TypeRef::Array(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())), len) |
144 | 156 | }
|
145 | 157 | ast::Type::SliceType(inner) => {
|
146 | 158 | TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty())))
|
@@ -212,7 +224,7 @@ impl TypeRef {
|
212 | 224 | }
|
213 | 225 | TypeRef::RawPtr(type_ref, _)
|
214 | 226 | | TypeRef::Reference(type_ref, ..)
|
215 |
| - | TypeRef::Array(type_ref) |
| 227 | + | TypeRef::Array(type_ref, _) |
216 | 228 | | TypeRef::Slice(type_ref) => go(&type_ref, f),
|
217 | 229 | TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
|
218 | 230 | for bound in bounds {
|
@@ -298,3 +310,58 @@ impl TypeBound {
|
298 | 310 | }
|
299 | 311 | }
|
300 | 312 | }
|
| 313 | + |
| 314 | +/// A concrete constant value |
| 315 | +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
| 316 | +pub enum ConstScalar { |
| 317 | + // for now, we only support the trivial case of constant evaluating the length of an array |
| 318 | + // Note that this is u64 because the target usize may be bigger than our usize |
| 319 | + Usize(u64), |
| 320 | + |
| 321 | + /// Case of an unknown value that rustc might know but we don't |
| 322 | + // FIXME: this is a hack to get around chalk not being able to represent unevaluatable |
| 323 | + // constants |
| 324 | + // https://github.com/rust-analyzer/rust-analyzer/pull/8813#issuecomment-840679177 |
| 325 | + // https://rust-lang.zulipchat.com/#narrow/stream/144729-wg-traits/topic/Handling.20non.20evaluatable.20constants'.20equality/near/238386348 |
| 326 | + Unknown, |
| 327 | +} |
| 328 | + |
| 329 | +impl std::fmt::Display for ConstScalar { |
| 330 | + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { |
| 331 | + match self { |
| 332 | + ConstScalar::Usize(us) => write!(fmt, "{}", us), |
| 333 | + ConstScalar::Unknown => write!(fmt, "_"), |
| 334 | + } |
| 335 | + } |
| 336 | +} |
| 337 | + |
| 338 | +impl ConstScalar { |
| 339 | + /// Gets a target usize out of the ConstScalar |
| 340 | + pub fn as_usize(&self) -> Option<u64> { |
| 341 | + match self { |
| 342 | + &ConstScalar::Usize(us) => Some(us), |
| 343 | + _ => None, |
| 344 | + } |
| 345 | + } |
| 346 | + |
| 347 | + // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this |
| 348 | + // parse stage. |
| 349 | + fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar { |
| 350 | + match expr { |
| 351 | + ast::Expr::Literal(lit) => { |
| 352 | + let lkind = lit.kind(); |
| 353 | + match lkind { |
| 354 | + ast::LiteralKind::IntNumber(num) |
| 355 | + if num.suffix() == None || num.suffix() == Some("usize") => |
| 356 | + { |
| 357 | + num.value().and_then(|v| v.try_into().ok()) |
| 358 | + } |
| 359 | + _ => None, |
| 360 | + } |
| 361 | + } |
| 362 | + _ => None, |
| 363 | + } |
| 364 | + .map(ConstScalar::Usize) |
| 365 | + .unwrap_or(ConstScalar::Unknown) |
| 366 | + } |
| 367 | +} |
0 commit comments