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

SmallVec<[T; N]> is invariant over T #146

Open
zakarumych opened this issue Apr 12, 2019 · 7 comments
Open

SmallVec<[T; N]> is invariant over T #146

zakarumych opened this issue Apr 12, 2019 · 7 comments

Comments

@zakarumych
Copy link

zakarumych commented Apr 12, 2019

SmallVec<[T; N]> is invariant over T.
Although [T; N] is covariant over T as expected.

This is due to SmallVec<A> having field of type <A as Array>::Item in underlying union.
I propose to change that field type to A and remove A: Array bound from type declaration.

@mbrubeck
Copy link
Collaborator

mbrubeck commented Apr 16, 2019

For reference, this is similar to bluss/arrayvec#96, and is caused by rust-lang/rust#21726.

@Nadrieril
Copy link

Nadrieril commented Nov 28, 2019

The following trick (can't remember where I found it):

enum SmallVec<A: Array<Item=Item>, Item=<A as Array>::Item> {
    Inline(MaybeUninit<A>),
    Heap((NonNull<Item>, usize)),
}

fixes the variance issue (playground link).
Would that be possible to use or would it be a breaking change to the API ?

Nadrieril added a commit to Nadrieril/rust that referenced this issue Dec 2, 2019
We want the lifetimes of the patterns contained in the matrix and the
candidate `PatStack` to be the same so that they can be mixed together.
A lot of this would not be necessary if `SmallVec` was covariant in its
type argument (see servo/rust-smallvec#146).
@bkolobara
Copy link

I just spent a few hours debugging a lifetime compilation error related to this after replacing Vec with SmallVec. It took me a long time to figure out that the error originated in SmallVec. This can be really a tricky issue.

@mbrubeck
Copy link
Collaborator

Fortunately, I expect this issue will be fixed in smallvec 2.0 when we replace the Array trait with const generics (#240).

That work depends on the min_const_generics feature, which the Rust team is planning to ship in early 2021: rust-lang/rust#79135

@tesujimath
Copy link

Having stumbled upon a lifetime problem caused by this, I found the very new 2.0.0-alpha.1 version, tried it, and found it fixed my problem, so yay! And thanks!

@Nadrieril
Copy link

min_const_generics was stabilized 3 years ago: rust-lang/rust#79135, are there any plans to provide a SmallVec<T, N> alternative that has the right variance?

@Nadrieril
Copy link

Oh wait, it looks like master has that already, I guess it's not finalized yet?

MichaReiser added a commit to astral-sh/ruff that referenced this issue Mar 6, 2024
## Summary

When you try to remove an internal representation leaking into another
type and end up rewriting a simple version of `smallvec`.

The goal of this PR is to replace the `Box<[&'a str]>` with
`Box<QualifiedName>` to avoid that the internal `QualifiedName`
representation leaks (and it gives us a nicer API too). However, doing
this when `QualifiedName` uses `SmallVec` internally gives us all sort
of funny lifetime errors. I was lost but @BurntSushi came to rescue me.
He figured out that `smallvec` has a variance problem which is already
tracked in servo/rust-smallvec#146

To fix the variants problem, I could use the smallvec-2-alpha-4 or
implement our own smallvec. I went with implementing our own small vec
for this specific problem. It obviously isn't as sophisticated as
smallvec (only uses safe code), e.g. it doesn't perform any size
optimizations, but it does its job.

Other changes:

* Removed `Imported::qualified_name` (the version that returns a
`String`). This can be replaced by calling `ToString` on the qualified
name.
* Renamed `Imported::call_path` to `qualified_name` and changed its
return type to `&QualifiedName`.
* Renamed `QualifiedName::imported` to `user_defined` which is the more
common term when talking about builtins vs the rest/user defined
functions.


## Test plan

`cargo test`
nkxxll pushed a commit to nkxxll/ruff that referenced this issue Mar 10, 2024
)

## Summary

When you try to remove an internal representation leaking into another
type and end up rewriting a simple version of `smallvec`.

The goal of this PR is to replace the `Box<[&'a str]>` with
`Box<QualifiedName>` to avoid that the internal `QualifiedName`
representation leaks (and it gives us a nicer API too). However, doing
this when `QualifiedName` uses `SmallVec` internally gives us all sort
of funny lifetime errors. I was lost but @BurntSushi came to rescue me.
He figured out that `smallvec` has a variance problem which is already
tracked in servo/rust-smallvec#146

To fix the variants problem, I could use the smallvec-2-alpha-4 or
implement our own smallvec. I went with implementing our own small vec
for this specific problem. It obviously isn't as sophisticated as
smallvec (only uses safe code), e.g. it doesn't perform any size
optimizations, but it does its job.

Other changes:

* Removed `Imported::qualified_name` (the version that returns a
`String`). This can be replaced by calling `ToString` on the qualified
name.
* Renamed `Imported::call_path` to `qualified_name` and changed its
return type to `&QualifiedName`.
* Renamed `QualifiedName::imported` to `user_defined` which is the more
common term when talking about builtins vs the rest/user defined
functions.


## Test plan

`cargo test`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants