Add joining slices of slices with a slice separator, not just a single item
https://github.com/rust-lang/rust/issues/27747#issuecomment-294525391
> It's kinda annoying to be able to join strings with a str (which can have multiple chars), but joining a slice of slices, you can only join with a single element.
This turns out to be fixable, with some possible inference regressions.
# TL;DR
Related trait(s) are unstable and tracked at https://github.com/rust-lang/rust/issues/27747, but the `[T]::join` method that is being extended here is already stable.
Example use of the new insta-stable functionality:
```rust
let nested: Vec<Vec<Foo>> = /* … */;
let separator: &[Foo] = /* … */; // Previously: could only be a single &Foo
nested.join(separator)
```
Complete API affected by this PR, after changes:
```rust
impl<T> [T] {
pub fn concat<Item: ?Sized>(&self) -> <Self as Concat<Item>>::Output
where Self: Concat<Item>
{
Concat::concat(self)
}
pub fn join<Separator>(&self, sep: Separator) -> <Self as Join<Separator>>::Output
where Self: Join<Separator>
{
Join::join(self, sep)
}
}
// The `Item` parameter is only useful for the the slice-of-slices impl.
pub trait Concat<Item: ?Sized> {
type Output;
fn concat(slice: &Self) -> Self::Output;
}
pub trait Join<Separator> {
type Output;
fn join(slice: &Self, sep: Separator) -> Self::Output;
}
impl<T: Clone, V: Borrow<[T]>> Concat<T> for [V] {
type Output = Vec<T>;
}
impl<T: Clone, V: Borrow<[T]>> Join<&'_ T> for [V] {
type Output = Vec<T>;
}
// New functionality here!
impl<T: Clone, V: Borrow<[T]>> Join<&'_ [T]> for [V] {
type Output = Vec<T>;
}
impl<S: Borrow<str>> Concat<str> for [S] {
type Output = String;
}
impl<S: Borrow<str>> Join<&'_ str> for [S] {
type Output = String;
}
```
# Details
After https://github.com/rust-lang/rust/pull/62403 but before this PR, the API is:
```rust
impl<T> [T] {
pub fn concat<Separator: ?Sized>(&self) -> T::Output
where T: SliceConcat<Separator>
{
SliceConcat::concat(self)
}
pub fn join<Separator: ?Sized>(&self, sep: &Separator) -> T::Output
where T: SliceConcat<Separator>
{
SliceConcat::join(self, sep)
}
}
pub trait SliceConcat<Separator: ?Sized>: Sized {
type Output;
fn concat(slice: &[Self]) -> Self::Output;
fn join(slice: &[Self], sep: &Separator) -> Self::Output;
}
impl<T: Clone, V: Borrow<[T]>> SliceConcat<T> for V {
type Output = Vec<T>;
}
impl<S: Borrow<str>> SliceConcat<str> for S {
type Output = String;
}
```
By adding a trait impl we should be able to accept a slice of `T` as the separator, as an alternative to a single `T` value.
In a `some_slice.join(some_separator)` call, trait resolution will pick an impl or the other based on the type of `some_separator`. In `some_slice.concat()` however there is no separator, so this call would become ambiguous. Some regression in type inference or trait resolution may be acceptable on principle, but requiring a turbofish for every single call to `concat` isn’t great.
The solution to that is splitting the `SliceConcat` trait into two `Concat` and `Join` traits, one for each eponymous method. Only `Join` would gain a new impl, so that `some_slice.concat()` would not become ambiguous.
Now, at the trait level the `Concat` trait does not need a `Separator` parameter anymore. However, simply removing it causes one of the impls not to be accepted anymore:
```rust
error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates
--> src/liballoc/slice.rs:608:6
|
608 | impl<T: Clone, V: Borrow<[T]>> Concat for [V] {
| ^ unconstrained type parameter
```
This makes sense: if `[V]::concat` is a method that is itself not generic, then its return type (which is the `Concat::Output` associated type) needs to be determined based on solely `V`. And although there is no such type in the standard library, there is nothing stopping another crate from defining a `V` type that implements both `Borrow<[Foo]>` and `Borrow<[Bar]>`. It might not be a good idea, but it’s possible. Both would apply here, and there would be no way to determine `T`.
This could be a warning sign that this API is too generic. Perhaps we’d be better off having one less type variable, and only implement `Concat for [&'_ [T]]` and `Concat for [Vec<T>]` etc. However this aspect of `[V]::concat` is already stable, so we’re stuck with it.
The solution is to keep a dummy type parameter on the `Concat` trait. That way, if a type has multiple `Borrow<[_]>` impls, it’ll end up with multiple corresponding `Concat<_>` impls.
In `impl<S: Borrow<str>> Concat<str> for [S]`, the second occurrence of `str` is not meaningful. It could be any type. As long as there is only once such type with an applicable impl, trait resolution will be appeased without demanding turbofishes.
# Joining strings with `char`
For symmetry I also tried adding this impl (because why not):
```rust
impl<S: Borrow<str>> Join<char> for [S] {
type Output = String;
}
```
This immediately caused an inference regression in a dependency of rustc:
```rust
error[E0277]: the trait bound `std::string::String: std::borrow::Borrow<[std::string::String]>` is not satisfied
--> /home/simon/.cargo/registry/src/github.com-1ecc6299db9ec823/getopts-0.2.19/src/lib.rs:595:37
|
595 | row.push_str(&desc_rows.join(&desc_sep));
| ^^^^ the trait `std::borrow::Borrow<[std::string::String]>` is not implemented for `std::string::String`
|
= help: the following implementations were found:
<std::string::String as std::borrow::Borrow<str>>
= note: required because of the requirements on the impl of `std::slice::Join<&std::string::String>` for `[std::string::String]`
```
In the context of this code, two facts are known:
* `desc_rows` is a `Vec<String>`
* `desc_sep` is a `String`
Previously the first fact alone reduces the resolution of `join` to only one solution, where its argument it expected to be `&str`. Then, `&String` is coerced to `&str`.
With the new `Join` impl, the first fact leavs two applicable impls where the separator can be either `&str` or `char`. But `&String` is neither of these things. It appears that possible coercions are not accounted for, in the search for a solution in trait resolution.
I have not included this new impl in this PR. It’s still possible to add later, but the `getopts` breakage does not need to block the rest of the PR. And the functionality easy for end-user to duplicate: `slice_of_strings.join(&*char_separator.encode_utf8(&mut [0_u8, 4]))`
The `&*` part of that last code snippet is another case of the same issue: `encode_utf8` returns `&mut str` which can be coerced to `&str`, but isn’t when trait resolution is ambiguous.
Fix some sanity checks
Update: Changes that made it not to work dropped.
* Fix `building_llvm` in sanity check
* This was subtly broken: we build LLVM if any of the hosts builds LLVM, and not setting the config meant that LLVM is built for that target. Because of filtering away the targets not configured and the semantics of `Iterator::any`, it currently didn't set the `building_llvm` flag even if we indeed build it.
* Add `swig` sanity check
* This checks whether there is a `swig` executable needed for LLDB.
Stabilize the type_name intrinsic in core::any
Stabilize `type_name` in `core::any`.
Closesrust-lang/rfcs#1428
FCP completed over there.
`RELEASES.md`: Prefer T-libs for categorization.
Attempt to create sockets with the WSA_FLAG_NO_HANDLE_INHERIT flag, and
handle the potential error gracefully (as the flag isn't support on
Windows 7 before SP1)
So far it is assumed that using a DLL as a -l parameter argument is ok,
but the assumption doesn't hold when compiling the native code with
llvm.
In which case, an import library is required, so let's build one
This also requires the cargo counterpart to add the import library in
the stamp files, at least when compiling libstd. Otherwise, the files
don't get uplifted
Rename .cap() methods to .capacity()
As mentioned in #60316, there are a few `.cap()` methods, which seem out-of-place because such methods are called `.capacity()` in the rest of the code.
This PR renames them to `.capacity()` but leaves `RawVec::cap()` in there for backwards compatibility.
I didn't try to mark the old version as "deprecated", because I guess this would cause too much noise.
This commit moves `thread_local!` on WebAssembly targets to using the
`#[thread_local]` attribute in LLVM. This was recently implemented
upstream and is [in the process of being documented][dox]. This change
only takes affect if modules are compiled with `+atomics` which is
currently unstable and a pretty esoteric method of compiling wasm
artifacts.
This "new power" of the wasm toolchain means that the old
`wasm-bindgen-threads` feature of the standard library can be removed
since it should now be possible to create a fully functioning threaded
wasm module without intrusively dealing with libstd symbols or
intrinsics. Yay!
[dox]: https://github.com/WebAssembly/tool-conventions/pull/116
In PR #62435 ("Use const generics for array impls [part 1]") the old
macro-based implementations were not removed but still used with
`cfg(bootstrap)` since the bootstrap compiler had some problems with
const generics at the time. This does not seem to be the case anymore,
so there is no reason to keep the old code.
This commit brings in a number of minor updates for rustc's support for
the wasm target which has changed in the LLVM 9 update. Notable updates
include:
* The compiler now no longer manually inserts the `producers` section,
instead relying on LLVM to do so. LLVM uses the `llvm.ident` metadata
for the `processed-by` directive (which is now emitted on the wasm
target in this PR) and it uses debuginfo to figure out what `language`
to put in the `producers` section.
* Threaded WebAssembly code now requires different flags to be passed
with LLD. In LLD we now pass:
* `--shared-memory` - required since objects are compiled with
atomics. This also means that the generated memory will be marked as
`shared`.
* `--max-memory=1GB` - required with the `--shared-memory` argument
since shared memories in WebAssembly must have a maximum size. The
1GB number is intended to be a conservative estimate for rustc, but
it should be overridable with `-C link-arg` if necessary.
* `--passive-segments` - this has become the default for multithreaded
memory, but when compiling a threaded module all data segments need
to be marked as passive to ensure they don't re-initialize memory
for each thread. This will also cause LLD to emit a synthetic
function to initialize memory which users will have to arrange to
call.
* The `__heap_base` and `__data_end` globals are explicitly exported
since they're now hidden by default due to the `--export` flags we
pass to LLD.
Unfortunately due to an Azure quirk the TOOLSTATE_REPO_ACCESS_TOKEN is
not suitable to gate whether to push new commits to the repo, as if it's
not defined on the Azure side it will actually be set to the literal
`$(TOOLSTATE_REPO_ACCESS_TOKEN)`, which screws everything up.
This instead adds another, non-secret environment variable to gate
publishing: TOOLSTATE_PUBLISH. As non-secret environment variables
behave correctly this fixes the issue.
Rollup of 9 pull requests
Successful merges:
- #61727 (Add binary dependencies to dep-info files)
- #62736 (Polonius: fix some cases of `killed` fact generation, and most of the `ui` test suite)
- #62758 (ci: Install clang on Windows through tarballs)
- #62784 (Add riscv32i-unknown-none-elf target)
- #62814 (add support for hexagon-unknown-linux-musl)
- #62827 (Don't link mcjit/interpreter LLVM components)
- #62901 (cleanup: Remove `extern crate serialize as rustc_serialize`s)
- #62903 (Support SDKROOT env var on iOS)
- #62906 (Require a value for configure --debuginfo-level)
Failed merges:
- #62910 (cleanup: Remove lint annotations in specific crates that are already enforced by rustbuild)
r? @ghost
Require a value for configure --debuginfo-level
In `configure.py`, using the `o` function creates an enable/disable
boolean setting, and writes `true` or `false` in `config.toml`. However,
rustbuild is expecting to parse a `u32` debuginfo level. We can change
to the `v` function to have the options require a value.
Don't link mcjit/interpreter LLVM components
We don't use these. Drop related unused ExecutionEngine header uses.
As some drive-by cleanup drop the unused `EnableARMEHABI` global and remove an outdated version check for the hexagon component.
r? @alexcrichton
ci: Install clang on Windows through tarballs
Previously we used the executables built the LLVM project but these
executables are difficult to run in a CI environment, they can
accidentally pollute global state, etc. In testing some of the possible
4-core machine environments for Azure this step would frequently cause
issues.
To assuage these future issues and hopefully make builds slightly more
self-contained, this commit changes to install from a tarball instead.
The tarball isn't provided by LLVM itself, but we use the offical LLVM
installer to extract itself and then we pack up the LLVM installation
directory into the tarball.
Polonius: fix some cases of `killed` fact generation, and most of the `ui` test suite
Since basic Polonius functionality was re-enabled by @matthewjasper in #54468, some tests were still failing in the polonius compare-mode.
This PR fixes all but one test in the `ui` suite by:
- fixing some bugs in the fact generation code, related to the `killed` relation: Polonius would incorrectly reject some NLL-accepted code, because of these missing `killed` facts.
- ignoring some tests in the polonius compare-mode: a lot of those manually test the NLL or migrate mode, and the failures were mostly artifacts of the test revisions, e.g. that `-Z polonius` requires full NLLs. Some others were also both failing with NLL and succeeding with Polonius, which we can't encode in tests at the moment.
- blessing the output of some tests: whenever Polonius and NLL have basically the same errors, except for diagnostics differences, the Polonius output is blessed. Whenever we've advanced into a less experimental phase, we'll want to revisit these cases (much like we did on the NLL test suite last year) to specifically work on diagnostics.
Fact generation changes:
- we now kill loans on the destination place of `Call` terminators
- we now kill loans on the locals destroyed by `StorageDead`
- we now also handle assignments to projections: killing the loans on a either a deref-ed local, or the ones whose `borrowed_place` conflicts with the current place.
One failing test remains: an overflow during fact generation, on a case of polymorphic recursion (and which I'll continue investigating later).
This adds some tests for the fact generation changes, with some simple Polonius cases similar to the existing smoke tests, but also for some cases encountered in the wild (in the `rand` crate for example).
A more detailed write-up is available [here](https://hackmd.io/CjYB0fs4Q9CweyeTdKWyEg?view) with an explanation for each test failure, the steps taken to resolve it (as a commit in the current PR), NLL and Polonius outputs (and diff), etc.
Since they've worked on this before, and we've discussed some of these failures together:
r? @matthewjasper
Add binary dependencies to dep-info files
I'm not sure about the lack of incremental-tracking here, but since I'm pretty sure this runs on every compile anyway it might not matter? If there's a better place/way to get at the information I want, I'm happy to refactor the code to match.
r? @alexcrichton