3333//!
3434//! [concatenate]: struct.PartialPath.html#method.concatenate
3535
36- use std:: collections:: VecDeque ;
3736use std:: convert:: TryFrom ;
3837use std:: fmt:: Display ;
3938use std:: num:: NonZeroU32 ;
@@ -46,21 +45,14 @@ use smallvec::SmallVec;
4645use crate :: arena:: Deque ;
4746use crate :: arena:: DequeArena ;
4847use crate :: arena:: Handle ;
49- use crate :: cycles:: Appendables ;
50- use crate :: cycles:: AppendingCycleDetector ;
5148use crate :: graph:: Edge ;
52- use crate :: graph:: File ;
5349use crate :: graph:: Node ;
5450use crate :: graph:: NodeID ;
5551use crate :: graph:: StackGraph ;
5652use crate :: graph:: Symbol ;
57- use crate :: paths:: Extend ;
5853use crate :: paths:: PathResolutionError ;
59- use crate :: stitching:: GraphEdges ;
6054use crate :: utils:: cmp_option;
6155use crate :: utils:: equals_option;
62- use crate :: CancellationError ;
63- use crate :: CancellationFlag ;
6456
6557//-------------------------------------------------------------------------------------------------
6658// Displaying stuff
@@ -2232,54 +2224,6 @@ impl PartialPath {
22322224
22332225 Ok ( ( ) )
22342226 }
2235-
2236- /// Attempts to extend one partial path as part of the partial-path-finding algorithm. If a file
2237- /// is provided, only outgoing edges that belong to that file are used. When calling this function,
2238- /// you are responsible for ensuring that `graph` already contains data for all of the possible edges
2239- /// that we might want to extend `path` with.
2240- ///
2241- /// The resulting extended partial paths will be added to `result`. We have you pass that in
2242- /// as a parameter, instead of building it up ourselves, so that you have control over which
2243- /// particular collection type to use, and so that you can reuse result collections across
2244- /// multiple calls.
2245- fn extend < R : Extend < ( PartialPath , AppendingCycleDetector < Edge > ) > > (
2246- & self ,
2247- graph : & StackGraph ,
2248- partials : & mut PartialPaths ,
2249- file : Option < Handle < File > > ,
2250- edges : & mut Appendables < Edge > ,
2251- path_cycle_detector : AppendingCycleDetector < Edge > ,
2252- result : & mut R ,
2253- ) {
2254- let extensions = graph. outgoing_edges ( self . end_node ) ;
2255- result. reserve ( extensions. size_hint ( ) . 0 ) ;
2256- for extension in extensions {
2257- copious_debugging ! (
2258- " -> with edge {} -> {}" ,
2259- extension. source. display( graph) ,
2260- extension. sink. display( graph)
2261- ) ;
2262- if let Some ( file) = file {
2263- if !graph[ extension. sink ] . is_in_file ( file) {
2264- copious_debugging ! ( " * outside file" ) ;
2265- continue ;
2266- }
2267- }
2268- let mut new_path = self . clone ( ) ;
2269- // If there are errors adding this edge to the partial path, or resolving the resulting
2270- // partial path, just skip the edge — it's not a fatal error.
2271- if new_path. append ( graph, partials, extension) . is_err ( ) {
2272- copious_debugging ! ( " * invalid extension" ) ;
2273- continue ;
2274- }
2275- // We assume languages do not introduce similar paths (paths between the same nodes with
2276- // equivalent pre- and postconditions), so we do not guard against that here. We may need
2277- // to revisit that assumption in the future.
2278- let mut new_cycle_detector = path_cycle_detector. clone ( ) ;
2279- new_cycle_detector. append ( edges, extension) ;
2280- result. push ( ( new_path, new_cycle_detector) ) ;
2281- }
2282- }
22832227}
22842228
22852229impl Node {
@@ -2513,142 +2457,6 @@ impl Node {
25132457 }
25142458}
25152459
2516- impl PartialPaths {
2517- /// Finds a minimal set of partial paths in a file, calling the `visit` closure for each one.
2518- ///
2519- /// This function ensures that the set of visited partial paths
2520- /// (a) is minimal, no path can be constructed by stitching other paths in the set, and
2521- /// (b) covers all complete paths, from references to definitions, when used for path stitching
2522- ///
2523- /// This function will not return until all reachable partial paths have been processed, so
2524- /// `graph` must already contain a complete stack graph. If you have a very large stack graph
2525- /// stored in some other storage system, and want more control over lazily loading only the
2526- /// necessary pieces, then you should code up your own loop that calls
2527- /// [`PartialPath::extend`][] manually.
2528- ///
2529- /// Caveat: Edges between nodes of different files are not used. Hence the returned set of partial
2530- /// paths will not cover paths going through those edges.
2531- ///
2532- /// [`PartialPath::extend`]: struct.PartialPath.html#method.extend
2533- pub fn find_minimal_partial_path_set_in_file < F > (
2534- & mut self ,
2535- graph : & StackGraph ,
2536- file : Handle < File > ,
2537- cancellation_flag : & dyn CancellationFlag ,
2538- mut visit : F ,
2539- ) -> Result < ( ) , CancellationError >
2540- where
2541- F : FnMut ( & StackGraph , & mut PartialPaths , PartialPath ) ,
2542- {
2543- fn as_complete_as_necessary ( graph : & StackGraph , path : & PartialPath ) -> bool {
2544- path. starts_at_endpoint ( graph)
2545- && ( path. ends_at_endpoint ( graph) || graph[ path. end_node ] . is_jump_to ( ) )
2546- }
2547-
2548- copious_debugging ! ( "Find all partial paths in {}" , graph[ file] ) ;
2549- let mut queue = VecDeque :: new ( ) ;
2550- let mut edges = Appendables :: new ( ) ;
2551- queue. extend (
2552- graph
2553- . nodes_for_file ( file)
2554- . chain ( std:: iter:: once ( StackGraph :: root_node ( ) ) )
2555- . filter ( |node| graph[ * node] . is_endpoint ( ) )
2556- . map ( |node| {
2557- (
2558- PartialPath :: from_node ( graph, self , node) ,
2559- AppendingCycleDetector :: new ( ) ,
2560- )
2561- } ) ,
2562- ) ;
2563- while let Some ( ( path, path_cycle_detector) ) = queue. pop_front ( ) {
2564- cancellation_flag. check ( "finding partial paths in file" ) ?;
2565- let is_seed = path. edges . is_empty ( ) ;
2566- copious_debugging ! ( " => {}" , path. display( graph, self ) ) ;
2567- if !is_seed && as_complete_as_necessary ( graph, & path) {
2568- copious_debugging ! ( " * visit" ) ;
2569- visit ( graph, self , path) ;
2570- } else if !path_cycle_detector
2571- . is_cyclic ( graph, self , & GraphEdges ( Some ( file) ) , & mut edges)
2572- . expect ( "cyclic test failed when finding partial paths" )
2573- . is_empty ( )
2574- {
2575- copious_debugging ! ( " * cycle" ) ;
2576- } else {
2577- copious_debugging ! ( " * extend" ) ;
2578- path. extend (
2579- graph,
2580- self ,
2581- Some ( file) ,
2582- & mut edges,
2583- path_cycle_detector,
2584- & mut queue,
2585- ) ;
2586- }
2587- }
2588- Ok ( ( ) )
2589- }
2590-
2591- /// Finds all complete paths reachable from a set of starting nodes, calling the `visit` closure
2592- /// for each one.
2593- ///
2594- /// This function will not return until all reachable paths have been processed, so `graph`
2595- /// must already contain a complete stack graph. If you have a very large stack graph stored
2596- /// in some other storage system, and want more control over lazily loading only the necessary
2597- /// pieces, then you should code up your own loop that calls [`Path::extend`][] manually.
2598- ///
2599- /// [`Path::extend`]: struct.Path.html#method.extend
2600- pub fn find_all_complete_paths < I , F > (
2601- & mut self ,
2602- graph : & StackGraph ,
2603- starting_nodes : I ,
2604- cancellation_flag : & dyn CancellationFlag ,
2605- mut visit : F ,
2606- ) -> Result < ( ) , CancellationError >
2607- where
2608- I : IntoIterator < Item = Handle < Node > > ,
2609- F : FnMut ( & StackGraph , & mut PartialPaths , PartialPath ) ,
2610- {
2611- copious_debugging ! ( "Find all complete paths from nodes" ) ;
2612- let mut queue = starting_nodes
2613- . into_iter ( )
2614- . filter ( |node| graph[ * node] . is_reference ( ) )
2615- . map ( |node| {
2616- let mut p = PartialPath :: from_node ( graph, self , node) ;
2617- p. eliminate_precondition_stack_variables ( self ) ;
2618- ( p, AppendingCycleDetector :: new ( ) )
2619- } )
2620- . collect :: < VecDeque < _ > > ( ) ;
2621- let mut partials = PartialPaths :: new ( ) ;
2622- let mut edges = Appendables :: new ( ) ;
2623- while let Some ( ( path, path_cycle_detector) ) = queue. pop_front ( ) {
2624- cancellation_flag. check ( "finding complete paths" ) ?;
2625- if path. is_complete ( graph) {
2626- copious_debugging ! ( " * visit" ) ;
2627- visit ( graph, self , path. clone ( ) ) ;
2628- }
2629- if !path_cycle_detector
2630- . is_cyclic ( graph, & mut partials, & GraphEdges ( None ) , & mut edges)
2631- . expect ( "cyclic test failed when finding complete paths" )
2632- . into_iter ( )
2633- . all ( |c| c == Cyclicity :: StrengthensPrecondition )
2634- {
2635- copious_debugging ! ( " * cycle" ) ;
2636- } else {
2637- copious_debugging ! ( " * extend" ) ;
2638- path. extend (
2639- graph,
2640- self ,
2641- None ,
2642- & mut edges,
2643- path_cycle_detector,
2644- & mut queue,
2645- ) ;
2646- }
2647- }
2648- Ok ( ( ) )
2649- }
2650- }
2651-
26522460//-------------------------------------------------------------------------------------------------
26532461// Extending partial paths with partial paths
26542462
0 commit comments