Unnamed repository; edit this file 'description' to name the repository.
Lazy evaluate consts in `path_to_const`
hkalbasi 2023-05-05
parent 0dd94d3 · commit aafe9b1
-rw-r--r--crates/hir-ty/src/consteval.rs8
-rw-r--r--crates/hir-ty/src/infer.rs11
-rw-r--r--crates/hir-ty/src/infer/unify.rs45
-rw-r--r--crates/hir-ty/src/layout/tests.rs8
-rw-r--r--crates/hir-ty/src/lower.rs1
-rw-r--r--crates/hir-ty/src/tests/simple.rs20
6 files changed, 76 insertions, 17 deletions
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 80b72768b3..c3726905b6 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -76,6 +76,7 @@ pub(crate) fn path_to_const(
mode: ParamLoweringMode,
args_lazy: impl FnOnce() -> Generics,
debruijn: DebruijnIndex,
+ expected_ty: Ty,
) -> Option<Const> {
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
Some(ValueNs::GenericParam(p)) => {
@@ -100,6 +101,10 @@ pub(crate) fn path_to_const(
};
Some(ConstData { ty, value }.intern(Interner))
}
+ Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
+ ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
+ expected_ty,
+ )),
_ => None,
}
}
@@ -227,9 +232,10 @@ pub(crate) fn eval_to_const(
debruijn: DebruijnIndex,
) -> Const {
let db = ctx.db;
+ let infer = ctx.clone().resolve_all();
if let Expr::Path(p) = &ctx.body.exprs[expr] {
let resolver = &ctx.resolver;
- if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn) {
+ if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) {
return c;
}
}
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 0e9b7206d0..32e8703143 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -17,7 +17,7 @@ use std::{convert::identity, ops::Index};
use chalk_ir::{
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
- Scalar, TypeFlags,
+ Scalar, TyKind, TypeFlags,
};
use either::Either;
use hir_def::{
@@ -44,7 +44,7 @@ use crate::{
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal,
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
- TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+ TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
};
// This lint has a false positive here. See the link below for details.
@@ -118,7 +118,12 @@ pub(crate) fn infer_query(db: &dyn HirDatabase, def: DefWithBodyId) -> Arc<Infer
/// This is appropriate to use only after type-check: it assumes
/// that normalization will succeed, for example.
pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
- if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
+ // FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
+ // works for the type case, so we check array unconditionally. Remove the array part
+ // when the bug in chalk becomes fixed.
+ if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION)
+ && !matches!(ty.kind(Interner), TyKind::Array(..))
+ {
return ty;
}
let mut table = unify::InferenceTable::new(db, trait_env);
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index b735a11adf..21b962a48f 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -15,11 +15,11 @@ use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{
- db::HirDatabase, fold_tys, fold_tys_and_consts, static_lifetime, to_chalk_trait_id,
- traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex,
- GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
- ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty,
- TyBuilder, TyExt, TyKind, VariableKind,
+ db::HirDatabase, fold_tys_and_consts, static_lifetime, to_chalk_trait_id, traits::FnTrait,
+ AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg,
+ GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime, ParamKind,
+ ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder,
+ TyExt, TyKind, VariableKind,
};
impl<'a> InferenceContext<'a> {
@@ -236,13 +236,36 @@ impl<'a> InferenceTable<'a> {
where
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
{
- fold_tys(
+ fold_tys_and_consts(
ty,
- |ty, _| match ty.kind(Interner) {
- TyKind::Alias(AliasTy::Projection(proj_ty)) => {
- self.normalize_projection_ty(proj_ty.clone())
- }
- _ => ty,
+ |e, _| match e {
+ Either::Left(ty) => Either::Left(match ty.kind(Interner) {
+ TyKind::Alias(AliasTy::Projection(proj_ty)) => {
+ self.normalize_projection_ty(proj_ty.clone())
+ }
+ _ => ty,
+ }),
+ Either::Right(c) => Either::Right(match &c.data(Interner).value {
+ chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
+ crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
+ // FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable
+ // and registering an obligation. But it needs chalk support, so we handle the most basic
+ // case (a non associated const without generic parameters) manually.
+ if subst.len(Interner) == 0 {
+ if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
+ {
+ eval
+ } else {
+ c
+ }
+ } else {
+ c
+ }
+ }
+ _ => c,
+ },
+ _ => c,
+ }),
},
DebruijnIndex::INNERMOST,
)
diff --git a/crates/hir-ty/src/layout/tests.rs b/crates/hir-ty/src/layout/tests.rs
index 1502ab14cc..e1038c0aff 100644
--- a/crates/hir-ty/src/layout/tests.rs
+++ b/crates/hir-ty/src/layout/tests.rs
@@ -354,6 +354,14 @@ fn niche_optimization() {
}
#[test]
+fn const_eval() {
+ size_and_align! {
+ const X: usize = 5;
+ struct Goal([i32; X]);
+ }
+}
+
+#[test]
fn enums_with_discriminants() {
size_and_align! {
enum Goal {
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 4000ba5c14..0f823580cb 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -2023,6 +2023,7 @@ pub(crate) fn const_or_path_to_chalk(
mode,
args,
debruijn,
+ expected_ty.clone(),
)
.unwrap_or_else(|| unknown_const(expected_ty))
}
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 72e98138a3..e249cddc2f 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -3529,14 +3529,30 @@ fn main() {
#[test]
fn issue_14275() {
- // FIXME: evaluate const generic
check_types(
r#"
struct Foo<const T: bool>;
fn main() {
const B: bool = false;
let foo = Foo::<B>;
- //^^^ Foo<_>
+ //^^^ Foo<false>
+}
+"#,
+ );
+ check_types(
+ r#"
+struct Foo<const T: bool>;
+impl Foo<true> {
+ fn foo(self) -> u8 { 2 }
+}
+impl Foo<false> {
+ fn foo(self) -> u16 { 5 }
+}
+fn main() {
+ const B: bool = false;
+ let foo: Foo<B> = Foo;
+ let x = foo.foo();
+ //^ u16
}
"#,
);