-
Notifications
You must be signed in to change notification settings - Fork 183
Semantic equality to syntactic equality #401
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
Conversation
8d371a2
to
011cbd3
Compare
eea51d7
to
ccce5d0
Compare
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.
some old comments, perhaps no longer relevant
.intern(interner) | ||
}; | ||
|
||
self.clauses.push(syn_eq_lower(interner, &clause)); |
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.
One thing I was considering in doing this was making ClauseBuilder
generic over two Interner
values, one of which represented "Semantically equal" predicates and one of which represented "syntactically equal". This helps ensure we are not failing to do the conversion. I'm not sure how much value it really adds, though.
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.
Yeah, I thought about making syn_eq_lower
to return a SynLowered<Fold::Result>
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.
Not sure I follow -- what is SynLowered
, just a newtype?
@@ -735,6 +735,7 @@ impl<I: Interner> ToProgramClauses<I> for AssociatedTyDatum<I> { | |||
|
|||
// add new type parameter U | |||
builder.push_bound_ty(|builder, ty| { | |||
let alias = AliasTy::Projection(projection.clone()); |
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.
just a random refactoring?
Woah you can push to my branch |
@Areredify There is a checkbox "Allow edits and access to secrets by maintainers" both when opening a PR and when you opened it at the bottom of the sidebar. It is checked by default. |
clause: &ProgramClause<I>, | ||
outer_binder: DebruijnIndex, | ||
) -> Fallible<ProgramClause<I>> { | ||
let interner = self.interner; |
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 think we should either
- save the old values of
new_params
/new_goals
, and restore before we return - or assert that they are empty (if that is known to be true)
I don't see why they would be known to be empty, though, so I think we should save the values of the vector. The alternative would be to rewrite the code to not touch pre-existing things and just save the lengths.
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.
Probably we need to save binders_len
too
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.
We know them to be empty because only domain goals and program clauses contain types (and EqGoal, but it is unique), and when folding domain goals we are guaranteed to not encounter another goal or clause. If we restrict input types of syn_lower
to only be ProgramClause
and Goal
, then the lowering should be correct.
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.
ok, then add assertions -- I guess it's true that we only have to worry about domain goal, and it cannot contain clauses. Right. I was thinking about how goals can contain clauses in general (and vice versa, of course).
let ((binders, implication), in_binders) = match clause.data(interner) { | ||
ProgramClauseData::ForAll(for_all) => (for_all.clone().into(), true), | ||
// introduce a dummy binder and shift implication through it | ||
ProgramClauseData::Implies(implication) => ( |
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 keep meaning to factor away ProgramClauseData::Implies
, and just always have a binder.
}; | ||
let mut binders: Vec<_> = binders.as_slice(interner).clone().into(); | ||
|
||
let outer_binder = outer_binder.shifted_in(); |
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.
Comment:
// Adjust the outer binder to account for the binder in the program clause
|
||
let outer_binder = outer_binder.shifted_in(); | ||
|
||
self.binders_len = binders.len(); |
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.
Comment here, referencing the function comment:
// First lower the "consequence" -- in our example that is
//
// ```
// Implemented(<X as Iterator>::Item: Debug)
// ```
//
// then save out the `new_params` and `new_goals` vectors to store any new variables created as a result. In this case, that would be the `Y` parameter and `AliasEq(<X as Iterator>::Item, Y)` goals.
//
// Note that these new parameters will have indices that come after the existing parameters, so any references to existing parameters like `X` in the "conditions" are still valid even if we insert new parameters.
self.binders_len = binders.len(); | ||
let consequence = implication.consequence.fold_with(self, outer_binder)?; | ||
// Immediately move `new_params` out of of the folder struct so it's safe | ||
// to call `.fold_with` again |
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.
(then I think you can remove this comment, it's explained more usefully above)
|
||
let outer_binder = outer_binder.shifted_in(); | ||
|
||
self.binders_len = binders.len(); |
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.
Comment:
Set binders_len to binders.len
since new parameters will be added into the existing forall<...>
binder on the program clause.
|
||
struct SynEqFolder<'i, I: Interner> { | ||
interner: &'i I, | ||
new_params: Vec<ParameterKind<()>>, |
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.
comments on these fields -- what do they store?
My suggestions:
Store the kinds of any new parameters that are introduced during folding. These parameters will either be added to an enclosing exists
binder (when lowering a goal) or an enclosing forall
binder (when lowering a program clause).
struct SynEqFolder<'i, I: Interner> { | ||
interner: &'i I, | ||
new_params: Vec<ParameterKind<()>>, | ||
new_goals: Vec<Goal<I>>, |
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.
For each new parameter X
, introduces an AliasEq
goal that defines it, like AliasEq(<T as Iterator>::Item, X)
interner: &'i I, | ||
new_params: Vec<ParameterKind<()>>, | ||
new_goals: Vec<Goal<I>>, | ||
binders_len: usize, |
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.
Stores the number of variables in the binder that we are adding parameters into thus far. Incremented for each new variable we add.
TyData, | ||
}; | ||
|
||
pub fn syn_eq_lower<I: Interner, T: Fold<I>>(interner: &I, clause: &T) -> <T as Fold<I>>::Result { |
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.
Needs a comment. Also, I wonder if it's worth adding some other trait since you only really want to fold program clauses and goals here..? Nah, probably not, but we should add a comment about it.
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 think making it into syn_lower_clause
and syn_lower_goal
should be enough
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.
Yeah, two separate functions would be fine
Closing in favor of #589 |
No description provided.