-
Notifications
You must be signed in to change notification settings - Fork 1.5k
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
Rust: introduce typed labels #17460
Rust: introduce typed labels #17460
Conversation
668da07
to
a16aa31
Compare
a16aa31
to
faf1eee
Compare
args, | ||
ellipsis_index, | ||
}) | ||
self.trap |
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.
Can't we avoid all the into()
calls. They are a bit annoying to write and make things less type safe. Would it be possible to have the following type for trap.emit()
?
fn emit<T>(node: T) -> Label<T>
That way the type checker knows that emit(generated::TuplePat{})
returns a Label<generated::TuplePat>
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.
That's what's actually happening already (with T::Label
rather than Label<T>
because I encountered some problems with the latter). So emit
gives the very precise type. The problem is that then we need to convert that to a more generic label, for example from a TuplePat::Label
to a Pat::Label
, which from the TRAP point of view is perfectly valid. As rust abhors implicit conversions, in that case an into()
must be used.
However, that doesn't mean it's unsafe, as an into()
from X::Label
to Y::Label
will only compile if X
is a subclass of Y
.
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 see, it feels a bit more complicated then what I would do in Haskell, but it should indeed work ;-)
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'll still play around with it for a bit, maybe I'll get to do a more ergonomic Label<T>
. But in any case because it's Rust we won't get rid of the into()
s.
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.
Ah, I managed to get it into a much better spot, using Label<T>
(the problem was the missing PhantomData
and the wrong derived Clone
and Copy
). And, I ended up having an explicitly unsafe from_untyped
, which I think is pretty neat to prevent accidental use :). The clippy check also enforced a safety comment on unsafe blocks, which is also pretty cool
{{! virtual class, make it unbuildable }} | ||
#[derive(Debug)] | ||
pub struct {{name}} { | ||
_unused: () |
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.
Can't this just be pub struct {{name}} { }
?
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.
a pub struct X {}
can be built by a user (e.g. let x = X{}
), and I'd like to avoid that as we shouldn't be building instances of structs that are not leaves in the hierarchy. By adding one private field we disallow that.
This looks great, thanks! |
This introduces a generate
{{x}}TrapLabel
wrapper around untyped labels for each class in the schema (including class that are inherited from). Then all relevantFrom
traits are implemented so that.into()
can be used to do "casting" of labels, with the compiler checking that the cast is valid.Also, this adds automatic type-based prefixing of global trap keys.