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,
|
mode: ParamLoweringMode,
|
||||||
args_lazy: impl FnOnce() -> Generics,
|
args_lazy: impl FnOnce() -> Generics,
|
||||||
debruijn: DebruijnIndex,
|
debruijn: DebruijnIndex,
|
||||||
|
expected_ty: Ty,
|
||||||
) -> Option<Const> {
|
) -> Option<Const> {
|
||||||
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
|
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
|
||||||
Some(ValueNs::GenericParam(p)) => {
|
Some(ValueNs::GenericParam(p)) => {
|
||||||
@ -100,6 +101,10 @@ pub(crate) fn path_to_const(
|
|||||||
};
|
};
|
||||||
Some(ConstData { ty, value }.intern(Interner))
|
Some(ConstData { ty, value }.intern(Interner))
|
||||||
}
|
}
|
||||||
|
Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
|
||||||
|
ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
|
||||||
|
expected_ty,
|
||||||
|
)),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -227,9 +232,10 @@ pub(crate) fn eval_to_const(
|
|||||||
debruijn: DebruijnIndex,
|
debruijn: DebruijnIndex,
|
||||||
) -> Const {
|
) -> Const {
|
||||||
let db = ctx.db;
|
let db = ctx.db;
|
||||||
|
let infer = ctx.clone().resolve_all();
|
||||||
if let Expr::Path(p) = &ctx.body.exprs[expr] {
|
if let Expr::Path(p) = &ctx.body.exprs[expr] {
|
||||||
let resolver = &ctx.resolver;
|
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;
|
return c;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -17,7 +17,7 @@ use std::{convert::identity, ops::Index};
|
|||||||
|
|
||||||
use chalk_ir::{
|
use chalk_ir::{
|
||||||
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
|
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
|
||||||
Scalar, TypeFlags,
|
Scalar, TyKind, TypeFlags,
|
||||||
};
|
};
|
||||||
use either::Either;
|
use either::Either;
|
||||||
use hir_def::{
|
use hir_def::{
|
||||||
@ -44,7 +44,7 @@ use crate::{
|
|||||||
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
|
||||||
static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal,
|
static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal,
|
||||||
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
|
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.
|
// 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
|
/// This is appropriate to use only after type-check: it assumes
|
||||||
/// that normalization will succeed, for example.
|
/// that normalization will succeed, for example.
|
||||||
pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
|
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;
|
return ty;
|
||||||
}
|
}
|
||||||
let mut table = unify::InferenceTable::new(db, trait_env);
|
let mut table = unify::InferenceTable::new(db, trait_env);
|
||||||
|
@ -15,11 +15,11 @@ use triomphe::Arc;
|
|||||||
|
|
||||||
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
use super::{InferOk, InferResult, InferenceContext, TypeError};
|
||||||
use crate::{
|
use crate::{
|
||||||
db::HirDatabase, fold_tys, fold_tys_and_consts, static_lifetime, to_chalk_trait_id,
|
db::HirDatabase, fold_tys_and_consts, static_lifetime, to_chalk_trait_id, traits::FnTrait,
|
||||||
traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex,
|
AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg,
|
||||||
GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
|
GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime, ParamKind,
|
||||||
ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty,
|
ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder,
|
||||||
TyBuilder, TyExt, TyKind, VariableKind,
|
TyExt, TyKind, VariableKind,
|
||||||
};
|
};
|
||||||
|
|
||||||
impl<'a> InferenceContext<'a> {
|
impl<'a> InferenceContext<'a> {
|
||||||
@ -236,13 +236,36 @@ impl<'a> InferenceTable<'a> {
|
|||||||
where
|
where
|
||||||
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
|
||||||
{
|
{
|
||||||
fold_tys(
|
fold_tys_and_consts(
|
||||||
ty,
|
ty,
|
||||||
|ty, _| match ty.kind(Interner) {
|
|e, _| match e {
|
||||||
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
|
Either::Left(ty) => Either::Left(match ty.kind(Interner) {
|
||||||
self.normalize_projection_ty(proj_ty.clone())
|
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
|
||||||
}
|
self.normalize_projection_ty(proj_ty.clone())
|
||||||
_ => ty,
|
}
|
||||||
|
_ => 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,
|
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]
|
#[test]
|
||||||
fn enums_with_discriminants() {
|
fn enums_with_discriminants() {
|
||||||
size_and_align! {
|
size_and_align! {
|
||||||
|
@ -2023,6 +2023,7 @@ pub(crate) fn const_or_path_to_chalk(
|
|||||||
mode,
|
mode,
|
||||||
args,
|
args,
|
||||||
debruijn,
|
debruijn,
|
||||||
|
expected_ty.clone(),
|
||||||
)
|
)
|
||||||
.unwrap_or_else(|| unknown_const(expected_ty))
|
.unwrap_or_else(|| unknown_const(expected_ty))
|
||||||
}
|
}
|
||||||
|
@ -3529,14 +3529,30 @@ fn main() {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn issue_14275() {
|
fn issue_14275() {
|
||||||
// FIXME: evaluate const generic
|
|
||||||
check_types(
|
check_types(
|
||||||
r#"
|
r#"
|
||||||
struct Foo<const T: bool>;
|
struct Foo<const T: bool>;
|
||||||
fn main() {
|
fn main() {
|
||||||
const B: bool = false;
|
const B: bool = false;
|
||||||
let foo = Foo::<B>;
|
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…
x
Reference in New Issue
Block a user