From 6a7a8d1c7e74d34dadaa1172245cf5d09a852605 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 22 Jul 2026 14:24:31 +0200 Subject: [PATCH 01/13] gnullvm: always link libunwind statically --- compiler/rustc_target/src/spec/base/windows_gnullvm.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 5db5fb95924c5..28afb54aed358 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -13,13 +13,14 @@ pub(crate) fn opts() -> TargetOptions { // but LLVM maintainers rejected it: https://reviews.llvm.org/D51440 let pre_link_args = TargetOptions::link_args( LinkerFlavor::Gnu(Cc::Yes, Lld::No), - &["-nolibc", "--unwindlib=none"], + &["-nolibc", "--unwindlib=libunwind", "-static-libgcc"], ); // Order of `late_link_args*` does not matter with LLD. let mingw_libs = &["-lmingw32", "-lmingwex", "-lmsvcrt", "-lkernel32", "-luser32"]; let mut late_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::No, Lld::No), mingw_libs); + add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::No, Lld::No), &["-l:libunwind.a"]); add_link_args(&mut late_link_args, LinkerFlavor::Gnu(Cc::Yes, Lld::No), mingw_libs); TargetOptions { From 9acbf04101f842031d8076705722a3c2539a5636 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 22 Jul 2026 14:24:31 +0200 Subject: [PATCH 02/13] gnullvm: stop handling crt-static --- compiler/rustc_target/src/spec/base/windows_gnullvm.rs | 2 -- library/unwind/src/lib.rs | 5 ----- 2 files changed, 7 deletions(-) diff --git a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs index 28afb54aed358..751927fcac0a7 100644 --- a/compiler/rustc_target/src/spec/base/windows_gnullvm.rs +++ b/compiler/rustc_target/src/spec/base/windows_gnullvm.rs @@ -47,8 +47,6 @@ pub(crate) fn opts() -> TargetOptions { eh_frame_header: false, no_default_libraries: false, has_thread_local: true, - crt_static_allows_dylibs: true, - crt_static_respected: true, debuginfo_kind: DebuginfoKind::Dwarf, // FIXME(davidtwco): Support Split DWARF on Windows GNU - may require LLVM changes to // output DWO, despite using DWARF, doesn't use ELF.. diff --git a/library/unwind/src/lib.rs b/library/unwind/src/lib.rs index 69b5e81a39215..3842e47781c53 100644 --- a/library/unwind/src/lib.rs +++ b/library/unwind/src/lib.rs @@ -219,8 +219,3 @@ unsafe extern "C" {} #[cfg(all(target_os = "wasi", panic = "unwind"))] #[link(name = "unwind")] unsafe extern "C" {} - -#[cfg(all(target_os = "windows", target_env = "gnu", target_abi = "llvm"))] -#[link(name = "unwind", kind = "static", modifiers = "-bundle", cfg(target_feature = "crt-static"))] -#[link(name = "unwind", cfg(not(target_feature = "crt-static")))] -unsafe extern "C" {} From 6e0d85d6de54a900737bdd7661ad24f114a981b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Wed, 22 Jul 2026 14:24:31 +0200 Subject: [PATCH 03/13] gnullvm: stop shipping libunwind import lib --- src/bootstrap/src/core/build_steps/dist.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 43ac42a8158ba..0f592486b5aca 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -323,7 +323,6 @@ fn make_win_llvm_dist(plat_root: &Path, target: TargetSelection, builder: &Build let target_libs = [ // MinGW libs "libunwind.a", - "libunwind.dll.a", "libmingw32.a", "libmingwex.a", "libmsvcrt.a", From e2eb9742f8796368da6cac71ee750e0656ad2720 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mateusz=20Miku=C5=82a?= Date: Fri, 7 Aug 2026 18:32:09 +0200 Subject: [PATCH 04/13] gnullvm: document the need for static libunwind --- src/doc/rustc/src/platform-support/windows-gnullvm.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustc/src/platform-support/windows-gnullvm.md b/src/doc/rustc/src/platform-support/windows-gnullvm.md index fccde2da99f55..80794294a994b 100644 --- a/src/doc/rustc/src/platform-support/windows-gnullvm.md +++ b/src/doc/rustc/src/platform-support/windows-gnullvm.md @@ -19,7 +19,7 @@ Target triples available so far: ## Requirements Building those targets requires an LLVM-based C toolchain, for example, [llvm-mingw][1] or [MSYS2][2] with CLANG* -environment. +environment, with static libunwind library available. Binaries for this target should be at least on par with `*-windows-gnu` in terms of requirements and functionality, except for implicit self-contained mode (explained in [the section below](#building-rust-programs)). From c321d90e6fcaf329a2ca52e524d61ff4b9d9edb7 Mon Sep 17 00:00:00 2001 From: sgasho Date: Fri, 4 Sep 2026 16:49:05 +0000 Subject: [PATCH 05/13] offload: automate manual clang-linker-wrapper step --- compiler/rustc_codegen_llvm/src/back/write.rs | 23 ++++-- .../src/builder/gpu_offload.rs | 74 ------------------- compiler/rustc_codegen_llvm/src/context.rs | 5 -- .../rustc_codegen_llvm/src/diagnostics.rs | 4 + compiler/rustc_codegen_llvm/src/intrinsic.rs | 5 +- .../src/llvm/offload_ffi.rs | 13 ++++ compiler/rustc_codegen_ssa/src/back/link.rs | 6 ++ .../llvm-wrapper/offload/OffloadWrapper.cpp | 56 ++++++++++++++ 8 files changed, 98 insertions(+), 88 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs index b8952ffc6bf81..90b2cab5b63e2 100644 --- a/compiler/rustc_codegen_llvm/src/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -612,6 +612,8 @@ pub(crate) unsafe fn llvm_optimize( let pgo_use_path = get_pgo_use_path(config); let pgo_sample_use_path = get_pgo_sample_use_path(config); let is_lto = opt_stage == llvm::OptStage::ThinLTO || opt_stage == llvm::OptStage::FatLTO; + let is_final_stage = + !matches!(opt_stage, llvm::OptStage::PreLinkFatLTO | llvm::OptStage::PreLinkThinLTO); let instr_profile_output_path = get_instr_profile_output_path(config); let sanitize_dataflow_abilist: Vec<_> = config .sanitizer_dataflow_abilist @@ -840,7 +842,7 @@ pub(crate) unsafe fn llvm_optimize( // don't need any other artifacts from the previous run. We will embed this artifact into our // LLVM-IR host module, to create a `host.o` ObjectFile, which we will write to disk. // The last, not yet automated steps uses the `clang-linker-wrapper` to process `host.o`. - if !cgcx.target_is_like_gpu { + if !cgcx.target_is_like_gpu && is_final_stage { if let Some(device_path) = config .offload .iter() @@ -866,10 +868,11 @@ pub(crate) unsafe fn llvm_optimize( // 2) Finalize host: lib.bc + device.bin -> host.o (host TM) // We create a full clone of our LLVM host module, since we will embed the device IR // into it, and this might break caching or incremental compilation otherwise. - let llmod2 = llvm::LLVMCloneModule(module.module_llvm.llmod()); let ok = unsafe { - llvm::RustOffloadWrapper::get_instance() - .llvm_rust_offload_embed_buffer_in_module(llmod2, device_bin_c.as_c_str()) + llvm::RustOffloadWrapper::get_instance().llvm_rust_offload_embed_buffer_in_module( + module.module_llvm.llmod(), + device_bin_c.as_c_str(), + ) }; if !ok { dcx.emit_err(crate::diagnostics::OffloadEmbedFailed); @@ -878,7 +881,7 @@ pub(crate) unsafe fn llvm_optimize( dcx, module.module_llvm.tm.raw(), config.no_builtins, - llmod2, + module.module_llvm.llmod(), &out_obj, None, llvm::FileType::ObjectFile, @@ -888,6 +891,16 @@ pub(crate) unsafe fn llvm_optimize( // We ignore cgcx.save_temps here and unconditionally always keep our `device.bin` artifact. // Otherwise, recompiling the host code would fail since we deleted that device artifact // in the previous host compilation, which would be confusing at best. + + let ok = unsafe { + llvm::RustOffloadWrapper::get_instance().llvm_rust_offload_wrap_images( + module.module_llvm.llmod(), + device_bin_c.as_c_str(), + ) + }; + if !ok { + dcx.emit_err(crate::diagnostics::OffloadWrapImagesFailed); + } } } result.into_result().unwrap_or_else(|()| llvm_err(dcx, LlvmError::RunLlvmPasses)) diff --git a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs index d20a73e8e6825..e2ec20226e3ce 100644 --- a/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs +++ b/compiler/rustc_codegen_llvm/src/builder/gpu_offload.rs @@ -57,80 +57,6 @@ impl<'ll> OffloadGlobals<'ll> { } } -// We need to register offload before using it. We also should unregister it once we are done, for -// good measures. Previously we have done so before and after each individual offload intrinsic -// call, but that comes at a performance cost. The repeated (un)register calls might also confuse -// the LLVM ompOpt pass, which tries to move operations to a better location. The easiest solution, -// which we copy from clang, is to just have those two calls once, in the global ctor/dtor section -// of the final binary. -pub(crate) fn register_offload<'ll>(cx: &CodegenCx<'ll, '_>) { - // First we check quickly whether we already have done our setup, in which case we return early. - // Shouldn't be needed for correctness. - let register_lib_name = "__tgt_register_lib"; - if cx.get_function(register_lib_name).is_some() { - return; - } - - let reg_lib_decl = cx.type_func(&[cx.type_ptr()], cx.type_void()); - let register_lib = declare_offload_fn(&cx, register_lib_name, reg_lib_decl); - let unregister_lib = declare_offload_fn(&cx, "__tgt_unregister_lib", reg_lib_decl); - - let ptr_null = cx.const_null(cx.type_ptr()); - let const_struct = cx.const_struct(&[cx.get_const_i32(0), ptr_null, ptr_null, ptr_null], false); - let omp_descriptor = - add_global(cx, ".omp_offloading.descriptor", const_struct, InternalLinkage); - // @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 1, ptr @.omp_offloading.device_images, ptr @__start_llvm_offload_entries, ptr @__stop_llvm_offload_entries } - // @.omp_offloading.descriptor = internal constant %__tgt_bin_desc { i32 0, ptr null, ptr null, ptr null } - - let atexit = cx.type_func(&[cx.type_ptr()], cx.type_i32()); - let atexit_fn = declare_offload_fn(cx, "atexit", atexit); - - // FIXME(offload): Drop this, once we fully automated our offload compilation pipeline, since - // LLVM will initialize them for us if it sees gpu kernels being registered. - let init_ty = cx.type_func(&[], cx.type_void()); - let init_rtls = declare_offload_fn(cx, "__tgt_init_all_rtls", init_ty); - - let desc_ty = cx.type_func(&[], cx.type_void()); - let reg_name = ".omp_offloading.descriptor_reg"; - let unreg_name = ".omp_offloading.descriptor_unreg"; - let desc_reg_fn = declare_offload_fn(cx, reg_name, desc_ty); - let desc_unreg_fn = declare_offload_fn(cx, unreg_name, desc_ty); - llvm::set_linkage(desc_reg_fn, InternalLinkage); - llvm::set_linkage(desc_unreg_fn, InternalLinkage); - llvm::set_section(desc_reg_fn, c".text.startup"); - llvm::set_section(desc_unreg_fn, c".text.startup"); - - // define internal void @.omp_offloading.descriptor_reg() section ".text.startup" { - // entry: - // call void @__tgt_register_lib(ptr @.omp_offloading.descriptor) - // call void @__tgt_init_all_rtls() - // %0 = call i32 @atexit(ptr @.omp_offloading.descriptor_unreg) - // ret void - // } - let bb = Builder::append_block(cx, desc_reg_fn, "entry"); - let mut a = Builder::build(cx, bb); - a.call(reg_lib_decl, None, None, register_lib, &[omp_descriptor], None, None); - a.call(init_ty, None, None, init_rtls, &[], None, None); - a.call(atexit, None, None, atexit_fn, &[desc_unreg_fn], None, None); - a.ret_void(); - - // define internal void @.omp_offloading.descriptor_unreg() section ".text.startup" { - // entry: - // call void @__tgt_unregister_lib(ptr @.omp_offloading.descriptor) - // ret void - // } - let bb = Builder::append_block(cx, desc_unreg_fn, "entry"); - let mut a = Builder::build(cx, bb); - a.call(reg_lib_decl, None, None, unregister_lib, &[omp_descriptor], None, None); - a.ret_void(); - - // @llvm.global_ctors = appending global [1 x { i32, ptr, ptr }] [{ i32, ptr, ptr } { i32 101, ptr @.omp_offloading.descriptor_reg, ptr null }] - let args = vec![cx.get_const_i32(101), desc_reg_fn, ptr_null]; - let const_struct = cx.const_struct(&args, false); - let arr = cx.const_array(cx.val_ty(const_struct), &[const_struct]); - add_global(cx, "llvm.global_ctors", arr, AppendingLinkage); -} - pub(crate) struct OffloadKernelDims<'ll> { num_workgroups: &'ll Value, threads_per_block: &'ll Value, diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs index 853c4bfc9ca3f..ecad6e5629172 100644 --- a/compiler/rustc_codegen_llvm/src/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -883,11 +883,6 @@ impl<'ll, CX: Borrow>> GenericCx<'ll, CX> { self.get_const_int(self.type_i8(), n) } - pub(crate) fn get_function(&self, name: &str) -> Option<&'ll Value> { - let name = SmallCStr::new(name); - unsafe { llvm::LLVMGetNamedFunction((**self).borrow().llmod, name.as_ptr()) } - } - pub(crate) fn get_md_kind_id(&self, name: &str) -> llvm::MetadataKindId { unsafe { llvm::LLVMGetMDKindIDInContext( diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index fb43b36fe39b9..3f6ce440ef3f7 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -107,6 +107,10 @@ pub(crate) struct OffloadBundleImagesFailed; #[diag("call to EmbedBufferInModule failed, `host.o` was not created")] pub(crate) struct OffloadEmbedFailed; +#[derive(Diagnostic)] +#[diag("call to WrapImages failed, `wrapper.o` was not created")] +pub(crate) struct OffloadWrapImagesFailed; + #[derive(Diagnostic)] #[diag("failed to get bitcode from object file for LTO ({$err})")] pub(crate) struct LtoBitcodeFromRlib { diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs index 58957b46964c7..1f36a9543df72 100644 --- a/compiler/rustc_codegen_llvm/src/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -36,9 +36,7 @@ use tracing::debug; use crate::abi::FnAbiLlvmExt; use crate::builder::Builder; use crate::builder::autodiff::{adjust_activity_to_abi, generate_enzyme_call}; -use crate::builder::gpu_offload::{ - self, OffloadKernelDims, declare_omp_get_num_devices, register_offload, -}; +use crate::builder::gpu_offload::{self, OffloadKernelDims, declare_omp_get_num_devices}; use crate::context::CodegenCx; use crate::declare::declare_raw_fn; use crate::diagnostics::{ @@ -1880,7 +1878,6 @@ fn codegen_offload<'ll, 'tcx>( return; } }; - register_offload(cx); let offload_data = gpu_offload::gen_define_handling(&cx, &metadata, target_symbol, offload_globals); gpu_offload::gen_call_handling( diff --git a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs index 46d9320248a9b..6e7f164d2bd4a 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs @@ -6,6 +6,7 @@ use super::ffi::{Module, TargetMachine, Value}; type LLVMRustBundleImagesFn = unsafe extern "C" fn(&Module, &TargetMachine, *const c_char) -> bool; type LLVMRustOffloadEmbedBufferInModuleFn = unsafe extern "C" fn(&Module, *const c_char) -> bool; type LLVMRustOffloadMapperFn = unsafe extern "C" fn(&Value, &Value, *const &Value); +type LLVMRustOffloadWrapImagesFn = unsafe extern "C" fn(&Module, *const c_char) -> bool; use rustc_session::config::host_tuple; use rustc_session::filesearch; @@ -16,6 +17,7 @@ pub(crate) struct RustOffloadWrapper { LLVMRustBundleImages: LLVMRustBundleImagesFn, LLVMRustOffloadEmbedBufferInModule: LLVMRustOffloadEmbedBufferInModuleFn, LLVMRustOffloadMapper: LLVMRustOffloadMapperFn, + LLVMRustOffloadWrapImages: LLVMRustOffloadWrapImagesFn, // Keep the dynamic library loaded while the function pointers are used. _lib: libloading::Library, } @@ -71,6 +73,14 @@ impl RustOffloadWrapper { unsafe { (self.LLVMRustOffloadMapper)(v1, v2, vs.as_ptr()) } } + pub(crate) unsafe fn llvm_rust_offload_wrap_images( + &self, + host_m: &Module, + device_bin_path: &CStr, + ) -> bool { + unsafe { (self.LLVMRustOffloadWrapImages)(host_m, device_bin_path.as_ptr()) } + } + fn call_dynamic( sysroot: &rustc_session::config::Sysroot, ) -> Result { @@ -86,11 +96,14 @@ impl RustOffloadWrapper { }; let llvm_rust_offload_wrapper = *unsafe { lib.get::(b"LLVMRustOffloadMapper\0")? }; + let llvm_rust_offload_wrap_images = + *unsafe { lib.get::(b"LLVMRustOffloadWrapImages\0")? }; Ok(Self { LLVMRustBundleImages: llvm_rust_bundle_images, LLVMRustOffloadEmbedBufferInModule: llvm_rust_offload_embed_buffer_in_module, LLVMRustOffloadMapper: llvm_rust_offload_wrapper, + LLVMRustOffloadWrapImages: llvm_rust_offload_wrap_images, _lib: lib, }) } diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index 25003e071beb7..e7eac04649334 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3029,6 +3029,12 @@ fn linker_with_args( link_output_kind, ); + if sess.opts.unstable_opts.offload.iter().any(|o| matches!(o, config::Offload::Host(_))) { + cmd.link_dylib_by_name("omptarget", false, true); + cmd.link_dylib_by_name("omp", false, true); + cmd.link_args(["-z", "nostart-stop-gc"]); + } + // Upstream rust crates and their non-dynamic native libraries. add_upstream_rust_crates( cmd, diff --git a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp index 8c18f2453e9d8..8bd555807f2a8 100644 --- a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp @@ -3,6 +3,8 @@ #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitcodeWriter.h" +#include "llvm/Frontend/Offloading/OffloadWrapper.h" +#include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Object/OffloadBinary.h" #include "llvm/Support/CBindingWrapping.h" @@ -115,3 +117,57 @@ extern "C" void LLVMRustOffloadMapper(LLVMValueRef OldFn, LLVMValueRef NewFn, IRBuilder<> B(&entry); B.CreateBr(&clonedEntry); } + +static Error extractImages(StringRef DeviceBinPath, + SmallVectorImpl &Binaries) { + ErrorOr> BufOrErr = + MemoryBuffer::getFile(DeviceBinPath); + if (std::error_code EC = BufOrErr.getError()) + return createFileError(DeviceBinPath, EC); + std::unique_ptr Buf = std::move(*BufOrErr); + + if (!isAddrAligned(Align(OffloadBinary::getAlignment()), + Buf->getBufferStart())) + Buf = MemoryBuffer::getMemBufferCopy(Buf->getBuffer(), + Buf->getBufferIdentifier()); + + return extractOffloadBinaries(*Buf, Binaries); +} + +static bool hasOffloadEntries(Module &M) { + for (GlobalVariable &GV : M.globals()) + if (GV.hasSection() && GV.getSection() == "llvm_offload_entries") + return true; + return false; +} + +static bool reportAndFailWrappingImages(Error E, const char *What) { + handleAllErrors(std::move(E), [&](const ErrorInfoBase &EI) { + errs() << "LLVMRustOffloadWrapImages: " << What << ": " << EI.message() + << "\n"; + }); + return false; +} + +extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, + const char *DeviceBinPath) { + Module &M = *unwrap(HostMRef); + if (!hasOffloadEntries(M)) + return true; + + SmallVector Binaries; + if (Error E = extractImages(DeviceBinPath, Binaries)) + return reportAndFailWrappingImages(std::move(E), "extract"); + + SmallVector> Images; + for (OffloadFile &F : Binaries) { + StringRef Img = F.getBinary()->getImage(); + Images.emplace_back(Img.data(), Img.size()); + } + + if (Error E = offloading::wrapOpenMPBinaries( + M, Images, offloading::getOffloadEntryArray(M), /*Suffix=*/"", + /*Relocatable=*/false)) + return reportAndFailWrappingImages(std::move(E), "wrap"); + return true; +} From 18ada5c34dc7495b1d80ec5b94fe63f3512472a3 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 6 Sep 2026 13:31:35 +0000 Subject: [PATCH 06/13] compile bitcode in device.bin beforehand in order to avoid LLVM JIT, which causes Unable to find target error --- .../src/llvm/offload_ffi.rs | 79 +++++++------ .../llvm-wrapper/offload/OffloadWrapper.cpp | 105 ++++++++++++++++-- src/bootstrap/src/core/build_steps/compile.rs | 13 ++- src/bootstrap/src/core/build_steps/dist.rs | 17 ++- src/bootstrap/src/core/build_steps/llvm.rs | 57 ++++++++++ 5 files changed, 226 insertions(+), 45 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs index 6e7f164d2bd4a..c4b6ed6611add 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs @@ -1,4 +1,5 @@ use std::ffi::{CStr, c_char}; +use std::path::PathBuf; use std::sync::OnceLock; use super::ffi::{Module, TargetMachine, Value}; @@ -6,8 +7,10 @@ use super::ffi::{Module, TargetMachine, Value}; type LLVMRustBundleImagesFn = unsafe extern "C" fn(&Module, &TargetMachine, *const c_char) -> bool; type LLVMRustOffloadEmbedBufferInModuleFn = unsafe extern "C" fn(&Module, *const c_char) -> bool; type LLVMRustOffloadMapperFn = unsafe extern "C" fn(&Value, &Value, *const &Value); -type LLVMRustOffloadWrapImagesFn = unsafe extern "C" fn(&Module, *const c_char) -> bool; +type LLVMRustOffloadWrapImagesFn = + unsafe extern "C" fn(&Module, *const c_char, *const c_char) -> bool; +use rustc_fs_util::path_to_c_string; use rustc_session::config::host_tuple; use rustc_session::filesearch; @@ -18,6 +21,7 @@ pub(crate) struct RustOffloadWrapper { LLVMRustOffloadEmbedBufferInModule: LLVMRustOffloadEmbedBufferInModuleFn, LLVMRustOffloadMapper: LLVMRustOffloadMapperFn, LLVMRustOffloadWrapImages: LLVMRustOffloadWrapImagesFn, + clang_path: PathBuf, // Keep the dynamic library loaded while the function pointers are used. _lib: libloading::Library, } @@ -78,13 +82,19 @@ impl RustOffloadWrapper { host_m: &Module, device_bin_path: &CStr, ) -> bool { - unsafe { (self.LLVMRustOffloadWrapImages)(host_m, device_bin_path.as_ptr()) } + unsafe { + (self.LLVMRustOffloadWrapImages)( + host_m, + path_to_c_string(&self.clang_path).as_ptr(), + device_bin_path.as_ptr(), + ) + } } fn call_dynamic( sysroot: &rustc_session::config::Sysroot, ) -> Result { - let rust_offload_path = Self::get_rust_offload_path(sysroot)?; + let (rust_offload_path, clang_path) = Self::get_offload_and_clang_paths(sysroot)?; let lib = unsafe { libloading::Library::new(rust_offload_path)? }; let llvm_rust_bundle_images = @@ -104,43 +114,42 @@ impl RustOffloadWrapper { LLVMRustOffloadEmbedBufferInModule: llvm_rust_offload_embed_buffer_in_module, LLVMRustOffloadMapper: llvm_rust_offload_wrapper, LLVMRustOffloadWrapImages: llvm_rust_offload_wrap_images, + clang_path, _lib: lib, }) } - fn get_rust_offload_path( + fn get_offload_and_clang_paths( sysroot: &rustc_session::config::Sysroot, - ) -> Result { + ) -> Result<(PathBuf, PathBuf), RustOffloadLibraryError> { let llvm_version_major = unsafe { LLVMRustVersionMajor() }; - - let path_buf = sysroot - .all_paths() - .find_map(|p| { - let candidate = filesearch::make_target_lib_path(p, host_tuple()) - .join(format!("libRustOffload-{}", llvm_version_major)) - .with_extension(std::env::consts::DLL_EXTENSION); - - candidate.exists().then_some(candidate) - }) - .ok_or_else(|| { - let candidates = sysroot - .all_paths() - .map(|p| p.join("lib").display().to_string()) - .collect::>() - .join("\n* "); - RustOffloadLibraryError::NotFound { - err: format!( - "failed to find a `libRustOffload-{llvm_version_major}` \ - in the sysroot candidates:\n* {candidates}" - ), - } - })?; - - Ok(path_buf - .to_str() - .ok_or_else(|| RustOffloadLibraryError::LoadFailed { - err: format!("invalid UTF-8 in path: {}", path_buf.display()), - })? - .to_string()) + let clang_name = format!("clang{}", std::env::consts::EXE_SUFFIX); + let mut searched = Vec::new(); + + for root in sysroot.all_paths() { + let rust_offload_path = filesearch::make_target_lib_path(root, host_tuple()) + .join(format!("libRustOffload-{llvm_version_major}")) + .with_extension(std::env::consts::DLL_EXTENSION); + + let clang_path = filesearch::make_target_bin_path(root, host_tuple()).join(&clang_name); + + if rust_offload_path.is_file() && clang_path.is_file() { + return Ok((rust_offload_path, clang_path)); + } + + searched.extend([rust_offload_path, clang_path]); + } + + Err(RustOffloadLibraryError::NotFound { + err: format!( + "could not find both libRustOffload-{llvm_version_major} and Clang \ + in the same sysroot. Searched:\n{}", + searched + .iter() + .map(|path| path.parent().unwrap().display().to_string()) + .collect::>() + .join("\n"), + ), + }) } } diff --git a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp index 8bd555807f2a8..9360850a91f32 100644 --- a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp @@ -1,20 +1,32 @@ #include "../SuppressLLVMWarnings.h" +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/MapVector.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/ScopeExit.h" +#include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/IRBuilder.h" #include "llvm/Object/OffloadBinary.h" -#include "llvm/Support/CBindingWrapping.h" +#include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" +#include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" +#include "llvm/Support/Path.h" +#include "llvm/Support/Program.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include "llvm/Transforms/Utils/ValueMapper.h" +#include +#include +#include + using namespace llvm; using namespace llvm::object; @@ -149,7 +161,73 @@ static bool reportAndFailWrappingImages(Error E, const char *What) { return false; } +static Expected> +compileAndLinkDeviceImages(const OffloadBinary &Input, const char *ClangPath) { + const Triple DeviceTriple(Input.getTriple()); + const StringRef Arch = Input.getArch(); + + SmallString<128> TempDir; + if (std::error_code E = + sys::fs::createUniqueDirectory("rust-offload", TempDir)) + return errorCodeToError(E); + + auto Cleanup = scope_exit([&] { + if (std::error_code E = sys::fs::remove_directories(TempDir)) + (void)reportAndFailWrappingImages( + errorCodeToError(E), "compileAndLinkDeviceImages: tempdir cleanup"); + }); + + SmallString<128> OutputPath(TempDir); + sys::path::append(OutputPath, "device.img"); + + SmallVector ArgStorage{ + ClangPath, + "--no-default-config", + "--target=" + DeviceTriple.str(), + "-o", + OutputPath.str().str(), + "-dumpdir", + OutputPath.str().str() + ".", + }; + + if (!Arch.empty() && Arch != "generic") + ArgStorage.push_back( + ((DeviceTriple.isAMDGPU() ? "-mcpu=" : "-march=") + Arch).str()); + + if (DeviceTriple.isAMDGPU()) + ArgStorage.push_back("-Wl,--no-undefined"); + + SmallString<128> InputPath(TempDir); + sys::path::append(InputPath, "input.o"); + + if (Error E = writeFile(InputPath, Input.getImage())) + return std::move(E); + + ArgStorage.push_back(InputPath.str().str()); + + SmallVector CmdArgs; + for (const StringRef Arg : ArgStorage) + CmdArgs.push_back(Arg); + + std::string ExecError; + int Status = sys::ExecuteAndWait(ClangPath, CmdArgs, std::nullopt, {}, 0, 0, + &ExecError); + + if (Status != 0) + return createStringError("compileAndLinkDeviceImages: device compiler " + "failed for %s/%s (status %d): %s", + DeviceTriple.str().c_str(), Arch.str().c_str(), + Status, ExecError.c_str()); + + auto ImageOrErr = MemoryBuffer::getFileAsStream(OutputPath); + if (!ImageOrErr) + return createFileError(OutputPath, ImageOrErr.getError()); + + return std::move(*ImageOrErr); +} + extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, + const char *ClangPath, const char *DeviceBinPath) { Module &M = *unwrap(HostMRef); if (!hasOffloadEntries(M)) @@ -159,15 +237,26 @@ extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, if (Error E = extractImages(DeviceBinPath, Binaries)) return reportAndFailWrappingImages(std::move(E), "extract"); - SmallVector> Images; - for (OffloadFile &F : Binaries) { - StringRef Img = F.getBinary()->getImage(); - Images.emplace_back(Img.data(), Img.size()); - } + // LLVMRustBundleImages writes exactly one device image + if (Binaries.size() != 1) + return reportAndFailWrappingImages( + createStringError("expected exactly one device image, found %zu", + Binaries.size()), + "extract"); + + const OffloadBinary &Input = *Binaries.front().getBinary(); + + auto ImageOrErr = compileAndLinkDeviceImages(Input, ClangPath); + if (!ImageOrErr) + return reportAndFailWrappingImages(ImageOrErr.takeError(), "device link"); + + StringRef ImageBuf = (*ImageOrErr)->getBuffer(); + ArrayRef Image(ImageBuf.data(), ImageBuf.size()); if (Error E = offloading::wrapOpenMPBinaries( - M, Images, offloading::getOffloadEntryArray(M), /*Suffix=*/"", - /*Relocatable=*/false)) + M, {Image}, offloading::getOffloadEntryArray(M), /*Suffix=*/"", + /*Relocatable=*/ + false)) return reportAndFailWrappingImages(std::move(E), "wrap"); return true; } diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index fb83e4ae5754c..b224f4b4dafed 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -21,7 +21,9 @@ use tracing::span; use crate::core::backend::CodegenBackendKind; use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair}; -use crate::core::build_steps::llvm::{LlvmFromCi, LlvmKind, prebuilt_llvm_output}; +use crate::core::build_steps::llvm::{ + LlvmFromCi, LlvmKind, offload_clang_lib_paths, offload_tool_paths, prebuilt_llvm_output, +}; use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder::{ @@ -2321,6 +2323,15 @@ impl CommandLineStep for Assemble { let dst_lib = target_libdir.join(libname); builder.resolve_symlink_and_copy(&p, &dst_lib); } + + for (source, filename) in offload_tool_paths(builder, target_compiler.host) { + builder.resolve_symlink_and_copy(&source, &libdir_bin.join(filename)); + } + + for source in offload_clang_lib_paths(builder, target_compiler.host) { + let filename = source.file_name().unwrap(); + builder.resolve_symlink_and_copy(&source, &target_libdir.join(filename)); + } } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index a335172631307..3825b2e90d97d 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -27,6 +27,7 @@ use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::GccTargetPair; use crate::core::build_steps::llvm::{ LLVM_CI_LINK_TYPE_PATH, LlvmBuildStatus, LlvmKind, get_llvm_build_status, + offload_clang_lib_paths, offload_tool_paths, }; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler, @@ -2900,7 +2901,21 @@ impl CommandLineStep for Offload { tarball.add_file(path, destdir, FileType::NativeLibrary); } - tarball.add_file(rust_offload.rust_offload_path(), target_libdir, FileType::NativeLibrary); + tarball.add_file(rust_offload.rust_offload_path(), &target_libdir, FileType::NativeLibrary); + + let target_bindir = PathBuf::from(format!("lib/rustlib/{}/bin", target.triple)); + for (source, filename) in offload_tool_paths(builder, target) { + let source = t!(fs::canonicalize(source)); + tarball.add_renamed_file(source, &target_bindir, &filename, FileType::Executable); + } + + for source in offload_clang_lib_paths(builder, target) { + let filename = source.file_name().unwrap().to_str().unwrap(); + let resolved = t!(fs::canonicalize(&source)); + tarball.add_renamed_file(resolved, &target_libdir, filename, FileType::NativeLibrary); + } + + maybe_install_llvm_target(builder, target, tarball.image_dir()); Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index f1864c736ed03..d39be4b19e7ff 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1211,6 +1211,63 @@ impl CommandLineStep for RustOffload { } } +/// Returns the binary and library directories of the selected clang. +fn offload_clang_dirs(builder: &Builder<'_>, target: TargetSelection) -> (PathBuf, PathBuf) { + if builder.config.llvm_clang { + let llvm = builder.ensure(llvm::Llvm { target }); + return (llvm.root_dir().join("bin"), llvm.root_dir().join("lib")); + } + + let lib_dir = builder + .config + .offload_clang_dir + .as_deref() + .and_then(|dir| dir.ancestors().nth(2)) + .expect("llvm.offload-clang-dir must point to //cmake/clang"); + + let root = lib_dir.parent().expect("Clang library directory must have a parent"); + + (root.join("bin"), lib_dir.into()) +} + +/// Returns (source path, destination filename) pairs for offloading tools such as clang. +pub(crate) fn offload_tool_paths( + builder: &Builder<'_>, + target: TargetSelection, +) -> Vec<(PathBuf, String)> { + let lld = builder.ensure(llvm::Lld { target }); + let (clang_bin_dir, _) = offload_clang_dirs(builder, target); + + let mut tools = Vec::new(); + + for name in ["clang", "clang-nvlink-wrapper"] { + let filename = exe(name, target); + let source = clang_bin_dir.join(&filename); + tools.push((source, filename)); + } + + tools.push((lld.join("bin").join(exe("lld", target)), exe("ld.lld", target))); + + tools +} + +pub(crate) fn offload_clang_lib_paths( + builder: &Builder<'_>, + target: TargetSelection, +) -> Vec { + let (_, lib_dir) = offload_clang_dirs(builder, target); + + let mut paths = Vec::new(); + for entry in builder.read_dir(&lib_dir) { + let filename = entry.file_name(); + let filename = filename.to_string_lossy(); + if filename == "libclang-cpp.so" || filename.starts_with("libclang-cpp.so.") { + paths.push(entry.path()); + } + } + paths +} + #[derive(Clone)] pub struct BuiltOmpOffload { /// Path to the omp and offload dylibs. From f9017b16304e7191d3057302d91874772884fbe7 Mon Sep 17 00:00:00 2001 From: sgasho Date: Sun, 6 Sep 2026 14:35:53 +0000 Subject: [PATCH 07/13] add rpath --- compiler/rustc_codegen_ssa/src/back/link.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs index e7eac04649334..abe41f8ae8e7c 100644 --- a/compiler/rustc_codegen_ssa/src/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -3033,6 +3033,8 @@ fn linker_with_args( cmd.link_dylib_by_name("omptarget", false, true); cmd.link_dylib_by_name("omp", false, true); cmd.link_args(["-z", "nostart-stop-gc"]); + cmd.link_arg("-rpath"); + cmd.link_arg(std::path::absolute(&*sess.target_tlib_path.dir).unwrap()); } // Upstream rust crates and their non-dynamic native libraries. From ff680e2717baf80131eebf7c3691a72100263fd8 Mon Sep 17 00:00:00 2001 From: sgasho Date: Mon, 7 Sep 2026 17:47:04 +0000 Subject: [PATCH 08/13] compile device image without adding extra binaries --- .../rustc_codegen_llvm/src/diagnostics.rs | 2 +- .../src/llvm/offload_ffi.rs | 40 ++-- .../llvm-wrapper/offload/OffloadWrapper.cpp | 181 +++++++++++++----- src/bootstrap/src/core/build_steps/compile.rs | 13 +- src/bootstrap/src/core/build_steps/dist.rs | 17 +- src/bootstrap/src/core/build_steps/llvm.rs | 57 ------ 6 files changed, 155 insertions(+), 155 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/diagnostics.rs b/compiler/rustc_codegen_llvm/src/diagnostics.rs index 3f6ce440ef3f7..70a14288aec0c 100644 --- a/compiler/rustc_codegen_llvm/src/diagnostics.rs +++ b/compiler/rustc_codegen_llvm/src/diagnostics.rs @@ -108,7 +108,7 @@ pub(crate) struct OffloadBundleImagesFailed; pub(crate) struct OffloadEmbedFailed; #[derive(Diagnostic)] -#[diag("call to WrapImages failed, `wrapper.o` was not created")] +#[diag("call to WrapImages failed, device image was not wrapped into the host module")] pub(crate) struct OffloadWrapImagesFailed; #[derive(Diagnostic)] diff --git a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs index c4b6ed6611add..7ecf450ab1dba 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/offload_ffi.rs @@ -21,7 +21,7 @@ pub(crate) struct RustOffloadWrapper { LLVMRustOffloadEmbedBufferInModule: LLVMRustOffloadEmbedBufferInModuleFn, LLVMRustOffloadMapper: LLVMRustOffloadMapperFn, LLVMRustOffloadWrapImages: LLVMRustOffloadWrapImagesFn, - clang_path: PathBuf, + lld_path: Option, // Keep the dynamic library loaded while the function pointers are used. _lib: libloading::Library, } @@ -82,19 +82,16 @@ impl RustOffloadWrapper { host_m: &Module, device_bin_path: &CStr, ) -> bool { + let lld_c = self.lld_path.as_deref().map(path_to_c_string).unwrap_or_default(); unsafe { - (self.LLVMRustOffloadWrapImages)( - host_m, - path_to_c_string(&self.clang_path).as_ptr(), - device_bin_path.as_ptr(), - ) + (self.LLVMRustOffloadWrapImages)(host_m, lld_c.as_ptr(), device_bin_path.as_ptr()) } } fn call_dynamic( sysroot: &rustc_session::config::Sysroot, ) -> Result { - let (rust_offload_path, clang_path) = Self::get_offload_and_clang_paths(sysroot)?; + let (rust_offload_path, lld_path) = Self::get_offload_and_lld_paths(sysroot)?; let lib = unsafe { libloading::Library::new(rust_offload_path)? }; let llvm_rust_bundle_images = @@ -114,16 +111,15 @@ impl RustOffloadWrapper { LLVMRustOffloadEmbedBufferInModule: llvm_rust_offload_embed_buffer_in_module, LLVMRustOffloadMapper: llvm_rust_offload_wrapper, LLVMRustOffloadWrapImages: llvm_rust_offload_wrap_images, - clang_path, + lld_path, _lib: lib, }) } - fn get_offload_and_clang_paths( + fn get_offload_and_lld_paths( sysroot: &rustc_session::config::Sysroot, - ) -> Result<(PathBuf, PathBuf), RustOffloadLibraryError> { + ) -> Result<(PathBuf, Option), RustOffloadLibraryError> { let llvm_version_major = unsafe { LLVMRustVersionMajor() }; - let clang_name = format!("clang{}", std::env::consts::EXE_SUFFIX); let mut searched = Vec::new(); for root in sysroot.all_paths() { @@ -131,24 +127,22 @@ impl RustOffloadWrapper { .join(format!("libRustOffload-{llvm_version_major}")) .with_extension(std::env::consts::DLL_EXTENSION); - let clang_path = filesearch::make_target_bin_path(root, host_tuple()).join(&clang_name); - - if rust_offload_path.is_file() && clang_path.is_file() { - return Ok((rust_offload_path, clang_path)); + if !rust_offload_path.is_file() { + searched.push(rust_offload_path); + continue; } - searched.extend([rust_offload_path, clang_path]); + let lld_path = filesearch::make_target_bin_path(root, host_tuple()) + .join(format!("rust-lld{}", std::env::consts::EXE_SUFFIX)); + let lld_path = lld_path.is_file().then_some(lld_path); + + return Ok((rust_offload_path, lld_path)); } Err(RustOffloadLibraryError::NotFound { err: format!( - "could not find both libRustOffload-{llvm_version_major} and Clang \ - in the same sysroot. Searched:\n{}", - searched - .iter() - .map(|path| path.parent().unwrap().display().to_string()) - .collect::>() - .join("\n"), + "could not find libRustOffload-{llvm_version_major} in the sysroot candidates:\n* {}", + searched.iter().map(|p| p.display().to_string()).collect::>().join("\n* ") ), }) } diff --git a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp index 9360850a91f32..bed54da0a7045 100644 --- a/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/offload/OffloadWrapper.cpp @@ -6,18 +6,26 @@ #include "llvm/ADT/ScopeExit.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/Bitcode/BitcodeReader.h" #include "llvm/Bitcode/BitcodeWriter.h" #include "llvm/Frontend/Offloading/OffloadWrapper.h" #include "llvm/Frontend/Offloading/Utility.h" #include "llvm/IR/IRBuilder.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/IR/LegacyPassManager.h" +#include "llvm/IR/Module.h" +#include "llvm/MC/TargetRegistry.h" #include "llvm/Object/OffloadBinary.h" +#include "llvm/Support/CodeGen.h" #include "llvm/Support/Error.h" #include "llvm/Support/FileOutputBuffer.h" #include "llvm/Support/FileSystem.h" #include "llvm/Support/MemoryBuffer.h" -#include "llvm/Support/Path.h" +#include "llvm/Support/MemoryBufferRef.h" #include "llvm/Support/Program.h" +#include "llvm/Support/raw_ostream.h" #include "llvm/Target/TargetMachine.h" +#include "llvm/Target/TargetOptions.h" #include "llvm/TargetParser/Triple.h" #include "llvm/Transforms/Utils/Cloning.h" #include "llvm/Transforms/Utils/ModuleUtils.h" @@ -26,6 +34,7 @@ #include #include #include +#include using namespace llvm; using namespace llvm::object; @@ -162,72 +171,151 @@ static bool reportAndFailWrappingImages(Error E, const char *What) { } static Expected> -compileAndLinkDeviceImages(const OffloadBinary &Input, const char *ClangPath) { - const Triple DeviceTriple(Input.getTriple()); - const StringRef Arch = Input.getArch(); +assembleWithPtxas(StringRef Ptx, StringRef Arch) { + const ErrorOr Ptxas = sys::findProgramByName("ptxas"); + if (!Ptxas) + return createStringError(Ptxas.getError(), "ptxas not found in PATH"); + + SmallString<128> PtxFilePath; + if (std::error_code E = + sys::fs::createTemporaryFile("rust-offload", "ptx", PtxFilePath)) + return errorCodeToError(E); - SmallString<128> TempDir; + SmallString<128> CubinFilePath; if (std::error_code E = - sys::fs::createUniqueDirectory("rust-offload", TempDir)) + sys::fs::createTemporaryFile("rust-offload", "cubin", CubinFilePath)) return errorCodeToError(E); auto Cleanup = scope_exit([&] { - if (std::error_code E = sys::fs::remove_directories(TempDir)) + if (std::error_code E = sys::fs::remove(PtxFilePath)) + (void)reportAndFailWrappingImages( + errorCodeToError(E), "assembleWithPtxas: PtxFilePath cleanup"); + if (std::error_code E = sys::fs::remove(CubinFilePath)) (void)reportAndFailWrappingImages( - errorCodeToError(E), "compileAndLinkDeviceImages: tempdir cleanup"); + errorCodeToError(E), "assembleWithPtxas: CubinFilePath cleanup"); }); - SmallString<128> OutputPath(TempDir); - sys::path::append(OutputPath, "device.img"); - - SmallVector ArgStorage{ - ClangPath, - "--no-default-config", - "--target=" + DeviceTriple.str(), - "-o", - OutputPath.str().str(), - "-dumpdir", - OutputPath.str().str() + ".", + if (Error E = writeFile(PtxFilePath, Ptx)) + return std::move(E); + + const StringRef Args[] = { + *Ptxas, "-m64", "-O3", "--gpu-name", + Arch, "--output-file", CubinFilePath, PtxFilePath, }; - if (!Arch.empty() && Arch != "generic") - ArgStorage.push_back( - ((DeviceTriple.isAMDGPU() ? "-mcpu=" : "-march=") + Arch).str()); + std::string ErrorMsg; + const int Status = + sys::ExecuteAndWait(*Ptxas, Args, std::nullopt, {}, 0, 0, &ErrorMsg); - if (DeviceTriple.isAMDGPU()) - ArgStorage.push_back("-Wl,--no-undefined"); + if (Status != 0) + return createStringError("assembleWithPtxas: status %d: %s", Status, + ErrorMsg.c_str()); - SmallString<128> InputPath(TempDir); - sys::path::append(InputPath, "input.o"); + ErrorOr> CubinOrError = + MemoryBuffer::getFileAsStream(CubinFilePath); + if (!CubinOrError) + return errorCodeToError(CubinOrError.getError()); - if (Error E = writeFile(InputPath, Input.getImage())) - return std::move(E); + return std::move(*CubinOrError); +} + +static Expected> +linkWithRustLld(StringRef Obj, StringRef LldPath) { + SmallString<128> ObjFilePath; + if (std::error_code E = + sys::fs::createTemporaryFile("rust-offload", "o", ObjFilePath)) + return errorCodeToError(E); + + SmallString<128> SoFilePath; + if (std::error_code E = + sys::fs::createTemporaryFile("rust-offload", "so", SoFilePath)) + return errorCodeToError(E); + + auto Cleanup = scope_exit([&] { + if (std::error_code E = sys::fs::remove(ObjFilePath)) + (void)reportAndFailWrappingImages(errorCodeToError(E), + "linkWithRustLld: ObjFilePath cleanup"); + if (std::error_code E = sys::fs::remove(SoFilePath)) + (void)reportAndFailWrappingImages(errorCodeToError(E), + "linkWithRustLld: SoFilePath cleanup"); + }); - ArgStorage.push_back(InputPath.str().str()); + if (Error E = writeFile(ObjFilePath, Obj)) + return std::move(E); - SmallVector CmdArgs; - for (const StringRef Arg : ArgStorage) - CmdArgs.push_back(Arg); + const StringRef Args[] = { + LldPath, "-flavor", "gnu", "-shared", + "--no-undefined", "-o", SoFilePath, ObjFilePath, + }; - std::string ExecError; - int Status = sys::ExecuteAndWait(ClangPath, CmdArgs, std::nullopt, {}, 0, 0, - &ExecError); + std::string ErrorMsg; + const int Status = + sys::ExecuteAndWait(LldPath, Args, std::nullopt, {}, 0, 0, &ErrorMsg); if (Status != 0) - return createStringError("compileAndLinkDeviceImages: device compiler " - "failed for %s/%s (status %d): %s", - DeviceTriple.str().c_str(), Arch.str().c_str(), - Status, ExecError.c_str()); + return createStringError("linkWithRustLld: status %d: %s", Status, + ErrorMsg.c_str()); - auto ImageOrErr = MemoryBuffer::getFileAsStream(OutputPath); - if (!ImageOrErr) - return createFileError(OutputPath, ImageOrErr.getError()); + ErrorOr> ElfOrError = + MemoryBuffer::getFileAsStream(SoFilePath); + if (!ElfOrError) + return errorCodeToError(ElfOrError.getError()); + + return std::move(*ElfOrError); +} + +static Expected> +compileDeviceImage(const OffloadBinary &Input, const char *LldPath) { + const Triple DeviceTriple(Input.getTriple()); + const StringRef Arch = Input.getArch(); + + LLVMContext Ctx; + Expected> ImageObjOrError = + parseBitcodeFile(MemoryBufferRef(Input.getImage(), "device.bc"), Ctx); + if (!ImageObjOrError) + return ImageObjOrError.takeError(); + + std::string ErrorMsg; + const Target *DeviceTarget = + TargetRegistry::lookupTarget(DeviceTriple, ErrorMsg); + if (!DeviceTarget) + return createStringError(ErrorMsg); + + std::unique_ptr TM(DeviceTarget->createTargetMachine( + DeviceTriple, Arch, /*Features=*/"", TargetOptions(), Reloc::PIC_)); + if (!TM) + return createStringError("createTargetMachine failed for %s", + DeviceTriple.str().c_str()); + + const bool IsNvptx = DeviceTriple.isNVPTX(); + + legacy::PassManager PM; + SmallString<0> Emitted; + raw_svector_ostream OS(Emitted); + const CodeGenFileType FileType = + IsNvptx ? CodeGenFileType::AssemblyFile : CodeGenFileType::ObjectFile; + if (TM->addPassesToEmitFile(PM, OS, nullptr, FileType)) + return createStringError("target %s cannot emit %s", + DeviceTriple.str().c_str(), + IsNvptx ? "assembly" : "object"); + + PM.run(**ImageObjOrError); + + if (IsNvptx) + return assembleWithPtxas(Emitted, Arch); + if (DeviceTriple.isAMDGPU()) { + if (!LldPath || !*LldPath) + return createStringError("rust-lld path was not provided for %s", + DeviceTriple.str().c_str()); + return linkWithRustLld(Emitted, LldPath); + } - return std::move(*ImageOrErr); + return createStringError("unsupported offload target %s", + DeviceTriple.str().c_str()); } extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, - const char *ClangPath, + const char *LldPath, const char *DeviceBinPath) { Module &M = *unwrap(HostMRef); if (!hasOffloadEntries(M)) @@ -246,9 +334,10 @@ extern "C" bool LLVMRustOffloadWrapImages(LLVMModuleRef HostMRef, const OffloadBinary &Input = *Binaries.front().getBinary(); - auto ImageOrErr = compileAndLinkDeviceImages(Input, ClangPath); + auto ImageOrErr = compileDeviceImage(Input, LldPath); if (!ImageOrErr) - return reportAndFailWrappingImages(ImageOrErr.takeError(), "device link"); + return reportAndFailWrappingImages(ImageOrErr.takeError(), + "device compile"); StringRef ImageBuf = (*ImageOrErr)->getBuffer(); ArrayRef Image(ImageBuf.data(), ImageBuf.size()); diff --git a/src/bootstrap/src/core/build_steps/compile.rs b/src/bootstrap/src/core/build_steps/compile.rs index b224f4b4dafed..fb83e4ae5754c 100644 --- a/src/bootstrap/src/core/build_steps/compile.rs +++ b/src/bootstrap/src/core/build_steps/compile.rs @@ -21,9 +21,7 @@ use tracing::span; use crate::core::backend::CodegenBackendKind; use crate::core::build_steps::gcc::{Gcc, GccOutput, GccTargetPair}; -use crate::core::build_steps::llvm::{ - LlvmFromCi, LlvmKind, offload_clang_lib_paths, offload_tool_paths, prebuilt_llvm_output, -}; +use crate::core::build_steps::llvm::{LlvmFromCi, LlvmKind, prebuilt_llvm_output}; use crate::core::build_steps::tool::{RustcPrivateCompilers, SourceType, copy_lld_artifacts}; use crate::core::build_steps::{dist, llvm}; use crate::core::builder::{ @@ -2323,15 +2321,6 @@ impl CommandLineStep for Assemble { let dst_lib = target_libdir.join(libname); builder.resolve_symlink_and_copy(&p, &dst_lib); } - - for (source, filename) in offload_tool_paths(builder, target_compiler.host) { - builder.resolve_symlink_and_copy(&source, &libdir_bin.join(filename)); - } - - for source in offload_clang_lib_paths(builder, target_compiler.host) { - let filename = source.file_name().unwrap(); - builder.resolve_symlink_and_copy(&source, &target_libdir.join(filename)); - } } } diff --git a/src/bootstrap/src/core/build_steps/dist.rs b/src/bootstrap/src/core/build_steps/dist.rs index 3825b2e90d97d..a335172631307 100644 --- a/src/bootstrap/src/core/build_steps/dist.rs +++ b/src/bootstrap/src/core/build_steps/dist.rs @@ -27,7 +27,6 @@ use crate::core::build_steps::doc::DocumentationFormat; use crate::core::build_steps::gcc::GccTargetPair; use crate::core::build_steps::llvm::{ LLVM_CI_LINK_TYPE_PATH, LlvmBuildStatus, LlvmKind, get_llvm_build_status, - offload_clang_lib_paths, offload_tool_paths, }; use crate::core::build_steps::tool::{ self, RustcPrivateCompilers, ToolTargetBuildMode, get_tool_target_compiler, @@ -2901,21 +2900,7 @@ impl CommandLineStep for Offload { tarball.add_file(path, destdir, FileType::NativeLibrary); } - tarball.add_file(rust_offload.rust_offload_path(), &target_libdir, FileType::NativeLibrary); - - let target_bindir = PathBuf::from(format!("lib/rustlib/{}/bin", target.triple)); - for (source, filename) in offload_tool_paths(builder, target) { - let source = t!(fs::canonicalize(source)); - tarball.add_renamed_file(source, &target_bindir, &filename, FileType::Executable); - } - - for source in offload_clang_lib_paths(builder, target) { - let filename = source.file_name().unwrap().to_str().unwrap(); - let resolved = t!(fs::canonicalize(&source)); - tarball.add_renamed_file(resolved, &target_libdir, filename, FileType::NativeLibrary); - } - - maybe_install_llvm_target(builder, target, tarball.image_dir()); + tarball.add_file(rust_offload.rust_offload_path(), target_libdir, FileType::NativeLibrary); Some(tarball.generate()) } diff --git a/src/bootstrap/src/core/build_steps/llvm.rs b/src/bootstrap/src/core/build_steps/llvm.rs index d39be4b19e7ff..f1864c736ed03 100644 --- a/src/bootstrap/src/core/build_steps/llvm.rs +++ b/src/bootstrap/src/core/build_steps/llvm.rs @@ -1211,63 +1211,6 @@ impl CommandLineStep for RustOffload { } } -/// Returns the binary and library directories of the selected clang. -fn offload_clang_dirs(builder: &Builder<'_>, target: TargetSelection) -> (PathBuf, PathBuf) { - if builder.config.llvm_clang { - let llvm = builder.ensure(llvm::Llvm { target }); - return (llvm.root_dir().join("bin"), llvm.root_dir().join("lib")); - } - - let lib_dir = builder - .config - .offload_clang_dir - .as_deref() - .and_then(|dir| dir.ancestors().nth(2)) - .expect("llvm.offload-clang-dir must point to //cmake/clang"); - - let root = lib_dir.parent().expect("Clang library directory must have a parent"); - - (root.join("bin"), lib_dir.into()) -} - -/// Returns (source path, destination filename) pairs for offloading tools such as clang. -pub(crate) fn offload_tool_paths( - builder: &Builder<'_>, - target: TargetSelection, -) -> Vec<(PathBuf, String)> { - let lld = builder.ensure(llvm::Lld { target }); - let (clang_bin_dir, _) = offload_clang_dirs(builder, target); - - let mut tools = Vec::new(); - - for name in ["clang", "clang-nvlink-wrapper"] { - let filename = exe(name, target); - let source = clang_bin_dir.join(&filename); - tools.push((source, filename)); - } - - tools.push((lld.join("bin").join(exe("lld", target)), exe("ld.lld", target))); - - tools -} - -pub(crate) fn offload_clang_lib_paths( - builder: &Builder<'_>, - target: TargetSelection, -) -> Vec { - let (_, lib_dir) = offload_clang_dirs(builder, target); - - let mut paths = Vec::new(); - for entry in builder.read_dir(&lib_dir) { - let filename = entry.file_name(); - let filename = filename.to_string_lossy(); - if filename == "libclang-cpp.so" || filename.starts_with("libclang-cpp.so.") { - paths.push(entry.path()); - } - } - paths -} - #[derive(Clone)] pub struct BuiltOmpOffload { /// Path to the omp and offload dylibs. From 2c4265a2764f262aa94a7034fee5885e1472d69d Mon Sep 17 00:00:00 2001 From: aerooneqq Date: Tue, 8 Sep 2026 09:27:16 +0300 Subject: [PATCH 09/13] Supporting delegations to inherent functions --- compiler/rustc_ast/src/ast.rs | 8 + .../src/delegation/generics.rs | 93 +++- .../rustc_ast_lowering/src/delegation/mod.rs | 37 +- .../src/delegation/resolution.rs | 274 +++++++++-- .../rustc_ast_lowering/src/diagnostics.rs | 21 + compiler/rustc_ast_lowering/src/lib.rs | 4 + compiler/rustc_hir_analysis/src/delegation.rs | 212 ++++++-- compiler/rustc_hir_typeck/src/method/probe.rs | 25 +- compiler/rustc_middle/src/middle/resolve.rs | 44 +- compiler/rustc_middle/src/queries.rs | 6 + compiler/rustc_middle/src/ty/context.rs | 4 + compiler/rustc_resolve/src/late.rs | 94 +++- compiler/rustc_resolve/src/lib.rs | 7 +- tests/ui/delegation/bad-resolve.rs | 8 +- tests/ui/delegation/bad-resolve.stderr | 75 ++- tests/ui/delegation/explicit-paths.rs | 5 +- tests/ui/delegation/explicit-paths.stderr | 69 +-- tests/ui/delegation/glob-non-fn.rs | 4 +- tests/ui/delegation/glob-non-fn.stderr | 51 +- .../delegation/impl-reuse-non-reuse-items.rs | 6 +- .../impl-reuse-non-reuse-items.stderr | 50 +- tests/ui/delegation/inherent-impls-ambig.rs | 22 +- .../ui/delegation/inherent-impls-ambig.stderr | 170 ++++--- tests/ui/delegation/inherent-impls-enums.rs | 30 +- .../ui/delegation/inherent-impls-enums.stderr | 185 ++----- .../ui/delegation/inherent-impls-glob-list.rs | 2 - .../inherent-impls-glob-list.stderr | 17 +- .../inherent-impls-mixed-generics.rs | 3 +- .../inherent-impls-mixed-generics.stderr | 24 +- .../inherent-impls-non-local-crate.rs | 14 +- .../inherent-impls-non-local-crate.stderr | 50 +- .../inherent-impls-parent-generics.rs | 61 +-- .../inherent-impls-parent-generics.stderr | 459 +++++++++++++++--- .../inherent-impls-receiver-mapping.rs | 21 +- .../inherent-impls-receiver-mapping.stderr | 280 +++-------- .../inherent-impls-recursive-cycle.rs | 20 +- .../inherent-impls-recursive-cycle.stderr | 118 +++-- .../ui/delegation/inherent-impls-recursive.rs | 9 +- .../inherent-impls-recursive.stderr | 61 --- tests/ui/delegation/inherent-impls-rename.rs | 3 +- .../delegation/inherent-impls-rename.stderr | 9 - .../delegation/inherent-impls-self-mapping.rs | 4 +- .../inherent-impls-self-mapping.stderr | 40 +- .../inherent-impls-self-replacement.rs | 23 +- .../inherent-impls-self-replacement.stderr | 201 ++++++-- tests/ui/delegation/inherent-impls-structs.rs | 30 +- .../delegation/inherent-impls-structs.stderr | 185 ++----- .../inherent-impls-wrong-header-args-ice.rs | 4 +- ...nherent-impls-wrong-header-args-ice.stderr | 26 +- ...ult-trait-shadow-cycle-issue-151358.stderr | 2 + .../query-cycle-printing-issue-151358.stderr | 2 + .../resolve/query-cycle-issue-124901.stderr | 2 + 52 files changed, 1968 insertions(+), 1206 deletions(-) delete mode 100644 tests/ui/delegation/inherent-impls-recursive.stderr delete mode 100644 tests/ui/delegation/inherent-impls-rename.stderr diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index bc8753f4dcaa7..c14ad62e9a60b 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -294,6 +294,14 @@ impl GenericArg { GenericArg::Const(ct) => ct.value.span, } } + + pub fn is_maybe_parenthesised_infer(&self) -> bool { + match self { + GenericArg::Lifetime(lt) => lt.ident.name == kw::UnderscoreLifetime, + GenericArg::Type(ty) => ty.is_maybe_parenthesised_infer(), + GenericArg::Const(_) => false, + } + } } /// A path like `Foo<'a, T>`. diff --git a/compiler/rustc_ast_lowering/src/delegation/generics.rs b/compiler/rustc_ast_lowering/src/delegation/generics.rs index 867ed364433e7..7cb904ab5c353 100644 --- a/compiler/rustc_ast_lowering/src/delegation/generics.rs +++ b/compiler/rustc_ast_lowering/src/delegation/generics.rs @@ -1,3 +1,5 @@ +use std::assert_matches; + use hir::HirId; use hir::def::{DefKind, Res}; use rustc_ast::*; @@ -11,7 +13,10 @@ use rustc_span::{ErrorGuaranteed, Ident, Span, sym}; use crate::LoweringContext; use crate::delegation::resolution::resolver::DelegationResolver; -use crate::diagnostics::DelegationInfersMismatch; +use crate::diagnostics::{ + DelegationInfersMismatch, DelegationToInherentImplMustContainParentGenerics, + DelegationToInherentImplParentContainsInfer, +}; #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub(super) enum GenericsPosition { @@ -25,6 +30,7 @@ pub(super) enum GenericArgSlot { Generate(T, Option /* Infer arg index from AST */), } +#[derive(Debug)] pub(super) struct DelegationGenerics { data: T, pos: GenericsPosition, @@ -57,11 +63,13 @@ impl<'hir> DelegationGenerics> { /// meaning we did not propagate them and thus we do not need to generate generic params /// (i.e., method call scenarios), in such a case this approach helps /// a lot as if `into_hir_generics` will not be called then uplifting will not happen. +#[derive(Debug)] pub(super) enum HirOrTyGenerics<'hir> { Ty(DelegationGenerics>), Hir(DelegationGenerics<&'hir hir::Generics<'hir>>), } +#[derive(Debug)] pub(super) struct GenericsGenerationResult<'hir> { pub(super) generics: HirOrTyGenerics<'hir>, pub(super) args_segment_id: HirId, @@ -80,6 +88,7 @@ pub(super) struct GenericsGenerationResults<'hir> { pub(super) self_ty_propagation_kind: Option, } +#[derive(Debug)] pub(super) struct DelegationGenericArgsIterator<'hir> { index: usize = Default::default(), params: &'hir [hir::GenericParam<'hir>], @@ -145,6 +154,7 @@ impl<'hir> DelegationGenericArgsIterator<'hir> { ctx: &mut LoweringContext<'_, 'hir>, ) -> Vec> { let mut args = vec![]; + while let Some(arg) = self.next(ctx, |ctx| ctx.next_id()) { args.push(arg); } @@ -238,6 +248,7 @@ impl<'hir> GenericsGenerationResult<'hir> { } } +#[derive(Debug)] enum ParentSegmentArgs<'a> { /// Parent segment is valid and generic args are specified: /// `reuse Trait::<'static, ()>::foo;`. @@ -273,7 +284,7 @@ struct GenericsResolution<'a, 'tcx> { /// `reuse <_ as Trait>::foo;`. qself_is_infer: bool, /// Whether we should generate `Self` generic param. - generate_self: bool, + generate_free_to_trait_self: bool, } impl<'hir> DelegationResolver<'_, 'hir> { @@ -288,8 +299,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { let delegation_in_free_ctx = !matches!(delegation_parent_kind, DefKind::Trait | DefKind::Impl { .. }); - let sig_parent = tcx.parent(sig_id); - let sig_in_trait = matches!(tcx.def_kind(sig_parent), DefKind::Trait); + let sig_in_trait = matches!(tcx.def_kind(tcx.parent(sig_id)), DefKind::Trait); let free_to_trait_delegation = delegation_in_free_ctx && sig_in_trait; let mut sig_parent_params: &[ty::GenericParamDef] = &[]; @@ -301,8 +311,13 @@ impl<'hir> DelegationResolver<'_, 'hir> { let parent_args = if let [.., parent_segment, _] = &delegation.path.segments[..] { let res = self.get_resolution_id(parent_segment.id)?; - if matches!(tcx.def_kind(res), DefKind::Trait | DefKind::TraitAlias) { - sig_parent_params = &tcx.generics_of(sig_parent).own_params; + if !matches!(tcx.def_kind(res), DefKind::Mod) { + assert_matches!( + tcx.def_kind(res), + DefKind::Trait | DefKind::Struct | DefKind::Enum + ); + + sig_parent_params = &tcx.generics_of(res).own_params; self.get_user_args(parent_segment) .map(|args| ParentSegmentArgs::Specified(args)) .unwrap_or(ParentSegmentArgs::NotSpecified) @@ -319,7 +334,8 @@ impl<'hir> DelegationResolver<'_, 'hir> { qself_is_none, qself_is_infer, free_to_trait_delegation, - generate_self: free_to_trait_delegation && (qself_is_none || qself_is_infer), + generate_free_to_trait_self: free_to_trait_delegation + && (qself_is_none || qself_is_infer), trait_impl: matches!(delegation_parent_kind, DefKind::Impl { of_trait: true }), sig_child_params: &tcx.generics_of(sig_id).own_params, child_args: self.get_user_args( @@ -349,10 +365,11 @@ impl<'hir> DelegationResolver<'_, 'hir> { &self, delegation: &Delegation, sig_id: DefId, + span: Span, ) -> Result, ErrorGuaranteed> { let res @ GenericsResolution { trait_impl, - generate_self, + generate_free_to_trait_self, sig_child_params, sig_parent_params, .. @@ -376,20 +393,27 @@ impl<'hir> DelegationResolver<'_, 'hir> { return Ok(GenericsGenerationResults { parent, child, self_ty_propagation_kind: None }); } + self.check_delegation_to_inherent_impl(&res.parent_args, sig_id, span)?; + let tcx = self.tcx(); + + // If parent is inherent impl then there is no `Self` param to skip, so add additional check. + let skip_self = + !generate_free_to_trait_self && tcx.def_kind(tcx.parent(sig_id)) == DefKind::Trait; + let parent_generics = match res.parent_args { ParentSegmentArgs::Specified(args) => DelegationGenerics { data: Self::create_slots_from_args( tcx, args, - &sig_parent_params[usize::from(!generate_self)..], - generate_self, + &sig_parent_params[usize::from(skip_self)..], + generate_free_to_trait_self, ), pos: GenericsPosition::Parent, trait_impl, }, ParentSegmentArgs::NotSpecified => DelegationGenerics::generate_all( - &sig_parent_params[usize::from(!generate_self)..], + &sig_parent_params[usize::from(skip_self)..], GenericsPosition::Parent, trait_impl, ), @@ -437,6 +461,46 @@ impl<'hir> DelegationResolver<'_, 'hir> { }) } + fn check_delegation_to_inherent_impl( + &self, + parent_args: &ParentSegmentArgs<'_>, + sig_id: DefId, + span: Span, + ) -> Result<(), ErrorGuaranteed> { + let tcx = self.tcx(); + + if !(tcx.def_kind(sig_id) == DefKind::AssocFn + && matches!(tcx.def_kind(tcx.parent(sig_id)), DefKind::Impl { of_trait: false })) + { + return Ok(()); + } + + let ty::Adt(def, _) = tcx.type_of(tcx.parent(sig_id)).skip_binder().kind() else { + unreachable!("parent of inherent function can be only struct or enum") + }; + + match parent_args { + ParentSegmentArgs::Invalid => unreachable!(), + ParentSegmentArgs::Specified(args) => args + .args + .iter() + .all(|arg| { + let AngleBracketedArg::Arg(arg) = arg else { return false }; + !arg.is_maybe_parenthesised_infer() + }) + .ok_or_else(|| { + self.tcx().dcx().emit_err(DelegationToInherentImplParentContainsInfer { span }) + }), + ParentSegmentArgs::NotSpecified => match tcx.generics_of(def.did()).own_params.len() { + 0 => Ok(()), + _ => Err(self + .tcx() + .dcx() + .emit_err(DelegationToInherentImplMustContainParentGenerics { span })), + }, + } + } + /// Generates generic argument slots for user-specified `args` and /// generic `params` of the signature function. This function checks whether /// there are infers (`kw::UnderscoreLifetime` or `kw::Underscore`) in @@ -459,12 +523,7 @@ impl<'hir> DelegationResolver<'_, 'hir> { let params = ¶ms[usize::from(add_first_self)..]; for (idx, (arg, param)) in args.args.iter().zip(params).enumerate() { let AngleBracketedArg::Arg(arg) = arg else { continue }; - - let is_infer = match arg { - GenericArg::Lifetime(lt) => lt.ident.name == kw::UnderscoreLifetime, - GenericArg::Type(ty) => ty.is_maybe_parenthesised_infer(), - GenericArg::Const(_) => false, - }; + let is_infer = arg.is_maybe_parenthesised_infer(); // If `'_` is used instead of `_` (or vice versa) we emit a meaningful // error instead of processing this infer or leaving it as is for signature diff --git a/compiler/rustc_ast_lowering/src/delegation/mod.rs b/compiler/rustc_ast_lowering/src/delegation/mod.rs index a92b62517e61d..0e94016963c78 100644 --- a/compiler/rustc_ast_lowering/src/delegation/mod.rs +++ b/compiler/rustc_ast_lowering/src/delegation/mod.rs @@ -47,7 +47,7 @@ use rustc_ast as ast; use rustc_ast::*; use rustc_hir::attrs::lang_items::LangItem; use rustc_hir::def::DefKind; -use rustc_hir::{self as hir, FnDeclFlags}; +use rustc_hir::{self as hir, FnDeclFlags, QPath}; use rustc_middle::ty::Asyncness; use rustc_span::def_id::DefId; use rustc_span::symbol::kw; @@ -62,7 +62,7 @@ use crate::{ mod attributes; mod generics; -mod resolution; +pub(crate) mod resolution; pub(crate) struct DelegationResults<'hir> { pub body_id: hir::BodyId, @@ -416,7 +416,37 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::QPath::Resolved(ty, self.arena.alloc(new_path)) } - hir::QPath::TypeRelative(..) => unreachable!("until inherent methods are supported"), + hir::QPath::TypeRelative(mut ty, segment) => { + let mut segment = self.process_segment(span, segment, &mut generics.child); + segment.res = Res::Def(self.tcx.def_kind(res.call_path_res), res.call_path_res); + + let ty_hir_id = ty.hir_id; + + // Propagating child generics if needed. + ty = if let hir::TyKind::Path(QPath::Resolved(ty, path)) = ty.kind { + let mut new_path = path.clone(); + + new_path.segments = self.arena.alloc_from_iter( + new_path.segments.iter().enumerate().map(|(idx, segment)| { + if idx + 1 == new_path.segments.len() { + self.process_segment(span, segment, &mut generics.parent) + } else { + segment.clone() + } + }), + ); + + self.arena.alloc(hir::Ty { + hir_id: ty_hir_id, + span, + kind: hir::TyKind::Path(QPath::Resolved(ty, self.arena.alloc(new_path))), + }) + } else { + ty + }; + + hir::QPath::TypeRelative(ty, self.arena.alloc(segment)) + } }; if let Some(hir::DelegationSelfTyPropagationKind::SelfTy(id)) = @@ -491,6 +521,7 @@ impl<'hir> LoweringContext<'_, 'hir> { result.generics.into_hir_generics(self, span); let mut segment = segment.clone(); + let mut args_iter = result.generics.create_args_iterator(); let new_args = segment diff --git a/compiler/rustc_ast_lowering/src/delegation/resolution.rs b/compiler/rustc_ast_lowering/src/delegation/resolution.rs index 85604223c8509..0e4992267b250 100644 --- a/compiler/rustc_ast_lowering/src/delegation/resolution.rs +++ b/compiler/rustc_ast_lowering/src/delegation/resolution.rs @@ -2,22 +2,143 @@ use std::ops::ControlFlow; use ast::visit::Visitor; use hir::def::DefKind; -use rustc_ast::{self as ast, Delegation, DelegationSource, NodeId}; -use rustc_data_structures::fx::{FxHashSet, FxIndexSet}; +use rustc_ast::{self as ast, AssocItemKind, Delegation, DelegationSource, Item, ItemKind, NodeId}; +use rustc_data_structures::fx::{FxHashSet, FxIndexMap, FxIndexSet}; +use rustc_data_structures::steal::Steal; use rustc_hir as hir; -use rustc_middle::ty::{Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor}; -use rustc_middle::{span_bug, ty}; +use rustc_middle::middle::resolve::{ + self as mid_res, AstOwner, DelegationInherentFnKind, TypeRelativeDelegationRes, +}; +use rustc_middle::ty::{ + self as ty, AssocKind, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor, +}; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::{ErrorGuaranteed, Span}; use crate::delegation::generics::GenericsGenerationResults; use crate::delegation::resolution::resolver::DelegationResolver; use crate::diagnostics::{ - CycleInDelegationSignatureResolution, DelegationAttemptedBlockWithDefsDeletion, - DelegationAttemptedBlockWithDefsRelowering, DelegationBlockSpecifiedWhenNoParams, - UnresolvedDelegationCallee, + AmbiguousDelegationToInherentImpl, CycleInDelegationSignatureResolution, + DelegationAttemptedBlockWithDefsDeletion, DelegationAttemptedBlockWithDefsRelowering, + DelegationBlockSpecifiedWhenNoParams, UnresolvedDelegationCallee, }; +/// Simple (hack or heuristic) resolution of some delegations to inherent impls +/// while correct resolution through `ProbeContext` is not available +/// during AST -> HIR lowering due to query cycles. +/// Successful resolutions from this heuristics are not a subset of +/// successful resolutions from the correct approach, if we want to stabilize +/// delegations to inherent impls with this approach we need a second pass in type checking +/// (i.e., when there's no cycles) that makes sure that resolutions from +/// the heuristic match the correct resolutions, or report errors otherwise. +/// FIXME(fn_delegation): correct resolution through `ProbeContext` engine +pub(crate) fn resolve_type_relative_delegations( + tcx: TyCtxt<'_>, + _: (), +) -> FxIndexMap { + let ast_index = tcx.index_ast(()); + let resolutions = tcx.resolutions(()); + + let infos = &resolutions.delegation_infos; + let inh_fns = &resolutions.delegation_inherent_fn_map; + + let mut type_relative_resolutions: FxIndexMap = + Default::default(); + + for (&def_id, res) in infos { + match res.resolution { + mid_res::DelegationResolution::Error(..) | mid_res::DelegationResolution::Full(_) => { + continue; + } + // Also record resolutions for cases when signature is resolved but call path is not. + mid_res::DelegationResolution::Partial + | mid_res::DelegationResolution::PartialCall(_) => { + let Some(r_and_owner) = ast_index.get(def_id).map(Steal::borrow) else { + unreachable!("ast index must contain delegations"); + }; + + let (r, owner) = &*r_and_owner; + + let delegation = match owner { + AstOwner::Item(Item { kind: ItemKind::Delegation(d), .. }) + | AstOwner::TraitItem(Item { kind: AssocItemKind::Delegation(d), .. }) + | AstOwner::ImplItem(Item { kind: AssocItemKind::Delegation(d), .. }) => d, + _ => unreachable!("we are processing only delegations"), + }; + + let res = r.partial_res_map.get(&delegation.id); + let res = res.and_then(|res| res.base_res().opt_def_id()); + let ident = delegation.path.segments.last().map(|s| s.ident); + + let span = delegation.last_segment_span(); + + let ambig_error_res = || { + TypeRelativeDelegationRes::Ambig( + tcx.dcx().span_delayed_bug(span, "ambiguous delegation to inherent impl"), + ) + }; + + let default_error_res = + || { + TypeRelativeDelegationRes::Error(tcx.dcx().span_delayed_bug( + span, + "failed to resolve delegation to inherent impl", + )) + }; + + let res = if let Some(res) = res + && let Some(ident) = ident + { + match res.as_local() { + Some(local_def_id) => { + let res = inh_fns.get(&local_def_id).and_then(|map| map.get(&ident)); + + match res { + Some(res) => match res { + DelegationInherentFnKind::Ambig => ambig_error_res(), + DelegationInherentFnKind::Single(res) => { + TypeRelativeDelegationRes::Ok(res.to_def_id()) + } + }, + _ => default_error_res(), + } + } + None => { + let mut sig_res = None; + 'inh_loop: for inh_impl_id in tcx.inherent_impls(res) { + let assoc_items = tcx.associated_items(*inh_impl_id); + + // FIXME(fn_delegation): use correct identifier hygiene + let mut candidates = assoc_items + .filter_by_name_unhygienic(ident.name) + .filter(|it| matches!(it.kind, AssocKind::Fn { .. })); + + while let Some(candidate) = candidates.next() { + if sig_res.is_some() { + sig_res = Some(ambig_error_res()); + break 'inh_loop; + } else { + sig_res = + Some(TypeRelativeDelegationRes::Ok(candidate.def_id)); + } + } + } + + sig_res.unwrap_or_else(default_error_res) + } + } + } else { + default_error_res() + }; + + type_relative_resolutions.insert(def_id, res); + } + } + } + + type_relative_resolutions +} + /// Summary info about function parameters. #[derive(Debug, Clone, Copy, Eq, PartialEq)] pub(super) struct ParamInfo { @@ -114,26 +235,34 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // Delegation can be missing from the `delegations_resolutions` table // in illegal places such as function bodies in extern blocks (see #151356). - let sig_id = tcx - .resolutions(()) - .delegation_infos - .get(&def_id) - .map(|info| { - info.resolution_id.and_then(|id| self.check_for_cycles(id, span).map(|_| id)) - }) - .unwrap_or_else(|| { - Err(tcx.dcx().span_delayed_bug( - span, - format!("delegation resolution record was not found for {:?}", def_id), - )) - })?; - - let is_method = match tcx.def_kind(sig_id) { - DefKind::Fn => false, - DefKind::AssocFn => tcx.associated_item(sig_id).is_method(), - _ => span_bug!(span, "unexpected DefKind for delegation item"), - }; + let sig_id = self.resolve_delegation_sig(def_id, span)?; + + let create_invalid_path_error = + || tcx.dcx().span_delayed_bug(span, "invalid delegation path"); + match &delegation.path.segments[..] { + [] => return Err(create_invalid_path_error()), + [child] => { + let res = self.get_resolution_id(child.id)?; + if tcx.def_kind(res) != DefKind::Fn { + return Err(create_invalid_path_error()); + } + } + [.., parent, _] => { + let child_res = self.get_call_path_res(delegation, span)?; + let parent_res = self.get_resolution_id(parent.id)?; + + match (tcx.def_kind(child_res), tcx.def_kind(parent_res)) { + (DefKind::Fn, DefKind::Mod) => {} + (DefKind::AssocFn, DefKind::Trait | DefKind::Struct | DefKind::Enum) => {} + _ => return Err(create_invalid_path_error()), + } + } + } + + self.check_for_cycles(sig_id, span)?; + + let is_method = tcx.is_method(sig_id); let sig = tcx.fn_sig(sig_id).skip_binder().skip_binder(); let param_count = sig.inputs().len() + usize::from(sig.c_variadic()); let parent = tcx.local_parent(def_id); @@ -149,7 +278,7 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // FIXME(splat): use `sig.splatted()` once FnSig has it param_info: ParamInfo { param_count, c_variadic: sig.c_variadic(), splatted: None }, source: delegation.source, - call_path_res: self.get_resolution_id(delegation.id)?, + call_path_res: self.get_call_path_res(delegation, span)?, sig_mapping: self.create_sig_mapping( delegation, span, @@ -160,12 +289,73 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { )?, }; - Ok((res, self.resolve_and_generate_generics(delegation, sig_id)?)) + Ok((res, self.resolve_and_generate_generics(delegation, sig_id, span)?)) + } + + fn get_call_path_res( + &self, + delegation: &Delegation, + span: Span, + ) -> Result { + let def_id = self.owner_id(); + + match self.tcx().resolutions(()).delegation_infos[&def_id].resolution { + mid_res::DelegationResolution::Full(_) => self.get_resolution_id(delegation.id), + mid_res::DelegationResolution::Partial + | mid_res::DelegationResolution::PartialCall(_) => { + self.resolve_type_relative_delegation_sig(def_id, span) + } + mid_res::DelegationResolution::Error(err) => Err(err), + } + } + + fn resolve_delegation_sig( + &self, + def_id: LocalDefId, + span: Span, + ) -> Result { + let tcx = self.tcx(); + + match tcx.resolutions(()).delegation_infos.get(&def_id) { + Some(res) => match res.resolution { + mid_res::DelegationResolution::Error(err) => Err(err), + mid_res::DelegationResolution::Full(def_id) + | mid_res::DelegationResolution::PartialCall(def_id) => Ok(def_id), + mid_res::DelegationResolution::Partial => { + self.resolve_type_relative_delegation_sig(def_id, span) + } + }, + None => Err(self.create_unresolved_error(def_id, span)), + } + } + + fn create_unresolved_error(&self, def_id: LocalDefId, span: Span) -> ErrorGuaranteed { + self.tcx().dcx().span_delayed_bug(span, format!("unresolved delegation {def_id:?}")) + } + + fn resolve_type_relative_delegation_sig( + &self, + def_id: LocalDefId, + span: Span, + ) -> Result { + let tcx = self.tcx(); + + match tcx.resolve_type_relative_delegations(()).get(&def_id) { + Some(res) => match *res { + TypeRelativeDelegationRes::Ok(sig_id) => Ok(sig_id), + TypeRelativeDelegationRes::Error(err) => Err(err), + TypeRelativeDelegationRes::Ambig(_) => { + Err(tcx.dcx().emit_err(AmbiguousDelegationToInherentImpl { span })) + } + }, + None => Err(self.create_unresolved_error(def_id, span)), + } } fn check_for_cycles(&self, mut def_id: DefId, span: Span) -> Result<(), ErrorGuaranteed> { let tcx = self.tcx(); let mut visited: FxHashSet = Default::default(); + let delegation_infos = &tcx.resolutions(()).delegation_infos; loop { visited.insert(def_id); @@ -174,8 +364,8 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // it means that we refer to another delegation as a callee, so in order to obtain // a signature DefId we obtain NodeId of the callee delegation and try to get signature from it. if let Some(local_id) = def_id.as_local() - && let Some(info) = tcx.resolutions(()).delegation_infos.get(&local_id) - && let Ok(id) = info.resolution_id + && delegation_infos.contains_key(&local_id) + && let Ok(id) = self.resolve_delegation_sig(local_id, span) { def_id = id; if visited.contains(&def_id) { @@ -253,7 +443,7 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { mapping.arguments_to_map.insert(0); } - if self.can_perform_self_mapping(delegation, parent)? { + if self.can_perform_self_mapping(delegation, parent, span) { /// Finds `Self` generic param only in ADT or references, so we avoid cases like /// `Self::Item` which will return true if `output.contains(...)` will be used. struct SelfFinder; @@ -307,10 +497,9 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // We can't yet map more than one argument if there are definitions inside. // FIXME(fn_delegation): support relowering with defs inside if contains_defs && mapping.arguments_to_map.len() > 1 { - return Err(self - .tcx() - .dcx() - .emit_err(DelegationAttemptedBlockWithDefsRelowering { span })); + let err = DelegationAttemptedBlockWithDefsRelowering { span }; + let err = self.tcx().dcx().emit_err(err); + return Err(err); } Ok(mapping) @@ -320,10 +509,11 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { &self, delegation: &Delegation, parent: LocalDefId, - ) -> Result { + span: Span, + ) -> bool { // Heuristic: don't do wrapping if there is no target expression. if delegation.body.is_none() { - return Ok(false); + return false; } let tcx = self.tcx(); @@ -339,13 +529,17 @@ impl<'tcx> DelegationResolver<'_, 'tcx> { // 2) Inherent methods when delegating to trait, as we change the type of // `Self` to type of struct or enum we delegate from. if !matches!(tcx.def_kind(parent), DefKind::Impl { .. }) { - return Ok(false); + return false; } // Check that delegation path resolves to a trait AssocFn, not to a free method. // After previous check we are sure that `sig_id` and `delegation.id` // point to the same function. - let id = self.get_resolution_id(delegation.id)?; - Ok(tcx.def_kind(id) == DefKind::AssocFn && tcx.def_kind(tcx.parent(id)) == DefKind::Trait) + let id = self + .get_call_path_res(delegation, span) + .ok() + .expect("invalid paths are filtered out earlier"); + + tcx.def_kind(id) == DefKind::AssocFn && tcx.def_kind(tcx.parent(id)) == DefKind::Trait } } diff --git a/compiler/rustc_ast_lowering/src/diagnostics.rs b/compiler/rustc_ast_lowering/src/diagnostics.rs index b0fada9d3cd9e..2542268712f98 100644 --- a/compiler/rustc_ast_lowering/src/diagnostics.rs +++ b/compiler/rustc_ast_lowering/src/diagnostics.rs @@ -609,3 +609,24 @@ pub(crate) struct RestrictionAncestorOnly { pub(crate) span: Span, pub(crate) kind: ResolvingRestrictionKind, } + +#[derive(Diagnostic)] +#[diag("ambiguous delegation to inherent impl function")] +pub(crate) struct AmbiguousDelegationToInherentImpl { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("delegation to inherent impl must contain parent generics")] +pub(crate) struct DelegationToInherentImplMustContainParentGenerics { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag("parent segment of delegation to inherent impl can not contain infers")] +pub(crate) struct DelegationToInherentImplParentContainsInfer { + #[primary_span] + pub span: Span, +} diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ef6995d9c11d6..ac79703e63c01 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -102,6 +102,8 @@ pub mod stability; pub fn provide(providers: &mut Providers) { providers.index_ast = index_ast; providers.lower_to_hir = lower_to_hir; + providers.resolve_type_relative_delegations = + delegation::resolution::resolve_type_relative_delegations; } #[cfg(debug_assertions)] @@ -739,6 +741,8 @@ fn index_ast<'tcx>( #[instrument(level = "trace", skip(tcx))] fn lower_to_hir(tcx: TyCtxt<'_>, def_id: LocalDefId) -> hir::MaybeOwner<'_> { + tcx.ensure_done().resolve_type_relative_delegations(()); + let ast_index = tcx.index_ast(()); let resolver_and_node = ast_index.get(def_id).map(Steal::steal); diff --git a/compiler/rustc_hir_analysis/src/delegation.rs b/compiler/rustc_hir_analysis/src/delegation.rs index 1ae3fecf92096..2ffd335fb67b9 100644 --- a/compiler/rustc_hir_analysis/src/delegation.rs +++ b/compiler/rustc_hir_analysis/src/delegation.rs @@ -2,12 +2,15 @@ //! //! For more information about delegation design, see the tracking issue #118212. +use std::assert_matches; + use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::{DelegationSelfTyPropagationKind, PathSegment}; use rustc_middle::ty::{ - self, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + self, ConstKind, EarlyBinder, GenericArg, GenericArgKind, RegionKind, Ty, TyCtxt, TypeFoldable, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use rustc_span::{ErrorGuaranteed, Span, kw}; @@ -121,8 +124,6 @@ fn fn_kinds(tcx: TyCtxt<'_>, def_id: LocalDefId, sig_id: DefId) -> (FnKind, FnKi // For trait impl's `sig_id` is always equal to the corresponding trait method. assert!(!matches!(kinds, (_, FnKind::AssocTraitImpl))); - // Delegation to inherent impls is not yet supported. - assert!(!matches!(kinds, (_, FnKind::AssocInherentImpl))); kinds } @@ -176,20 +177,80 @@ fn create_mapping<'tcx>( args_index += is_self_at_zero as usize; args_index += get_delegation_parent_args_count_without_self(tcx, def_id, sig_id); - let sig_generics = tcx.generics_of(sig_id); - let process_sig_parent_generics = matches!(fn_kind(tcx, sig_id), FnKind::AssocTrait); + let parent_kind = fn_kind(tcx, sig_id); + let process_parent = matches!(parent_kind, FnKind::AssocTrait | FnKind::AssocInherentImpl); + let parent_generics = process_parent.then(|| tcx.generics_of(tcx.parent(sig_id))); + + // In case of delegations to inherent impls indices of generic params which are passed + // to ADT can be random numbers not from range 0..parent_params_count, so we need to + // use original indices in mapping: + // impl<'a, 'b, 'c, A: 'a, const C: usize> S<'a, A, C> { + // fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + // fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + // }, + // 'a has index 0, A index 3, C index 4. If we encounter not a generic param as generic arg, + // then we do not need to map it (i.e. consts like `1`, `2`, `3`; `'static`, etc.). + let parent_params = match parent_kind { + FnKind::AssocInherentImpl => { + let ty::Adt(_, args) = tcx.type_of(tcx.parent(sig_id)).skip_binder().kind() else { + unreachable!("parent of inherent function in delegation can be only struct or enum") + }; + + let opt_param_info = |arg: GenericArg<'_>| match arg.kind() { + GenericArgKind::Lifetime(r) => ( + match r.kind() { + RegionKind::ReEarlyParam(p) => Some(p.index), + _ => None, + }, + false, + ), + GenericArgKind::Type(t) => ( + match t.kind() { + ty::Param(p) => Some(p.index), + _ => None, + }, + true, + ), + GenericArgKind::Const(c) => ( + match c.kind() { + ConstKind::Param(p) => Some(p.index), + _ => None, + }, + true, + ), + }; + + args.iter().map(opt_param_info).collect::>() + } + FnKind::AssocTrait => parent_generics + .expect("trait must have generics") + .own_params + .iter() + .map(|p| (Some(p.index as u32), p.kind.is_ty_or_const())) + .collect::>(), + _ => vec![], + }; + + let has_self = match parent_kind { + FnKind::AssocTrait => parent_generics.expect("trait must have generics").has_self, + _ => false, + }; + + if process_parent { + for i in (has_self as usize)..parent_params.len() { + let (index, is_ty_or_const) = parent_params[i]; + if !is_ty_or_const { + if let Some(index) = index { + mapping.insert(index, args_index as u32); + } - if process_sig_parent_generics { - for i in (sig_generics.has_self as usize)..sig_generics.parent_count { - let param = sig_generics.param_at(i, tcx); - if !param.kind.is_ty_or_const() { - mapping.insert(param.index, args_index as u32); args_index += 1; } } } - for param in &sig_generics.own_params { + let child_generics = tcx.generics_of(sig_id); + for param in &child_generics.own_params { if !param.kind.is_ty_or_const() { mapping.insert(param.index, args_index as u32); args_index += 1; @@ -204,17 +265,20 @@ fn create_mapping<'tcx>( args_index += 1; } - if process_sig_parent_generics { - for i in (sig_generics.has_self as usize)..sig_generics.parent_count { - let param = sig_generics.param_at(i, tcx); - if param.kind.is_ty_or_const() { - mapping.insert(param.index, args_index as u32); + if process_parent { + for i in (has_self as usize)..parent_params.len() { + let (index, is_ty_or_const) = parent_params[i]; + if is_ty_or_const { + if let Some(index) = index { + mapping.insert(index, args_index as u32); + } + args_index += 1; } } } - for param in &sig_generics.own_params { + for param in &child_generics.own_params { if param.kind.is_ty_or_const() { mapping.insert(param.index, args_index as u32); args_index += 1; @@ -339,7 +403,7 @@ fn create_generic_args<'tcx>( let delegation_args = &delegation_args[delegation_generics.parent_count..]; - let kinds = fn_kinds(tcx, def_id, sig_id); + let kinds @ (_, parent_kind) = fn_kinds(tcx, def_id, sig_id); if matches!(kinds, (FnKind::AssocTraitImpl, FnKind::AssocTrait)) { // Special case, as user specifies Trait args in trait impl header, we want to treat // them as parent args. We always generate a function whose generics match @@ -357,10 +421,14 @@ fn create_generic_args<'tcx>( let self_type = get_delegation_self_ty(tcx, def_id).map(ty::GenericArg::from); - // Remove `Self` from parent args (it is always at the `0th` index) as it is - // added manually. if self_type.is_some() && !parent_args.is_empty() { - parent_args = &parent_args[1..]; + parent_args = match parent_kind { + FnKind::AssocInherentImpl => parent_args, + // Remove `Self` from parent args (it is always at the `0th` index) as it is + // added manually. + FnKind::AssocTrait => &parent_args[1..], + _ => unreachable!("if parent args are non-empty then the parent must exist"), + } } let (zero_self, after_lifetimes_self) = @@ -582,8 +650,66 @@ pub(crate) fn inherit_sig_for_delegation_item<'tcx>( let caller_sig = EarlyBinder::bind(tcx, caller_sig.skip_binder().fold_with(&mut folder)); let sig = caller_sig.instantiate(tcx, args.as_slice()).skip_binder(); - let sig_iter = sig.inputs().iter().cloned().chain(std::iter::once(sig.output())); - tcx.arena.alloc_from_iter(sig_iter) + let output = std::iter::once(sig.output()); + let mut sig = sig.inputs().iter().cloned().chain(output).collect::>(); + + adjust_sig_in_inherent_impl_cases(tcx, sig_id, def_id, parent_args, &mut sig); + + tcx.arena.alloc_from_iter(sig) +} + +/// We need to replace `Self` type of the signature function parent with +/// either type of parent of delegation (which is either `Self` param in case of trait) +/// and other ADT in case of inherent impl. We do the same thing when delegating to trait, +/// in this case replacement happens during signature instantiation (as we can replace `Self` +/// generic param with other type from `args` when instantiating). +fn adjust_sig_in_inherent_impl_cases<'tcx>( + tcx: TyCtxt<'tcx>, + sig_id: DefId, + def_id: LocalDefId, + parent_args: &[ty::GenericArg<'tcx>], + sig: &mut [Ty<'tcx>], +) { + if !tcx.is_method(sig_id) { + return; + } + + let kinds @ (def_kind, _) = fn_kinds(tcx, def_id, sig_id); + if def_kind == FnKind::Free || !matches!(kinds, (_, FnKind::AssocInherentImpl)) { + return; + } + + let ty::Adt(def, _) = tcx.type_of(tcx.parent(sig_id)).skip_binder().kind() else { + unreachable!("delegation is supported only to struct or enums") + }; + + for i in 0..sig.len() { + let to_replace = Ty::new_adt(tcx, *def, tcx.mk_args(parent_args)); + let replacement = match def_kind { + FnKind::Free => unreachable!(), + + FnKind::AssocTrait => Ty::new_param(tcx, 0, kw::SelfUpper), + _ => tcx.type_of(tcx.parent(def_id.to_def_id())).instantiate_identity().skip_norm_wip(), + }; + + struct Replacer<'tcx> { + tcx: TyCtxt<'tcx>, + to_replace: Ty<'tcx>, + replacement: Ty<'tcx>, + } + + impl<'tcx> TypeFolder> for Replacer<'tcx> { + fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { + if t == self.to_replace { self.replacement } else { t.super_fold_with(self) } + } + + fn cx(&self) -> TyCtxt<'tcx> { + self.tcx + } + } + + sig[i] = sig[i].fold_with(&mut Replacer { tcx, to_replace, replacement }) + } } // Creates user-specified generic arguments from delegation path, @@ -603,11 +729,16 @@ pub(crate) fn delegation_user_specified_args<'tcx>( let ctx = ItemCtxt::new_for_delegation(tcx, def_id); let lowerer = ctx.lowerer(); + let parent_args = info .parent_seg_id_for_sig .and_then(get_segment) - .filter(|(_, def_id)| matches!(tcx.def_kind(*def_id), DefKind::Trait)) + .filter(|(_, def_id)| !matches!(tcx.def_kind(*def_id), DefKind::Mod)) .map(|(segment, def_id)| { + // After lowering parent segment can be resolved only to those variants (and `DefKind::Mod`), + // which we do not process here. + assert_matches!(tcx.def_kind(def_id), DefKind::Trait | DefKind::Struct | DefKind::Enum); + let self_ty = (tcx.def_kind(def_id) == DefKind::Trait) .then(|| Ty::new_param(tcx, 0, kw::SelfUpper)); @@ -617,29 +748,26 @@ pub(crate) fn delegation_user_specified_args<'tcx>( .as_slice() }); - let child_args = info - .child_seg_id_for_sig - .and_then(get_segment) - .filter(|(_, def_id)| matches!(tcx.def_kind(*def_id), DefKind::Fn | DefKind::AssocFn)) - .map(|(segment, def_id)| { - let parent_args = if let Some(parent_args) = parent_args { + let child_args = info.child_seg_id_for_sig.and_then(get_segment).map(|(segment, def_id)| { + assert_matches!(tcx.def_kind(def_id), DefKind::Fn | DefKind::AssocFn); + let parent = tcx.parent(def_id); + + let parent_args = + if matches!(tcx.def_kind(parent), DefKind::Impl { of_trait: false } | DefKind::Trait) { + ty::GenericArgs::identity_for_item(tcx, parent).as_slice() + } else if let Some(parent_args) = parent_args { parent_args } else { - let parent = tcx.parent(def_id); - if matches!(tcx.def_kind(parent), DefKind::Trait) { - ty::GenericArgs::identity_for_item(tcx, parent).as_slice() - } else { - &[] - } + &[] }; - let args = lowerer - .lower_generic_args_of_path(segment.ident.span, def_id, parent_args, segment, None) - .0; + let args = lowerer + .lower_generic_args_of_path(segment.ident.span, def_id, parent_args, segment, None) + .0; - let synth_params_count = tcx.generics_of(def_id).own_synthetic_params_count(); - &args[parent_args.len()..args.len() - synth_params_count] - }); + let synth_params_count = tcx.generics_of(def_id).own_synthetic_params_count(); + &args[parent_args.len()..args.len() - synth_params_count] + }); (parent_args.unwrap_or_default(), child_args.unwrap_or_default()) } diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 40bf435e6d110..6e6ded6c59ea1 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -1,7 +1,7 @@ use std::cell::{Cell, RefCell}; use std::cmp::max; -use std::debug_assert_matches; use std::ops::Deref; +use std::{assert_matches, debug_assert_matches}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sso::SsoHashSet; @@ -595,8 +595,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ProbeScope::Single(def_id, self_ty_override) => { let item = self.tcx.associated_item(def_id); - // FIXME(fn_delegation): Delegation to inherent methods is not yet supported. - assert_eq!(item.container, AssocContainer::Trait); + assert_matches!( + item.container, + AssocContainer::Trait | AssocContainer::InherentImpl + ); let trait_def_id = self.tcx.parent(def_id); let trait_span = self.tcx.def_span(trait_def_id); @@ -608,10 +610,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { probe_cx.push_candidate( Candidate { item, - kind: CandidateKind::TraitCandidate( - ty::Binder::dummy(trait_ref), - false, - ), + kind: match item.container { + AssocContainer::Trait => CandidateKind::TraitCandidate( + ty::Binder::dummy(trait_ref), + false, + ), + AssocContainer::InherentImpl => { + CandidateKind::InherentImplCandidate { + impl_def_id: self.tcx.parent(def_id), + receiver_steps: 0, + } + } + _ => unreachable!(), + }, import_ids: &[], }, false, diff --git a/compiler/rustc_middle/src/middle/resolve.rs b/compiler/rustc_middle/src/middle/resolve.rs index 2958048103320..8267cde89ad27 100644 --- a/compiler/rustc_middle/src/middle/resolve.rs +++ b/compiler/rustc_middle/src/middle/resolve.rs @@ -190,6 +190,8 @@ pub struct ResolverGlobalCtxt { // Information about delegations which is used when handling recursive delegations // and ensures easy access to delegation-only `LocalDefId`s. pub delegation_infos: FxIndexMap, + pub delegation_inherent_fn_map: + FxIndexMap>, } #[derive(Debug)] @@ -261,14 +263,44 @@ pub struct ResolverAstLowering<'tcx> { pub disambiguators: LocalDefIdMap>, } +#[derive(Debug, Clone, Copy, StableHash)] +pub enum DelegationResolution { + /// Corresponds to paths that are fully resolved by resolver (i.e., `reuse Trait::foo`). + Full(DefId /* Signature and call path resolutions are the same */), + + /// We can encounter cases like delegation to inherent impl function from trait impl, + /// in this case we will have resolved signature id, but the call-path itself will + /// not be resolved, so we will need to use type-relative resolution routine during + /// AST -> HIR lowering. + PartialCall(DefId /* Signature resolution, call path is unresolved */), + + /// Corresponds to paths that are partially resolved by resolver (i.e., `reuse Struct::foo`). + Partial, + + Error(ErrorGuaranteed), +} + #[derive(Debug, StableHash)] pub struct DelegationInfo { - // `DefId` (either the resolution at delegation.id or item_id in case of a trait impl) for - // signature resolution, for details see - // https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914. - /// Refers to the next element in a delegation resolution chain. Usually points to the final - /// resolution, as most "chains" are just one step to a trait or an impl. - pub resolution_id: Result, + // `DefId` (either the resolution at delegation.id or item_id in case of a trait impl) for signature resolution, + // for details see https://github.com/rust-lang/rust/issues/118212#issuecomment-2160686914 + /// Refers to the next element in a delegation resolution chain. + /// Usually points to the final resolution, as most "chains" are just + /// one step to a trait or an impl. + pub resolution: DelegationResolution, +} + +#[derive(Debug, StableHash)] +pub enum TypeRelativeDelegationRes { + Ok(DefId), + Ambig(ErrorGuaranteed), + Error(ErrorGuaranteed), +} + +#[derive(Debug, StableHash)] +pub enum DelegationInherentFnKind { + Single(LocalDefId), + Ambig, } #[derive(Clone, Copy, Debug, StableHash)] diff --git a/compiler/rustc_middle/src/queries.rs b/compiler/rustc_middle/src/queries.rs index e127693a2e231..aa354e1ab8df0 100644 --- a/compiler/rustc_middle/src/queries.rs +++ b/compiler/rustc_middle/src/queries.rs @@ -71,6 +71,7 @@ use rustc_hir::{ItemLocalId, PreciseCapturingArgKind}; use rustc_index::{IndexSlice, IndexVec}; use rustc_lint_defs::{LintId, StableLintExpectationId}; use rustc_macros::rustc_queries; +use rustc_middle::middle::resolve::TypeRelativeDelegationRes; use rustc_session::Limits; use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion}; use rustc_span::def_id::{LOCAL_CRATE, ModId}; @@ -227,6 +228,11 @@ rustc_queries! { desc { "getting the source span" } } + query resolve_type_relative_delegations(_: ()) -> &'tcx FxIndexMap { + arena_cache + desc { "resolving type relative delegations" } + } + query lower_to_hir(def_id: LocalDefId) -> hir::MaybeOwner<'tcx> { eval_always desc { "lowering HIR for `{}`", tcx.def_path_str(def_id) } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 5ff5c05de734a..93e407570f04c 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1283,6 +1283,10 @@ impl<'tcx> TyCtxt<'tcx> { None => Err(VarError::NotPresent), } } + + pub fn is_method(self, id: DefId) -> bool { + self.opt_associated_item(id).is_some_and(|item| item.is_method()) + } } impl<'tcx> TyCtxtAt<'tcx> { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 2966e3ad24a07..9b879d9a443fa 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -29,7 +29,9 @@ use rustc_hir::def::{CtorKind, DefKind, NonMacroAttrKind, PerNS}; use rustc_hir::def_id::{CRATE_DEF_ID, DefId, LOCAL_CRATE, LocalDefId}; use rustc_hir::{MissingLifetimeKind, PrimTy}; use rustc_lint_defs::builtin::{ELIDED_LIFETIMES_IN_PATHS, UNUSED_LABELS}; -use rustc_middle::middle::resolve::{DelegationInfo, LifetimeRes, PartialRes}; +use rustc_middle::middle::resolve::{ + DelegationInfo, DelegationInherentFnKind, DelegationResolution, LifetimeRes, PartialRes, +}; use rustc_middle::middle::resolve_bound_vars::Set1; use rustc_middle::ty::{AssocTag, Visibility}; use rustc_middle::{bug, span_bug}; @@ -501,11 +503,11 @@ impl PathSource<'_, '_, '_> { | PathSource::Pat | PathSource::Struct(_) | PathSource::TupleStruct(..) + | PathSource::Delegation | PathSource::ReturnTypeNotation => true, PathSource::Trait(_) | PathSource::TraitItem(..) | PathSource::DefineOpaques - | PathSource::Delegation | PathSource::ExternItemImpl | PathSource::PreciseCapturingArg(..) | PathSource::Macro @@ -3603,7 +3605,13 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { let mut seen_trait_items = Default::default(); for item in impl_items { with_owner(this, item.id, |this| { - this.resolve_impl_item(&**item, &mut seen_trait_items, trait_id, of_trait.is_some()); + this.resolve_impl_item( + &**item, + &mut seen_trait_items, + trait_id, + of_trait.is_some(), + self_type.id, + ); }) } }); @@ -3646,6 +3654,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { seen_trait_items: &mut FxHashMap, trait_id: Option, is_in_trait_impl: bool, + self_type_id: NodeId, ) { use crate::ResolutionError::*; self.resolve_doc_links(&item.attrs, MaybeExported::ImplItem(trait_id.ok_or(&item.vis))); @@ -3747,6 +3756,10 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }, ); + if !is_in_trait_impl { + self.fill_delegation_inherent_fn_map(self_type_id, ident); + } + self.resolve_define_opaques(define_opaque); } AssocItemKind::Type(TyAlias { ident, generics, .. }) => { @@ -3789,6 +3802,14 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { LifetimeBinderKind::Function, delegation.path.segments.last().unwrap().ident.span, |this| { + if !is_in_trait_impl { + this.fill_delegation_inherent_fn_map( + self_type_id, + // If rename is specified then ident equals rename. + &delegation.ident, + ); + } + this.check_trait_item( item.id, delegation.ident, @@ -3813,6 +3834,34 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.diag_metadata.current_impl_item = prev; } + /// A heuristic to resolve delegations to inherent impls during AST -> HIR lowering. + /// Ideally we would do it through `ProbeContext`, however now it is impossible due to + /// query cycles even in the code without errors. + /// Not all paths will be properly resolved this way (i.e., type aliases). + /// FIXME(fn_delegation): remove it when resolution through `ProbeContext` will be ready + fn fill_delegation_inherent_fn_map(&mut self, self_type_id: NodeId, ident: &Ident) { + let res = self.r.partial_res_map.get(&self_type_id); + + let Some(self_type_def_id) = res.and_then(|res| { + res.full_res().and_then(|r| r.opt_def_id()).and_then(|id| id.as_local()) + }) else { + return; + }; + + // FIXME(fn_delegation): use correct identifier hygiene + let map = self.r.delegation_inherent_fn_map.entry(self_type_def_id).or_default(); + + match map.get(ident) { + None => { + map.insert(*ident, DelegationInherentFnKind::Single(self.r.current_owner.def_id)); + } + Some(DelegationInherentFnKind::Single(..)) => { + map.insert(*ident, DelegationInherentFnKind::Ambig); + } + _ => {} + }; + } + fn check_trait_item( &mut self, id: NodeId, @@ -3985,22 +4034,39 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }); let resolution_node_id = if is_in_trait_impl { item_id } else { delegation.id }; - let def_id = self + let resolution = self .r .partial_res_map .get(&resolution_node_id) - .and_then(|r| r.expect_full_res().opt_def_id()); + .map(|r| match r.full_res().and_then(|r| r.opt_def_id()) { + None => { + // If we are inside trait impl delegation is either resolved or not. + assert!(!is_in_trait_impl); + DelegationResolution::Partial + } + Some(def_id) => { + // If we are inside trait impl do additional check if call path is resolved, + // this will later be used to decide if we should apply type-relative resolution + // routine during call path resolution in AST -> HIR lowering. + if is_in_trait_impl { + let path_res = self.r.partial_res_map[&delegation.id]; + + if path_res.full_res().and_then(|r| r.opt_def_id()).is_none() { + return DelegationResolution::PartialCall(def_id); + } + } - let resolution_id = def_id.ok_or_else(|| { - self.r.tcx.dcx().span_delayed_bug( - delegation.path.span, - format!( - "LateResolutionVisitor: couldn't resolve node {resolution_node_id:?} in delegation item", - ), - ) - }); + DelegationResolution::Full(def_id) + } + }) + .unwrap_or_else(|| { + DelegationResolution::Error(self.r.tcx.dcx().span_delayed_bug( + delegation.path.span, + format!("bad resolution for delegation {item_id:?}"), + )) + }); - let info = DelegationInfo { resolution_id }; + let info = DelegationInfo { resolution }; self.r.delegation_infos.insert(self.r.current_owner.def_id, info); let Some(body) = &delegation.body else { return }; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index d5b1457865891..baadbc644582b 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -62,8 +62,8 @@ use rustc_lint_defs::builtin::PRIVATE_MACRO_USE; use rustc_metadata::creader::CStore; use rustc_middle::middle::privacy::EffectiveVisibilities; use rustc_middle::middle::resolve::{ - AmbigModChild, DelegationInfo, DocLinkResMap, MainDefinition, ModChild, PartialRes, - PerOwnerResolverData, Reexport, ResolverAstLowering, ResolverGlobalCtxt, + AmbigModChild, DelegationInfo, DelegationInherentFnKind, DocLinkResMap, MainDefinition, + ModChild, PartialRes, PerOwnerResolverData, Reexport, ResolverAstLowering, ResolverGlobalCtxt, }; use rustc_middle::query::Providers; use rustc_middle::ty::{self, RegisteredTools, TyCtxt, TyCtxtFeed, Visibility}; @@ -1515,6 +1515,7 @@ pub struct Resolver<'ra, 'tcx> { item_required_generic_args_suggestions: FxHashMap = default::fx_hash_map(), delegation_fn_sigs: LocalDefIdMap = Default::default(), delegation_infos: FxIndexMap, + delegation_inherent_fn_map: FxIndexMap>, main_def: Option = None, trait_impls: FxIndexMap>, @@ -1887,6 +1888,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { current_crate_outer_attr_insert_span, disambiguators: Default::default(), delegation_infos: Default::default(), + delegation_inherent_fn_map: Default::default(), features: tcx.features(), .. }; @@ -1991,6 +1993,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { all_macro_rules: self.all_macro_rules, stripped_cfg_items, delegation_infos: self.delegation_infos, + delegation_inherent_fn_map: self.delegation_inherent_fn_map, }; let ast_lowering = ResolverAstLowering { partial_res_map: self.partial_res_map, diff --git a/tests/ui/delegation/bad-resolve.rs b/tests/ui/delegation/bad-resolve.rs index eb31c20081461..0864776ab49fd 100644 --- a/tests/ui/delegation/bad-resolve.rs +++ b/tests/ui/delegation/bad-resolve.rs @@ -33,10 +33,12 @@ impl Trait for S { reuse foo { &self.0 } //~^ ERROR cannot find function `foo` in this scope - //~| ERROR: method `foo` has a `&self` declaration in the trait, but not in the impl + //~| ERROR method `foo` has a `&self` declaration in the trait, but not in the impl reuse Trait::foo2 { self.0 } - //~^ ERROR cannot find function `foo2` in trait `Trait` - //~| ERROR method `foo2` is not a member of trait `Trait` + //~^ ERROR: method `foo2` is not a member of trait `Trait` + //~| WARN: trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| ERROR: the trait `Trait` is not dyn compatible [E0038] } mod prefix {} diff --git a/tests/ui/delegation/bad-resolve.stderr b/tests/ui/delegation/bad-resolve.stderr index 44cf5149d08dd..9740442e4b9f3 100644 --- a/tests/ui/delegation/bad-resolve.stderr +++ b/tests/ui/delegation/bad-resolve.stderr @@ -71,25 +71,8 @@ error[E0425]: cannot find function `foo` in this scope LL | reuse foo { &self.0 } | ^^^ not found in this scope -error[E0425]: cannot find function `foo2` in trait `Trait` - --> $DIR/bad-resolve.rs:37:18 - | -LL | reuse Trait::foo2 { self.0 } - | ^^^^ not found in `Trait` - | -note: similarly named associated function `foo` defined here - --> $DIR/bad-resolve.rs:7:5 - | -LL | fn foo(&self, x: i32) -> i32 { x } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: an associated function with a similar name exists - | -LL - reuse Trait::foo2 { self.0 } -LL + reuse Trait::foo { self.0 } - | - error[E0423]: cannot find function `self` in module `prefix` - --> $DIR/bad-resolve.rs:44:16 + --> $DIR/bad-resolve.rs:46:16 | LL | reuse prefix::{self, super, crate}; | ^^^^ not found in `prefix` @@ -114,8 +97,54 @@ LL | type Type; LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ missing `Type` in implementation +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/bad-resolve.rs:37:11 + | +LL | reuse Trait::foo2 { self.0 } + | ^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | reuse ::foo2 { self.0 } + | ++++ + + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/bad-resolve.rs:37:11 + | +LL | reuse Trait::foo2 { self.0 } + | ^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/bad-resolve.rs:4:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | const C: u32 = 0; + | ^ ...because it contains associated const `C` +LL | type Type; +LL | fn bar() {} + | ^^^ ...because associated function `bar` has no `self` parameter + = help: consider moving `C` to another trait + = help: the following types implement `Trait`: + F + S + consider defining an enum where each variant holds one of these types, + implementing `Trait` for this new enum and using it instead +help: consider turning `bar` into a method by giving it a `&self` argument, so that it is accessible through the trait object's vtable + | +LL | fn bar(&self) {} + | +++++ +help: alternatively, consider constraining `bar` so it is explicitly marked as not applying to trait objects + | +LL | fn bar() where Self: Sized {} + | +++++++++++++++++ + error[E0433]: cannot find module or crate `unresolved_prefix` in this scope - --> $DIR/bad-resolve.rs:43:7 + --> $DIR/bad-resolve.rs:45:7 | LL | reuse unresolved_prefix::{a, b, c}; | ^^^^^^^^^^^^^^^^^ use of unresolved module or unlinked crate `unresolved_prefix` @@ -123,12 +152,12 @@ LL | reuse unresolved_prefix::{a, b, c}; = help: you might be missing a crate named `unresolved_prefix` error[E0433]: `crate` in paths can only be used in start position - --> $DIR/bad-resolve.rs:44:29 + --> $DIR/bad-resolve.rs:46:29 | LL | reuse prefix::{self, super, crate}; | ^^^^^ can only be used in path start position -error: aborting due to 14 previous errors +error: aborting due to 14 previous errors; 1 warning emitted -Some errors have detailed explanations: E0046, E0186, E0324, E0407, E0423, E0425, E0433, E0575, E0576. -For more information about an error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0038, E0046, E0186, E0324, E0407, E0423, E0425, E0433, E0575... +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/delegation/explicit-paths.rs b/tests/ui/delegation/explicit-paths.rs index 2592d3d2698fc..e9530ec9d2314 100644 --- a/tests/ui/delegation/explicit-paths.rs +++ b/tests/ui/delegation/explicit-paths.rs @@ -25,7 +25,7 @@ mod fn_to_other { reuse ::foo2; reuse to_reuse::foo3; reuse S::foo4; - //~^ ERROR cannot find function `foo4` in `S` + //~^ ERROR: method `foo4` is private } mod inherent_impl_assoc_fn_to_other { @@ -36,7 +36,6 @@ mod inherent_impl_assoc_fn_to_other { reuse ::foo2; reuse to_reuse::foo3; reuse F::foo4 { &self.0 } - //~^ ERROR cannot find function `foo4` in `F` } } @@ -50,7 +49,6 @@ mod trait_impl_assoc_fn_to_other { //~^ ERROR method `foo3` is not a member of trait `Trait` reuse F::foo4 { &self.0 } //~^ ERROR method `foo4` is not a member of trait `Trait` - //~| ERROR cannot find function `foo4` in `F` } } @@ -63,7 +61,6 @@ mod trait_assoc_fn_to_other { reuse ::foo2; reuse to_reuse::foo3; reuse F::foo4 { &F } - //~^ ERROR cannot find function `foo4` in `F` } } diff --git a/tests/ui/delegation/explicit-paths.stderr b/tests/ui/delegation/explicit-paths.stderr index 30239f3648a53..f92bfd73266c3 100644 --- a/tests/ui/delegation/explicit-paths.stderr +++ b/tests/ui/delegation/explicit-paths.stderr @@ -1,5 +1,5 @@ error[E0407]: method `foo3` is not a member of trait `Trait` - --> $DIR/explicit-paths.rs:49:9 + --> $DIR/explicit-paths.rs:48:9 | LL | reuse to_reuse::foo3; | ^^^^^^^^^^^^^^^^----^ @@ -8,7 +8,7 @@ LL | reuse to_reuse::foo3; | not a member of trait `Trait` error[E0407]: method `foo4` is not a member of trait `Trait` - --> $DIR/explicit-paths.rs:51:9 + --> $DIR/explicit-paths.rs:50:9 | LL | reuse F::foo4 { &self.0 } | ^^^^^^^^^----^^^^^^^^^^^^ @@ -16,50 +16,8 @@ LL | reuse F::foo4 { &self.0 } | | help: there is an associated function with a similar name: `foo1` | not a member of trait `Trait` -error[E0425]: cannot find function `foo4` in `S` - --> $DIR/explicit-paths.rs:27:14 - | -LL | reuse S::foo4; - | ^^^^ not found in `S` - -error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:38:18 - | -LL | reuse F::foo4 { &self.0 } - | ^^^^ not found in `F` - | -note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:27:5 - | -LL | reuse S::foo4; - | ^^^^^^^^^^^^^^ not accessible - -error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:51:18 - | -LL | reuse F::foo4 { &self.0 } - | ^^^^ not found in `F` - | -note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:27:5 - | -LL | reuse S::foo4; - | ^^^^^^^^^^^^^^ not accessible - -error[E0425]: cannot find function `foo4` in `F` - --> $DIR/explicit-paths.rs:65:18 - | -LL | reuse F::foo4 { &F } - | ^^^^ not found in `F` - | -note: function `fn_to_other::foo4` exists but is inaccessible - --> $DIR/explicit-paths.rs:27:5 - | -LL | reuse S::foo4; - | ^^^^^^^^^^^^^^ not accessible - error[E0119]: conflicting implementations of trait `Trait` for type `S` - --> $DIR/explicit-paths.rs:74:5 + --> $DIR/explicit-paths.rs:71:5 | LL | impl Trait for S { | ---------------- first implementation here @@ -67,8 +25,17 @@ LL | impl Trait for S { LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ conflicting implementation for `S` +error[E0624]: method `foo4` is private + --> $DIR/explicit-paths.rs:27:14 + | +LL | reuse S::foo4; + | ^^^^ private method +... +LL | reuse F::foo4 { &self.0 } + | ---- private method defined here + error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:61:36 + --> $DIR/explicit-paths.rs:59:36 | LL | trait Trait2 : Trait { | -------------------- found this type parameter @@ -86,13 +53,13 @@ LL | fn foo1(&self, x: i32) -> i32 { x } | ^^^^ ----- error[E0277]: the trait bound `S2: Trait` is not satisfied - --> $DIR/explicit-paths.rs:76:16 + --> $DIR/explicit-paths.rs:73:16 | LL | reuse ::foo1; | ^^ unsatisfied trait bound | help: the trait `Trait` is not implemented for `S2` - --> $DIR/explicit-paths.rs:73:5 + --> $DIR/explicit-paths.rs:70:5 | LL | struct S2; | ^^^^^^^^^ @@ -109,7 +76,7 @@ LL | impl Trait for S { | ^^^^^^^^^^^^^^^^ `S` error[E0308]: mismatched types - --> $DIR/explicit-paths.rs:76:30 + --> $DIR/explicit-paths.rs:73:30 | LL | reuse ::foo1; | ^^^^ @@ -125,7 +92,7 @@ note: method defined here LL | fn foo1(&self, x: i32) -> i32 { x } | ^^^^ ----- -error: aborting due to 10 previous errors +error: aborting due to 7 previous errors -Some errors have detailed explanations: E0119, E0277, E0308, E0407, E0425. +Some errors have detailed explanations: E0119, E0277, E0308, E0407, E0624. For more information about an error, try `rustc --explain E0119`. diff --git a/tests/ui/delegation/glob-non-fn.rs b/tests/ui/delegation/glob-non-fn.rs index 939c5db6a0e8f..72111fc81d7f0 100644 --- a/tests/ui/delegation/glob-non-fn.rs +++ b/tests/ui/delegation/glob-non-fn.rs @@ -31,7 +31,9 @@ impl Trait for Bad { //~ ERROR not all trait items implemented, missing: `CONST` //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait` //~| ERROR duplicate definitions with name `method` //~| ERROR expected function, found associated constant `Trait::CONST` - //~| ERROR cannot find function `Type` in trait `Trait` + //~| ERROR the trait `Trait` is not dyn compatible + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! } fn main() {} diff --git a/tests/ui/delegation/glob-non-fn.stderr b/tests/ui/delegation/glob-non-fn.stderr index 6f7010d43d8ae..e1a4ffce5ac17 100644 --- a/tests/ui/delegation/glob-non-fn.stderr +++ b/tests/ui/delegation/glob-non-fn.stderr @@ -34,14 +34,6 @@ error[E0423]: expected function, found associated constant `Trait::CONST` LL | reuse Trait::* { &self.0 } | ^^^^^ not a function -error[E0423]: cannot find function `Type` in trait `Trait` - --> $DIR/glob-non-fn.rs:29:18 - | -LL | reuse Trait::* { &self.0 } - | ^ not found in `Trait` - | - = note: an associated type named `Trait::Type` exists in another namespace - error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` --> $DIR/glob-non-fn.rs:28:1 | @@ -56,7 +48,44 @@ LL | type method; LL | impl Trait for Bad { | ^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation -error: aborting due to 6 previous errors +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/glob-non-fn.rs:29:11 + | +LL | reuse Trait::* { &self.0 } + | ^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | reuse ::* { &self.0 } + | ++++ + + +error[E0038]: the trait `Trait` is not dyn compatible + --> $DIR/glob-non-fn.rs:29:11 + | +LL | reuse Trait::* { &self.0 } + | ^^^^^ `Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/glob-non-fn.rs:5:11 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | fn method(&self); +LL | const CONST: u8; + | ^^^^^ ...because it contains associated const `CONST` + = help: consider moving `CONST` to another trait + = help: the following types implement `Trait`: + u8 + Good + Bad + consider defining an enum where each variant holds one of these types, + implementing `Trait` for this new enum and using it instead + +error: aborting due to 6 previous errors; 1 warning emitted -Some errors have detailed explanations: E0046, E0201, E0324, E0423. -For more information about an error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0038, E0046, E0201, E0324, E0423. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.rs b/tests/ui/delegation/impl-reuse-non-reuse-items.rs index 23c22a61cbb0a..517e2b26a36f9 100644 --- a/tests/ui/delegation/impl-reuse-non-reuse-items.rs +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.rs @@ -23,9 +23,11 @@ mod non_delegatable_items { //~^ ERROR item `CONST` is an associated method, which doesn't match its trait `Trait` //~| ERROR item `Type` is an associated method, which doesn't match its trait `Trait` //~| ERROR duplicate definitions with name `method` - //~| ERROR expected function, found associated constant `Trait::CONST` - //~| ERROR cannot find function `Type` in trait `Trait` //~| ERROR not all trait items implemented, missing: `CONST`, `Type`, `method` + //~| ERROR expected function, found associated constant `Trait::CONST` + //~| WARN trait objects without an explicit `dyn` are deprecated [bare_trait_objects] + //~| WARN this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + //~| ERROR the trait `non_delegatable_items::Trait` is not dyn compatible } fn main() {} diff --git a/tests/ui/delegation/impl-reuse-non-reuse-items.stderr b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr index 2bd488e9fb3d8..2a33982cc6730 100644 --- a/tests/ui/delegation/impl-reuse-non-reuse-items.stderr +++ b/tests/ui/delegation/impl-reuse-non-reuse-items.stderr @@ -34,14 +34,6 @@ error[E0423]: expected function, found associated constant `Trait::CONST` LL | reuse impl Trait for S { &self.0 } | ^^^^^ not a function -error[E0423]: cannot find function `Type` in trait `Trait` - --> $DIR/impl-reuse-non-reuse-items.rs:22:5 - | -LL | reuse impl Trait for S { &self.0 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not found in `Trait` - | - = note: an associated type named `Trait::Type` exists in another namespace - error[E0046]: not all trait items implemented, missing: `CONST`, `Type`, `method` --> $DIR/impl-reuse-non-reuse-items.rs:22:5 | @@ -56,7 +48,43 @@ LL | type method; LL | reuse impl Trait for S { &self.0 } | ^^^^^^^^^^^^^^^^^^^^^^ missing `CONST`, `Type`, `method` in implementation -error: aborting due to 6 previous errors +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/impl-reuse-non-reuse-items.rs:22:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ + | + = warning: this is accepted in the current edition (Rust 2015) but is a hard error in Rust 2021! + = note: for more information, see + = note: `#[warn(bare_trait_objects)]` (part of `#[warn(rust_2021_compatibility)]`) on by default +help: if this is a dyn-compatible trait, use `dyn` + | +LL | reuse impl for S { &self.0 } + | ++++ + + +error[E0038]: the trait `non_delegatable_items::Trait` is not dyn compatible + --> $DIR/impl-reuse-non-reuse-items.rs:22:16 + | +LL | reuse impl Trait for S { &self.0 } + | ^^^^^ `non_delegatable_items::Trait` is not dyn compatible + | +note: for a trait to be dyn compatible it needs to allow building a vtable + for more information, visit + --> $DIR/impl-reuse-non-reuse-items.rs:6:15 + | +LL | trait Trait { + | ----- this trait is not dyn compatible... +LL | fn method(&self); +LL | const CONST: u8; + | ^^^^^ ...because it contains associated const `CONST` + = help: consider moving `CONST` to another trait + = help: the following types implement `non_delegatable_items::Trait`: + non_delegatable_items::F + non_delegatable_items::S + consider defining an enum where each variant holds one of these types, + implementing `non_delegatable_items::Trait` for this new enum and using it instead + +error: aborting due to 6 previous errors; 1 warning emitted -Some errors have detailed explanations: E0046, E0201, E0324, E0423. -For more information about an error, try `rustc --explain E0046`. +Some errors have detailed explanations: E0038, E0046, E0201, E0324, E0423. +For more information about an error, try `rustc --explain E0038`. diff --git a/tests/ui/delegation/inherent-impls-ambig.rs b/tests/ui/delegation/inherent-impls-ambig.rs index 1c419034d2446..1b7c9a6fcef0f 100644 --- a/tests/ui/delegation/inherent-impls-ambig.rs +++ b/tests/ui/delegation/inherent-impls-ambig.rs @@ -14,16 +14,19 @@ mod test_1 { } reuse X::foo; - //~^ ERROR: cannot find function `foo` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: multiple applicable items in scope [E0034] reuse X::foo_self; - //~^ ERROR: cannot find function `foo_self` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: multiple applicable items in scope [E0034] reuse X::<()>::foo as foo1; - //~^ ERROR: cannot find function `foo` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function reuse X::::foo_self as foo_self1; - //~^ ERROR: cannot find function `foo_self` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: this function takes 1 argument but 0 arguments were supplied } mod test_2 { @@ -47,16 +50,19 @@ mod test_2 { impl Marker2 for M2 {} reuse X::foo; - //~^ ERROR: cannot find function `foo` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: multiple applicable items in scope [E0034] reuse X::foo_self; - //~^ ERROR: cannot find function `foo_self` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: multiple applicable items in scope [E0034] reuse X::::foo as foo1; - //~^ ERROR: cannot find function `foo` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function reuse X::::foo_self as foo_self1; - //~^ ERROR: cannot find function `foo_self` in `X` + //~^ ERROR: ambiguous delegation to inherent impl function + //~| ERROR: no associated function or constant named `foo_self` found for struct `test_2::X` in the current scope } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-ambig.stderr b/tests/ui/delegation/inherent-impls-ambig.stderr index 0be82bcdd6f74..a15fc0f2af268 100644 --- a/tests/ui/delegation/inherent-impls-ambig.stderr +++ b/tests/ui/delegation/inherent-impls-ambig.stderr @@ -1,99 +1,145 @@ -error[E0425]: cannot find function `foo` in `X` +error: ambiguous delegation to inherent impl function --> $DIR/inherent-impls-ambig.rs:16:14 | LL | reuse X::foo; - | ^^^ not found in `X` - | -note: function `test_2::foo` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:49:5 - | -LL | reuse X::foo; - | ^^^^^^^^^^^^^ not accessible + | ^^^ -error[E0425]: cannot find function `foo_self` in `X` - --> $DIR/inherent-impls-ambig.rs:19:14 - | -LL | reuse X::foo_self; - | ^^^^^^^^ not found in `X` - | -note: function `test_2::foo_self` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:52:5 +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:20:14 | LL | reuse X::foo_self; - | ^^^^^^^^^^^^^^^^^^ not accessible + | ^^^^^^^^ -error[E0425]: cannot find function `foo` in `X` - --> $DIR/inherent-impls-ambig.rs:22:20 +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:24:20 | LL | reuse X::<()>::foo as foo1; - | ^^^ not found in `X` + | ^^^ + +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:27:23 | -note: function `test_2::foo` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:49:5 +LL | reuse X::::foo_self as foo_self1; + | ^^^^^^^^ + +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:52:14 | LL | reuse X::foo; - | ^^^^^^^^^^^^^ not accessible + | ^^^ -error[E0425]: cannot find function `foo_self` in `X` - --> $DIR/inherent-impls-ambig.rs:25:23 +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:56:14 | -LL | reuse X::::foo_self as foo_self1; - | ^^^^^^^^ not found in `X` +LL | reuse X::foo_self; + | ^^^^^^^^ + +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:60:27 | -note: function `test_2::foo_self` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:52:5 +LL | reuse X::::foo as foo1; + | ^^^ + +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-ambig.rs:63:28 | -LL | reuse X::foo_self; - | ^^^^^^^^^^^^^^^^^^ not accessible +LL | reuse X::::foo_self as foo_self1; + | ^^^^^^^^ -error[E0425]: cannot find function `foo` in `X` - --> $DIR/inherent-impls-ambig.rs:49:14 +error[E0034]: multiple applicable items in scope + --> $DIR/inherent-impls-ambig.rs:16:14 | LL | reuse X::foo; - | ^^^ not found in `X` + | ^^^ multiple `foo` found | -note: function `test_1::foo` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:16:5 +note: candidate #1 is defined in an impl for the type `test_1::X<()>` + --> $DIR/inherent-impls-ambig.rs:7:9 | -LL | reuse X::foo; - | ^^^^^^^^^^^^^ not accessible +LL | fn foo() {} + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `test_1::X` + --> $DIR/inherent-impls-ambig.rs:12:9 + | +LL | fn foo() {} + | ^^^^^^^^ -error[E0425]: cannot find function `foo_self` in `X` - --> $DIR/inherent-impls-ambig.rs:52:14 +error[E0034]: multiple applicable items in scope + --> $DIR/inherent-impls-ambig.rs:20:14 | LL | reuse X::foo_self; - | ^^^^^^^^ not found in `X` + | ^^^^^^^^ multiple `foo_self` found | -note: function `test_1::foo_self` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:19:5 +note: candidate #1 is defined in an impl for the type `test_1::X<()>` + --> $DIR/inherent-impls-ambig.rs:8:9 | -LL | reuse X::foo_self; - | ^^^^^^^^^^^^^^^^^^ not accessible +LL | fn foo_self(self) {} + | ^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `test_1::X` + --> $DIR/inherent-impls-ambig.rs:13:9 + | +LL | fn foo_self(self) {} + | ^^^^^^^^^^^^^^^^^ -error[E0425]: cannot find function `foo` in `X` - --> $DIR/inherent-impls-ambig.rs:55:27 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-ambig.rs:27:23 | -LL | reuse X::::foo as foo1; - | ^^^ not found in `X` +LL | reuse X::::foo_self as foo_self1; + | ^^^^^^^^ argument #1 of type `test_1::X` is missing | -note: function `test_1::foo` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:16:5 +note: method defined here + --> $DIR/inherent-impls-ambig.rs:13:12 | -LL | reuse X::foo; - | ^^^^^^^^^^^^^ not accessible +LL | fn foo_self(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse X::::foo_self(/* X */) as foo_self1; + | ++++++++++++++++ -error[E0425]: cannot find function `foo_self` in `X` - --> $DIR/inherent-impls-ambig.rs:58:28 +error[E0034]: multiple applicable items in scope + --> $DIR/inherent-impls-ambig.rs:52:14 | -LL | reuse X::::foo_self as foo_self1; - | ^^^^^^^^ not found in `X` +LL | reuse X::foo; + | ^^^ multiple `foo` found | -note: function `test_1::foo_self` exists but is inaccessible - --> $DIR/inherent-impls-ambig.rs:19:5 +note: candidate #1 is defined in an impl for the type `test_2::X` + --> $DIR/inherent-impls-ambig.rs:43:9 + | +LL | fn foo() {} + | ^^^^^^^^ +note: candidate #2 is defined in an impl for the type `test_2::X` + --> $DIR/inherent-impls-ambig.rs:38:9 + | +LL | fn foo() {} + | ^^^^^^^^ + +error[E0034]: multiple applicable items in scope + --> $DIR/inherent-impls-ambig.rs:56:14 | LL | reuse X::foo_self; - | ^^^^^^^^^^^^^^^^^^ not accessible + | ^^^^^^^^ multiple `foo_self` found + | +note: candidate #1 is defined in an impl for the type `test_2::X` + --> $DIR/inherent-impls-ambig.rs:44:9 + | +LL | fn foo_self(self) {} + | ^^^^^^^^^^^^^^^^^ +note: candidate #2 is defined in an impl for the type `test_2::X` + --> $DIR/inherent-impls-ambig.rs:39:9 + | +LL | fn foo_self(self) {} + | ^^^^^^^^^^^^^^^^^ + +error[E0599]: no associated function or constant named `foo_self` found for struct `test_2::X` in the current scope + --> $DIR/inherent-impls-ambig.rs:63:28 + | +LL | struct X(T, U); + | -------------- associated function or constant `foo_self` not found for this struct +... +LL | reuse X::::foo_self as foo_self1; + | ^^^^^^^^ associated function or constant not found in `test_2::X` -error: aborting due to 8 previous errors +error: aborting due to 14 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0034, E0061, E0599. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/delegation/inherent-impls-enums.rs b/tests/ui/delegation/inherent-impls-enums.rs index 301cbe32b6f88..e8c7ba891b5ef 100644 --- a/tests/ui/delegation/inherent-impls-enums.rs +++ b/tests/ui/delegation/inherent-impls-enums.rs @@ -11,80 +11,58 @@ impl<'a, 'b, 'c, A: 'a, const C: usize> S<'a, A, C> { } reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; -//~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static as foo_static_3; -//~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; -//~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1; -//~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self as foo_self_3; -//~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; -//~^ ERROR: cannot find function `foo_self` in enum `S` trait Trait<'a, AA, BB> where Self: Sized, { reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in enum `S` fn get_s(self) -> S<'static, (), 1> { panic!(); } reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in enum `S` + //~^ ERROR: mismatched types [E0308] } struct X; impl<'a, A, B> Trait<'a, A, B> for X { reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in enum `S` + //~^ ERROR: type annotations needed [E0284] reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` - //~| ERROR: delegation's target expression is specified for function with no params reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` - //~| ERROR: delegation's target expression is specified for function with no params reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in enum `S` + //~^ ERROR: mismatched types [E0308] } impl X { reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in enum `S` reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in enum `S` fn get_s(self) -> S<'static, (), 1> { panic!(); } reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in enum `S` reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in enum `S` + //~^ ERROR: mismatched types [E0308] } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-enums.stderr b/tests/ui/delegation/inherent-impls-enums.stderr index 0016488386017..d76aba9517ee4 100644 --- a/tests/ui/delegation/inherent-impls-enums.stderr +++ b/tests/ui/delegation/inherent-impls-enums.stderr @@ -1,159 +1,70 @@ -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:13:28 - | -LL | reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:15:28 - | -LL | reuse S::<'static, (), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:17:28 - | -LL | reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:20:28 - | -LL | reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:22:28 - | -LL | reuse S::<'static, (), 1>::foo_self as foo_self_3; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:24:28 - | -LL | reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:31:32 - | -LL | reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:33:32 - | -LL | reuse S::<'static, (), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` +error[E0308]: mismatched types --> $DIR/inherent-impls-enums.rs:35:32 | -LL | reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:42:32 - | -LL | reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:44:32 - | -LL | reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:46:32 - | +LL | trait Trait<'a, AA, BB> + | ----------------------- found this type parameter +... LL | reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:53:32 + | ^^^^^^^^ + | | + | expected `S<'_, (), 1>`, found type parameter `Self` + | arguments to this function are incorrect | -LL | reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:55:32 + = note: expected enum `S<'_, (), 1>` + found type parameter `Self` +note: method defined here + --> $DIR/inherent-impls-enums.rs:10:8 | -LL | reuse S::<'static, (), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:57:32 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-enums.rs:44:32 | LL | reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:60:32 + | ^^^^^^^^^^ cannot infer the value of const parameter `B` declared on the associated function `foo_static` | -LL | reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:63:32 +note: required by a const generic parameter in `S::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-enums.rs:9:34 | -LL | reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `S::<'a, A, C>::foo_static` -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:66:32 +error[E0308]: mismatched types + --> $DIR/inherent-impls-enums.rs:49:32 | LL | reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:71:32 + | ^^^^^^^^ + | | + | expected `S<'_, (), 1>`, found `X` + | arguments to this function are incorrect | -LL | reuse S::<'static, (), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:73:32 - | -LL | reuse S::<'static, (), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in enum `S` - --> $DIR/inherent-impls-enums.rs:75:32 - | -LL | reuse S::<'static, (), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:82:32 - | -LL | reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:84:32 + = note: expected enum `S<'_, (), 1>` + found struct `X` +note: method defined here + --> $DIR/inherent-impls-enums.rs:10:8 | -LL | reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error[E0425]: cannot find function `foo_self` in enum `S` - --> $DIR/inherent-impls-enums.rs:86:32 +error[E0308]: mismatched types + --> $DIR/inherent-impls-enums.rs:64:32 | LL | reuse S::<'static, (), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-enums.rs:60:76 + | ^^^^^^^^ + | | + | expected `S<'_, (), 1>`, found `X` + | arguments to this function are incorrect | -LL | reuse S::<'static, (), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^^^^^^^^^ - -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-enums.rs:63:55 + = note: expected enum `S<'_, (), 1>` + found struct `X` +note: method defined here + --> $DIR/inherent-impls-enums.rs:10:8 | -LL | reuse S::<'static, (), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^^^^^^^^^ +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error: aborting due to 26 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0284, E0308. +For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/delegation/inherent-impls-glob-list.rs b/tests/ui/delegation/inherent-impls-glob-list.rs index 51d24e6838df0..d983711102dde 100644 --- a/tests/ui/delegation/inherent-impls-glob-list.rs +++ b/tests/ui/delegation/inherent-impls-glob-list.rs @@ -11,8 +11,6 @@ struct Y; impl Y { reuse X::{foo, foo2} { X } - //~^ ERROR: cannot find function `foo` in `X` - //~| ERROR: cannot find function `foo2` in `X` } impl Y { diff --git a/tests/ui/delegation/inherent-impls-glob-list.stderr b/tests/ui/delegation/inherent-impls-glob-list.stderr index d2dfce86f860a..7972e598e1853 100644 --- a/tests/ui/delegation/inherent-impls-glob-list.stderr +++ b/tests/ui/delegation/inherent-impls-glob-list.stderr @@ -1,21 +1,8 @@ error: expected trait, found struct `X` - --> $DIR/inherent-impls-glob-list.rs:19:11 + --> $DIR/inherent-impls-glob-list.rs:17:11 | LL | reuse X::*; | ^ not a trait -error[E0425]: cannot find function `foo` in `X` - --> $DIR/inherent-impls-glob-list.rs:13:15 - | -LL | reuse X::{foo, foo2} { X } - | ^^^ not found in `X` - -error[E0425]: cannot find function `foo2` in `X` - --> $DIR/inherent-impls-glob-list.rs:13:20 - | -LL | reuse X::{foo, foo2} { X } - | ^^^^ not found in `X` - -error: aborting due to 3 previous errors +error: aborting due to 1 previous error -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/inherent-impls-mixed-generics.rs b/tests/ui/delegation/inherent-impls-mixed-generics.rs index 027dcace3ab0d..b24acff6187eb 100644 --- a/tests/ui/delegation/inherent-impls-mixed-generics.rs +++ b/tests/ui/delegation/inherent-impls-mixed-generics.rs @@ -10,7 +10,8 @@ impl<'a, 'b, 'c, A, const C: usize> S<'static, A, usize, C> { trait Trait<'a, AA, BB> where Self: Sized { reuse S::foo_self; - //~^ ERROR: cannot find function `foo_self` in `S` + //~^ ERROR: delegation to inherent impl must contain parent generics + //~| ERROR: this function takes 1 argument but 0 arguments were supplied } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-mixed-generics.stderr b/tests/ui/delegation/inherent-impls-mixed-generics.stderr index f515b52ca45ab..f730d5360eef7 100644 --- a/tests/ui/delegation/inherent-impls-mixed-generics.stderr +++ b/tests/ui/delegation/inherent-impls-mixed-generics.stderr @@ -1,9 +1,25 @@ -error[E0425]: cannot find function `foo_self` in `S` +error: delegation to inherent impl must contain parent generics --> $DIR/inherent-impls-mixed-generics.rs:12:14 | LL | reuse S::foo_self; - | ^^^^^^^^ not found in `S` + | ^^^^^^^^ -error: aborting due to 1 previous error +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-mixed-generics.rs:12:14 + | +LL | reuse S::foo_self; + | ^^^^^^^^ argument #1 of type `S<'static, _, usize, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-mixed-generics.rs:8:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse S::foo_self(/* value */); + | +++++++++++++ + +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/inherent-impls-non-local-crate.rs b/tests/ui/delegation/inherent-impls-non-local-crate.rs index c2f07fd8e7ae7..27b8d387a7e63 100644 --- a/tests/ui/delegation/inherent-impls-non-local-crate.rs +++ b/tests/ui/delegation/inherent-impls-non-local-crate.rs @@ -3,23 +3,21 @@ #![feature(fn_delegation)] reuse inherent_impl::S::foo; -//~^ ERROR: cannot find function `foo` in `inherent_impl::S` reuse inherent_impl::S::not_existing; -//~^ ERROR: cannot find function `not_existing` in `inherent_impl::S` - +//~^ ERROR: no associated function or constant named `not_existing` found for struct `S` in the current scope reuse inherent_impl::S::TYPE; -//~^ ERROR: cannot find function `TYPE` in `inherent_impl::S` - +//~^ ERROR: no associated function or constant named `TYPE` found for struct `S` in the current scope reuse inherent_impl::S::CONST; -//~^ ERROR: cannot find function `CONST` in `inherent_impl::S` +//~^ ERROR: expected function, found `usize` [E0618] reuse inherent_impl::S::bar; -//~^ ERROR: cannot find function `bar` in `inherent_impl::S` +//~^ ERROR: no associated function or constant named `bar` found for struct `S` in the current scope reuse ::bar as trait_bar; reuse inherent_impl::X::foo as x_foo; -//~^ ERROR: cannot find function `foo` in `inherent_impl::X` +//~^ ERROR: ambiguous delegation to inherent impl function +//~| ERROR: multiple applicable items in scope fn main() {} diff --git a/tests/ui/delegation/inherent-impls-non-local-crate.stderr b/tests/ui/delegation/inherent-impls-non-local-crate.stderr index 983c8b8f3cb9b..31358b1d7144e 100644 --- a/tests/ui/delegation/inherent-impls-non-local-crate.stderr +++ b/tests/ui/delegation/inherent-impls-non-local-crate.stderr @@ -1,39 +1,49 @@ -error[E0425]: cannot find function `foo` in `inherent_impl::S` - --> $DIR/inherent-impls-non-local-crate.rs:5:25 +error: ambiguous delegation to inherent impl function + --> $DIR/inherent-impls-non-local-crate.rs:19:25 | -LL | reuse inherent_impl::S::foo; - | ^^^ not found in `inherent_impl::S` +LL | reuse inherent_impl::X::foo as x_foo; + | ^^^ -error[E0425]: cannot find function `not_existing` in `inherent_impl::S` - --> $DIR/inherent-impls-non-local-crate.rs:8:25 +error[E0599]: no associated function or constant named `not_existing` found for struct `S` in the current scope + --> $DIR/inherent-impls-non-local-crate.rs:7:25 | LL | reuse inherent_impl::S::not_existing; - | ^^^^^^^^^^^^ not found in `inherent_impl::S` + | ^^^^^^^^^^^^ associated function or constant not found in `S` -error[E0425]: cannot find function `TYPE` in `inherent_impl::S` - --> $DIR/inherent-impls-non-local-crate.rs:11:25 +error[E0599]: no associated function or constant named `TYPE` found for struct `S` in the current scope + --> $DIR/inherent-impls-non-local-crate.rs:9:25 | LL | reuse inherent_impl::S::TYPE; - | ^^^^ not found in `inherent_impl::S` + | ^^^^ associated function or constant not found in `S` -error[E0425]: cannot find function `CONST` in `inherent_impl::S` - --> $DIR/inherent-impls-non-local-crate.rs:14:25 +error[E0618]: expected function, found `usize` + --> $DIR/inherent-impls-non-local-crate.rs:11:25 | LL | reuse inherent_impl::S::CONST; - | ^^^^^ not found in `inherent_impl::S` + | ^^^^^ call expression requires function -error[E0425]: cannot find function `bar` in `inherent_impl::S` - --> $DIR/inherent-impls-non-local-crate.rs:17:25 +error[E0599]: no associated function or constant named `bar` found for struct `S` in the current scope + --> $DIR/inherent-impls-non-local-crate.rs:14:25 | LL | reuse inherent_impl::S::bar; - | ^^^ not found in `inherent_impl::S` + | ^^^ associated function or constant not found in `S` + | + = help: items from traits can only be used if the trait is in scope +help: trait `Trait` which provides `bar` is implemented but not in scope; perhaps you want to import it + | +LL + use inherent_impl::Trait; + | -error[E0425]: cannot find function `foo` in `inherent_impl::X` - --> $DIR/inherent-impls-non-local-crate.rs:22:25 +error[E0034]: multiple applicable items in scope + --> $DIR/inherent-impls-non-local-crate.rs:19:25 | LL | reuse inherent_impl::X::foo as x_foo; - | ^^^ not found in `inherent_impl::X` + | ^^^ multiple `foo` found + | + = note: candidate #1 is defined in an impl for the type `X` + = note: candidate #2 is defined in an impl for the type `X` error: aborting due to 6 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0034, E0599, E0618. +For more information about an error, try `rustc --explain E0034`. diff --git a/tests/ui/delegation/inherent-impls-parent-generics.rs b/tests/ui/delegation/inherent-impls-parent-generics.rs index 0f95540643bd7..1c303e16a0272 100644 --- a/tests/ui/delegation/inherent-impls-parent-generics.rs +++ b/tests/ui/delegation/inherent-impls-parent-generics.rs @@ -12,32 +12,36 @@ impl<'a, 'b, 'c, A: 'a, const C: usize> E<'a, A, C> { } reuse E::foo_static as e; -//~^ ERROR: cannot find function `foo_static` in enum `E` - +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse E::foo_self as e1; -//~^ ERROR: cannot find function `foo_self` in enum `E` +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: this function takes 1 argument but 0 arguments were supplied reuse E::foo_static::<'static, (), true> as e2; -//~^ ERROR: cannot find function `foo_static` in enum `E` - +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse E::foo_self::<'static, (), true> as e3; -//~^ ERROR: cannot find function `foo_self` in enum `E` +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: this function takes 1 argument but 0 arguments were supplied reuse E::<'static, (), 123>::foo_static as e4; -//~^ ERROR: cannot find function `foo_static` in enum `E` reuse E::<'static, (), 123>::foo_self as e5; -//~^ ERROR: cannot find function `foo_self` in enum `E` reuse E::<'static, (), 123>::foo_static::<'static, (), true> as e6; -//~^ ERROR: cannot find function `foo_static` in enum `E` reuse E::<'static, (), 123>::foo_self::<'static, (), true> as e7; -//~^ ERROR: cannot find function `foo_self` in enum `E` reuse E::<'_, (), _>::foo_static as e8; -//~^ ERROR: cannot find function `foo_static` in enum `E` - +//~^ ERROR: parent segment of delegation to inherent impl can not contain infers +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse E::<'_, _, _>::foo_self as e9; -//~^ ERROR: cannot find function `foo_self` in enum `E` +//~^ ERROR: parent segment of delegation to inherent impl can not contain infers +//~| ERROR: this function takes 1 argument but 0 arguments were supplied struct S { xd: [A; C], @@ -49,32 +53,35 @@ impl<'a, 'b, 'c, A, const C: usize> S { } reuse S::foo_static as s; -//~^ ERROR: cannot find function `foo_static` in `S` - +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse S::foo_self as s1; -//~^ ERROR: cannot find function `foo_self` in `S` +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: this function takes 1 argument but 0 arguments were supplied reuse S::foo_static::<'static, (), true> as s2; -//~^ ERROR: cannot find function `foo_static` in `S` - +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse S::foo_self::<'static, (), true> as s3; -//~^ ERROR: cannot find function `foo_self` in `S` +//~^ ERROR: delegation to inherent impl must contain parent generics +//~| ERROR: this function takes 1 argument but 0 arguments were supplied reuse S::<(), 123>::foo_static as s4; -//~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 123>::foo_self as s5; -//~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 123>::foo_static::<'static, (), true> as s6; -//~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 123>::foo_self::<'static, (), true> as s7; -//~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), _>::foo_static as s8; -//~^ ERROR: cannot find function `foo_static` in `S` - +//~^ ERROR: parent segment of delegation to inherent impl can not contain infers +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed +//~| ERROR: type annotations needed reuse S::<_, 123>::foo_self as s9; -//~^ ERROR: cannot find function `foo_self` in `S` - +//~^ ERROR: parent segment of delegation to inherent impl can not contain infers +//~| ERROR: this function takes 1 argument but 0 arguments were supplied fn main() {} diff --git a/tests/ui/delegation/inherent-impls-parent-generics.stderr b/tests/ui/delegation/inherent-impls-parent-generics.stderr index 508ca65316457..b1001e193a9cd 100644 --- a/tests/ui/delegation/inherent-impls-parent-generics.stderr +++ b/tests/ui/delegation/inherent-impls-parent-generics.stderr @@ -1,123 +1,440 @@ -error[E0425]: cannot find function `foo_static` in enum `E` +error: delegation to inherent impl must contain parent generics --> $DIR/inherent-impls-parent-generics.rs:14:10 | LL | reuse E::foo_static as e; - | ^^^^^^^^^^ not found in `E` + | ^^^^^^^^^^ -error[E0425]: cannot find function `foo_self` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:17:10 +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:19:10 | LL | reuse E::foo_self as e1; - | ^^^^^^^^ not found in `E` + | ^^^^^^^^ -error[E0425]: cannot find function `foo_static` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:20:10 +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:23:10 | LL | reuse E::foo_static::<'static, (), true> as e2; - | ^^^^^^^^^^ not found in `E` + | ^^^^^^^^^^ -error[E0425]: cannot find function `foo_self` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:23:10 +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:27:10 | LL | reuse E::foo_self::<'static, (), true> as e3; - | ^^^^^^^^ not found in `E` + | ^^^^^^^^ + +error: parent segment of delegation to inherent impl can not contain infers + --> $DIR/inherent-impls-parent-generics.rs:37:23 + | +LL | reuse E::<'_, (), _>::foo_static as e8; + | ^^^^^^^^^^ -error[E0425]: cannot find function `foo_static` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:26:30 +error: parent segment of delegation to inherent impl can not contain infers + --> $DIR/inherent-impls-parent-generics.rs:42:22 + | +LL | reuse E::<'_, _, _>::foo_self as e9; + | ^^^^^^^^ + +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:55:10 + | +LL | reuse S::foo_static as s; + | ^^^^^^^^^^ + +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:60:10 + | +LL | reuse S::foo_self as s1; + | ^^^^^^^^ + +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:64:10 + | +LL | reuse S::foo_static::<'static, (), true> as s2; + | ^^^^^^^^^^ + +error: delegation to inherent impl must contain parent generics + --> $DIR/inherent-impls-parent-generics.rs:68:10 + | +LL | reuse S::foo_self::<'static, (), true> as s3; + | ^^^^^^^^ + +error: parent segment of delegation to inherent impl can not contain infers + --> $DIR/inherent-impls-parent-generics.rs:78:19 + | +LL | reuse S::<(), _>::foo_static as s8; + | ^^^^^^^^^^ + +error: parent segment of delegation to inherent impl can not contain infers + --> $DIR/inherent-impls-parent-generics.rs:83:20 + | +LL | reuse S::<_, 123>::foo_self as s9; + | ^^^^^^^^ + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:14:10 + | +LL | reuse E::foo_static as e; + | - ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | | + | type must be known at this point + | +note: required by a const generic parameter in `E` + --> $DIR/inherent-impls-parent-generics.rs:4:23 + | +LL | enum E<'a: 'a, A: 'a, const C: usize> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E` +help: consider specifying the generic arguments + | +LL - reuse E::foo_static as e; +LL + reuse E:: as e; + | + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:14:10 + | +LL | reuse E::foo_static as e; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | +note: required by a const generic parameter in `E::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:9:25 + | +LL | impl<'a, 'b, 'c, A: 'a, const C: usize> E<'a, A, C> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E::<'a, A, C>::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function +help: consider specifying the generic arguments + | +LL - reuse E::foo_static as e; +LL + reuse E:: as e; + | + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:14:10 + | +LL | reuse E::foo_static as e; + | ^^^^^^^^^^ cannot infer the value of the const parameter `B` declared on the associated function `foo_static` + | +note: required by a const generic parameter in `E::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:10:34 + | +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `E::<'a, A, C>::foo_static` +help: consider specifying the generic arguments + | +LL | reuse E::foo_static:: as e; + | ++++++++ + +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-parent-generics.rs:19:10 + | +LL | reuse E::foo_self as e1; + | ^^^^^^^^ argument #1 of type `E<'_, _, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:11:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse E::foo_self(/* value */) as e1; + | +++++++++++++ + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:23:10 + | +LL | reuse E::foo_static::<'static, (), true> as e2; + | - ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | | + | type must be known at this point + | +note: required by a const generic parameter in `E` + --> $DIR/inherent-impls-parent-generics.rs:4:23 + | +LL | enum E<'a: 'a, A: 'a, const C: usize> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E` +help: consider specifying the generic arguments + | +LL - reuse E::foo_static::<'static, (), true> as e2; +LL + reuse E:: as e2; + | + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:23:10 + | +LL | reuse E::foo_static::<'static, (), true> as e2; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | +note: required by a const generic parameter in `E::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:9:25 + | +LL | impl<'a, 'b, 'c, A: 'a, const C: usize> E<'a, A, C> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E::<'a, A, C>::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function +help: consider specifying the generic arguments + | +LL - reuse E::foo_static::<'static, (), true> as e2; +LL + reuse E:: as e2; | -LL | reuse E::<'static, (), 123>::foo_static as e4; - | ^^^^^^^^^^ not found in `E` -error[E0425]: cannot find function `foo_self` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:28:30 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-parent-generics.rs:27:10 + | +LL | reuse E::foo_self::<'static, (), true> as e3; + | ^^^^^^^^ argument #1 of type `E<'_, _, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:11:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument | -LL | reuse E::<'static, (), 123>::foo_self as e5; - | ^^^^^^^^ not found in `E` +LL | reuse E::foo_self(/* value */)::<'static, (), true> as e3; + | +++++++++++++ -error[E0425]: cannot find function `foo_static` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:31:30 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:37:23 | -LL | reuse E::<'static, (), 123>::foo_static::<'static, (), true> as e6; - | ^^^^^^^^^^ not found in `E` +LL | reuse E::<'_, (), _>::foo_static as e8; + | -------------- ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | | + | type must be known at this point + | +note: required by a const generic parameter in `E` + --> $DIR/inherent-impls-parent-generics.rs:4:23 + | +LL | enum E<'a: 'a, A: 'a, const C: usize> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E` -error[E0425]: cannot find function `foo_self` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:33:30 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:37:23 + | +LL | reuse E::<'_, (), _>::foo_static as e8; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the enum `E` + | +note: required by a const generic parameter in `E::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:9:25 | -LL | reuse E::<'static, (), 123>::foo_self::<'static, (), true> as e7; - | ^^^^^^^^ not found in `E` +LL | impl<'a, 'b, 'c, A: 'a, const C: usize> E<'a, A, C> { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `E::<'a, A, C>::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function -error[E0425]: cannot find function `foo_static` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:36:23 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:37:23 | LL | reuse E::<'_, (), _>::foo_static as e8; - | ^^^^^^^^^^ not found in `E` + | ^^^^^^^^^^ cannot infer the value of the const parameter `B` declared on the associated function `foo_static` + | +note: required by a const generic parameter in `E::<'a, A, C>::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:10:34 + | +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `E::<'a, A, C>::foo_static` +help: consider specifying the generic arguments + | +LL | reuse E::<'_, (), _>::foo_static:: as e8; + | ++++++++ -error[E0425]: cannot find function `foo_self` in enum `E` - --> $DIR/inherent-impls-parent-generics.rs:39:22 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-parent-generics.rs:42:22 | LL | reuse E::<'_, _, _>::foo_self as e9; - | ^^^^^^^^ not found in `E` + | ^^^^^^^^ argument #1 of type `E<'_, _, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:11:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse E::<'_, _, _>::foo_self(/* value */) as e9; + | +++++++++++++ -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-parent-generics.rs:51:10 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:55:10 | LL | reuse S::foo_static as s; - | ^^^^^^^^^^ not found in `S` + | - ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | | + | type must be known at this point + | +note: required by a const generic parameter in `S` + --> $DIR/inherent-impls-parent-generics.rs:46:13 + | +LL | struct S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S` +help: consider specifying the generic arguments + | +LL | reuse S::::foo_static as s; + | ++++++++ -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-parent-generics.rs:54:10 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:55:10 | -LL | reuse S::foo_self as s1; - | ^^^^^^^^ not found in `S` +LL | reuse S::foo_static as s; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:50:21 + | +LL | impl<'a, 'b, 'c, A, const C: usize> S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function +help: consider specifying the generic arguments + | +LL | reuse S::::foo_static as s; + | ++++++++ -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-parent-generics.rs:57:10 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:55:10 | -LL | reuse S::foo_static::<'static, (), true> as s2; - | ^^^^^^^^^^ not found in `S` +LL | reuse S::foo_static as s; + | ^^^^^^^^^^ cannot infer the value of the const parameter `B` declared on the associated function `foo_static` + | +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:51:34 + | +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` +help: consider specifying the generic arguments + | +LL | reuse S::foo_static:: as s; + | ++++++++ -error[E0425]: cannot find function `foo_self` in `S` +error[E0061]: this function takes 1 argument but 0 arguments were supplied --> $DIR/inherent-impls-parent-generics.rs:60:10 | -LL | reuse S::foo_self::<'static, (), true> as s3; - | ^^^^^^^^ not found in `S` +LL | reuse S::foo_self as s1; + | ^^^^^^^^ argument #1 of type `S<_, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:52:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse S::foo_self(/* value */) as s1; + | +++++++++++++ + +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:64:10 + | +LL | reuse S::foo_static::<'static, (), true> as s2; + | - ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | | + | type must be known at this point + | +note: required by a const generic parameter in `S` + --> $DIR/inherent-impls-parent-generics.rs:46:13 + | +LL | struct S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S` +help: consider specifying the generic arguments + | +LL | reuse S::::foo_static::<'static, (), true> as s2; + | ++++++++ -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-parent-generics.rs:63:21 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:64:10 + | +LL | reuse S::foo_static::<'static, (), true> as s2; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:50:21 + | +LL | impl<'a, 'b, 'c, A, const C: usize> S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function +help: consider specifying the generic arguments | -LL | reuse S::<(), 123>::foo_static as s4; - | ^^^^^^^^^^ not found in `S` +LL | reuse S::::foo_static::<'static, (), true> as s2; + | ++++++++ -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-parent-generics.rs:65:21 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-parent-generics.rs:68:10 | -LL | reuse S::<(), 123>::foo_self as s5; - | ^^^^^^^^ not found in `S` +LL | reuse S::foo_self::<'static, (), true> as s3; + | ^^^^^^^^ argument #1 of type `S<_, _>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:52:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse S::foo_self(/* value */)::<'static, (), true> as s3; + | +++++++++++++ -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-parent-generics.rs:68:21 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:78:19 | -LL | reuse S::<(), 123>::foo_static::<'static, (), true> as s6; - | ^^^^^^^^^^ not found in `S` +LL | reuse S::<(), _>::foo_static as s8; + | ---------- ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | | + | type must be known at this point + | +note: required by a const generic parameter in `S` + --> $DIR/inherent-impls-parent-generics.rs:46:13 + | +LL | struct S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S` -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-parent-generics.rs:70:21 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:78:19 + | +LL | reuse S::<(), _>::foo_static as s8; + | ^^^^^^^^^^ cannot infer the value of the const parameter `C` declared on the struct `S` + | +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:50:21 | -LL | reuse S::<(), 123>::foo_self::<'static, (), true> as s7; - | ^^^^^^^^ not found in `S` +LL | impl<'a, 'b, 'c, A, const C: usize> S { + | ^^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ---------- required by a bound in this associated function -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-parent-generics.rs:73:19 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-parent-generics.rs:78:19 | LL | reuse S::<(), _>::foo_static as s8; - | ^^^^^^^^^^ not found in `S` + | ^^^^^^^^^^ cannot infer the value of the const parameter `B` declared on the associated function `foo_static` + | +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-parent-generics.rs:51:34 + | +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` +help: consider specifying the generic arguments + | +LL | reuse S::<(), _>::foo_static:: as s8; + | ++++++++ -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-parent-generics.rs:76:20 +error[E0061]: this function takes 1 argument but 0 arguments were supplied + --> $DIR/inherent-impls-parent-generics.rs:83:20 | LL | reuse S::<_, 123>::foo_self as s9; - | ^^^^^^^^ not found in `S` + | ^^^^^^^^ argument #1 of type `S<_, 123>` is missing + | +note: method defined here + --> $DIR/inherent-impls-parent-generics.rs:52:8 + | +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- +help: provide the argument + | +LL | reuse S::<_, 123>::foo_self(/* value */) as s9; + | +++++++++++++ -error: aborting due to 20 previous errors +error: aborting due to 34 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0061, E0284. +For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/inherent-impls-receiver-mapping.rs b/tests/ui/delegation/inherent-impls-receiver-mapping.rs index 05a9c350af746..d4678134e5de1 100644 --- a/tests/ui/delegation/inherent-impls-receiver-mapping.rs +++ b/tests/ui/delegation/inherent-impls-receiver-mapping.rs @@ -15,36 +15,27 @@ mod receiver_mapping { impl Y { fn get_x(&self) -> X { X } reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - //~^ ERROR: cannot find function `by_mut_ref` in `X` - //~| ERROR: cannot find function `by_ref` in `X` - //~| ERROR: cannot find function `by_value` in `X` - //~| ERROR: cannot find function `static_f` in `X` } fn check() { let y = Y; y.by_ref(); - //~^ ERROR: no method named `by_ref` found for struct `Y` in the current scope y.by_mut_ref(); - //~^ ERROR: no method named `by_mut_ref` found for struct `Y` in the current scope + //~^ ERROR: cannot borrow `y` as mutable, as it is not declared as mutable y.by_value(); - //~^ ERROR: no method named `by_value` found for struct `Y` in the current scope let y = &Y; y.by_value(); - //~^ ERROR: no method named `by_value` found for reference `&Y` in the current scope + //~^ ERROR: cannot move out of `*y` which is behind a shared reference y.by_ref(); - //~^ ERROR: no method named `by_ref` found for reference `&Y` in the current scope y.by_mut_ref(); - //~^ ERROR: no method named `by_mut_ref` found for reference `&Y` in the current scope + //~^ ERROR: cannot borrow `*y` as mutable, as it is behind a `&` reference let y = &mut Y; y.by_value(); - //~^ ERROR: no method named `by_value` found for mutable reference `&mut Y` in the current scope + //~^ ERROR: cannot move out of `*y` which is behind a mutable reference y.by_ref(); - //~^ ERROR: the method `by_ref` exists for mutable reference `&mut Y`, but its trait bounds were not satisfied y.by_mut_ref(); - //~^ ERROR: no method named `by_mut_ref` found for mutable reference `&mut Y` in the current scope } } @@ -59,12 +50,12 @@ mod self_type_mapping { struct W(X); impl W { reuse X::add { self.0 } - //~^ ERROR: cannot find function `add` in `X` + //~^ ERROR: mismatched types + //~| ERROR: mismatched types } fn check() { W(X).add(W(X)); - //~^ ERROR: no method named `add` found for struct `W` in the current scope } } diff --git a/tests/ui/delegation/inherent-impls-receiver-mapping.stderr b/tests/ui/delegation/inherent-impls-receiver-mapping.stderr index 92baa5ff53ed0..60982076f4acd 100644 --- a/tests/ui/delegation/inherent-impls-receiver-mapping.stderr +++ b/tests/ui/delegation/inherent-impls-receiver-mapping.stderr @@ -1,256 +1,90 @@ -error[E0425]: cannot find function `static_f` in `X` - --> $DIR/inherent-impls-receiver-mapping.rs:17:19 +error[E0308]: mismatched types + --> $DIR/inherent-impls-receiver-mapping.rs:52:18 | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^ not found in `X` - -error[E0425]: cannot find function `by_value` in `X` - --> $DIR/inherent-impls-receiver-mapping.rs:17:29 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^ not found in `X` - -error[E0425]: cannot find function `by_ref` in `X` - --> $DIR/inherent-impls-receiver-mapping.rs:17:39 +LL | reuse X::add { self.0 } + | ^^^ + | | + | expected `X`, found `W` + | arguments to this function are incorrect | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^ not found in `X` - -error[E0425]: cannot find function `by_mut_ref` in `X` - --> $DIR/inherent-impls-receiver-mapping.rs:17:47 +note: method defined here + --> $DIR/inherent-impls-receiver-mapping.rs:45:12 | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^^^ not found in `X` +LL | fn add(self, other: Self) -> Self { + | ^^^ ----------- -error[E0425]: cannot find function `add` in `X` - --> $DIR/inherent-impls-receiver-mapping.rs:61:18 +error[E0308]: mismatched types + --> $DIR/inherent-impls-receiver-mapping.rs:52:18 | LL | reuse X::add { self.0 } - | ^^^ not found in `X` - -error[E0599]: no method named `by_ref` found for struct `Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:26:11 - | -LL | struct Y; - | -------- method `by_ref` not found for this struct -... -LL | y.by_ref(); - | ^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:39 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^ - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `by_ref`, perhaps you need to implement one of them: - candidate #1: `Iterator` - candidate #2: `std::io::Read` - candidate #3: `std::io::Write` -help: use associated function syntax instead + | ^^^ + | | + | expected `W`, found `X` + | expected `W` because of return type | -LL - y.by_ref(); -LL + Y::by_ref(); +help: try wrapping the expression in `self_type_mapping::W` | +LL | reuse X::self_type_mapping::W(add) { self.0 } + | +++++++++++++++++++++ + -error[E0599]: no method named `by_mut_ref` found for struct `Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:28:11 +error[E0596]: cannot borrow `y` as mutable, as it is not declared as mutable + --> $DIR/inherent-impls-receiver-mapping.rs:23:9 | -LL | struct Y; - | -------- method `by_mut_ref` not found for this struct -... LL | y.by_mut_ref(); - | ^^^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:47 + | ^ cannot borrow as mutable | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_mut_ref(); -LL + Y::by_mut_ref(); +help: consider changing this to be mutable | +LL | let mut y = Y; + | +++ -error[E0599]: no method named `by_value` found for struct `Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:30:11 +error[E0507]: cannot move out of `*y` which is behind a shared reference + --> $DIR/inherent-impls-receiver-mapping.rs:28:9 | -LL | struct Y; - | -------- method `by_value` not found for this struct -... LL | y.by_value(); - | ^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:29 + | ^ ---------- `*y` moved due to this method call + | | + | move occurs because `*y` has type `Y`, which does not implement the `Copy` trait | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_value(); -LL + Y::by_value(); - | - -error[E0599]: no method named `by_value` found for reference `&Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:34:11 + = note: `receiver_mapping::Y::by_value` takes ownership of the receiver `self`, which moves `*y` +note: if `Y` implemented `Clone`, you could clone the value + --> $DIR/inherent-impls-receiver-mapping.rs:13:5 | +LL | struct Y; + | ^^^^^^^^ consider implementing `Clone` for this type +... LL | y.by_value(); - | ^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:29 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_value(); -LL + Y::by_value(); - | + | - you could clone this value -error[E0599]: no method named `by_ref` found for reference `&Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:36:11 - | -LL | y.by_ref(); - | ^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:39 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^ - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `by_ref`, perhaps you need to implement one of them: - candidate #1: `std::io::Read` - candidate #2: `std::io::Write` - = note: the trait `Iterator` defines an item `by_ref`, but is explicitly unimplemented -help: use associated function syntax instead - | -LL - y.by_ref(); -LL + Y::by_ref(); - | - -error[E0599]: no method named `by_mut_ref` found for reference `&Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:38:11 +error[E0596]: cannot borrow `*y` as mutable, as it is behind a `&` reference + --> $DIR/inherent-impls-receiver-mapping.rs:31:9 | LL | y.by_mut_ref(); - | ^^^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:47 + | ^ `y` is a `&` reference, so it cannot be borrowed as mutable | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_mut_ref(); -LL + Y::by_mut_ref(); +help: consider changing this to be a mutable reference | +LL | let y = &mut Y; + | +++ -error[E0599]: no method named `by_value` found for mutable reference `&mut Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:42:11 +error[E0507]: cannot move out of `*y` which is behind a mutable reference + --> $DIR/inherent-impls-receiver-mapping.rs:35:9 | LL | y.by_value(); - | ^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:29 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_value(); -LL + Y::by_value(); + | ^ ---------- `*y` moved due to this method call + | | + | move occurs because `*y` has type `Y`, which does not implement the `Copy` trait | - -error[E0599]: the method `by_ref` exists for mutable reference `&mut Y`, but its trait bounds were not satisfied - --> $DIR/inherent-impls-receiver-mapping.rs:44:11 +note: if `Y` implemented `Clone`, you could clone the value + --> $DIR/inherent-impls-receiver-mapping.rs:13:5 | LL | struct Y; - | -------- doesn't satisfy `Y: Iterator` + | ^^^^^^^^ consider implementing `Clone` for this type ... -LL | y.by_ref(); - | ^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:39 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^ - = note: the following trait bounds were not satisfied: - `Y: Iterator` - which is required by `&mut Y: Iterator` -note: the trait `Iterator` must be implemented - --> $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following traits define an item `by_ref`, perhaps you need to implement one of them: - candidate #1: `std::io::Read` - candidate #2: `std::io::Write` - = note: the trait `Iterator` defines an item `by_ref`, but is explicitly unimplemented -help: use associated function syntax instead - | -LL - y.by_ref(); -LL + Y::by_ref(); - | - -error[E0599]: no method named `by_mut_ref` found for mutable reference `&mut Y` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:46:11 - | -LL | y.by_mut_ref(); - | ^^^^^^^^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `Y` - --> $DIR/inherent-impls-receiver-mapping.rs:17:47 - | -LL | reuse X::{static_f, by_value, by_ref, by_mut_ref} { self.get_x() } - | ^^^^^^^^^^ -help: use associated function syntax instead - | -LL - y.by_mut_ref(); -LL + Y::by_mut_ref(); - | - -error[E0599]: no method named `add` found for struct `W` in the current scope - --> $DIR/inherent-impls-receiver-mapping.rs:66:14 - | -LL | struct W(X); - | -------- method `add` not found for this struct -... -LL | W(X).add(W(X)); - | ^^^ this is an associated function, not a method - | - = note: found the following associated functions; to be used as methods, functions must have a `self` parameter -note: the candidate is defined in an impl for the type `W` - --> $DIR/inherent-impls-receiver-mapping.rs:61:18 - | -LL | reuse X::add { self.0 } - | ^^^ - = help: items from traits can only be used if the trait is implemented and in scope - = note: the following trait defines an item `add`, perhaps you need to implement it: - candidate #1: `Add` -help: use associated function syntax instead - | -LL - W(X).add(W(X)); -LL + W::add(W(X)); - | -help: one of the expressions' fields has a method of the same name - | -LL | W(X).0.add(W(X)); - | ++ +LL | y.by_value(); + | - you could clone this value -error: aborting due to 15 previous errors +error: aborting due to 6 previous errors -Some errors have detailed explanations: E0425, E0599. -For more information about an error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0308, E0507, E0596. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/inherent-impls-recursive-cycle.rs b/tests/ui/delegation/inherent-impls-recursive-cycle.rs index 0860ff39f51ee..81a59b63874fb 100644 --- a/tests/ui/delegation/inherent-impls-recursive-cycle.rs +++ b/tests/ui/delegation/inherent-impls-recursive-cycle.rs @@ -2,6 +2,7 @@ trait Trait1 { reuse trait_foo_reused as foo; + //~^ ERROR: encountered a cycle during delegation signature resolution } impl Trait1 for () {} @@ -9,44 +10,49 @@ impl Trait1 for () {} struct S1(T); impl S1 { reuse Trait1::foo { self.0 } - //~^ ERROR: delegation's target expression is specified for function with no params + //~^ ERROR: encountered a cycle during delegation signature resolution //~| ERROR: this function takes 0 arguments but 1 argument was supplied } struct S2(S1<()>); impl S2 { reuse S1::<()>::foo { self.0 } - //~^ ERROR: cannot find function `foo` in `S1` + //~^ ERROR: encountered a cycle during delegation signature resolution + //~| ERROR: this function takes 0 arguments but 1 argument was supplied } reuse S2::foo; -//~^ ERROR: cannot find function `foo` in `S2` +//~^ ERROR: encountered a cycle during delegation signature resolution struct S3; impl S3 { reuse foo; + //~^ ERROR: encountered a cycle during delegation signature resolution } impl Trait1 for S3 { reuse S2::foo { S2(S1(())) } - //~^ ERROR: delegation's target expression is specified for function with no params - //~| ERROR: cannot find function `foo` in `S2` + //~^ ERROR: encountered a cycle during delegation signature resolution + //~| ERROR: this function takes 0 arguments but 1 argument was supplied } trait Trait2 { reuse ::foo { S3 } - //~^ ERROR: delegation's target expression is specified for function with no params + //~^ ERROR: encountered a cycle during delegation signature resolution //~| ERROR: this function takes 0 arguments but 1 argument was supplied } reuse Trait2::foo as trait_foo; +//~^ ERROR: encountered a cycle during delegation signature resolution +//~| ERROR: type annotations needed struct S4; impl S4 { reuse trait_foo; + //~^ ERROR: encountered a cycle during delegation signature resolution } reuse S4::trait_foo as trait_foo_reused; -//~^ ERROR: cannot find function `trait_foo` in `S4` +//~^ ERROR: encountered a cycle during delegation signature resolution fn main() {} diff --git a/tests/ui/delegation/inherent-impls-recursive-cycle.stderr b/tests/ui/delegation/inherent-impls-recursive-cycle.stderr index a68931f8abce7..9c88b8e7cacc4 100644 --- a/tests/ui/delegation/inherent-impls-recursive-cycle.stderr +++ b/tests/ui/delegation/inherent-impls-recursive-cycle.stderr @@ -1,47 +1,65 @@ -error[E0425]: cannot find function `foo` in `S1` - --> $DIR/inherent-impls-recursive-cycle.rs:18:21 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:4:11 + | +LL | reuse trait_foo_reused as foo; + | ^^^^^^^^^^^^^^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:12:19 + | +LL | reuse Trait1::foo { self.0 } + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:19:21 | LL | reuse S1::<()>::foo { self.0 } - | ^^^ not found in `S1` + | ^^^ -error[E0425]: cannot find function `foo` in `S2` - --> $DIR/inherent-impls-recursive-cycle.rs:22:11 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:24:11 | LL | reuse S2::foo; - | ^^^ not found in `S2` + | ^^^ + +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:29:11 + | +LL | reuse foo; + | ^^^ -error[E0425]: cannot find function `foo` in `S2` - --> $DIR/inherent-impls-recursive-cycle.rs:31:15 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:34:15 | LL | reuse S2::foo { S2(S1(())) } - | ^^^ not found in `S2` + | ^^^ -error[E0425]: cannot find function `trait_foo` in `S4` - --> $DIR/inherent-impls-recursive-cycle.rs:49:11 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:40:27 | -LL | reuse S4::trait_foo as trait_foo_reused; - | ^^^^^^^^^ not found in `S4` +LL | reuse ::foo { S3 } + | ^^^ -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-recursive-cycle.rs:11:23 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:45:15 | -LL | reuse Trait1::foo { self.0 } - | ^^^^^^^^^^ +LL | reuse Trait2::foo as trait_foo; + | ^^^ -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-recursive-cycle.rs:31:19 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:51:11 | -LL | reuse S2::foo { S2(S1(())) } - | ^^^^^^^^^^^^^^ +LL | reuse trait_foo; + | ^^^^^^^^^ -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-recursive-cycle.rs:37:31 +error: encountered a cycle during delegation signature resolution + --> $DIR/inherent-impls-recursive-cycle.rs:55:11 | -LL | reuse ::foo { S3 } - | ^^^^^^ +LL | reuse S4::trait_foo as trait_foo_reused; + | ^^^^^^^^^ error[E0061]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/inherent-impls-recursive-cycle.rs:11:19 + --> $DIR/inherent-impls-recursive-cycle.rs:12:19 | LL | reuse Trait1::foo { self.0 } | ^^^ ---------- unexpected argument @@ -58,7 +76,41 @@ LL + reuse Trait1::fo{ self.0 } | error[E0061]: this function takes 0 arguments but 1 argument was supplied - --> $DIR/inherent-impls-recursive-cycle.rs:37:27 + --> $DIR/inherent-impls-recursive-cycle.rs:19:21 + | +LL | reuse S1::<()>::foo { self.0 } + | ^^^ ---------- unexpected argument + | +note: associated function defined here + --> $DIR/inherent-impls-recursive-cycle.rs:12:19 + | +LL | reuse Trait1::foo { self.0 } + | ^^^ +help: remove the extra argument + | +LL - reuse S1::<()>::foo { self.0 } +LL + reuse S1::<()>::fo{ self.0 } + | + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/inherent-impls-recursive-cycle.rs:34:15 + | +LL | reuse S2::foo { S2(S1(())) } + | ^^^ -------------- unexpected argument of type `S2` + | +note: associated function defined here + --> $DIR/inherent-impls-recursive-cycle.rs:19:21 + | +LL | reuse S1::<()>::foo { self.0 } + | ^^^ +help: remove the extra argument + | +LL - reuse S2::foo { S2(S1(())) } +LL + reuse S2::fo{ S2(S1(())) } + | + +error[E0061]: this function takes 0 arguments but 1 argument was supplied + --> $DIR/inherent-impls-recursive-cycle.rs:40:27 | LL | reuse ::foo { S3 } | ^^^ ------ unexpected argument of type `S3` @@ -74,7 +126,15 @@ LL - reuse ::foo { S3 } LL + reuse ::fo{ S3 } | -error: aborting due to 9 previous errors +error[E0283]: type annotations needed + --> $DIR/inherent-impls-recursive-cycle.rs:45:15 + | +LL | reuse Trait2::foo as trait_foo; + | ^^^ cannot infer type + | + = note: the type must implement `Trait2` + +error: aborting due to 15 previous errors -Some errors have detailed explanations: E0061, E0425. +Some errors have detailed explanations: E0061, E0283. For more information about an error, try `rustc --explain E0061`. diff --git a/tests/ui/delegation/inherent-impls-recursive.rs b/tests/ui/delegation/inherent-impls-recursive.rs index c57ef40642346..7d86cf93a4660 100644 --- a/tests/ui/delegation/inherent-impls-recursive.rs +++ b/tests/ui/delegation/inherent-impls-recursive.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(fn_delegation)] mod test_1 { @@ -9,13 +11,11 @@ mod test_1 { struct S2; impl S2 { reuse S1::foo; - //~^ ERROR: cannot find function `foo` in `S1` } struct S3; impl S3 { reuse S2::foo; - //~^ ERROR: cannot find function `foo` in `S2` } } @@ -34,11 +34,9 @@ mod test_2 { struct S2(S1<()>); impl S2 { reuse S1::<()>::foo { self.0 } - //~^ ERROR: cannot find function `foo` in `S1` } reuse S2::foo; - //~^ ERROR: cannot find function `foo` in `S2` struct S3; impl S3 { @@ -47,8 +45,6 @@ mod test_2 { impl Trait1 for S3 { reuse S2::foo { &S2(S1(())) } - //~^ ERROR: method `foo` has a `&self` declaration in the trait, but not in the impl - //~| ERROR: cannot find function `foo` in `S2` } trait Trait2 { @@ -63,7 +59,6 @@ mod test_2 { } reuse S4::trait_foo as trait_foo_reused; - //~^ ERROR: cannot find function `trait_foo` in `S4` } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-recursive.stderr b/tests/ui/delegation/inherent-impls-recursive.stderr deleted file mode 100644 index f80d9d3b84097..0000000000000 --- a/tests/ui/delegation/inherent-impls-recursive.stderr +++ /dev/null @@ -1,61 +0,0 @@ -error[E0425]: cannot find function `foo` in `S1` - --> $DIR/inherent-impls-recursive.rs:11:19 - | -LL | reuse S1::foo; - | ^^^ not found in `S1` - | -note: function `test_2::foo` exists but is inaccessible - --> $DIR/inherent-impls-recursive.rs:40:5 - | -LL | reuse S2::foo; - | ^^^^^^^^^^^^^^ not accessible - -error[E0425]: cannot find function `foo` in `S2` - --> $DIR/inherent-impls-recursive.rs:17:19 - | -LL | reuse S2::foo; - | ^^^ not found in `S2` - | -note: function `test_2::foo` exists but is inaccessible - --> $DIR/inherent-impls-recursive.rs:40:5 - | -LL | reuse S2::foo; - | ^^^^^^^^^^^^^^ not accessible - -error[E0425]: cannot find function `foo` in `S1` - --> $DIR/inherent-impls-recursive.rs:36:25 - | -LL | reuse S1::<()>::foo { self.0 } - | ^^^ not found in `S1` - -error[E0425]: cannot find function `foo` in `S2` - --> $DIR/inherent-impls-recursive.rs:40:15 - | -LL | reuse S2::foo; - | ^^^ not found in `S2` - -error[E0425]: cannot find function `foo` in `S2` - --> $DIR/inherent-impls-recursive.rs:49:19 - | -LL | reuse S2::foo { &S2(S1(())) } - | ^^^ not found in `S2` - -error[E0425]: cannot find function `trait_foo` in `S4` - --> $DIR/inherent-impls-recursive.rs:65:15 - | -LL | reuse S4::trait_foo as trait_foo_reused; - | ^^^^^^^^^ not found in `S4` - -error[E0186]: method `foo` has a `&self` declaration in the trait, but not in the impl - --> $DIR/inherent-impls-recursive.rs:49:19 - | -LL | fn foo(&self) {} - | ------------- `&self` used in trait -... -LL | reuse S2::foo { &S2(S1(())) } - | ^^^ expected `&self` in impl - -error: aborting due to 7 previous errors - -Some errors have detailed explanations: E0186, E0425. -For more information about an error, try `rustc --explain E0186`. diff --git a/tests/ui/delegation/inherent-impls-rename.rs b/tests/ui/delegation/inherent-impls-rename.rs index 7b6e1e4b7cddc..6a0fd672cf8e5 100644 --- a/tests/ui/delegation/inherent-impls-rename.rs +++ b/tests/ui/delegation/inherent-impls-rename.rs @@ -1,3 +1,5 @@ +//@ check-pass + #![feature(fn_delegation)] struct X; @@ -9,6 +11,5 @@ impl X { } reuse X::bar; -//~^ ERROR: cannot find function `bar` in `X` fn main() {} diff --git a/tests/ui/delegation/inherent-impls-rename.stderr b/tests/ui/delegation/inherent-impls-rename.stderr deleted file mode 100644 index e2e8946412e93..0000000000000 --- a/tests/ui/delegation/inherent-impls-rename.stderr +++ /dev/null @@ -1,9 +0,0 @@ -error[E0425]: cannot find function `bar` in `X` - --> $DIR/inherent-impls-rename.rs:11:10 - | -LL | reuse X::bar; - | ^^^ not found in `X` - -error: aborting due to 1 previous error - -For more information about this error, try `rustc --explain E0425`. diff --git a/tests/ui/delegation/inherent-impls-self-mapping.rs b/tests/ui/delegation/inherent-impls-self-mapping.rs index 36aef3a7bc7d8..9c13c13786fa7 100644 --- a/tests/ui/delegation/inherent-impls-self-mapping.rs +++ b/tests/ui/delegation/inherent-impls-self-mapping.rs @@ -11,10 +11,10 @@ impl X { trait Trait { reuse X::foo; - //~^ ERROR: cannot find function `foo` in `X` + //~^ ERROR: arguments to this function are incorrect + //~| ERROR: mismatched types } reuse X::foo; -//~^ ERROR: cannot find function `foo` in `X` fn main() {} diff --git a/tests/ui/delegation/inherent-impls-self-mapping.stderr b/tests/ui/delegation/inherent-impls-self-mapping.stderr index 9ecf04626d29c..82ea263a8513b 100644 --- a/tests/ui/delegation/inherent-impls-self-mapping.stderr +++ b/tests/ui/delegation/inherent-impls-self-mapping.stderr @@ -1,15 +1,41 @@ -error[E0425]: cannot find function `foo` in `X` +error[E0308]: arguments to this function are incorrect --> $DIR/inherent-impls-self-mapping.rs:13:14 | +LL | trait Trait { + | ----------- + | | + | found this type parameter + | found this type parameter LL | reuse X::foo; - | ^^^ not found in `X` + | ^^^ + | | + | expected `Rc>`, found `Rc>` + | expected `Box>`, found `Box>` + | + = note: expected struct `Rc>` + found struct `Rc>` + = note: expected struct `Box>` + found struct `Box>` +note: method defined here + --> $DIR/inherent-impls-self-mapping.rs:7:8 + | +LL | fn foo(self: Rc>, other: Box>) -> Option> { + | ^^^ ---- -------------------- -error[E0425]: cannot find function `foo` in `X` - --> $DIR/inherent-impls-self-mapping.rs:17:10 +error[E0308]: mismatched types + --> $DIR/inherent-impls-self-mapping.rs:13:14 + | +LL | trait Trait { + | ----------- expected this type parameter +LL | reuse X::foo; + | ^^^ + | | + | expected `Option>`, found `Option>` + | expected `Option>` because of return type | -LL | reuse X::foo; - | ^^^ not found in `X` + = note: expected enum `Option>` + found enum `Option>` error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0425`. +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/inherent-impls-self-replacement.rs b/tests/ui/delegation/inherent-impls-self-replacement.rs index e6aa7458993fd..65ecccf766719 100644 --- a/tests/ui/delegation/inherent-impls-self-replacement.rs +++ b/tests/ui/delegation/inherent-impls-self-replacement.rs @@ -20,37 +20,36 @@ trait Trait: Sized { fn get_s(self) -> S<(), 123>; reuse S::<(), 123>::by_value { self.get_s() } - //~^ ERROR: cannot find function `by_value` in `S` reuse S::<(), 123>::by_ref { self.get_s() } - //~^ ERROR: cannot find function `by_ref` in `S` + //~^ ERROR: cannot move out of `*self` which is behind a shared reference reuse S::<(), 123>::by_mut_ref { self.get_s() } - //~^ ERROR: cannot find function `by_mut_ref` in `S` + //~^ ERROR: cannot move out of `*self` which is behind a mutable reference reuse S::<(), 123>::by_box { self.get_s() } - //~^ ERROR: cannot find function `by_box` in `S` + //~^ ERROR: mismatched types reuse S::<(), 123>::by_rc { self.get_s() } - //~^ ERROR: cannot find function `by_rc` in `S` + //~^ ERROR: mismatched types reuse S::<(), 123>::by_pin { self.get_s() } - //~^ ERROR: cannot find function `by_pin` in `S` + //~^ ERROR: mismatched types } trait Trait2: Sized { reuse S::<(), 123>::by_value { self.get_s() } - //~^ ERROR: cannot find function `by_value` in `S` + //~^ ERROR: no method named `get_s` found for type parameter `Self` in the current scope reuse S::<(), 123>::by_ref { self.get_s() } - //~^ ERROR: cannot find function `by_ref` in `S` + //~^ ERROR: no method named `get_s` found for reference `&Self` in the current scope reuse S::<(), 123>::by_mut_ref { self.get_s() } - //~^ ERROR: cannot find function `by_mut_ref` in `S` + //~^ ERROR: no method named `get_s` found for mutable reference `&mut Self` in the current scope reuse S::<(), 123>::by_box { self.get_s() } - //~^ ERROR: cannot find function `by_box` in `S` + //~^ ERROR: no method named `get_s` found for struct `Box` in the current scope reuse S::<(), 123>::by_rc { self.get_s() } - //~^ ERROR: cannot find function `by_rc` in `S` + //~^ ERROR: no method named `get_s` found for struct `Rc` in the current scope reuse S::<(), 123>::by_pin { self.get_s() } - //~^ ERROR: cannot find function `by_pin` in `S` + //~^ ERROR: no method named `get_s` found for struct `Pin>` in the current scope } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-self-replacement.stderr b/tests/ui/delegation/inherent-impls-self-replacement.stderr index e293635e4a1ea..e017bee8af540 100644 --- a/tests/ui/delegation/inherent-impls-self-replacement.stderr +++ b/tests/ui/delegation/inherent-impls-self-replacement.stderr @@ -1,75 +1,186 @@ -error[E0425]: cannot find function `by_value` in `S` - --> $DIR/inherent-impls-self-replacement.rs:22:25 +error[E0308]: mismatched types + --> $DIR/inherent-impls-self-replacement.rs:30:34 | -LL | reuse S::<(), 123>::by_value { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `by_ref` in `S` - --> $DIR/inherent-impls-self-replacement.rs:25:25 +LL | reuse S::<(), 123>::by_box { self.get_s() } + | ------ ^^^^^^^^^^^^ expected `Box>`, found `S<(), 123>` + | | + | arguments to this function are incorrect | -LL | reuse S::<(), 123>::by_ref { self.get_s() } - | ^^^^^^ not found in `S` - -error[E0425]: cannot find function `by_mut_ref` in `S` - --> $DIR/inherent-impls-self-replacement.rs:28:25 + = note: expected struct `Box>` + found struct `S<_, _>` + = note: for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html +note: method defined here + --> $DIR/inherent-impls-self-replacement.rs:14:8 | -LL | reuse S::<(), 123>::by_mut_ref { self.get_s() } - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `by_box` in `S` - --> $DIR/inherent-impls-self-replacement.rs:31:25 +LL | fn by_box<'d: 'd, 'e, T, const B: bool>(self: Box) {} + | ^^^^^^ ---- +help: store this in the heap by calling `Box::new` | -LL | reuse S::<(), 123>::by_box { self.get_s() } - | ^^^^^^ not found in `S` +LL | reuse S::<(), 123>::by_box { Box::new(self.get_s()) } + | +++++++++ + -error[E0425]: cannot find function `by_rc` in `S` - --> $DIR/inherent-impls-self-replacement.rs:34:25 +error[E0308]: mismatched types + --> $DIR/inherent-impls-self-replacement.rs:33:33 | LL | reuse S::<(), 123>::by_rc { self.get_s() } - | ^^^^^ not found in `S` + | ----- ^^^^^^^^^^^^ expected `Rc>`, found `S<(), 123>` + | | + | arguments to this function are incorrect + | + = note: expected struct `Rc>` + found struct `S<_, _>` +note: method defined here + --> $DIR/inherent-impls-self-replacement.rs:15:8 + | +LL | fn by_rc<'d: 'd, 'e, T, const B: bool>(self: Rc) {} + | ^^^^^ ---- +help: call `Into::into` on this expression to convert `S<(), 123>` into `Rc>` + | +LL | reuse S::<(), 123>::by_rc { self.get_s().into() } + | +++++++ -error[E0425]: cannot find function `by_pin` in `S` - --> $DIR/inherent-impls-self-replacement.rs:37:25 +error[E0308]: mismatched types + --> $DIR/inherent-impls-self-replacement.rs:36:34 | LL | reuse S::<(), 123>::by_pin { self.get_s() } - | ^^^^^^ not found in `S` + | ------ ^^^^^^^^^^^^ expected `Pin>>`, found `S<(), 123>` + | | + | arguments to this function are incorrect + | + = note: expected struct `Pin>>` + found struct `S<(), 123>` +note: method defined here + --> $DIR/inherent-impls-self-replacement.rs:16:8 + | +LL | fn by_pin<'d: 'd, 'e, T, const B: bool>(self: Pin>) {} + | ^^^^^^ ---- +help: you need to pin and box this expression + | +LL | reuse S::<(), 123>::by_pin { Box::pin(self.get_s()) } + | +++++++++ + -error[E0425]: cannot find function `by_value` in `S` - --> $DIR/inherent-impls-self-replacement.rs:42:25 +error[E0599]: no method named `get_s` found for type parameter `Self` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:41:41 | +LL | trait Trait2: Sized { + | ------------------- method `get_s` not found for this type parameter LL | reuse S::<(), 123>::by_value { self.get_s() } - | ^^^^^^^^ not found in `S` + | ^^^^^ method not found in `Self` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `get_s`, perhaps you need to add another supertrait for it: + | +LL | trait Trait2: Sized + Trait { + | +++++++ -error[E0425]: cannot find function `by_ref` in `S` - --> $DIR/inherent-impls-self-replacement.rs:44:25 +error[E0599]: no method named `get_s` found for reference `&Self` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:43:39 | LL | reuse S::<(), 123>::by_ref { self.get_s() } - | ^^^^^^ not found in `S` + | ^^^^^ method not found in `&Self` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `get_s`, perhaps you need to add another supertrait for it: + | +LL | trait Trait2: Sized + Trait { + | +++++++ -error[E0425]: cannot find function `by_mut_ref` in `S` - --> $DIR/inherent-impls-self-replacement.rs:46:25 +error[E0599]: no method named `get_s` found for mutable reference `&mut Self` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:45:43 | LL | reuse S::<(), 123>::by_mut_ref { self.get_s() } - | ^^^^^^^^^^ not found in `S` + | ^^^^^ method not found in `&mut Self` + | + = help: items from traits can only be used if the type parameter is bounded by the trait +help: the following trait defines an item `get_s`, perhaps you need to add another supertrait for it: + | +LL | trait Trait2: Sized + Trait { + | +++++++ -error[E0425]: cannot find function `by_box` in `S` - --> $DIR/inherent-impls-self-replacement.rs:48:25 +error[E0599]: no method named `get_s` found for struct `Box` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:47:39 | LL | reuse S::<(), 123>::by_box { self.get_s() } - | ^^^^^^ not found in `S` + | ^^^^^ method not found in `Box` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `get_s`, perhaps you need to implement it + --> $DIR/inherent-impls-self-replacement.rs:19:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ -error[E0425]: cannot find function `by_rc` in `S` - --> $DIR/inherent-impls-self-replacement.rs:50:25 +error[E0599]: no method named `get_s` found for struct `Rc` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:49:38 | LL | reuse S::<(), 123>::by_rc { self.get_s() } - | ^^^^^ not found in `S` + | ^^^^^ method not found in `Rc` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `get_s`, perhaps you need to implement it + --> $DIR/inherent-impls-self-replacement.rs:19:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ -error[E0425]: cannot find function `by_pin` in `S` - --> $DIR/inherent-impls-self-replacement.rs:52:25 +error[E0599]: no method named `get_s` found for struct `Pin>` in the current scope + --> $DIR/inherent-impls-self-replacement.rs:51:39 | LL | reuse S::<(), 123>::by_pin { self.get_s() } - | ^^^^^^ not found in `S` + | ^^^^^ method not found in `Pin>` + | + = help: items from traits can only be used if the trait is implemented and in scope +note: `Trait` defines an item `get_s`, perhaps you need to implement it + --> $DIR/inherent-impls-self-replacement.rs:19:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ + +error[E0507]: cannot move out of `*self` which is behind a shared reference + --> $DIR/inherent-impls-self-replacement.rs:24:34 + | +LL | reuse S::<(), 123>::by_ref { self.get_s() } + | ^^^^ ------- `*self` moved due to this method call + | | + | move occurs because `*self` has type `Self`, which does not implement the `Copy` trait + | +note: `Trait::get_s` takes ownership of the receiver `self`, which moves `*self` + --> $DIR/inherent-impls-self-replacement.rs:20:14 + | +LL | fn get_s(self) -> S<(), 123>; + | ^^^^ +help: if `Self` implemented `Clone`, you could clone the value + --> $DIR/inherent-impls-self-replacement.rs:19:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ consider constraining this type parameter with `Clone` +... +LL | reuse S::<(), 123>::by_ref { self.get_s() } + | ---- you could clone this value + +error[E0507]: cannot move out of `*self` which is behind a mutable reference + --> $DIR/inherent-impls-self-replacement.rs:27:38 + | +LL | reuse S::<(), 123>::by_mut_ref { self.get_s() } + | ^^^^ ------- `*self` moved due to this method call + | | + | move occurs because `*self` has type `Self`, which does not implement the `Copy` trait + | +note: `Trait::get_s` takes ownership of the receiver `self`, which moves `*self` + --> $DIR/inherent-impls-self-replacement.rs:20:14 + | +LL | fn get_s(self) -> S<(), 123>; + | ^^^^ +help: if `Self` implemented `Clone`, you could clone the value + --> $DIR/inherent-impls-self-replacement.rs:19:1 + | +LL | trait Trait: Sized { + | ^^^^^^^^^^^^^^^^^^ consider constraining this type parameter with `Clone` +... +LL | reuse S::<(), 123>::by_mut_ref { self.get_s() } + | ---- you could clone this value -error: aborting due to 12 previous errors +error: aborting due to 11 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0308, E0507, E0599. +For more information about an error, try `rustc --explain E0308`. diff --git a/tests/ui/delegation/inherent-impls-structs.rs b/tests/ui/delegation/inherent-impls-structs.rs index a5950185b6dad..f7a9d362dd9ca 100644 --- a/tests/ui/delegation/inherent-impls-structs.rs +++ b/tests/ui/delegation/inherent-impls-structs.rs @@ -10,77 +10,55 @@ impl<'a, 'b, 'c, A, const C: usize> S { } reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; -//~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static as foo_static_3; -//~^ ERROR: cannot find function `foo_static` in `S` reuse S::::foo_static::<'static, _, _> as foo_static_4; -//~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1; -//~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 1>::foo_self as foo_self_3; -//~^ ERROR: cannot find function `foo_self` in `S` reuse S::::foo_self::<'static, _, _> as foo_self_4; -//~^ ERROR: cannot find function `foo_self` in `S` trait Trait<'a, AA, BB> where Self: Sized { reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in `S` fn get_s(self) -> S<(), 1> { panic!(); } reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in `S` + //~^ ERROR: mismatched types [E0308] } struct X; impl<'a, A, B> Trait<'a, A, B> for X { reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in `S` + //~^ ERROR: type annotations needed [E0284] reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` - //~| ERROR: delegation's target expression is specified for function with no params reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` - //~| ERROR: delegation's target expression is specified for function with no params reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in `S` + //~^ ERROR: mismatched types [E0308] } impl X { reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static as foo_static_3; - //~^ ERROR: cannot find function `foo_static` in `S` reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - //~^ ERROR: cannot find function `foo_static` in `S` fn get_s(self) -> S<(), 1> { panic!(); } reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - //~^ ERROR: cannot find function `foo_self` in `S` reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - //~^ ERROR: cannot find function `foo_self` in `S` + //~^ ERROR: mismatched types [E0308] } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-structs.stderr b/tests/ui/delegation/inherent-impls-structs.stderr index 6a426564a6e3a..29963431b1451 100644 --- a/tests/ui/delegation/inherent-impls-structs.stderr +++ b/tests/ui/delegation/inherent-impls-structs.stderr @@ -1,159 +1,70 @@ -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:12:19 - | -LL | reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:14:19 - | -LL | reuse S::<(), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:16:22 - | -LL | reuse S::::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:19:19 - | -LL | reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:21:19 - | -LL | reuse S::<(), 1>::foo_self as foo_self_3; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:23:23 - | -LL | reuse S::::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:27:23 - | -LL | reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:29:23 - | -LL | reuse S::<(), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` +error[E0308]: mismatched types --> $DIR/inherent-impls-structs.rs:31:23 | -LL | reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:38:23 - | -LL | reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:40:23 - | -LL | reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:42:23 - | +LL | trait Trait<'a, AA, BB> where Self: Sized { + | ----------------------- found this type parameter +... LL | reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:49:23 + | ^^^^^^^^ + | | + | expected `S<(), 1>`, found type parameter `Self` + | arguments to this function are incorrect | -LL | reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:51:23 + = note: expected struct `S<(), 1>` + found type parameter `Self` +note: method defined here + --> $DIR/inherent-impls-structs.rs:9:8 | -LL | reuse S::<(), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:53:23 +error[E0284]: type annotations needed + --> $DIR/inherent-impls-structs.rs:40:23 | LL | reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:56:23 + | ^^^^^^^^^^ cannot infer the value of const parameter `B` declared on the associated function `foo_static` | -LL | reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:59:23 +note: required by a const generic parameter in `S::::foo_static` + --> $DIR/inherent-impls-structs.rs:8:34 | -LL | reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` +LL | fn foo_static<'d: 'd, 'e, T, const B: bool>() {} + | ^^^^^^^^^^^^^ required by this const generic parameter in `S::::foo_static` -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:62:23 +error[E0308]: mismatched types + --> $DIR/inherent-impls-structs.rs:45:23 | LL | reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:67:23 + | ^^^^^^^^ + | | + | expected `S<(), 1>`, found `X` + | arguments to this function are incorrect | -LL | reuse S::<(), 1>::foo_static::<'static, (), true> as foo_static_1; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:69:23 - | -LL | reuse S::<(), 1>::foo_static as foo_static_3; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_static` in `S` - --> $DIR/inherent-impls-structs.rs:71:23 - | -LL | reuse S::<(), 1>::foo_static::<'static, _, _> as foo_static_4; - | ^^^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:78:23 - | -LL | reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^ not found in `S` - -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:80:23 + = note: expected struct `S<(), 1>` + found struct `X` +note: method defined here + --> $DIR/inherent-impls-structs.rs:9:8 | -LL | reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^ not found in `S` +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-structs.rs:82:23 +error[E0308]: mismatched types + --> $DIR/inherent-impls-structs.rs:60:23 | LL | reuse S::<(), 1>::foo_self::<'static, _, _> as foo_self_4; - | ^^^^^^^^ not found in `S` - -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-structs.rs:56:67 + | ^^^^^^^^ + | | + | expected `S<(), 1>`, found `X` + | arguments to this function are incorrect | -LL | reuse S::<(), 1>::foo_self::<'static, (), true> as foo_self_1 { self.get_s() } - | ^^^^^^^^^^^^^^^^ - -error: delegation's target expression is specified for function with no params - --> $DIR/inherent-impls-structs.rs:59:46 + = note: expected struct `S<(), 1>` + found struct `X` +note: method defined here + --> $DIR/inherent-impls-structs.rs:9:8 | -LL | reuse S::<(), 1>::foo_self as foo_self_3 { self.get_s() } - | ^^^^^^^^^^^^^^^^ +LL | fn foo_self<'d: 'd, 'e, T, const B: bool>(self) {} + | ^^^^^^^^ ---- -error: aborting due to 26 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0284, E0308. +For more information about an error, try `rustc --explain E0284`. diff --git a/tests/ui/delegation/inherent-impls-wrong-header-args-ice.rs b/tests/ui/delegation/inherent-impls-wrong-header-args-ice.rs index 8375df5f26587..90c329ea6a69c 100644 --- a/tests/ui/delegation/inherent-impls-wrong-header-args-ice.rs +++ b/tests/ui/delegation/inherent-impls-wrong-header-args-ice.rs @@ -11,7 +11,9 @@ impl<'a, 'b, 'c, A, const C: usize> S { trait Trait<'a, AA, BB> where Self: Sized { reuse S::<(), ()>::foo_self; - //~^ ERROR: cannot find function `foo_self` in `S` + //~^ ERROR: inferred lifetimes are not allowed in delegations as we need to inherit signature + //~| ERROR: type provided when a constant was expected + //~| ERROR: type provided when a constant was expected } fn main() {} diff --git a/tests/ui/delegation/inherent-impls-wrong-header-args-ice.stderr b/tests/ui/delegation/inherent-impls-wrong-header-args-ice.stderr index bfa377dcc2db6..bda4c7ceab9e8 100644 --- a/tests/ui/delegation/inherent-impls-wrong-header-args-ice.stderr +++ b/tests/ui/delegation/inherent-impls-wrong-header-args-ice.stderr @@ -9,13 +9,27 @@ help: indicate the anonymous lifetime LL | impl<'a, 'b, 'c, A, const C: usize> S<'_, A, C> { | +++ -error[E0425]: cannot find function `foo_self` in `S` - --> $DIR/inherent-impls-wrong-header-args-ice.rs:13:24 +error: inferred lifetimes are not allowed in delegations as we need to inherit signature + --> $DIR/inherent-impls-wrong-header-args-ice.rs:13:15 | LL | reuse S::<(), ()>::foo_self; - | ^^^^^^^^ not found in `S` + | ^ -error: aborting due to 2 previous errors +error[E0747]: type provided when a constant was expected + --> $DIR/inherent-impls-wrong-header-args-ice.rs:13:19 + | +LL | reuse S::<(), ()>::foo_self; + | ^^ + +error[E0747]: type provided when a constant was expected + --> $DIR/inherent-impls-wrong-header-args-ice.rs:13:19 + | +LL | reuse S::<(), ()>::foo_self; + | ^^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error: aborting due to 4 previous errors -Some errors have detailed explanations: E0425, E0726. -For more information about an error, try `rustc --explain E0425`. +Some errors have detailed explanations: E0726, E0747. +For more information about an error, try `rustc --explain E0726`. diff --git a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr index 594f6cc66690e..da16e49a777eb 100644 --- a/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr +++ b/tests/ui/parallel-rustc/default-trait-shadow-cycle-issue-151358.stderr @@ -2,6 +2,7 @@ error: internal compiler error: query cycle when printing cycle detected | = note: ...when getting owner for `Default` = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which requires looking up span for `Default`... @@ -13,6 +14,7 @@ error[E0391]: cycle detected when getting the resolver for lowering | = note: ...which requires getting owner for `Default`... = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which again requires getting the resolver for lowering, completing the cycle diff --git a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr index 594f6cc66690e..da16e49a777eb 100644 --- a/tests/ui/query-system/query-cycle-printing-issue-151358.stderr +++ b/tests/ui/query-system/query-cycle-printing-issue-151358.stderr @@ -2,6 +2,7 @@ error: internal compiler error: query cycle when printing cycle detected | = note: ...when getting owner for `Default` = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which requires looking up span for `Default`... @@ -13,6 +14,7 @@ error[E0391]: cycle detected when getting the resolver for lowering | = note: ...which requires getting owner for `Default`... = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which again requires getting the resolver for lowering, completing the cycle diff --git a/tests/ui/resolve/query-cycle-issue-124901.stderr b/tests/ui/resolve/query-cycle-issue-124901.stderr index 594f6cc66690e..da16e49a777eb 100644 --- a/tests/ui/resolve/query-cycle-issue-124901.stderr +++ b/tests/ui/resolve/query-cycle-issue-124901.stderr @@ -2,6 +2,7 @@ error: internal compiler error: query cycle when printing cycle detected | = note: ...when getting owner for `Default` = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which requires looking up span for `Default`... @@ -13,6 +14,7 @@ error[E0391]: cycle detected when getting the resolver for lowering | = note: ...which requires getting owner for `Default`... = note: ...which requires lowering HIR for `Default`... + = note: ...which requires resolving type relative delegations... = note: ...which requires getting the AST for lowering... = note: ...which requires perform lints prior to AST lowering... = note: ...which again requires getting the resolver for lowering, completing the cycle From 7ce50f87c0439e7352680fd76bdaa5ae02cfecfc Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Tue, 8 Sep 2026 07:05:59 -0300 Subject: [PATCH 10/13] Add test for soundness issue on new solver --- tests/ui/const-generics/dyn-trait-ill-typed.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 tests/ui/const-generics/dyn-trait-ill-typed.rs diff --git a/tests/ui/const-generics/dyn-trait-ill-typed.rs b/tests/ui/const-generics/dyn-trait-ill-typed.rs new file mode 100644 index 0000000000000..d6c1fdc29fb53 --- /dev/null +++ b/tests/ui/const-generics/dyn-trait-ill-typed.rs @@ -0,0 +1,14 @@ +//! Regression test for . +//@ compile-flags: -Znext-solver=globally +//@ check-pass + +// CHECK PASS TO SHOW IT PASSES, BUT IT SHOULD NOT +// THIS CODE SEGFAULTS, WITH REASON + +fn foo() -> Box> { + loop {} +} + +trait Tr {} + +fn main() {} From 265ca102b5ec5755a92bfa50c246df39a4943732 Mon Sep 17 00:00:00 2001 From: Lucas Sunsi Abreu Date: Mon, 7 Sep 2026 11:04:13 -0300 Subject: [PATCH 11/13] Make ConstKind Placeholder also check ConstArgHasType --- compiler/rustc_trait_selection/src/traits/wf.rs | 5 ++++- tests/ui/const-generics/dyn-trait-ill-typed.rs | 3 ++- tests/ui/const-generics/dyn-trait-ill-typed.stderr | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 tests/ui/const-generics/dyn-trait-ill-typed.stderr diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5fc9e57795b72..1de2318fe77f4 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -1003,7 +1003,10 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { let kind = obligation.predicate.kind().skip_binder(); let keep = match kind { ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(ct, _)) - if matches!(ct.kind(), ty::ConstKind::Param(..)) => + if matches!( + ct.kind(), + ty::ConstKind::Param(..) | ty::ConstKind::Placeholder(..) + ) => { // ConstArgHasType clauses are not higher kinded. Assert as // such so we can fix this up if that ever changes. diff --git a/tests/ui/const-generics/dyn-trait-ill-typed.rs b/tests/ui/const-generics/dyn-trait-ill-typed.rs index d6c1fdc29fb53..3dba700a7fa39 100644 --- a/tests/ui/const-generics/dyn-trait-ill-typed.rs +++ b/tests/ui/const-generics/dyn-trait-ill-typed.rs @@ -1,10 +1,11 @@ //! Regression test for . //@ compile-flags: -Znext-solver=globally -//@ check-pass +//@ check-fail // CHECK PASS TO SHOW IT PASSES, BUT IT SHOULD NOT // THIS CODE SEGFAULTS, WITH REASON +//~v ERROR: the constant `M` is not of type `usize` fn foo() -> Box> { loop {} } diff --git a/tests/ui/const-generics/dyn-trait-ill-typed.stderr b/tests/ui/const-generics/dyn-trait-ill-typed.stderr new file mode 100644 index 0000000000000..8917b53d4d826 --- /dev/null +++ b/tests/ui/const-generics/dyn-trait-ill-typed.stderr @@ -0,0 +1,14 @@ +error: the constant `M` is not of type `usize` + --> $DIR/dyn-trait-ill-typed.rs:9:27 + | +LL | fn foo() -> Box> { + | ^^^^^^^^^^^^^^ expected `usize`, found `u32` + | +note: required by a const generic parameter in `Tr` + --> $DIR/dyn-trait-ill-typed.rs:13:10 + | +LL | trait Tr {} + | ^^^^^^^^^^^^^^ required by this const generic parameter in `Tr` + +error: aborting due to 1 previous error + From 8622679cb619e6791c65e1b0c9e0c74664f4f5e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jana=20D=C3=B6nszelmann?= Date: Fri, 4 Sep 2026 15:11:28 +0200 Subject: [PATCH 12/13] limit the api of fold_predicate and visit_predicate --- .../src/collect/item_bounds.rs | 6 +- compiler/rustc_hir_typeck/src/writeback.rs | 8 +- .../src/infer/canonical/canonicalizer.rs | 3 +- .../src/infer/canonical/instantiate.rs | 3 +- compiler/rustc_infer/src/infer/resolve.rs | 3 +- compiler/rustc_middle/src/ty/erase_regions.rs | 3 +- compiler/rustc_middle/src/ty/fold.rs | 3 +- .../rustc_middle/src/ty/structural_impls.rs | 77 +++++++++++++++++-- compiler/rustc_middle/src/ty/util.rs | 38 ++++----- .../src/canonical/canonicalizer.rs | 6 +- .../rustc_next_trait_solver/src/normalize.rs | 6 +- .../src/placeholder.rs | 4 +- .../src/solve/eval_ctxt/mod.rs | 7 +- compiler/rustc_privacy/src/lib.rs | 14 ++-- .../src/traits/normalize.rs | 6 +- .../src/traits/query/normalize.rs | 8 +- .../rustc_trait_selection/src/traits/wf.rs | 6 +- compiler/rustc_type_ir/src/binder.rs | 6 +- compiler/rustc_type_ir/src/fold.rs | 42 ++++++++-- compiler/rustc_type_ir/src/infer_ctxt.rs | 6 +- compiler/rustc_type_ir/src/visit.rs | 8 +- 21 files changed, 184 insertions(+), 79 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index 4874eacd79b63..b3fbdc03e8478 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -2,8 +2,8 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_hir as hir; use rustc_infer::traits::util; use rustc_middle::ty::{ - self, GenericArgs, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, - Upcast, shift_vars, + self, GenericArgs, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitableExt, Upcast, shift_vars, }; use rustc_middle::{bug, span_bug}; use rustc_span::Span; @@ -347,7 +347,7 @@ impl<'tcx> TypeFolder> for MapAndCompressBoundVars<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if !p.has_bound_vars() { p } else { p.super_fold_with(self) } } } diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 7b1f38f882747..b71290b658744 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -21,9 +21,9 @@ use rustc_infer::traits::solve::Goal; use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCoercion}; use rustc_middle::ty::{ - self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, Ty, TyCtxt, TypeFoldable, TypeFolder, - TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - Unnormalized, fold_regions, + self, DefiningScopeKind, DefinitionSiteHiddenType, Flags, PredicateProxy, Ty, TyCtxt, + TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, + TypeVisitableExt, TypeVisitor, Unnormalized, fold_regions, }; use rustc_span::Span; use rustc_trait_selection::error_reporting::infer::need_type_info::TypeAnnotationNeeded; @@ -1032,7 +1032,7 @@ impl<'cx, 'tcx> TypeFolder> for Resolver<'cx, 'tcx> { self.handle_term(ct, ty::Const::outer_exclusive_binder, ty::Const::new_error) } - fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, predicate: P) -> P { assert!( !self.should_normalize, "normalizing predicates in writeback is not generally sound" diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index 770520413c666..9b3deac32222b 100644 --- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -13,6 +13,7 @@ use rustc_middle::ty::{ self, BoundVar, Flags, GenericArg, InferConst, List, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, TypingModeEqWrapper, }; +use rustc_type_ir::PredicateProxy; use smallvec::SmallVec; use tracing::debug; @@ -483,7 +484,7 @@ impl<'cx, 'tcx> TypeFolder> for Canonicalizer<'cx, 'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.flags().intersects(self.needs_canonical_flags) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_infer/src/infer/canonical/instantiate.rs b/compiler/rustc_infer/src/infer/canonical/instantiate.rs index 7e670cc233752..2bc7e269efc9d 100644 --- a/compiler/rustc_infer/src/infer/canonical/instantiate.rs +++ b/compiler/rustc_infer/src/infer/canonical/instantiate.rs @@ -11,6 +11,7 @@ use rustc_middle::ty::{ self, DelayedMap, Ty, TyCtxt, TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; +use rustc_type_ir::PredicateProxy; use crate::infer::canonical::{Canonical, CanonicalVarValues}; @@ -124,7 +125,7 @@ impl<'tcx> TypeFolder> for CanonicalInstantiator<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_type_flags(TypeFlags::HAS_CANONICAL_BOUND) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs index 13df23a39b967..db4f313903a5a 100644 --- a/compiler/rustc_infer/src/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -3,6 +3,7 @@ use rustc_middle::ty::{ self, Const, DelayedMap, FallibleTypeFolder, InferConst, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; +use rustc_type_ir::PredicateProxy; use super::{FixupError, FixupResult, InferCtxt}; use crate::infer::TyOrConstInferVar; @@ -57,7 +58,7 @@ impl<'a, 'tcx> TypeFolder> for OpportunisticVarResolver<'a, 'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if !p.has_non_region_infer() { p } else { p.super_fold_with(self) } } diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs index 74b4adda7fdd4..e1e138374209c 100644 --- a/compiler/rustc_middle/src/ty/erase_regions.rs +++ b/compiler/rustc_middle/src/ty/erase_regions.rs @@ -1,3 +1,4 @@ +use rustc_type_ir::PredicateProxy; use tracing::debug; use crate::query::Providers; @@ -79,7 +80,7 @@ impl<'tcx> TypeFolder> for RegionEraserAndAnonymizerVisitor<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_type_flags(TypeFlags::HAS_BINDER_VARS | TypeFlags::HAS_FREE_REGIONS) { p.super_fold_with(self) } else { diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs index 3d9148d6ed7ba..c19cda4f3edea 100644 --- a/compiler/rustc_middle/src/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -1,5 +1,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_hir::def_id::DefId; +use rustc_type_ir::PredicateProxy; use rustc_type_ir::data_structures::DelayedMap; use crate::ty::{ @@ -180,7 +181,7 @@ where } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index eb3a53d8fa968..0ea7e403ee111 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -9,14 +9,14 @@ use rustc_abi::TyAndLayout; use rustc_hir::def::Namespace; use rustc_hir::def_id::LocalDefId; use rustc_span::Spanned; -use rustc_type_ir::{ConstKind, TypeFolder, VisitorResult, try_visit}; +use rustc_type_ir::{ConstKind, PredicateProxy, TypeFolder, Upcast, VisitorResult, try_visit}; use super::{GenericArg, GenericArgKind, Pattern}; use crate::mir::PlaceElem; use crate::ty::print::{FmtPrinter, Printer, with_no_trimmed_paths}; use crate::ty::{ - self, FallibleTypeFolder, Lift, Term, TermKind, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, - TypeSuperVisitable, TypeVisitable, TypeVisitor, + self, Binder, FallibleTypeFolder, Lift, ProjectionClause, Term, TermKind, Ty, TyCtxt, + TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitor, }; impl fmt::Debug for ty::TraitDef { @@ -491,17 +491,84 @@ impl<'tcx> TypeFoldable> for ty::Predicate<'tcx> { } } +impl<'tcx> PredicateProxy> for ty::Predicate<'tcx> { + fn allow_normalization(&self) -> bool { + rustc_type_ir::inherent::Predicate::allow_normalization(*self) + } + + fn map_projection( + self, + tcx: TyCtxt<'tcx>, + f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>, + ) -> Option { + self.as_projection_clause().map(|kind| f(kind).upcast(tcx)) + } + + fn clause_kind_unchecked(&self) -> Option>> { + self.as_clause().map(|clause| clause.kind()) + } +} + // FIXME(clause): This is wonky impl<'tcx> TypeFoldable> for ty::Clause<'tcx> { fn try_fold_with>>( self, folder: &mut F, ) -> Result { - Ok(folder.try_fold_predicate(self.as_predicate())?.expect_clause()) + Ok(folder.try_fold_predicate(self)?) } fn fold_with>>(self, folder: &mut F) -> Self { - folder.fold_predicate(self.as_predicate()).expect_clause() + folder.fold_predicate(self) + } +} + +// follow `Predicate`'s implementation (by deferring to it) +impl<'tcx> TypeSuperFoldable> for ty::Clause<'tcx> { + fn try_super_fold_with>>( + self, + folder: &mut F, + ) -> Result { + as TypeSuperFoldable>>::try_super_fold_with( + self.as_predicate(), + folder, + ) + .map(|i| i.expect_clause()) + } + + fn super_fold_with>>(self, folder: &mut F) -> Self { + as TypeSuperFoldable>>::super_fold_with( + self.as_predicate(), + folder, + ) + .expect_clause() + } +} + +impl<'tcx> TypeSuperVisitable> for ty::Clause<'tcx> { + fn super_visit_with>>(&self, visitor: &mut V) -> V::Result { + as TypeSuperVisitable>>::super_visit_with( + &self.as_predicate(), + visitor, + ) + } +} + +impl<'tcx> PredicateProxy> for ty::Clause<'tcx> { + fn allow_normalization(&self) -> bool { + self.as_predicate().allow_normalization() + } + + fn map_projection( + self, + tcx: TyCtxt<'tcx>, + f: impl FnOnce(Binder<'tcx, ProjectionClause<'tcx>>) -> Binder<'tcx, ProjectionClause<'tcx>>, + ) -> Option { + self.as_projection_clause().map(|kind| f(kind).upcast(tcx)) + } + + fn clause_kind_unchecked(&self) -> Option>> { + Some(self.kind()) } } diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 622086b56c638..5361d9268f6a6 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -15,6 +15,7 @@ use rustc_index::bit_set::GrowableBitSet; use rustc_macros::{StableHash, TyDecodable, TyEncodable, extension}; use rustc_span::sym; use rustc_structures::Limit; +use rustc_type_ir::PredicateProxy; use rustc_type_ir::solve::SizedTraitKind; use smallvec::{SmallVec, smallvec}; use tracing::{debug, instrument}; @@ -27,7 +28,7 @@ use crate::traits::ObligationCause; use crate::ty::layout::{FloatExt, IntegerExt}; use crate::ty::{ self, Asyncness, FallibleTypeFolder, GenericArgKind, GenericArgsRef, Ty, TyCtxt, TypeFoldable, - TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized, Upcast, + TypeFolder, TypeSuperFoldable, TypeVisitableExt, Unnormalized, }; #[derive(Copy, Clone, Debug)] @@ -1037,24 +1038,23 @@ impl<'tcx> TypeFolder> for OpaqueTypeExpander<'tcx> { } } - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { - if let ty::PredicateKind::Clause(clause) = p.kind().skip_binder() - && let ty::ClauseKind::Projection(projection_pred) = clause - { - p.kind() - .rebind(ty::ProjectionClause { - projection_term: projection_pred.projection_term.fold_with(self), - // Don't fold the term on the RHS of the projection predicate. - // This is because for default trait methods with RPITITs, we - // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` - // predicate, which would trivially cause a cycle when we do - // anything that requires `TypingEnv::with_post_analysis_normalized`. - term: projection_pred.term, - }) - .upcast(self.tcx) - } else { - p.super_fold_with(self) - } + fn fold_predicate>>(&mut self, p: P) -> P { + // We use `map_projection` to execute the closure only if `p` is a projection clause, + // to implement the logic described below (i.e. avoid folding the `term`). + // In all other cases, fold recursively, as normal. + p.map_projection(self.tcx, |bound_clause| { + let projection_clause = bound_clause.skip_binder(); + bound_clause.rebind(ty::ProjectionClause { + projection_term: projection_clause.projection_term.fold_with(self), + // Don't fold the term on the RHS of the projection predicate. + // This is because for default trait methods with RPITITs, we + // install a `NormalizesTo(Projection(RPITIT) -> Opaque(RPITIT))` + // predicate, which would trivially cause a cycle when we do + // anything that requires `TypingEnv::with_post_analysis_normalized`. + term: projection_clause.term, + }) + }) + .unwrap_or_else(|| p.super_fold_with(self)) } } diff --git a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs index cf36b1922b8c1..6047966248bb2 100644 --- a/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs +++ b/compiler/rustc_next_trait_solver/src/canonical/canonicalizer.rs @@ -5,8 +5,8 @@ use rustc_type_ir::inherent::*; use rustc_type_ir::solve::{Goal, QueryInput}; use rustc_type_ir::{ self as ty, Canonical, CanonicalParamEnvCacheEntry, CanonicalVarKind, CanonicalizerState, - Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, Region, TypeFlags, - TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + Flags, InferCtxtLike, Interner, PlaceholderConst, PlaceholderType, PredicateProxy, Region, + TypeFlags, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use thin_vec::ThinVec; @@ -583,7 +583,7 @@ impl, I: Interner> TypeFolder for Canonicaliz Const::new_canonical_bound(self.cx(), var) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if !p.flags().intersects(NEEDS_CANONICAL) { p } else { p.super_fold_with(self) } } diff --git a/compiler/rustc_next_trait_solver/src/normalize.rs b/compiler/rustc_next_trait_solver/src/normalize.rs index ff9ed6cb06cfd..1fd62213b735a 100644 --- a/compiler/rustc_next_trait_solver/src/normalize.rs +++ b/compiler/rustc_next_trait_solver/src/normalize.rs @@ -2,8 +2,8 @@ use std::fmt::Debug; use rustc_type_ir::inherent::*; use rustc_type_ir::{ - self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, TypeFoldable, - TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars, + self as ty, AliasTerm, Binder, FallibleTypeFolder, InferCtxtLike, Interner, PredicateProxy, + TypeFoldable, TypeSuperFoldable, TypeVisitableExt, UniverseIndex, eager_resolve_vars, }; use tracing::instrument; @@ -197,7 +197,7 @@ where Ok(normalized) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + fn try_fold_predicate>(&mut self, p: P) -> Result { if p.allow_normalization() { p.try_super_fold_with(self) } else { Ok(p) } } } diff --git a/compiler/rustc_next_trait_solver/src/placeholder.rs b/compiler/rustc_next_trait_solver/src/placeholder.rs index 83b2eb6ac6295..e24037e2da7cd 100644 --- a/compiler/rustc_next_trait_solver/src/placeholder.rs +++ b/compiler/rustc_next_trait_solver/src/placeholder.rs @@ -4,7 +4,7 @@ use rustc_type_ir::data_structures::IndexMap; use rustc_type_ir::inherent::*; use rustc_type_ir::{ self as ty, InferCtxtLike, Interner, PlaceholderConst, PlaceholderRegion, PlaceholderType, - Region, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, + PredicateProxy, Region, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt, }; use tracing::debug; @@ -183,7 +183,7 @@ where } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 697a7ad53464b..ae5cf61aac91e 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -18,8 +18,9 @@ use rustc_type_ir::solve::{ }; use rustc_type_ir::{ self as ty, CanonicalVarValues, ClauseKind, InferCtxtLike, Interner, MayBeErased, - OpaqueTypeKey, PredicateKind, Region, RegionVid, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, eager_resolve_vars, max_universe, + OpaqueTypeKey, PredicateKind, PredicateProxy, Region, RegionVid, TypeFoldable, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, + eager_resolve_vars, max_universe, }; use thin_vec::ThinVec; use tracing::{Level, debug, instrument, trace, warn}; @@ -1177,7 +1178,7 @@ where } } - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, p: P) -> Self::Result { if p.has_non_region_infer() || p.has_placeholders() { p.super_visit_with(self) } else { diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 9f1ff3fa6bc6b..5eea894c19c37 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -31,8 +31,8 @@ use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, use rustc_middle::query::Providers; use rustc_middle::ty::print::PrintTraitRefExt as _; use rustc_middle::ty::{ - self, AssocContainer, Const, GenericParamDefKind, TraitRef, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitor, + self, AssocContainer, Const, GenericParamDefKind, PredicateProxy, TraitRef, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitor, }; use rustc_middle::{bug, span_bug}; use rustc_span::{Ident, Span, Symbol, sym}; @@ -130,8 +130,8 @@ where } } - fn visit_clause(&mut self, clause: ty::Clause<'tcx>) -> V::Result { - match clause.kind().skip_binder() { + fn visit_clause(&mut self, clause: ty::Binder<'tcx, ty::ClauseKind<'tcx>>) -> V::Result { + match clause.skip_binder() { ty::ClauseKind::Trait(ty::TraitClause { trait_ref, polarity: _ }) => { self.visit_trait(trait_ref) } @@ -160,7 +160,7 @@ where fn visit_clauses(&mut self, clauses: &[(ty::Clause<'tcx>, Span)]) -> V::Result { for &(clause, _) in clauses { - try_visit!(self.visit_clause(clause)); + try_visit!(self.visit_clause(clause.kind())); } V::Result::output() } @@ -172,8 +172,8 @@ where { type Result = V::Result; - fn visit_predicate(&mut self, p: ty::Predicate<'tcx>) -> Self::Result { - self.visit_clause(p.as_clause().unwrap()) + fn visit_predicate>>(&mut self, p: P) -> Self::Result { + self.visit_clause(p.clause_kind_unchecked().unwrap()) } fn visit_ty(&mut self, ty: Ty<'tcx>) -> Self::Result { diff --git a/compiler/rustc_trait_selection/src/traits/normalize.rs b/compiler/rustc_trait_selection/src/traits/normalize.rs index 56df5d917e108..2d2c4ff38acee 100644 --- a/compiler/rustc_trait_selection/src/traits/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/normalize.rs @@ -10,8 +10,8 @@ use rustc_macros::extension; use rustc_middle::span_bug; use rustc_middle::traits::{ObligationCause, ObligationCauseCode}; use rustc_middle::ty::{ - self, AliasTerm, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitable, - TypeVisitableExt, TypingMode, Unnormalized, + self, AliasTerm, PredicateProxy, Term, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, + TypeVisitable, TypeVisitableExt, TypingMode, Unnormalized, }; use thin_vec::ThinVec; use tracing::{debug, instrument}; @@ -512,7 +512,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } #[inline] - fn fold_predicate(&mut self, p: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate>>(&mut self, p: P) -> P { if p.allow_normalization() && needs_normalization(self.selcx.infcx, &p) { p.super_fold_with(self) } else { diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 96e41f89be573..c4994fa5c4b7a 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -7,7 +7,7 @@ use rustc_infer::traits::PredicateObligations; use rustc_macros::extension; pub use rustc_middle::traits::query::NormalizationResult; use rustc_middle::ty::{ - self, FallibleTypeFolder, Flags, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, + self, FallibleTypeFolder, Flags, PredicateProxy, Ty, TyCtxt, TypeFoldable, TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, TypingMode, Unnormalized, }; use rustc_span::DUMMY_SP; @@ -290,10 +290,10 @@ impl<'a, 'tcx> FallibleTypeFolder> for QueryNormalizer<'a, 'tcx> { } #[inline] - fn try_fold_predicate( + fn try_fold_predicate>>( &mut self, - p: ty::Predicate<'tcx>, - ) -> Result, Self::Error> { + p: P, + ) -> Result { if p.allow_normalization() && needs_normalization(self.infcx, &p) { p.try_super_fold_with(self) } else { diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs index 5fc9e57795b72..1dc5470d58af7 100644 --- a/compiler/rustc_trait_selection/src/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -10,8 +10,8 @@ use rustc_hir::attrs::lang_items::LangItem; use rustc_infer::traits::{ObligationCauseCode, PredicateObligation, PredicateObligations}; use rustc_middle::bug; use rustc_middle::ty::{ - self, DelayedSet, GenericArgsRef, Term, TermKind, Ty, TyCtxt, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, DelayedSet, GenericArgsRef, PredicateProxy, Term, TermKind, Ty, TyCtxt, + TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, }; use rustc_session::diagnostics::feature_err; use rustc_span::def_id::{DefId, LocalDefId}; @@ -1240,7 +1240,7 @@ impl<'a, 'tcx> TypeVisitor> for WfPredicates<'a, 'tcx> { c.super_visit_with(self) } - fn visit_predicate(&mut self, _p: ty::Predicate<'tcx>) -> Self::Result { + fn visit_predicate>>(&mut self, _p: P) -> Self::Result { bug!("predicate should not be checked for well-formedness"); } } diff --git a/compiler/rustc_type_ir/src/binder.rs b/compiler/rustc_type_ir/src/binder.rs index 7fc29cd8ebcf1..a16610a520406 100644 --- a/compiler/rustc_type_ir/src/binder.rs +++ b/compiler/rustc_type_ir/src/binder.rs @@ -15,7 +15,9 @@ use crate::data_structures::SsoHashSet; use crate::fold::{FallibleTypeFolder, TypeFoldable, TypeFolder, TypeSuperFoldable}; use crate::inherent::*; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor}; -use crate::{self as ty, DebruijnIndex, Interner, Region, UniverseIndex, Unnormalized}; +use crate::{ + self as ty, DebruijnIndex, Interner, PredicateProxy, Region, UniverseIndex, Unnormalized, +}; /// `Binder` is a binder for higher-ranked lifetimes or types. It is part of the /// compiler's representation for things like `for<'a> Fn(&'a isize)` @@ -747,7 +749,7 @@ impl<'a, I: Interner> TypeFolder for ArgFolder<'a, I> { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_param() { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs index f57a9aba69302..2b25de4132e62 100644 --- a/compiler/rustc_type_ir/src/fold.rs +++ b/compiler/rustc_type_ir/src/fold.rs @@ -55,7 +55,10 @@ use tracing::{debug, instrument}; use crate::inherent::*; use crate::visit::{TypeVisitable, TypeVisitableExt as _}; -use crate::{self as ty, BoundVarIndexKind, Interner, Region}; +use crate::{ + self as ty, Binder, BoundVarIndexKind, ClauseKind, Flags, Interner, ProjectionClause, Region, + TypeSuperVisitable, +}; /// This trait is implemented for every type that can be folded, /// providing the skeleton of the traversal. @@ -145,7 +148,7 @@ pub trait TypeFolder: Sized { c.super_fold_with(self) } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { p.super_fold_with(self) } @@ -154,6 +157,33 @@ pub trait TypeFolder: Sized { } } +/// [Fold predicate](TypeFolder::fold_predicate) deliberately doesn't get access +/// to an actual predicate. This way, we can compress lists of predicates, and hide +/// this detail to folders. Instead, some type implementing this trait, [`PredicateProxy`] +/// is passed, with its limited API. +/// +/// Most [`TypeFolder`]s only use `fold_predicate` to inspect type flags. +pub trait PredicateProxy: + TypeSuperFoldable + TypeSuperVisitable + Flags + Copy +{ + fn allow_normalization(&self) -> bool; + + /// Gets the underlying clause kind (if this predicate is a clause, otherwise `None`). + /// The fact that it's `unchecked`, is because no attempt is made to hide implementation + /// details. For example, in the future we may compress clauses together. Code calling + /// `clause_kind_unchecked` will have to correctly deal with these implementation details, + /// and have code handling any edgecase arising as a result. + fn clause_kind_unchecked(&self) -> Option>>; + + /// If self is a projection clause, call `f` with it. The result will be rebound and returned as `Some`. + /// Otherwise, when self is not a projection clause, `None` is returned. + fn map_projection( + self, + cx: I, + f: impl FnOnce(Binder>) -> Binder>, + ) -> Option; +} + /// This trait is implemented for every folding traversal. There is a fold /// method defined for every type of interest. Each such method has a default /// that does an "identity" fold. @@ -187,7 +217,7 @@ pub trait FallibleTypeFolder: Sized { c.try_super_fold_with(self) } - fn try_fold_predicate(&mut self, p: I::Predicate) -> Result { + fn try_fold_predicate>(&mut self, p: P) -> Result { p.try_super_fold_with(self) } @@ -430,7 +460,7 @@ impl TypeFolder for Shifter { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_vars_bound_at_or_above(self.current_index) { p.super_fold_with(self) } else { p } } @@ -546,7 +576,7 @@ where if ct.has_regions() { ct.super_fold_with(self) } else { ct } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_regions() { p.super_fold_with(self) } else { p } } @@ -692,7 +722,7 @@ impl TypeFolder for RigidnessFolder { } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if self.mode.needs_change(&p) { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/infer_ctxt.rs b/compiler/rustc_type_ir/src/infer_ctxt.rs index 31fe3cf99d88c..8d1d3372fac69 100644 --- a/compiler/rustc_type_ir/src/infer_ctxt.rs +++ b/compiler/rustc_type_ir/src/infer_ctxt.rs @@ -11,8 +11,8 @@ use crate::relate::RelateResult; use crate::relate::combine::PredicateEmittingRelation; use crate::solve::{TyOrConstInferVar, VisibleForLeakCheck}; use crate::{ - self as ty, Interner, Region, TyVid, TypeFoldable, TypeFolder, TypeSuperFoldable, - TypeVisitableExt, + self as ty, Interner, PredicateProxy, Region, TyVid, TypeFoldable, TypeFolder, + TypeSuperFoldable, TypeVisitableExt, }; mod private { @@ -717,7 +717,7 @@ impl, I: Interner> TypeFolder for EagerRes } } - fn fold_predicate(&mut self, p: I::Predicate) -> I::Predicate { + fn fold_predicate>(&mut self, p: P) -> P { if p.has_infer() { p.super_fold_with(self) } else { p } } diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs index 360687f530690..1138d8cf9edad 100644 --- a/compiler/rustc_type_ir/src/visit.rs +++ b/compiler/rustc_type_ir/src/visit.rs @@ -52,7 +52,7 @@ use smallvec::SmallVec; use thin_vec::ThinVec; use crate::inherent::*; -use crate::{self as ty, Interner, Region, TypeFlags}; +use crate::{self as ty, Interner, PredicateProxy, Region, TypeFlags}; /// This trait is implemented for every type that can be visited, /// providing the skeleton of the traversal. @@ -116,7 +116,7 @@ pub trait TypeVisitor: Sized { c.super_visit_with(self) } - fn visit_predicate(&mut self, p: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, p: P) -> Self::Result { p.super_visit_with(self) } @@ -485,7 +485,7 @@ impl TypeVisitor for HasTypeFlagsVisitor { } #[inline] - fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, predicate: P) -> Self::Result { // Note: no `super_visit_with` call. if predicate.flags().intersects(self.flags) { ControlFlow::Break(FoundFlags) @@ -597,7 +597,7 @@ impl TypeVisitor for HasEscapingVarsVisitor { } #[inline] - fn visit_predicate(&mut self, predicate: I::Predicate) -> Self::Result { + fn visit_predicate>(&mut self, predicate: P) -> Self::Result { if predicate.outer_exclusive_binder() > self.outer_index { ControlFlow::Break(FoundEscapingVars) } else { From a80f20df1ed7121908b65abfa6393beeaae7d702 Mon Sep 17 00:00:00 2001 From: Joao Roberto Date: Tue, 8 Sep 2026 11:28:36 -0300 Subject: [PATCH 13/13] Keep type-op region constraints in borrowck Under `-Zassumptions-on-binders` the next solver stores its region constraints in the `InferCtxt` instead of registering region obligations. The canonical type-op path never copied them into `QueryResponse`, so they were dropped once the query's inference context went away. Borrowck then saw a type op with no constraints and lost the outlives error entirely. `QueryRegionConstraints` now carries the constraint next to the old style constraints and assumptions. It stays unspanned while passing through a canonical query and the caller attaches its own origin span when consuming the response. Borrowck accumulates these in `MirTypeckRegionConstraints` through `ConstraintConversion`, the same way it handles everything else, and destructures them into NLL outlives constraints at the end of MIR type checking. Implied bound normalization was dropping the same constraint before lexical regionck, so that path registers it now as well. --- .../rustc_borrowck/src/handle_placeholders.rs | 8 +++ .../src/type_check/constraint_conversion.rs | 6 ++- compiler/rustc_borrowck/src/type_check/mod.rs | 30 +++++++++++ .../src/infer/canonical/query_response.rs | 52 ++++++++++++------- .../src/infer/outlives/obligations.rs | 11 ++-- .../src/infer/solver_region_constraints.rs | 19 ++++++- .../infer/solver_region_constraints/tests.rs | 22 ++++++++ compiler/rustc_middle/src/infer/canonical.rs | 29 +++++++++-- .../src/solve/delegate.rs | 5 ++ .../src/traits/outlives_bounds.rs | 5 +- .../src/traits/query/type_op/custom.rs | 11 +++- .../src/traits/query/type_op/mod.rs | 5 +- .../rustc_traits/src/coroutine_witnesses.rs | 4 ++ .../assumptions_on_binders/alias_outlives.rs | 28 +++++++++- .../alias_outlives.stderr | 17 +++++- 15 files changed, 215 insertions(+), 37 deletions(-) diff --git a/compiler/rustc_borrowck/src/handle_placeholders.rs b/compiler/rustc_borrowck/src/handle_placeholders.rs index 11b8890346dfb..bdb30090925d0 100644 --- a/compiler/rustc_borrowck/src/handle_placeholders.rs +++ b/compiler/rustc_borrowck/src/handle_placeholders.rs @@ -246,8 +246,16 @@ pub(crate) fn compute_sccs_applying_placeholder_outlives_constraints<'tcx>( mut outlives_constraints, universe_causes, type_tests, + solver_constraints, } = constraints; + // These have already been destructured into `outlives_constraints` at the + // end of MIR type checking. + assert!( + solver_constraints.is_true(), + "solver region constraints not lowered to NLL = {solver_constraints:#?}", + ); + let fr_static = universal_regions.fr_static; let compute_sccs = |constraints: &OutlivesConstraintSet<'tcx>, diff --git a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs index f845d9137f759..f11e3b8fd6d80 100644 --- a/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs +++ b/compiler/rustc_borrowck/src/type_check/constraint_conversion.rs @@ -68,7 +68,8 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { #[instrument(skip(self), level = "debug")] pub(super) fn convert_all(&mut self, query_constraints: &QueryRegionConstraints<'tcx>) { - let QueryRegionConstraints { constraints, assumptions } = query_constraints; + let QueryRegionConstraints { constraints, assumptions, solver_constraints } = + query_constraints; let assumptions = elaborate::elaborate_outlives_assumptions(self.infcx.tcx, assumptions.iter().copied()); @@ -77,6 +78,9 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { self.convert(predicate, category, &assumptions); }); } + + self.constraints + .register_solver_constraint(solver_constraints.clone().with_spans(self.span)); } /// Given an instance of the closure type, this method instantiates the "extra" requirements diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 9f23a0d5ab631..ed080c26d60f3 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -17,6 +17,7 @@ use rustc_infer::infer::outlives::env::RegionBoundPairs; use rustc_infer::infer::region_constraints::RegionConstraintData; use rustc_infer::infer::{ BoundRegionConversionTime, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, + SolverRegionConstraint, }; use rustc_infer::traits::{Obligation, ObligationCause, PredicateObligations}; use rustc_middle::bug; @@ -113,6 +114,7 @@ pub(crate) fn type_check<'tcx>( outlives_constraints: OutlivesConstraintSet::default(), type_tests: Vec::default(), universe_causes: FxIndexMap::default(), + solver_constraints: SolverRegionConstraint::new_true(), }; let CreateResult { @@ -134,6 +136,13 @@ pub(crate) fn type_check<'tcx>( pre_assumptions.is_empty(), "there should be no incoming region assumptions = {pre_assumptions:#?}", ); + // Solver region constraints from computing the implied bounds went through + // `ConstraintConversion` and are already stored in `constraints`. + let pre_solver_constraints = infcx.take_solver_region_constraints(); + assert!( + pre_solver_constraints.is_true(), + "there should be no incoming solver region constraints = {pre_solver_constraints:#?}", + ); } debug!(?normalized_inputs_and_output); @@ -174,6 +183,10 @@ pub(crate) fn type_check<'tcx>( let polonius_context = typeck.polonius_context; if infcx.tcx.assumptions_on_binders() { + let solver_constraints = mem::replace( + &mut typeck.constraints.solver_constraints, + SolverRegionConstraint::new_true(), + ); let mut converter = constraint_conversion::ConstraintConversion::new( typeck.infcx, typeck.universal_regions, @@ -185,6 +198,7 @@ pub(crate) fn type_check<'tcx>( typeck.constraints, ); typeck.infcx.destructure_solver_region_constraints_for_borrowck( + solver_constraints, &mut converter, typeck.known_type_outlives_obligations, universal_region_relations.outlives.clone(), @@ -293,9 +307,25 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { pub(crate) universe_causes: FxIndexMap>, pub(crate) type_tests: Vec>, + + /// The region constraints emitted by the next solver under + /// `-Zassumptions-on-binders`. Unlike the constraints above these are not yet + /// lowered to NLL, we destructure them into `outlives_constraints` at the end + /// of MIR type checking. + pub(crate) solver_constraints: SolverRegionConstraint<'tcx>, } impl<'tcx> MirTypeckRegionConstraints<'tcx> { + /// Adds `constraint` to the constraints we've accumulated so far. + pub(crate) fn register_solver_constraint(&mut self, constraint: SolverRegionConstraint<'tcx>) { + // FIXME(-Zassumptions-on-binders): This is pretty bad for perf, we rebuild the + // entire constraint every time instead of updating it incrementally. + self.solver_constraints = SolverRegionConstraint::build_and( + constraint, + mem::replace(&mut self.solver_constraints, SolverRegionConstraint::new_true()), + ); + } + /// Creates a `Region` for a given `PlaceholderRegion`, or returns the /// region that corresponds to a previously created one. pub(crate) fn placeholder_region( diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs index cd35af8be73cf..d1c4480b59347 100644 --- a/compiler/rustc_infer/src/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -146,11 +146,13 @@ impl<'tcx> InferCtxt<'tcx> { let region_obligations = self.take_registered_region_obligations(); let region_assumptions = self.take_registered_region_assumptions(); debug!(?region_obligations); + let solver_constraints = self.take_solver_region_constraints(); let region_constraints = self.with_region_constraints(|region_constraints| { make_query_region_constraints( region_obligations, region_constraints, region_assumptions, + solver_constraints, ) }); debug!(?region_constraints); @@ -195,9 +197,10 @@ impl<'tcx> InferCtxt<'tcx> { let InferOk { value: result_args, obligations } = self.query_response_instantiation(cause, param_env, original_values, query_response)?; - for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in - &query_response.value.region_constraints.constraints - { + let QueryRegionConstraints { constraints, assumptions, solver_constraints } = + &query_response.value.region_constraints; + + for QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in constraints { let constraint = instantiate_value(self.tcx, &result_args, *constraint); match constraint { ty::RegionConstraint::Outlives(clause) => { @@ -209,11 +212,15 @@ impl<'tcx> InferCtxt<'tcx> { } } - for assumption in &query_response.value.region_constraints.assumptions { + for assumption in assumptions { let assumption = instantiate_value(self.tcx, &result_args, *assumption); self.register_region_assumption(assumption); } + let solver_constraints = + instantiate_value(self.tcx, &result_args, solver_constraints.clone()); + self.register_solver_region_constraint(solver_constraints.with_spans(cause.span)); + let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -325,27 +332,31 @@ impl<'tcx> InferCtxt<'tcx> { } } + let QueryRegionConstraints { constraints, assumptions, solver_constraints } = + &query_response.value.region_constraints; + // ...also include the other query region constraints from the query. - output_query_region_constraints.constraints.extend( - query_response.value.region_constraints.constraints.iter().filter_map(|&r_c| { - let r_c = instantiate_value(self.tcx, &result_args, r_c); + output_query_region_constraints.constraints.extend(constraints.iter().filter_map(|&r_c| { + let r_c = instantiate_value(self.tcx, &result_args, r_c); - // Screen out `'a: 'a` or `'a == 'a` cases. - if r_c.constraint.is_trivial() { None } else { Some(r_c) } - }), - ); + // Screen out `'a: 'a` or `'a == 'a` cases. + if r_c.constraint.is_trivial() { None } else { Some(r_c) } + })); // FIXME(higher_ranked_auto): Optimize this to instantiate all assumptions // at once, rather than calling `instantiate_value` repeatedly which may // create more universes. - output_query_region_constraints.assumptions.extend( - query_response - .value - .region_constraints - .assumptions - .iter() - .map(|&r_c| instantiate_value(self.tcx, &result_args, r_c)), - ); + output_query_region_constraints + .assumptions + .extend(assumptions.iter().map(|&r_c| instantiate_value(self.tcx, &result_args, r_c))); + + let solver_constraints = + instantiate_value(self.tcx, &result_args, solver_constraints.clone()); + output_query_region_constraints.solver_constraints = + ty::region_constraint::RegionConstraint::build_and( + std::mem::take(&mut output_query_region_constraints.solver_constraints), + solver_constraints, + ); let user_result: R = query_response.instantiate_projected(self.tcx, &result_args, |q_r| q_r.value.clone()); @@ -619,6 +630,7 @@ pub fn make_query_region_constraints<'tcx>( outlives_obligations: Vec>, region_constraints: &RegionConstraintData<'tcx>, assumptions: Vec>, + solver_constraints: ty::region_constraint::RegionConstraint>, ) -> QueryRegionConstraints<'tcx> { let RegionConstraintData { constraints, verifys } = region_constraints; @@ -663,5 +675,5 @@ pub fn make_query_region_constraints<'tcx>( )) .collect(); - QueryRegionConstraints { constraints, assumptions } + QueryRegionConstraints { constraints, assumptions, solver_constraints } } diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs index 42f686b39136b..c7fafd00ce740 100644 --- a/compiler/rustc_infer/src/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -238,11 +238,16 @@ impl<'tcx> InferCtxt<'tcx> { outlives_env.known_type_outlives().into_iter().cloned().collect(), outlives_env.free_region_map().relation.clone(), ); - self.destructure_solver_region_constraints(assumptions, self); + let constraint = self.inner.borrow().solver_region_constraint_storage.get_constraint(); + self.destructure_solver_region_constraints(constraint, assumptions, self); } + /// Unlike regionck, borrowck doesn't keep these constraints in the `InferCtxt`. + /// It stores them in `MirTypeckRegionConstraints` alongside its other region + /// constraints, so it hands us the constraint to destructure. pub fn destructure_solver_region_constraints_for_borrowck( &self, + constraint: SolverRegionConstraint<'tcx>, // this is always ConstraintConversion but lol conversion: impl TypeOutlivesDelegate<'tcx>, known_type_outlives: &[PolyTypeOutlivesClause<'tcx>], @@ -252,19 +257,19 @@ impl<'tcx> InferCtxt<'tcx> { known_type_outlives.into_iter().cloned().collect(), region_outlives.maybe_map(|r| Some(Region::new_var(self.tcx, r))).unwrap(), ); - self.destructure_solver_region_constraints(assumptions, conversion); + self.destructure_solver_region_constraints(constraint, assumptions, conversion); } #[instrument(level = "debug", skip(self, conversion))] pub fn destructure_solver_region_constraints( &self, + constraint: SolverRegionConstraint<'tcx>, assumptions: rustc_type_ir::region_constraint::Assumptions>, mut conversion: impl TypeOutlivesDelegate<'tcx>, ) { assert!(self.tcx.assumptions_on_binders()); assert!(self.next_trait_solver()); - let constraint = self.inner.borrow().solver_region_constraint_storage.get_constraint(); debug!(?constraint); let constraint = region_constraint::destructure_type_outlives_constraints_in_root( self, diff --git a/compiler/rustc_infer/src/infer/solver_region_constraints.rs b/compiler/rustc_infer/src/infer/solver_region_constraints.rs index 09baae2ca8a42..965ccf70442b8 100644 --- a/compiler/rustc_infer/src/infer/solver_region_constraints.rs +++ b/compiler/rustc_infer/src/infer/solver_region_constraints.rs @@ -1,9 +1,11 @@ use rustc_middle::ty::TyCtxt; use rustc_span::Span; +use rustc_type_ir::region_constraint::RegionConstraint; use tracing::instrument; -pub type SolverRegionConstraint<'tcx> = - rustc_type_ir::region_constraint::RegionConstraint, Span>; +use super::InferCtxt; + +pub type SolverRegionConstraint<'tcx> = RegionConstraint, Span>; #[derive(Clone, Debug)] pub(crate) struct SolverRegionConstraintStorage<'tcx>(SolverRegionConstraint<'tcx>); @@ -17,11 +19,24 @@ impl<'tcx> SolverRegionConstraintStorage<'tcx> { self.0.clone() } + pub(crate) fn take(&mut self) -> SolverRegionConstraint<'tcx> { + core::mem::replace(&mut self.0, SolverRegionConstraint::new_true()) + } + #[instrument(level = "debug", skip(self))] pub(crate) fn overwrite(&mut self, constraint: SolverRegionConstraint<'tcx>) { self.0 = constraint; } } +impl<'tcx> InferCtxt<'tcx> { + /// Trait queries just want to pass back the solver region constraints "as is", + /// mirroring `take_registered_region_obligations`. + pub fn take_solver_region_constraints(&self) -> RegionConstraint> { + assert!(!self.in_snapshot(), "cannot take solver region constraints in a snapshot"); + self.inner.borrow_mut().solver_region_constraint_storage.take().without_spans() + } +} + #[cfg(test)] mod tests; diff --git a/compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs b/compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs index 529ecf43f5ee1..540aa5e4f8cb2 100644 --- a/compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs +++ b/compiler/rustc_infer/src/infer/solver_region_constraints/tests.rs @@ -1,7 +1,29 @@ +use rustc_middle::infer::canonical::QueryRegionConstraints; use rustc_middle::ty::TyCtxt; use rustc_span::{BytePos, Span}; use rustc_type_ir::region_constraint::{And, LeafRegionConstraint, Or}; +use super::{SolverRegionConstraint, SolverRegionConstraintStorage}; + +#[test] +fn true_constraint_keeps_query_response_empty() { + // Mirrors `register_solver_region_constraint`, which registers unconditionally: + // anding a trivially true constraint into an empty store has to leave the store + // trivially true, as the resulting query response would otherwise no longer be + // empty. This relies on `And`/`Or` being kept in canonical form. + let mut storage = SolverRegionConstraintStorage::<'static>::new(); + storage.overwrite(SolverRegionConstraint::build_and( + SolverRegionConstraint::new_true(), + storage.get_constraint(), + )); + + let constraints = QueryRegionConstraints { + solver_constraints: storage.get_constraint().without_spans(), + ..Default::default() + }; + assert!(constraints.is_empty()); +} + #[test] fn canonicalization_preserves_only_one_ambiguity() { let first = Span::with_root_ctxt(BytePos(1), BytePos(2)); diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs index 46429f7adfb12..f99280bb744a1 100644 --- a/compiler/rustc_middle/src/infer/canonical.rs +++ b/compiler/rustc_middle/src/infer/canonical.rs @@ -76,13 +76,21 @@ pub struct QueryResponse<'tcx, R> { pub value: R, } -#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, Default, PartialEq, Hash)] #[derive(StableHash, TypeFoldable, TypeVisitable)] pub struct QueryRegionConstraints<'tcx> { pub constraints: Vec>, pub assumptions: Vec>, + /// Region constraints emitted by the next solver under + /// `-Zassumptions-on-binders`. + /// + /// These stay unspanned while passing through a canonical query. The type-op + /// caller attaches its origin span when consuming the response. + pub solver_constraints: ir::region_constraint::RegionConstraint>, } +impl Eq for QueryRegionConstraints<'_> {} + impl QueryRegionConstraints<'_> { /// Represents an empty (trivially true) set of region constraints. /// @@ -91,8 +99,23 @@ impl QueryRegionConstraints<'_> { /// discharge a requirement from another query, which is a potential problem if we did throw /// away these assumptions because there were no constraints. pub fn is_empty(&self) -> bool { - let QueryRegionConstraints { constraints, assumptions } = self; - constraints.is_empty() && assumptions.is_empty() + let QueryRegionConstraints { constraints, assumptions, solver_constraints } = self; + constraints.is_empty() && assumptions.is_empty() && solver_constraints.is_true() + } + + pub fn extend(&mut self, other: &Self) { + let QueryRegionConstraints { constraints, assumptions, solver_constraints } = self; + let QueryRegionConstraints { + constraints: other_constraints, + assumptions: other_assumptions, + solver_constraints: other_solver_constraints, + } = other; + constraints.extend(other_constraints.iter().cloned()); + assumptions.extend(other_assumptions.iter().cloned()); + *solver_constraints = ir::region_constraint::RegionConstraint::build_and( + std::mem::take(solver_constraints), + other_solver_constraints.clone(), + ); } } diff --git a/compiler/rustc_trait_selection/src/solve/delegate.rs b/compiler/rustc_trait_selection/src/solve/delegate.rs index 818d8e1a4e0c3..60339b1982233 100644 --- a/compiler/rustc_trait_selection/src/solve/delegate.rs +++ b/compiler/rustc_trait_selection/src/solve/delegate.rs @@ -374,6 +374,11 @@ impl<'tcx> rustc_next_trait_solver::delegate::SolverDelegate for SolverDelegate< region_obligations, region_constraints, region_assumptions, + // We're only called with `-Zassumptions-on-binders` disabled, in which + // case the solver never emits new-style region constraints. With it + // enabled the solver instead returns `ExternalRegionConstraints::NextGen`, + // reading the constraint straight out of the `InferCtxt`. + Default::default(), ) }); diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs index 84cae1e7bfa0a..bcb932f74b1f8 100644 --- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs @@ -82,7 +82,10 @@ fn implied_outlives_bounds<'a, 'tcx>( // FIXME(higher_ranked_auto): Should we register assumptions here? // We otherwise would get spurious errors if normalizing an implied // outlives bound required proving some higher-ranked coroutine obl. - let QueryRegionConstraints { constraints, assumptions: _ } = constraints; + let QueryRegionConstraints { constraints, assumptions: _, solver_constraints } = + constraints; + infcx.register_solver_region_constraint(solver_constraints.with_spans(span)); + let cause = ObligationCause::misc(span, body_def_id); for &QueryRegionConstraint { constraint, visible_for_leak_check: vis, .. } in &constraints { match constraint { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs index 25385d15e36f4..39f439cad64d3 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs @@ -60,8 +60,8 @@ impl fmt::Debug for CustomTypeOp { } } -/// Executes `op` and then scrapes out all the "old style" region -/// constraints that result, creating query-region-constraints. +/// Executes `op` and then scrapes out all resulting region constraints +/// in the `infcx`, creating query-region-constraints. pub fn scrape_region_constraints<'tcx, Op, R>( infcx: &InferCtxt<'tcx>, root_def_id: LocalDefId, @@ -88,6 +88,11 @@ where pre_assumptions.is_empty(), "scrape_region_constraints: incoming region assumptions = {pre_assumptions:#?}", ); + let pre_solver_constraints = infcx.take_solver_region_constraints(); + assert!( + pre_solver_constraints.is_true(), + "scrape_region_constraints: incoming solver constraints = {pre_solver_constraints:#?}", + ); let value = infcx.commit_if_ok(|_| { let ocx = ObligationCtxt::new(infcx); @@ -144,11 +149,13 @@ where let region_obligations = infcx.take_registered_region_obligations(); let region_assumptions = infcx.take_registered_region_assumptions(); + let solver_constraints = infcx.take_solver_region_constraints(); let region_constraint_data = infcx.take_and_reset_region_constraints(); let region_constraints = query_response::make_query_region_constraints( region_obligations, ®ion_constraint_data, region_assumptions, + solver_constraints, ); if region_constraints.is_empty() { diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs index 250579a2b064a..ac516afbc783c 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs @@ -151,9 +151,8 @@ where Ok(output) })?; output.error_info = error_info; - if let Some(QueryRegionConstraints { constraints, assumptions }) = output.constraints { - region_constraints.constraints.extend(constraints.iter().cloned()); - region_constraints.assumptions.extend(assumptions.iter().cloned()); + if let Some(constraints) = output.constraints { + region_constraints.extend(constraints); } output.constraints = if region_constraints.is_empty() { None diff --git a/compiler/rustc_traits/src/coroutine_witnesses.rs b/compiler/rustc_traits/src/coroutine_witnesses.rs index 762471eefe4dd..b7ff4cca0bb1f 100644 --- a/compiler/rustc_traits/src/coroutine_witnesses.rs +++ b/compiler/rustc_traits/src/coroutine_witnesses.rs @@ -84,6 +84,10 @@ fn compute_assumptions<'tcx>( region_obligations, ®ion_constraints, region_assumptions, + // We return early above unless the old solver is used globally, while + // `-Zassumptions-on-binders` enables the next solver globally. So there + // are never any new-style region constraints to pass along here. + Default::default(), ) .constraints .fold_with(&mut OpportunisticRegionResolver::new(&infcx)); diff --git a/tests/ui/assumptions_on_binders/alias_outlives.rs b/tests/ui/assumptions_on_binders/alias_outlives.rs index 0c2ed6585cf45..9e1516132dd9d 100644 --- a/tests/ui/assumptions_on_binders/alias_outlives.rs +++ b/tests/ui/assumptions_on_binders/alias_outlives.rs @@ -23,11 +23,11 @@ where } fn borrowck_env_fail<'a, T: AliasHaver>() -// FIXME: ^ this should raise an ERROR: unsatisfied lifetime constraint from -Zassumptions-on-binders where ::Assoc: 'a, { let _: ReqTrait; + //~^ ERROR: higher-ranked lifetime bound could not be satisfied } const REGIONCK_ENV_PASS<'a, T: AliasHaver>: ReqTrait = todo!() @@ -39,4 +39,30 @@ const REGIONCK_ENV_FAIL<'a, T: AliasHaver>: ReqTrait = todo!() where ::Assoc: 'a; +// Solver constraints produced while normalizing implied bounds must be returned +// to lexical regionck. +trait Project { + type Assoc; +} + +impl Project for (T,) +where + T::Assoc: for<'a> Trait<'a>, +{ + type Assoc = (); +} + +struct Normalizes(T) +where + T::Assoc: Clone; + +trait TestTrait {} + +impl<'a, T: AliasHaver> TestTrait for [Normalizes<(T,)>; 1] +//~^ ERROR: higher-ranked lifetime bound could not be satisfied +where + T::Assoc: 'a, +{ +} + fn main() {} diff --git a/tests/ui/assumptions_on_binders/alias_outlives.stderr b/tests/ui/assumptions_on_binders/alias_outlives.stderr index 1787c1912ae4f..a6eaf3e11bad7 100644 --- a/tests/ui/assumptions_on_binders/alias_outlives.stderr +++ b/tests/ui/assumptions_on_binders/alias_outlives.stderr @@ -4,5 +4,20 @@ error: higher-ranked lifetime bound could not be satisfied LL | const REGIONCK_ENV_FAIL<'a, T: AliasHaver>: ReqTrait = todo!() | ^^^^^^^^^^^^^^^^^^ -error: aborting due to 1 previous error +error: higher-ranked lifetime bound could not be satisfied + --> $DIR/alias_outlives.rs:61:1 + | +LL | / impl<'a, T: AliasHaver> TestTrait for [Normalizes<(T,)>; 1] +LL | | +LL | | where +LL | | T::Assoc: 'a, + | |_________________^ + +error: higher-ranked lifetime bound could not be satisfied + --> $DIR/alias_outlives.rs:29:12 + | +LL | let _: ReqTrait; + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to 3 previous errors