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

Closed
arielb1 opened this Issue Dec 2, 2014 · 35 comments

Comments

Projects
None yet
7 participants
@arielb1
Contributor

arielb1 commented Dec 2, 2014

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:

pub trait Base { fn work(&self); }

foo.rs:

extern crate base;
pub struct Foo;

impl<T> base::Base for (Foo, T) {
  fn work(&self) { println!("foo!"); }
}

bar.rs:

extern crate base;
pub struct Bar;

impl<T> base::Base for (T, Bar) {
  fn work(&self) { println!("bar!"); }
}

foobar.rs:

extern crate foo;
extern crate bar;
extern crate base;
use base::Base;

fn main() { (foo::Foo, bar::Bar).work(); }

Which of course ICE-s with a trans ambiguity.

@arielb1

This comment has been minimized.

Show comment
Hide comment
Contributor

arielb1 commented Dec 2, 2014

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 2, 2014

Contributor

@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.

Contributor

nikomatsakis commented Dec 2, 2014

@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.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Dec 3, 2014

Contributor

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 <Bar as base::Base<Foo>> being ambigious.

Contributor

arielb1 commented Dec 3, 2014

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 <Bar as base::Base<Foo>> being ambigious.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment

@nikomatsakis nikomatsakis referenced this issue Dec 5, 2014

Closed

Trait reform #5527

3 of 5 tasks complete
@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 11, 2014

Contributor

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:

Local(Trait<T2...Tn> for T1) =
    Trait is local || (
       exists i. Local(Ti) &&
       forall i. Ti is not a type parameter
    )
Local(Type<T1...Tn>) =
    Type is local || (
       exists i. Local(Ti) &&
       forall i. Ti is not a type parameter
    )

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.

Contributor

nikomatsakis commented Dec 11, 2014

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:

Local(Trait<T2...Tn> for T1) =
    Trait is local || (
       exists i. Local(Ti) &&
       forall i. Ti is not a type parameter
    )
Local(Type<T1...Tn>) =
    Type is local || (
       exists i. Local(Ti) &&
       forall i. Ti is not a type parameter
    )

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.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Dec 11, 2014

Contributor

@nikomatsakis

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 Option<T> isn't a type parameter (it just contains one).

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.

Contributor

arielb1 commented Dec 11, 2014

@nikomatsakis

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 Option<T> isn't a type parameter (it just contains one).

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.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 11, 2014

Contributor

@arielb1 that does not follow the rules because of their recursion nature. Note that the Pair type is not local, and neither is Option, and hence the rules recurse in and ultimately reject both impls because of their use of a type parameter.

Contributor

nikomatsakis commented Dec 11, 2014

@arielb1 that does not follow the rules because of their recursion nature. Note that the Pair type is not local, and neither is Option, and hence the rules recurse in and ultimately reject both impls because of their use of a type parameter.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 11, 2014

Contributor

(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 exists vs forall)

Contributor

nikomatsakis commented Dec 11, 2014

(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 exists vs forall)

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 11, 2014

Contributor

(Or maybe that's the point, perhaps you are correct and I haven't quite formulated the rules the way I wanted them)

Contributor

nikomatsakis commented Dec 11, 2014

(Or maybe that's the point, perhaps you are correct and I haven't quite formulated the rules the way I wanted them)

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Dec 11, 2014

Contributor

By the way, the partial-order rules in sequent form:

Rule C0:
a crate
T type
T has-no-free-parameters
---------------------------------
a ⊢ T complete

Rule C1:
a crate
T type
a ⊢ T local
---------------------------------
a ⊢ T complete

Rule T0:
a crate
Q unsubstituted-type
Q defined-in a
∀i. Pᵢ type
---------------------------------
a ⊢ Q〈Pᵢ〉 local

Rule T1:
a crate
Q unsubstituted-type
∀i. Pᵢ type
∀i. a ⊢ Pᵢ complete
∃i. a ⊢ Pᵢ local
---------------------------------
a ⊢ Q〈Pᵢ〉 local


Rule R0:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
Tr defined-in a
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

Rule R1:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
a ⊢ S local
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

Rule R2:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
a ⊢ S complete
∀i. a ⊢ Pᵢ complete
∃i. a ⊢ Pᵢ local
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

Contributor

arielb1 commented Dec 11, 2014

By the way, the partial-order rules in sequent form:

Rule C0:
a crate
T type
T has-no-free-parameters
---------------------------------
a ⊢ T complete

Rule C1:
a crate
T type
a ⊢ T local
---------------------------------
a ⊢ T complete

Rule T0:
a crate
Q unsubstituted-type
Q defined-in a
∀i. Pᵢ type
---------------------------------
a ⊢ Q〈Pᵢ〉 local

Rule T1:
a crate
Q unsubstituted-type
∀i. Pᵢ type
∀i. a ⊢ Pᵢ complete
∃i. a ⊢ Pᵢ local
---------------------------------
a ⊢ Q〈Pᵢ〉 local


Rule R0:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
Tr defined-in a
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

Rule R1:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
a ⊢ S local
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

Rule R2:
a crate
Tr unsubstituted-trait
∀i. Pᵢ type
S type
a ⊢ S complete
∀i. a ⊢ Pᵢ complete
∃i. a ⊢ Pᵢ local
---------------------------------
〈Tr〈Pᵢ〉 for S〉 local

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 11, 2014

Contributor

I created btw a repository for experimenting with rules and their effects on various scenarios:

https://github.com/nikomatsakis/orphan

Contributor

nikomatsakis commented Dec 11, 2014

I created btw a repository for experimenting with rules and their effects on various scenarios:

https://github.com/nikomatsakis/orphan

@brson brson added this to the 1.0 milestone Dec 11, 2014

@brson

This comment has been minimized.

Show comment
Hide comment
@brson

brson Dec 11, 2014

Contributor

1.0 P-backcompat-lang

Contributor

brson commented Dec 11, 2014

1.0 P-backcompat-lang

@brson brson removed the I-nominated label Dec 11, 2014

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 12, 2014

Contributor

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 Trait for some type Type (multidispatch can be considered as a tuple) is legal if:

  • Trait is defined in the current crate OR (Type is local AND Type is covered)

A type Type is local if:

  • It contains at least one nominal type defined in the current crate

A type Type is covered if:

  • All type parameters appear underneath a local type constructor

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 Trait<Self,T1,...Tn> in pre-order, a local type always appeared before any type-parameter. In these rules, the type parameter must appear underneath a local type, so by definition it appears after the local type in pre-order.

@arielb1 let me know what you think!

Contributor

nikomatsakis commented Dec 12, 2014

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 Trait for some type Type (multidispatch can be considered as a tuple) is legal if:

  • Trait is defined in the current crate OR (Type is local AND Type is covered)

A type Type is local if:

  • It contains at least one nominal type defined in the current crate

A type Type is covered if:

  • All type parameters appear underneath a local type constructor

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 Trait<Self,T1,...Tn> in pre-order, a local type always appeared before any type-parameter. In these rules, the type parameter must appear underneath a local type, so by definition it appears after the local type in pre-order.

@arielb1 let me know what you think!

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 12, 2014

Contributor

@arielb1 points out that this rule prohibits impl<T> Iterator<T> for Vec<T>, which seems reasonable and mildly useful. ;) He also opened a PR on the orphan repo implementing his order-dependent suggestion. I am coming to the idea that this is the only way to preserve the expressiveness we want.

Note in particular that if we permit

Crate 1: impl<T> Iterator<T> for Foo<T>
Crate 2: impl<A,B> Iterator<Bar<A>> for B

then there is a potential coherence conflict for Iterator<Bar<Foo<T>> for Foo<T>.

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.

Contributor

nikomatsakis commented Dec 12, 2014

@arielb1 points out that this rule prohibits impl<T> Iterator<T> for Vec<T>, which seems reasonable and mildly useful. ;) He also opened a PR on the orphan repo implementing his order-dependent suggestion. I am coming to the idea that this is the only way to preserve the expressiveness we want.

Note in particular that if we permit

Crate 1: impl<T> Iterator<T> for Foo<T>
Crate 2: impl<A,B> Iterator<Bar<A>> for B

then there is a potential coherence conflict for Iterator<Bar<Foo<T>> for Foo<T>.

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.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 12, 2014

Contributor

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.

Contributor

nikomatsakis commented Dec 12, 2014

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.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 12, 2014

Contributor

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.

Contributor

nikomatsakis commented Dec 12, 2014

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.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 12, 2014

Contributor

@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.

Contributor

nikomatsakis commented Dec 12, 2014

@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.

@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Dec 12, 2014

Contributor

Prettier Proof:
Definitions:

Substitution - written as Ty[{Tₖ←Sₖ|k}], substitutes the
parameters Tₖ with the arguments Sₖ. For example,
Option⟨T⟩[T←Vec⟨uint⟩] = Option⟨Vec⟨uint⟩⟩
DefId - same as in rustc
TyDefId - DefId of a type (struct/enum/etc.)
TrDefId - DefId of a trait
Type - same as in rust
Complete Type - a type without free type parameters
TraitRef - ⟨TrDefId⟨T₁, .., Tₖ⟩ for Type⟩

an impl is treated as
∀S₁∀S₂...∀Sₖ BOUNDS→impl(⟨Trait⟨...⟩ for Self⟩[{Tᵢ←Sᵢ|i}]

defid-of(Type) = def-id of the root (e.g.
defid-of(Option(Pair(Foo,Bar⟩⟩) = Option

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
contains-param T, and Q=P[T←Ty].

These 3 overloaded relations will be labeled as
T⪯Q. Of course, T≺Q when T⪯Q and T≠Q.

Lemmas I'm using:

Substitution:
S0: ⪯ is a partial order.
S1: ⪯ respects substitution: if Tᵢ is a parameter, S⪯T and Ty⪯Tᵢ,
then S⪯Ty[Tᵢ←T]
S2: defid-of is preserved by substitution:
if Ty is not a type parameter, then
defid-of(Ty[{Tᵢ←Sᵢ}]) = defid-of(Ty)
S3: If defid-of(Ty)⋠Q, and Ty⪯Q[{Tᵢ←Sᵢ|i}], then
∃Tᵢ. Tᵢ⪯Q ∧ Ty⪯Sᵢ

Combinatorics:
C0: The only finite directed acyclic graph with no vertex
of non-zero indegree is the empty graph.
C1: A subgraph of a directed acyclic graph is also directed and
acyclic
C2: The graph of a partial order is directed and acyclic

Main Theorem:
Let R₁=⟨TrB⟨...⟩ for ...⟩, R₂=⟨TrA⟨...⟩ for ...⟩ be TraitRefs,
U₁...Uₖ, V₁...Vₗ be types, such that
R₁[{Tᵢ←Uᵢ|i}] = R₂[{Tᵢ←Vᵢ|i}].

And, for all i, if Tᵢ⪯R₁, then there exists a
Ty that is not a type parameter, such that Tᵢ⪱Ty⪯R₁ and
defid-of(Ty)⋠R₂, and vice-versa (if Tᵢ⪯R₂, then there exists a
non-type-parameter Ty, such that Tᵢ⪱Ty⪯R₂ and defid-of(Ty)⋠R₁)

Then for no i and j, Tᵢ⪯Rⱼ (neither trait-ref contains
type parameters).

Proof:

Let i be such that Tᵢ⪯R₁. There exists a Ty such
that Tᵢ≺Ty⪯R₁ and defid-of(Ty)⋠R₂.
By the definition of substitition, Tᵢ[{Tᵢ←Uᵢ|i}] = Uᵢ, so
Uᵢ≺Ty[{Tᵢ←Uᵢ|i}]. Ty is not a type parameter, so
defid-of(Ty[{Tᵢ←Uᵢ|i}])⋠R₂. By S3,
there exists a j such that Tⱼ⪯R₁ and Uᵢ≺Ty[{Tᵢ←Uᵢ|i}]⪯Vⱼ,
and we get that ∀i.Tᵢ⪯R₁→∃j.Tⱼ⪯R₂∧Uᵢ≺Vⱼ. By swapping R₁ and R₂, this argument also proves ∀i.Tᵢ⪯R₂→∃j.Tⱼ⪯R₁∧Vᵢ≺Uⱼ.

Let G be the graph of the partial order ≺ restricted to
{Vⱼ|Tⱼ⪯R₁} ∪ {Uⱼ|Tⱼ⪯R₂}. This graph is directed, acyclic, and
finite, and every vertex of it has a non-zero indegree (by
the previous paragraph), so it is empty.

Q.E.D.

Contributor

arielb1 commented Dec 12, 2014

Prettier Proof:
Definitions:

Substitution - written as Ty[{Tₖ←Sₖ|k}], substitutes the
parameters Tₖ with the arguments Sₖ. For example,
Option⟨T⟩[T←Vec⟨uint⟩] = Option⟨Vec⟨uint⟩⟩
DefId - same as in rustc
TyDefId - DefId of a type (struct/enum/etc.)
TrDefId - DefId of a trait
Type - same as in rust
Complete Type - a type without free type parameters
TraitRef - ⟨TrDefId⟨T₁, .., Tₖ⟩ for Type⟩

an impl is treated as
∀S₁∀S₂...∀Sₖ BOUNDS→impl(⟨Trait⟨...⟩ for Self⟩[{Tᵢ←Sᵢ|i}]

defid-of(Type) = def-id of the root (e.g.
defid-of(Option(Pair(Foo,Bar⟩⟩) = Option

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
contains-param T, and Q=P[T←Ty].

These 3 overloaded relations will be labeled as
T⪯Q. Of course, T≺Q when T⪯Q and T≠Q.

Lemmas I'm using:

Substitution:
S0: ⪯ is a partial order.
S1: ⪯ respects substitution: if Tᵢ is a parameter, S⪯T and Ty⪯Tᵢ,
then S⪯Ty[Tᵢ←T]
S2: defid-of is preserved by substitution:
if Ty is not a type parameter, then
defid-of(Ty[{Tᵢ←Sᵢ}]) = defid-of(Ty)
S3: If defid-of(Ty)⋠Q, and Ty⪯Q[{Tᵢ←Sᵢ|i}], then
∃Tᵢ. Tᵢ⪯Q ∧ Ty⪯Sᵢ

Combinatorics:
C0: The only finite directed acyclic graph with no vertex
of non-zero indegree is the empty graph.
C1: A subgraph of a directed acyclic graph is also directed and
acyclic
C2: The graph of a partial order is directed and acyclic

Main Theorem:
Let R₁=⟨TrB⟨...⟩ for ...⟩, R₂=⟨TrA⟨...⟩ for ...⟩ be TraitRefs,
U₁...Uₖ, V₁...Vₗ be types, such that
R₁[{Tᵢ←Uᵢ|i}] = R₂[{Tᵢ←Vᵢ|i}].

And, for all i, if Tᵢ⪯R₁, then there exists a
Ty that is not a type parameter, such that Tᵢ⪱Ty⪯R₁ and
defid-of(Ty)⋠R₂, and vice-versa (if Tᵢ⪯R₂, then there exists a
non-type-parameter Ty, such that Tᵢ⪱Ty⪯R₂ and defid-of(Ty)⋠R₁)

Then for no i and j, Tᵢ⪯Rⱼ (neither trait-ref contains
type parameters).

Proof:

Let i be such that Tᵢ⪯R₁. There exists a Ty such
that Tᵢ≺Ty⪯R₁ and defid-of(Ty)⋠R₂.
By the definition of substitition, Tᵢ[{Tᵢ←Uᵢ|i}] = Uᵢ, so
Uᵢ≺Ty[{Tᵢ←Uᵢ|i}]. Ty is not a type parameter, so
defid-of(Ty[{Tᵢ←Uᵢ|i}])⋠R₂. By S3,
there exists a j such that Tⱼ⪯R₁ and Uᵢ≺Ty[{Tᵢ←Uᵢ|i}]⪯Vⱼ,
and we get that ∀i.Tᵢ⪯R₁→∃j.Tⱼ⪯R₂∧Uᵢ≺Vⱼ. By swapping R₁ and R₂, this argument also proves ∀i.Tᵢ⪯R₂→∃j.Tⱼ⪯R₁∧Vᵢ≺Uⱼ.

Let G be the graph of the partial order ≺ restricted to
{Vⱼ|Tⱼ⪯R₁} ∪ {Uⱼ|Tⱼ⪯R₂}. This graph is directed, acyclic, and
finite, and every vertex of it has a non-zero indegree (by
the previous paragraph), so it is empty.

Q.E.D.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 26, 2014

Contributor

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 Hash impls are not legal otherwise:

impl<S, T:Hasher<S>> Hash<S> for Type<T> { ... }

S here is uncovered. (You could rewrite this pattern so that Type takes S as a parameter as well.)

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.

Contributor

nikomatsakis commented Dec 26, 2014

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 Hash impls are not legal otherwise:

impl<S, T:Hasher<S>> Hash<S> for Type<T> { ... }

S here is uncovered. (You could rewrite this pattern so that Type takes S as a parameter as well.)

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.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 26, 2014

Contributor

This is the actual example where I encountered a problem:

impl<S: hash::Writer, Sized? T: Hash<S>> Hash<S> for Box<T>
Contributor

nikomatsakis commented Dec 26, 2014

This is the actual example where I encountered a problem:

impl<S: hash::Writer, Sized? T: Hash<S>> Hash<S> for Box<T>
@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Dec 26, 2014

Contributor

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).

Contributor

nikomatsakis commented Dec 26, 2014

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).

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Dec 26, 2014

Fix orphan checking. Fixes #19470.
This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Dec 26, 2014

Fix orphan checking (cc #19470). (This is not a complete fix of #19470
…because

of the backwards compatibility feature gate.)

This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.
@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Dec 28, 2014

Contributor

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?

Contributor

arielb1 commented Dec 28, 2014

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?

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Dec 29, 2014

Fix orphan checking (cc #19470). (This is not a complete fix of #19470
…because of the backwards compatibility feature gate.)

This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Dec 29, 2014

Fix orphan checking (cc #19470). (This is not a complete fix of #19470
…because of the backwards compatibility feature gate.)

This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Jan 1, 2015

Fix orphan checking (cc #19470). (This is not a complete fix of #19470
…because of the backwards compatibility feature gate.)

This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.

nikomatsakis added a commit to nikomatsakis/rust that referenced this issue Jan 2, 2015

Fix orphan checking (cc #19470). (This is not a complete fix of #19470
…because of the backwards compatibility feature gate.)

This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.
@arielb1

This comment has been minimized.

Show comment
Hide comment
@arielb1

arielb1 Jan 4, 2015

Contributor

Looking at this again, I kind of do want to be able to do impl<D:Decoder<E>, E> Decodable<D, E> for InternedString. This does require something like the privileged self rule.

Actually, this could be implemented by having a

trait UniversalDecodable {
    fn decode_by<D: Decoder<E>, E>(d: &mut D) -> Result<Self, E>;
}

impl<D: Decoder<E>, E, T: UniversalDecodable> Decodable<D, E> for T {
    fn decode(d: &mut D) -> Result<Self, E> {
        UniversalDecodable::decode_by(d)
    }
}

Unfortunately, this would create problems with #19032.

Contributor

arielb1 commented Jan 4, 2015

Looking at this again, I kind of do want to be able to do impl<D:Decoder<E>, E> Decodable<D, E> for InternedString. This does require something like the privileged self rule.

Actually, this could be implemented by having a

trait UniversalDecodable {
    fn decode_by<D: Decoder<E>, E>(d: &mut D) -> Result<Self, E>;
}

impl<D: Decoder<E>, E, T: UniversalDecodable> Decodable<D, E> for T {
    fn decode(d: &mut D) -> Result<Self, E> {
        UniversalDecodable::decode_by(d)
    }
}

Unfortunately, this would create problems with #19032.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jan 4, 2015

Member

@nikomatsakis

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).

Somehow I did not fully think through the implications of this limitation before. I think it's a serious one and I agree with @arielb1 that we should consider a less conservative form of the rules that can allow it.

Member

aturon commented Jan 4, 2015

@nikomatsakis

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).

Somehow I did not fully think through the implications of this limitation before. I think it's a serious one and I agree with @arielb1 that we should consider a less conservative form of the rules that can allow it.

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 4, 2015

Contributor

So @aturon and I had a long conversation about this and we've decided that @arielb1's original ordering-based solution is probably the best we are going to do. It is somewhat unfortunate, but there are critical patterns that are just not supported by the coverage-based rules. We tried to find a way to combine the two rules, but the most important pattern seems inherently unsupportable:

impl<T> BorrowFrom<Rc<T>> for T

As long as you permit something like:

impl<T> BorrowFrom<T> for LocalType

then there will be an inherent conflict. Luckily we are planning to change BorrowFrom to Borrow, so maybe this just becomes a thing -- you must order your type parameters well.

Similar problems arise with binops, but there the problems run deeper:

impl<E,T:Iterator<Item=E>> Add<T> for MyVec<E>

This pattern is ok, but changing the order of the add operands is not. However, that seems to just be...what it is. And what's more, if we DID permit both orders, there's an obvious conflict between any two vector implementations that want to be addable to all iterators. So forcing an ordering makes those semantics clear.

Perhaps we'll find a way to improve this rule in the future; it should be backwards compatible to accept more impls.

Sorry @arielb1 for taking so long to come around!

Contributor

nikomatsakis commented Jan 4, 2015

So @aturon and I had a long conversation about this and we've decided that @arielb1's original ordering-based solution is probably the best we are going to do. It is somewhat unfortunate, but there are critical patterns that are just not supported by the coverage-based rules. We tried to find a way to combine the two rules, but the most important pattern seems inherently unsupportable:

impl<T> BorrowFrom<Rc<T>> for T

As long as you permit something like:

impl<T> BorrowFrom<T> for LocalType

then there will be an inherent conflict. Luckily we are planning to change BorrowFrom to Borrow, so maybe this just becomes a thing -- you must order your type parameters well.

Similar problems arise with binops, but there the problems run deeper:

impl<E,T:Iterator<Item=E>> Add<T> for MyVec<E>

This pattern is ok, but changing the order of the add operands is not. However, that seems to just be...what it is. And what's more, if we DID permit both orders, there's an obvious conflict between any two vector implementations that want to be addable to all iterators. So forcing an ordering makes those semantics clear.

Perhaps we'll find a way to improve this rule in the future; it should be backwards compatible to accept more impls.

Sorry @arielb1 for taking so long to come around!

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 4, 2015

Contributor

So I implemented the partial ordering rule. Here are the traits that fail, and a sample impl from each one:

  • BorrowFrom
  • BorrowFromMut
  • IntoCow -- impl<'a, T> IntoCow<'a, Vec<T>, [T]> for &'a [T]
  • ToOwned -- impl<T: Clone> ToOwned<Vec<T>> for [T]
  • PartialEq -- impl<'b, A, B> PartialEq<Vec<A>> for &'b [B]
Contributor

nikomatsakis commented Jan 4, 2015

So I implemented the partial ordering rule. Here are the traits that fail, and a sample impl from each one:

  • BorrowFrom
  • BorrowFromMut
  • IntoCow -- impl<'a, T> IntoCow<'a, Vec<T>, [T]> for &'a [T]
  • ToOwned -- impl<T: Clone> ToOwned<Vec<T>> for [T]
  • PartialEq -- impl<'b, A, B> PartialEq<Vec<A>> for &'b [B]
@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 4, 2015

Contributor

(While it's not clear what the best sol'n is for each of these traits, it seems like they are all solvable.)

Contributor

nikomatsakis commented Jan 4, 2015

(While it's not clear what the best sol'n is for each of these traits, it seems like they are all solvable.)

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 5, 2015

Contributor

So out of curiosity, I also implemented a more restrictive rule:

  1. The self type must reach something local
  2. Any type parameters in the self type must be "covered by" something local

This also lets everything in the standard library build. It does cause failures on some test cases that the other check accepted, such as:

  • impl Remote<BigInt> for int
  • impl Remote<BigInt> for Vec<int>

Both of these are interesting patterns, but otoh they can't be scaled up to blanket impls over all T:ToInt or anything like that.

The advantage of the simpler check is primarily that it's easier to explain. It also doesn't commit us to the full ordering rules just yet, in case we come up with something better (though I'm not so worried about that). The disadvantage is that we lose some impls.

Thoughts?

Contributor

nikomatsakis commented Jan 5, 2015

So out of curiosity, I also implemented a more restrictive rule:

  1. The self type must reach something local
  2. Any type parameters in the self type must be "covered by" something local

This also lets everything in the standard library build. It does cause failures on some test cases that the other check accepted, such as:

  • impl Remote<BigInt> for int
  • impl Remote<BigInt> for Vec<int>

Both of these are interesting patterns, but otoh they can't be scaled up to blanket impls over all T:ToInt or anything like that.

The advantage of the simpler check is primarily that it's easier to explain. It also doesn't commit us to the full ordering rules just yet, in case we come up with something better (though I'm not so worried about that). The disadvantage is that we lose some impls.

Thoughts?

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 5, 2015

Contributor

Ah, I was wrong, there one additional failure that I didn't notice before using the more restrictive rules, and it's a semi-interesting one:

  • impl<'a, T> FromIterator<T> for Cow<'a, Vec<T>, [T]>

Here the type parameter T appears uncovered, even though it also appears covered.

This gives me an idea for an alternative rule. One could imagine:

  1. The self type must reach something local
  2. All type parameters in the self type must be covered by a local type in the self type

This allows type parameters to appear in arbitrary other places. I believe this is sound, though, or at least as sound as the original typing rule -- it's basically the covering rule applied only to the self type.

One reason this rule is interesting is that it does permit for truly order-independent traits, though they must be implemented using tuples in the self type. (Rather like my original max-min proposal for multidispatch.) Not saying we will use this pattern, but it leaves the door open.

I implemented this rule too. It builds all stdlibs as well.

Contributor

nikomatsakis commented Jan 5, 2015

Ah, I was wrong, there one additional failure that I didn't notice before using the more restrictive rules, and it's a semi-interesting one:

  • impl<'a, T> FromIterator<T> for Cow<'a, Vec<T>, [T]>

Here the type parameter T appears uncovered, even though it also appears covered.

This gives me an idea for an alternative rule. One could imagine:

  1. The self type must reach something local
  2. All type parameters in the self type must be covered by a local type in the self type

This allows type parameters to appear in arbitrary other places. I believe this is sound, though, or at least as sound as the original typing rule -- it's basically the covering rule applied only to the self type.

One reason this rule is interesting is that it does permit for truly order-independent traits, though they must be implemented using tuples in the self type. (Rather like my original max-min proposal for multidispatch.) Not saying we will use this pattern, but it leaves the door open.

I implemented this rule too. It builds all stdlibs as well.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jan 5, 2015

Member

@nikomatsakis and I talked about this last proposal:

  1. The self type must reach something local
  2. All type parameters in the self type must be covered by a local type in the self type

and think it seems very promising. On the one hand, it covers the most important impl patterns we want to cover. On the other hand, it's relatively easy to think about: to a rough approximation, only the definer of a trait can give a blanket impl for Self; downstream crates must impl "on" a type defined in their crate. (Of course the full rule is more subtle, but that gets you most of the way there.)

It also means that the order of type parameters does not become significant for impl purposes other than Self -- and Self is already special in various other ways.

Finally, it seems plausible to extend this rule in the future, allowing traits to mark additional non-Self parameters as participating in the same locality checks.

Member

aturon commented Jan 5, 2015

@nikomatsakis and I talked about this last proposal:

  1. The self type must reach something local
  2. All type parameters in the self type must be covered by a local type in the self type

and think it seems very promising. On the one hand, it covers the most important impl patterns we want to cover. On the other hand, it's relatively easy to think about: to a rough approximation, only the definer of a trait can give a blanket impl for Self; downstream crates must impl "on" a type defined in their crate. (Of course the full rule is more subtle, but that gets you most of the way there.)

It also means that the order of type parameters does not become significant for impl purposes other than Self -- and Self is already special in various other ways.

Finally, it seems plausible to extend this rule in the future, allowing traits to mark additional non-Self parameters as participating in the same locality checks.

@glaebhoerl

This comment has been minimized.

Show comment
Hide comment
@glaebhoerl

glaebhoerl Jan 8, 2015

Contributor

Interestingly this seems very similar to a bug GHC also has.

Contributor

glaebhoerl commented Jan 8, 2015

Interestingly this seems very similar to a bug GHC also has.

@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Jan 8, 2015

Member

Nominating to move to the -beta milestone.

Member

aturon commented Jan 8, 2015

Nominating to move to the -beta milestone.

@aturon aturon added the I-nominated label Jan 8, 2015

@brson brson modified the milestones: 1.0 beta, 1.0 Jan 15, 2015

@nikomatsakis nikomatsakis changed the title from Orphan checking isn't strict enough with multidispatch to Remove the remaining uses of `old_orphan_rules` Jan 31, 2015

@nikomatsakis

This comment has been minimized.

Show comment
Hide comment
@nikomatsakis

nikomatsakis Jan 31, 2015

Contributor

I updated the issue to better highlight what remains to be done, and made a checklist of traits that are still using old_orphan_check for one reason or another.

Contributor

nikomatsakis commented Jan 31, 2015

I updated the issue to better highlight what remains to be done, and made a checklist of traits that are still using old_orphan_check for one reason or another.

bors added a commit that referenced this issue Feb 1, 2015

Auto merge of #21792 - nikomatsakis:orphan-ordered-first, r=aturon
Update the coherence rules to "covered first" -- the first type parameter to contain either a local type or a type parameter must contain only covered type parameters.

cc #19470.
Fixes #20974.
Fixes #20749.

r? @aturon
@aturon

This comment has been minimized.

Show comment
Hide comment
@aturon

aturon Feb 16, 2015

Member

Nominating to move to P-backcompat-libs.

This will largely go away with the stabilization of std::borrow (which is currently blocked) but there are a couple other instances lurking.

Member

aturon commented Feb 16, 2015

Nominating to move to P-backcompat-libs.

This will largely go away with the stabilization of std::borrow (which is currently blocked) but there are a couple other instances lurking.

@aturon aturon added the I-nominated label Feb 16, 2015

@pnkfelix

This comment has been minimized.

Show comment
Hide comment
@pnkfelix

pnkfelix Feb 19, 2015

Member

P-backcompat-libs, 1.0 beta.

Member

pnkfelix commented Feb 19, 2015

P-backcompat-libs, 1.0 beta.

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 11, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 11, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 17, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 24, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 27, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 28, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 31, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 31, 2015

rollup merge of #23288: alexcrichton/issue-19470
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 #19470
[breaking-change]

bors added a commit that referenced this issue Mar 31, 2015

Auto merge of #23288 - alexcrichton:issue-19470, r=aturon
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 31, 2015

std: Remove #[old_orphan_check] from PartialEq
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 31, 2015

rollup merge of #23288: alexcrichton/issue-19470
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 #19470
[breaking-change]

alexcrichton added a commit to alexcrichton/rust that referenced this issue Mar 31, 2015

rollup merge of #23288: alexcrichton/issue-19470
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 #19470
[breaking-change]

@bors bors closed this in #23288 Apr 1, 2015

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment