11use std:: any:: { type_name, Any } ;
22use std:: cell:: { Cell , RefCell } ;
3- use std:: collections:: BTreeSet ;
3+ use std:: collections:: { BTreeSet , HashSet } ;
44use std:: env;
55use std:: ffi:: { OsStr , OsString } ;
66use std:: fmt:: { Debug , Write } ;
@@ -197,28 +197,29 @@ impl PathSet {
197197 }
198198 }
199199
200- /// Return all `TaskPath`s in `Self` that contain any of the `needles`, removing the
201- /// matched needles.
200+ /// Return all `TaskPath`s in `Self` that contain any of the `needles`, as well as the matched
201+ /// needles.
202202 ///
203203 /// This is used for `StepDescription::krate`, which passes all matching crates at once to
204204 /// `Step::make_run`, rather than calling it many times with a single crate.
205205 /// See `tests.rs` for examples.
206- fn intersection_removing_matches (
206+ fn intersection_with_matches < ' p > (
207207 & self ,
208- needles : & mut Vec < & Path > ,
208+ needles : & [ & ' p Path ] ,
209209 module : Option < Kind > ,
210- ) -> PathSet {
210+ ) -> ( PathSet , Vec < & ' p Path > ) {
211+ let mut matched_paths = vec ! [ ] ;
211212 let mut check = |p| {
212- for ( i , n ) in needles. iter ( ) . enumerate ( ) {
213+ for n in needles {
213214 let matched = Self :: check ( p, n, module) ;
214215 if matched {
215- needles . remove ( i ) ;
216+ matched_paths . push ( * n ) ;
216217 return true ;
217218 }
218219 }
219220 false
220221 } ;
221- match self {
222+ let pathset = match self {
222223 PathSet :: Set ( set) => PathSet :: Set ( set. iter ( ) . filter ( |& p| check ( p) ) . cloned ( ) . collect ( ) ) ,
223224 PathSet :: Suite ( suite) => {
224225 if check ( suite) {
@@ -227,7 +228,8 @@ impl PathSet {
227228 PathSet :: empty ( )
228229 }
229230 }
230- }
231+ } ;
232+ ( pathset, matched_paths)
231233 }
232234
233235 /// A convenience wrapper for Steps which know they have no aliases and all their sets contain only a single path.
@@ -315,6 +317,7 @@ impl StepDescription {
315317
316318 // Handle all test suite paths.
317319 // (This is separate from the loop below to avoid having to handle multiple paths in `is_suite_path` somehow.)
320+ // Note that unlike below, we don't allow multiple suite paths to share the same path.
318321 paths. retain ( |path| {
319322 for ( desc, should_run) in v. iter ( ) . zip ( & should_runs) {
320323 if let Some ( suite) = should_run. is_suite_path ( & path) {
@@ -330,15 +333,19 @@ impl StepDescription {
330333 }
331334
332335 // Handle all PathSets.
336+ let mut seen_paths = HashSet :: new ( ) ;
333337 for ( desc, should_run) in v. iter ( ) . zip ( & should_runs) {
334- let pathsets = should_run. pathset_for_paths_removing_matches ( & mut paths, desc. kind ) ;
338+ let ( pathsets, matched ) = should_run. pathset_for_paths_with_matches ( & paths, desc. kind ) ;
335339 if !pathsets. is_empty ( ) {
340+ seen_paths. extend ( matched) ;
336341 desc. maybe_run ( builder, pathsets) ;
337342 }
338343 }
339344
340- if !paths. is_empty ( ) {
341- eprintln ! ( "error: no `{}` rules matched {:?}" , builder. kind. as_str( ) , paths, ) ;
345+ let cli_paths: HashSet < _ > = paths. into_iter ( ) . collect ( ) ;
346+ let missing_paths: Vec < _ > = cli_paths. difference ( & seen_paths) . collect ( ) ;
347+ if !missing_paths. is_empty ( ) {
348+ eprintln ! ( "error: no `{}` rules matched {:?}" , builder. kind. as_str( ) , missing_paths) ;
342349 eprintln ! (
343350 "help: run `x.py {} --help --verbose` to show a list of available paths" ,
344351 builder. kind. as_str( )
@@ -500,19 +507,21 @@ impl<'a> ShouldRun<'a> {
500507 ///
501508 /// The reason we return PathSet instead of PathBuf is to allow for aliases that mean the same thing
502509 /// (for now, just `all_krates` and `paths`, but we may want to add an `aliases` function in the future?)
503- fn pathset_for_paths_removing_matches (
510+ fn pathset_for_paths_with_matches < ' p > (
504511 & self ,
505- paths : & mut Vec < & Path > ,
512+ paths : & [ & ' p Path ] ,
506513 kind : Kind ,
507- ) -> Vec < PathSet > {
514+ ) -> ( Vec < PathSet > , HashSet < & ' p Path > ) {
515+ let mut all_matched_paths = HashSet :: new ( ) ;
508516 let mut sets = vec ! [ ] ;
509517 for pathset in & self . paths {
510- let subset = pathset. intersection_removing_matches ( paths, Some ( kind) ) ;
518+ let ( subset, matched_paths ) = pathset. intersection_with_matches ( paths, Some ( kind) ) ;
511519 if subset != PathSet :: empty ( ) {
512520 sets. push ( subset) ;
521+ all_matched_paths. extend ( matched_paths) ;
513522 }
514523 }
515- sets
524+ ( sets, all_matched_paths )
516525 }
517526}
518527
0 commit comments