Auto merge of #14913 - HKalbasi:fix14844, r=HKalbasi

Evaluate `UnevalutedConst` before trait solving

cc #14844
This commit is contained in:
bors 2023-05-26 21:01:20 +00:00
commit 1b5523a8cd
4 changed files with 80 additions and 14 deletions

View File

@ -15,11 +15,11 @@ use triomphe::Arc;
use super::{InferOk, InferResult, InferenceContext, TypeError};
use crate::{
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,
consteval::unknown_const, 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> {
@ -256,10 +256,10 @@ impl<'a> InferenceTable<'a> {
{
eval
} else {
c
unknown_const(c.data(Interner).ty.clone())
}
} else {
c
unknown_const(c.data(Interner).ty.clone())
}
}
_ => c,

View File

@ -1912,3 +1912,26 @@ fn main() {
"#,
);
}
#[test]
fn regression_14844_2() {
check_no_mismatches(
r#"
//- minicore: fn
pub const ONE: usize = 1;
pub type MyInner = Inner<ONE>;
pub struct Inner<const P: usize>();
impl Inner<1> {
fn map<F>(&self, func: F) -> bool
where
F: Fn(&MyInner) -> bool,
{
func(self)
}
}
"#,
);
}

View File

@ -2,7 +2,7 @@
use std::env::var;
use chalk_ir::GoalData;
use chalk_ir::{fold::TypeFoldable, DebruijnIndex, GoalData};
use chalk_recursive::Cache;
use chalk_solve::{logging_db::LoggingRustIrDatabase, rust_ir, Solver};
@ -16,9 +16,9 @@ use stdx::panic_context;
use triomphe::Arc;
use crate::{
db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
Guidance, InEnvironment, Interner, ProjectionTy, ProjectionTyExt, Solution, TraitRefExt, Ty,
TyKind, WhereClause,
db::HirDatabase, infer::unify::InferenceTable, utils::UnevaluatedConstEvaluatorFolder, AliasEq,
AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment, Interner, ProjectionTy,
ProjectionTyExt, Solution, TraitRefExt, Ty, TyKind, WhereClause,
};
/// This controls how much 'time' we give the Chalk solver before giving up.
@ -106,6 +106,12 @@ pub(crate) fn trait_solve_query(
}
}
// Chalk see `UnevaluatedConst` as a unique concrete value, but we see it as an alias for another const. So
// we should get rid of it when talking to chalk.
let goal = goal
.try_fold_with(&mut UnevaluatedConstEvaluatorFolder { db }, DebruijnIndex::INNERMOST)
.unwrap();
// We currently don't deal with universes (I think / hope they're not yet
// relevant for our use cases?)
let u_canonical = chalk_ir::UCanonical { canonical: goal, universes: 1 };

View File

@ -4,7 +4,11 @@
use std::iter;
use base_db::CrateId;
use chalk_ir::{cast::Cast, fold::Shift, BoundVar, DebruijnIndex, Mutability};
use chalk_ir::{
cast::Cast,
fold::{FallibleTypeFolder, Shift},
BoundVar, DebruijnIndex, Mutability,
};
use either::Either;
use hir_def::{
db::DefDatabase,
@ -26,8 +30,8 @@ use smallvec::{smallvec, SmallVec};
use stdx::never;
use crate::{
db::HirDatabase, ChalkTraitId, GenericArg, Interner, Substitution, TraitRef, TraitRefExt, Ty,
TyExt, WhereClause,
consteval::unknown_const, db::HirDatabase, ChalkTraitId, Const, ConstScalar, GenericArg,
Interner, Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
};
pub(crate) fn fn_traits(
@ -403,3 +407,36 @@ pub(crate) fn pattern_matching_dereference_count(
}
r
}
pub(crate) struct UnevaluatedConstEvaluatorFolder<'a> {
pub(crate) db: &'a dyn HirDatabase,
}
impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
type Error = ();
fn as_dyn(&mut self) -> &mut dyn FallibleTypeFolder<Interner, Error = ()> {
self
}
fn interner(&self) -> Interner {
Interner
}
fn try_fold_const(
&mut self,
constant: Const,
_outer_binder: DebruijnIndex,
) -> Result<Const, Self::Error> {
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
return Ok(eval);
} else {
return Ok(unknown_const(constant.data(Interner).ty.clone()));
}
}
}
Ok(constant)
}
}