Skip to content

Commit ff8b969

Browse files
committed
Auto merge of rust-lang#14727 - HKalbasi:mir, r=HKalbasi
Lazy evaluate consts in `path_to_const` fix rust-lang#14275
2 parents 833d530 + aafe9b1 commit ff8b969

File tree

6 files changed

+76
-17
lines changed

6 files changed

+76
-17
lines changed

crates/hir-ty/src/consteval.rs

+7-1
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub(crate) fn path_to_const(
7676
mode: ParamLoweringMode,
7777
args_lazy: impl FnOnce() -> Generics,
7878
debruijn: DebruijnIndex,
79+
expected_ty: Ty,
7980
) -> Option<Const> {
8081
match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
8182
Some(ValueNs::GenericParam(p)) => {
@@ -100,6 +101,10 @@ pub(crate) fn path_to_const(
100101
};
101102
Some(ConstData { ty, value }.intern(Interner))
102103
}
104+
Some(ValueNs::ConstId(c)) => Some(intern_const_scalar(
105+
ConstScalar::UnevaluatedConst(c.into(), Substitution::empty(Interner)),
106+
expected_ty,
107+
)),
103108
_ => None,
104109
}
105110
}
@@ -227,9 +232,10 @@ pub(crate) fn eval_to_const(
227232
debruijn: DebruijnIndex,
228233
) -> Const {
229234
let db = ctx.db;
235+
let infer = ctx.clone().resolve_all();
230236
if let Expr::Path(p) = &ctx.body.exprs[expr] {
231237
let resolver = &ctx.resolver;
232-
if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn) {
238+
if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) {
233239
return c;
234240
}
235241
}

crates/hir-ty/src/infer.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ use std::{convert::identity, ops::Index};
1717

1818
use chalk_ir::{
1919
cast::Cast, fold::TypeFoldable, interner::HasInterner, DebruijnIndex, Mutability, Safety,
20-
Scalar, TypeFlags,
20+
Scalar, TyKind, TypeFlags,
2121
};
2222
use either::Either;
2323
use hir_def::{
@@ -44,7 +44,7 @@ use crate::{
4444
db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
4545
static_lifetime, to_assoc_type_id, traits::FnTrait, AliasEq, AliasTy, ClosureId, DomainGoal,
4646
GenericArg, Goal, ImplTraitId, InEnvironment, Interner, ProjectionTy, RpitId, Substitution,
47-
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
47+
TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt,
4848
};
4949

5050
// 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
118118
/// This is appropriate to use only after type-check: it assumes
119119
/// that normalization will succeed, for example.
120120
pub(crate) fn normalize(db: &dyn HirDatabase, trait_env: Arc<TraitEnvironment>, ty: Ty) -> Ty {
121-
if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION) {
121+
// FIXME: TypeFlags::HAS_CT_PROJECTION is not implemented in chalk, so TypeFlags::HAS_PROJECTION only
122+
// works for the type case, so we check array unconditionally. Remove the array part
123+
// when the bug in chalk becomes fixed.
124+
if !ty.data(Interner).flags.intersects(TypeFlags::HAS_PROJECTION)
125+
&& !matches!(ty.kind(Interner), TyKind::Array(..))
126+
{
122127
return ty;
123128
}
124129
let mut table = unify::InferenceTable::new(db, trait_env);

crates/hir-ty/src/infer/unify.rs

+34-11
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,11 @@ use triomphe::Arc;
1515

1616
use super::{InferOk, InferResult, InferenceContext, TypeError};
1717
use crate::{
18-
db::HirDatabase, fold_tys, fold_tys_and_consts, static_lifetime, to_chalk_trait_id,
19-
traits::FnTrait, AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex,
20-
GenericArg, GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime,
21-
ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty,
22-
TyBuilder, TyExt, TyKind, VariableKind,
18+
db::HirDatabase, fold_tys_and_consts, static_lifetime, to_chalk_trait_id, traits::FnTrait,
19+
AliasEq, AliasTy, BoundVar, Canonical, Const, ConstValue, DebruijnIndex, GenericArg,
20+
GenericArgData, Goal, Guidance, InEnvironment, InferenceVar, Interner, Lifetime, ParamKind,
21+
ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution, TraitEnvironment, Ty, TyBuilder,
22+
TyExt, TyKind, VariableKind,
2323
};
2424

2525
impl<'a> InferenceContext<'a> {
@@ -236,13 +236,36 @@ impl<'a> InferenceTable<'a> {
236236
where
237237
T: HasInterner<Interner = Interner> + TypeFoldable<Interner>,
238238
{
239-
fold_tys(
239+
fold_tys_and_consts(
240240
ty,
241-
|ty, _| match ty.kind(Interner) {
242-
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
243-
self.normalize_projection_ty(proj_ty.clone())
244-
}
245-
_ => ty,
241+
|e, _| match e {
242+
Either::Left(ty) => Either::Left(match ty.kind(Interner) {
243+
TyKind::Alias(AliasTy::Projection(proj_ty)) => {
244+
self.normalize_projection_ty(proj_ty.clone())
245+
}
246+
_ => ty,
247+
}),
248+
Either::Right(c) => Either::Right(match &c.data(Interner).value {
249+
chalk_ir::ConstValue::Concrete(cc) => match &cc.interned {
250+
crate::ConstScalar::UnevaluatedConst(c_id, subst) => {
251+
// FIXME: Ideally here we should do everything that we do with type alias, i.e. adding a variable
252+
// and registering an obligation. But it needs chalk support, so we handle the most basic
253+
// case (a non associated const without generic parameters) manually.
254+
if subst.len(Interner) == 0 {
255+
if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
256+
{
257+
eval
258+
} else {
259+
c
260+
}
261+
} else {
262+
c
263+
}
264+
}
265+
_ => c,
266+
},
267+
_ => c,
268+
}),
246269
},
247270
DebruijnIndex::INNERMOST,
248271
)

crates/hir-ty/src/layout/tests.rs

+8
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,14 @@ fn niche_optimization() {
353353
}
354354
}
355355

356+
#[test]
357+
fn const_eval() {
358+
size_and_align! {
359+
const X: usize = 5;
360+
struct Goal([i32; X]);
361+
}
362+
}
363+
356364
#[test]
357365
fn enums_with_discriminants() {
358366
size_and_align! {

crates/hir-ty/src/lower.rs

+1
Original file line numberDiff line numberDiff line change
@@ -2023,6 +2023,7 @@ pub(crate) fn const_or_path_to_chalk(
20232023
mode,
20242024
args,
20252025
debruijn,
2026+
expected_ty.clone(),
20262027
)
20272028
.unwrap_or_else(|| unknown_const(expected_ty))
20282029
}

crates/hir-ty/src/tests/simple.rs

+18-2
Original file line numberDiff line numberDiff line change
@@ -3529,14 +3529,30 @@ fn main() {
35293529

35303530
#[test]
35313531
fn issue_14275() {
3532-
// FIXME: evaluate const generic
35333532
check_types(
35343533
r#"
35353534
struct Foo<const T: bool>;
35363535
fn main() {
35373536
const B: bool = false;
35383537
let foo = Foo::<B>;
3539-
//^^^ Foo<_>
3538+
//^^^ Foo<false>
3539+
}
3540+
"#,
3541+
);
3542+
check_types(
3543+
r#"
3544+
struct Foo<const T: bool>;
3545+
impl Foo<true> {
3546+
fn foo(self) -> u8 { 2 }
3547+
}
3548+
impl Foo<false> {
3549+
fn foo(self) -> u16 { 5 }
3550+
}
3551+
fn main() {
3552+
const B: bool = false;
3553+
let foo: Foo<B> = Foo;
3554+
let x = foo.foo();
3555+
//^ u16
35403556
}
35413557
"#,
35423558
);

0 commit comments

Comments
 (0)