Skip to content

Various fixes to trait alias feature #55994

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

Closed
wants to merge 12 commits into from

Conversation

alexreg
Copy link
Contributor

@alexreg alexreg commented Nov 16, 2018

  1. Disallows multiple regular traits in trait objects when trait aliases used, ensuring code like the following fails to compile.

    #![feature(trait_alias)]
    
    trait Foo = std::io::Read + std::io::Write;
    
    fn main() {
        let foo: Box<dyn Foo>;
    }
  2. Implemented cross-crate usage of trait aliases. They know get properly encoded and decoded in crate metadata. Added test.

  3. Introduces the DUPLICATE_AUTO_TRAITS_IN_BOUNDS lint (warn-by-default).

  4. Added test for issue ICE with trait aliases and use items #56488. (Appears to be false positive.)

Issue fixes

CC @nikomatsakis @scalexm

@rust-highfive
Copy link
Contributor

r? @nikomatsakis

(rust_highfive has picked a reviewer for you, use r? to override)

@rust-highfive rust-highfive added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Nov 16, 2018
@rust-highfive

This comment has been minimized.

@alexreg
Copy link
Contributor Author

alexreg commented Nov 16, 2018

I still want to improve error messages a bit, but this is nearly ready. Feel free to review.

@rust-highfive

This comment has been minimized.

@alexreg
Copy link
Contributor Author

alexreg commented Nov 17, 2018

Ready for review and (hopefully) merge now, I think.

@rust-highfive

This comment has been minimized.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks great! Left one nit (on the test)

@nikomatsakis
Copy link
Contributor

@bors r+

@bors
Copy link
Collaborator

bors commented Nov 20, 2018

📌 Commit c180d7ce09bba0ab7c97365e2a1d1c33face2618 has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. labels Nov 20, 2018
@bors
Copy link
Collaborator

bors commented Nov 23, 2018

☔ The latest upstream changes (presumably #55808) made this pull request unmergeable. Please resolve the merge conflicts.

@bors bors added S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 23, 2018
@alexreg
Copy link
Contributor Author

alexreg commented Nov 24, 2018

What on Earth... this didn't merge yet?!

@rust-highfive

This comment has been minimized.

@Mark-Simulacrum
Copy link
Member

@bors r=nikomatsakis

@bors
Copy link
Collaborator

bors commented Nov 25, 2018

📌 Commit 4fb40da has been approved by nikomatsakis

@bors bors added S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. and removed S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. labels Nov 25, 2018
@bors
Copy link
Collaborator

bors commented Nov 26, 2018

⌛ Testing commit 4fb40da with merge 2fd1af3...

bors added a commit that referenced this pull request Nov 26, 2018
Disallow multiple regular traits in trait objects when trait aliases used

This ensures code like the following fails to compile.

```rust
#![feature(trait_alias)]

trait Foo = std::io::Read + std::io::Write;

fn main() {
    let foo: Box<dyn Foo>;
}
```

CC @nikomatsakis @scalexm
@bors
Copy link
Collaborator

bors commented Nov 26, 2018

💔 Test failed - status-appveyor

@bors bors added S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. and removed S-waiting-on-bors Status: Waiting on bors to run and complete tests. Bors will change the label on completion. labels Nov 26, 2018
@alexreg
Copy link
Contributor Author

alexreg commented Nov 26, 2018

Err, what's up with this? @nikomatsakis

   Compiling unicode-normalization v0.1.4
error[E0119]: conflicting implementations of trait `Trait` for type `(dyn std::marker::Send + std::marker::Sync + 'static)`:
  --> C:\Users\appveyor\.cargo\registry\src\github.com-1ecc6299db9ec823\traitobject-0.1.0\src\impls.rs:72:1
   |
71 | unsafe impl Trait for ::std::marker::Send + Sync { }
   | ------------------------------------------------ first implementation here
72 | unsafe impl Trait for ::std::marker::Send + Send + Sync { }
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `(dyn std::marker::Send + std::marker::Sync + 'static)`
error: aborting due to previous error

@nikomatsakis
Copy link
Contributor

We discussed this failure on Zulip and concluded that we probably need to do a future-compatibility warning here.

@nikomatsakis nikomatsakis added the S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. label Nov 26, 2018
@rust-highfive

This comment has been minimized.

@rust-highfive

This comment has been minimized.

@alexreg
Copy link
Contributor Author

alexreg commented Dec 31, 2018

@nikomatsakis Unless you want to extend the lint to all traits (not just auto traits), can we get this r+'ed soon please? :-)

@bors
Copy link
Collaborator

bors commented Jan 1, 2019

☔ The latest upstream changes (presumably #55937) made this pull request unmergeable. Please resolve the merge conflicts.

Copy link
Contributor

@nikomatsakis nikomatsakis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Two nits.

}

declare_lint! {
pub DUPLICATE_AUTO_TRAITS_IN_BOUNDS,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should just call this DUPLICATE_BOUNDS In particular, I think we could easily extend this in the future to non-auto-traits as well as to other sorts of bounds (e.g., where Self: 'static, Self: 'static etc).

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree we should keep this general for any sort of bound... However, Foo: Bar and Bar + Baz cannot both be bounds at the same time; I call the former a constraint and the latter a bound; Thus, Self: 'static, Self: 'static and Self: 'static + 'static are not the same thing, the first is duplicate constraints and the latter duplicate bounds. (tho you can desugar the latter to the former)

Copy link
Contributor

@nikomatsakis nikomatsakis Jan 2, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I'm not sure I see what distinction you are drawing, precisely. Is if the difference between Foo: Bar (where the self type is stated) and just Bar (which is missing the self type), or is the difference between Foo: Bar and Foo: Bar + Baz?

In the compiler / in the past, I think we draw the distinction between a where clause (which includes the self type, so e.g. Foo: Bar) and a bound (which is just the Bar part).

I think that the term "bound" and "constraint" don't make it particularly clear what we are referring to. They seem basically like synonyms to me. I wonder if we can use modifiers instead?

  • Foo: Bar -- a bound
  • Foo: Bar + Baz -- a compound bound
  • Bar -- an .. incomplete bound? =)

OTOH I'm not sure if it's really important to have a term for Bar without the self type -- though it obviously comes up for trait objects, at least grammatically. Still I feel like we could get by just using one term.

In general, I like the term "where clause" because it seems to be clearly linked to Rust syntax, and hence the most obvious. But I fear that people will assume (reasonably) that a "where clause" must be introduced with where, and hence may be confused if we refer to the Bar in fn foo<T: Bar>() or dyn Bar as a "where clause".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Interesting. I'm not sure I see what distinction you are drawing, precisely. Is if the difference between Foo: Bar (where the self type is stated) and just Bar (which is missing the self type), or is the difference between Foo: Bar and Foo: Bar + Baz?

The difference between former; i.e. Foo: Bar + 'a vs. Bar + 'a.
In my model, I think of Rust roughly (forgetting about for<'a> and such...) as having:

  • base kinds k0 ::= type | lifetime;
  • bounds as "incomplete constraints": bound = k0 -> constraint ("1-argument curried constraint")
  • + as a binary operator bound, bound -> bound (tho in reality its a list)
  • axiom sets: where [constraint]*

In the compiler / in the past, I think we draw the distinction between a where clause (which includes the self type, so e.g. Foo: Bar) and a bound (which is just the Bar part).

In Wadler's terminology (as per the paper Quantified Class Constraints) a where clause would correspond to an "axiom set" (denoted by A in the paper) and an axiom set consists of a list of "constraints".

I think that the term "bound" and "constraint" don't make it particularly clear what we are referring to.

ISTM that this is mainly due to using "bound" both for Foo: Bar and Bar which is confusing. I find that we primarily use "bound" for Bar right now. For the reference we need clear terminology, and since Wadler came up with type classes, my preference is for using Wadler's "constraint" terminology... ;)

They seem basically like synonyms to me. I wonder if we can use modifiers instead?

  • Foo: Bar -- a bound
  • Foo: Bar + Baz -- a compound bound
  • Bar -- an .. incomplete bound? =)

I'd categorize as this instead:

  • where Foo: Bar, Baz: Quux -- a where clause (or axiom set, but we don't need to call it that...)
  • Foo: Bar -- a constraint
  • for<'a> Foo<'a>: Bar -- still a constraint, but generic/universally quantified over lifetimes
  • Bar + Baz -- a compound bound
  • Bar -- a bound
  • for<'a> Bar<'a> -- still a bound, but generic over lifetimes

where bounds are constraint-constructors (but we don't need to call it that in user documentation...)

OTOH I'm not sure if it's really important to have a term for Bar without the self type -- though it obviously comes up for trait objects, at least grammatically. Still I feel like we could get by just using one term.

I feel like at least for the sake of not confusing ourselves (which I find happens often) we need 2 terms... trait objects are a good reason distinguish; we can think of dyn as an operator bound -> type.

In general, I like the term "where clause" because it seems to be clearly linked to Rust syntax, and hence the most obvious. But I fear that people will assume (reasonably) that a "where clause" must be introduced with where, and hence may be confused if we refer to the Bar in fn foo<T: Bar>() or dyn Bar as a "where clause".

<T: Bar> is a bit tricky here since it's both quantification and an axiom set at the same time... I think we should probably leave "where clause" to the syntactic rather than semantic construct...

@rust-highfive

This comment has been minimized.

@alexreg
Copy link
Contributor Author

alexreg commented Jan 3, 2019

@nikomatsakis Okay, finally reading for r+ I think! Linting has been removed; that will be addressed in a separated PR.

@bors
Copy link
Collaborator

bors commented Jan 5, 2019

☔ The latest upstream changes (presumably #56837) made this pull request unmergeable. Please resolve the merge conflicts.

@stokhos
Copy link

stokhos commented Jan 14, 2019

Ping from triage @alexreg : Have you been able to make any progress on this PR?

@alexreg
Copy link
Contributor Author

alexreg commented Jan 14, 2019

@stokhos 2 and 4 have been factored out into a separate PR by @nikomatsakis (and merged), while he is still working on 1, because it's slightly non-trivial. 3 is postponed for now.

Perhaps we should close this PR?

@nikomatsakis
Copy link
Contributor

Let's go ahead and close this PR, the relevant commits are in other branches by now.

Centril added a commit to Centril/rust that referenced this pull request Jan 19, 2019
…nikomatsakis

make trait-aliases work across crates

This is rebase of a small part of @alexreg's PR rust-lang#55994. It focuses just on the changes that integrate trait aliases properly into crate metadata, excluding the stylistic edits and the trait objects.

The stylistic edits I also rebased and can open a separate PR.

The trait object stuff I found challenging and decided it basically needed to be reimplemented. For now I've excluded it.

Since this is really @alexreg's work (I really just rebased) I am going to make it r=me once it is working.

Fixes rust-lang#56488.
Fixes rust-lang#57023.
bors added a commit that referenced this pull request May 20, 2019
…=oli-obk

Ban multi-trait objects via trait aliases

Obviously, multi-trait objects are not normally supported, so they should not be supported via trait aliases.

This has been factored out from the previous PR #55994 (see point 1).

r? @Centril

CC @nikomatsakis
bors added a commit that referenced this pull request May 22, 2019
…=oli-obk

Ban multi-trait objects via trait aliases

Obviously, multi-trait objects are not normally supported, so they should not be supported via trait aliases.

This has been factored out from the previous PR #55994 (see point 1).

r? @Centril

CC @nikomatsakis

------------------

### RELNOTES:

We now allow `dyn Send + fmt::Debug` with equivalent semantics to `dyn fmt::Debug + Send`.
That is, the order of the mentioned traits does not matter wrt. principal/not-principal traits.
This is a small change that might deserve a mention in the blog post because it is a language change but most likely not.

See https://github.com/rust-lang/rust/blob/ce2ee305f9165c037ecddddb5792588a15ff6c37/src/test/ui/traits/wf-trait-object-reverse-order.rs.

// @Centril
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-trait-system Area: Trait system F-trait_alias `#![feature(trait_alias)]` S-waiting-on-author Status: This is awaiting some action (such as code changes or more information) from the author. T-lang Relevant to the language team
Projects
None yet
10 participants