-
Notifications
You must be signed in to change notification settings - Fork 183
Add binders validator #694
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
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).