@@ -37,8 +37,7 @@ use rustc_hir::def_id::DefId;
3737use rustc_index:: bit_set:: { BitSet , HybridBitSet } ;
3838use rustc_index:: vec:: Idx ;
3939use rustc_middle:: mir:: { self , BasicBlock , Location } ;
40- use rustc_middle:: ty:: { self , TyCtxt } ;
41- use rustc_target:: abi:: VariantIdx ;
40+ use rustc_middle:: ty:: TyCtxt ;
4241
4342mod cursor;
4443mod direction;
@@ -152,6 +151,8 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
152151 ) {
153152 }
154153
154+ /* Edge-specific effects */
155+
155156 /// Updates the current dataflow state with the effect of a successful return from a `Call`
156157 /// terminator.
157158 ///
@@ -183,20 +184,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> {
183184 /// Updates the current dataflow state with the effect of taking a particular branch in a
184185 /// `SwitchInt` terminator.
185186 ///
186- /// Much like `apply_call_return_effect`, this effect is only propagated along a single
187- /// outgoing edge from this basic block.
187+ /// Unlike the other edge-specific effects, which are allowed to mutate `Self::Domain`
188+ /// directly, overriders of this method must pass a callback to
189+ /// [`SwitchIntEdgeEffects::apply`]. The callback will be run once for each outgoing edge and
190+ /// will have access to the dataflow state that will be propagated along that edge.
191+ ///
192+ /// This interface is somewhat more complex than the other visitor-like "effect" methods.
193+ /// However, it is both more ergonomic—callers don't need to recompute or cache information
194+ /// about a given `SwitchInt` terminator for each one of its edges—and more efficient—the
195+ /// engine doesn't need to clone the exit state for a block unless
196+ /// `SwitchIntEdgeEffects::apply` is actually called.
188197 ///
189198 /// FIXME: This class of effects is not supported for backward dataflow analyses.
190- fn apply_discriminant_switch_effect (
199+ fn apply_switch_int_edge_effects (
191200 & self ,
192- _state : & mut Self :: Domain ,
193201 _block : BasicBlock ,
194- _enum_place : mir:: Place < ' tcx > ,
195- _adt : & ty:: AdtDef ,
196- _variant : VariantIdx ,
202+ _discr : & mir:: Operand < ' tcx > ,
203+ _apply_edge_effects : & mut impl SwitchIntEdgeEffects < Self :: Domain > ,
197204 ) {
198205 }
199206
207+ /* Extension methods */
208+
200209 /// Creates an `Engine` to find the fixpoint for this dataflow problem.
201210 ///
202211 /// You shouldn't need to override this outside this module, since the combination of the
@@ -267,6 +276,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
267276 ) {
268277 }
269278
279+ /* Edge-specific effects */
280+
270281 /// See `Analysis::apply_call_return_effect`.
271282 fn call_return_effect (
272283 & self ,
@@ -286,14 +297,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> {
286297 ) {
287298 }
288299
289- /// See `Analysis::apply_discriminant_switch_effect `.
290- fn discriminant_switch_effect (
300+ /// See `Analysis::apply_switch_int_edge_effects `.
301+ fn switch_int_edge_effects < G : GenKill < Self :: Idx > > (
291302 & self ,
292- _state : & mut impl GenKill < Self :: Idx > ,
293303 _block : BasicBlock ,
294- _enum_place : mir:: Place < ' tcx > ,
295- _adt : & ty:: AdtDef ,
296- _variant : VariantIdx ,
304+ _discr : & mir:: Operand < ' tcx > ,
305+ _edge_effects : & mut impl SwitchIntEdgeEffects < G > ,
297306 ) {
298307 }
299308}
@@ -339,6 +348,8 @@ where
339348 self . before_terminator_effect ( state, terminator, location) ;
340349 }
341350
351+ /* Edge-specific effects */
352+
342353 fn apply_call_return_effect (
343354 & self ,
344355 state : & mut A :: Domain ,
@@ -359,17 +370,17 @@ where
359370 self . yield_resume_effect ( state, resume_block, resume_place) ;
360371 }
361372
362- fn apply_discriminant_switch_effect (
373+ fn apply_switch_int_edge_effects (
363374 & self ,
364- state : & mut A :: Domain ,
365375 block : BasicBlock ,
366- enum_place : mir:: Place < ' tcx > ,
367- adt : & ty:: AdtDef ,
368- variant : VariantIdx ,
376+ discr : & mir:: Operand < ' tcx > ,
377+ edge_effects : & mut impl SwitchIntEdgeEffects < A :: Domain > ,
369378 ) {
370- self . discriminant_switch_effect ( state , block, enum_place , adt , variant ) ;
379+ self . switch_int_edge_effects ( block, discr , edge_effects ) ;
371380 }
372381
382+ /* Extension methods */
383+
373384 fn into_engine (
374385 self ,
375386 tcx : TyCtxt < ' tcx > ,
@@ -531,5 +542,17 @@ impl EffectIndex {
531542 }
532543}
533544
545+ pub struct SwitchIntTarget {
546+ pub value : Option < u128 > ,
547+ pub target : BasicBlock ,
548+ }
549+
550+ /// A type that records the edge-specific effects for a `SwitchInt` terminator.
551+ pub trait SwitchIntEdgeEffects < D > {
552+ /// Calls `apply_edge_effect` for each outgoing edge from a `SwitchInt` terminator and
553+ /// records the results.
554+ fn apply ( & mut self , apply_edge_effect : impl FnMut ( & mut D , SwitchIntTarget ) ) ;
555+ }
556+
534557#[ cfg( test) ]
535558mod tests;
0 commit comments