diff options
| author | bors <bors@rust-lang.org> | 2023-05-08 07:14:57 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2023-05-08 07:14:57 +0000 |
| commit | ff8b9699518d4fe92f08629d91b3983e00f75282 (patch) | |
| tree | 6f30c49ff0f86c95b8c08167ac88431c13b25511 | |
| parent | 833d5301d1ac47b2d3f0a71b67c5887f7481cc4e (diff) | |
| parent | aafe9b1e06b2027b04bc87389adef04f931823e6 (diff) | |
| download | rust-ff8b9699518d4fe92f08629d91b3983e00f75282.tar.gz rust-ff8b9699518d4fe92f08629d91b3983e00f75282.zip | |
Auto merge of #14727 - HKalbasi:mir, r=HKalbasi
Lazy evaluate consts in `path_to_const` fix #14275
| -rw-r--r-- | crates/hir-ty/src/consteval.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer.rs | 11 | ||||
| -rw-r--r-- | crates/hir-ty/src/infer/unify.rs | 45 | ||||
| -rw-r--r-- | crates/hir-ty/src/layout/tests.rs | 8 | ||||
| -rw-r--r-- | crates/hir-ty/src/lower.rs | 1 | ||||
| -rw-r--r-- | 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<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 0e9b7206d04..32e87031438 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 b735a11adfb..21b962a48f2 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 1502ab14cc7..e1038c0affe 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 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<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 } "#, ); |
