@@ -503,6 +503,32 @@ impl TraitDatum {
503
503
// IsUpstream(V),
504
504
// CannotProve, // returns ambiguous
505
505
// }
506
+ //
507
+ // In certain situations, this is too restrictive. Consider the following code:
508
+ //
509
+ // // In crate std:
510
+ // trait Sized { }
511
+ // struct str { }
512
+ //
513
+ // // In crate bar: (depends on std)
514
+ // trait Bar { }
515
+ // impl Bar for str { }
516
+ // impl<T> Bar for T where T: Sized { }
517
+ //
518
+ // Here, because of the rules we've defined, these two impls overlap. The std crate is
519
+ // upstream to bar, and thus it is allowed to compatibly implement Sized for str. If str
520
+ // can implement Sized in a compatible future, these two impls definitely overlap since the
521
+ // second impl covers all types that implement Sized.
522
+ //
523
+ // The solution we've got right now is to mark Sized as "fundamental" when it is defined.
524
+ // This signals to the Rust compiler that it can rely on the fact that str does not
525
+ // implement Sized in all contexts. A consequence of this is that we can no longer add an
526
+ // implementation of Sized compatibly for str. This is the trade off you make when defining
527
+ // a fundamental trait.
528
+ //
529
+ // To implement fundamental traits, we simply just do not add the rule above that allows
530
+ // upstream types to implement upstream traits. Fundamental traits are not allowed to
531
+ // compatibly do that.
506
532
507
533
let mut clauses = Vec :: new ( ) ;
508
534
@@ -578,19 +604,23 @@ impl TraitDatum {
578
604
clauses. push ( impl_maybe_allowed) ;
579
605
}
580
606
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
607
+ // Fundamental traits can be reasoned about negatively without any ambiguity, so no
608
+ // need for this rule if the trait is fundamental.
609
+ if !self . binders . value . flags . fundamental {
610
+ let impl_may_exist = self . binders . map_ref ( |bound_datum| ProgramClauseImplication {
611
+ consequence : DomainGoal :: Holds ( WhereClause :: Implemented ( bound_datum. trait_ref . clone ( ) ) ) ,
612
+ conditions : bound_datum. where_clauses
584
613
. iter ( )
585
614
. cloned ( )
586
615
. casted ( )
587
616
. chain ( iter:: once ( DomainGoal :: Compatible ( ( ) ) . cast ( ) ) )
588
617
. chain ( bound_datum. trait_ref . type_parameters ( ) . map ( |ty| DomainGoal :: IsUpstream ( ty) . cast ( ) ) )
589
618
. chain ( iter:: once ( Goal :: CannotProve ( ( ) ) ) )
590
619
. collect ( ) ,
591
- } ) . cast ( ) ;
620
+ } ) . cast ( ) ;
592
621
593
- clauses. push ( impl_may_exist) ;
622
+ clauses. push ( impl_may_exist) ;
623
+ }
594
624
}
595
625
596
626
let condition = DomainGoal :: FromEnv ( FromEnv :: Trait ( trait_ref. clone ( ) ) ) ;
0 commit comments