Add lowering of array lengths in types

Now e.g.

```rust
fn a(b: [u8; 2]) {
}
```

will know about the length of b.
This commit is contained in:
Jade 2021-05-12 04:39:48 -07:00
parent 312f1fe20a
commit 8b147624ff
10 changed files with 114 additions and 79 deletions

View File

@ -2,6 +2,7 @@
//! be directly created from an ast::TypeRef, without further queries. //! be directly created from an ast::TypeRef, without further queries.
use hir_expand::{name::Name, AstId, InFile}; use hir_expand::{name::Name, AstId, InFile};
use std::convert::TryInto;
use syntax::ast; use syntax::ast;
use crate::{body::LowerCtx, path::Path}; use crate::{body::LowerCtx, path::Path};
@ -79,7 +80,7 @@ pub enum TypeRef {
Path(Path), Path(Path),
RawPtr(Box<TypeRef>, Mutability), RawPtr(Box<TypeRef>, Mutability),
Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability), Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
Array(Box<TypeRef> /*, Expr*/), Array(Box<TypeRef>, ConstScalar),
Slice(Box<TypeRef>), Slice(Box<TypeRef>),
/// A fn pointer. Last element of the vector is the return type. /// A fn pointer. Last element of the vector is the return type.
Fn(Vec<TypeRef>, bool /*varargs*/), 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) TypeRef::RawPtr(Box::new(inner_ty), mutability)
} }
ast::Type::ArrayType(inner) => { 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) => { ast::Type::SliceType(inner) => {
TypeRef::Slice(Box::new(TypeRef::from_ast_opt(&ctx, inner.ty()))) 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::RawPtr(type_ref, _)
| TypeRef::Reference(type_ref, ..) | TypeRef::Reference(type_ref, ..)
| TypeRef::Array(type_ref) | TypeRef::Array(type_ref, _)
| TypeRef::Slice(type_ref) => go(&type_ref, f), | TypeRef::Slice(type_ref) => go(&type_ref, f),
TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => { TypeRef::ImplTrait(bounds) | TypeRef::DynTrait(bounds) => {
for bound in 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)
}
}

View File

@ -1,21 +0,0 @@
//! Handling of concrete const values
/// 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, "_"),
}
}
}

View File

@ -962,11 +962,10 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
write!(f, "{}", mutability)?; write!(f, "{}", mutability)?;
inner.hir_fmt(f)?; inner.hir_fmt(f)?;
} }
TypeRef::Array(inner) => { TypeRef::Array(inner, len) => {
write!(f, "[")?; write!(f, "[")?;
inner.hir_fmt(f)?; inner.hir_fmt(f)?;
// FIXME: Array length? write!(f, "; {}]", len)?;
write!(f, "; _]")?;
} }
TypeRef::Slice(inner) => { TypeRef::Slice(inner) => {
write!(f, "[")?; write!(f, "[")?;

View File

@ -8,6 +8,7 @@
expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp}, expr::{Array, BinaryOp, Expr, ExprId, Literal, Statement, UnaryOp},
path::{GenericArg, GenericArgs}, path::{GenericArg, GenericArgs},
resolver::resolver_for_expr, resolver::resolver_for_expr,
type_ref::ConstScalar,
AssocContainerId, FieldId, Lookup, AssocContainerId, FieldId, Lookup,
}; };
use hir_expand::name::{name, Name}; use hir_expand::name::{name, Name};
@ -15,9 +16,7 @@
use syntax::ast::RangeOp; use syntax::ast::RangeOp;
use crate::{ use crate::{
autoderef, autoderef, dummy_usize_const,
consts::ConstScalar,
dummy_usize_const,
lower::lower_to_chalk_mutability, lower::lower_to_chalk_mutability,
mapping::from_chalk, mapping::from_chalk,
method_resolution, op, method_resolution, op,
@ -737,7 +736,8 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner), TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
), ),
); );
// FIXME: support length for Repeat array expressions // FIXME: we don't know the length here because hir Exprs don't actually
// get the value out of the AST, even though it is there.
None None
} }
}; };

View File

@ -1,11 +1,12 @@
//! Implementation of the Chalk `Interner` trait, which allows customizing the //! Implementation of the Chalk `Interner` trait, which allows customizing the
//! representation of the various objects Chalk deals with (types, goals etc.). //! representation of the various objects Chalk deals with (types, goals etc.).
use crate::{chalk_db, consts::ConstScalar, tls, GenericArg}; use crate::{chalk_db, tls, GenericArg};
use base_db::salsa::InternId; use base_db::salsa::InternId;
use chalk_ir::{Goal, GoalData}; use chalk_ir::{Goal, GoalData};
use hir_def::{ use hir_def::{
intern::{impl_internable, InternStorage, Internable, Interned}, intern::{impl_internable, InternStorage, Internable, Interned},
type_ref::ConstScalar,
TypeAliasId, TypeAliasId,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;

View File

@ -12,7 +12,6 @@ macro_rules! eprintln {
mod chalk_ext; mod chalk_ext;
mod infer; mod infer;
mod interner; mod interner;
mod consts;
mod lower; mod lower;
mod mapping; mod mapping;
mod op; mod op;
@ -38,9 +37,13 @@ macro_rules! eprintln {
interner::HasInterner, interner::HasInterner,
UintTy, UintTy,
}; };
use hir_def::{expr::ExprId, type_ref::Rawness, TypeParamId}; use hir_def::{
expr::ExprId,
type_ref::{ConstScalar, Rawness},
TypeParamId,
};
use crate::{consts::ConstScalar, db::HirDatabase, display::HirDisplay, utils::generics}; use crate::{db::HirDatabase, display::HirDisplay, utils::generics};
pub use autoderef::autoderef; pub use autoderef::autoderef;
pub use builder::TyBuilder; pub use builder::TyBuilder;

View File

@ -9,7 +9,9 @@
use std::{iter, sync::Arc}; use std::{iter, sync::Arc};
use base_db::CrateId; use base_db::CrateId;
use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety}; use chalk_ir::{
cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety, Scalar, UintTy,
};
use hir_def::{ use hir_def::{
adt::StructKind, adt::StructKind,
body::{Expander, LowerCtx}, body::{Expander, LowerCtx},
@ -30,16 +32,15 @@
use crate::{ use crate::{
db::HirDatabase, db::HirDatabase,
dummy_usize_const,
mapping::ToChalk, mapping::ToChalk,
static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx, static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
utils::{ utils::{
all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics, all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
}, },
AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig, AliasEq, AliasTy, Binders, BoundVar, CallableSig, ConstData, ConstValue, DebruijnIndex, DynTy,
FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy, QuantifiedWhereClause, FnPointer, FnSig, FnSubst, ImplTraitId, Interner, OpaqueTy, PolyFnSig, ProjectionTy,
QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution, QuantifiedWhereClause, QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits,
TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause, Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyBuilder, TyKind, WhereClause,
}; };
#[derive(Debug)] #[derive(Debug)]
@ -172,11 +173,16 @@ pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);
TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner) TyKind::Raw(lower_to_chalk_mutability(*mutability), inner_ty).intern(&Interner)
} }
TypeRef::Array(inner) => { TypeRef::Array(inner, len) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);
// FIXME: we don't have length info here because we don't store an expression for
// the length let const_len = ConstData {
TyKind::Array(inner_ty, dummy_usize_const()).intern(&Interner) ty: TyKind::Scalar(Scalar::Uint(UintTy::Usize)).intern(&Interner),
value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: *len }),
}
.intern(&Interner);
TyKind::Array(inner_ty, const_len).intern(&Interner)
} }
TypeRef::Slice(inner) => { TypeRef::Slice(inner) => {
let inner_ty = self.lower_ty(inner); let inner_ty = self.lower_ty(inner);

View File

@ -64,42 +64,42 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
81..92 '{ loop {} }': T 81..92 '{ loop {} }': T
83..90 'loop {}': ! 83..90 'loop {}': !
88..90 '{}': () 88..90 '{}': ()
121..132 '{ loop {} }': *mut [T; _] 121..132 '{ loop {} }': *mut [T; 2]
123..130 'loop {}': ! 123..130 'loop {}': !
128..130 '{}': () 128..130 '{}': ()
159..172 '{ gen() }': *mut [U] 159..172 '{ gen() }': *mut [U]
165..168 'gen': fn gen<U>() -> *mut [U; _] 165..168 'gen': fn gen<U>() -> *mut [U; 2]
165..170 'gen()': *mut [U; _] 165..170 'gen()': *mut [U; 2]
185..419 '{ ...rr); }': () 185..419 '{ ...rr); }': ()
195..198 'arr': &[u8; _] 195..198 'arr': &[u8; 1]
211..215 '&[1]': &[u8; 1] 211..215 '&[1]': &[u8; 1]
212..215 '[1]': [u8; 1] 212..215 '[1]': [u8; 1]
213..214 '1': u8 213..214 '1': u8
226..227 'a': &[u8] 226..227 'a': &[u8]
236..239 'arr': &[u8; _] 236..239 'arr': &[u8; 1]
249..250 'b': u8 249..250 'b': u8
253..254 'f': fn f<u8>(&[u8]) -> u8 253..254 'f': fn f<u8>(&[u8]) -> u8
253..259 'f(arr)': u8 253..259 'f(arr)': u8
255..258 'arr': &[u8; _] 255..258 'arr': &[u8; 1]
269..270 'c': &[u8] 269..270 'c': &[u8]
279..286 '{ arr }': &[u8] 279..286 '{ arr }': &[u8]
281..284 'arr': &[u8; _] 281..284 'arr': &[u8; 1]
296..297 'd': u8 296..297 'd': u8
300..301 'g': fn g<u8>(S<&[u8]>) -> u8 300..301 'g': fn g<u8>(S<&[u8]>) -> u8
300..315 'g(S { a: arr })': u8 300..315 'g(S { a: arr })': u8
302..314 'S { a: arr }': S<&[u8]> 302..314 'S { a: arr }': S<&[u8]>
309..312 'arr': &[u8; _] 309..312 'arr': &[u8; 1]
325..326 'e': [&[u8]; _] 325..326 'e': [&[u8]; 1]
340..345 '[arr]': [&[u8]; 1] 340..345 '[arr]': [&[u8]; 1]
341..344 'arr': &[u8; _] 341..344 'arr': &[u8; 1]
355..356 'f': [&[u8]; _] 355..356 'f': [&[u8]; 2]
370..378 '[arr; 2]': [&[u8]; _] 370..378 '[arr; 2]': [&[u8]; _]
371..374 'arr': &[u8; _] 371..374 'arr': &[u8; 1]
376..377 '2': usize 376..377 '2': usize
388..389 'g': (&[u8], &[u8]) 388..389 'g': (&[u8], &[u8])
406..416 '(arr, arr)': (&[u8], &[u8]) 406..416 '(arr, arr)': (&[u8], &[u8])
407..410 'arr': &[u8; _] 407..410 'arr': &[u8; 1]
412..415 'arr': &[u8; _] 412..415 'arr': &[u8; 1]
"#]], "#]],
); );
} }
@ -159,7 +159,7 @@ pub trait CoerceUnsized<T> {}
impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {} impl<'a, 'b: 'a, T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<&'a U> for &'b T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {} impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
"#, "#,
expect![[r" expect![[r#"
257..258 'x': A<[T]> 257..258 'x': A<[T]>
278..283 '{ x }': A<[T]> 278..283 '{ x }': A<[T]>
280..281 'x': A<[T]> 280..281 'x': A<[T]>
@ -169,23 +169,23 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
333..334 'x': C<[T]> 333..334 'x': C<[T]>
354..359 '{ x }': C<[T]> 354..359 '{ x }': C<[T]>
356..357 'x': C<[T]> 356..357 'x': C<[T]>
369..370 'a': A<[u8; _]> 369..370 'a': A<[u8; 2]>
384..385 'b': B<[u8; _]> 384..385 'b': B<[u8; 2]>
399..400 'c': C<[u8; _]> 399..400 'c': C<[u8; 2]>
414..480 '{ ...(c); }': () 414..480 '{ ...(c); }': ()
424..425 'd': A<[{unknown}]> 424..425 'd': A<[{unknown}]>
428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]> 428..432 'foo1': fn foo1<{unknown}>(A<[{unknown}]>) -> A<[{unknown}]>
428..435 'foo1(a)': A<[{unknown}]> 428..435 'foo1(a)': A<[{unknown}]>
433..434 'a': A<[u8; _]> 433..434 'a': A<[u8; 2]>
445..446 'e': B<[u8]> 445..446 'e': B<[u8]>
449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]> 449..453 'foo2': fn foo2<u8>(B<[u8]>) -> B<[u8]>
449..456 'foo2(b)': B<[u8]> 449..456 'foo2(b)': B<[u8]>
454..455 'b': B<[u8; _]> 454..455 'b': B<[u8; 2]>
466..467 'f': C<[u8]> 466..467 'f': C<[u8]>
470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]> 470..474 'foo3': fn foo3<u8>(C<[u8]>) -> C<[u8]>
470..477 'foo3(c)': C<[u8]> 470..477 'foo3(c)': C<[u8]>
475..476 'c': C<[u8; _]> 475..476 'c': C<[u8; 2]>
"]], "#]],
); );
} }

View File

@ -345,19 +345,19 @@ fn test() {
"#, "#,
expect![[r#" expect![[r#"
10..179 '{ ... } }': () 10..179 '{ ... } }': ()
20..23 'arr': [f64; _] 20..23 'arr': [f64; 2]
36..46 '[0.0, 1.0]': [f64; 2] 36..46 '[0.0, 1.0]': [f64; 2]
37..40 '0.0': f64 37..40 '0.0': f64
42..45 '1.0': f64 42..45 '1.0': f64
52..177 'match ... }': () 52..177 'match ... }': ()
58..61 'arr': [f64; _] 58..61 'arr': [f64; 2]
72..80 '[1.0, a]': [f64; _] 72..80 '[1.0, a]': [f64; 2]
73..76 '1.0': f64 73..76 '1.0': f64
73..76 '1.0': f64 73..76 '1.0': f64
78..79 'a': f64 78..79 'a': f64
84..110 '{ ... }': () 84..110 '{ ... }': ()
98..99 'a': f64 98..99 'a': f64
120..126 '[b, c]': [f64; _] 120..126 '[b, c]': [f64; 2]
121..122 'b': f64 121..122 'b': f64
124..125 'c': f64 124..125 'c': f64
130..171 '{ ... }': () 130..171 '{ ... }': ()

View File

@ -1313,7 +1313,7 @@ fn test(x: &str, y: isize) {
255..256 'a': [&str; 1] 255..256 'a': [&str; 1]
258..263 '["b"]': [&str; 1] 258..263 '["b"]': [&str; 1]
259..262 '"b"': &str 259..262 '"b"': &str
274..275 'x': [u8; _] 274..275 'x': [u8; 0]
287..289 '[]': [u8; 0] 287..289 '[]': [u8; 0]
"#]], "#]],
); );
@ -2409,38 +2409,38 @@ fn test() {
320..422 '{ ... }': V2 320..422 '{ ... }': V2
334..335 'x': f32 334..335 'x': f32
338..342 'self': V2 338..342 'self': V2
338..344 'self.0': [f32; _] 338..344 'self.0': [f32; 2]
338..347 'self.0[0]': {unknown} 338..347 'self.0[0]': {unknown}
338..358 'self.0...s.0[0]': f32 338..358 'self.0...s.0[0]': f32
345..346 '0': i32 345..346 '0': i32
350..353 'rhs': V2 350..353 'rhs': V2
350..355 'rhs.0': [f32; _] 350..355 'rhs.0': [f32; 2]
350..358 'rhs.0[0]': {unknown} 350..358 'rhs.0[0]': {unknown}
356..357 '0': i32 356..357 '0': i32
372..373 'y': f32 372..373 'y': f32
376..380 'self': V2 376..380 'self': V2
376..382 'self.0': [f32; _] 376..382 'self.0': [f32; 2]
376..385 'self.0[1]': {unknown} 376..385 'self.0[1]': {unknown}
376..396 'self.0...s.0[1]': f32 376..396 'self.0...s.0[1]': f32
383..384 '1': i32 383..384 '1': i32
388..391 'rhs': V2 388..391 'rhs': V2
388..393 'rhs.0': [f32; _] 388..393 'rhs.0': [f32; 2]
388..396 'rhs.0[1]': {unknown} 388..396 'rhs.0[1]': {unknown}
394..395 '1': i32 394..395 '1': i32
406..408 'V2': V2([f32; _]) -> V2 406..408 'V2': V2([f32; 2]) -> V2
406..416 'V2([x, y])': V2 406..416 'V2([x, y])': V2
409..415 '[x, y]': [f32; 2] 409..415 '[x, y]': [f32; 2]
410..411 'x': f32 410..411 'x': f32
413..414 'y': f32 413..414 'y': f32
436..519 '{ ... vb; }': () 436..519 '{ ... vb; }': ()
446..448 'va': V2 446..448 'va': V2
451..453 'V2': V2([f32; _]) -> V2 451..453 'V2': V2([f32; 2]) -> V2
451..465 'V2([0.0, 1.0])': V2 451..465 'V2([0.0, 1.0])': V2
454..464 '[0.0, 1.0]': [f32; 2] 454..464 '[0.0, 1.0]': [f32; 2]
455..458 '0.0': f32 455..458 '0.0': f32
460..463 '1.0': f32 460..463 '1.0': f32
475..477 'vb': V2 475..477 'vb': V2
480..482 'V2': V2([f32; _]) -> V2 480..482 'V2': V2([f32; 2]) -> V2
480..494 'V2([0.0, 1.0])': V2 480..494 'V2([0.0, 1.0])': V2
483..493 '[0.0, 1.0]': [f32; 2] 483..493 '[0.0, 1.0]': [f32; 2]
484..487 '0.0': f32 484..487 '0.0': f32