-
Notifications
You must be signed in to change notification settings - Fork 181
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support const evaulation #596
Changes from 8 commits
eea70d6
58fb4ff
e0748ad
69623ba
b4684d0
f4cd784
f2ca1db
d767d7e
6a6a68f
3389719
bce9291
0b603f9
d4ee9a3
d05b66c
60da39c
1c38d7c
e048d93
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -12,3 +12,4 @@ chalk-parse/src/parser.rs | |
|
||
## IDE files | ||
/.idea/ | ||
/.vscode/ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -29,7 +29,7 @@ use tracing::{debug, instrument}; | |
// | ||
// From EWFS: | ||
// | ||
// Let G be an X-clause A :- D | L1,...Ln, where N > 0, and Li be selected atom. | ||
// Let G be an X-clause A :- D | L1,...Ln, where n > 0, and Li be selected atom. | ||
// | ||
// Let C be an X-clause with no delayed literals. Let | ||
// | ||
|
@@ -42,7 +42,7 @@ use tracing::{debug, instrument}; | |
// | ||
// Then: | ||
// | ||
// S(A :- D | L1...Li-1, L1'...L'm, Li+1...Ln) | ||
// S(A :- D | L1...Li-1, L'1...L'm, Li+1...Ln) | ||
// | ||
// is the SLG resolvent of G with C. | ||
|
||
|
@@ -507,14 +507,45 @@ impl<'i, I: Interner> Zipper<'i, I> for AnswerSubstitutor<'i, I> { | |
Ok(()) | ||
} | ||
|
||
(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)), | ||
|
||
Err(ConstEvalError::TooGeneric) => panic!( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Similarly here...feels like we should have already have caught this before and the answer itself (or the goal) shouldn't have unevaluated consts. (Well...maybe the goal would?) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Turns out that unevaluated const expressions can appear in the answer and the goal in the resolvent if we so much as write |
||
"structural mismatch between answer `{:?}` and pending goal `{:?}`", | ||
answer, pending, | ||
), | ||
} | ||
Ok(()) | ||
} | ||
|
||
(ConstValue::Unevaluated(u1), ConstValue::Unevaluated(u2)) => { | ||
match ( | ||
u1.try_eval(answer_ty, interner), | ||
u2.try_eval(answer_ty, interner), | ||
) { | ||
(Ok(c1), Ok(c2)) => assert!(c1.const_eq(answer_ty, &c2, interner)), | ||
|
||
(Err(ConstEvalError::TooGeneric), _) | (_, Err(ConstEvalError::TooGeneric)) => { | ||
panic!( | ||
"structural mismatch between answer `{:?}` and pending goal `{:?}`", | ||
answer, pending, | ||
) | ||
} | ||
} | ||
Ok(()) | ||
} | ||
|
||
(ConstValue::InferenceVar(_), _) | (_, ConstValue::InferenceVar(_)) => panic!( | ||
"unexpected inference var in answer `{:?}` or pending goal `{:?}`", | ||
answer, pending, | ||
), | ||
|
||
(ConstValue::BoundVar(_), _) | ||
| (ConstValue::Placeholder(_), _) | ||
| (ConstValue::Concrete(_), _) => panic!( | ||
| (ConstValue::Concrete(_), _) | ||
| (ConstValue::Unevaluated(_), _) => panic!( | ||
"structural mismatch between answer `{:?}` and pending goal `{:?}`", | ||
answer, pending, | ||
), | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -33,7 +33,7 @@ use crate::Ty; | |
use crate::TyData; | ||
use crate::VariableKind; | ||
use crate::VariableKinds; | ||
use crate::{Const, ConstData}; | ||
use crate::{Const, ConstData, ConstEvalError}; | ||
use std::fmt::{self, Debug}; | ||
use std::hash::Hash; | ||
use std::marker::PhantomData; | ||
|
@@ -93,6 +93,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { | |
/// evaluated consts. | ||
type InternedConcreteConst: Debug + Clone + Eq + Hash; | ||
|
||
/// "Interned" representation of an unevaluated const expression. In normal user code, | ||
/// `Self::InternedUnevaluatedConst` is not referenced. Instead, | ||
/// we refer to `UnevaluatedConst<Self>`, which wraps this type. | ||
/// | ||
/// `InternedUnevaluatedConst` instances are not created by chalk, | ||
/// it can only evaluate them with the [`try_eval_const`] method | ||
/// and check for (syntactic for now) equality between them. | ||
type InternedUnevaluatedConst: Debug + Clone + Eq + Hash; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we anticipate that this will carry a "substitutions"? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I expect not, right? |
||
|
||
/// "Interned" representation of a "generic parameter", which can | ||
/// be either a type or a lifetime. In normal user code, | ||
/// `Self::InternedGenericArg` is not referenced. Instead, we refer to | ||
|
@@ -456,14 +465,21 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { | |
/// Lookup the `ConstData` that was interned to create a `InternedConst`. | ||
fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a ConstData<Self>; | ||
|
||
/// Deterermine whether two concrete const values are equal. | ||
/// Determine whether two concrete const values are equal. | ||
fn const_eq( | ||
&self, | ||
ty: &Self::InternedType, | ||
c1: &Self::InternedConcreteConst, | ||
c2: &Self::InternedConcreteConst, | ||
) -> 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>; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kind of expect this to take a set of substitutions. Consider how the rustc variant looks. |
||
|
||
/// Create an "interned" parameter from `data`. This is not | ||
/// normally invoked directly; instead, you invoke | ||
/// `GenericArgData::intern` (which will ultimately call this | ||
|
@@ -634,6 +650,12 @@ pub trait TargetInterner<I: Interner>: Interner { | |
const_evaluated: &I::InternedConcreteConst, | ||
) -> Self::InternedConcreteConst; | ||
|
||
/// Transfer unevaluated constant expressions to the target interner. | ||
fn transfer_unevaluated_const( | ||
&self, | ||
const_unevaluated: &I::InternedUnevaluatedConst, | ||
) -> Self::InternedUnevaluatedConst; | ||
|
||
/// Transfer function ABI to the target interner. | ||
fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi; | ||
} | ||
|
@@ -666,6 +688,13 @@ impl<I: Interner> TargetInterner<I> for I { | |
const_evaluated.clone() | ||
} | ||
|
||
fn transfer_unevaluated_const( | ||
&self, | ||
const_unevaluated: &I::InternedUnevaluatedConst, | ||
) -> Self::InternedUnevaluatedConst { | ||
const_unevaluated.clone() | ||
} | ||
|
||
fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi { | ||
abi | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Initial thought: Will we ever actually give an answer with an
Unevaluated
const?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't see why not. Chalk can return associated type projections in answers, and an unevalutated const is basically a projection.