Merge from rustc
This commit is contained in:
commit
eb3ccfd841
338 changed files with 9244 additions and 3352 deletions
|
|
@ -261,7 +261,7 @@ fn copy_self_contained_objects(
|
|||
// to using gcc from a glibc-targeting toolchain for linking.
|
||||
// To do that we have to distribute musl startup objects as a part of Rust toolchain
|
||||
// and link with them manually in the self-contained mode.
|
||||
if target.contains("musl") {
|
||||
if target.contains("musl") && !target.contains("unikraft") {
|
||||
let srcdir = builder.musl_libdir(target).unwrap_or_else(|| {
|
||||
panic!("Target {:?} does not have a \"musl-libdir\" key", target.triple)
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1085,13 +1085,6 @@ impl Step for Cargo {
|
|||
tarball.add_dir(etc.join("man"), "share/man/man1");
|
||||
tarball.add_legal_and_readme_to("share/doc/cargo");
|
||||
|
||||
for dirent in fs::read_dir(cargo.parent().unwrap()).expect("read_dir") {
|
||||
let dirent = dirent.expect("read dir entry");
|
||||
if dirent.file_name().to_str().expect("utf8").starts_with("cargo-credential-") {
|
||||
tarball.add_file(&dirent.path(), "libexec", 0o755);
|
||||
}
|
||||
}
|
||||
|
||||
Some(tarball.generate())
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ use crate::cache::{Interned, INTERNER};
|
|||
use crate::compile;
|
||||
use crate::config::{Config, TargetSelection};
|
||||
use crate::tool::{self, prepare_tool_cargo, SourceType, Tool};
|
||||
use crate::util::{symlink_dir, t, up_to_date};
|
||||
use crate::util::{dir_is_empty, symlink_dir, t, up_to_date};
|
||||
use crate::Mode;
|
||||
|
||||
macro_rules! submodule_helper {
|
||||
|
|
@ -197,11 +197,21 @@ impl Step for TheBook {
|
|||
let compiler = self.compiler;
|
||||
let target = self.target;
|
||||
|
||||
let absolute_path = builder.src.join(&relative_path);
|
||||
let redirect_path = absolute_path.join("redirects");
|
||||
if !absolute_path.exists()
|
||||
|| !redirect_path.exists()
|
||||
|| dir_is_empty(&absolute_path)
|
||||
|| dir_is_empty(&redirect_path)
|
||||
{
|
||||
eprintln!("Please checkout submodule: {}", relative_path.display());
|
||||
crate::exit!(1);
|
||||
}
|
||||
// build book
|
||||
builder.ensure(RustbookSrc {
|
||||
target,
|
||||
name: INTERNER.intern_str("book"),
|
||||
src: INTERNER.intern_path(builder.src.join(&relative_path)),
|
||||
src: INTERNER.intern_path(absolute_path.clone()),
|
||||
parent: Some(self),
|
||||
});
|
||||
|
||||
|
|
@ -210,7 +220,7 @@ impl Step for TheBook {
|
|||
builder.ensure(RustbookSrc {
|
||||
target,
|
||||
name: INTERNER.intern_string(format!("book/{}", edition)),
|
||||
src: INTERNER.intern_path(builder.src.join(&relative_path).join(edition)),
|
||||
src: INTERNER.intern_path(absolute_path.join(edition)),
|
||||
// There should only be one book that is marked as the parent for each target, so
|
||||
// treat the other editions as not having a parent.
|
||||
parent: Option::<Self>::None,
|
||||
|
|
@ -225,7 +235,7 @@ impl Step for TheBook {
|
|||
|
||||
// build the redirect pages
|
||||
let _guard = builder.msg_doc(compiler, "book redirect pages", target);
|
||||
for file in t!(fs::read_dir(builder.src.join(&relative_path).join("redirects"))) {
|
||||
for file in t!(fs::read_dir(redirect_path)) {
|
||||
let file = t!(file);
|
||||
let path = file.path();
|
||||
let path = path.to_str().unwrap();
|
||||
|
|
@ -884,19 +894,10 @@ tool_doc!(
|
|||
"-p",
|
||||
"cargo-credential",
|
||||
"-p",
|
||||
"cargo-credential-1password",
|
||||
"-p",
|
||||
"mdman",
|
||||
// FIXME: this trips a license check in tidy.
|
||||
// "-p",
|
||||
// "resolver-tests",
|
||||
// FIXME: we should probably document these, but they're different per-platform so we can't use `tool_doc`.
|
||||
// "-p",
|
||||
// "cargo-credential-gnome-secret",
|
||||
// "-p",
|
||||
// "cargo-credential-macos-keychain",
|
||||
// "-p",
|
||||
// "cargo-credential-wincred",
|
||||
]
|
||||
);
|
||||
tool_doc!(Tidy, "tidy", "src/tools/tidy", rustc_tool = false, ["-p", "tidy"]);
|
||||
|
|
|
|||
|
|
@ -36,7 +36,7 @@ use once_cell::sync::OnceCell;
|
|||
use crate::builder::Kind;
|
||||
use crate::config::{LlvmLibunwind, TargetSelection};
|
||||
use crate::util::{
|
||||
exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
|
||||
dir_is_empty, exe, libdir, mtime, output, run, run_suppressed, symlink_dir, try_run_suppressed,
|
||||
};
|
||||
|
||||
mod bolt;
|
||||
|
|
@ -131,6 +131,8 @@ const EXTRA_CHECK_CFGS: &[(Option<Mode>, &'static str, Option<&[&'static str]>)]
|
|||
(Some(Mode::Std), "freebsd13", None),
|
||||
(Some(Mode::Std), "backtrace_in_libstd", None),
|
||||
/* Extra values not defined in the built-in targets yet, but used in std */
|
||||
// #[cfg(bootstrap)]
|
||||
(Some(Mode::Std), "target_vendor", Some(&["unikraft"])),
|
||||
(Some(Mode::Std), "target_env", Some(&["libnx"])),
|
||||
// (Some(Mode::Std), "target_os", Some(&[])),
|
||||
// #[cfg(bootstrap)] mips32r6, mips64r6
|
||||
|
|
@ -535,10 +537,6 @@ impl Build {
|
|||
///
|
||||
/// `relative_path` should be relative to the root of the git repository, not an absolute path.
|
||||
pub(crate) fn update_submodule(&self, relative_path: &Path) {
|
||||
fn dir_is_empty(dir: &Path) -> bool {
|
||||
t!(std::fs::read_dir(dir)).next().is_none()
|
||||
}
|
||||
|
||||
if !self.config.submodules(&self.rust_info()) {
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ than building it.
|
|||
}
|
||||
|
||||
// Make sure musl-root is valid
|
||||
if target.contains("musl") {
|
||||
if target.contains("musl") && !target.contains("unikraft") {
|
||||
// If this is a native target (host is also musl) and no musl-root is given,
|
||||
// fall back to the system toolchain in /usr before giving up
|
||||
if build.musl_root(*target).is_none() && build.config.build == *target {
|
||||
|
|
|
|||
|
|
@ -558,39 +558,6 @@ impl Step for Cargo {
|
|||
allow_features: "",
|
||||
})
|
||||
.expect("expected to build -- essential tool");
|
||||
|
||||
let build_cred = |name, path| {
|
||||
// These credential helpers are currently experimental.
|
||||
// Any build failures will be ignored.
|
||||
let _ = builder.ensure(ToolBuild {
|
||||
compiler: self.compiler,
|
||||
target: self.target,
|
||||
tool: name,
|
||||
mode: Mode::ToolRustc,
|
||||
path,
|
||||
is_optional_tool: true,
|
||||
source_type: SourceType::Submodule,
|
||||
extra_features: Vec::new(),
|
||||
allow_features: "",
|
||||
});
|
||||
};
|
||||
|
||||
if self.target.contains("windows") {
|
||||
build_cred(
|
||||
"cargo-credential-wincred",
|
||||
"src/tools/cargo/credential/cargo-credential-wincred",
|
||||
);
|
||||
}
|
||||
if self.target.contains("apple-darwin") {
|
||||
build_cred(
|
||||
"cargo-credential-macos-keychain",
|
||||
"src/tools/cargo/credential/cargo-credential-macos-keychain",
|
||||
);
|
||||
}
|
||||
build_cred(
|
||||
"cargo-credential-1password",
|
||||
"src/tools/cargo/credential/cargo-credential-1password",
|
||||
);
|
||||
cargo_bin_path
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -493,3 +493,7 @@ pub fn lld_flag_no_threads(is_windows: bool) -> &'static str {
|
|||
});
|
||||
if is_windows { windows } else { other }
|
||||
}
|
||||
|
||||
pub fn dir_is_empty(dir: &Path) -> bool {
|
||||
t!(std::fs::read_dir(dir)).next().is_none()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,6 +42,8 @@
|
|||
- [sparc-unknown-none-elf](./platform-support/sparc-unknown-none-elf.md)
|
||||
- [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md)
|
||||
- [\*-nto-qnx-\*](platform-support/nto-qnx.md)
|
||||
- [*-unikraft-linux-musl](platform-support/unikraft-linux-musl.md)
|
||||
- [*-unknown-hermit](platform-support/hermit.md)
|
||||
- [\*-unknown-netbsd\*](platform-support/netbsd.md)
|
||||
- [*-unknown-openbsd](platform-support/openbsd.md)
|
||||
- [\*-unknown-uefi](platform-support/unknown-uefi.md)
|
||||
|
|
|
|||
|
|
@ -223,7 +223,7 @@ target | std | host | notes
|
|||
[`aarch64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARM64 OpenHarmony |
|
||||
[`aarch64-unknown-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | ARM64 QNX Neutrino 7.1 RTOS |
|
||||
`aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD
|
||||
`aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore
|
||||
[`aarch64-unknown-hermit`](platform-support/hermit.md) | ✓ | | ARM64 Hermit
|
||||
`aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI)
|
||||
[`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD
|
||||
[`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD
|
||||
|
|
@ -303,6 +303,7 @@ target | std | host | notes
|
|||
[`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA)
|
||||
[`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
|
||||
[`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF
|
||||
[`riscv64gc-unknown-hermit`](platform-support/hermit.md) | ✓ | | RISC-V Hermit
|
||||
`riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD
|
||||
`riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia
|
||||
`riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0)
|
||||
|
|
@ -325,9 +326,10 @@ target | std | host | notes
|
|||
[`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ |
|
||||
`x86_64-pc-windows-msvc` | * | | 64-bit Windows XP support
|
||||
`x86_64-sun-solaris` | ? | | Deprecated target for 64-bit Solaris 10/11, illumos
|
||||
[`x86_64-unikraft-linux-musl`](platform-support/unikraft-linux-musl.md) | ✓ | | 64-bit Unikraft with musl
|
||||
`x86_64-unknown-dragonfly` | ✓ | ✓ | 64-bit DragonFlyBSD
|
||||
`x86_64-unknown-haiku` | ✓ | ✓ | 64-bit Haiku
|
||||
`x86_64-unknown-hermit` | ✓ | | HermitCore
|
||||
[`x86_64-unknown-hermit`](platform-support/hermit.md) | ✓ | | x86_64 Hermit
|
||||
`x86_64-unknown-l4re-uclibc` | ? | |
|
||||
[`x86_64-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | x86_64 OpenHarmony |
|
||||
[`x86_64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 64-bit OpenBSD
|
||||
|
|
|
|||
75
src/doc/rustc/src/platform-support/hermit.md
Normal file
75
src/doc/rustc/src/platform-support/hermit.md
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
# `*-unknown-hermit`
|
||||
|
||||
**Tier: 3**
|
||||
|
||||
The [Hermit] unikernel target allows compiling your applications into self-contained, specialized unikernel images that can be run in small virtual machines.
|
||||
|
||||
[Hermit]: https://github.com/hermitcore
|
||||
|
||||
Target triplets available so far:
|
||||
|
||||
- `x86_64-unknown-hermit`
|
||||
- `aarch64-unknown-hermit`
|
||||
- `riscv64gc-unknown-hermit`
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- Stefan Lankes ([@stlankes](https://github.com/stlankes))
|
||||
- Martin Kröning ([@mkroening](https://github.com/mkroening))
|
||||
|
||||
## Requirements
|
||||
|
||||
These targets only support cross-compilation.
|
||||
The targets do support std.
|
||||
|
||||
When building binaries for this target, the Hermit unikernel is built from scratch.
|
||||
The application developer themselves specializes the target and sets corresponding expectations.
|
||||
|
||||
The Hermit targets follow Linux's `extern "C"` calling convention.
|
||||
|
||||
Hermit binaries have the ELF format.
|
||||
|
||||
## Building the target
|
||||
|
||||
You can build Rust with support for the targets by adding it to the `target` list in `config.toml`.
|
||||
To run the Hermit build scripts, you also have to enable your host target.
|
||||
The build scripts rely on `llvm-tools` and binaries are linked using `rust-lld`, so those have to be enabled as well.
|
||||
|
||||
```toml
|
||||
[build]
|
||||
build-stage = 1
|
||||
target = [
|
||||
"<HOST_TARGET>",
|
||||
"x86_64-unknown-hermit",
|
||||
"aarch64-unknown-hermit",
|
||||
"riscv64gc-unknown-hermit",
|
||||
]
|
||||
|
||||
[rust]
|
||||
lld = true
|
||||
llvm-tools = true
|
||||
```
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
Rust does not yet ship pre-compiled artifacts for these targets.
|
||||
To compile for these targets, you will either need to build Rust with the targets enabled
|
||||
(see “Building the targets” above), or build your own copy of `core` by using `build-std` or similar.
|
||||
|
||||
Building Rust programs can be done by following the tutorial in our starter application [rusty-demo].
|
||||
|
||||
[rusty-demo]: https://github.com/hermitcore/rusty-demo
|
||||
|
||||
## Testing
|
||||
|
||||
The targets support running binaries in the form of self-contained unikernel images.
|
||||
These images can be chainloaded by Hermit's [loader] or hypervisor ([Uhyve]).
|
||||
QEMU can be used to boot Hermit binaries using the loader on any architecture.
|
||||
The targets do not support running the Rust test suite.
|
||||
|
||||
[loader]: https://github.com/hermitcore/rusty-loader
|
||||
[Uhyve]: https://github.com/hermitcore/uhyve
|
||||
|
||||
## Cross-compilation toolchains and C code
|
||||
|
||||
The targets do not yet support C code and Rust code at the same time.
|
||||
|
|
@ -17,13 +17,6 @@ Rust for bare-metal 32-bit SPARC V7 and V8 systems, e.g. the Gaisler LEON3.
|
|||
This target is cross-compiled. There is no support for `std`. There is no
|
||||
default allocator, but it's possible to use `alloc` by supplying an allocator.
|
||||
|
||||
This allows the generated code to run in environments, such as kernels, which
|
||||
may need to avoid the use of such registers or which may have special
|
||||
considerations about the use of such registers (e.g. saving and restoring them
|
||||
to avoid breaking userspace code using the same registers). You can change code
|
||||
generation to use additional CPU features via the `-C target-feature=` codegen
|
||||
options to rustc, or via the `#[target_feature]` mechanism within Rust code.
|
||||
|
||||
By default, code generated with this target should run on any `SPARC` hardware;
|
||||
enabling additional target features may raise this baseline.
|
||||
|
||||
|
|
@ -46,20 +39,31 @@ list in `config.toml`:
|
|||
```toml
|
||||
[build]
|
||||
build-stage = 1
|
||||
target = ["sparc-unknown-none-elf"]
|
||||
host = ["<target for your host>"]
|
||||
target = ["<target for your host>", "sparc-unknown-none-elf"]
|
||||
```
|
||||
|
||||
Replace `<target for your host>` with `x86_64-unknown-linux-gnu` or whatever
|
||||
else is appropriate for your host machine.
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
```text
|
||||
To build with this target, pass it to the `--target` argument, like:
|
||||
|
||||
```console
|
||||
cargo build --target sparc-unknown-none-elf
|
||||
```
|
||||
|
||||
This target uses GCC as a linker, and so you will need an appropriate GCC
|
||||
compatible `sparc-unknown-none` toolchain.
|
||||
compatible `sparc-unknown-none` toolchain. The default linker binary is
|
||||
`sparc-elf-gcc`, but you can override this in your project configuration, as
|
||||
follows:
|
||||
|
||||
The default linker name is `sparc-elf-gcc`, but you can override this in your
|
||||
project configuration.
|
||||
`.cargo/config.toml`:
|
||||
```toml
|
||||
[target.sparc-unknown-none-elf]
|
||||
linker = "sparc-custom-elf-gcc"
|
||||
```
|
||||
|
||||
## Testing
|
||||
|
||||
|
|
@ -81,6 +85,26 @@ something like:
|
|||
linker = "sparc-gaisler-elf-gcc"
|
||||
runner = "tsim-leon3"
|
||||
|
||||
[build]
|
||||
target = ["sparc-unknown-none-elf"]
|
||||
rustflags = "-Ctarget-cpu=leon3"
|
||||
```
|
||||
|
||||
With this configuration, running `cargo run` will compile your code for the
|
||||
SPARC V8 compatible Gaisler Leon3 processor and then start the `tsim-leon3`
|
||||
simulator. The `libcore` was pre-compiled as part of the `rustc` compilation
|
||||
process using the SPARC V7 baseline, but if you are using a nightly toolchain
|
||||
you can use the
|
||||
[`-Z build-std=core`](https://doc.rust-lang.org/cargo/reference/unstable.html#build-std)
|
||||
option to rebuild `libcore` from source. This may be useful if you want to
|
||||
compile it for SPARC V8 and take advantage of the extra instructions.
|
||||
|
||||
`.cargo/config.toml`:
|
||||
```toml
|
||||
[target.sparc-unknown-none-elf]
|
||||
linker = "sparc-gaisler-elf-gcc"
|
||||
runner = "tsim-leon3"
|
||||
|
||||
[build]
|
||||
target = ["sparc-unknown-none-elf"]
|
||||
rustflags = "-Ctarget-cpu=leon3"
|
||||
|
|
@ -89,16 +113,16 @@ rustflags = "-Ctarget-cpu=leon3"
|
|||
build-std = ["core"]
|
||||
```
|
||||
|
||||
With this configuration, running `cargo run` will compile your code for the
|
||||
SPARC V8 compatible Gaisler Leon3 processor and then start the `tsim-leon3`
|
||||
simulator. Once the simulator is running, simply enter the command
|
||||
`run` to start the code executing in the simulator.
|
||||
Either way, once the simulator is running, simply enter the command `run` to
|
||||
start the code executing in the simulator.
|
||||
|
||||
The default C toolchain libraries are linked in, so with the Gaisler [BCC2]
|
||||
toolchain, and using its default Leon3 BSP, you can use call the C `putchar`
|
||||
function and friends to output to the simulator console.
|
||||
function and friends to output to the simulator console. The default linker
|
||||
script is also appropriate for the Leon3 simulator, so no linker script is
|
||||
required.
|
||||
|
||||
Here's a complete example:
|
||||
Here's a complete example using the above config file:
|
||||
|
||||
```rust,ignore (cannot-test-this-because-it-assumes-special-libc-functions)
|
||||
#![no_std]
|
||||
|
|
|
|||
67
src/doc/rustc/src/platform-support/unikraft-linux-musl.md
Normal file
67
src/doc/rustc/src/platform-support/unikraft-linux-musl.md
Normal file
|
|
@ -0,0 +1,67 @@
|
|||
# `*-unikraft-linux-musl`
|
||||
|
||||
**Tier: 3**
|
||||
|
||||
Targets for the [Unikraft] Unikernel Development Kit (with musl).
|
||||
|
||||
[Unikraft]: https://unikraft.org/
|
||||
|
||||
Target triplets available so far:
|
||||
|
||||
- `x86_64-unikraft-linux-musl`
|
||||
|
||||
## Target maintainers
|
||||
|
||||
- Martin Kröning ([@mkroening](https://github.com/mkroening))
|
||||
|
||||
## Requirements
|
||||
|
||||
These targets only support cross-compilation.
|
||||
The targets do support std.
|
||||
|
||||
Unikraft pretends to behave exactly like Linux.
|
||||
How much of that functionality is available depends on the individual unikernel configuration.
|
||||
For example, the basic Unikraft + musl config does not support `poll` or networking out of the box.
|
||||
That functionality requires enabling [`LIBPOSIX_EVENT`] or [lwIP] respectively.
|
||||
|
||||
[`LIBPOSIX_EVENT`]: https://github.com/unikraft/unikraft/blob/RELEASE-0.13.1/lib/posix-event/Config.uk
|
||||
[lwIP]: https://github.com/unikraft/lib-lwip
|
||||
|
||||
The Unikraft targets follow Linux's `extern "C"` calling convention.
|
||||
|
||||
For these targets, `rustc` does not perform the final linking step.
|
||||
Instead, the Unikraft build system will produce the final Unikernel image for the selected platform (e.g., KVM, Linux user space, and Xen).
|
||||
|
||||
## Building the targets
|
||||
|
||||
You can build Rust with support for the targets by adding it to the `target` list in `config.toml`:
|
||||
|
||||
```toml
|
||||
[build]
|
||||
build-stage = 1
|
||||
target = [ "x86_64-unikraft-linux-musl" ]
|
||||
```
|
||||
|
||||
## Building Rust programs
|
||||
|
||||
Rust does not yet ship pre-compiled artifacts for these targets.
|
||||
To compile for these targets, you will either need to build Rust with the targets enabled
|
||||
(see “Building the targets” above), or build your own copy of `core` by using `build-std` or similar.
|
||||
|
||||
Linking requires a [KraftKit] shim.
|
||||
See [unikraft/kraftkit#612] for more information.
|
||||
|
||||
[KraftKit]: https://github.com/unikraft/kraftkit
|
||||
[unikraft/kraftkit#612]: https://github.com/unikraft/kraftkit/issues/612
|
||||
|
||||
## Testing
|
||||
|
||||
The targets do support running binaries in the form of unikernel images.
|
||||
How the unikernel image is run depends on the specific platform (e.g., KVM, Linux user space, and Xen).
|
||||
The targets do not support running the Rust test suite.
|
||||
|
||||
## Cross-compilation toolchains and C code
|
||||
|
||||
The targets do support C code.
|
||||
To build compatible C code, you have to use the same compiler and flags as does the Unikraft build system for your specific configuration.
|
||||
The easiest way to achieve that, is to build the C code with the Unikraft build system when building your unikernel image.
|
||||
|
|
@ -121,7 +121,8 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> {
|
|||
.tcx
|
||||
.associated_items(impl_def_id)
|
||||
.in_definition_order()
|
||||
.map(|x| clean_middle_assoc_item(x, cx))
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| clean_middle_assoc_item(item, cx))
|
||||
.collect::<Vec<_>>(),
|
||||
polarity: ty::ImplPolarity::Positive,
|
||||
kind: ImplKind::Blanket(Box::new(clean_middle_ty(
|
||||
|
|
|
|||
|
|
@ -216,6 +216,7 @@ pub(crate) fn build_external_trait(cx: &mut DocContext<'_>, did: DefId) -> clean
|
|||
.tcx
|
||||
.associated_items(did)
|
||||
.in_definition_order()
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.map(|item| clean_middle_assoc_item(item, cx))
|
||||
.collect();
|
||||
|
||||
|
|
@ -459,6 +460,7 @@ pub(crate) fn build_impl(
|
|||
None => (
|
||||
tcx.associated_items(did)
|
||||
.in_definition_order()
|
||||
.filter(|item| !item.is_impl_trait_in_trait())
|
||||
.filter(|item| {
|
||||
// If this is a trait impl, filter out associated items whose corresponding item
|
||||
// in the associated trait is marked `doc(hidden)`.
|
||||
|
|
|
|||
|
|
@ -2643,15 +2643,12 @@ fn clean_extern_crate<'tcx>(
|
|||
}
|
||||
}
|
||||
|
||||
// FIXME: using `from_def_id_and_kind` breaks `rustdoc/masked` for some reason
|
||||
vec![Item {
|
||||
name: Some(name),
|
||||
attrs: Box::new(Attributes::from_ast(attrs)),
|
||||
item_id: crate_def_id.into(),
|
||||
kind: Box::new(ExternCrateItem { src: orig_name }),
|
||||
cfg: attrs.cfg(cx.tcx, &cx.cache.hidden_cfg),
|
||||
inline_stmt_id: Some(krate_owner_def_id),
|
||||
}]
|
||||
vec![Item::from_def_id_and_parts(
|
||||
krate_owner_def_id,
|
||||
Some(name),
|
||||
ExternCrateItem { src: orig_name },
|
||||
cx,
|
||||
)]
|
||||
}
|
||||
|
||||
fn clean_use_statement<'tcx>(
|
||||
|
|
|
|||
|
|
@ -38,11 +38,15 @@ pub(crate) fn krate(cx: &mut DocContext<'_>) -> Crate {
|
|||
for it in &module.items {
|
||||
// `compiler_builtins` should be masked too, but we can't apply
|
||||
// `#[doc(masked)]` to the injected `extern crate` because it's unstable.
|
||||
if it.is_extern_crate()
|
||||
&& (it.attrs.has_doc_flag(sym::masked)
|
||||
|| cx.tcx.is_compiler_builtins(it.item_id.krate()))
|
||||
{
|
||||
if cx.tcx.is_compiler_builtins(it.item_id.krate()) {
|
||||
cx.cache.masked_crates.insert(it.item_id.krate());
|
||||
} else if it.is_extern_crate()
|
||||
&& it.attrs.has_doc_flag(sym::masked)
|
||||
&& let Some(def_id) = it.item_id.as_def_id()
|
||||
&& let Some(local_def_id) = def_id.as_local()
|
||||
&& let Some(cnum) = cx.tcx.extern_mod_stmt_cnum(local_def_id)
|
||||
{
|
||||
cx.cache.masked_crates.insert(cnum);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ use rustc_data_structures::captures::Captures;
|
|||
use rustc_data_structures::fx::FxHashSet;
|
||||
use rustc_hir as hir;
|
||||
use rustc_hir::def::DefKind;
|
||||
use rustc_hir::def_id::DefId;
|
||||
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
|
||||
use rustc_metadata::creader::{CStore, LoadedMacro};
|
||||
use rustc_middle::ty;
|
||||
use rustc_middle::ty::TyCtxt;
|
||||
|
|
@ -662,6 +662,14 @@ pub(crate) fn href_with_root_path(
|
|||
// documented on their parent's page
|
||||
tcx.parent(did)
|
||||
}
|
||||
DefKind::ExternCrate => {
|
||||
// Link to the crate itself, not the `extern crate` item.
|
||||
if let Some(local_did) = did.as_local() {
|
||||
tcx.extern_mod_stmt_cnum(local_did).unwrap_or(LOCAL_CRATE).as_def_id()
|
||||
} else {
|
||||
did
|
||||
}
|
||||
}
|
||||
_ => did,
|
||||
};
|
||||
let cache = cx.cache();
|
||||
|
|
|
|||
|
|
@ -1678,11 +1678,11 @@ fn render_impl(
|
|||
rendering_params: ImplRenderingParameters,
|
||||
) {
|
||||
for trait_item in &t.items {
|
||||
// Skip over any default trait items that are impossible to call
|
||||
// Skip over any default trait items that are impossible to reference
|
||||
// (e.g. if it has a `Self: Sized` bound on an unsized type).
|
||||
if let Some(impl_def_id) = parent.item_id.as_def_id()
|
||||
&& let Some(trait_item_def_id) = trait_item.item_id.as_def_id()
|
||||
&& cx.tcx().is_impossible_method((impl_def_id, trait_item_def_id))
|
||||
&& cx.tcx().is_impossible_associated_item((impl_def_id, trait_item_def_id))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_hir::def::{DefKind, Namespace, PerNS};
|
|||
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
|
||||
use rustc_hir::Mutability;
|
||||
use rustc_middle::ty::{Ty, TyCtxt};
|
||||
use rustc_middle::{bug, ty};
|
||||
use rustc_middle::{bug, span_bug, ty};
|
||||
use rustc_resolve::rustdoc::{has_primitive_or_keyword_docs, prepare_to_doc_link_resolution};
|
||||
use rustc_resolve::rustdoc::{strip_generics_from_path, MalformedGenerics};
|
||||
use rustc_session::lint::Lint;
|
||||
|
|
@ -402,7 +402,12 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
|
|||
// `doc_link_resolutions` is missing a `path_str`, that means that there are valid links
|
||||
// that are being missed. To fix the ICE, change
|
||||
// `rustc_resolve::rustdoc::attrs_to_preprocessed_links` to cache the link.
|
||||
.unwrap_or_else(|| panic!("no resolution for {:?} {:?} {:?}", path_str, ns, module_id))
|
||||
.unwrap_or_else(|| {
|
||||
span_bug!(
|
||||
self.cx.tcx.def_span(item_id),
|
||||
"no resolution for {path_str:?} {ns:?} {module_id:?}",
|
||||
)
|
||||
})
|
||||
.and_then(|res| res.try_into().ok())
|
||||
.or_else(|| resolve_primitive(path_str, ns));
|
||||
debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns);
|
||||
|
|
@ -963,6 +968,7 @@ fn preprocessed_markdown_links(s: &str) -> Vec<PreprocessedMarkdownLink> {
|
|||
}
|
||||
|
||||
impl LinkCollector<'_, '_> {
|
||||
#[instrument(level = "debug", skip_all)]
|
||||
fn resolve_links(&mut self, item: &Item) {
|
||||
if !self.cx.render_options.document_private
|
||||
&& let Some(def_id) = item.item_id.as_def_id()
|
||||
|
|
|
|||
|
|
@ -122,6 +122,7 @@ static TARGETS: &[&str] = &[
|
|||
"riscv32imac-unknown-none-elf",
|
||||
"riscv32gc-unknown-linux-gnu",
|
||||
"riscv64imac-unknown-none-elf",
|
||||
"riscv64gc-unknown-hermit",
|
||||
"riscv64gc-unknown-none-elf",
|
||||
"riscv64gc-unknown-linux-gnu",
|
||||
"s390x-unknown-linux-gnu",
|
||||
|
|
@ -147,6 +148,7 @@ static TARGETS: &[&str] = &[
|
|||
"x86_64-pc-windows-msvc",
|
||||
"x86_64-sun-solaris",
|
||||
"x86_64-pc-solaris",
|
||||
"x86_64-unikraft-linux-musl",
|
||||
"x86_64-unknown-freebsd",
|
||||
"x86_64-unknown-illumos",
|
||||
"x86_64-unknown-linux-gnu",
|
||||
|
|
|
|||
|
|
@ -36,25 +36,26 @@ impl CiEnv {
|
|||
}
|
||||
|
||||
pub mod gha {
|
||||
use std::sync::atomic::{AtomicBool, Ordering};
|
||||
use std::sync::Mutex;
|
||||
|
||||
static GROUP_ACTIVE: AtomicBool = AtomicBool::new(false);
|
||||
static ACTIVE_GROUPS: Mutex<Vec<String>> = Mutex::new(Vec::new());
|
||||
|
||||
/// All github actions log messages from this call to the Drop of the return value
|
||||
/// will be grouped and hidden by default in logs. Note that nesting these does
|
||||
/// not really work.
|
||||
/// will be grouped and hidden by default in logs. Note that since github actions doesn't
|
||||
/// support group nesting, any active group will be first finished when a subgroup is started,
|
||||
/// and then re-started when the subgroup finishes.
|
||||
#[track_caller]
|
||||
pub fn group(name: impl std::fmt::Display) -> Group {
|
||||
if std::env::var_os("GITHUB_ACTIONS").is_some() {
|
||||
eprintln!("::group::{name}");
|
||||
} else {
|
||||
eprintln!("{name}")
|
||||
let mut groups = ACTIVE_GROUPS.lock().unwrap();
|
||||
|
||||
// A group is currently active. End it first to avoid nesting.
|
||||
if !groups.is_empty() {
|
||||
end_group();
|
||||
}
|
||||
// https://github.com/actions/toolkit/issues/1001
|
||||
assert!(
|
||||
!GROUP_ACTIVE.swap(true, Ordering::Relaxed),
|
||||
"nested groups are not supported by GHA!"
|
||||
);
|
||||
|
||||
let name = name.to_string();
|
||||
start_group(&name);
|
||||
groups.push(name);
|
||||
Group(())
|
||||
}
|
||||
|
||||
|
|
@ -64,13 +65,36 @@ pub mod gha {
|
|||
|
||||
impl Drop for Group {
|
||||
fn drop(&mut self) {
|
||||
if std::env::var_os("GITHUB_ACTIONS").is_some() {
|
||||
eprintln!("::endgroup::");
|
||||
end_group();
|
||||
|
||||
let mut groups = ACTIVE_GROUPS.lock().unwrap();
|
||||
// Remove the current group
|
||||
groups.pop();
|
||||
|
||||
// If there was some previous group, restart it
|
||||
if is_in_gha() {
|
||||
if let Some(name) = groups.last() {
|
||||
start_group(format!("{name} (continued)"));
|
||||
}
|
||||
}
|
||||
assert!(
|
||||
GROUP_ACTIVE.swap(false, Ordering::Relaxed),
|
||||
"group dropped but no group active!"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
fn start_group(name: impl std::fmt::Display) {
|
||||
if is_in_gha() {
|
||||
eprintln!("::group::{name}");
|
||||
} else {
|
||||
eprintln!("{name}")
|
||||
}
|
||||
}
|
||||
|
||||
fn end_group() {
|
||||
if is_in_gha() {
|
||||
eprintln!("::endgroup::");
|
||||
}
|
||||
}
|
||||
|
||||
fn is_in_gha() -> bool {
|
||||
std::env::var_os("GITHUB_ACTIONS").is_some()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
Subproject commit 1b15556767f4b78a64e868eedf4073c423f02b93
|
||||
Subproject commit 7ac9416d82cd4fc5e707c9ec3574d22dff6466e5
|
||||
|
|
@ -328,7 +328,7 @@ impl<'tcx> LateLintPass<'tcx> for StringLitAsBytes {
|
|||
{
|
||||
// Don't lint. Byte strings produce `&[u8; N]` whereas `as_bytes()` produces
|
||||
// `&[u8]`. This change would prevent matching with different sized slices.
|
||||
} else {
|
||||
} else if !callsite.starts_with("env!") {
|
||||
span_lint_and_sugg(
|
||||
cx,
|
||||
STRING_LIT_AS_BYTES,
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ use rustc_middle::mir::{
|
|||
Body, CastKind, NonDivergingIntrinsic, NullOp, Operand, Place, ProjectionElem, Rvalue, Statement, StatementKind,
|
||||
Terminator, TerminatorKind,
|
||||
};
|
||||
use rustc_middle::traits::{ImplSource, ObligationCause};
|
||||
use rustc_middle::traits::{ImplSource, ObligationCause, BuiltinImplSource};
|
||||
use rustc_middle::ty::adjustment::PointerCoercion;
|
||||
use rustc_middle::ty::{self, BoundConstness, GenericArgKind, TraitRef, Ty, TyCtxt};
|
||||
use rustc_semver::RustcVersion;
|
||||
|
|
@ -411,7 +411,7 @@ fn is_ty_const_destruct<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, body: &Body<'tcx>
|
|||
|
||||
if !matches!(
|
||||
impl_src,
|
||||
ImplSource::Builtin(_) | ImplSource::Param(_, ty::BoundConstness::ConstIfConst)
|
||||
ImplSource::Builtin(BuiltinImplSource::Misc, _) | ImplSource::Param(ty::BoundConstness::ConstIfConst, _)
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ pub fn positives(mut a: usize, b: &mut u32, mut s: S) {
|
|||
*b = *b;
|
||||
s = s;
|
||||
s.a = s.a;
|
||||
s.b[10] = s.b[5 + 5];
|
||||
s.b[9] = s.b[5 + 4];
|
||||
s.c[0][1] = s.c[0][1];
|
||||
s.b[a] = s.b[a];
|
||||
*s.e = *s.e;
|
||||
|
|
|
|||
|
|
@ -24,11 +24,11 @@ error: self-assignment of `s.a` to `s.a`
|
|||
LL | s.a = s.a;
|
||||
| ^^^^^^^^^
|
||||
|
||||
error: self-assignment of `s.b[5 + 5]` to `s.b[10]`
|
||||
error: self-assignment of `s.b[5 + 4]` to `s.b[9]`
|
||||
--> $DIR/self_assignment.rs:17:5
|
||||
|
|
||||
LL | s.b[10] = s.b[5 + 5];
|
||||
| ^^^^^^^^^^^^^^^^^^^^
|
||||
LL | s.b[9] = s.b[5 + 4];
|
||||
| ^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
error: self-assignment of `s.c[0][1]` to `s.c[0][1]`
|
||||
--> $DIR/self_assignment.rs:18:5
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ use std::io::BufReader;
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::process::Command;
|
||||
|
||||
use build_helper::ci::CiEnv;
|
||||
use tracing::*;
|
||||
|
||||
use crate::common::{Config, Debugger, FailMode, Mode, PassMode};
|
||||
|
|
@ -298,13 +297,6 @@ impl TestProps {
|
|||
/// `//[foo]`), then the property is ignored unless `cfg` is
|
||||
/// `Some("foo")`.
|
||||
fn load_from(&mut self, testfile: &Path, cfg: Option<&str>, config: &Config) {
|
||||
// In CI, we've sometimes encountered non-determinism related to truncating very long paths.
|
||||
// Set a consistent (short) prefix to avoid issues, but only in CI to avoid regressing the
|
||||
// contributor experience.
|
||||
if CiEnv::is_ci() {
|
||||
self.remap_src_base = config.mode == Mode::Ui && !config.suite.contains("rustdoc");
|
||||
}
|
||||
|
||||
let mut has_edition = false;
|
||||
if !testfile.is_dir() {
|
||||
let file = File::open(testfile).unwrap();
|
||||
|
|
|
|||
|
|
@ -2330,6 +2330,7 @@ impl<'test> TestCx<'test> {
|
|||
// Hide line numbers to reduce churn
|
||||
rustc.arg("-Zui-testing");
|
||||
rustc.arg("-Zdeduplicate-diagnostics=no");
|
||||
rustc.arg("-Zwrite-long-types-to-disk=no");
|
||||
// FIXME: use this for other modes too, for perf?
|
||||
rustc.arg("-Cstrip=debuginfo");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -928,13 +928,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
impl<'ecx, 'mir, 'tcx> ValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
for RetagVisitor<'ecx, 'mir, 'tcx>
|
||||
{
|
||||
type V = PlaceTy<'tcx, Provenance>;
|
||||
|
||||
#[inline(always)]
|
||||
fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
|
||||
fn ecx(&self) -> &MiriInterpCx<'mir, 'tcx> {
|
||||
self.ecx
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -413,13 +413,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(())
|
||||
}
|
||||
}
|
||||
impl<'ecx, 'mir, 'tcx> MutValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
impl<'ecx, 'mir, 'tcx> ValueVisitor<'mir, 'tcx, MiriMachine<'mir, 'tcx>>
|
||||
for RetagVisitor<'ecx, 'mir, 'tcx>
|
||||
{
|
||||
type V = PlaceTy<'tcx, Provenance>;
|
||||
|
||||
#[inline(always)]
|
||||
fn ecx(&mut self) -> &mut MiriInterpCx<'mir, 'tcx> {
|
||||
fn ecx(&self) -> &MiriInterpCx<'mir, 'tcx> {
|
||||
self.ecx
|
||||
}
|
||||
|
||||
|
|
@ -578,14 +578,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
/// I.e. input is what you get from the visitor upon encountering an `adt` that is `Unique`,
|
||||
/// and output can be used by `retag_ptr_inplace`.
|
||||
fn inner_ptr_of_unique<'tcx>(
|
||||
ecx: &mut MiriInterpCx<'_, 'tcx>,
|
||||
ecx: &MiriInterpCx<'_, 'tcx>,
|
||||
place: &PlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
// Follows the same layout as `interpret/visitor.rs:walk_value` for `Box` in
|
||||
// `rustc_const_eval`, just with one fewer layer.
|
||||
// Here we have a `Unique(NonNull(*mut), PhantomData)`
|
||||
assert_eq!(place.layout.fields.count(), 2, "Unique must have exactly 2 fields");
|
||||
let (nonnull, phantom) = (ecx.place_field(place, 0)?, ecx.place_field(place, 1)?);
|
||||
let (nonnull, phantom) = (ecx.project_field(place, 0)?, ecx.project_field(place, 1)?);
|
||||
assert!(
|
||||
phantom.layout.ty.ty_adt_def().is_some_and(|adt| adt.is_phantom_data()),
|
||||
"2nd field of `Unique` should be `PhantomData` but is `{:?}`",
|
||||
|
|
@ -593,7 +593,7 @@ fn inner_ptr_of_unique<'tcx>(
|
|||
);
|
||||
// Now down to `NonNull(*mut)`
|
||||
assert_eq!(nonnull.layout.fields.count(), 1, "NonNull must have exactly 1 field");
|
||||
let ptr = ecx.place_field(&nonnull, 0)?;
|
||||
let ptr = ecx.project_field(&nonnull, 0)?;
|
||||
// Finally a plain `*mut`
|
||||
Ok(ptr)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -320,7 +320,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||
))?;
|
||||
let argvs_place = ecx.allocate(argvs_layout, MiriMemoryKind::Machine.into())?;
|
||||
for (idx, arg) in argvs.into_iter().enumerate() {
|
||||
let place = ecx.mplace_field(&argvs_place, idx)?;
|
||||
let place = ecx.project_field(&argvs_place, idx)?;
|
||||
ecx.write_immediate(arg, &place.into())?;
|
||||
}
|
||||
ecx.mark_immutable(&argvs_place);
|
||||
|
|
@ -354,7 +354,7 @@ pub fn create_ecx<'mir, 'tcx: 'mir>(
|
|||
ecx.machine.cmd_line = Some(*cmd_place);
|
||||
// Store the UTF-16 string. We just allocated so we know the bounds are fine.
|
||||
for (idx, &c) in cmd_utf16.iter().enumerate() {
|
||||
let place = ecx.mplace_field(&cmd_place, idx)?;
|
||||
let place = ecx.project_field(&cmd_place, idx)?;
|
||||
ecx.write_scalar(Scalar::from_u16(c), &place.into())?;
|
||||
}
|
||||
ecx.mark_immutable(&cmd_place);
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ use log::trace;
|
|||
|
||||
use rustc_hir::def::{DefKind, Namespace};
|
||||
use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_middle::mir;
|
||||
use rustc_middle::ty::{
|
||||
self,
|
||||
|
|
@ -17,7 +18,7 @@ use rustc_middle::ty::{
|
|||
List, TyCtxt,
|
||||
};
|
||||
use rustc_span::{def_id::CrateNum, sym, Span, Symbol};
|
||||
use rustc_target::abi::{Align, FieldsShape, Size, Variants};
|
||||
use rustc_target::abi::{Align, FieldIdx, FieldsShape, Size, Variants};
|
||||
use rustc_target::spec::abi::Abi;
|
||||
|
||||
use rand::RngCore;
|
||||
|
|
@ -229,20 +230,20 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
this.layout_of(ty).unwrap()
|
||||
}
|
||||
|
||||
/// Project to the given *named* field of the mplace (which must be a struct or union type).
|
||||
fn mplace_field_named(
|
||||
/// Project to the given *named* field (which must be a struct or union type).
|
||||
fn project_field_named<P: Projectable<'mir, 'tcx, Provenance>>(
|
||||
&self,
|
||||
mplace: &MPlaceTy<'tcx, Provenance>,
|
||||
base: &P,
|
||||
name: &str,
|
||||
) -> InterpResult<'tcx, MPlaceTy<'tcx, Provenance>> {
|
||||
) -> InterpResult<'tcx, P> {
|
||||
let this = self.eval_context_ref();
|
||||
let adt = mplace.layout.ty.ty_adt_def().unwrap();
|
||||
let adt = base.layout().ty.ty_adt_def().unwrap();
|
||||
for (idx, field) in adt.non_enum_variant().fields.iter().enumerate() {
|
||||
if field.name.as_str() == name {
|
||||
return this.mplace_field(mplace, idx);
|
||||
return this.project_field(base, idx);
|
||||
}
|
||||
}
|
||||
bug!("No field named {} in type {}", name, mplace.layout.ty);
|
||||
bug!("No field named {} in type {}", name, base.layout().ty);
|
||||
}
|
||||
|
||||
/// Write an int of the appropriate size to `dest`. The target type may be signed or unsigned,
|
||||
|
|
@ -270,7 +271,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
for (idx, &val) in values.iter().enumerate() {
|
||||
let field = this.mplace_field(dest, idx)?;
|
||||
let field = this.project_field(dest, idx)?;
|
||||
this.write_int(val, &field.into())?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -284,7 +285,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
) -> InterpResult<'tcx> {
|
||||
let this = self.eval_context_mut();
|
||||
for &(name, val) in values.iter() {
|
||||
let field = this.mplace_field_named(dest, name)?;
|
||||
let field = this.project_field_named(dest, name)?;
|
||||
this.write_int(val, &field.into())?;
|
||||
}
|
||||
Ok(())
|
||||
|
|
@ -301,8 +302,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
|
||||
/// Get the `Place` for a local
|
||||
fn local_place(&mut self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_mut();
|
||||
fn local_place(&self, local: mir::Local) -> InterpResult<'tcx, PlaceTy<'tcx, Provenance>> {
|
||||
let this = self.eval_context_ref();
|
||||
let place = mir::Place { local, projection: List::empty() };
|
||||
this.eval_place(place)
|
||||
}
|
||||
|
|
@ -479,6 +480,16 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
self.ecx
|
||||
}
|
||||
|
||||
fn aggregate_field_order(memory_index: &IndexVec<FieldIdx, u32>, idx: usize) -> usize {
|
||||
// We need to do an *inverse* lookup: find the field that has position `idx` in memory order.
|
||||
for (src_field, &mem_pos) in memory_index.iter_enumerated() {
|
||||
if mem_pos as usize == idx {
|
||||
return src_field.as_usize();
|
||||
}
|
||||
}
|
||||
panic!("invalid `memory_index`, could not find {}-th field in memory order", idx);
|
||||
}
|
||||
|
||||
// Hook to detect `UnsafeCell`.
|
||||
fn visit_value(&mut self, v: &MPlaceTy<'tcx, Provenance>) -> InterpResult<'tcx> {
|
||||
trace!("UnsafeCellVisitor: {:?} {:?}", *v, v.layout.ty);
|
||||
|
|
@ -524,33 +535,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
}
|
||||
}
|
||||
|
||||
// Make sure we visit aggregates in increasing offset order.
|
||||
fn visit_aggregate(
|
||||
&mut self,
|
||||
place: &MPlaceTy<'tcx, Provenance>,
|
||||
fields: impl Iterator<Item = InterpResult<'tcx, MPlaceTy<'tcx, Provenance>>>,
|
||||
) -> InterpResult<'tcx> {
|
||||
match place.layout.fields {
|
||||
FieldsShape::Array { .. } => {
|
||||
// For the array layout, we know the iterator will yield sorted elements so
|
||||
// we can avoid the allocation.
|
||||
self.walk_aggregate(place, fields)
|
||||
}
|
||||
FieldsShape::Arbitrary { .. } => {
|
||||
// Gather the subplaces and sort them before visiting.
|
||||
let mut places = fields
|
||||
.collect::<InterpResult<'tcx, Vec<MPlaceTy<'tcx, Provenance>>>>()?;
|
||||
// we just compare offsets, the abs. value never matters
|
||||
places.sort_by_key(|place| place.ptr.addr());
|
||||
self.walk_aggregate(place, places.into_iter().map(Ok))
|
||||
}
|
||||
FieldsShape::Union { .. } | FieldsShape::Primitive => {
|
||||
// Uh, what?
|
||||
bug!("unions/primitives are not aggregates we should ever visit")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn visit_union(
|
||||
&mut self,
|
||||
_v: &MPlaceTy<'tcx, Provenance>,
|
||||
|
|
@ -746,7 +730,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
Ok(mplace)
|
||||
}
|
||||
|
||||
fn deref_pointer_as(
|
||||
/// Deref' a pointer *without* checking that the place is dereferenceable.
|
||||
fn deref_pointer_unchecked(
|
||||
&self,
|
||||
val: &ImmTy<'tcx, Provenance>,
|
||||
layout: TyAndLayout<'tcx>,
|
||||
|
|
@ -811,10 +796,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
tp: &MPlaceTy<'tcx, Provenance>,
|
||||
) -> InterpResult<'tcx, Option<Duration>> {
|
||||
let this = self.eval_context_mut();
|
||||
let seconds_place = this.mplace_field(tp, 0)?;
|
||||
let seconds_place = this.project_field(tp, 0)?;
|
||||
let seconds_scalar = this.read_scalar(&seconds_place.into())?;
|
||||
let seconds = seconds_scalar.to_target_isize(this)?;
|
||||
let nanoseconds_place = this.mplace_field(tp, 1)?;
|
||||
let nanoseconds_place = this.project_field(tp, 1)?;
|
||||
let nanoseconds_scalar = this.read_scalar(&nanoseconds_place.into())?;
|
||||
let nanoseconds = nanoseconds_scalar.to_target_isize(this)?;
|
||||
|
||||
|
|
|
|||
|
|
@ -83,7 +83,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
// Write pointers into array
|
||||
for (i, ptr) in ptrs.into_iter().enumerate() {
|
||||
let place = this.mplace_index(&alloc, i as u64)?;
|
||||
let place = this.project_index(&alloc, i as u64)?;
|
||||
|
||||
this.write_pointer(ptr, &place.into())?;
|
||||
}
|
||||
|
|
@ -196,33 +196,33 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
this.write_immediate(
|
||||
name_alloc.to_ref(this),
|
||||
&this.mplace_field(&dest, 0)?.into(),
|
||||
&this.project_field(&dest, 0)?.into(),
|
||||
)?;
|
||||
this.write_immediate(
|
||||
filename_alloc.to_ref(this),
|
||||
&this.mplace_field(&dest, 1)?.into(),
|
||||
&this.project_field(&dest, 1)?.into(),
|
||||
)?;
|
||||
}
|
||||
1 => {
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(name.len().try_into().unwrap(), this),
|
||||
&this.mplace_field(&dest, 0)?.into(),
|
||||
&this.project_field(&dest, 0)?.into(),
|
||||
)?;
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(filename.len().try_into().unwrap(), this),
|
||||
&this.mplace_field(&dest, 1)?.into(),
|
||||
&this.project_field(&dest, 1)?.into(),
|
||||
)?;
|
||||
}
|
||||
_ => throw_unsup_format!("unknown `miri_resolve_frame` flags {}", flags),
|
||||
}
|
||||
|
||||
this.write_scalar(Scalar::from_u32(lineno), &this.mplace_field(&dest, 2)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(colno), &this.mplace_field(&dest, 3)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(lineno), &this.project_field(&dest, 2)?.into())?;
|
||||
this.write_scalar(Scalar::from_u32(colno), &this.project_field(&dest, 3)?.into())?;
|
||||
|
||||
// Support a 4-field struct for now - this is deprecated
|
||||
// and slated for removal.
|
||||
if num_fields == 5 {
|
||||
this.write_pointer(fn_ptr, &this.mplace_field(&dest, 4)?.into())?;
|
||||
this.write_pointer(fn_ptr, &this.project_field(&dest, 4)?.into())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
|||
|
|
@ -456,7 +456,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
))?;
|
||||
let vars_place = this.allocate(vars_layout, MiriMemoryKind::Runtime.into())?;
|
||||
for (idx, var) in vars.into_iter().enumerate() {
|
||||
let place = this.mplace_field(&vars_place, idx)?;
|
||||
let place = this.project_field(&vars_place, idx)?;
|
||||
this.write_pointer(var, &place.into())?;
|
||||
}
|
||||
this.write_pointer(vars_place.ptr, &this.machine.env_vars.environ.unwrap().into())?;
|
||||
|
|
|
|||
|
|
@ -942,9 +942,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
#[allow(clippy::arithmetic_side_effects)] // it's a u128, we can shift by 64
|
||||
let (c_out, sum) = ((wide_sum >> 64).truncate::<u8>(), wide_sum.truncate::<u64>());
|
||||
|
||||
let c_out_field = this.place_field(dest, 0)?;
|
||||
let c_out_field = this.project_field(dest, 0)?;
|
||||
this.write_scalar(Scalar::from_u8(c_out), &c_out_field)?;
|
||||
let sum_field = this.place_field(dest, 1)?;
|
||||
let sum_field = this.project_field(dest, 1)?;
|
||||
this.write_scalar(Scalar::from_u64(sum), &sum_field)?;
|
||||
}
|
||||
"llvm.x86.sse2.pause"
|
||||
|
|
|
|||
|
|
@ -57,8 +57,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
for i in 0..dest_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
let val = match which {
|
||||
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar(),
|
||||
Op::Abs => {
|
||||
|
|
@ -172,9 +172,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
for i in 0..dest_len {
|
||||
let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?;
|
||||
let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let left = this.read_immediate(&this.project_index(&left, i)?.into())?;
|
||||
let right = this.read_immediate(&this.project_index(&right, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
let val = match which {
|
||||
Op::MirOp(mir_op) => {
|
||||
let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?;
|
||||
|
|
@ -232,10 +232,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, c_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let a = this.read_scalar(&this.mplace_index(&a, i)?.into())?;
|
||||
let b = this.read_scalar(&this.mplace_index(&b, i)?.into())?;
|
||||
let c = this.read_scalar(&this.mplace_index(&c, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let a = this.read_scalar(&this.project_index(&a, i)?.into())?;
|
||||
let b = this.read_scalar(&this.project_index(&b, i)?.into())?;
|
||||
let c = this.read_scalar(&this.project_index(&c, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
// Works for f32 and f64.
|
||||
// FIXME: using host floats to work around https://github.com/rust-lang/miri/issues/2468.
|
||||
|
|
@ -295,13 +295,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
};
|
||||
|
||||
// Initialize with first lane, then proceed with the rest.
|
||||
let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?;
|
||||
let mut res = this.read_immediate(&this.project_index(&op, 0)?.into())?;
|
||||
if matches!(which, Op::MirOpBool(_)) {
|
||||
// Convert to `bool` scalar.
|
||||
res = imm_from_bool(simd_element_to_bool(res)?);
|
||||
}
|
||||
for i in 1..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
res = match which {
|
||||
Op::MirOp(mir_op) => {
|
||||
this.binary_op(mir_op, &res, &op)?
|
||||
|
|
@ -355,7 +355,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let mut res = init;
|
||||
for i in 0..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
res = this.binary_op(mir_op, &res, &op)?;
|
||||
}
|
||||
this.write_immediate(*res, dest)?;
|
||||
|
|
@ -372,10 +372,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, no_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let yes = this.read_immediate(&this.mplace_index(&yes, i)?.into())?;
|
||||
let no = this.read_immediate(&this.mplace_index(&no, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
let yes = this.read_immediate(&this.project_index(&yes, i)?.into())?;
|
||||
let no = this.read_immediate(&this.project_index(&no, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if simd_element_to_bool(mask)? { yes } else { no };
|
||||
this.write_immediate(*val, &dest.into())?;
|
||||
|
|
@ -403,9 +403,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
& 1u64
|
||||
.checked_shl(simd_bitmask_index(i, dest_len, this.data_layout().endian))
|
||||
.unwrap();
|
||||
let yes = this.read_immediate(&this.mplace_index(&yes, i.into())?.into())?;
|
||||
let no = this.read_immediate(&this.mplace_index(&no, i.into())?.into())?;
|
||||
let dest = this.mplace_index(&dest, i.into())?;
|
||||
let yes = this.read_immediate(&this.project_index(&yes, i.into())?.into())?;
|
||||
let no = this.read_immediate(&this.project_index(&no, i.into())?.into())?;
|
||||
let dest = this.project_index(&dest, i.into())?;
|
||||
|
||||
let val = if mask != 0 { yes } else { no };
|
||||
this.write_immediate(*val, &dest.into())?;
|
||||
|
|
@ -435,8 +435,8 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
let from_exposed_cast = intrinsic_name == "from_exposed_addr";
|
||||
|
||||
for i in 0..dest_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = match (op.layout.ty.kind(), dest.layout.ty.kind()) {
|
||||
// Int-to-(int|float): always safe
|
||||
|
|
@ -496,17 +496,17 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
for i in 0..dest_len {
|
||||
let src_index: u64 = this
|
||||
.read_immediate(&this.operand_index(index, i)?)?
|
||||
.read_immediate(&this.project_index(index, i)?)?
|
||||
.to_scalar()
|
||||
.to_u32()?
|
||||
.into();
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if src_index < left_len {
|
||||
this.read_immediate(&this.mplace_index(&left, src_index)?.into())?
|
||||
this.read_immediate(&this.project_index(&left, src_index)?.into())?
|
||||
} else if src_index < left_len.checked_add(right_len).unwrap() {
|
||||
let right_idx = src_index.checked_sub(left_len).unwrap();
|
||||
this.read_immediate(&this.mplace_index(&right, right_idx)?.into())?
|
||||
this.read_immediate(&this.project_index(&right, right_idx)?.into())?
|
||||
} else {
|
||||
span_bug!(
|
||||
this.cur_span(),
|
||||
|
|
@ -528,10 +528,10 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(dest_len, mask_len);
|
||||
|
||||
for i in 0..dest_len {
|
||||
let passthru = this.read_immediate(&this.mplace_index(&passthru, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let passthru = this.read_immediate(&this.project_index(&passthru, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
let dest = this.project_index(&dest, i)?;
|
||||
|
||||
let val = if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr.into())?;
|
||||
|
|
@ -552,9 +552,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
assert_eq!(ptrs_len, mask_len);
|
||||
|
||||
for i in 0..ptrs_len {
|
||||
let value = this.read_immediate(&this.mplace_index(&value, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.mplace_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.mplace_index(&mask, i)?.into())?;
|
||||
let value = this.read_immediate(&this.project_index(&value, i)?.into())?;
|
||||
let ptr = this.read_immediate(&this.project_index(&ptrs, i)?.into())?;
|
||||
let mask = this.read_immediate(&this.project_index(&mask, i)?.into())?;
|
||||
|
||||
if simd_element_to_bool(mask)? {
|
||||
let place = this.deref_operand(&ptr.into())?;
|
||||
|
|
@ -578,7 +578,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
|
||||
let mut res = 0u64;
|
||||
for i in 0..op_len {
|
||||
let op = this.read_immediate(&this.mplace_index(&op, i.into())?.into())?;
|
||||
let op = this.read_immediate(&this.project_index(&op, i.into())?.into())?;
|
||||
if simd_element_to_bool(op)? {
|
||||
res |= 1u64
|
||||
.checked_shl(simd_bitmask_index(i, op_len, this.data_layout().endian))
|
||||
|
|
|
|||
|
|
@ -593,7 +593,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
#[allow(deprecated)]
|
||||
let home_dir = std::env::home_dir().unwrap();
|
||||
let (written, _) = this.write_path_to_c_str(&home_dir, buf, buflen)?;
|
||||
let pw_dir = this.mplace_field_named(&pwd, "pw_dir")?;
|
||||
let pw_dir = this.project_field_named(&pwd, "pw_dir")?;
|
||||
this.write_pointer(buf, &pw_dir.into())?;
|
||||
|
||||
if written {
|
||||
|
|
|
|||
|
|
@ -1141,7 +1141,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", access_sec.into()),
|
||||
("tv_nsec", access_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_atime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_atime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1149,7 +1149,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", created_sec.into()),
|
||||
("tv_nsec", created_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_btime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_btime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1157,7 +1157,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", 0.into()),
|
||||
("tv_nsec", 0.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_ctime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_ctime")?,
|
||||
)?;
|
||||
#[rustfmt::skip]
|
||||
this.write_int_fields_named(
|
||||
|
|
@ -1165,7 +1165,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
("tv_sec", modified_sec.into()),
|
||||
("tv_nsec", modified_nsec.into()),
|
||||
],
|
||||
&this.mplace_field_named(&statxbuf, "stx_mtime")?,
|
||||
&this.project_field_named(&statxbuf, "stx_mtime")?,
|
||||
)?;
|
||||
|
||||
Ok(0)
|
||||
|
|
@ -1421,7 +1421,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// }
|
||||
|
||||
let entry_place = this.deref_operand_as(entry_op, this.libc_ty_layout("dirent"))?;
|
||||
let name_place = this.mplace_field(&entry_place, 5)?;
|
||||
let name_place = this.project_field(&entry_place, 5)?;
|
||||
|
||||
let file_name = dir_entry.file_name(); // not a Path as there are no separators!
|
||||
let (name_fits, file_name_buf_len) = this.write_os_str_to_c_str(
|
||||
|
|
|
|||
|
|
@ -73,9 +73,9 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
if op == epoll_ctl_add || op == epoll_ctl_mod {
|
||||
let event = this.deref_operand_as(event, this.libc_ty_layout("epoll_event"))?;
|
||||
|
||||
let events = this.mplace_field(&event, 0)?;
|
||||
let events = this.project_field(&event, 0)?;
|
||||
let events = this.read_scalar(&events.into())?.to_u32()?;
|
||||
let data = this.mplace_field(&event, 1)?;
|
||||
let data = this.project_field(&event, 1)?;
|
||||
let data = this.read_scalar(&data.into())?;
|
||||
let event = EpollEvent { events, data };
|
||||
|
||||
|
|
|
|||
|
|
@ -85,7 +85,8 @@ pub fn futex<'tcx>(
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
let timeout = this.deref_pointer_as(
|
||||
// `read_timespec` will check the place when it is not null.
|
||||
let timeout = this.deref_pointer_unchecked(
|
||||
&this.read_immediate(&args[3])?,
|
||||
this.libc_ty_layout("timespec"),
|
||||
)?;
|
||||
|
|
|
|||
|
|
@ -122,7 +122,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
|
|||
// We have to put the result into io_status_block.
|
||||
if let Some(n) = written {
|
||||
let io_status_information =
|
||||
this.mplace_field_named(&io_status_block, "Information")?;
|
||||
this.project_field_named(&io_status_block, "Information")?;
|
||||
this.write_scalar(
|
||||
Scalar::from_target_usize(n.into(), this),
|
||||
&io_status_information.into(),
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
//! Tests for various intrinsics that do not fit anywhere else.
|
||||
|
||||
use std::intrinsics;
|
||||
use std::mem::{size_of, size_of_val, size_of_val_raw};
|
||||
use std::mem::{size_of, size_of_val, size_of_val_raw, discriminant};
|
||||
|
||||
struct Bomb;
|
||||
|
||||
|
|
@ -39,4 +39,7 @@ fn main() {
|
|||
let _v = intrinsics::discriminant_value(&0);
|
||||
let _v = intrinsics::discriminant_value(&true);
|
||||
let _v = intrinsics::discriminant_value(&vec![1, 2, 3]);
|
||||
// Make sure that even if the discriminant is stored together with data, the intrinsic returns
|
||||
// only the discriminant, nothing about the data.
|
||||
assert_eq!(discriminant(&Some(false)), discriminant(&Some(true)));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -161,10 +161,21 @@ jobs:
|
|||
# if: runner.os == 'Linux'
|
||||
# working-directory: ./editors/code
|
||||
|
||||
# If this steps fails, your code's type integrity might be wrong at some places at TypeScript level.
|
||||
- run: npm run typecheck
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
# You may fix the code automatically by running `npm run lint:fix` if this steps fails.
|
||||
- run: npm run lint
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
# To fix this steps, please run `npm run format`.
|
||||
- run: npm run format:check
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
- name: Run VS Code tests (Linux)
|
||||
if: matrix.os == 'ubuntu-latest' && needs.changes.outputs.typescript == 'true'
|
||||
env:
|
||||
|
|
@ -179,10 +190,6 @@ jobs:
|
|||
run: npm test
|
||||
working-directory: ./editors/code
|
||||
|
||||
- run: npm run pretest
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
||||
- run: npm run package --scripts-prepend-node-path
|
||||
working-directory: ./editors/code
|
||||
if: needs.changes.outputs.typescript == 'true'
|
||||
|
|
|
|||
|
|
@ -634,7 +634,7 @@ impl Printer<'_> {
|
|||
match literal {
|
||||
Literal::String(it) => w!(self, "{:?}", it),
|
||||
Literal::ByteString(it) => w!(self, "\"{}\"", it.escape_ascii()),
|
||||
Literal::CString(it) => w!(self, "\"{}\\0\"", it),
|
||||
Literal::CString(it) => w!(self, "\"{}\\0\"", it.escape_ascii()),
|
||||
Literal::Char(it) => w!(self, "'{}'", it.escape_debug()),
|
||||
Literal::Bool(it) => w!(self, "{}", it),
|
||||
Literal::Int(i, suffix) => {
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ impl fmt::Display for FloatTypeWrapper {
|
|||
pub enum Literal {
|
||||
String(Box<str>),
|
||||
ByteString(Box<[u8]>),
|
||||
CString(Box<str>),
|
||||
CString(Box<[u8]>),
|
||||
Char(char),
|
||||
Bool(bool),
|
||||
Int(i128, Option<BuiltinInt>),
|
||||
|
|
|
|||
|
|
@ -16,7 +16,8 @@ use triomphe::Arc;
|
|||
use crate::{
|
||||
db::HirDatabase, infer::InferenceContext, lower::ParamLoweringMode,
|
||||
mir::monomorphize_mir_body_bad, to_placeholder_idx, utils::Generics, Const, ConstData,
|
||||
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, Ty, TyBuilder,
|
||||
ConstScalar, ConstValue, GenericArg, Interner, MemoryMap, Substitution, TraitEnvironment, Ty,
|
||||
TyBuilder,
|
||||
};
|
||||
|
||||
use super::mir::{interpret_mir, lower_to_mir, pad16, MirEvalError, MirLowerError};
|
||||
|
|
@ -135,7 +136,7 @@ pub fn intern_const_ref(
|
|||
ty: Ty,
|
||||
krate: CrateId,
|
||||
) -> Const {
|
||||
let layout = db.layout_of_ty(ty.clone(), krate);
|
||||
let layout = db.layout_of_ty(ty.clone(), Arc::new(TraitEnvironment::empty(krate)));
|
||||
let bytes = match value {
|
||||
LiteralConstRef::Int(i) => {
|
||||
// FIXME: We should handle failure of layout better.
|
||||
|
|
@ -173,7 +174,7 @@ pub fn try_const_usize(db: &dyn HirDatabase, c: &Const) -> Option<u128> {
|
|||
chalk_ir::ConstValue::Concrete(c) => match &c.interned {
|
||||
ConstScalar::Bytes(it, _) => Some(u128::from_le_bytes(pad16(&it, false))),
|
||||
ConstScalar::UnevaluatedConst(c, subst) => {
|
||||
let ec = db.const_eval(*c, subst.clone()).ok()?;
|
||||
let ec = db.const_eval(*c, subst.clone(), None).ok()?;
|
||||
try_const_usize(db, &ec)
|
||||
}
|
||||
_ => None,
|
||||
|
|
@ -186,6 +187,7 @@ pub(crate) fn const_eval_recover(
|
|||
_: &[String],
|
||||
_: &GeneralConstId,
|
||||
_: &Substitution,
|
||||
_: &Option<Arc<TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError> {
|
||||
Err(ConstEvalError::MirLowerError(MirLowerError::Loop))
|
||||
}
|
||||
|
|
@ -210,6 +212,7 @@ pub(crate) fn const_eval_query(
|
|||
db: &dyn HirDatabase,
|
||||
def: GeneralConstId,
|
||||
subst: Substitution,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError> {
|
||||
let body = match def {
|
||||
GeneralConstId::ConstId(c) => {
|
||||
|
|
@ -228,7 +231,7 @@ pub(crate) fn const_eval_query(
|
|||
}
|
||||
GeneralConstId::InTypeConstId(c) => db.mir_body(c.into())?,
|
||||
};
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
let c = interpret_mir(db, body, false, trait_env).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
|
@ -241,7 +244,7 @@ pub(crate) fn const_eval_static_query(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def.into()),
|
||||
)?;
|
||||
let c = interpret_mir(db, body, false).0?;
|
||||
let c = interpret_mir(db, body, false, None).0?;
|
||||
Ok(c)
|
||||
}
|
||||
|
||||
|
|
@ -268,7 +271,7 @@ pub(crate) fn const_eval_discriminant_variant(
|
|||
Substitution::empty(Interner),
|
||||
db.trait_environment_for_body(def),
|
||||
)?;
|
||||
let c = interpret_mir(db, mir_body, false).0?;
|
||||
let c = interpret_mir(db, mir_body, false, None).0?;
|
||||
let c = try_const_usize(db, &c).unwrap() as i128;
|
||||
Ok(c)
|
||||
}
|
||||
|
|
@ -293,7 +296,7 @@ pub(crate) fn eval_to_const(
|
|||
}
|
||||
let infer = ctx.clone().resolve_all();
|
||||
if let Ok(mir_body) = lower_to_mir(ctx.db, ctx.owner, &ctx.body, &infer, expr) {
|
||||
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true).0 {
|
||||
if let Ok(result) = interpret_mir(db, Arc::new(mir_body), true, None).0 {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -114,7 +114,7 @@ fn eval_goal(db: &TestDB, file_id: FileId) -> Result<Const, ConstEvalError> {
|
|||
_ => None,
|
||||
})
|
||||
.expect("No const named GOAL found in the test");
|
||||
db.const_eval(const_id.into(), Substitution::empty(Interner))
|
||||
db.const_eval(const_id.into(), Substitution::empty(Interner), None)
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -1941,6 +1941,33 @@ fn dyn_trait() {
|
|||
"#,
|
||||
900,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: coerce_unsized, index, slice
|
||||
trait A {
|
||||
fn x(&self) -> i32;
|
||||
}
|
||||
|
||||
trait B: A {}
|
||||
|
||||
impl A for i32 {
|
||||
fn x(&self) -> i32 {
|
||||
5
|
||||
}
|
||||
}
|
||||
|
||||
impl B for i32 {
|
||||
|
||||
}
|
||||
|
||||
const fn f(x: &dyn B) -> i32 {
|
||||
x.x()
|
||||
}
|
||||
|
||||
const GOAL: i32 = f(&2i32);
|
||||
"#,
|
||||
5,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -2492,6 +2519,28 @@ fn const_trait_assoc() {
|
|||
"#,
|
||||
5,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
//- minicore: size_of
|
||||
//- /a/lib.rs crate:a
|
||||
use core::mem::size_of;
|
||||
pub struct S<T>(T);
|
||||
impl<T> S<T> {
|
||||
pub const X: usize = core::mem::size_of::<T>();
|
||||
}
|
||||
//- /main.rs crate:main deps:a
|
||||
use a::{S};
|
||||
trait Tr {
|
||||
type Ty;
|
||||
}
|
||||
impl Tr for i32 {
|
||||
type Ty = u64;
|
||||
}
|
||||
struct K<T: Tr>(<T as Tr>::Ty);
|
||||
const GOAL: usize = S::<K<i32>>::X;
|
||||
"#,
|
||||
8,
|
||||
);
|
||||
check_number(
|
||||
r#"
|
||||
struct S<T>(*mut T);
|
||||
|
|
|
|||
|
|
@ -77,8 +77,12 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
|
||||
#[salsa::invoke(crate::consteval::const_eval_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_recover)]
|
||||
fn const_eval(&self, def: GeneralConstId, subst: Substitution)
|
||||
-> Result<Const, ConstEvalError>;
|
||||
fn const_eval(
|
||||
&self,
|
||||
def: GeneralConstId,
|
||||
subst: Substitution,
|
||||
trait_env: Option<Arc<crate::TraitEnvironment>>,
|
||||
) -> Result<Const, ConstEvalError>;
|
||||
|
||||
#[salsa::invoke(crate::consteval::const_eval_static_query)]
|
||||
#[salsa::cycle(crate::consteval::const_eval_static_recover)]
|
||||
|
|
@ -100,12 +104,16 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
|
|||
&self,
|
||||
def: AdtId,
|
||||
subst: Substitution,
|
||||
krate: CrateId,
|
||||
env: Arc<crate::TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError>;
|
||||
|
||||
#[salsa::invoke(crate::layout::layout_of_ty_query)]
|
||||
#[salsa::cycle(crate::layout::layout_of_ty_recover)]
|
||||
fn layout_of_ty(&self, ty: Ty, krate: CrateId) -> Result<Arc<Layout>, LayoutError>;
|
||||
fn layout_of_ty(
|
||||
&self,
|
||||
ty: Ty,
|
||||
env: Arc<crate::TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError>;
|
||||
|
||||
#[salsa::invoke(crate::layout::target_data_layout_query)]
|
||||
fn target_data_layout(&self, krate: CrateId) -> Option<Arc<TargetDataLayout>>;
|
||||
|
|
|
|||
|
|
@ -14,13 +14,12 @@ mod case_conv;
|
|||
|
||||
use std::fmt;
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
hir::{Pat, PatId},
|
||||
src::HasSource,
|
||||
AdtId, AttrDefId, ConstId, EnumId, FunctionId, ItemContainerId, Lookup, ModuleDefId, StaticId,
|
||||
StructId,
|
||||
AdtId, AttrDefId, ConstId, DefWithBodyId, EnumId, EnumVariantId, FunctionId, ItemContainerId,
|
||||
Lookup, ModuleDefId, StaticId, StructId,
|
||||
};
|
||||
use hir_expand::{
|
||||
name::{AsName, Name},
|
||||
|
|
@ -44,13 +43,9 @@ mod allow {
|
|||
pub(super) const NON_CAMEL_CASE_TYPES: &str = "non_camel_case_types";
|
||||
}
|
||||
|
||||
pub fn incorrect_case(
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
owner: ModuleDefId,
|
||||
) -> Vec<IncorrectCase> {
|
||||
pub fn incorrect_case(db: &dyn HirDatabase, owner: ModuleDefId) -> Vec<IncorrectCase> {
|
||||
let _p = profile::span("validate_module_item");
|
||||
let mut validator = DeclValidator::new(db, krate);
|
||||
let mut validator = DeclValidator::new(db);
|
||||
validator.validate_item(owner);
|
||||
validator.sink
|
||||
}
|
||||
|
|
@ -120,7 +115,6 @@ pub struct IncorrectCase {
|
|||
|
||||
pub(super) struct DeclValidator<'a> {
|
||||
db: &'a dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
pub(super) sink: Vec<IncorrectCase>,
|
||||
}
|
||||
|
||||
|
|
@ -132,8 +126,8 @@ struct Replacement {
|
|||
}
|
||||
|
||||
impl<'a> DeclValidator<'a> {
|
||||
pub(super) fn new(db: &'a dyn HirDatabase, krate: CrateId) -> DeclValidator<'a> {
|
||||
DeclValidator { db, krate, sink: Vec::new() }
|
||||
pub(super) fn new(db: &'a dyn HirDatabase) -> DeclValidator<'a> {
|
||||
DeclValidator { db, sink: Vec::new() }
|
||||
}
|
||||
|
||||
pub(super) fn validate_item(&mut self, item: ModuleDefId) {
|
||||
|
|
@ -195,8 +189,7 @@ impl<'a> DeclValidator<'a> {
|
|||
AttrDefId::TypeAliasId(_) => None,
|
||||
AttrDefId::GenericParamId(_) => None,
|
||||
}
|
||||
.map(|mid| self.allowed(mid, allow_name, true))
|
||||
.unwrap_or(false)
|
||||
.is_some_and(|mid| self.allowed(mid, allow_name, true))
|
||||
}
|
||||
|
||||
fn validate_func(&mut self, func: FunctionId) {
|
||||
|
|
@ -206,17 +199,7 @@ impl<'a> DeclValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
let body = self.db.body(func.into());
|
||||
|
||||
// Recursively validate inner scope items, such as static variables and constants.
|
||||
for (_, block_def_map) in body.blocks(self.db.upcast()) {
|
||||
for (_, module) in block_def_map.modules() {
|
||||
for def_id in module.scope.declarations() {
|
||||
let mut validator = DeclValidator::new(self.db, self.krate);
|
||||
validator.validate_item(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
self.validate_body_inner_items(func.into());
|
||||
|
||||
// Check whether non-snake case identifiers are allowed for this function.
|
||||
if self.allowed(func.into(), allow::NON_SNAKE_CASE, false) {
|
||||
|
|
@ -231,6 +214,8 @@ impl<'a> DeclValidator<'a> {
|
|||
expected_case: CaseType::LowerSnakeCase,
|
||||
});
|
||||
|
||||
let body = self.db.body(func.into());
|
||||
|
||||
// Check the patterns inside the function body.
|
||||
// This includes function parameters.
|
||||
let pats_replacements = body
|
||||
|
|
@ -496,6 +481,11 @@ impl<'a> DeclValidator<'a> {
|
|||
fn validate_enum(&mut self, enum_id: EnumId) {
|
||||
let data = self.db.enum_data(enum_id);
|
||||
|
||||
for (local_id, _) in data.variants.iter() {
|
||||
let variant_id = EnumVariantId { parent: enum_id, local_id };
|
||||
self.validate_body_inner_items(variant_id.into());
|
||||
}
|
||||
|
||||
// Check whether non-camel case names are allowed for this enum.
|
||||
if self.allowed(enum_id.into(), allow::NON_CAMEL_CASE_TYPES, false) {
|
||||
return;
|
||||
|
|
@ -512,13 +502,11 @@ impl<'a> DeclValidator<'a> {
|
|||
// Check the field names.
|
||||
let enum_fields_replacements = data
|
||||
.variants
|
||||
.iter()
|
||||
.filter_map(|(_, variant)| {
|
||||
.values()
|
||||
.filter_map(|variant| {
|
||||
Some(Replacement {
|
||||
current_name: variant.name.clone(),
|
||||
suggested_text: to_camel_case(
|
||||
&variant.name.display(self.db.upcast()).to_string(),
|
||||
)?,
|
||||
suggested_text: to_camel_case(&variant.name.to_smol_str())?,
|
||||
expected_case: CaseType::UpperCamelCase,
|
||||
})
|
||||
})
|
||||
|
|
@ -622,6 +610,8 @@ impl<'a> DeclValidator<'a> {
|
|||
fn validate_const(&mut self, const_id: ConstId) {
|
||||
let data = self.db.const_data(const_id);
|
||||
|
||||
self.validate_body_inner_items(const_id.into());
|
||||
|
||||
if self.allowed(const_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
|
||||
return;
|
||||
}
|
||||
|
|
@ -631,7 +621,7 @@ impl<'a> DeclValidator<'a> {
|
|||
None => return,
|
||||
};
|
||||
|
||||
let const_name = name.display(self.db.upcast()).to_string();
|
||||
let const_name = name.to_smol_str();
|
||||
let replacement = if let Some(new_name) = to_upper_snake_case(&const_name) {
|
||||
Replacement {
|
||||
current_name: name.clone(),
|
||||
|
|
@ -670,13 +660,15 @@ impl<'a> DeclValidator<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
self.validate_body_inner_items(static_id.into());
|
||||
|
||||
if self.allowed(static_id.into(), allow::NON_UPPER_CASE_GLOBAL, false) {
|
||||
return;
|
||||
}
|
||||
|
||||
let name = &data.name;
|
||||
|
||||
let static_name = name.display(self.db.upcast()).to_string();
|
||||
let static_name = name.to_smol_str();
|
||||
let replacement = if let Some(new_name) = to_upper_snake_case(&static_name) {
|
||||
Replacement {
|
||||
current_name: name.clone(),
|
||||
|
|
@ -707,4 +699,17 @@ impl<'a> DeclValidator<'a> {
|
|||
|
||||
self.sink.push(diagnostic);
|
||||
}
|
||||
|
||||
// FIXME: We don't currently validate names within `DefWithBodyId::InTypeConstId`.
|
||||
/// Recursively validates inner scope items, such as static variables and constants.
|
||||
fn validate_body_inner_items(&mut self, body_id: DefWithBodyId) {
|
||||
let body = self.db.body(body_id);
|
||||
for (_, block_def_map) in body.blocks(self.db.upcast()) {
|
||||
for (_, module) in block_def_map.modules() {
|
||||
for def_id in module.scope.declarations() {
|
||||
self.validate_item(def_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ use itertools::Itertools;
|
|||
use la_arena::ArenaMap;
|
||||
use smallvec::SmallVec;
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
consteval::try_const_usize,
|
||||
|
|
@ -43,7 +44,7 @@ use crate::{
|
|||
AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstScalar, ConstValue,
|
||||
DomainGoal, GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives,
|
||||
MemoryMap, Mutability, OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar,
|
||||
Substitution, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
|
||||
Substitution, TraitEnvironment, TraitRef, TraitRefExt, Ty, TyExt, WhereClause,
|
||||
};
|
||||
|
||||
pub trait HirWrite: fmt::Write {
|
||||
|
|
@ -454,7 +455,9 @@ fn render_const_scalar(
|
|||
) -> Result<(), HirDisplayError> {
|
||||
// FIXME: We need to get krate from the final callers of the hir display
|
||||
// infrastructure and have it here as a field on `f`.
|
||||
let krate = *f.db.crate_graph().crates_in_topological_order().last().unwrap();
|
||||
let trait_env = Arc::new(TraitEnvironment::empty(
|
||||
*f.db.crate_graph().crates_in_topological_order().last().unwrap(),
|
||||
));
|
||||
match ty.kind(Interner) {
|
||||
TyKind::Scalar(s) => match s {
|
||||
Scalar::Bool => write!(f, "{}", if b[0] == 0 { false } else { true }),
|
||||
|
|
@ -497,7 +500,7 @@ fn render_const_scalar(
|
|||
TyKind::Slice(ty) => {
|
||||
let addr = usize::from_le_bytes(b[0..b.len() / 2].try_into().unwrap());
|
||||
let count = usize::from_le_bytes(b[b.len() / 2..].try_into().unwrap());
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size_one = layout.size.bytes_usize();
|
||||
|
|
@ -523,7 +526,7 @@ fn render_const_scalar(
|
|||
let Ok(t) = memory_map.vtable.ty(ty_id) else {
|
||||
return f.write_str("<ty-missing-in-vtable-map>");
|
||||
};
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
@ -555,7 +558,7 @@ fn render_const_scalar(
|
|||
return f.write_str("<layout-error>");
|
||||
}
|
||||
});
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(t.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
@ -567,7 +570,7 @@ fn render_const_scalar(
|
|||
}
|
||||
},
|
||||
TyKind::Tuple(_, subst) => {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
f.write_str("(")?;
|
||||
|
|
@ -580,7 +583,7 @@ fn render_const_scalar(
|
|||
}
|
||||
let ty = ty.assert_ty_ref(Interner); // Tuple only has type argument
|
||||
let offset = layout.fields.offset(id).bytes_usize();
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
f.write_str("<layout-error>")?;
|
||||
continue;
|
||||
};
|
||||
|
|
@ -590,7 +593,7 @@ fn render_const_scalar(
|
|||
f.write_str(")")
|
||||
}
|
||||
TyKind::Adt(adt, subst) => {
|
||||
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_adt(adt.0, subst.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
match adt.0 {
|
||||
|
|
@ -602,7 +605,7 @@ fn render_const_scalar(
|
|||
&data.variant_data,
|
||||
f,
|
||||
&field_types,
|
||||
adt.0.module(f.db.upcast()).krate(),
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
&layout,
|
||||
subst,
|
||||
b,
|
||||
|
|
@ -614,7 +617,7 @@ fn render_const_scalar(
|
|||
}
|
||||
hir_def::AdtId::EnumId(e) => {
|
||||
let Some((var_id, var_layout)) =
|
||||
detect_variant_from_bytes(&layout, f.db, krate, b, e)
|
||||
detect_variant_from_bytes(&layout, f.db, trait_env.clone(), b, e)
|
||||
else {
|
||||
return f.write_str("<failed-to-detect-variant>");
|
||||
};
|
||||
|
|
@ -626,7 +629,7 @@ fn render_const_scalar(
|
|||
&data.variant_data,
|
||||
f,
|
||||
&field_types,
|
||||
adt.0.module(f.db.upcast()).krate(),
|
||||
f.db.trait_environment(adt.0.into()),
|
||||
&var_layout,
|
||||
subst,
|
||||
b,
|
||||
|
|
@ -645,7 +648,7 @@ fn render_const_scalar(
|
|||
let Some(len) = try_const_usize(f.db, len) else {
|
||||
return f.write_str("<unknown-array-len>");
|
||||
};
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size_one = layout.size.bytes_usize();
|
||||
|
|
@ -684,7 +687,7 @@ fn render_variant_after_name(
|
|||
data: &VariantData,
|
||||
f: &mut HirFormatter<'_>,
|
||||
field_types: &ArenaMap<LocalFieldId, Binders<Ty>>,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
layout: &Layout,
|
||||
subst: &Substitution,
|
||||
b: &[u8],
|
||||
|
|
@ -695,7 +698,7 @@ fn render_variant_after_name(
|
|||
let render_field = |f: &mut HirFormatter<'_>, id: LocalFieldId| {
|
||||
let offset = layout.fields.offset(u32::from(id.into_raw()) as usize).bytes_usize();
|
||||
let ty = field_types[id].clone().substitute(Interner, subst);
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), krate) else {
|
||||
let Ok(layout) = f.db.layout_of_ty(ty.clone(), trait_env.clone()) else {
|
||||
return f.write_str("<layout-error>");
|
||||
};
|
||||
let size = layout.size.bytes_usize();
|
||||
|
|
|
|||
|
|
@ -1665,6 +1665,7 @@ impl InferenceContext<'_> {
|
|||
// the parameter to coerce to the expected type (for example in
|
||||
// `coerce_unsize_expected_type_4`).
|
||||
let param_ty = self.normalize_associated_types_in(param_ty);
|
||||
let expected_ty = self.normalize_associated_types_in(expected_ty);
|
||||
let expected = Expectation::rvalue_hint(self, expected_ty);
|
||||
// infer with the expected type we have...
|
||||
let ty = self.infer_expr_inner(arg, &expected);
|
||||
|
|
|
|||
|
|
@ -252,7 +252,8 @@ impl<'a> InferenceTable<'a> {
|
|||
// and registering an obligation. But it needs chalk support, so we handle the most basic
|
||||
// case (a non associated const without generic parameters) manually.
|
||||
if subst.len(Interner) == 0 {
|
||||
if let Ok(eval) = self.db.const_eval((*c_id).into(), subst.clone())
|
||||
if let Ok(eval) =
|
||||
self.db.const_eval((*c_id).into(), subst.clone(), None)
|
||||
{
|
||||
eval
|
||||
} else {
|
||||
|
|
@ -785,7 +786,7 @@ impl<'a> InferenceTable<'a> {
|
|||
crate::ConstScalar::Unknown => self.new_const_var(data.ty.clone()),
|
||||
// try to evaluate unevaluated const. Replace with new var if const eval failed.
|
||||
crate::ConstScalar::UnevaluatedConst(id, subst) => {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
eval
|
||||
} else {
|
||||
self.new_const_var(data.ty.clone())
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
//! Compute the binary representation of a type
|
||||
|
||||
use base_db::CrateId;
|
||||
use chalk_ir::{AdtId, FloatTy, IntTy, TyKind, UintTy};
|
||||
use hir_def::{
|
||||
layout::{
|
||||
|
|
@ -61,7 +60,6 @@ pub enum LayoutError {
|
|||
}
|
||||
|
||||
struct LayoutCx<'a> {
|
||||
krate: CrateId,
|
||||
target: &'a TargetDataLayout,
|
||||
}
|
||||
|
||||
|
|
@ -82,7 +80,7 @@ fn layout_of_simd_ty(
|
|||
db: &dyn HirDatabase,
|
||||
id: StructId,
|
||||
subst: &Substitution,
|
||||
krate: CrateId,
|
||||
env: Arc<TraitEnvironment>,
|
||||
dl: &TargetDataLayout,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let fields = db.field_types(id.into());
|
||||
|
|
@ -111,7 +109,7 @@ fn layout_of_simd_ty(
|
|||
// * the homogeneous field type and the number of fields.
|
||||
let (e_ty, e_len, is_array) = if let TyKind::Array(e_ty, _) = f0_ty.kind(Interner) {
|
||||
// Extract the number of elements from the layout of the array field:
|
||||
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), krate)?.fields else {
|
||||
let FieldsShape::Array { count, .. } = db.layout_of_ty(f0_ty.clone(), env.clone())?.fields else {
|
||||
user_error!("Array with non array layout");
|
||||
};
|
||||
|
||||
|
|
@ -122,7 +120,7 @@ fn layout_of_simd_ty(
|
|||
};
|
||||
|
||||
// Compute the ABI of the element type:
|
||||
let e_ly = db.layout_of_ty(e_ty, krate)?;
|
||||
let e_ly = db.layout_of_ty(e_ty, env.clone())?;
|
||||
let Abi::Scalar(e_abi) = e_ly.abi else {
|
||||
user_error!("simd type with inner non scalar type");
|
||||
};
|
||||
|
|
@ -152,25 +150,25 @@ fn layout_of_simd_ty(
|
|||
pub fn layout_of_ty_query(
|
||||
db: &dyn HirDatabase,
|
||||
ty: Ty,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let krate = trait_env.krate;
|
||||
let Some(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = &*cx.current_data_layout();
|
||||
let trait_env = Arc::new(TraitEnvironment::empty(krate));
|
||||
let ty = normalize(db, trait_env, ty.clone());
|
||||
let ty = normalize(db, trait_env.clone(), ty.clone());
|
||||
let result = match ty.kind(Interner) {
|
||||
TyKind::Adt(AdtId(def), subst) => {
|
||||
if let hir_def::AdtId::StructId(s) = def {
|
||||
let data = db.struct_data(*s);
|
||||
let repr = data.repr.unwrap_or_default();
|
||||
if repr.simd() {
|
||||
return layout_of_simd_ty(db, *s, subst, krate, &target);
|
||||
return layout_of_simd_ty(db, *s, subst, trait_env.clone(), &target);
|
||||
}
|
||||
};
|
||||
return db.layout_of_adt(*def, subst.clone(), krate);
|
||||
return db.layout_of_adt(*def, subst.clone(), trait_env.clone());
|
||||
}
|
||||
TyKind::Scalar(s) => match s {
|
||||
chalk_ir::Scalar::Bool => Layout::scalar(
|
||||
|
|
@ -228,7 +226,7 @@ pub fn layout_of_ty_query(
|
|||
|
||||
let fields = tys
|
||||
.iter(Interner)
|
||||
.map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), krate))
|
||||
.map(|k| db.layout_of_ty(k.assert_ty_ref(Interner).clone(), trait_env.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
let fields = fields.iter().map(|it| &**it).collect::<Vec<_>>();
|
||||
let fields = fields.iter().collect::<Vec<_>>();
|
||||
|
|
@ -238,7 +236,7 @@ pub fn layout_of_ty_query(
|
|||
let count = try_const_usize(db, &count).ok_or(LayoutError::UserError(
|
||||
"unevaluated or mistyped const generic parameter".to_string(),
|
||||
))? as u64;
|
||||
let element = db.layout_of_ty(element.clone(), krate)?;
|
||||
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
|
||||
let size = element.size.checked_mul(count, dl).ok_or(LayoutError::SizeOverflow)?;
|
||||
|
||||
let abi = if count != 0 && matches!(element.abi, Abi::Uninhabited) {
|
||||
|
|
@ -259,7 +257,7 @@ pub fn layout_of_ty_query(
|
|||
}
|
||||
}
|
||||
TyKind::Slice(element) => {
|
||||
let element = db.layout_of_ty(element.clone(), krate)?;
|
||||
let element = db.layout_of_ty(element.clone(), trait_env.clone())?;
|
||||
Layout {
|
||||
variants: Variants::Single { index: struct_variant_idx() },
|
||||
fields: FieldsShape::Array { stride: element.size, count: 0 },
|
||||
|
|
@ -335,7 +333,7 @@ pub fn layout_of_ty_query(
|
|||
match impl_trait_id {
|
||||
crate::ImplTraitId::ReturnTypeImplTrait(func, idx) => {
|
||||
let infer = db.infer(func.into());
|
||||
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), krate);
|
||||
return db.layout_of_ty(infer.type_of_rpit[idx].clone(), trait_env.clone());
|
||||
}
|
||||
crate::ImplTraitId::AsyncBlockTypeImplTrait(_, _) => {
|
||||
return Err(LayoutError::NotImplemented)
|
||||
|
|
@ -351,7 +349,7 @@ pub fn layout_of_ty_query(
|
|||
.map(|it| {
|
||||
db.layout_of_ty(
|
||||
it.ty.clone().substitute(Interner, ClosureSubst(subst).parent_subst()),
|
||||
krate,
|
||||
trait_env.clone(),
|
||||
)
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
|
@ -377,7 +375,7 @@ pub fn layout_of_ty_recover(
|
|||
_: &dyn HirDatabase,
|
||||
_: &[String],
|
||||
_: &Ty,
|
||||
_: &CrateId,
|
||||
_: &Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,7 +2,6 @@
|
|||
|
||||
use std::{cmp, ops::Bound};
|
||||
|
||||
use base_db::CrateId;
|
||||
use hir_def::{
|
||||
data::adt::VariantData,
|
||||
layout::{Integer, LayoutCalculator, ReprOptions, TargetDataLayout},
|
||||
|
|
@ -16,7 +15,7 @@ use crate::{
|
|||
db::HirDatabase,
|
||||
lang_items::is_unsafe_cell,
|
||||
layout::{field_ty, Layout, LayoutError, RustcEnumVariantIdx},
|
||||
Substitution,
|
||||
Substitution, TraitEnvironment,
|
||||
};
|
||||
|
||||
use super::LayoutCx;
|
||||
|
|
@ -29,17 +28,18 @@ pub fn layout_of_adt_query(
|
|||
db: &dyn HirDatabase,
|
||||
def: AdtId,
|
||||
subst: Substitution,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
let krate = trait_env.krate;
|
||||
let Some(target) = db.target_data_layout(krate) else {
|
||||
return Err(LayoutError::TargetLayoutNotAvailable);
|
||||
};
|
||||
let cx = LayoutCx { krate, target: &target };
|
||||
let cx = LayoutCx { target: &target };
|
||||
let dl = cx.current_data_layout();
|
||||
let handle_variant = |def: VariantId, var: &VariantData| {
|
||||
var.fields()
|
||||
.iter()
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), cx.krate))
|
||||
.map(|(fd, _)| db.layout_of_ty(field_ty(db, def, fd, &subst), trait_env.clone()))
|
||||
.collect::<Result<Vec<_>, _>>()
|
||||
};
|
||||
let (variants, repr) = match def {
|
||||
|
|
@ -134,7 +134,7 @@ pub fn layout_of_adt_recover(
|
|||
_: &[String],
|
||||
_: &AdtId,
|
||||
_: &Substitution,
|
||||
_: &CrateId,
|
||||
_: &Arc<TraitEnvironment>,
|
||||
) -> Result<Arc<Layout>, LayoutError> {
|
||||
user_error!("infinite sized recursive type");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
);
|
||||
|
||||
let (db, file_ids) = TestDB::with_many_files(&ra_fixture);
|
||||
let (adt_or_type_alias_id, module_id) = file_ids
|
||||
let adt_or_type_alias_id = file_ids
|
||||
.into_iter()
|
||||
.find_map(|file_id| {
|
||||
let module_id = db.module_for_file(file_id);
|
||||
|
|
@ -47,7 +47,7 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
}
|
||||
_ => None,
|
||||
})?;
|
||||
Some((adt_or_type_alias_id, module_id))
|
||||
Some(adt_or_type_alias_id)
|
||||
})
|
||||
.unwrap();
|
||||
let goal_ty = match adt_or_type_alias_id {
|
||||
|
|
@ -58,7 +58,13 @@ fn eval_goal(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
db.ty(ty_id.into()).substitute(Interner, &Substitution::empty(Interner))
|
||||
}
|
||||
};
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
db.layout_of_ty(
|
||||
goal_ty,
|
||||
db.trait_environment(match adt_or_type_alias_id {
|
||||
Either::Left(adt) => hir_def::GenericDefId::AdtId(adt),
|
||||
Either::Right(ty) => hir_def::GenericDefId::TypeAliasId(ty),
|
||||
}),
|
||||
)
|
||||
}
|
||||
|
||||
/// A version of `eval_goal` for types that can not be expressed in ADTs, like closures and `impl Trait`
|
||||
|
|
@ -72,7 +78,7 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
let module_id = db.module_for_file(file_id);
|
||||
let def_map = module_id.def_map(&db);
|
||||
let scope = &def_map[module_id.local_id].scope;
|
||||
let adt_id = scope
|
||||
let function_id = scope
|
||||
.declarations()
|
||||
.find_map(|x| match x {
|
||||
hir_def::ModuleDefId::FunctionId(x) => {
|
||||
|
|
@ -82,11 +88,11 @@ fn eval_expr(ra_fixture: &str, minicore: &str) -> Result<Arc<Layout>, LayoutErro
|
|||
_ => None,
|
||||
})
|
||||
.unwrap();
|
||||
let hir_body = db.body(adt_id.into());
|
||||
let hir_body = db.body(function_id.into());
|
||||
let b = hir_body.bindings.iter().find(|x| x.1.name.to_smol_str() == "goal").unwrap().0;
|
||||
let infer = db.infer(adt_id.into());
|
||||
let infer = db.infer(function_id.into());
|
||||
let goal_ty = infer.type_of_binding[b].clone();
|
||||
db.layout_of_ty(goal_ty, module_id.krate())
|
||||
db.layout_of_ty(goal_ty, db.trait_environment(function_id.into()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
|
|
|
|||
|
|
@ -665,13 +665,21 @@ pub fn is_dyn_method(
|
|||
};
|
||||
let self_ty = trait_ref.self_type_parameter(Interner);
|
||||
if let TyKind::Dyn(d) = self_ty.kind(Interner) {
|
||||
let is_my_trait_in_bounds =
|
||||
d.bounds.skip_binders().as_slice(Interner).iter().any(|it| match it.skip_binders() {
|
||||
// rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
|
||||
// what the generics are, we are sure that the method is come from the vtable.
|
||||
WhereClause::Implemented(tr) => tr.trait_id == trait_ref.trait_id,
|
||||
_ => false,
|
||||
});
|
||||
let is_my_trait_in_bounds = d
|
||||
.bounds
|
||||
.skip_binders()
|
||||
.as_slice(Interner)
|
||||
.iter()
|
||||
.map(|it| it.skip_binders())
|
||||
.flat_map(|it| match it {
|
||||
WhereClause::Implemented(tr) => {
|
||||
all_super_traits(db.upcast(), from_chalk_trait_id(tr.trait_id))
|
||||
}
|
||||
_ => smallvec![],
|
||||
})
|
||||
// rustc doesn't accept `impl Foo<2> for dyn Foo<5>`, so if the trait id is equal, no matter
|
||||
// what the generics are, we are sure that the method is come from the vtable.
|
||||
.any(|x| x == trait_id);
|
||||
if is_my_trait_in_bounds {
|
||||
return Some(fn_params);
|
||||
}
|
||||
|
|
@ -1504,7 +1512,7 @@ fn autoderef_method_receiver(
|
|||
ty: Ty,
|
||||
) -> Vec<(Canonical<Ty>, ReceiverAdjustments)> {
|
||||
let mut deref_chain: Vec<_> = Vec::new();
|
||||
let mut autoderef = autoderef::Autoderef::new(table, ty, true);
|
||||
let mut autoderef = autoderef::Autoderef::new(table, ty, false);
|
||||
while let Some((ty, derefs)) = autoderef.next() {
|
||||
deref_chain.push((
|
||||
autoderef.table.canonicalize(ty).value,
|
||||
|
|
|
|||
|
|
@ -142,7 +142,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
closure_field: impl FnOnce(ClosureId, &Substitution, usize) -> Ty,
|
||||
krate: CrateId,
|
||||
) -> Ty {
|
||||
if matches!(base.data(Interner).kind, TyKind::Alias(_) | TyKind::AssociatedType(..)) {
|
||||
if matches!(base.kind(Interner), TyKind::Alias(_) | TyKind::AssociatedType(..)) {
|
||||
base = normalize(
|
||||
db,
|
||||
// FIXME: we should get this from caller
|
||||
|
|
@ -151,7 +151,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
);
|
||||
}
|
||||
match self {
|
||||
ProjectionElem::Deref => match &base.data(Interner).kind {
|
||||
ProjectionElem::Deref => match &base.kind(Interner) {
|
||||
TyKind::Raw(_, inner) | TyKind::Ref(_, _, inner) => inner.clone(),
|
||||
TyKind::Adt(adt, subst) if is_box(db, adt.0) => {
|
||||
subst.at(Interner, 0).assert_ty_ref(Interner).clone()
|
||||
|
|
@ -161,7 +161,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
return TyKind::Error.intern(Interner);
|
||||
}
|
||||
},
|
||||
ProjectionElem::Field(f) => match &base.data(Interner).kind {
|
||||
ProjectionElem::Field(f) => match &base.kind(Interner) {
|
||||
TyKind::Adt(_, subst) => {
|
||||
db.field_types(f.parent)[f.local_id].clone().substitute(Interner, subst)
|
||||
}
|
||||
|
|
@ -170,7 +170,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
return TyKind::Error.intern(Interner);
|
||||
}
|
||||
},
|
||||
ProjectionElem::TupleOrClosureField(f) => match &base.data(Interner).kind {
|
||||
ProjectionElem::TupleOrClosureField(f) => match &base.kind(Interner) {
|
||||
TyKind::Tuple(_, subst) => subst
|
||||
.as_slice(Interner)
|
||||
.get(*f)
|
||||
|
|
@ -187,7 +187,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
}
|
||||
},
|
||||
ProjectionElem::ConstantIndex { .. } | ProjectionElem::Index(_) => {
|
||||
match &base.data(Interner).kind {
|
||||
match &base.kind(Interner) {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
|
||||
_ => {
|
||||
never!("Overloaded index is not a projection");
|
||||
|
|
@ -195,7 +195,7 @@ impl<V, T> ProjectionElem<V, T> {
|
|||
}
|
||||
}
|
||||
}
|
||||
&ProjectionElem::Subslice { from, to } => match &base.data(Interner).kind {
|
||||
&ProjectionElem::Subslice { from, to } => match &base.kind(Interner) {
|
||||
TyKind::Array(inner, c) => {
|
||||
let next_c = usize_const(
|
||||
db,
|
||||
|
|
|
|||
|
|
@ -484,9 +484,10 @@ pub fn interpret_mir(
|
|||
// a zero size, hoping that they are all outside of our current body. Even without a fix for #7434, we can
|
||||
// (and probably should) do better here, for example by excluding bindings outside of the target expression.
|
||||
assert_placeholder_ty_is_unused: bool,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> (Result<Const>, String, String) {
|
||||
let ty = body.locals[return_slot()].ty.clone();
|
||||
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused);
|
||||
let mut evaluator = Evaluator::new(db, body.owner, assert_placeholder_ty_is_unused, trait_env);
|
||||
let it: Result<Const> = (|| {
|
||||
if evaluator.ptr_size() != std::mem::size_of::<usize>() {
|
||||
not_supported!("targets with different pointer size from host");
|
||||
|
|
@ -512,9 +513,9 @@ impl Evaluator<'_> {
|
|||
db: &'a dyn HirDatabase,
|
||||
owner: DefWithBodyId,
|
||||
assert_placeholder_ty_is_unused: bool,
|
||||
trait_env: Option<Arc<TraitEnvironment>>,
|
||||
) -> Evaluator<'a> {
|
||||
let crate_id = owner.module(db.upcast()).krate();
|
||||
let trait_env = db.trait_environment_for_body(owner);
|
||||
Evaluator {
|
||||
stack: vec![0],
|
||||
heap: vec![0],
|
||||
|
|
@ -524,7 +525,7 @@ impl Evaluator<'_> {
|
|||
static_locations: HashMap::default(),
|
||||
db,
|
||||
random_state: oorandom::Rand64::new(0),
|
||||
trait_env,
|
||||
trait_env: trait_env.unwrap_or_else(|| db.trait_environment_for_body(owner)),
|
||||
crate_id,
|
||||
stdout: vec![],
|
||||
stderr: vec![],
|
||||
|
|
@ -634,7 +635,7 @@ impl Evaluator<'_> {
|
|||
addr = addr.offset(ty_size * offset);
|
||||
}
|
||||
&ProjectionElem::Subslice { from, to } => {
|
||||
let inner_ty = match &ty.data(Interner).kind {
|
||||
let inner_ty = match &ty.kind(Interner) {
|
||||
TyKind::Array(inner, _) | TyKind::Slice(inner) => inner.clone(),
|
||||
_ => TyKind::Error.intern(Interner),
|
||||
};
|
||||
|
|
@ -694,14 +695,14 @@ impl Evaluator<'_> {
|
|||
}
|
||||
let r = self
|
||||
.db
|
||||
.layout_of_ty(ty.clone(), self.crate_id)
|
||||
.layout_of_ty(ty.clone(), self.trait_env.clone())
|
||||
.map_err(|e| MirEvalError::LayoutError(e, ty.clone()))?;
|
||||
self.layout_cache.borrow_mut().insert(ty.clone(), r.clone());
|
||||
Ok(r)
|
||||
}
|
||||
|
||||
fn layout_adt(&self, adt: AdtId, subst: Substitution) -> Result<Arc<Layout>> {
|
||||
self.db.layout_of_adt(adt, subst.clone(), self.crate_id).map_err(|e| {
|
||||
self.db.layout_of_adt(adt, subst.clone(), self.trait_env.clone()).map_err(|e| {
|
||||
MirEvalError::LayoutError(e, TyKind::Adt(chalk_ir::AdtId(adt), subst).intern(Interner))
|
||||
})
|
||||
}
|
||||
|
|
@ -793,7 +794,7 @@ impl Evaluator<'_> {
|
|||
.iter()
|
||||
.map(|it| self.operand_ty_and_eval(it, &mut locals))
|
||||
.collect::<Result<Vec<_>>>()?;
|
||||
let stack_frame = match &fn_ty.data(Interner).kind {
|
||||
let stack_frame = match &fn_ty.kind(Interner) {
|
||||
TyKind::Function(_) => {
|
||||
let bytes = self.eval_operand(func, &mut locals)?;
|
||||
self.exec_fn_pointer(
|
||||
|
|
@ -1255,7 +1256,7 @@ impl Evaluator<'_> {
|
|||
PointerCast::ReifyFnPointer | PointerCast::ClosureFnPointer(_) => {
|
||||
let current_ty = self.operand_ty(operand, locals)?;
|
||||
if let TyKind::FnDef(_, _) | TyKind::Closure(_, _) =
|
||||
¤t_ty.data(Interner).kind
|
||||
¤t_ty.kind(Interner)
|
||||
{
|
||||
let id = self.vtable_map.id(current_ty);
|
||||
let ptr_size = self.ptr_size();
|
||||
|
|
@ -1408,8 +1409,8 @@ impl Evaluator<'_> {
|
|||
addr: Interval,
|
||||
) -> Result<IntervalOrOwned> {
|
||||
use IntervalOrOwned::*;
|
||||
Ok(match &target_ty.data(Interner).kind {
|
||||
TyKind::Slice(_) => match ¤t_ty.data(Interner).kind {
|
||||
Ok(match &target_ty.kind(Interner) {
|
||||
TyKind::Slice(_) => match ¤t_ty.kind(Interner) {
|
||||
TyKind::Array(_, size) => {
|
||||
let len = match try_const_usize(self.db, size) {
|
||||
None => {
|
||||
|
|
@ -1435,7 +1436,7 @@ impl Evaluator<'_> {
|
|||
r.extend(vtable.to_le_bytes().into_iter());
|
||||
Owned(r)
|
||||
}
|
||||
TyKind::Adt(id, target_subst) => match ¤t_ty.data(Interner).kind {
|
||||
TyKind::Adt(id, target_subst) => match ¤t_ty.kind(Interner) {
|
||||
TyKind::Adt(current_id, current_subst) => {
|
||||
if id != current_id {
|
||||
not_supported!("unsizing struct with different type");
|
||||
|
|
@ -1582,10 +1583,13 @@ impl Evaluator<'_> {
|
|||
const_id = hir_def::GeneralConstId::ConstId(c);
|
||||
subst = s;
|
||||
}
|
||||
result_owner = self.db.const_eval(const_id.into(), subst).map_err(|e| {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
MirEvalError::ConstEvalError(name, Box::new(e))
|
||||
})?;
|
||||
result_owner = self
|
||||
.db
|
||||
.const_eval(const_id.into(), subst, Some(self.trait_env.clone()))
|
||||
.map_err(|e| {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
MirEvalError::ConstEvalError(name, Box::new(e))
|
||||
})?;
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &result_owner.data(Interner).value {
|
||||
if let ConstScalar::Bytes(v, mm) = &c.interned {
|
||||
break 'b (v, mm);
|
||||
|
|
@ -1818,9 +1822,13 @@ impl Evaluator<'_> {
|
|||
}
|
||||
AdtId::EnumId(e) => {
|
||||
let layout = this.layout(ty)?;
|
||||
if let Some((v, l)) =
|
||||
detect_variant_from_bytes(&layout, this.db, this.crate_id, bytes, e)
|
||||
{
|
||||
if let Some((v, l)) = detect_variant_from_bytes(
|
||||
&layout,
|
||||
this.db,
|
||||
this.trait_env.clone(),
|
||||
bytes,
|
||||
e,
|
||||
) {
|
||||
let data = &this.db.enum_data(e).variants[v].variant_data;
|
||||
let field_types = this
|
||||
.db
|
||||
|
|
@ -1931,7 +1939,7 @@ impl Evaluator<'_> {
|
|||
) -> Result<Option<StackFrame>> {
|
||||
let id = from_bytes!(usize, bytes.get(self)?);
|
||||
let next_ty = self.vtable_map.ty(id)?.clone();
|
||||
match &next_ty.data(Interner).kind {
|
||||
match &next_ty.kind(Interner) {
|
||||
TyKind::FnDef(def, generic_args) => {
|
||||
self.exec_fn_def(*def, generic_args, destination, args, &locals, target_bb, span)
|
||||
}
|
||||
|
|
@ -2182,7 +2190,7 @@ impl Evaluator<'_> {
|
|||
let size = self.size_of_sized(&func_ty, locals, "self type of fn trait")?;
|
||||
func_data = Interval { addr: Address::from_bytes(func_data.get(self)?)?, size };
|
||||
}
|
||||
match &func_ty.data(Interner).kind {
|
||||
match &func_ty.kind(Interner) {
|
||||
TyKind::FnDef(def, subst) => {
|
||||
return self.exec_fn_def(
|
||||
*def,
|
||||
|
|
@ -2409,7 +2417,7 @@ pub fn render_const_using_debug_impl(
|
|||
owner: ConstId,
|
||||
c: &Const,
|
||||
) -> Result<String> {
|
||||
let mut evaluator = Evaluator::new(db, owner.into(), false);
|
||||
let mut evaluator = Evaluator::new(db, owner.into(), false, None);
|
||||
let locals = &Locals {
|
||||
ptr: ArenaMap::new(),
|
||||
body: db
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ fn eval_main(db: &TestDB, file_id: FileId) -> Result<(String, String), MirEvalEr
|
|||
db.trait_environment(func_id.into()),
|
||||
)
|
||||
.map_err(|e| MirEvalError::MirLowerError(func_id.into(), e))?;
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false, None);
|
||||
result?;
|
||||
Ok((stdout, stderr))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -633,7 +633,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
);
|
||||
}
|
||||
let callee_ty = self.expr_ty_after_adjustments(*callee);
|
||||
match &callee_ty.data(Interner).kind {
|
||||
match &callee_ty.kind(Interner) {
|
||||
chalk_ir::TyKind::FnDef(..) => {
|
||||
let func = Operand::from_bytes(vec![], callee_ty.clone());
|
||||
self.lower_call_and_args(
|
||||
|
|
@ -1229,7 +1229,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
}
|
||||
Expr::Array(l) => match l {
|
||||
Array::ElementList { elements, .. } => {
|
||||
let elem_ty = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
|
||||
let elem_ty = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
|
||||
TyKind::Array(ty, _) => ty.clone(),
|
||||
_ => {
|
||||
return Err(MirLowerError::TypeError(
|
||||
|
|
@ -1260,7 +1260,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
else {
|
||||
return Ok(None);
|
||||
};
|
||||
let len = match &self.expr_ty_without_adjust(expr_id).data(Interner).kind {
|
||||
let len = match &self.expr_ty_without_adjust(expr_id).kind(Interner) {
|
||||
TyKind::Array(_, len) => len.clone(),
|
||||
_ => {
|
||||
return Err(MirLowerError::TypeError(
|
||||
|
|
@ -1341,7 +1341,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<Operand> {
|
||||
let size = self
|
||||
.db
|
||||
.layout_of_ty(ty.clone(), self.owner.module(self.db.upcast()).krate())?
|
||||
.layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))?
|
||||
.size
|
||||
.bytes_usize();
|
||||
let bytes = match l {
|
||||
|
|
@ -1355,7 +1355,6 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
return Ok(Operand::from_concrete_const(data, mm, ty));
|
||||
}
|
||||
hir_def::hir::Literal::CString(b) => {
|
||||
let b = b.as_bytes();
|
||||
let bytes = b.iter().copied().chain(iter::once(0)).collect::<Vec<_>>();
|
||||
|
||||
let mut data = Vec::with_capacity(mem::size_of::<usize>() * 2);
|
||||
|
|
@ -1418,7 +1417,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
|||
} else {
|
||||
let name = const_id.name(self.db.upcast());
|
||||
self.db
|
||||
.const_eval(const_id.into(), subst)
|
||||
.const_eval(const_id.into(), subst, None)
|
||||
.map_err(|e| MirLowerError::ConstEvalError(name, Box::new(e)))?
|
||||
};
|
||||
Ok(Operand::Constant(c))
|
||||
|
|
|
|||
|
|
@ -1236,6 +1236,27 @@ fn main() {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn inherent_method_ref_self_deref_raw() {
|
||||
check_types(
|
||||
r#"
|
||||
struct Val;
|
||||
|
||||
impl Val {
|
||||
pub fn method(&self) -> u32 {
|
||||
0
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let foo: *const Val;
|
||||
foo.method();
|
||||
// ^^^^^^^^^^^^ {unknown}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn trait_method_deref_raw() {
|
||||
check_types(
|
||||
|
|
|
|||
|
|
@ -4434,3 +4434,47 @@ fn test(v: S<i32>) {
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn associated_type_in_argument() {
|
||||
check(
|
||||
r#"
|
||||
trait A {
|
||||
fn m(&self) -> i32;
|
||||
}
|
||||
|
||||
fn x<T: B>(k: &<T as B>::Ty) {
|
||||
k.m();
|
||||
}
|
||||
|
||||
struct X;
|
||||
struct Y;
|
||||
|
||||
impl A for X {
|
||||
fn m(&self) -> i32 {
|
||||
8
|
||||
}
|
||||
}
|
||||
|
||||
impl A for Y {
|
||||
fn m(&self) -> i32 {
|
||||
32
|
||||
}
|
||||
}
|
||||
|
||||
trait B {
|
||||
type Ty: A;
|
||||
}
|
||||
|
||||
impl B for u16 {
|
||||
type Ty = X;
|
||||
}
|
||||
|
||||
fn ttt() {
|
||||
let inp = Y;
|
||||
x::<u16>(&inp);
|
||||
//^^^^ expected &X, got &Y
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,14 +28,15 @@ use intern::Interned;
|
|||
use rustc_hash::FxHashSet;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
consteval::unknown_const,
|
||||
db::HirDatabase,
|
||||
layout::{Layout, TagEncoding},
|
||||
mir::pad16,
|
||||
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitRef, TraitRefExt,
|
||||
Ty, WhereClause,
|
||||
ChalkTraitId, Const, ConstScalar, GenericArg, Interner, Substitution, TraitEnvironment,
|
||||
TraitRef, TraitRefExt, Ty, WhereClause,
|
||||
};
|
||||
|
||||
pub(crate) fn fn_traits(
|
||||
|
|
@ -417,7 +418,7 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
|||
) -> Result<Const, Self::Error> {
|
||||
if let chalk_ir::ConstValue::Concrete(c) = &constant.data(Interner).value {
|
||||
if let ConstScalar::UnevaluatedConst(id, subst) = &c.interned {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone()) {
|
||||
if let Ok(eval) = self.db.const_eval(*id, subst.clone(), None) {
|
||||
return Ok(eval);
|
||||
} else {
|
||||
return Ok(unknown_const(constant.data(Interner).ty.clone()));
|
||||
|
|
@ -431,10 +432,11 @@ impl FallibleTypeFolder<Interner> for UnevaluatedConstEvaluatorFolder<'_> {
|
|||
pub(crate) fn detect_variant_from_bytes<'a>(
|
||||
layout: &'a Layout,
|
||||
db: &dyn HirDatabase,
|
||||
krate: CrateId,
|
||||
trait_env: Arc<TraitEnvironment>,
|
||||
b: &[u8],
|
||||
e: EnumId,
|
||||
) -> Option<(LocalEnumVariantId, &'a Layout)> {
|
||||
let krate = trait_env.krate;
|
||||
let (var_id, var_layout) = match &layout.variants {
|
||||
hir_def::layout::Variants::Single { index } => (index.0, &*layout),
|
||||
hir_def::layout::Variants::Multiple { tag, tag_encoding, variants, .. } => {
|
||||
|
|
|
|||
|
|
@ -378,11 +378,6 @@ impl ModuleDef {
|
|||
ModuleDef::BuiltinType(_) | ModuleDef::Macro(_) => return Vec::new(),
|
||||
};
|
||||
|
||||
let module = match self.module(db) {
|
||||
Some(it) => it,
|
||||
None => return Vec::new(),
|
||||
};
|
||||
|
||||
let mut acc = Vec::new();
|
||||
|
||||
match self.as_def_with_body() {
|
||||
|
|
@ -390,7 +385,7 @@ impl ModuleDef {
|
|||
def.diagnostics(db, &mut acc);
|
||||
}
|
||||
None => {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, module.id.krate(), id) {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, id) {
|
||||
acc.push(diag.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -965,8 +960,15 @@ impl Field {
|
|||
}
|
||||
|
||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||
db.layout_of_ty(self.ty(db).ty.clone(), self.parent.module(db).krate().into())
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
|
||||
db.layout_of_ty(
|
||||
self.ty(db).ty.clone(),
|
||||
db.trait_environment(match hir_def::VariantId::from(self.parent) {
|
||||
hir_def::VariantId::EnumVariantId(id) => GenericDefId::EnumVariantId(id),
|
||||
hir_def::VariantId::StructId(id) => GenericDefId::AdtId(id.into()),
|
||||
hir_def::VariantId::UnionId(id) => GenericDefId::AdtId(id.into()),
|
||||
}),
|
||||
)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.krate(db).into()).unwrap()))
|
||||
}
|
||||
|
||||
pub fn parent_def(&self, _db: &dyn HirDatabase) -> VariantDef {
|
||||
|
|
@ -1246,8 +1248,12 @@ impl Adt {
|
|||
return Err(LayoutError::HasPlaceholder);
|
||||
}
|
||||
let krate = self.krate(db).id;
|
||||
db.layout_of_adt(self.into(), Substitution::empty(Interner), krate)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
|
||||
db.layout_of_adt(
|
||||
self.into(),
|
||||
Substitution::empty(Interner),
|
||||
db.trait_environment(self.into()),
|
||||
)
|
||||
.map(|layout| Layout(layout, db.target_data_layout(krate).unwrap()))
|
||||
}
|
||||
|
||||
/// Turns this ADT into a type. Any type parameters of the ADT will be
|
||||
|
|
@ -1820,7 +1826,7 @@ impl DefWithBody {
|
|||
// FIXME: don't ignore diagnostics for in type const
|
||||
DefWithBody::InTypeConst(_) => return,
|
||||
};
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, krate, def.into()) {
|
||||
for diag in hir_ty::diagnostics::incorrect_case(db, def.into()) {
|
||||
acc.push(diag.into())
|
||||
}
|
||||
}
|
||||
|
|
@ -1987,7 +1993,7 @@ impl Function {
|
|||
return r;
|
||||
}
|
||||
};
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false);
|
||||
let (result, stdout, stderr) = interpret_mir(db, body, false, None);
|
||||
let mut text = match result {
|
||||
Ok(_) => "pass".to_string(),
|
||||
Err(e) => {
|
||||
|
|
@ -2156,7 +2162,7 @@ impl Const {
|
|||
}
|
||||
|
||||
pub fn render_eval(self, db: &dyn HirDatabase) -> Result<String, ConstEvalError> {
|
||||
let c = db.const_eval(self.id.into(), Substitution::empty(Interner))?;
|
||||
let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
|
||||
let data = &c.data(Interner);
|
||||
if let TyKind::Scalar(s) = data.ty.kind(Interner) {
|
||||
if matches!(s, Scalar::Int(_) | Scalar::Uint(_)) {
|
||||
|
|
@ -4322,7 +4328,7 @@ impl Type {
|
|||
}
|
||||
|
||||
pub fn layout(&self, db: &dyn HirDatabase) -> Result<Layout, LayoutError> {
|
||||
db.layout_of_ty(self.ty.clone(), self.env.krate)
|
||||
db.layout_of_ty(self.ty.clone(), self.env.clone())
|
||||
.map(|layout| Layout(layout, db.target_data_layout(self.env.krate).unwrap()))
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,9 +2,10 @@ use syntax::{
|
|||
ast::{self, HasName, HasVisibility},
|
||||
AstNode,
|
||||
SyntaxKind::{
|
||||
CONST, ENUM, FN, MACRO_DEF, MODULE, STATIC, STRUCT, TRAIT, TYPE_ALIAS, USE, VISIBILITY,
|
||||
self, ASSOC_ITEM_LIST, CONST, ENUM, FN, MACRO_DEF, MODULE, SOURCE_FILE, STATIC, STRUCT,
|
||||
TRAIT, TYPE_ALIAS, USE, VISIBILITY,
|
||||
},
|
||||
T,
|
||||
SyntaxNode, T,
|
||||
};
|
||||
|
||||
use crate::{utils::vis_offset, AssistContext, AssistId, AssistKind, Assists};
|
||||
|
|
@ -46,13 +47,11 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
|||
|
||||
let (offset, target) = if let Some(keyword) = item_keyword {
|
||||
let parent = keyword.parent()?;
|
||||
let def_kws =
|
||||
vec![CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
|
||||
// Parent is not a definition, can't add visibility
|
||||
if !def_kws.iter().any(|&def_kw| def_kw == parent.kind()) {
|
||||
|
||||
if !can_add(&parent) {
|
||||
return None;
|
||||
}
|
||||
// Already have visibility, do nothing
|
||||
// Already has visibility, do nothing
|
||||
if parent.children().any(|child| child.kind() == VISIBILITY) {
|
||||
return None;
|
||||
}
|
||||
|
|
@ -86,6 +85,29 @@ fn add_vis(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
|
|||
)
|
||||
}
|
||||
|
||||
fn can_add(node: &SyntaxNode) -> bool {
|
||||
const LEGAL: &[SyntaxKind] =
|
||||
&[CONST, STATIC, TYPE_ALIAS, FN, MODULE, STRUCT, ENUM, TRAIT, USE, MACRO_DEF];
|
||||
|
||||
LEGAL.contains(&node.kind()) && {
|
||||
let Some(p) = node.parent() else {
|
||||
return false;
|
||||
};
|
||||
|
||||
if p.kind() == ASSOC_ITEM_LIST {
|
||||
p.parent()
|
||||
.and_then(|it| ast::Impl::cast(it))
|
||||
// inherent impls i.e 'non-trait impls' have a non-local
|
||||
// effect, thus can have visibility even when nested.
|
||||
// so filter them out
|
||||
.filter(|imp| imp.for_token().is_none())
|
||||
.is_some()
|
||||
} else {
|
||||
matches!(p.kind(), SOURCE_FILE | MODULE)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn change_vis(acc: &mut Assists, vis: ast::Visibility) -> Option<()> {
|
||||
if vis.syntax().text() == "pub" {
|
||||
let target = vis.syntax().text_range();
|
||||
|
|
@ -129,6 +151,16 @@ mod tests {
|
|||
check_assist(change_visibility, "unsafe f$0n foo() {}", "pub(crate) unsafe fn foo() {}");
|
||||
check_assist(change_visibility, "$0macro foo() {}", "pub(crate) macro foo() {}");
|
||||
check_assist(change_visibility, "$0use foo;", "pub(crate) use foo;");
|
||||
check_assist(
|
||||
change_visibility,
|
||||
"impl Foo { f$0n foo() {} }",
|
||||
"impl Foo { pub(crate) fn foo() {} }",
|
||||
);
|
||||
check_assist(
|
||||
change_visibility,
|
||||
"fn bar() { impl Foo { f$0n foo() {} } }",
|
||||
"fn bar() { impl Foo { pub(crate) fn foo() {} } }",
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
@ -213,4 +245,33 @@ mod tests {
|
|||
check_assist_target(change_visibility, "pub(crate)$0 fn foo() {}", "pub(crate)");
|
||||
check_assist_target(change_visibility, "struct S { $0field: u32 }", "field");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_for_items_within_traits() {
|
||||
check_assist_not_applicable(change_visibility, "trait Foo { f$0n run() {} }");
|
||||
check_assist_not_applicable(change_visibility, "trait Foo { con$0st FOO: u8 = 69; }");
|
||||
check_assist_not_applicable(change_visibility, "impl Foo for Bar { f$0n quox() {} }");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn not_applicable_for_items_within_fns() {
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { unsafe f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { const f$0n inner() {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { con$0st FOO: u8 = 69; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { en$0um Foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { stru$0ct Foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { mo$0d foo {} }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { $0use foo; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { $0type Foo = Bar<T>; }");
|
||||
check_assist_not_applicable(change_visibility, "fn foo() { tr$0ait Foo {} }");
|
||||
check_assist_not_applicable(
|
||||
change_visibility,
|
||||
"fn foo() { impl Trait for Bar { f$0n bar() {} } }",
|
||||
);
|
||||
check_assist_not_applicable(
|
||||
change_visibility,
|
||||
"fn foo() { impl Trait for Bar { con$0st FOO: u8 = 69; } }",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -545,4 +545,100 @@ pub static SomeStatic: u8 = 10;
|
|||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fn_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
fn main() {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
let INNER_INNER = 42;
|
||||
//^^^^^^^^^^^ 💡 warn: Variable `INNER_INNER` should have snake_case name, e.g. `inner_inner`
|
||||
}
|
||||
|
||||
let INNER_LOCAL = 42;
|
||||
//^^^^^^^^^^^ 💡 warn: Variable `INNER_LOCAL` should have snake_case name, e.g. `inner_local`
|
||||
}
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn const_body_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
const _: () = {
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
|
||||
const foo: () = {
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
};
|
||||
};
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn static_body_inner_items() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
static FOO: () = {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
|
||||
static bar: () = {
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
};
|
||||
};
|
||||
"#,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn enum_variant_body_inner_item() {
|
||||
check_diagnostics(
|
||||
r#"
|
||||
enum E {
|
||||
A = {
|
||||
const foo: bool = true;
|
||||
//^^^ 💡 warn: Constant `foo` should have UPPER_SNAKE_CASE name, e.g. `FOO`
|
||||
static bar: bool = true;
|
||||
//^^^ 💡 warn: Static variable `bar` should have UPPER_SNAKE_CASE name, e.g. `BAR`
|
||||
fn BAZ() {}
|
||||
//^^^ 💡 warn: Function `BAZ` should have snake_case name, e.g. `baz`
|
||||
42
|
||||
},
|
||||
}
|
||||
"#,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ use syntax::{
|
|||
|
||||
use crate::{
|
||||
syntax_highlighting::{
|
||||
escape::{highlight_escape_char, highlight_escape_string},
|
||||
escape::{highlight_escape_byte, highlight_escape_char, highlight_escape_string},
|
||||
format::highlight_format_string,
|
||||
highlights::Highlights,
|
||||
macro_::MacroHighlighter,
|
||||
|
|
@ -471,6 +471,14 @@ fn traverse(
|
|||
};
|
||||
|
||||
highlight_escape_char(hl, &char, range.start())
|
||||
} else if ast::Byte::can_cast(token.kind())
|
||||
&& ast::Byte::can_cast(descended_token.kind())
|
||||
{
|
||||
let Some(byte) = ast::Byte::cast(token) else {
|
||||
continue;
|
||||
};
|
||||
|
||||
highlight_escape_byte(hl, &byte, range.start())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
//! Syntax highlighting for escape sequences
|
||||
use crate::syntax_highlighting::highlights::Highlights;
|
||||
use crate::{HlRange, HlTag};
|
||||
use syntax::ast::{Char, IsString};
|
||||
use syntax::ast::{Byte, Char, IsString};
|
||||
use syntax::{AstToken, TextRange, TextSize};
|
||||
|
||||
pub(super) fn highlight_escape_string<T: IsString>(
|
||||
|
|
@ -10,14 +10,14 @@ pub(super) fn highlight_escape_string<T: IsString>(
|
|||
start: TextSize,
|
||||
) {
|
||||
string.escaped_char_ranges(&mut |piece_range, char| {
|
||||
if char.is_err() {
|
||||
return;
|
||||
}
|
||||
|
||||
if string.text()[piece_range.start().into()..].starts_with('\\') {
|
||||
let highlight = match char {
|
||||
Ok(_) => HlTag::EscapeSequence,
|
||||
Err(_) => HlTag::InvalidEscapeSequence,
|
||||
};
|
||||
stack.add(HlRange {
|
||||
range: piece_range + start,
|
||||
highlight: HlTag::EscapeSequence.into(),
|
||||
highlight: highlight.into(),
|
||||
binding_hash: None,
|
||||
});
|
||||
}
|
||||
|
|
@ -26,6 +26,9 @@ pub(super) fn highlight_escape_string<T: IsString>(
|
|||
|
||||
pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start: TextSize) {
|
||||
if char.value().is_none() {
|
||||
// We do not emit invalid escapes highlighting here. The lexer would likely be in a bad
|
||||
// state and this token contains junks, since `'` is not a reliable delimiter (consider
|
||||
// lifetimes). Nonetheless, parser errors should already be emitted.
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -43,3 +46,24 @@ pub(super) fn highlight_escape_char(stack: &mut Highlights, char: &Char, start:
|
|||
TextRange::new(start + TextSize::from(1), start + TextSize::from(text.len() as u32 + 1));
|
||||
stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
|
||||
}
|
||||
|
||||
pub(super) fn highlight_escape_byte(stack: &mut Highlights, byte: &Byte, start: TextSize) {
|
||||
if byte.value().is_none() {
|
||||
// See `highlight_escape_char` for why no error highlighting here.
|
||||
return;
|
||||
}
|
||||
|
||||
let text = byte.text();
|
||||
if !text.starts_with("b'") || !text.ends_with('\'') {
|
||||
return;
|
||||
}
|
||||
|
||||
let text = &text[2..text.len() - 1];
|
||||
if !text.starts_with('\\') {
|
||||
return;
|
||||
}
|
||||
|
||||
let range =
|
||||
TextRange::new(start + TextSize::from(2), start + TextSize::from(text.len() as u32 + 2));
|
||||
stack.add(HlRange { range, highlight: HlTag::EscapeSequence.into(), binding_hash: None })
|
||||
}
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
";
|
||||
|
|
|
|||
|
|
@ -29,6 +29,7 @@ pub enum HlTag {
|
|||
Comment,
|
||||
EscapeSequence,
|
||||
FormatSpecifier,
|
||||
InvalidEscapeSequence,
|
||||
Keyword,
|
||||
NumericLiteral,
|
||||
Operator(HlOperator),
|
||||
|
|
@ -166,6 +167,7 @@ impl HlTag {
|
|||
HlTag::CharLiteral => "char_literal",
|
||||
HlTag::Comment => "comment",
|
||||
HlTag::EscapeSequence => "escape_sequence",
|
||||
HlTag::InvalidEscapeSequence => "invalid_escape_sequence",
|
||||
HlTag::FormatSpecifier => "format_specifier",
|
||||
HlTag::Keyword => "keyword",
|
||||
HlTag::Punctuation(punct) => match punct {
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">not_static</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="builtin_attr attribute library">allow</span><span class="parenthesis attribute">(</span><span class="none attribute">dead_code</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
|
||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="tool_module attribute library">rustfmt</span><span class="operator attribute">::</span><span class="tool_module attribute library">skip</span><span class="attribute_bracket attribute">]</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root library">foo</span><span class="semicolon">;</span>
|
||||
<span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">use</span> <span class="module crate_root default_library library">core</span><span class="operator">::</span><span class="module default_library library">iter</span><span class="semicolon">;</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">//! This is a module to test doc injection.</span>
|
||||
<span class="comment documentation">//! ```</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">std</span><span class="semicolon">;</span>
|
||||
<span class="keyword">extern</span> <span class="keyword">crate</span> <span class="module crate_root default_library library">alloc</span> <span class="keyword">as</span> <span class="module crate_root default_library declaration library">abc</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">use</span> <span class="module">inner</span><span class="operator">::</span><span class="brace">{</span><span class="self_keyword">self</span> <span class="keyword">as</span> <span class="module declaration">inner_mod</span><span class="brace">}</span><span class="semicolon">;</span>
|
||||
<span class="keyword">mod</span> <span class="module declaration">inner</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">fixture</span><span class="parenthesis">(</span><span class="value_param declaration reference">ra_fixture</span><span class="colon">:</span> <span class="punctuation">&</span><span class="builtin_type">str</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">extern</span> <span class="keyword">crate</span> <span class="self_keyword crate_root public">self</span><span class="semicolon">;</span>
|
||||
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code>
|
||||
<span class="attribute_bracket attribute">#</span><span class="attribute_bracket attribute">[</span><span class="attribute attribute default_library library">derive</span><span class="parenthesis attribute">(</span><span class="parenthesis attribute">)</span><span class="attribute_bracket attribute">]</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="module crate_root library">proc_macros</span><span class="operator">::</span><span class="macro library">mirror</span><span class="macro_bang">!</span> <span class="brace macro">{</span>
|
||||
<span class="brace macro">{</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">//! </span><span class="struct documentation injected intra_doc_link">[Struct]</span>
|
||||
<span class="comment documentation">//! This is an intra doc injection test for modules</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="comment documentation">/// </span><span class="struct documentation injected intra_doc_link">[crate::foo::Struct]</span>
|
||||
<span class="comment documentation">/// This is an intra doc injection test for modules</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||
<span class="numeric_literal">1</span> <span class="arithmetic">+</span> <span class="numeric_literal">1</span> <span class="arithmetic">-</span> <span class="numeric_literal">1</span> <span class="arithmetic">*</span> <span class="numeric_literal">1</span> <span class="arithmetic">/</span> <span class="numeric_literal">1</span> <span class="arithmetic">%</span> <span class="numeric_literal">1</span> <span class="bitwise">|</span> <span class="numeric_literal">1</span> <span class="bitwise">&</span> <span class="numeric_literal">1</span> <span class="logical">!</span> <span class="numeric_literal">1</span> <span class="bitwise">^</span> <span class="numeric_literal">1</span> <span class="bitwise">>></span> <span class="numeric_literal">1</span> <span class="bitwise"><<</span> <span class="numeric_literal">1</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration reference" data-binding-hash="8121853618659664005" style="color: hsl(273,88%,88%);">hello</span> <span class="operator">=</span> <span class="string_literal">"hello"</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">println</span> <span class="brace">{</span>
|
||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>arg<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="parenthesis">(</span><span class="brace">{</span>
|
||||
|
|
@ -105,6 +106,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x65</span><span class="char_literal">'</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="char_literal">'</span><span class="escape_sequence">\x00</span><span class="char_literal">'</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="variable declaration">a</span> <span class="operator">=</span> <span class="byte_literal">b'</span><span class="escape_sequence">\xFF</span><span class="byte_literal">'</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello </span><span class="escape_sequence">{{</span><span class="string_literal macro">Hello</span><span class="escape_sequence">}}</span><span class="string_literal macro">"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="comment">// from https://doc.rust-lang.org/std/fmt/index.html</span>
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span> <span class="comment">// => "Hello"</span>
|
||||
|
|
@ -159,8 +162,9 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"Hello</span><span class="escape_sequence">\n</span><span class="string_literal macro">World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="escape_sequence">\u{48}</span><span class="escape_sequence">\x65</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6C</span><span class="escape_sequence">\x6F</span><span class="string_literal macro"> World"</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="invalid_escape_sequence">\xFF</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// invalid non-UTF8 escape sequences</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">b"</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x28</span><span class="escape_sequence">\x00</span><span class="escape_sequence">\x63</span><span class="escape_sequence">\xFF</span><span class="invalid_escape_sequence">\u{FF}</span><span class="escape_sequence">\n</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, invalid unicodes</span>
|
||||
<span class="keyword">let</span> <span class="punctuation">_</span> <span class="operator">=</span> <span class="string_literal">c"</span><span class="escape_sequence">\u{FF}</span><span class="escape_sequence">\xFF</span><span class="string_literal">"</span><span class="semicolon">;</span> <span class="comment">// valid bytes, valid unicodes</span>
|
||||
<span class="keyword">let</span> <span class="variable declaration reference">backslash</span> <span class="operator">=</span> <span class="string_literal">r"\\"</span><span class="semicolon">;</span>
|
||||
|
||||
<span class="macro">println</span><span class="macro_bang">!</span><span class="parenthesis macro">(</span><span class="string_literal macro">"</span><span class="format_specifier">{</span><span class="escape_sequence">\x41</span><span class="format_specifier">}</span><span class="string_literal macro">"</span><span class="comma macro">,</span> <span class="none macro">A</span> <span class="operator macro">=</span> <span class="numeric_literal macro">92</span><span class="parenthesis macro">)</span><span class="semicolon">;</span>
|
||||
|
|
|
|||
|
|
@ -40,7 +40,8 @@ pre { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
|
|||
.control { font-style: italic; }
|
||||
.reference { font-style: italic; font-weight: bold; }
|
||||
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
.invalid_escape_sequence { color: #FC5555; text-decoration: wavy underline; }
|
||||
.unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
|
||||
</style>
|
||||
<pre><code><span class="keyword">macro_rules</span><span class="macro_bang">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
|
||||
<span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">></span> <span class="brace">{</span>
|
||||
|
|
|
|||
|
|
@ -451,6 +451,8 @@ fn main() {
|
|||
let a = '\x65';
|
||||
let a = '\x00';
|
||||
|
||||
let a = b'\xFF';
|
||||
|
||||
println!("Hello {{Hello}}");
|
||||
// from https://doc.rust-lang.org/std/fmt/index.html
|
||||
println!("Hello"); // => "Hello"
|
||||
|
|
@ -505,8 +507,9 @@ fn main() {
|
|||
println!("Hello\nWorld");
|
||||
println!("\u{48}\x65\x6C\x6C\x6F World");
|
||||
|
||||
let _ = "\x28\x28\x00\x63\n";
|
||||
let _ = b"\x28\x28\x00\x63\n";
|
||||
let _ = "\x28\x28\x00\x63\xFF\u{FF}\n"; // invalid non-UTF8 escape sequences
|
||||
let _ = b"\x28\x28\x00\x63\xFF\u{FF}\n"; // valid bytes, invalid unicodes
|
||||
let _ = c"\u{FF}\xFF"; // valid bytes, valid unicodes
|
||||
let backslash = r"\\";
|
||||
|
||||
println!("{\x41}", A = 92);
|
||||
|
|
|
|||
|
|
@ -211,70 +211,54 @@ impl BlockLike {
|
|||
const VISIBILITY_FIRST: TokenSet = TokenSet::new(&[T![pub], T![crate]]);
|
||||
|
||||
fn opt_visibility(p: &mut Parser<'_>, in_tuple_field: bool) -> bool {
|
||||
match p.current() {
|
||||
T![pub] => {
|
||||
let m = p.start();
|
||||
p.bump(T![pub]);
|
||||
if p.at(T!['(']) {
|
||||
match p.nth(1) {
|
||||
// test crate_visibility
|
||||
// pub(crate) struct S;
|
||||
// pub(self) struct S;
|
||||
// pub(super) struct S;
|
||||
if !p.at(T![pub]) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// test_err crate_visibility_empty_recover
|
||||
// pub() struct S;
|
||||
let m = p.start();
|
||||
p.bump(T![pub]);
|
||||
if p.at(T!['(']) {
|
||||
match p.nth(1) {
|
||||
// test crate_visibility
|
||||
// pub(crate) struct S;
|
||||
// pub(self) struct S;
|
||||
// pub(super) struct S;
|
||||
|
||||
// test pub_parens_typepath
|
||||
// struct B(pub (super::A));
|
||||
// struct B(pub (crate::A,));
|
||||
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
|
||||
// If we are in a tuple struct, then the parens following `pub`
|
||||
// might be an tuple field, not part of the visibility. So in that
|
||||
// case we don't want to consume an identifier.
|
||||
// test_err crate_visibility_empty_recover
|
||||
// pub() struct S;
|
||||
|
||||
// test pub_tuple_field
|
||||
// struct MyStruct(pub (u32, u32));
|
||||
// struct MyStruct(pub (u32));
|
||||
// struct MyStruct(pub ());
|
||||
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
|
||||
p.bump(T!['(']);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
}
|
||||
// test crate_visibility_in
|
||||
// pub(in super::A) struct S;
|
||||
// pub(in crate) struct S;
|
||||
T![in] => {
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![in]);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
_ => {}
|
||||
// test pub_parens_typepath
|
||||
// struct B(pub (super::A));
|
||||
// struct B(pub (crate::A,));
|
||||
T![crate] | T![self] | T![super] | T![ident] | T![')'] if p.nth(2) != T![:] => {
|
||||
// If we are in a tuple struct, then the parens following `pub`
|
||||
// might be an tuple field, not part of the visibility. So in that
|
||||
// case we don't want to consume an identifier.
|
||||
|
||||
// test pub_tuple_field
|
||||
// struct MyStruct(pub (u32, u32));
|
||||
// struct MyStruct(pub (u32));
|
||||
// struct MyStruct(pub ());
|
||||
if !(in_tuple_field && matches!(p.nth(1), T![ident] | T![')'])) {
|
||||
p.bump(T!['(']);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
}
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
}
|
||||
// test crate_keyword_vis
|
||||
// crate fn main() { }
|
||||
// struct S { crate field: u32 }
|
||||
// struct T(crate u32);
|
||||
T![crate] => {
|
||||
if p.nth_at(1, T![::]) {
|
||||
// test crate_keyword_path
|
||||
// fn foo() { crate::foo(); }
|
||||
return false;
|
||||
// test crate_visibility_in
|
||||
// pub(in super::A) struct S;
|
||||
// pub(in crate) struct S;
|
||||
T![in] => {
|
||||
p.bump(T!['(']);
|
||||
p.bump(T![in]);
|
||||
paths::use_path(p);
|
||||
p.expect(T![')']);
|
||||
}
|
||||
let m = p.start();
|
||||
p.bump(T![crate]);
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
_ => {}
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
m.complete(p, VISIBILITY);
|
||||
true
|
||||
}
|
||||
|
||||
fn opt_rename(p: &mut Parser<'_>) {
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@ fn vis() {
|
|||
check(PrefixEntryPoint::Vis, "fn foo() {}", "");
|
||||
check(PrefixEntryPoint::Vis, "pub(fn foo() {}", "pub");
|
||||
check(PrefixEntryPoint::Vis, "pub(crate fn foo() {}", "pub(crate");
|
||||
check(PrefixEntryPoint::Vis, "crate fn foo() {}", "crate");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -1,63 +0,0 @@
|
|||
SOURCE_FILE
|
||||
FN
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
FN_KW "fn"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "main"
|
||||
PARAM_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
STRUCT
|
||||
STRUCT_KW "struct"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "S"
|
||||
WHITESPACE " "
|
||||
RECORD_FIELD_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
RECORD_FIELD
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "field"
|
||||
COLON ":"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u32"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
STRUCT
|
||||
STRUCT_KW "struct"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "T"
|
||||
TUPLE_FIELD_LIST
|
||||
L_PAREN "("
|
||||
TUPLE_FIELD
|
||||
VISIBILITY
|
||||
CRATE_KW "crate"
|
||||
WHITESPACE " "
|
||||
PATH_TYPE
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "u32"
|
||||
R_PAREN ")"
|
||||
SEMICOLON ";"
|
||||
WHITESPACE "\n"
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
crate fn main() { }
|
||||
struct S { crate field: u32 }
|
||||
struct T(crate u32);
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
SOURCE_FILE
|
||||
FN
|
||||
FN_KW "fn"
|
||||
WHITESPACE " "
|
||||
NAME
|
||||
IDENT "foo"
|
||||
PARAM_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
WHITESPACE " "
|
||||
BLOCK_EXPR
|
||||
STMT_LIST
|
||||
L_CURLY "{"
|
||||
WHITESPACE " "
|
||||
EXPR_STMT
|
||||
CALL_EXPR
|
||||
PATH_EXPR
|
||||
PATH
|
||||
PATH
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
CRATE_KW "crate"
|
||||
COLON2 "::"
|
||||
PATH_SEGMENT
|
||||
NAME_REF
|
||||
IDENT "foo"
|
||||
ARG_LIST
|
||||
L_PAREN "("
|
||||
R_PAREN ")"
|
||||
SEMICOLON ";"
|
||||
WHITESPACE " "
|
||||
R_CURLY "}"
|
||||
WHITESPACE "\n"
|
||||
|
|
@ -1 +0,0 @@
|
|||
fn foo() { crate::foo(); }
|
||||
|
|
@ -145,7 +145,7 @@ pub struct PackageDependency {
|
|||
pub kind: DepKind,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Eq, PartialEq, PartialOrd, Ord)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum DepKind {
|
||||
/// Available to the library, binary, and dev targets in the package (but not the build script).
|
||||
Normal,
|
||||
|
|
@ -156,23 +156,20 @@ pub enum DepKind {
|
|||
}
|
||||
|
||||
impl DepKind {
|
||||
fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> + '_ {
|
||||
let mut dep_kinds = Vec::new();
|
||||
fn iter(list: &[cargo_metadata::DepKindInfo]) -> impl Iterator<Item = Self> {
|
||||
let mut dep_kinds = [None; 3];
|
||||
if list.is_empty() {
|
||||
dep_kinds.push(Self::Normal);
|
||||
dep_kinds[0] = Some(Self::Normal);
|
||||
}
|
||||
for info in list {
|
||||
let kind = match info.kind {
|
||||
cargo_metadata::DependencyKind::Normal => Self::Normal,
|
||||
cargo_metadata::DependencyKind::Development => Self::Dev,
|
||||
cargo_metadata::DependencyKind::Build => Self::Build,
|
||||
match info.kind {
|
||||
cargo_metadata::DependencyKind::Normal => dep_kinds[0] = Some(Self::Normal),
|
||||
cargo_metadata::DependencyKind::Development => dep_kinds[1] = Some(Self::Dev),
|
||||
cargo_metadata::DependencyKind::Build => dep_kinds[2] = Some(Self::Build),
|
||||
cargo_metadata::DependencyKind::Unknown => continue,
|
||||
};
|
||||
dep_kinds.push(kind);
|
||||
}
|
||||
}
|
||||
dep_kinds.sort_unstable();
|
||||
dep_kinds.dedup();
|
||||
dep_kinds.into_iter()
|
||||
dep_kinds.into_iter().flatten()
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ use std::{
|
|||
|
||||
use hir::{
|
||||
db::{DefDatabase, ExpandDatabase, HirDatabase},
|
||||
Adt, AssocItem, Crate, DefWithBody, HasCrate, HasSource, HirDisplay, ModuleDef, Name,
|
||||
Adt, AssocItem, Crate, DefWithBody, HasSource, HirDisplay, ModuleDef, Name,
|
||||
};
|
||||
use hir_def::{
|
||||
body::{BodySourceMap, SyntheticSyntax},
|
||||
|
|
@ -277,7 +277,7 @@ impl flags::AnalysisStats {
|
|||
let Err(e) = db.layout_of_adt(
|
||||
hir_def::AdtId::from(a).into(),
|
||||
Substitution::empty(Interner),
|
||||
a.krate(db).into(),
|
||||
db.trait_environment(a.into()),
|
||||
) else {
|
||||
continue;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ define_semantic_token_types![
|
|||
(DERIVE_HELPER, "deriveHelper") => DECORATOR,
|
||||
(DOT, "dot"),
|
||||
(ESCAPE_SEQUENCE, "escapeSequence") => STRING,
|
||||
(INVALID_ESCAPE_SEQUENCE, "invalidEscapeSequence") => STRING,
|
||||
(FORMAT_SPECIFIER, "formatSpecifier") => STRING,
|
||||
(GENERIC, "generic") => TYPE_PARAMETER,
|
||||
(LABEL, "label"),
|
||||
|
|
|
|||
|
|
@ -640,6 +640,7 @@ fn semantic_token_type_and_modifiers(
|
|||
HlTag::CharLiteral => semantic_tokens::CHAR,
|
||||
HlTag::Comment => semantic_tokens::COMMENT,
|
||||
HlTag::EscapeSequence => semantic_tokens::ESCAPE_SEQUENCE,
|
||||
HlTag::InvalidEscapeSequence => semantic_tokens::INVALID_ESCAPE_SEQUENCE,
|
||||
HlTag::FormatSpecifier => semantic_tokens::FORMAT_SPECIFIER,
|
||||
HlTag::Keyword => semantic_tokens::KEYWORD,
|
||||
HlTag::None => semantic_tokens::GENERIC,
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@
|
|||
|
||||
use std::borrow::Cow;
|
||||
|
||||
use rustc_lexer::unescape::{unescape_byte, unescape_char, unescape_literal, Mode};
|
||||
use rustc_lexer::unescape::{
|
||||
unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit, Mode,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
ast::{self, AstToken},
|
||||
|
|
@ -146,6 +148,7 @@ impl QuoteOffsets {
|
|||
|
||||
pub trait IsString: AstToken {
|
||||
const RAW_PREFIX: &'static str;
|
||||
const MODE: Mode;
|
||||
fn is_raw(&self) -> bool {
|
||||
self.text().starts_with(Self::RAW_PREFIX)
|
||||
}
|
||||
|
|
@ -181,7 +184,7 @@ pub trait IsString: AstToken {
|
|||
let text = &self.text()[text_range_no_quotes - start];
|
||||
let offset = text_range_no_quotes.start() - start;
|
||||
|
||||
unescape_literal(text, Mode::Str, &mut |range, unescaped_char| {
|
||||
unescape_literal(text, Self::MODE, &mut |range, unescaped_char| {
|
||||
let text_range =
|
||||
TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
|
||||
cb(text_range + offset, unescaped_char);
|
||||
|
|
@ -196,6 +199,7 @@ pub trait IsString: AstToken {
|
|||
|
||||
impl IsString for ast::String {
|
||||
const RAW_PREFIX: &'static str = "r";
|
||||
const MODE: Mode = Mode::Str;
|
||||
}
|
||||
|
||||
impl ast::String {
|
||||
|
|
@ -213,7 +217,7 @@ impl ast::String {
|
|||
let mut buf = String::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
|
||||
unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
|
|
@ -239,6 +243,7 @@ impl ast::String {
|
|||
|
||||
impl IsString for ast::ByteString {
|
||||
const RAW_PREFIX: &'static str = "br";
|
||||
const MODE: Mode = Mode::ByteStr;
|
||||
}
|
||||
|
||||
impl ast::ByteString {
|
||||
|
|
@ -256,7 +261,7 @@ impl ast::ByteString {
|
|||
let mut buf: Vec<u8> = Vec::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::ByteStr, &mut |char_range, unescaped_char| match (
|
||||
unescape_literal(text, Self::MODE, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
|
|
@ -282,42 +287,70 @@ impl ast::ByteString {
|
|||
|
||||
impl IsString for ast::CString {
|
||||
const RAW_PREFIX: &'static str = "cr";
|
||||
const MODE: Mode = Mode::CStr;
|
||||
|
||||
fn escaped_char_ranges(
|
||||
&self,
|
||||
cb: &mut dyn FnMut(TextRange, Result<char, rustc_lexer::unescape::EscapeError>),
|
||||
) {
|
||||
let text_range_no_quotes = match self.text_range_between_quotes() {
|
||||
Some(it) => it,
|
||||
None => return,
|
||||
};
|
||||
|
||||
let start = self.syntax().text_range().start();
|
||||
let text = &self.text()[text_range_no_quotes - start];
|
||||
let offset = text_range_no_quotes.start() - start;
|
||||
|
||||
unescape_c_string(text, Self::MODE, &mut |range, unescaped_char| {
|
||||
let text_range =
|
||||
TextRange::new(range.start.try_into().unwrap(), range.end.try_into().unwrap());
|
||||
// XXX: This method should only be used for highlighting ranges. The unescaped
|
||||
// char/byte is not used. For simplicity, we return an arbitrary placeholder char.
|
||||
cb(text_range + offset, unescaped_char.map(|_| ' '));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl ast::CString {
|
||||
pub fn value(&self) -> Option<Cow<'_, str>> {
|
||||
pub fn value(&self) -> Option<Cow<'_, [u8]>> {
|
||||
if self.is_raw() {
|
||||
let text = self.text();
|
||||
let text =
|
||||
&text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
return Some(Cow::Borrowed(text));
|
||||
return Some(Cow::Borrowed(text.as_bytes()));
|
||||
}
|
||||
|
||||
let text = self.text();
|
||||
let text = &text[self.text_range_between_quotes()? - self.syntax().text_range().start()];
|
||||
|
||||
let mut buf = String::new();
|
||||
let mut buf = Vec::new();
|
||||
let mut prev_end = 0;
|
||||
let mut has_error = false;
|
||||
unescape_literal(text, Mode::Str, &mut |char_range, unescaped_char| match (
|
||||
unescaped_char,
|
||||
let mut char_buf = [0u8; 4];
|
||||
let mut extend_unit = |buf: &mut Vec<u8>, unit: CStrUnit| match unit {
|
||||
CStrUnit::Byte(b) => buf.push(b),
|
||||
CStrUnit::Char(c) => buf.extend(c.encode_utf8(&mut char_buf).as_bytes()),
|
||||
};
|
||||
unescape_c_string(text, Self::MODE, &mut |char_range, unescaped| match (
|
||||
unescaped,
|
||||
buf.capacity() == 0,
|
||||
) {
|
||||
(Ok(c), false) => buf.push(c),
|
||||
(Ok(u), false) => extend_unit(&mut buf, u),
|
||||
(Ok(_), true) if char_range.len() == 1 && char_range.start == prev_end => {
|
||||
prev_end = char_range.end
|
||||
}
|
||||
(Ok(c), true) => {
|
||||
(Ok(u), true) => {
|
||||
buf.reserve_exact(text.len());
|
||||
buf.push_str(&text[..prev_end]);
|
||||
buf.push(c);
|
||||
buf.extend(text[..prev_end].as_bytes());
|
||||
extend_unit(&mut buf, u);
|
||||
}
|
||||
(Err(_), _) => has_error = true,
|
||||
});
|
||||
|
||||
match (has_error, buf.capacity() == 0) {
|
||||
(true, _) => None,
|
||||
(false, true) => Some(Cow::Borrowed(text)),
|
||||
(false, true) => Some(Cow::Borrowed(text.as_bytes())),
|
||||
(false, false) => Some(Cow::Owned(buf)),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -449,27 +449,24 @@ You'll need to close and reopen all .rs and Cargo files, or to restart the IDE,
|
|||
Support for the language server protocol is built into Kate through the LSP plugin, which is included by default.
|
||||
It is preconfigured to use rust-analyzer for Rust sources since Kate 21.12.
|
||||
|
||||
Earlier versions allow you to use rust-analyzer through a simple settings change.
|
||||
In the LSP Client settings of Kate, copy the content of the third tab "default parameters" to the second tab "server configuration".
|
||||
Then in the configuration replace:
|
||||
To change rust-analyzer config options, start from the following example and put it into Kate's "User Server Settings" tab (located under the LSP Client settings):
|
||||
[source,json]
|
||||
----
|
||||
{
|
||||
"servers": {
|
||||
"rust": {
|
||||
"command": ["rls"],
|
||||
"rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
|
||||
"url": "https://github.com/rust-lang/rls",
|
||||
"highlightingModeRegex": "^Rust$"
|
||||
},
|
||||
----
|
||||
With
|
||||
[source,json]
|
||||
----
|
||||
"rust": {
|
||||
"command": ["rust-analyzer"],
|
||||
"rootIndicationFileNames": ["Cargo.lock", "Cargo.toml"],
|
||||
"url": "https://github.com/rust-lang/rust-analyzer",
|
||||
"highlightingModeRegex": "^Rust$"
|
||||
},
|
||||
"initializationOptions": {
|
||||
"cachePriming": {
|
||||
"enable": false
|
||||
},
|
||||
"check": {
|
||||
"allTargets": false
|
||||
},
|
||||
"checkOnSave": false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
----
|
||||
Then click on apply, and restart the LSP server for your rust project.
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue