@@ -27,7 +27,10 @@ use crate::Edition;
2727#[ cfg( feature = "salsa" ) ]
2828#[ derive( Copy , Clone , PartialEq , PartialOrd , Eq , Ord , Hash ) ]
2929pub struct SyntaxContext (
30- salsa:: Id ,
30+ /// # Invariant
31+ ///
32+ /// This is either a valid `salsa::Id` or a root `SyntaxContext`.
33+ u32 ,
3134 std:: marker:: PhantomData < & ' static salsa:: plumbing:: interned:: Value < SyntaxContext > > ,
3235) ;
3336
@@ -95,10 +98,11 @@ const _: () = {
9598 type Fields < ' a > = SyntaxContextData ;
9699 type Struct < ' a > = SyntaxContext ;
97100 fn struct_from_id < ' db > ( id : salsa:: Id ) -> Self :: Struct < ' db > {
98- SyntaxContext ( id , std :: marker :: PhantomData )
101+ SyntaxContext :: from_salsa_id ( id )
99102 }
100103 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`" )
102106 }
103107 }
104108 impl SyntaxContext {
@@ -115,12 +119,12 @@ const _: () = {
115119 }
116120 impl zalsa_:: AsId for SyntaxContext {
117121 fn as_id ( & self ) -> salsa:: Id {
118- self . 0
122+ self . as_salsa_id ( ) . expect ( "`SyntaxContext::as_id()` called on a root `SyntaxContext`" )
119123 }
120124 }
121125 impl zalsa_:: FromId for SyntaxContext {
122126 fn from_id ( id : salsa:: Id ) -> Self {
123- Self ( id , std :: marker :: PhantomData )
127+ Self :: from_salsa_id ( id )
124128 }
125129 }
126130 unsafe impl Send for SyntaxContext { }
@@ -210,90 +214,78 @@ const _: () = {
210214 where
211215 Db : ?Sized + zalsa_:: Database ,
212216 {
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
218220 }
219221
220222 pub fn outer_transparency < Db > ( self , db : & ' db Db ) -> Transparency
221223 where
222224 Db : ?Sized + zalsa_:: Database ,
223225 {
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
229229 }
230230
231231 pub fn edition < Db > ( self , db : & ' db Db ) -> Edition
232232 where
233233 Db : ?Sized + zalsa_:: Database ,
234234 {
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 ( ) ) ,
237241 }
238- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
239- std:: clone:: Clone :: clone ( & fields. edition )
240242 }
241243
242244 pub fn parent < Db > ( self , db : & ' db Db ) -> SyntaxContext
243245 where
244246 Db : ?Sized + zalsa_:: Database ,
245247 {
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 ,
248254 }
249- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
250- std:: clone:: Clone :: clone ( & fields. parent )
251255 }
252256
253257 /// This context, but with all transparent and semi-transparent expansions filtered away.
254258 pub fn opaque < Db > ( self , db : & ' db Db ) -> SyntaxContext
255259 where
256260 Db : ?Sized + zalsa_:: Database ,
257261 {
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 ,
260268 }
261- let fields = SyntaxContext :: ingredient ( db) . fields ( db. as_dyn_database ( ) , self ) ;
262- std:: clone:: Clone :: clone ( & fields. opaque )
263269 }
264270
265271 /// This context, but with all transparent expansions filtered away.
266272 pub fn opaque_and_semitransparent < Db > ( self , db : & ' db Db ) -> SyntaxContext
267273 where
268274 Db : ?Sized + zalsa_:: Database ,
269275 {
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 ,
272282 }
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- } )
292283 }
293284 }
294285} ;
295286
296287impl SyntaxContext {
288+ #[ inline]
297289 pub fn is_root ( self ) -> bool {
298290 ( SyntaxContext :: MAX_ID - Edition :: LATEST as u32 ) <= self . into_u32 ( )
299291 && self . into_u32 ( ) <= ( SyntaxContext :: MAX_ID - Edition :: Edition2015 as u32 )
@@ -307,22 +299,46 @@ impl SyntaxContext {
307299 }
308300
309301 /// The root context, which is the parent of all other contexts. All [`FileId`]s have this context.
302+ #[ inline]
310303 pub const fn root ( edition : Edition ) -> Self {
311304 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) }
313307 }
314308}
315309
316310#[ cfg( feature = "salsa" ) ]
317311impl SyntaxContext {
318312 const MAX_ID : u32 = salsa:: Id :: MAX_U32 - 1 ;
319313
314+ #[ inline]
320315 pub const fn into_u32 ( self ) -> u32 {
321- self . 0 . as_u32 ( )
316+ self . 0
322317 }
323318
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 ( ) ) }
326342 }
327343}
328344#[ cfg( not( feature = "salsa" ) ) ]
@@ -342,7 +358,10 @@ impl SyntaxContext {
342358 self . 0
343359 }
344360
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 {
346365 Self ( u32)
347366 }
348367}
0 commit comments