@@ -192,7 +192,9 @@ public bool TryCreateWalker(int version, int walkerDepthLimit, out IDependencyCh
192192 return false ;
193193 }
194194
195- if ( ! TryCreateWalkingGraph ( vertices , version , out var walkingGraph ) ) {
195+ var depths = CalculateDepths ( vertices ) ;
196+
197+ if ( ! TryCreateWalkingGraph ( vertices , depths , version , out var walkingGraph ) ) {
196198 walker = default ;
197199 return false ;
198200 }
@@ -202,7 +204,14 @@ public bool TryCreateWalker(int version, int walkerDepthLimit, out IDependencyCh
202204 return false ;
203205 }
204206
205- if ( ! TryResolveLoops ( walkingGraph , loopsCount , version , out var startingVertices , out var totalNodesCount ) ) {
207+ if ( ! TryResolveLoops ( walkingGraph , loopsCount , version , out var totalNodesCount ) ) {
208+ walker = default ;
209+ return false ;
210+ }
211+
212+ // Iterate original graph to get starting vertices
213+ var startingVertices = walkingGraph . Where ( v => v . IncomingCount == 0 ) ;
214+ if ( ! TryFindMissingDependencies ( vertices , walkingGraph , version ) ) {
206215 walker = default ;
207216 return false ;
208217 }
@@ -212,27 +221,27 @@ public bool TryCreateWalker(int version, int walkerDepthLimit, out IDependencyCh
212221 vertex . SecondPass ? . Seal ( ) ;
213222 }
214223
215- var depths = CalculateDepths ( vertices ) ;
224+ var affectedValues = walkingGraph . Select ( v => v . DependencyVertex . Value ) ;
225+ var missingKeys = ImmutableArray < TKey > . Empty ;
226+
216227 lock ( _syncObj ) {
217228 if ( version != _version ) {
218229 walker = default ;
219230 return false ;
220231 }
221-
222- var affectedValues = walkingGraph . Select ( v => v . DependencyVertex . Value ) ;
223- var missingKeys = ImmutableArray < TKey > . Empty ;
232+
224233 foreach ( var ( key , index ) in _keys ) {
225- if ( _vertices [ index ] == default /* && depths[index] <= walkerDepthLimit*/ ) {
234+ if ( vertices [ index ] == default /* && depths[index] <= walkerDepthLimit*/ ) {
226235 missingKeys = missingKeys . Add ( key ) ;
227236 }
228237 }
229-
230- walker = new DependencyChainWalker ( startingVertices , affectedValues , depths , missingKeys , totalNodesCount , version ) ;
231- return true ;
232238 }
239+
240+ walker = new DependencyChainWalker ( startingVertices , affectedValues , depths , missingKeys , totalNodesCount , version ) ;
241+ return true ;
233242 }
234243
235- private bool TryBuildReverseGraph ( ImmutableArray < DependencyVertex < TKey , TValue > > vertices , int version ) {
244+ private bool TryBuildReverseGraph ( in ImmutableArray < DependencyVertex < TKey , TValue > > vertices , int version ) {
236245 var reverseGraphIsBuilt = true ;
237246 foreach ( var vertex in vertices ) {
238247 if ( vertex != null && ! vertex . IsSealed ) {
@@ -283,12 +292,17 @@ private bool TryBuildReverseGraph(ImmutableArray<DependencyVertex<TKey, TValue>>
283292 }
284293 }
285294
286- private bool TryCreateWalkingGraph ( in ImmutableArray < DependencyVertex < TKey , TValue > > vertices , int version , out ImmutableArray < WalkingVertex < TKey , TValue > > analysisGraph ) {
295+ private bool TryCreateWalkingGraph ( in ImmutableArray < DependencyVertex < TKey , TValue > > vertices , ImmutableArray < int > depths , int version , out ImmutableArray < WalkingVertex < TKey , TValue > > analysisGraph ) {
296+ if ( version != _version ) {
297+ analysisGraph = default ;
298+ return false ;
299+ }
300+
287301 var nodesByVertexIndex = new Dictionary < int , WalkingVertex < TKey , TValue > > ( ) ;
288302
289303 for ( var index = 0 ; index < vertices . Count ; index ++ ) {
290304 var vertex = vertices [ index ] ;
291- if ( vertex == null || vertex . IsWalked ) {
305+ if ( vertex == null || vertex . IsWalked || depths [ index ] == - 1 ) {
292306 continue ;
293307 }
294308
@@ -332,7 +346,7 @@ private bool TryCreateWalkingGraph(in ImmutableArray<DependencyVertex<TKey, TVal
332346 private static ImmutableArray < int > CalculateDepths ( in ImmutableArray < DependencyVertex < TKey , TValue > > vertices ) {
333347 var depths = new int [ vertices . Count ] ;
334348 for ( var i = 0 ; i < depths . Length ; i ++ ) {
335- depths [ i ] = - 1 ;
349+ depths [ i ] = - 1 ; // Unreachable vertices will be marked as -1
336350 }
337351
338352 for ( var i = 0 ; i < depths . Length ; i ++ ) {
@@ -342,19 +356,11 @@ private static ImmutableArray<int> CalculateDepths(in ImmutableArray<DependencyV
342356 SetDepths ( depths , vertices , vertex . Incoming , 1 ) ;
343357 }
344358 }
345-
346- for ( var i = 0 ; i < depths . Length ; i ++ ) {
347- var vertex = vertices [ i ] ;
348- if ( vertex != null && depths [ i ] == - 1 ) {
349- depths [ i ] = 1 ;
350- SetDepths ( depths , vertices , vertex . Incoming , 2 ) ;
351- }
352- }
353-
359+
354360 return ImmutableArray < int > . Create ( depths ) ;
355361 }
356362
357- private static void SetDepths ( int [ ] depths , ImmutableArray < DependencyVertex < TKey , TValue > > vertices , ImmutableArray < int > indices , int depth ) {
363+ private static void SetDepths ( in int [ ] depths , in ImmutableArray < DependencyVertex < TKey , TValue > > vertices , in ImmutableArray < int > indices , int depth ) {
358364 foreach ( var index in indices ) {
359365 if ( depths [ index ] != - 1 && depths [ index ] <= depth ) {
360366 continue ;
@@ -432,7 +438,12 @@ private static bool SetLoopNumber(WalkingVertex<TKey, TValue> vertex, Stack<Walk
432438 return false ;
433439 }
434440
435- private bool TryResolveLoops ( ImmutableArray < WalkingVertex < TKey , TValue > > graph , int loopsCount , int version , out ImmutableArray < WalkingVertex < TKey , TValue > > startingVertices , out int totalNodesCount ) {
441+ private bool TryResolveLoops ( in ImmutableArray < WalkingVertex < TKey , TValue > > graph , int loopsCount , int version , out int totalNodesCount ) {
442+ if ( loopsCount == 0 ) {
443+ totalNodesCount = graph . Count ;
444+ return true ;
445+ }
446+
436447 // Create vertices for second pass
437448 var inLoopsCount = 0 ;
438449 var secondPassLoops = new List < WalkingVertex < TKey , TValue > > [ loopsCount ] ;
@@ -450,7 +461,6 @@ private bool TryResolveLoops(ImmutableArray<WalkingVertex<TKey, TValue>> graph,
450461 }
451462
452463 if ( version != _version ) {
453- startingVertices = default ;
454464 totalNodesCount = default ;
455465 return false ;
456466 }
@@ -471,7 +481,6 @@ private bool TryResolveLoops(ImmutableArray<WalkingVertex<TKey, TValue>> graph,
471481 }
472482
473483 if ( version != _version ) {
474- startingVertices = default ;
475484 totalNodesCount = default ;
476485 return false ;
477486 }
@@ -505,18 +514,14 @@ private bool TryResolveLoops(ImmutableArray<WalkingVertex<TKey, TValue>> graph,
505514 }
506515
507516 if ( version != _version ) {
508- startingVertices = default ;
509517 totalNodesCount = default ;
510518 return false ;
511519 }
512520
513521 loopsCount ++ ;
514522 }
515523
516- // Iterate original graph to get starting vertices
517- startingVertices = graph . Where ( v => v . IncomingCount == 0 ) ;
518524 totalNodesCount = graph . Count + inLoopsCount ;
519-
520525 return true ;
521526 }
522527
@@ -536,6 +541,50 @@ private static void RemoveOutgoingLoopEdges(WalkingVertex<TKey, TValue> vertex,
536541 }
537542 }
538543
544+ private bool TryFindMissingDependencies ( in ImmutableArray < DependencyVertex < TKey , TValue > > vertices , in ImmutableArray < WalkingVertex < TKey , TValue > > walkingGraph , int version ) {
545+ var haveMissingDependencies = new bool [ vertices . Count ] ;
546+ var queue = new Queue < DependencyVertex < TKey , TValue > > ( ) ;
547+
548+ foreach ( var vertex in vertices ) {
549+ if ( vertex == default ) {
550+ continue ;
551+ }
552+
553+ foreach ( var incoming in vertex . Incoming ) {
554+ if ( vertices [ incoming ] == default ) {
555+ haveMissingDependencies [ vertex . Index ] = true ;
556+ queue . Enqueue ( vertex ) ;
557+ break ;
558+ }
559+ }
560+ }
561+
562+ while ( queue . Count > 0 ) {
563+ if ( version != _version ) {
564+ return false ;
565+ }
566+
567+ var vertex = queue . Dequeue ( ) ;
568+ foreach ( var outgoing in vertex . Outgoing ) {
569+ if ( haveMissingDependencies [ outgoing ] ) {
570+ continue ; // This vertex has been visited
571+ }
572+
573+ haveMissingDependencies [ outgoing ] = true ;
574+ queue . Enqueue ( vertices [ outgoing ] ) ;
575+ }
576+ }
577+
578+ foreach ( var walkingVertex in walkingGraph ) {
579+ if ( haveMissingDependencies [ walkingVertex . DependencyVertex . Index ] ) {
580+ walkingVertex . MarkHasMissingDependencies ( ) ;
581+ walkingVertex . SecondPass ? . MarkHasMissingDependencies ( ) ;
582+ }
583+ }
584+
585+ return true ;
586+ }
587+
539588 private sealed class DependencyChainWalker : IDependencyChainWalker < TKey , TValue > {
540589 private readonly ImmutableArray < WalkingVertex < TKey , TValue > > _startingVertices ;
541590 private readonly ImmutableArray < int > _depths ;
@@ -630,6 +679,7 @@ private sealed class DependencyChainNode : IDependencyChainNode<TValue> {
630679 private readonly WalkingVertex < TKey , TValue > _vertex ;
631680 private DependencyChainWalker _walker ;
632681 public TValue Value => _vertex . DependencyVertex . Value ;
682+ public bool HasMissingDependencies => _vertex . HasMissingDependencies ;
633683 public int VertexDepth { get ; }
634684
635685 public DependencyChainNode ( DependencyChainWalker walker , WalkingVertex < TKey , TValue > vertex , int depth ) {
0 commit comments