-
Notifications
You must be signed in to change notification settings - Fork 12.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Remove the remaining uses of old_orphan_rules
#19470
Comments
@arielb1 that is definitely a hole! Nominating. Interesting, have to think a bit about what the best way is to patch the rules for this case. |
By the way, the ambiguity can also occur between the receiver and one of the trait's type parameters: base.rs: pub trait Base<T> { /* ... */} foo.rs: extern crate base;
pub struct Foo;
impl<T> base::Base<Foo> for T {} bar.rs: extern crate base;
pub struct Bar;
impl base::Base<T> for Bar {} With |
Some relevant comments from @arielb1 on IRC: https://botbot.me/mozilla/rust-internals/2014-12-03/?msg=26759795&page=7 |
I thought this through. I am mildly uncomfortable with @arielb1's proposed rules in that I do not expect the ordering of type parameters to be significant (which is not to say that those rules would not solve the problem). @aturon and I worked through some examples and we felt like these rules captured our intution reasonably well:
This can be summarized as "type parameters can only appear as parameters of a local type/trait". This seems to cover the various cases I can think of. I have not tried to prove it sound but I believe it is. Of course I thought that before. :) Once I've had some more coffee, I might take a crack at that, seems like it should be a simple inductive exercise. |
The version you wrote is broken: // Crate a:
struct A;
impl<T> Base for Pair<Option<T>, Option<A>> {}
// Crate b:
struct B;
impl<T> Base for Pair<Option<B>, Option<T>> {} Which follows the rules, as A working variant is my second version of the rule: let ≺ be the partial order on nodes in a trait-ref generated by Trait ≺ Self ≺ Tᵢ in the trait-ref 〈Trait〈Tᵢ〉 for Self〉, Type ≺ Tᵢ in a type Type〈Tᵢ〉, then for every type parameter node Q in the trait-ref there exists a local node L such that L ≺ Q. |
@arielb1 that does not follow the rules because of their recursion nature. Note that the |
(Not to say the rules are perfect, as I said, I have to go back through the list of examples I had and make sure they accept/reject correctly, I'm a bit nervous about the |
(Or maybe that's the point, perhaps you are correct and I haven't quite formulated the rules the way I wanted them) |
By the way, the partial-order rules in sequent form:
|
I created btw a repository for experimenting with rules and their effects on various scenarios: |
1.0 P-backcompat-lang |
The repository now contains an encoding of the rules that I think more accurately captures what I was going for, and has the side benefit of being (afaik) sound. An impl of some trait
A type
A type
If you find that textual definition confusing, see the code. In any case, I think this is a subset of @arielb1's definition (as expected). The reason is that @arielb1's requirement was that, when iterating @arielb1 let me know what you think! |
@arielb1 points out that this rule prohibits Note in particular that if we permit
then there is a potential coherence conflict for However, it may be that we can avoid ordering dependency by permitting "uncovered" type parameters as long as they are covered somewhere. I have to try and prove this. |
An argument in favor of the "must be covered somewhere" is that I think you can always reduce it to an ordered set (pre-order) by reordering the parameters in a given trait/type. |
Never mind, that is truly for one impl. Still, I think the rule is sound, though I haven't written up a full proof (of course, I thought the original was sound too). The intuition is that you will ultimately require a cyclic type to violate it. |
@arielb1 writes a proposed proof of the "all type parameters must be covered" rule in IRC here: https://botbot.me/mozilla/rust-internals/2014-12-12/?msg=27397345&page=5 I haven't read it deeply enough to comment yet. |
Prettier Proof: Substitution - written as Ty[{Tₖ←Sₖ|k}], substitutes the an impl is treated as defid-of(Type) = def-id of the root (e.g. Type/TraitRef contains-defid DefId : lexical containment Type/TraitRef contains-type Type : structural containment Q contains-type Ty is true when there exists a P that These 3 overloaded relations will be labeled as Lemmas I'm using: Substitution: Combinatorics: Main Theorem: And, for all i, if Tᵢ⪯R₁, then there exists a Then for no i and j, Tᵢ⪯Rⱼ (neither trait-ref contains Proof: Let i be such that Tᵢ⪯R₁. There exists a Ty such Let G be the graph of the partial order ≺ restricted to Q.E.D. |
I implemented this check. Interestingly, like so many things I have in progress, it seems to be somewhat blocked on associated types, in that the
For now I plan to land the new check with a (deprecated) feature-gate that disables it, so that old code can continue to work until everything else is in place. |
This is the actual example where I encountered a problem: impl<S: hash::Writer, Sized? T: Hash<S>> Hash<S> for Box<T> |
Another interesting example that fails (from libgraphviz): impl<'a, T: PartialEq, Sized? V: AsSlice<T>> Equiv<V> for MaybeOwnedVector<'a, T> This seems to be a pattern that is just inexpressible? (That is, relating a local type to any type that implements some trait). |
These do work with the "privileged self" variant of the order-based rules. Maybe we can find a mix of the covering-based and ordering-based rules that supports this? |
old_orphan_rules
I updated the issue to better highlight what remains to be done, and made a checklist of traits that are still using |
Nominating to move to P-backcompat-libs. This will largely go away with the stabilization of |
P-backcompat-libs, 1.0 beta. |
This is a deprecated attribute that is slated for removal, and it also affects all implementors of the trait. This commit removes the attribute and fixes up implementors accordingly. The primary implementation which was lost was the ability to compare `&[T]` and `Vec<T>` (in that order). This change also modifies the `assert_eq!` macro to not consider both directions of equality, only the one given in the left/right forms to the macro. This modification is motivated due to the fact that `&[T] == Vec<T>` no longer compiles, causing hundreds of errors in unit tests in the standard library (and likely throughout the community as well). cc rust-lang#19470 [breaking-change]
This is a deprecated attribute that is slated for removal, and it also affects all implementors of the trait. This commit removes the attribute and fixes up implementors accordingly. The primary implementation which was lost was the ability to compare `&[T]` and `Vec<T>` (in that order). This change also modifies the `assert_eq!` macro to not consider both directions of equality, only the one given in the left/right forms to the macro. This modification is motivated due to the fact that `&[T] == Vec<T>` no longer compiles, causing hundreds of errors in unit tests in the standard library (and likely throughout the community as well). Closes rust-lang#19470 [breaking-change]
UPDATED ISSUE:
The original issue that was reported by @arielb1 has largely been resolved. However, there remain some traits that were added before the new rules were completed, and which do not conform. Those traits are currently distinguished with
old_orphan_check
markers. The remaining work is to fix these traits:BorrowFrom
BorrowFromMut
IntoCow
ToOwned
PartialEq
- @nikomatsakis
ORIGINAL ISSUE:
The current version of orphan checking does not prevent me from break coherence if impls from different crates are non-orphan because of different type parameters of the same type, for example:
base.rs:
foo.rs:
bar.rs:
foobar.rs:
Which of course ICE-s with a trans ambiguity.
The text was updated successfully, but these errors were encountered: