Conversation
|
r? @oli-obk (rust_highfive has picked a reviewer for you, use r? to override) |
|
The job Click to expand the log.I'm a bot! I can only do what humans tell me to, so if this was not helpful or you have suggestions for improvements, please ping or otherwise contact |
|
Wtf, this compiled fine in stage 2... NLL bug or so? |
oli-obk
left a comment
There was a problem hiding this comment.
Preliminary review. I think reviewing the rest only makes sense with the review questions addressed
There was a problem hiding this comment.
I dislike the self mutation. It does not feel right. I think these downcast functions should be recursing via visit_value.
There was a problem hiding this comment.
downcast_dyn_trait is gone in a later commit.
For downcast_enum I will do this, but it actually makes the interface larger overall (i.e., one more method to implement).
There was a problem hiding this comment.
Oh and then there is an extra hook I need to keep the nice error reporting... of the validity check :/
There was a problem hiding this comment.
Okay I did something. Thanks for making me do it, it is now better than it was before. :) Let me know what you think.
There was a problem hiding this comment.
I am aware this is a bad error message. Fixing this will be fairly easy once #55293 lands: Use ScalarMaybeUndef in EvalErrorKind::InvalidDiscriminant.
oli-obk
left a comment
There was a problem hiding this comment.
oh damn, I never pressed the submit review button :/
Anyway, yes, this is getting closer to what I'm imagining.
Take the comments with a grain of salt, because I've not checked how obsolete they have become with your changes
There was a problem hiding this comment.
What do you mean by replace? changing a function argument does not persist outside the function call.
I would have assumed this to just forward to visit_value by default, ignoring all the other arguments.
There was a problem hiding this comment.
The visitor has in its internal state the current value we are visiting. This function makes it change that state to another value.
I know this is a somewhat strange architecture for a visitor, but it's the best I could come up with so far in terms of code reuse. But the original design also did not have the Value trait; now that I got that maybe I can separate the value from the rest of the visitor state. However, I actually found it quite nice that they are connected because the ValidationVisitor uses that to keep track of its stack.
There was a problem hiding this comment.
So I think I fundamentally misunderstood the nature of this visitor. I thought it was like the visitor for Mir, which just gives you mutable references to rustc::mir::* types and by default calls walk_*, which destructures the value and calls visit_* on all the values obtainable.
I am not sure what this "visitor" is doing anymore. Would it be possible to write a visitor of the following form, still support your use cases and still copy/allocate as little intermediate state as possible?
trait ValueVisitor<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>>: fmt::Debug + Sized {
type V: Value<'tcx, M>;
fn ecx(&mut self) -> &mut EvalContext<'a, 'mir, 'tcx, M>)
fn visit(&mut self, value: &mut V) -> EvalResult<'tcx> {
walk_value(self, value)
}
fn visit_array(&mut self, elements: impl Iterator<Item = &mut V>) -> EvalResult<'tcx> {
walk_array(self, elements)
}
fn visit_enum(&mut self, value: &mut Value) -> EvalResutl<'tcx> {
walk_enum(self, value)
}
// leafs
fn visit_scalar(&mut self, _scalar: &mut Scalar, _layout: &layout::Scalar) -> EvalResult<'tcx> { Ok(()) }
// ...
}
fn walk_value....
fn walk_array<VIS: ValueVisitor>(visitor: &mut VIS, elements: impl Iterator<Item = &mut VIS::V>) -> EvalResult<'tcx> {
for element in elements {
visitor.visit(element)?;
}
Ok(())
}
fn walk_enum<VIS: ValueVisitor>(visitor: &mut VIS, value: &mut VIS::V) -> EvalResult<'tcx> {
let variant = value.read_discriminant(self.ecx())?.1;
visitor.visit(value.downcast(self.ecx(), variant)?)
}This will increase the amount of recursion happening, but it has a much nicer feel to me, because fewer things are entangled with each other.
|
☔ The latest upstream changes (presumably #55579) made this pull request unmergeable. Please resolve the merge conflicts. |
oli-obk
left a comment
There was a problem hiding this comment.
The visitor as it is (except for the visit_scalar method as mentioned in the comments) looks good to me now. I'll review the rest of the code independently now
There was a problem hiding this comment.
| /// Visit the given value as a union. | |
| /// Visit the given value as a union. Does not recurse unless overwritten to do so. |
There was a problem hiding this comment.
how can an uninhabited type have fields?
There was a problem hiding this comment.
I think the default impl should be calling a walk_scalar method then. Pass all arguments needed to recurse. Implementing a visit_* function as Ok(()) should stop recursion right there.
There was a problem hiding this comment.
That does not match the structure we used for the validation visitor, and I think it is the wrong structure. The point is that being a scalar and being an aggregate are orthogonal properties, a value can be neither or both or any combination. Some scalars are primitives, some are not - -we'd have to duplicate all the primitive-vs-aggregate handling. I don't think that would be a good idea.
There was a problem hiding this comment.
Oh right. Add a comment that it's not really recursing into the scalar, but the value, so one should overwrite visit_value if they want to not recurse into this case
e27a04e to
bebf782
Compare
|
I added the iterator-based |
|
My plan is to ask for perf once #55316 lands, so that we can see just the impact of this refactor. |
09e4551 to
7f93557
Compare
|
Rebased onto master; now this PR can stand for itself. |
|
@bors try |
Value visitors for miri Generalize the traversal part of validation to a `ValueVisitor`. ~~This includes #55316, [click here](RalfJung/rust@retagging...RalfJung:miri-visitor) for just the new commits.~~ This PR does not change the interface to miri, so I use the opportunity to update miri.
|
☀️ Test successful - status-travis |
|
@rust-timer build 5f8bd0a |
|
Success: Queued 5f8bd0a with parent e53a5ff, comparison URL. |
| ScalarMaybeUndef::Scalar(Scalar::Bits { bits, .. }) => | ||
| bits.to_string(), | ||
| struct ValidityVisitor<'rt, 'a: 'rt, 'mir: 'rt, 'tcx: 'a+'rt+'mir, M: Machine<'a, 'mir, 'tcx>+'rt> { | ||
| /// The `path` may be pushed to, but the part that is present when a function |
There was a problem hiding this comment.
we really need to start using the im crate in the compiler
This comment has been minimized.
This comment has been minimized.
|
Finished benchmarking try commit 5f8bd0a |
|
Seems like something went wrong? There is no benchmark data. Cc @rust-lang/infra Maybe we should just try again. |
|
⌛ Trying commit 3538532cb617bcb6c97e304459c2135a5e2240b9 with merge ad5b1b390d95a7a68786df120aefae5118043810... |
|
@RalfJung the parent commit e53a5ff is still being benchmarked (see https://perf.rust-lang.org/status.html). There's no need to retry. |
|
Oh, so the bot was just wrong telling me that everything is done? Curious. |
|
☀️ Test successful - status-travis |
|
Some small losses, some small gains... @oli-obk seems acceptable? |
3538532 to
7b7c6ce
Compare
|
@bors r+ |
|
📌 Commit 7b7c6ce has been approved by |
Value visitors for miri Generalize the traversal part of validation to a `ValueVisitor`. ~~This includes #55316, [click here](RalfJung/rust@retagging...RalfJung:miri-visitor) for just the new commits.~~
|
☀️ Test successful - status-appveyor, status-travis |
Add escape-to-raw MIR statement Add a new MIR "ghost state statement": Escaping a ptr to permit raw accesses. ~~This includes #55549, [click here](RalfJung/rust@miri-visitor...RalfJung:escape-to-raw) for just the new commits.~~
Generalize the traversal part of validation to a
ValueVisitor.This includes #55316, click here for just the new commits.