-
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
Add binders validator #694
base: master
Are you sure you want to change the base?
Conversation
This is a visitor which checks that all bound vars refer to an existing binder of the right type. This has been quite useful for me: we somewhat regularly have errors in the binders which then cause a crash some time down the line when something tries to substitute them. At that point it's usually harder to find the actual place the error comes from; also you don't always hit the error. For the latest of these bugs, I added this validator, and immediately had failing tests that pointed me to the right location. The disadvantage is that I needed to add some rather specific methods to `Visitor`. I didn't find a better way to model this (and this is also the reason I couldn't just implement it in rust-analyzer).
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.
No objection, if it's useful.
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.
The only other thought I have is how useful it is to validate all bound vars in a "type" (or whatever we're checking), versus just checking for bound vars at the current level?
/// Invoked for each occurence of a `Binders`, before visiting them. | ||
fn before_binders(&mut self, _kinds: &crate::VariableKinds<I>) {} | ||
/// Invoked for each occurence of a `Canonical`, before visiting them. | ||
fn before_canonical(&mut self, _kinds: &crate::CanonicalVarKinds<I>) {} | ||
/// Invoked for each occurence of a `FnPointer`, before visiting them. | ||
fn before_fn_pointer_substs(&mut self, _number: usize) {} | ||
/// Invoked for each occurence of a type introducing binders, after visiting them. | ||
fn after_any_binders(&mut self) {} | ||
|
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 wonder if it's worth just adding a visit_binders
function like in rustc? (Probably) Is it all helpful to have these split out? I don't know if rustc calls visit_binder
for fn pointer substs or canonical items, but we should.
Unfortunately, I think that our visit_binders
would have to look like fn visit_binder<T: SuperVisit<I>>(&mut self, binders: crate::VariableKinds<I>, value: T) -> ControlFlow<Self::BreakTy>);
, but that's probably fine.
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.
Alternatively, we could just change this to only have before_binders
and do the "into VariableKinds
conversion" happen before calling 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 tried something like that first, the problem is that it makes the Visitor
trait not object safe.
We could do the before_binders
, but it'd mean doing the conversion in every visitor instead of just the one where it's necessary.
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.
Well, I mean, you only need to do the conversion in the Visit
impls, right?
I'd like to see the change/cleanup from my comment, but if that doesn't work out for whatever reason, I'm fine with the current state if things can't be cleaned up. So, r=me preferring the requested changes but either way I'm fine. |
Hmm. I guess it would actually be possible to validate bound vars in each |
☔ The latest upstream changes (presumably #735) made this pull request unmergeable. Please resolve the merge conflicts. |
This is a visitor which checks that all bound vars refer to an existing binder of the right type. This has been quite useful for me: we somewhat regularly have bugs in the Chalk transformation code (or now with the chalk_ir move earlier) where we don't shift the bound variables correctly, which then causes a crash some time down the line when something tries to substitute them. At that point it's usually harder to find the actual place the error comes from; also you don't always hit the error. For the latest of these bugs, I added this validator, and immediately had failing tests that pointed me to the right location.
The disadvantage is that I needed to add some rather specific methods to
Visitor
. I didn't find a better way to model this (and this is also the reason I couldn't just implement it in rust-analyzer).