Lazy evaluate consts in path_to_const
This commit is contained in:
parent
0dd94d3b07
commit
aafe9b1e06
@ -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;
|
||||
}
|
||||
}
|
||||
|
@ -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<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);
|
||||
|
@ -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<T>(&mut self, ty: T) -> T
|
||||
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,
|
||||
)
|
||||
|
@ -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! {
|
||||
|
@ -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))
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
"#,
|
||||
);
|
||||
|
Loading…
Reference in New Issue
Block a user