Skip to content
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

Tracking issue for trait aliases #41517

Open
withoutboats opened this issue Apr 24, 2017 · 96 comments
Open

Tracking issue for trait aliases #41517

withoutboats opened this issue Apr 24, 2017 · 96 comments

Comments

@withoutboats
Copy link
Contributor

@withoutboats withoutboats commented Apr 24, 2017

This is a tracking issue for trait aliases (rust-lang/rfcs#1733).

TODO:

  • Implement: tracking issue
  • #56485 — Bringing a trait alias into scope doesn't allow calling methods from its component traits (done in #59166)
  • #56488 — ICE with trait aliases and use items
  • #57023 — Nightly Type Alias Compiler panic unexpected definition: TraitAlias
  • #57059INCOHERENT_AUTO_TRAIT_OBJECTS future-compatibility warning (superseded by #56481)
  • Document
  • Stabilize

Unresolved questions:

  • Are bounds on other input types than the receiver enforced or implied?
  • Should we keep the current behaviour of "shallow-banning" ?Sized bounds in trait objects, ban them "deeply" (through trait alias expansion), or permit them everywhere with no effect?
  • Insufficient flexibility
  • Inconvenient syntax
  • Misleading naming
  • Which of constraint/bound/type aliases are desirable
@durka
Copy link
Contributor

@durka durka commented May 7, 2017

I think #24010 (allowing aliases to set associated types) should be mentioned here.

bors added a commit that referenced this issue Jun 5, 2017
Check types for privacy

This PR implements late post factum checking of type privacy, as opposed to early preventive "private-in-public" checking.
This will allow to turn private-in-public checks into a lint and make them more heuristic-based, and more aligned with what people may expect (e.g. reachability-based behavior).

Types are privacy-checked if they are written explicitly, and also if they are inferred as expression or pattern types.
This PR checks "semantic" types and does it unhygienically, this significantly restricts what macros 2.0 (as implemented in #40847) can do (sorry @jseyfried) - they still can use private *names*, but can't use private *types*.
This is the most conservative solution, but hopefully it's temporary and can be relaxed in the future, probably using macro contexts of expression/pattern spans.

Traits are also checked in preparation for [trait aliases](#41517), which will be able to leak private traits, and macros 2.0 which will be able to leak pretty much anything.

This is a [breaking-change], but the code that is not contrived and can be broken by this patch should be guarded by `private_in_public` lint. [Previous crater run](#34537 (comment)) discovered a few abandoned crates that weren't updated since `private_in_public` has been introduced in 2015.

cc #34537 https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504
Fixes #30476
Fixes #33479

cc @nikomatsakis
r? @eddyb
bors added a commit that referenced this issue Jun 19, 2017
Check types for privacy

This PR implements late post factum checking of type privacy, as opposed to early preventive "private-in-public" checking.
This will allow to turn private-in-public checks into a lint and make them more heuristic-based, and more aligned with what people may expect (e.g. reachability-based behavior).

Types are privacy-checked if they are written explicitly, and also if they are inferred as expression or pattern types.
This PR checks "semantic" types and does it unhygienically, this significantly restricts what macros 2.0 (as implemented in #40847) can do (sorry @jseyfried) - they still can use private *names*, but can't use private *types*.
This is the most conservative solution, but hopefully it's temporary and can be relaxed in the future, probably using macro contexts of expression/pattern spans.

Traits are also checked in preparation for [trait aliases](#41517), which will be able to leak private traits, and macros 2.0 which will be able to leak pretty much anything.

This is a [breaking-change], but the code that is not contrived and can be broken by this patch should be guarded by `private_in_public` lint. [Previous crater run](#34537 (comment)) discovered a few abandoned crates that weren't updated since `private_in_public` has been introduced in 2015.

cc #34537 https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504
Fixes #30476
Fixes #33479

cc @nikomatsakis
r? @eddyb
bors added a commit that referenced this issue Jul 7, 2017
Check types for privacy

This PR implements late post factum checking of type privacy, as opposed to early preventive "private-in-public" checking.
This will allow to turn private-in-public checks into a lint and make them more heuristic-based, and more aligned with what people may expect (e.g. reachability-based behavior).

Types are privacy-checked if they are written explicitly, and also if they are inferred as expression or pattern types.
This PR checks "semantic" types and does it unhygienically, this significantly restricts what macros 2.0 (as implemented in #40847) can do (sorry @jseyfried) - they still can use private *names*, but can't use private *types*.
This is the most conservative solution, but hopefully it's temporary and can be relaxed in the future, probably using macro contexts of expression/pattern spans.

Traits are also checked in preparation for [trait aliases](#41517), which will be able to leak private traits, and macros 2.0 which will be able to leak pretty much anything.

This is a [breaking-change], but the code that is not contrived and can be broken by this patch should be guarded by `private_in_public` lint. [Previous crater run](#34537 (comment)) discovered a few abandoned crates that weren't updated since `private_in_public` has been introduced in 2015.

cc #34537 https://internals.rust-lang.org/t/lang-team-minutes-private-in-public-rules/4504
Fixes #30476
Fixes #33479

cc @nikomatsakis
r? @eddyb
@durka
Copy link
Contributor

@durka durka commented Oct 2, 2017

I'd like to take a crack at this (starting with parsing).

@durka durka mentioned this issue Oct 5, 2017
7 of 10 tasks complete
@glaebhoerl glaebhoerl mentioned this issue Oct 16, 2017
6 of 12 tasks complete
@carllerche
Copy link
Member

@carllerche carllerche commented Nov 3, 2017

I read the RFC and I saw a call out to Service, but I am not sure if the RFC actually solves the Service problem.

Specifically, the "alias" needs to provide some additional associated types:

See this snippet: https://gist.github.com/carllerche/76605b9f7c724a61a11224a36d29e023

Basically, you rarely want to just alias HttpService to Service<Request = http::Request> You really want to do something like this (while making up syntax):

trait HttpService = Service<http::Request<Self::RequestBody>> {
    type RequestBody;
}

In other words, the trait alias introduces a new associated type.

The reason why you can't do: trait HttpService<B> = Service<http::Request<B>> is that then you end up getting into the "the type parameter B is not constrained by the impl trait, self type, or predicates" problem.

@phaazon
Copy link

@phaazon phaazon commented Nov 3, 2017

Basically, you rarely want to just alias HttpService to Service<Request = http::Request>

Rarely? How do you define that?

The syntax you suggest seems a bit complex to me and non-intuitive. I don’t get why we couldn’t make an exception in the way the “problem” shows up. Cannot we just hack around that rule you expressed? It’s not a “real trait”, it should be possible… right?

@carllerche
Copy link
Member

@carllerche carllerche commented Nov 3, 2017

@phaazon rarely with regards to the service trait. This was not a general statement for when you would want trait aliasing.

Also, the syntax was not meant to be a real proposal. It was only to illustrate what I was talking about.

@phaazon
Copy link

@phaazon phaazon commented Nov 3, 2017

I see. Cannot we just use free variables for that? Like, Service<Request = http::Request> implies the free variable used in http::request<_>?

@carllerche
Copy link
Member

@carllerche carllerche commented Nov 3, 2017

@phaazon I don't understand this proposal.

bors added a commit that referenced this issue Dec 13, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
bors added a commit that referenced this issue Dec 13, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
bors added a commit that referenced this issue Dec 13, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
bors added a commit that referenced this issue Dec 14, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
bors added a commit that referenced this issue Dec 14, 2017
trait alias infrastructure

This will be an implementation of trait aliases (RFC 1733, #41517).

Progress so far:

- [x] Feature gate
- [x] Add to parser
  - [x] `where` clauses
    - [x] prohibit LHS type parameter bounds via AST validation #45047 (comment)
- [x] Add to AST and HIR
  - [x] make a separate PathSource for trait alias contexts #45047 (comment)
- [x] Stub out enough of typeck and resolve to just barely not ICE

Postponed:

- [ ] Actually implement the alias part
- [ ] #21903
- [ ] #24010

I need some pointers on where to start with that last one. The test currently does this:

```
error[E0283]: type annotations required: cannot resolve `_: CD`
  --> src/test/run-pass/trait-alias.rs:34:16
   |
34 |     let both = foo();
   |                ^^^
   |
   = note: required by `foo`
```
@varkor
Copy link
Member

@varkor varkor commented Feb 21, 2018

@durka: how's the work on the follow-up to #45047 going?

@clarfonthey
Copy link
Contributor

@clarfonthey clarfonthey commented Feb 27, 2018

Something I mentioned in the RFC: trait Trait =; is accepted by the proposed grammar and I think that this is a bit weird. Perhaps maybe the proposed _ syntax might be more apt here, because I think that allowing empty trait requirements is useful.

@durka
Copy link
Contributor

@durka durka commented Feb 27, 2018

@clarfonthey
Copy link
Contributor

@clarfonthey clarfonthey commented Feb 27, 2018

One other thing to note as a general weirdness is macro expansions involving trait bounds. Currently, fn thing<T:>() is valid syntax but perhaps fn thing<T: _>() should be the recommended version.

But then, is _ + Copy or something okay? I'm not sure. I would just suggest Any but that has different guarantees.

@petrochenkov
Copy link
Contributor

@petrochenkov petrochenkov commented Feb 27, 2018

Empty bound lists (and other lists) are accepted in other contexts as well, e.g. fn f<T: /*nothing*/>() { ... }, so trait Trait = /*nothing*/; being accepted is more of a rule than an exception.

@clarfonthey
Copy link
Contributor

@clarfonthey clarfonthey commented Feb 27, 2018

I think it makes sense being accepted, although I wonder if making it the canonical way to do so outside of macros is the right way to go. We already have been pushing toward '_ for elided lifetimes in generics, for example.

@wdanilo
Copy link

@wdanilo wdanilo commented Oct 23, 2019

@alexreg when talking on a public channel, like here, I prefer to clarify things to readers not familiar with the concepts. You mentioned that they are more powerful, and I provided an additional explanation of why. In no means my message was suggesting that you don't know it, sorry if you felt so! :)

@phaazon
Copy link

@phaazon phaazon commented Oct 24, 2019

The value of that becomes even more visible when you've got more type parameters than two and you want to keep your codebase tidy and well-named. Then you want to name several different trait bounds on different types using a single alias. You cannot use trait Alias = Ix + OnDirty to express that. Does it make more sense now?

Yep, I got you. I got that need too. Thanks for clarifying.

@alexreg
Copy link
Contributor

@alexreg alexreg commented Oct 24, 2019

@wdanilo No problem, just a miscommunication then... I appreciate you elaborating!

github-actions bot pushed a commit to rust-lang/glacier that referenced this issue Nov 24, 2019
=== stdout ===
=== stderr ===
error[E0658]: trait aliases are experimental
  --> /home/runner/work/glacier/glacier/ices/65673.rs:11:1
   |
11 | trait Foo<Ix, OnSet> = where OnSet: Callback0;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: for more information, see rust-lang/rust#41517
   = help: add `#![feature(trait_alias)]` to the crate attributes to enable

warning: trait objects without an explicit `dyn` are deprecated
  --> /home/runner/work/glacier/glacier/ices/65673.rs:14:16
   |
14 |     type Ctx = Foo<Ix, OnSet>;
   |                ^^^^^^^^^^^^^^ help: use `dyn`: `dyn Foo<Ix, OnSet>`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

error[E0392]: parameter `Ix` is never used
 --> /home/runner/work/glacier/glacier/ices/65673.rs:1:24
  |
1 | pub struct SharedRange<Ix, OnSet> {
  |                        ^^ unused parameter
  |
  = help: consider removing `Ix`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

error[E0392]: parameter `OnSet` is never used
 --> /home/runner/work/glacier/glacier/ices/65673.rs:1:28
  |
1 | pub struct SharedRange<Ix, OnSet> {
  |                            ^^^^^ unused parameter
  |
  = help: consider removing `OnSet`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

error[E0277]: the size for values of type `(dyn Callback0 + 'static)` cannot be known at compilation time
  --> /home/runner/work/glacier/glacier/ices/65673.rs:14:5
   |
6  |     type Ctx;
   |          --- associated type defined here
...
13 | impl<Ix, OnSet> HasCtx for SharedRange<Ix, OnSet> {
   | ------------------------------------------------- in this `impl` item
14 |     type Ctx = Foo<Ix, OnSet>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn Callback0 + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0277, E0392, E0658.
For more information about an error, try `rustc --explain E0277`.
==============
Dylan-DPC added a commit to rust-lang/glacier that referenced this issue Nov 24, 2019
=== stdout ===
=== stderr ===
error[E0658]: trait aliases are experimental
  --> /home/runner/work/glacier/glacier/ices/65673.rs:11:1
   |
11 | trait Foo<Ix, OnSet> = where OnSet: Callback0;
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: for more information, see rust-lang/rust#41517
   = help: add `#![feature(trait_alias)]` to the crate attributes to enable

warning: trait objects without an explicit `dyn` are deprecated
  --> /home/runner/work/glacier/glacier/ices/65673.rs:14:16
   |
14 |     type Ctx = Foo<Ix, OnSet>;
   |                ^^^^^^^^^^^^^^ help: use `dyn`: `dyn Foo<Ix, OnSet>`
   |
   = note: `#[warn(bare_trait_objects)]` on by default

error[E0392]: parameter `Ix` is never used
 --> /home/runner/work/glacier/glacier/ices/65673.rs:1:24
  |
1 | pub struct SharedRange<Ix, OnSet> {
  |                        ^^ unused parameter
  |
  = help: consider removing `Ix`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

error[E0392]: parameter `OnSet` is never used
 --> /home/runner/work/glacier/glacier/ices/65673.rs:1:28
  |
1 | pub struct SharedRange<Ix, OnSet> {
  |                            ^^^^^ unused parameter
  |
  = help: consider removing `OnSet`, referring to it in a field, or using a marker such as `std::marker::PhantomData`

error[E0277]: the size for values of type `(dyn Callback0 + 'static)` cannot be known at compilation time
  --> /home/runner/work/glacier/glacier/ices/65673.rs:14:5
   |
6  |     type Ctx;
   |          --- associated type defined here
...
13 | impl<Ix, OnSet> HasCtx for SharedRange<Ix, OnSet> {
   | ------------------------------------------------- in this `impl` item
14 |     type Ctx = Foo<Ix, OnSet>;
   |     ^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
   |
   = help: the trait `std::marker::Sized` is not implemented for `(dyn Callback0 + 'static)`
   = note: to learn more, visit <https://doc.rust-lang.org/book/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>

error: aborting due to 4 previous errors

Some errors have detailed explanations: E0277, E0392, E0658.
For more information about an error, try `rustc --explain E0277`.
==============
@Jezza
Copy link

@Jezza Jezza commented Dec 2, 2019

Is this feature accepting feedback yet?
I've been playing around with it, and it doesn't work at all with associated types and closures.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d356124710c101f92436fdcfb245fa9b

Am I doing something wrong?

EDIT:
I looked into it, and it seems like it's just an issue with HRTB.

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=d596d3aa7c0ac62fe151813ecd91f4d0

@johnw42
Copy link

@johnw42 johnw42 commented Feb 29, 2020

I'd like to propose a syntax for what's referred to as "bound aliases" above. Instead of this:

trait Foo<A, B> = where ...

The syntax could look like this:

where Foo<Self, A, B, ...> = ...

Where, you may ask, did Self come from? It's there because every trait has an implicit type parameter named Self, but a bound alias may or may not have a Self parameter. Just as a method's self parameter comes from the expression before the . when the method is called, a trait's Self parameter comes from the type expression before the : when it appears in a bound.

Above, @wdanilo gave an example of a bound alias, ItemDirtyCtx, that does not use the Self parameter, so it appears with a dummy Self type in a where clause: where (): ItemDirtyCtx<...>. This is ugly and confusing, because it's not obvious from the declaration of ItemDirtyCtx that it's meant to be used that way, and at the point of use, () may be replaced by any type at all without changing the meaning!

In my proposal, a bound alias like ItemDirtyCtx would be written without a Self parameter, and it would appear on its own in a where clause, with no : and no dummy type. The rule would be that when the alias appears in a bound, it must appear after a : if it has a Self parameter, and it must appear without a : if it doesn't.

(Also, if you'll indulge me in a bit of meta-bikeshedding, I don't think "bound alias" is a good name, because it's not an alias any more than a function is an "expression alias". Maybe "bound constructor" would be be more appropriate?)

@shika-blyat
Copy link

@shika-blyat shika-blyat commented Mar 5, 2020

Just a simple question:

#![feature(trait_alias)]
trait Foo = ;

(playground link)
is this supposed to parse and compile without any error nor warning ? 🤔

@memoryruins
Copy link
Contributor

@memoryruins memoryruins commented Mar 5, 2020

Without the feature, these are already accepted today:

fn a<T>() where T: {}
fn b<T:>() {}

With the feature, I guess it's like writing:

#![feature(trait_alias)]
trait Foo = ;
fn a<T>() where T: Foo {}
fn b<T: Foo>() {}

Although not very useful, it appears consistent.

@shika-blyat
Copy link

@shika-blyat shika-blyat commented Mar 5, 2020

Oh okay, thank you for the explanation :)

@phaazon
Copy link

@phaazon phaazon commented Mar 6, 2020

Yes, IIRC, trait bounds can be null. And it’s actually a pretty good feature I’m happy exists, especially when generating bounds in macro with $(… +)* 😄

@reuvenpo
Copy link

@reuvenpo reuvenpo commented Sep 9, 2020

I stumbled across a case where i'd like to use this feature. Is it on the roadmap for stabilization?

@aidanhs
Copy link
Member

@aidanhs aidanhs commented Dec 20, 2020

It looks like Fn trait aliases do not help closure argument type inference, whereas the original trait does:

#![feature(trait_alias)]

trait MyFn = Fn(D);

struct D;
impl D {
    fn x(&self) {}
}

//fn add(_: impl Fn(D)) {} // yep!
fn add(_: impl MyFn) {} // no!

fn main() {
    add(|x| { x.x() });
}

https://play.rust-lang.org/?version=nightly&mode=debug&edition=2018&gist=e637bc855969fbac3c6f75c60d0070a1

@SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented Jan 1, 2021

@rust-lang/lang Does this feature seem ready enough to use in public standard library APIs?

rust-lang/rfcs#2580 proposes adding pub trait Thin = Pointee<Metadata = ()>; (with Pointee a trait also added) and using it in std::ptr::null, replacing the implied T: Sized bound with T: ?Sized + Thin (in order to extend it to extern types). Without trait aliases, that bound could be T: ?Sized + Pointee<Metadata = ()>.

Is there an observable difference between the two formulations of the relaxed bound, in terms of which programs can compile or not and therefore of stability commitments?

I see that the issue description lists two unresolved questions but I’m lacking context and am not sure what they mean, and this thread is long. Adding links there would be helpful.

@varkor
Copy link
Member

@varkor varkor commented Jan 1, 2021

The unresolved questions mentioned in the issue are two minor problems compared to several of the unresolved questions that have been brought up in the thread since (insufficient flexibility, inconvenient syntax, misleading naming, and the debate about which of constraint/bound/type aliases are desirable).

My personal feeling is that it would be worth forming a working group to discuss these issues in more detail and plan out a roadmap to stabilisation. (I would be very happy to be involved with this if the lang team thinks it worth doing.)

@SimonSapin
Copy link
Contributor

@SimonSapin SimonSapin commented Jan 1, 2021

I’ve added those to the issue description, thanks!

Then let me turn my question around: if the bounds of ptr::null are relaxed from implicit T: Sized to T: ?Sized + Pointee<Metadata=()> (this is indeed relaxed because Pointee is implemented for every type), then later after we’ve figured out what trait aliases should look like, would it likely be backward-compatible to change it to T: ?Sized + Thin? It should be the same constraint on callers, just expressed differently.

@varkor
Copy link
Member

@varkor varkor commented Jan 1, 2021

@SimonSapin: yes, regardless of how the feature is eventually stabilised, the two ought to be interchangeable, so it's safe to use the explicit Pointee<Metadata = ()> for now and later replace it with a Thin trait alias.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Linked pull requests

Successfully merging a pull request may close this issue.

None yet