Skip to content

Commit

Permalink
Code formatting and unevaluated const formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
hayashi-stl committed Aug 19, 2020
1 parent 58fb4ff commit e0748ad
Show file tree
Hide file tree
Showing 12 changed files with 114 additions and 60 deletions.
9 changes: 6 additions & 3 deletions chalk-engine/src/slg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -495,8 +495,8 @@ impl<I: Interner> MayInvalidate<'_, I> {
!c1.const_eq(new_ty, c2, interner)
}

(ConstValue::Concrete(c), ConstValue::Unevaluated(u)) |
(ConstValue::Unevaluated(u), ConstValue::Concrete(c)) => {
(ConstValue::Concrete(c), ConstValue::Unevaluated(u))
| (ConstValue::Unevaluated(u), ConstValue::Concrete(c)) => {
if let Ok(ev) = u.try_eval(new_ty, interner) {
!c.const_eq(new_ty, &ev, interner)
} else {
Expand All @@ -507,7 +507,10 @@ impl<I: Interner> MayInvalidate<'_, I> {
(ConstValue::Unevaluated(u1), ConstValue::Unevaluated(u2)) => {
if u1.const_eq(new_ty, u2, interner) {
false
} else if let (Ok(c1), Ok(c2)) = (u1.try_eval(new_ty, interner), u2.try_eval(current_ty, interner)) {
} else if let (Ok(c1), Ok(c2)) = (
u1.try_eval(new_ty, interner),
u2.try_eval(current_ty, interner),
) {
!c1.const_eq(new_ty, &c2, interner)
} else {
true
Expand Down
20 changes: 15 additions & 5 deletions chalk-engine/src/slg/aggregate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -483,15 +483,19 @@ impl<I: Interner> AntiUnifier<'_, '_, I> {
}
}

(ConstValue::Concrete(e), ConstValue::Unevaluated(u)) |
(ConstValue::Unevaluated(u), ConstValue::Concrete(e)) => {
(ConstValue::Concrete(e), ConstValue::Unevaluated(u))
| (ConstValue::Unevaluated(u), ConstValue::Concrete(e)) => {
let ev = match u.try_eval(&ty, interner) {
Ok(ev) => ev,
Err(_) => return self.new_const_variable(ty),
};

if e.const_eq(&ty, &ev, interner) {
ConstData { ty: ty.clone(), value: ConstValue::Concrete(ev) }.intern(interner)
ConstData {
ty: ty.clone(),
value: ConstValue::Concrete(ev),
}
.intern(interner)
} else {
self.new_const_variable(ty)
}
Expand All @@ -500,9 +504,15 @@ impl<I: Interner> AntiUnifier<'_, '_, I> {
(ConstValue::Unevaluated(u1), ConstValue::Unevaluated(u2)) => {
if u1.const_eq(&ty, u2, interner) {
c1.clone()
} else if let (Ok(e1), Ok(e2)) = (u1.try_eval(&ty, interner), u2.try_eval(&ty, interner)) {
} else if let (Ok(e1), Ok(e2)) =
(u1.try_eval(&ty, interner), u2.try_eval(&ty, interner))
{
if e1.const_eq(&ty, &e2, interner) {
ConstData { ty: ty.clone(), value: ConstValue::Concrete(e1) }.intern(interner)
ConstData {
ty: ty.clone(),
value: ConstValue::Concrete(e1),
}
.intern(interner)
} else {
self.new_const_variable(ty)
}
Expand Down
12 changes: 8 additions & 4 deletions chalk-engine/src/slg/resolvent.rs
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,8 @@ impl<'i, I: Interner> Zipper<'i, I> for AnswerSubstitutor<'i, I> {
Ok(())
}

(ConstValue::Concrete(c), ConstValue::Unevaluated(u)) |
(ConstValue::Unevaluated(u), ConstValue::Concrete(c)) => {
(ConstValue::Concrete(c), ConstValue::Unevaluated(u))
| (ConstValue::Unevaluated(u), ConstValue::Concrete(c)) => {
match u.try_eval(answer_ty, interner) {
Ok(ev) => assert!(c.const_eq(answer_ty, &ev, interner)),

Expand All @@ -524,13 +524,17 @@ impl<'i, I: Interner> Zipper<'i, I> for AnswerSubstitutor<'i, I> {
if u1.const_eq(answer_ty, u2, interner) {
Ok(())
} else {
match (u1.try_eval(answer_ty, interner), u2.try_eval(answer_ty, interner)) {
match (
u1.try_eval(answer_ty, interner),
u2.try_eval(answer_ty, interner),
) {
(Ok(ev1), Ok(ev2)) => {
assert!(ev1.const_eq(answer_ty, &ev2, interner));
Ok(())
}

(Err(ConstEvalError::TooGeneric), _) | (_, Err(ConstEvalError::TooGeneric)) => panic!(
(Err(ConstEvalError::TooGeneric), _)
| (_, Err(ConstEvalError::TooGeneric)) => panic!(
"structural mismatch between answer `{:?}` and pending goal `{:?}`",
answer, pending,
),
Expand Down
22 changes: 13 additions & 9 deletions chalk-integration/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@ use crate::tls;
use chalk_ir::interner::{HasInterner, Interner};
use chalk_ir::{
AdtId, AliasTy, ApplicationTy, AssocTypeId, CanonicalVarKind, CanonicalVarKinds, ConstData,
Constraint, FnDefId, Goals, InEnvironment, Lifetime, OpaqueTy, OpaqueTyId,
ConstEvalError, Constraint, FnDefId, Goals, InEnvironment, Lifetime, OpaqueTy, OpaqueTyId,
ProgramClauseImplication, ProgramClauses, ProjectionTy, QuantifiedWhereClauses,
SeparatorTraitRef, Substitution, TraitId, Ty, VariableKind, VariableKinds,
ConstEvalError
SeparatorTraitRef, Substitution, TraitId, Ty, UnevaluatedConstData, VariableKind,
VariableKinds,
};
use chalk_ir::{
GenericArg, GenericArgData, Goal, GoalData, LifetimeData, ProgramClause, ProgramClauseData,
Expand Down Expand Up @@ -45,7 +45,7 @@ impl Interner for ChalkIr {
type InternedLifetime = LifetimeData<ChalkIr>;
type InternedConst = Arc<ConstData<ChalkIr>>;
type InternedConcreteConst = u32;
type InternedUnevaluatedConst = Option<u32>;
type InternedUnevaluatedConst = UnevaluatedConstData;
type InternedGenericArg = GenericArgData<ChalkIr>;
type InternedGoal = Arc<GoalData<ChalkIr>>;
type InternedGoals = Vec<Goal<ChalkIr>>;
Expand Down Expand Up @@ -245,15 +245,19 @@ impl Interner for ChalkIr {
fn unevaluated_const_eq(
&self,
_ty: &Arc<TyData<ChalkIr>>,
c1: &Option<u32>,
c2: &Option<u32>,
c1: &UnevaluatedConstData,
c2: &UnevaluatedConstData,
) -> bool {
c1 == c2
}

fn try_eval_const(&self, _ty: &Arc<TyData<ChalkIr>>, constant: &Option<u32>) -> Result<u32, ConstEvalError> {
match constant {
Some(c) => Ok(*c),
fn try_eval_const(
&self,
_ty: &Arc<TyData<ChalkIr>>,
constant: &UnevaluatedConstData,
) -> Result<u32, ConstEvalError> {
match constant.0 {
Some(c) => Ok(c),
None => Err(ConstEvalError::TooGeneric),
}
}
Expand Down
9 changes: 6 additions & 3 deletions chalk-integration/src/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1763,7 +1763,7 @@ impl LowerConst for Const {
})
.map(|c| c.clone())
}

Const::Value(value) => Ok(chalk_ir::ConstData {
ty: get_type_of_u32(),
value: chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: *value }),
Expand All @@ -1772,8 +1772,11 @@ impl LowerConst for Const {

Const::Unevaluated(unev) => Ok(chalk_ir::ConstData {
ty: get_type_of_u32(),
value: chalk_ir::ConstValue::Unevaluated(chalk_ir::UnevaluatedConst { interned: *unev }),
}.intern(interner)),
value: chalk_ir::ConstValue::Unevaluated(chalk_ir::UnevaluatedConst {
interned: chalk_ir::UnevaluatedConstData(*unev),
}),
}
.intern(interner)),
}
}
}
Expand Down
11 changes: 7 additions & 4 deletions chalk-ir/src/fold.rs
Original file line number Diff line number Diff line change
Expand Up @@ -550,13 +550,16 @@ where
}),
}
.intern(folder.target_interner())),

ConstValue::Unevaluated(unev) => Ok(ConstData {
ty: fold_ty()?,
value: ConstValue::Unevaluated(UnevaluatedConst {
interned: folder.target_interner().transfer_unevaluated_const(&unev.interned),
})
}.intern(folder.target_interner())),
interned: folder
.target_interner()
.transfer_unevaluated_const(&unev.interned),
}),
}
.intern(folder.target_interner())),
}
}
}
Expand Down
6 changes: 5 additions & 1 deletion chalk-ir/src/interner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -482,7 +482,11 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash {
) -> bool;

/// Attempt to evaluate a const to a concrete const.
fn try_eval_const(&self, ty: &Self::InternedType, constant: &Self::InternedUnevaluatedConst) -> Result<Self::InternedConcreteConst, ConstEvalError>;
fn try_eval_const(
&self,
ty: &Self::InternedType,
constant: &Self::InternedUnevaluatedConst,
) -> Result<Self::InternedConcreteConst, ConstEvalError>;

/// Create an "interned" parameter from `data`. This is not
/// normally invoked directly; instead, you invoke
Expand Down
41 changes: 33 additions & 8 deletions chalk-ir/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ use crate::fold::shift::Shift;
use crate::fold::{Fold, Folder, Subst, SuperFold};
use crate::visit::{SuperVisit, Visit, VisitExt, VisitResult, Visitor};
use chalk_derive::{Fold, HasInterner, SuperVisit, Visit, Zip};
use std::fmt::Debug;
use std::marker::PhantomData;

pub use crate::debug::SeparatorTraitRef;
Expand Down Expand Up @@ -929,7 +930,8 @@ impl<I: Interner> Const<I> {
ConstValue::InferenceVar(_) => false,
ConstValue::Placeholder(_) => false,
ConstValue::Concrete(_) => false,
ConstValue::Unevaluated(_) => todo!("needs_shift for ConstValue::Unevaluated"),
// We assume for now that an unevaluated const expression doesn't contain bound vars
ConstValue::Unevaluated(_) => false,
}
}

Expand All @@ -954,11 +956,13 @@ impl<I: Interner> ConstData<I> {
/// This is guaranteed to return a concrete constant or an error.
pub fn try_eval(&self, interner: &I) -> Result<ConstData<I>, ConstEvalError> {
match &self.value {
ConstValue::BoundVar(_) | ConstValue::InferenceVar(_) | ConstValue::Placeholder(_) => Err(ConstEvalError::TooGeneric),
ConstValue::BoundVar(_) | ConstValue::InferenceVar(_) | ConstValue::Placeholder(_) => {
Err(ConstEvalError::TooGeneric)
}
ConstValue::Concrete(_) => Ok(self.clone()),
ConstValue::Unevaluated(expr) => Ok(ConstData {
ty: self.ty.clone(),
value: ConstValue::Concrete(expr.try_eval(&self.ty, interner)?)
value: ConstValue::Concrete(expr.try_eval(&self.ty, interner)?),
}),
}
}
Expand All @@ -976,13 +980,16 @@ pub enum ConstValue<I: Interner> {
/// Concrete constant value.
Concrete(ConcreteConst<I>),
/// Unevaluated constant expression.
/// We assume for now that this does not contain inference vars or bound vars.
Unevaluated(UnevaluatedConst<I>),
}

impl<I: Interner> Copy for ConstValue<I>
impl<I: Interner> Copy for ConstValue<I>
where
I::InternedConcreteConst: Copy,
I::InternedUnevaluatedConst: Copy, {}
I::InternedUnevaluatedConst: Copy,
{
}

impl<I: Interner> ConstData<I> {
/// Wraps the constant data in a `Const`.
Expand Down Expand Up @@ -1016,7 +1023,9 @@ pub struct UnevaluatedConst<I: Interner> {
impl<I: Interner> UnevaluatedConst<I> {
/// Attempts to evaluate the const expression.
pub fn try_eval(&self, ty: &Ty<I>, interner: &I) -> Result<ConcreteConst<I>, ConstEvalError> {
Ok(ConcreteConst {interned: interner.try_eval_const(&ty.interned, &self.interned)?})
Ok(ConcreteConst {
interned: interner.try_eval_const(&ty.interned, &self.interned)?,
})
}

/// Checks whether two unevaluated constants are equal.
Expand All @@ -1025,6 +1034,22 @@ impl<I: Interner> UnevaluatedConst<I> {
}
}

/// A mock unevaluated const expression.
/// `Some(n)` evaluates to `n`,
/// and `None` evaluates to a specific but unknown constant.
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub struct UnevaluatedConstData(pub Option<u32>);

impl Debug for UnevaluatedConstData {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self.0 {
Some(n) => write!(fmt, "{}?", n)?,
None => write!(fmt, "?")?,
}
Ok(())
}
}

/// An error that can occur when evaluating a const expression.
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum ConstEvalError {
Expand All @@ -1035,9 +1060,9 @@ pub enum ConstEvalError {
impl std::error::Error for ConstEvalError {}

impl std::fmt::Display for ConstEvalError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> {
match self {
ConstEvalError::TooGeneric => write!(f, "Const expression was too generic"),
ConstEvalError::TooGeneric => write!(fmt, "Const expression was too generic"),
}
}
}
Expand Down
23 changes: 5 additions & 18 deletions chalk-solve/src/infer/unify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,33 +417,20 @@ impl<'t, I: Interner> Unifier<'t, I> {

// Unifying an inference variable with a non-inference variable.
(&ConstValue::InferenceVar(var), &ConstValue::Concrete(_))
| (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) => {
| (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_))
// Note that we assume that the unevaluated const doesn't contain inference variables
| (&ConstValue::InferenceVar(var), &ConstValue::Unevaluated(_)) => {
debug!(?var, ty=?b, "unify_var_const");
self.unify_var_const(var, b)
}

(&ConstValue::Concrete(_), &ConstValue::InferenceVar(var))
| (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) => {
| (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var))
| (&ConstValue::Unevaluated(_), &ConstValue::InferenceVar(var)) => {
debug!(?var, ty=?a, "unify_var_const");
self.unify_var_const(var, a)
}

// It is important not to unify an inference variable with just any
// unevaluated const expression because the expression could contain
// a copy of the inference variable.
// In particular, ?X should not unify with ?X + 1
(&ConstValue::InferenceVar(var), &ConstValue::Unevaluated(_)) => {
let c = b.try_eval(interner).map_err(|_| NoSolution)?;
debug!(?var, ty=?c, "unify_var_const");
self.unify_var_const(var, &c)
}

(&ConstValue::Unevaluated(_), &ConstValue::InferenceVar(var)) => {
let c = a.try_eval(interner).map_err(|_| NoSolution)?;
debug!(?var, ty=?c, "unify_var_const");
self.unify_var_const(var, &c)
}

(&ConstValue::Placeholder(p1), &ConstValue::Placeholder(p2)) => {
Zip::zip_with(self, &p1, &p2)
}
Expand Down
1 change: 0 additions & 1 deletion tests/display/const_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -75,4 +75,3 @@ fn test_basic_const_values_in_assoc_ty_values() {
}
);
}

18 changes: 15 additions & 3 deletions tests/test/coherence.rs
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,18 @@ fn orphan_check() {
}
}

#[test]
fn unevaluated_const_unknown() {
lowering_success! {
program {
trait Foo<const N> {}
struct Baz {}

impl Foo<?> for Baz {}
}
}
}

#[test]
fn unevaluated_const_no_intersect() {
lowering_success! {
Expand All @@ -526,7 +538,7 @@ fn unevaluated_const_no_intersect() {

impl Foo<3> for Baz {}
impl Foo<2?> for Baz {}
}
}
}

lowering_success! {
Expand All @@ -536,7 +548,7 @@ fn unevaluated_const_no_intersect() {

impl Foo<3?> for Baz {}
impl Foo<2?> for Baz {}
}
}
}
}

Expand Down Expand Up @@ -586,7 +598,7 @@ fn unevaluated_const_too_generic() {
trait Foo<const N> { }
struct Baz { }

impl Foo<?> for Baz {}
impl Foo<3?> for Baz {}
impl Foo<?> for Baz {}
} error_msg {
"overlapping impls of trait `Foo`"
Expand Down
2 changes: 1 addition & 1 deletion tests/test/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ fn unevaluated_impl() {
S<N>: Trait
}
} yields {
"Unique; substitution [?0 := 3], lifetime constraints []"
"Unique; substitution [?0 := 3?], lifetime constraints []"
}

goal {
Expand Down

0 comments on commit e0748ad

Please sign in to comment.