From aafe9b1e06b2027b04bc87389adef04f931823e6 Mon Sep 17 00:00:00 2001 From: hkalbasi Date: Wed, 3 May 2023 18:54:30 +0330 Subject: [PATCH] Lazy evaluate consts in `path_to_const` --- crates/hir-ty/src/consteval.rs | 8 +++++- crates/hir-ty/src/infer.rs | 11 +++++--- crates/hir-ty/src/infer/unify.rs | 45 +++++++++++++++++++++++-------- crates/hir-ty/src/layout/tests.rs | 8 ++++++ crates/hir-ty/src/lower.rs | 1 + crates/hir-ty/src/tests/simple.rs | 20 ++++++++++++-- 6 files changed, 76 insertions(+), 17 deletions(-) diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs index 80b72768b3c..c3726905b67 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 { 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 0e9b7206d04..32e87031438 100644 --- a/crates/hir-ty/src/infer.rs +++ b/crates/hir-ty/src/infer.rs @@ -17,7 +17,7 @@ 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 @@ 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, 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 b735a11adfb..21b962a48f2 100644 --- a/crates/hir-ty/src/infer/unify.rs +++ b/crates/hir-ty/src/infer/unify.rs @@ -15,11 +15,11 @@ 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 @@ pub(crate) fn normalize_associated_types_in(&mut self, ty: T) -> T where T: HasInterner + TypeFoldable, { - 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 1502ab14cc7..e1038c0affe 100644 --- a/crates/hir-ty/src/layout/tests.rs +++ b/crates/hir-ty/src/layout/tests.rs @@ -353,6 +353,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! { diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs index 4000ba5c14c..0f823580cba 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 72e98138a34..e249cddc2fc 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; fn main() { const B: bool = false; let foo = Foo::; - //^^^ Foo<_> + //^^^ Foo +} +"#, + ); + check_types( + r#" +struct Foo; +impl Foo { + fn foo(self) -> u8 { 2 } +} +impl Foo { + fn foo(self) -> u16 { 5 } +} +fn main() { + const B: bool = false; + let foo: Foo = Foo; + let x = foo.foo(); + //^ u16 } "#, );