@@ -319,6 +319,8 @@ impl StructDatum {
319
319
//
320
320
// forall<T> { IsLocal(Box<T>) :- IsLocal(T) }
321
321
// forall<T> { IsUpstream(Box<T>) :- IsUpstream(T) }
322
+ // // Generated for both upstream and local fundamental types
323
+ // forall<T> { DownstreamType(Box<T>) :- DownstreamType(T) }
322
324
323
325
let wf = self . binders . map_ref ( |bound_datum| {
324
326
ProgramClauseImplication {
@@ -343,6 +345,32 @@ impl StructDatum {
343
345
344
346
let mut clauses = vec ! [ wf, is_fully_visible] ;
345
347
348
+ // Fundamental types often have rules in the form of:
349
+ // Goal(FundamentalType<T>) :- Goal(T)
350
+ // This macro makes creating that kind of clause easy
351
+ macro_rules! fundamental_rule {
352
+ ( $goal: ident) => {
353
+ // Fundamental types must always have at least one type parameter for this rule to
354
+ // make any sense. We currently do not have have any fundamental types with more than
355
+ // one type parameter, nor do we know what the behaviour for that should be. Thus, we
356
+ // are asserting here that there is only a single type parameter until the day when
357
+ // someone makes a decision about how that should behave.
358
+ assert_eq!( self . binders. value. self_ty. len_type_parameters( ) , 1 ,
359
+ "Only fundamental types with a single parameter are supported" ) ;
360
+
361
+ clauses. push( self . binders. map_ref( |bound_datum| ProgramClauseImplication {
362
+ consequence: DomainGoal :: $goal( bound_datum. self_ty. clone( ) . cast( ) ) ,
363
+ conditions: vec![
364
+ DomainGoal :: $goal(
365
+ // This unwrap is safe because we asserted above for the presence of a type
366
+ // parameter
367
+ bound_datum. self_ty. first_type_parameter( ) . unwrap( )
368
+ ) . cast( ) ,
369
+ ] ,
370
+ } ) . cast( ) ) ;
371
+ } ;
372
+ }
373
+
346
374
// Types that are not marked `#[upstream]` satisfy IsLocal(TypeName)
347
375
if !self . binders . value . flags . upstream {
348
376
// `IsLocalTy(Ty)` depends *only* on whether the type is marked #[upstream] and nothing else
@@ -355,33 +383,6 @@ impl StructDatum {
355
383
} else if self . binders . value . flags . fundamental {
356
384
// If a type is `#[upstream]`, but is also `#[fundamental]`, it satisfies IsLocal
357
385
// if and only if its parameters satisfy IsLocal
358
-
359
- // Fundamental types must always have at least one type parameter for this rule to
360
- // make any sense. We currently do not have have any fundamental types with more than
361
- // one type parameter, nor do we know what the behaviour for that should be. Thus, we
362
- // are asserting here that there is only a single type parameter until the day when
363
- // someone makes a decision about how that should behave.
364
- assert_eq ! ( self . binders. value. self_ty. len_type_parameters( ) , 1 ,
365
- "Only fundamental types with a single parameter are supported" ) ;
366
-
367
- // Fundamental types often have rules in the form of:
368
- // Goal(FundamentalType<T>) :- Goal(T)
369
- // This macro makes creating that kind of clause easy
370
- macro_rules! fundamental_rule {
371
- ( $goal: ident) => {
372
- clauses. push( self . binders. map_ref( |bound_datum| ProgramClauseImplication {
373
- consequence: DomainGoal :: $goal( bound_datum. self_ty. clone( ) . cast( ) ) ,
374
- conditions: vec![
375
- DomainGoal :: $goal(
376
- // This unwrap is safe because we asserted above for the presence of a type
377
- // parameter
378
- bound_datum. self_ty. first_type_parameter( ) . unwrap( )
379
- ) . cast( ) ,
380
- ] ,
381
- } ) . cast( ) ) ;
382
- } ;
383
- }
384
-
385
386
fundamental_rule ! ( IsLocal ) ;
386
387
fundamental_rule ! ( IsUpstream ) ;
387
388
} else {
@@ -395,6 +396,10 @@ impl StructDatum {
395
396
clauses. push ( is_upstream) ;
396
397
}
397
398
399
+ if self . binders . value . flags . fundamental {
400
+ fundamental_rule ! ( DownstreamType ) ;
401
+ }
402
+
398
403
let condition = DomainGoal :: FromEnv (
399
404
FromEnv :: Ty ( self . binders . value . self_ty . clone ( ) . cast ( ) )
400
405
) ;
@@ -481,6 +486,25 @@ impl TraitDatum {
481
486
// IsFullyVisible(U),
482
487
// IsLocal(V)
483
488
// }
489
+ //
490
+ // The overlap check uses compatible { ... } mode to ensure that it accounts for impls that
491
+ // may exist in some other *compatible* world. For every upstream trait, we add a rule to
492
+ // account for the fact that upstream crates are able to compatibly add impls of upstream
493
+ // traits for upstream types.
494
+ //
495
+ // // For `#[upstream] trait Foo<T, U, V> where Self: Eq<T> { ... }`
496
+ // forall<Self, T, U, V> {
497
+ // Implemented(Self: Foo<T, U, V>) :-
498
+ // Implemented(Self: Eq<T>), // where clauses
499
+ // Compatible, // compatible modality
500
+ // IsUpstream(Self),
501
+ // IsUpstream(T),
502
+ // IsUpstream(U),
503
+ // IsUpstream(V),
504
+ // CannotProve, // returns ambiguous
505
+ // }
506
+
507
+ let mut clauses = Vec :: new ( ) ;
484
508
485
509
let trait_ref = self . binders . value . trait_ref . clone ( ) ;
486
510
@@ -503,8 +527,32 @@ impl TraitDatum {
503
527
} ,
504
528
}
505
529
} ) . cast ( ) ;
530
+ clauses. push ( wf) ;
531
+
532
+ // The number of parameters will always be at least 1 because of the Self parameter
533
+ // that is automatically added to every trait. This is important because otherwise
534
+ // the added program clauses would not have any conditions.
535
+ let type_parameters: Vec < _ > = self . binders . value . trait_ref . type_parameters ( ) . collect ( ) ;
536
+
537
+ // Add all cases for potential downstream impls that could exist
538
+ for i in 0 ..type_parameters. len ( ) {
539
+ let impl_may_exist = self . binders . map_ref ( |bound_datum|
540
+ ProgramClauseImplication {
541
+ consequence : DomainGoal :: Holds ( WhereClause :: Implemented ( bound_datum. trait_ref . clone ( ) ) ) ,
542
+ conditions : bound_datum. where_clauses
543
+ . iter ( )
544
+ . cloned ( )
545
+ . casted ( )
546
+ . chain ( iter:: once ( DomainGoal :: Compatible ( ( ) ) . cast ( ) ) )
547
+ . chain ( ( 0 ..i) . map ( |j| DomainGoal :: IsFullyVisible ( type_parameters[ j] . clone ( ) ) . cast ( ) ) )
548
+ . chain ( iter:: once ( DomainGoal :: DownstreamType ( type_parameters[ i] . clone ( ) ) . cast ( ) ) )
549
+ . chain ( iter:: once ( Goal :: CannotProve ( ( ) ) ) )
550
+ . collect ( ) ,
551
+ }
552
+ ) . cast ( ) ;
506
553
507
- let mut clauses = vec ! [ wf] ;
554
+ clauses. push ( impl_may_exist) ;
555
+ }
508
556
509
557
if !self . binders . value . flags . upstream {
510
558
let impl_allowed = self . binders . map_ref ( |bound_datum|
@@ -516,12 +564,6 @@ impl TraitDatum {
516
564
517
565
clauses. push ( impl_allowed) ;
518
566
} else {
519
- // The number of parameters will always be at least 1 because of the Self parameter
520
- // that is automatically added to every trait. This is important because otherwise
521
- // the added program clauses would not have any conditions.
522
-
523
- let type_parameters: Vec < _ > = self . binders . value . trait_ref . type_parameters ( ) . collect ( ) ;
524
-
525
567
for i in 0 ..type_parameters. len ( ) {
526
568
let impl_maybe_allowed = self . binders . map_ref ( |bound_datum|
527
569
ProgramClauseImplication {
@@ -535,6 +577,20 @@ impl TraitDatum {
535
577
536
578
clauses. push ( impl_maybe_allowed) ;
537
579
}
580
+
581
+ let impl_may_exist = self . binders . map_ref ( |bound_datum| ProgramClauseImplication {
582
+ consequence : DomainGoal :: Holds ( WhereClause :: Implemented ( bound_datum. trait_ref . clone ( ) ) ) ,
583
+ conditions : bound_datum. where_clauses
584
+ . iter ( )
585
+ . cloned ( )
586
+ . casted ( )
587
+ . chain ( iter:: once ( DomainGoal :: Compatible ( ( ) ) . cast ( ) ) )
588
+ . chain ( bound_datum. trait_ref . type_parameters ( ) . map ( |ty| DomainGoal :: IsUpstream ( ty) . cast ( ) ) )
589
+ . chain ( iter:: once ( Goal :: CannotProve ( ( ) ) ) )
590
+ . collect ( ) ,
591
+ } ) . cast ( ) ;
592
+
593
+ clauses. push ( impl_may_exist) ;
538
594
}
539
595
540
596
let condition = DomainGoal :: FromEnv ( FromEnv :: Trait ( trait_ref. clone ( ) ) ) ;
0 commit comments