@@ -27,7 +27,10 @@ use crate::Edition;
27
27
#[ cfg( feature = "salsa" ) ]
28
28
#[ derive( Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
29
29
pub struct SyntaxContext (
30
- salsa:: Id ,
30
+ /// # Invariant
31
+ ///
32
+ /// This is either a valid `salsa::Id` or a root `SyntaxContext`.
33
+ u32 ,
31
34
std:: marker:: PhantomData < & ' static salsa:: plumbing:: interned:: Value < SyntaxContext > > ,
32
35
) ;
33
36
@@ -95,10 +98,11 @@ const _: () = {
95
98
type Fields < ' a > = SyntaxContextData ;
96
99
type Struct < ' a > = SyntaxContext ;
97
100
fn struct_from_id < ' db > ( id : salsa:: Id ) -> Self :: Struct < ' db > {
98
- SyntaxContext ( id , std :: marker :: PhantomData )
101
+ SyntaxContext :: from_salsa_id ( id )
99
102
}
100
103
fn deref_struct ( s : Self :: Struct < ' _ > ) -> salsa:: Id {
101
- s. 0
104
+ s. as_salsa_id ( )
105
+ . expect ( "`SyntaxContext::deref_structs()` called on a root `SyntaxContext`" )
102
106
}
103
107
}
104
108
impl SyntaxContext {
@@ -115,12 +119,12 @@ const _: () = {
115
119
}
116
120
impl zalsa_:: AsId for SyntaxContext {
117
121
fn as_id ( & self ) -> salsa:: Id {
118
- self . 0
122
+ self . as_salsa_id ( ) . expect ( "`SyntaxContext::as_id()` called on a root `SyntaxContext`" )
119
123
}
120
124
}
121
125
impl zalsa_:: FromId for SyntaxContext {
122
126
fn from_id ( id : salsa:: Id ) -> Self {
123
- Self ( id , std :: marker :: PhantomData )
127
+ Self :: from_salsa_id ( id )
124
128
}
125
129
}
126
130
unsafe impl Send for SyntaxContext { }
@@ -210,90 +214,78 @@ const _: () = {
210
214
where
211
215
Db : ?Sized + zalsa_:: Database ,
212
216
{
213
- if self . is_root ( ) {
214
- return None ;
215
- }
216
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
217
- std:: clone:: Clone :: clone ( & fields. outer_expn )
217
+ let id = self . as_salsa_id ( ) ?;
218
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
219
+ fields. outer_expn
218
220
}
219
221
220
222
pub fn outer_transparency < Db > ( self , db : & ' db Db ) -> Transparency
221
223
where
222
224
Db : ?Sized + zalsa_:: Database ,
223
225
{
224
- if self . is_root ( ) {
225
- return Transparency :: Opaque ;
226
- }
227
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
228
- std:: clone:: Clone :: clone ( & fields. outer_transparency )
226
+ let Some ( id) = self . as_salsa_id ( ) else { return Transparency :: Opaque } ;
227
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
228
+ fields. outer_transparency
229
229
}
230
230
231
231
pub fn edition < Db > ( self , db : & ' db Db ) -> Edition
232
232
where
233
233
Db : ?Sized + zalsa_:: Database ,
234
234
{
235
- if self . is_root ( ) {
236
- return Edition :: from_u32 ( SyntaxContext :: MAX_ID - self . 0 . as_u32 ( ) ) ;
235
+ match self . as_salsa_id ( ) {
236
+ Some ( id) => {
237
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
238
+ fields. edition
239
+ }
240
+ None => Edition :: from_u32 ( SyntaxContext :: MAX_ID - self . into_u32 ( ) ) ,
237
241
}
238
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
239
- std:: clone:: Clone :: clone ( & fields. edition )
240
242
}
241
243
242
244
pub fn parent < Db > ( self , db : & ' db Db ) -> SyntaxContext
243
245
where
244
246
Db : ?Sized + zalsa_:: Database ,
245
247
{
246
- if self . is_root ( ) {
247
- return self ;
248
+ match self . as_salsa_id ( ) {
249
+ Some ( id) => {
250
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
251
+ fields. parent
252
+ }
253
+ None => self ,
248
254
}
249
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
250
- std:: clone:: Clone :: clone ( & fields. parent )
251
255
}
252
256
253
257
/// This context, but with all transparent and semi-transparent expansions filtered away.
254
258
pub fn opaque < Db > ( self , db : & ' db Db ) -> SyntaxContext
255
259
where
256
260
Db : ?Sized + zalsa_:: Database ,
257
261
{
258
- if self . is_root ( ) {
259
- return self ;
262
+ match self . as_salsa_id ( ) {
263
+ Some ( id) => {
264
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
265
+ fields. opaque
266
+ }
267
+ None => self ,
260
268
}
261
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
262
- std:: clone:: Clone :: clone ( & fields. opaque )
263
269
}
264
270
265
271
/// This context, but with all transparent expansions filtered away.
266
272
pub fn opaque_and_semitransparent < Db > ( self , db : & ' db Db ) -> SyntaxContext
267
273
where
268
274
Db : ?Sized + zalsa_:: Database ,
269
275
{
270
- if self . is_root ( ) {
271
- return self ;
276
+ match self . as_salsa_id ( ) {
277
+ Some ( id) => {
278
+ let fields = SyntaxContext :: ingredient ( db) . data ( db. as_dyn_database ( ) , id) ;
279
+ fields. opaque_and_semitransparent
280
+ }
281
+ None => self ,
272
282
}
273
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
274
- std:: clone:: Clone :: clone ( & fields. opaque_and_semitransparent )
275
- }
276
-
277
- pub fn default_debug_fmt ( this : Self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
278
- salsa:: with_attached_database ( |db| {
279
- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , this) ;
280
- let mut f = f. debug_struct ( "SyntaxContextData" ) ;
281
- let f = f. field ( "outer_expn" , & fields. outer_expn ) ;
282
- let f = f. field ( "outer_transparency" , & fields. outer_expn ) ;
283
- let f = f. field ( "edition" , & fields. edition ) ;
284
- let f = f. field ( "parent" , & fields. parent ) ;
285
- let f = f. field ( "opaque" , & fields. opaque ) ;
286
- let f = f. field ( "opaque_and_semitransparent" , & fields. opaque_and_semitransparent ) ;
287
- f. finish ( )
288
- } )
289
- . unwrap_or_else ( || {
290
- f. debug_tuple ( "SyntaxContextData" ) . field ( & zalsa_:: AsId :: as_id ( & this) ) . finish ( )
291
- } )
292
283
}
293
284
}
294
285
} ;
295
286
296
287
impl SyntaxContext {
288
+ #[ inline]
297
289
pub fn is_root ( self ) -> bool {
298
290
( SyntaxContext :: MAX_ID - Edition :: LATEST as u32 ) <= self . into_u32 ( )
299
291
&& self . into_u32 ( ) <= ( SyntaxContext :: MAX_ID - Edition :: Edition2015 as u32 )
@@ -307,22 +299,46 @@ impl SyntaxContext {
307
299
}
308
300
309
301
/// The root context, which is the parent of all other contexts. All [`FileId`]s have this context.
302
+ #[ inline]
310
303
pub const fn root ( edition : Edition ) -> Self {
311
304
let edition = edition as u32 ;
312
- SyntaxContext :: from_u32 ( SyntaxContext :: MAX_ID - edition)
305
+ // SAFETY: Roots are valid `SyntaxContext`s
306
+ unsafe { SyntaxContext :: from_u32 ( SyntaxContext :: MAX_ID - edition) }
313
307
}
314
308
}
315
309
316
310
#[ cfg( feature = "salsa" ) ]
317
311
impl SyntaxContext {
318
312
const MAX_ID : u32 = salsa:: Id :: MAX_U32 - 1 ;
319
313
314
+ #[ inline]
320
315
pub const fn into_u32 ( self ) -> u32 {
321
- self . 0 . as_u32 ( )
316
+ self . 0
322
317
}
323
318
324
- pub const fn from_u32 ( u32 : u32 ) -> Self {
325
- Self ( salsa:: Id :: from_u32 ( u32) , std:: marker:: PhantomData )
319
+ /// # Safety
320
+ ///
321
+ /// The ID must be a valid `SyntaxContext`.
322
+ #[ inline]
323
+ pub const unsafe fn from_u32 ( u32 : u32 ) -> Self {
324
+ // INVARIANT: Our precondition.
325
+ Self ( u32, std:: marker:: PhantomData )
326
+ }
327
+
328
+ #[ inline]
329
+ fn as_salsa_id ( self ) -> Option < salsa:: Id > {
330
+ if self . is_root ( ) {
331
+ None
332
+ } else {
333
+ // SAFETY: By our invariant, this is either a root (which we verified it's not) or a valid `salsa::Id`.
334
+ unsafe { Some ( salsa:: Id :: from_u32 ( self . 0 ) ) }
335
+ }
336
+ }
337
+
338
+ #[ inline]
339
+ fn from_salsa_id ( id : salsa:: Id ) -> Self {
340
+ // SAFETY: This comes from a Salsa ID.
341
+ unsafe { Self :: from_u32 ( id. as_u32 ( ) ) }
326
342
}
327
343
}
328
344
#[ cfg( not( feature = "salsa" ) ) ]
@@ -342,7 +358,10 @@ impl SyntaxContext {
342
358
self . 0
343
359
}
344
360
345
- pub const fn from_u32 ( u32 : u32 ) -> Self {
361
+ /// # Safety
362
+ ///
363
+ /// None. This is always safe to call without the `salsa` feature.
364
+ pub const unsafe fn from_u32 ( u32 : u32 ) -> Self {
346
365
Self ( u32)
347
366
}
348
367
}
0 commit comments