@@ -240,8 +240,17 @@ impl Context {
240
240
}
241
241
}
242
242
243
+ impl Graph < PackageId , Rc < Vec < Dependency > > > {
244
+ pub fn parents_of ( & self , p : PackageId ) -> impl Iterator < Item = ( PackageId , bool ) > + ' _ {
245
+ self . edges ( & p)
246
+ . map ( |( grand, d) | ( * grand, d. iter ( ) . any ( |x| x. is_public ( ) ) ) )
247
+ }
248
+ }
249
+
243
250
#[ derive( Clone , Debug , Default ) ]
244
251
pub struct PublicDependency {
252
+ /// For each active package the set of all the names it can see,
253
+ /// for each name the exact package that name resolves to and whether it exports that visibility.
245
254
inner : im_rc:: HashMap < PackageId , im_rc:: HashMap < InternedString , ( PackageId , bool ) > > ,
246
255
}
247
256
@@ -251,29 +260,30 @@ impl PublicDependency {
251
260
inner : im_rc:: HashMap :: new ( ) ,
252
261
}
253
262
}
263
+ fn publicly_exports ( & self , candidate_pid : PackageId ) -> Vec < PackageId > {
264
+ self . inner
265
+ . get ( & candidate_pid) // if we have seen it before
266
+ . iter ( )
267
+ . flat_map ( |x| x. values ( ) ) // all the things we have stored
268
+ . filter ( |x| x. 1 ) // as publicly exported
269
+ . map ( |x| x. 0 )
270
+ . chain ( Some ( candidate_pid) ) // but even if not we know that everything exports itself
271
+ . collect ( )
272
+ }
254
273
pub fn add_edge (
255
274
& mut self ,
256
275
candidate_pid : PackageId ,
257
276
parent_pid : PackageId ,
258
- dep : & Dependency ,
277
+ is_public : bool ,
259
278
parents : & Graph < PackageId , Rc < Vec < Dependency > > > ,
260
279
) {
261
280
// one tricky part is that `candidate_pid` may already be active and
262
281
// have public dependencies of its own. So we not only need to mark
263
282
// `candidate_pid` as visible to its parents but also all of its existing
264
- // public dependencies.
265
- let existing_public_deps: Vec < PackageId > = self
266
- . inner
267
- . get ( & candidate_pid)
268
- . iter ( )
269
- . flat_map ( |x| x. values ( ) )
270
- . filter_map ( |x| if x. 1 { Some ( & x. 0 ) } else { None } )
271
- . chain ( & Some ( candidate_pid) )
272
- . cloned ( )
273
- . collect ( ) ;
274
- for c in existing_public_deps {
283
+ // publicly exported dependencies.
284
+ for c in self . publicly_exports ( candidate_pid) {
275
285
// for each (transitive) parent that can newly see `t`
276
- let mut stack = vec ! [ ( parent_pid, dep . is_public( ) ) ] ;
286
+ let mut stack = vec ! [ ( parent_pid, is_public) ] ;
277
287
while let Some ( ( p, public) ) = stack. pop ( ) {
278
288
match self . inner . entry ( p) . or_default ( ) . entry ( c. name ( ) ) {
279
289
im_rc:: hashmap:: Entry :: Occupied ( mut o) => {
@@ -299,9 +309,7 @@ impl PublicDependency {
299
309
// if `candidate_pid` was a private dependency of `p` then `p` parents can't see `c` thru `p`
300
310
if public {
301
311
// if it was public, then we add all of `p`s parents to be checked
302
- for & ( grand, ref d) in parents. edges ( & p) {
303
- stack. push ( ( grand, d. iter ( ) . any ( |x| x. is_public ( ) ) ) ) ;
304
- }
312
+ stack. extend ( parents. parents_of ( p) ) ;
305
313
}
306
314
}
307
315
}
@@ -310,21 +318,16 @@ impl PublicDependency {
310
318
& self ,
311
319
b_id : PackageId ,
312
320
parent : PackageId ,
313
- dep : & Dependency ,
321
+ is_public : bool ,
314
322
parents : & Graph < PackageId , Rc < Vec < Dependency > > > ,
315
323
) -> Result < ( ) , ( PackageId , ConflictReason ) > {
316
- let existing_public_deps: Vec < PackageId > = self
317
- . inner
318
- . get ( & b_id)
319
- . iter ( )
320
- . flat_map ( |x| x. values ( ) )
321
- . filter_map ( |x| if x. 1 { Some ( & x. 0 ) } else { None } )
322
- . chain ( & Some ( b_id) )
323
- . cloned ( )
324
- . collect ( ) ;
325
- for t in existing_public_deps {
324
+ // one tricky part is that `candidate_pid` may already be active and
325
+ // have public dependencies of its own. So we not only need to check
326
+ // `b_id` as visible to its parents but also all of its existing
327
+ // publicly exported dependencies.
328
+ for t in self . publicly_exports ( b_id) {
326
329
// for each (transitive) parent that can newly see `t`
327
- let mut stack = vec ! [ ( parent, dep . is_public( ) ) ] ;
330
+ let mut stack = vec ! [ ( parent, is_public) ] ;
328
331
while let Some ( ( p, public) ) = stack. pop ( ) {
329
332
// TODO: dont look at the same thing more then once
330
333
if let Some ( o) = self . inner . get ( & p) . and_then ( |x| x. get ( & t. name ( ) ) ) {
@@ -333,13 +336,17 @@ impl PublicDependency {
333
336
// So, adding `b` will cause `p` to have a public dependency conflict on `t`.
334
337
return Err ( ( p, ConflictReason :: PublicDependency ) ) ;
335
338
}
339
+ if o. 1 {
340
+ // The previous time the parent saw `t`, it was a public dependency.
341
+ // So all of its parents already know about `t`
342
+ // and we can save some time by stopping now.
343
+ continue ;
344
+ }
336
345
}
337
346
// if `b` was a private dependency of `p` then `p` parents can't see `t` thru `p`
338
347
if public {
339
348
// if it was public, then we add all of `p`s parents to be checked
340
- for & ( grand, ref d) in parents. edges ( & p) {
341
- stack. push ( ( grand, d. iter ( ) . any ( |x| x. is_public ( ) ) ) ) ;
342
- }
349
+ stack. extend ( parents. parents_of ( p) ) ;
343
350
}
344
351
}
345
352
}
0 commit comments