1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
use ;
/// The `OpVerifier` trait is expected to be implemented by all [crate::Op] impls as a prequisite.
///
/// The actual implementation is typically generated as part of deriving [crate::Op].
/// The `Verify` trait represents verification logic associated with implementations of some trait.
///
/// This is specifically used for automatically deriving verification checks for [crate::Op] impls
/// that implement traits that imply constraints on the representation or behavior of that op.
///
/// For example, if some [crate::Op] derives an op trait like `SingleBlock`, this information is
/// recorded in the underlying [crate::Operation] metadata, so that we can recover a trait object
/// reference for the trait when needed. However, just deriving the trait is not sufficient to
/// guarantee that the op actually adheres to the implicit constraints and behavior of that trait.
/// For example, `SingleBlock` implies that the implementing op contains only regions that consist
/// of a single [crate::Block]. This cannot be checked statically. The first step to addressing this
/// though, is to reify the implicit validation rules as explicit checks - hence this trait.
///
/// So we've established that some op traits, such as `SingleBlock` mentioned above, have implicit
/// validation rules, and we can implement [Verify] to make the implicit validation rules of such
/// traits explicit - but how do we ensure that when an op derives an op trait, that the [Verify]
/// impl is also derived, _and_ that it is called when the op is verified?
///
/// The answer lies in the use of some tricky type-level code to accomplish the following goals:
///
/// * Do not emit useless checks for op traits that have no verification rules
/// * Do not require storing data in each instance of an [crate::Op] just to verify a trait
/// * Do not require emitting a bunch of redundant type checks for information we know statically
/// * Be able to automatically derive all of the verification machinery along with the op traits
///
/// The way this works is as follows:
///
/// * We `impl<T> Verify<dyn Trait> for T where T: Op` for every trait `Trait` with validation rules.
/// * A blanket impl of [HasVerifier] exists for all `T: Verify<Trait>`. This is a marker trait used
/// in conjunction with specialization. See the trait docs for more details on its purpose.
/// * The [Verifier] trait provides a default vacuous impl for all `Trait` and `T` pairs. However,
/// we also provided a specialized [Verifier] impl for all `T: Verify<Trait>` using the
/// `HasVerifier` marker. The specialized impl applies the underlying `Verify` impl.
/// * When deriving the op traits for an `Op` impl, we generate a hidden type that encodes all of
/// the op traits implemented by the op. We then generate an `OpVerifier` impl for the op, which
/// uses the hidden type we generated to reify the `Verifier` impl for each trait. The
/// `OpVerifier` implementation uses const eval to strip out all of the vacuous verifier impls,
/// leaving behind just the "real" verification rules specific to the traits implemented by that
/// op.
/// * The `OpVerifier` impl is object-safe, and is in fact a required super-trait of `Op` to ensure
/// that verification is part of defining an `Op`, but also to ensure that `verify` is a method
/// of `Op`, and that we can cast an `Operation` to `&dyn OpVerifier` and call `verify` on that.
///
/// As a result of all this, we end up with highly-specialized verifiers for each op, with no
/// dynamic dispatch, and automatically maintained as part of the `Op` definition. When a new
/// op trait is derived, the verifier for the op is automatically updated to verify the new trait.
/// A marker trait used for verifier specialization.
///
/// # Safety
///
/// In order for the `#[rustc_unsafe_specialization_marker]` attribute to be used safely and
/// correctly, the following rules must hold:
///
/// * No associated items
/// * No impls with lifetime constraints, as specialization will ignore them
///
/// For our use case, which is specializing verification for a given type and trait combination,
/// by optimizing out verification-related code for type combinations which have no verifier, these
/// are easy rules to uphold.
///
/// However, we must ensure that we continue to uphold these rules moving forward.
pub unsafe
// While at first glance, it appears we would be using this to specialize on the fact that a type
// _has_ a verifier, which is strictly-speaking true, the actual goal we're aiming to acheive is
// to be able to identify the _absence_ of a verifier, so that we can eliminate the boilerplate for
// verifying that trait. See `Verifier` for more information.
unsafe
/// The `Verifier` trait is used to derive a verifier for a given trait and concrete type.
///
/// It does this by providing a default implementation for all combinations of `Trait` and `T`,
/// which always succeeds, and then specializing that implementation for `T: HasVerifier<Trait>`.
///
/// This has the effect of making all traits "verifiable", but only actually doing any verification
/// for types which implement `Verify<Trait>`.
///
/// We go a step further and actually set things up so that `rustc` can eliminate all of the dead
/// code when verification is vacuous. This is done by using const eval in the hidden type generated
/// for an [crate::Op] impls [OpVerifier] implementation, which will wrap verification in a
/// const-evaluated check of the `VACUOUS` associated const. It can also be used directly, but the
/// general idea behind all of this is that we don't need to directly touch any of this, it's all
/// generated.
///
/// NOTE: Because this trait provides a default blanket impl for all `T`, you should avoid bringing
/// it into scope unless absolutely needed. It is virtually always preferred to explicitly invoke
/// this trait using turbofish syntax, so as to avoid conflict with the [Verify] trait, and to
/// avoid polluting the namespace for all types in scope.
/// The default blanket impl for all types and traits
/// THe specialized impl for types which implement `Verify<Trait>`