From bd6fca201551382e12f08de37c1f67bc3deb968d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=AE=B8=E6=9D=B0=E5=8F=8B=20Jieyou=20Xu=20=28Joe=29?= Date: Wed, 10 Apr 2024 14:17:16 +0000 Subject: [PATCH 01/18] Clarify `Command::new` behavior if passed programs with arguments --- library/std/src/process.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c926c89f7a97f..f351dab78dc1a 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -629,6 +629,25 @@ impl Command { /// .spawn() /// .expect("sh command failed to start"); /// ``` + /// + /// # Caveats + /// + /// [`Command::new`] is only intended to accept the path of the program. If you pass a program + /// path along with arguments like `Command::new("ls -l").spawn()`, it will try to search for + /// `ls -l` literally. The arguments need to be passed separately, such as via [`arg`] or + /// [`args`]. + /// + /// ```no_run + /// use std::process::Command; + /// + /// Command::new("ls") + /// .arg("-l") // arg passed separately + /// .spawn() + /// .expect("ls command failed to start"); + /// ``` + /// + /// [`arg`]: Self::arg + /// [`args`]: Self::args #[stable(feature = "process", since = "1.0.0")] pub fn new>(program: S) -> Command { Command { inner: imp::Command::new(program.as_ref()) } From 523408e6613dfb2eb5926350cd377f2198c3d9b4 Mon Sep 17 00:00:00 2001 From: Christiaan Biesterbosch Date: Thu, 13 Jun 2024 11:46:42 +0200 Subject: [PATCH 02/18] Fix wording in {checked_}next_power_of_two --- library/core/src/num/nonzero.rs | 2 +- library/core/src/num/uint_macros.rs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 863f0d61df374..5956a08593ad4 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -1059,7 +1059,7 @@ macro_rules! nonzero_integer_signedness_dependent_methods { unsafe { Self::new_unchecked(self.get().unchecked_add(other)) } } - /// Returns the smallest power of two greater than or equal to n. + /// Returns the smallest power of two greater than or equal to `self`. /// Checks for overflow and returns [`None`] /// if the next power of two is greater than the type’s maximum value. /// As a consequence, the result cannot wrap to zero. diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 1491c27372bfb..cdbd695008e86 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -2830,7 +2830,7 @@ macro_rules! uint_impl { /// /// When return value overflows (i.e., `self > (1 << (N-1))` for type /// `uN`), it panics in debug mode and the return value is wrapped to 0 in - /// release mode (the only situation in which method can return 0). + /// release mode (the only situation in which this method can return 0). /// /// # Examples /// @@ -2851,7 +2851,7 @@ macro_rules! uint_impl { self.one_less_than_next_power_of_two() + 1 } - /// Returns the smallest power of two greater than or equal to `n`. If + /// Returns the smallest power of two greater than or equal to `self`. If /// the next power of two is greater than the type's maximum value, /// `None` is returned, otherwise the power of two is wrapped in `Some`. /// From 10c76433e8b06878fffe77eb8864aecaf587c3b6 Mon Sep 17 00:00:00 2001 From: Waffle Lapkin Date: Thu, 13 Jun 2024 12:13:54 +0200 Subject: [PATCH 03/18] Small style improvement in `gvn.rs` --- compiler/rustc_mir_transform/src/gvn.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs index 121a3b99a39ee..0f8f28e3462ab 100644 --- a/compiler/rustc_mir_transform/src/gvn.rs +++ b/compiler/rustc_mir_transform/src/gvn.rs @@ -330,8 +330,7 @@ impl<'body, 'tcx> VnState<'body, 'tcx> { let is_sized = !self.feature_unsized_locals || self.local_decls[local].ty.is_sized(self.tcx, self.param_env); if is_sized { - self.rev_locals.ensure_contains_elem(value, SmallVec::new); - self.rev_locals[value].push(local); + self.rev_locals.ensure_contains_elem(value, SmallVec::new).push(local); } } From 9314831b456b3f17c0849173436531d7d92b2231 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:30:23 +0200 Subject: [PATCH 04/18] Implement `CompletedProcess::assert_stdout_contains` and improve error output --- src/tools/run-make-support/src/command.rs | 10 ++++++++-- src/tools/run-make-support/src/lib.rs | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/tools/run-make-support/src/command.rs b/src/tools/run-make-support/src/command.rs index d689dc2f979a7..5ee58e4e7a951 100644 --- a/src/tools/run-make-support/src/command.rs +++ b/src/tools/run-make-support/src/command.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::process::{Command as StdCommand, ExitStatus, Output, Stdio}; use crate::drop_bomb::DropBomb; -use crate::{assert_not_contains, handle_failed_output}; +use crate::{assert_contains, assert_not_contains, handle_failed_output}; /// This is a custom command wrapper that simplifies working with commands and makes it easier to /// ensure that we check the exit status of executed processes. @@ -167,6 +167,12 @@ impl CompletedProcess { self } + #[track_caller] + pub fn assert_stdout_contains>(self, needle: S) -> Self { + assert_contains(&self.stdout_utf8(), needle.as_ref()); + self + } + #[track_caller] pub fn assert_stdout_not_contains>(&self, needle: S) -> &Self { assert_not_contains(&self.stdout_utf8(), needle.as_ref()); @@ -182,7 +188,7 @@ impl CompletedProcess { #[track_caller] pub fn assert_stderr_contains>(&self, needle: S) -> &Self { - assert!(self.stderr_utf8().contains(needle.as_ref())); + assert_contains(&self.stderr_utf8(), needle.as_ref()); self } diff --git a/src/tools/run-make-support/src/lib.rs b/src/tools/run-make-support/src/lib.rs index 0238255a53f3a..8bb6a8d51d0db 100644 --- a/src/tools/run-make-support/src/lib.rs +++ b/src/tools/run-make-support/src/lib.rs @@ -315,6 +315,18 @@ pub fn read_dir(dir: impl AsRef, callback: F) { } } +/// Check that `haystack` contains `needle`. Panic otherwise. +#[track_caller] +pub fn assert_contains(haystack: &str, needle: &str) { + if !haystack.contains(needle) { + eprintln!("=== HAYSTACK ==="); + eprintln!("{}", haystack); + eprintln!("=== NEEDLE ==="); + eprintln!("{}", needle); + panic!("needle was not found in haystack"); + } +} + /// Check that `haystack` does not contain `needle`. Panic otherwise. #[track_caller] pub fn assert_not_contains(haystack: &str, needle: &str) { From 96f9fe5488e74f8b0f75c993ffbcca2c14ba9d01 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:21:25 +0200 Subject: [PATCH 05/18] Migrate `run-make/allow-non-lint-warnings-cmdline` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - .../allow-non-lint-warnings-cmdline/Makefile | 12 ------------ .../allow-non-lint-warnings-cmdline/rmake.rs | 8 ++++++++ 3 files changed, 8 insertions(+), 13 deletions(-) delete mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/Makefile create mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 37da5d9c88d90..280420d022d66 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -1,5 +1,4 @@ run-make/allocator-shim-circular-deps/Makefile -run-make/allow-non-lint-warnings-cmdline/Makefile run-make/archive-duplicate-names/Makefile run-make/atomic-lock-free/Makefile run-make/branch-protection-check-IBT/Makefile diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile b/tests/run-make/allow-non-lint-warnings-cmdline/Makefile deleted file mode 100644 index 78b9a7b989895..0000000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/Makefile +++ /dev/null @@ -1,12 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test that -A warnings makes the 'empty trait list for derive' warning go away -OUT=$(shell $(RUSTC) foo.rs -A warnings 2>&1 | grep "warning" ) - -all: foo - test -z '$(OUT)' - -# This is just to make sure the above command actually succeeds -foo: - $(RUSTC) foo.rs -A warnings diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs new file mode 100644 index 0000000000000..3866ed3f5be51 --- /dev/null +++ b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs @@ -0,0 +1,8 @@ +// Test that -A warnings makes the 'empty trait list for derive' warning go away. + +use run_make_support::rustc; + +fn main() { + let output = rustc().input("foo.rs").arg("-Awarnings").run(); + output.assert_stderr_not_contains("warning"); +} From eca8d209d9c75ed0ba7ce434d62d9460d42271f5 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 12:52:05 +0200 Subject: [PATCH 06/18] Make `run-make/allow-non-lint-warnings-cmdline` into a ui test --- tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs | 8 -------- .../foo.rs => ui/allow-non-lint-warnings.rs} | 3 +++ 2 files changed, 3 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs rename tests/{run-make/allow-non-lint-warnings-cmdline/foo.rs => ui/allow-non-lint-warnings.rs} (60%) diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs b/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs deleted file mode 100644 index 3866ed3f5be51..0000000000000 --- a/tests/run-make/allow-non-lint-warnings-cmdline/rmake.rs +++ /dev/null @@ -1,8 +0,0 @@ -// Test that -A warnings makes the 'empty trait list for derive' warning go away. - -use run_make_support::rustc; - -fn main() { - let output = rustc().input("foo.rs").arg("-Awarnings").run(); - output.assert_stderr_not_contains("warning"); -} diff --git a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs b/tests/ui/allow-non-lint-warnings.rs similarity index 60% rename from tests/run-make/allow-non-lint-warnings-cmdline/foo.rs rename to tests/ui/allow-non-lint-warnings.rs index 02e8ccabf7921..f8f5a78ebff26 100644 --- a/tests/run-make/allow-non-lint-warnings-cmdline/foo.rs +++ b/tests/ui/allow-non-lint-warnings.rs @@ -1,3 +1,6 @@ +//@ compile-flags: -Awarnings +//@ check-pass + #[derive()] #[derive(Copy, Clone)] pub struct Foo; From 9bff23005dc8cfca8fab4e5edaaf7d910b6c10f3 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Jun 2024 14:05:30 +0200 Subject: [PATCH 07/18] Allow to bless diff tests --- src/tools/run-make-support/src/diff/mod.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index 105cdbc7b3275..d0be57ca9d7c5 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -1,6 +1,6 @@ use regex::Regex; use similar::TextDiff; -use std::path::Path; +use std::path::{Path, PathBuf}; use crate::drop_bomb::DropBomb; @@ -17,6 +17,7 @@ pub fn diff() -> Diff { pub struct Diff { expected: Option, expected_name: Option, + expected_file: Option, actual: Option, actual_name: Option, normalizers: Vec<(String, String)>, @@ -30,6 +31,7 @@ impl Diff { Self { expected: None, expected_name: None, + expected_file: None, actual: None, actual_name: None, normalizers: Vec::new(), @@ -43,6 +45,7 @@ impl Diff { let content = std::fs::read_to_string(path).expect("failed to read file"); let name = path.to_string_lossy().to_string(); + self.expected_file = Some(path.into()); self.expected = Some(content); self.expected_name = Some(name); self @@ -104,6 +107,15 @@ impl Diff { .to_string(); if !output.is_empty() { + // If we can bless (meaning we have a file to write into and the `RUSTC_BLESS_TEST` + // environment variable set), then we write into the file and return. + if let Some(ref expected_file) = self.expected_file { + if std::env::var("RUSTC_BLESS_TEST").is_ok() { + println!("Blessing `{}`", expected_file.display()); + std::fs::write(expected_file, actual).unwrap(); + return; + } + } panic!( "test failed: `{}` is different from `{}`\n\n{}", expected_name, actual_name, output From be7b587cd13af17bd23dd8e38182c454df23e278 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Tue, 11 Jun 2024 14:05:55 +0200 Subject: [PATCH 08/18] Migrate `run-make/const_fn_mir` to `rmake.rs` --- src/tools/tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/const_fn_mir/Makefile | 6 ------ tests/run-make/const_fn_mir/rmake.rs | 8 ++++++++ 3 files changed, 8 insertions(+), 7 deletions(-) delete mode 100644 tests/run-make/const_fn_mir/Makefile create mode 100644 tests/run-make/const_fn_mir/rmake.rs diff --git a/src/tools/tidy/src/allowed_run_make_makefiles.txt b/src/tools/tidy/src/allowed_run_make_makefiles.txt index 37da5d9c88d90..14d7bfe9ad453 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -18,7 +18,6 @@ run-make/compiler-lookup-paths-2/Makefile run-make/compiler-lookup-paths/Makefile run-make/compiler-rt-works-on-mingw/Makefile run-make/compressed-debuginfo/Makefile -run-make/const_fn_mir/Makefile run-make/crate-hash-rustc-version/Makefile run-make/crate-name-priority/Makefile run-make/cross-lang-lto-clang/Makefile diff --git a/tests/run-make/const_fn_mir/Makefile b/tests/run-make/const_fn_mir/Makefile deleted file mode 100644 index 3399446130d74..0000000000000 --- a/tests/run-make/const_fn_mir/Makefile +++ /dev/null @@ -1,6 +0,0 @@ -# needs-unwind -Cpanic=abort gives different MIR output -include ../tools.mk - -all: - $(RUSTC) main.rs --emit=mir -o "$(TMPDIR)"/dump.mir - $(RUSTC_TEST_OP) "$(TMPDIR)"/dump.mir dump.mir diff --git a/tests/run-make/const_fn_mir/rmake.rs b/tests/run-make/const_fn_mir/rmake.rs new file mode 100644 index 0000000000000..a4cc4299b1b01 --- /dev/null +++ b/tests/run-make/const_fn_mir/rmake.rs @@ -0,0 +1,8 @@ +// The `needs-unwind -Cpanic=abort` gives a different MIR output. + +use run_make_support::{cwd, diff, rustc}; + +fn main() { + rustc().input("main.rs").emit("mir").output("dump-actual.mir").run(); + diff().expected_file("dump.mir").actual_file("dump-actual.mir").run(); +} From 0cc099b8a205d838f8b67996e9a75c2217574fc0 Mon Sep 17 00:00:00 2001 From: Florian Sextl Date: Thu, 13 Jun 2024 14:45:45 +0200 Subject: [PATCH 09/18] fix wrong assert_unsafe_precondition message for core::ptr::copy --- library/core/src/intrinsics.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index cd3534ecb1239..6b5054a9f0612 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -3043,8 +3043,7 @@ pub const unsafe fn copy(src: *const T, dst: *mut T, count: usize) { unsafe { ub_checks::assert_unsafe_precondition!( check_language_ub, - "ptr::copy_nonoverlapping requires that both pointer arguments are aligned and non-null \ - and the specified memory ranges do not overlap", + "ptr::copy requires that both pointer arguments are aligned and non-null", ( src: *const () = src as *const (), dst: *mut () = dst as *mut (), From 5f4111f781abcd8faca117e18e25c633f9effdcc Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Thu, 13 Jun 2024 11:39:45 +0200 Subject: [PATCH 10/18] Update run-make-support/diff to new `fs_wrapper` API --- src/tools/run-make-support/src/diff/mod.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/tools/run-make-support/src/diff/mod.rs b/src/tools/run-make-support/src/diff/mod.rs index d0be57ca9d7c5..3e0bdc1c6f64c 100644 --- a/src/tools/run-make-support/src/diff/mod.rs +++ b/src/tools/run-make-support/src/diff/mod.rs @@ -3,6 +3,7 @@ use similar::TextDiff; use std::path::{Path, PathBuf}; use crate::drop_bomb::DropBomb; +use crate::fs_wrapper; #[cfg(test)] mod tests; @@ -42,7 +43,7 @@ impl Diff { /// Specify the expected output for the diff from a file. pub fn expected_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = std::fs::read_to_string(path).expect("failed to read file"); + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); self.expected_file = Some(path.into()); @@ -61,10 +62,7 @@ impl Diff { /// Specify the actual output for the diff from a file. pub fn actual_file>(&mut self, path: P) -> &mut Self { let path = path.as_ref(); - let content = match std::fs::read_to_string(path) { - Ok(c) => c, - Err(e) => panic!("failed to read `{}`: {:?}", path.display(), e), - }; + let content = fs_wrapper::read_to_string(path); let name = path.to_string_lossy().to_string(); self.actual = Some(content); @@ -112,7 +110,7 @@ impl Diff { if let Some(ref expected_file) = self.expected_file { if std::env::var("RUSTC_BLESS_TEST").is_ok() { println!("Blessing `{}`", expected_file.display()); - std::fs::write(expected_file, actual).unwrap(); + fs_wrapper::write(expected_file, actual); return; } } From d3812ac95fbf67725f1d13392a611b776b1a2608 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 18:15:33 -0400 Subject: [PATCH 11/18] LangItem-ify Coroutine trait in solvers --- compiler/rustc_hir/src/lang_items.rs | 4 +++- compiler/rustc_span/src/symbol.rs | 2 ++ .../src/solve/normalizes_to/mod.rs | 13 ++++++++----- .../rustc_trait_selection/src/traits/project.rs | 9 +++++---- library/core/src/ops/coroutine.rs | 2 ++ 5 files changed, 20 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index c3ccba487ede7..69461957f804d 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -244,7 +244,9 @@ language_item_table! { AsyncIterator, sym::async_iterator, async_iterator_trait, Target::Trait, GenericRequirement::Exact(0); CoroutineState, sym::coroutine_state, coroutine_state, Target::Enum, GenericRequirement::None; - Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Minimum(1); + Coroutine, sym::coroutine, coroutine_trait, Target::Trait, GenericRequirement::Exact(1); + CoroutineReturn, sym::coroutine_return, coroutine_return, Target::AssocTy, GenericRequirement::Exact(1); + CoroutineYield, sym::coroutine_yield, coroutine_yield, Target::AssocTy, GenericRequirement::Exact(1); CoroutineResume, sym::coroutine_resume, coroutine_resume, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; Unpin, sym::unpin, unpin_trait, Target::Trait, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index e245dfb9f5d77..c89323b7f1691 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -635,7 +635,9 @@ symbols! { coroutine, coroutine_clone, coroutine_resume, + coroutine_return, coroutine_state, + coroutine_yield, coroutines, cosf128, cosf16, diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 787f08a084ee6..50253d815283a 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -17,7 +17,7 @@ use rustc_middle::ty::NormalizesTo; use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_middle::ty::{TypeVisitableExt, Upcast}; use rustc_middle::{bug, span_bug}; -use rustc_span::{sym, ErrorGuaranteed, DUMMY_SP}; +use rustc_span::{ErrorGuaranteed, DUMMY_SP}; mod anon_const; mod inherent; @@ -719,13 +719,16 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> { let coroutine = args.as_coroutine(); - let name = tcx.associated_item(goal.predicate.def_id()).name; - let term = if name == sym::Return { + let lang_items = tcx.lang_items(); + let term = if Some(goal.predicate.def_id()) == lang_items.coroutine_return() { coroutine.return_ty().into() - } else if name == sym::Yield { + } else if Some(goal.predicate.def_id()) == lang_items.coroutine_yield() { coroutine.yield_ty().into() } else { - bug!("unexpected associated item `<{self_ty} as Coroutine>::{name}`") + bug!( + "unexpected associated item `<{self_ty} as Coroutine>::{}`", + tcx.item_name(goal.predicate.def_id()) + ) }; Self::probe_and_consider_implied_clause( diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 2c9cb79664b34..32409e13842e0 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -1373,15 +1373,16 @@ fn confirm_coroutine_candidate<'cx, 'tcx>( coroutine_sig, ); - let name = tcx.associated_item(obligation.predicate.def_id).name; - let ty = if name == sym::Return { + let lang_items = tcx.lang_items(); + let ty = if Some(obligation.predicate.def_id) == lang_items.coroutine_return() { return_ty - } else if name == sym::Yield { + } else if Some(obligation.predicate.def_id) == lang_items.coroutine_yield() { yield_ty } else { span_bug!( tcx.def_span(obligation.predicate.def_id), - "unexpected associated type: `Coroutine::{name}`" + "unexpected associated type: `Coroutine::{}`", + tcx.item_name(obligation.predicate.def_id), ); }; diff --git a/library/core/src/ops/coroutine.rs b/library/core/src/ops/coroutine.rs index 6a6c5db1ab115..753f14c6b85ec 100644 --- a/library/core/src/ops/coroutine.rs +++ b/library/core/src/ops/coroutine.rs @@ -76,6 +76,7 @@ pub trait Coroutine { /// values which are allowed to be returned each time a coroutine yields. /// For example an iterator-as-a-coroutine would likely have this type as /// `T`, the type being iterated over. + #[cfg_attr(not(bootstrap), lang = "coroutine_yield")] type Yield; /// The type of value this coroutine returns. @@ -84,6 +85,7 @@ pub trait Coroutine { /// `return` statement or implicitly as the last expression of a coroutine /// literal. For example futures would use this as `Result` as it /// represents a completed future. + #[cfg_attr(not(bootstrap), lang = "coroutine_return")] type Return; /// Resumes the execution of this coroutine. From b79360ad16cf845d3beda5048f96d4460bd81b27 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 29 May 2024 20:15:56 -0400 Subject: [PATCH 12/18] Rework most of structural_traits to be Interner-agnostic --- compiler/rustc_infer/src/infer/mod.rs | 21 +- compiler/rustc_middle/src/ty/adt.rs | 17 ++ compiler/rustc_middle/src/ty/context.rs | 53 ++++- compiler/rustc_middle/src/ty/generic_args.rs | 2 + compiler/rustc_middle/src/ty/mod.rs | 2 + compiler/rustc_middle/src/ty/sty.rs | 4 + .../src/solve/assembly/structural_traits.rs | 217 +++++++++--------- compiler/rustc_type_ir/src/infcx.rs | 41 +++- compiler/rustc_type_ir/src/inherent.rs | 80 ++++++- compiler/rustc_type_ir/src/interner.rs | 52 +++-- 10 files changed, 350 insertions(+), 139 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 32b50053b5076..46f18bd77a0ee 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -44,7 +44,7 @@ use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; use rustc_middle::ty::{GenericArg, GenericArgKind, GenericArgs, GenericArgsRef}; use rustc_middle::{bug, span_bug}; use rustc_span::symbol::Symbol; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use snapshot::undo_log::InferCtxtUndoLogs; use std::cell::{Cell, RefCell}; use std::fmt; @@ -405,6 +405,25 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } } + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder<'tcx, T>, + ) -> T { + self.instantiate_binder_with_fresh_vars( + DUMMY_SP, + BoundRegionConversionTime::HigherRankedType, + value, + ) + } + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder<'tcx, T>, + f: impl FnOnce(T) -> U, + ) -> U { + self.enter_forall(value, f) + } } /// See the `error_reporting` module for more details. diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs index 886dbd317afa3..a89ebe46c3749 100644 --- a/compiler/rustc_middle/src/ty/adt.rs +++ b/compiler/rustc_middle/src/ty/adt.rs @@ -204,6 +204,23 @@ impl<'tcx> rustc_type_ir::inherent::AdtDef> for AdtDef<'tcx> { fn def_id(self) -> DefId { self.did() } + + fn is_phantom_data(self) -> bool { + self.is_phantom_data() + } + + fn all_field_tys( + self, + tcx: TyCtxt<'tcx>, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ty::EarlyBinder::bind( + self.all_fields().map(move |field| tcx.type_of(field.did).skip_binder()), + ) + } + + fn sized_constraint(self, tcx: TyCtxt<'tcx>) -> Option>> { + self.sized_constraint(tcx) + } } #[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)] diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 65d744239a6ab..98c60ffee1252 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -154,7 +154,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { type VariancesOf = &'tcx [ty::Variance]; - fn variances_of(self, def_id: Self::DefId) -> Self::VariancesOf { + fn variances_of(self, def_id: DefId) -> Self::VariancesOf { self.variances_of(def_id) } @@ -198,7 +198,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn trait_ref_and_own_args_for_alias( self, - def_id: Self::DefId, + def_id: DefId, args: Self::GenericArgs, ) -> (rustc_type_ir::TraitRef, Self::GenericArgsSlice) { assert_matches!(self.def_kind(def_id), DefKind::AssocTy | DefKind::AssocConst); @@ -246,7 +246,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { self.mk_type_list_from_iter(args) } - fn parent(self, def_id: Self::DefId) -> Self::DefId { + fn parent(self, def_id: DefId) -> DefId { self.parent(def_id) } @@ -259,6 +259,49 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn features(self) -> Self::Features { self.features() } + + fn bound_coroutine_hidden_types( + self, + def_id: DefId, + ) -> impl Iterator>>> { + self.bound_coroutine_hidden_types(def_id) + } + + fn fn_sig(self, def_id: DefId) -> ty::EarlyBinder<'tcx, ty::PolyFnSig<'tcx>> { + self.fn_sig(def_id) + } + + fn coroutine_movability(self, def_id: DefId) -> rustc_ast::Movability { + self.coroutine_movability(def_id) + } + + fn coroutine_for_closure(self, def_id: DefId) -> DefId { + self.coroutine_for_closure(def_id) + } + + fn generics_require_sized_self(self, def_id: DefId) -> bool { + self.generics_require_sized_self(def_id) + } + + fn item_bounds( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + self.item_bounds(def_id).map_bound(IntoIterator::into_iter) + } + + fn super_predicates_of( + self, + def_id: DefId, + ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ty::EarlyBinder::bind( + self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), + ) + } + + fn has_target_features(self, def_id: DefId) -> bool { + !self.codegen_fn_attrs(def_id).target_features.is_empty() + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { @@ -281,6 +324,10 @@ impl<'tcx> rustc_type_ir::inherent::Features> for &'tcx rustc_featu fn generic_const_exprs(self) -> bool { self.generic_const_exprs } + + fn coroutine_clone(self) -> bool { + self.coroutine_clone + } } type InternedSet<'tcx, T> = ShardedHashMap, ()>; diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 7fff3d0132493..54c88e48614b0 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -41,6 +41,8 @@ pub struct GenericArg<'tcx> { marker: PhantomData<(Ty<'tcx>, ty::Region<'tcx>, ty::Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::GenericArg> for GenericArg<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::GenericArgs> for ty::GenericArgsRef<'tcx> { fn type_at(self, i: usize) -> Ty<'tcx> { self.type_at(i) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 83f8de6b6f93f..c322c87bce4ad 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -488,6 +488,8 @@ pub struct Term<'tcx> { marker: PhantomData<(Ty<'tcx>, Const<'tcx>)>, } +impl<'tcx> rustc_type_ir::inherent::Term> for Term<'tcx> {} + impl<'tcx> rustc_type_ir::inherent::IntoKind for Term<'tcx> { type Kind = TermKind<'tcx>; diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs index ba9ed0d5b70a6..8308e537e5edf 100644 --- a/compiler/rustc_middle/src/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -786,6 +786,10 @@ impl<'tcx> rustc_type_ir::inherent::Ty> for Ty<'tcx> { tcx.types.bool } + fn new_u8(tcx: TyCtxt<'tcx>) -> Self { + tcx.types.u8 + } + fn new_infer(tcx: TyCtxt<'tcx>, infer: ty::InferTy) -> Self { Ty::new_infer(tcx, infer) } diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index 98f98d9992d30..c90b458d7b1a4 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -1,14 +1,13 @@ //! Code which is used by built-in goals that match "structurally", such a auto //! traits, `Copy`/`Clone`. + +use rustc_ast_ir::{Movability, Mutability}; use rustc_data_structures::fx::FxHashMap; -use rustc_hir::LangItem; -use rustc_hir::{def_id::DefId, Movability, Mutability}; -use rustc_infer::infer::InferCtxt; -use rustc_infer::traits::query::NoSolution; -use rustc_macros::{TypeFoldable, TypeVisitable}; -use rustc_middle::bug; -use rustc_middle::traits::solve::Goal; -use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, Upcast}; +use rustc_next_trait_solver::solve::{Goal, NoSolution}; +use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; +use rustc_type_ir::inherent::*; +use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; +use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; use crate::solve::EvalCtxt; @@ -17,12 +16,15 @@ use crate::solve::EvalCtxt; // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { let tcx = ecx.interner(); - match *ty.kind() { + match ty.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -34,7 +36,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Char => Ok(vec![]), // Treat `str` like it's defined as `struct str([u8]);` - ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, tcx.types.u8))]), + ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(tcx, Ty::new_u8(tcx)))]), ty::Dynamic(..) | ty::Param(..) @@ -43,7 +45,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( | ty::Placeholder(..) | ty::Bound(..) | ty::Infer(_) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } ty::RawPtr(element_ty, _) | ty::Ref(_, element_ty, _) => { @@ -56,7 +58,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::Tuple(tys) => { // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet - Ok(tys.iter().map(ty::Binder::dummy).collect()) + Ok(tys.into_iter().map(ty::Binder::dummy).collect()) } ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -76,31 +78,36 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(tcx, args)) + .map(|bty| bty.instantiate(tcx, &args)) .collect()), // For `PhantomData`, we pass `T`. ty::Adt(def, args) if def.is_phantom_data() => Ok(vec![ty::Binder::dummy(args.type_at(0))]), - ty::Adt(def, args) => { - Ok(def.all_fields().map(|f| ty::Binder::dummy(f.ty(tcx, args))).collect()) - } + ty::Adt(def, args) => Ok(def + .all_field_tys(tcx) + .iter_instantiated(tcx, &args) + .map(ty::Binder::dummy) + .collect()), ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => { // We can resolve the `impl Trait` to its concrete type, // which enforces a DAG between the functions requiring // the auto trait bounds in question. - Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, args))]) + Ok(vec![ty::Binder::dummy(tcx.type_of(def_id).instantiate(tcx, &args))]) } } } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { + match ty.kind() { // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) @@ -133,7 +140,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Sized for () @@ -151,7 +158,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( // if the ADT is sized for all possible args. ty::Adt(def, args) => { if let Some(sized_crit) = def.sized_constraint(ecx.interner()) { - Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), args))]) + Ok(vec![ty::Binder::dummy(sized_crit.instantiate(ecx.interner(), &args))]) } else { Ok(vec![]) } @@ -160,11 +167,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait<'tcx>( } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - ty: Ty<'tcx>, -) -> Result>>, NoSolution> { - match *ty.kind() { +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + ty: I::Ty, +) -> Result>, NoSolution> { + match ty.kind() { // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -196,11 +206,11 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{ty}`") + panic!("unexpected type `{ty:?}`") } // impl Copy/Clone for (T1, T2, .., Tn) where T1: Copy/Clone, T2: Copy/Clone, .. Tn: Copy/Clone - ty::Tuple(tys) => Ok(tys.iter().map(ty::Binder::dummy).collect()), + ty::Tuple(tys) => Ok(tys.into_iter().map(ty::Binder::dummy).collect()), // impl Copy/Clone for Closure where Self::TupledUpvars: Copy/Clone ty::Closure(_, args) => Ok(vec![ty::Binder::dummy(args.as_closure().tupled_upvars_ty())]), @@ -212,7 +222,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::Coroutine(def_id, args) => match ecx.interner().coroutine_movability(def_id) { Movability::Static => Err(NoSolution), Movability::Movable => { - if ecx.interner().features().coroutine_clone { + if ecx.interner().features().coroutine_clone() { let coroutine = args.as_coroutine(); Ok(vec![ ty::Binder::dummy(coroutine.tupled_upvars_ty()), @@ -228,27 +238,25 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>( ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) - .map(|bty| bty.instantiate(ecx.interner(), args)) + .map(|bty| bty.instantiate(ecx.interner(), &args)) .collect()), } } // Returns a binder of the tupled inputs types and output type from a builtin callable type. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, -) -> Result, Ty<'tcx>)>>, NoSolution> { - match *self_ty.kind() { +) -> Result>, NoSolution> { + match self_ty.kind() { // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnDef(def_id, args) => { let sig = tcx.fn_sig(def_id); - if sig.skip_binder().is_fn_trait_compatible() - && tcx.codegen_fn_attrs(def_id).target_features.is_empty() - { + if sig.skip_binder().is_fn_trait_compatible() && !tcx.has_target_features(def_id) { Ok(Some( - sig.instantiate(tcx, args) - .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())), + sig.instantiate(tcx, &args) + .map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())), )) } else { Err(NoSolution) @@ -257,7 +265,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( // keep this in sync with assemble_fn_pointer_candidates until the old solver is removed. ty::FnPtr(sig) => { if sig.is_fn_trait_compatible() { - Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs()), sig.output())))) + Ok(Some(sig.map_bound(|sig| (Ty::new_tup(tcx, &sig.inputs()), sig.output())))) } else { Err(NoSolution) } @@ -311,7 +319,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -326,7 +334,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( coroutine_closure_to_ambiguous_coroutine( tcx, goal_kind, // No captures by ref, so this doesn't matter. - tcx.lifetimes.re_static, + Region::new_static(tcx), def_id, args, sig, @@ -362,22 +370,24 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>( ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Relevant types for an async callable, including its inputs, output, /// and the return type you get from awaiting the output. -#[derive(Copy, Clone, Debug, TypeVisitable, TypeFoldable)] -pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { - pub tupled_inputs_ty: Ty<'tcx>, +#[derive(derivative::Derivative)] +#[derivative(Clone(bound = ""), Copy(bound = ""), Debug(bound = ""))] +#[derive(TypeVisitable_Generic, TypeFoldable_Generic)] +pub(in crate::solve) struct AsyncCallableRelevantTypes { + pub tupled_inputs_ty: I::Ty, /// Type returned by calling the closure /// i.e. `f()`. - pub output_coroutine_ty: Ty<'tcx>, + pub output_coroutine_ty: I::Ty, /// Type returned by `await`ing the output /// i.e. `f().await`. - pub coroutine_return_ty: Ty<'tcx>, + pub coroutine_return_ty: I::Ty, } // Returns a binder of the tupled inputs types, output type, and coroutine type @@ -385,16 +395,13 @@ pub(in crate::solve) struct AsyncCallableRelevantTypes<'tcx> { // the coroutine-closure, emit an additional trait predicate for `AsyncFnKindHelper` // which enforces the closure is actually callable with the given trait. When we // know the kind already, we can short-circuit this check. -pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tcx>( - tcx: TyCtxt<'tcx>, - self_ty: Ty<'tcx>, +pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( + tcx: I, + self_ty: I::Ty, goal_kind: ty::ClosureKind, - env_region: ty::Region<'tcx>, -) -> Result< - (ty::Binder<'tcx, AsyncCallableRelevantTypes<'tcx>>, Vec>), - NoSolution, -> { - match *self_ty.kind() { + env_region: I::Region, +) -> Result<(ty::Binder>, Vec), NoSolution> { + match self_ty.kind() { ty::CoroutineClosure(def_id, args) => { let args = args.as_coroutine_closure(); let kind_ty = args.kind_ty(); @@ -457,7 +464,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { - tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs()), + tupled_inputs_ty: Ty::new_tup(tcx, &sig.inputs()), output_coroutine_ty: sig.output(), coroutine_return_ty: future_output_ty, }), @@ -542,21 +549,21 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc ty::Bound(..) | ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => { - bug!("unexpected type `{self_ty}`") + panic!("unexpected type `{self_ty:?}`") } } } /// Given a coroutine-closure, project to its returned coroutine when we are *certain* /// that the closure's kind is compatible with the goal. -fn coroutine_closure_to_certain_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_certain_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { sig.to_coroutine_given_kind_and_upvars( tcx, args.parent_args(), @@ -573,20 +580,20 @@ fn coroutine_closure_to_certain_coroutine<'tcx>( /// yet what the closure's upvars are. /// /// Note that we do not also push a `AsyncFnKindHelper` goal here. -fn coroutine_closure_to_ambiguous_coroutine<'tcx>( - tcx: TyCtxt<'tcx>, +fn coroutine_closure_to_ambiguous_coroutine( + tcx: I, goal_kind: ty::ClosureKind, - goal_region: ty::Region<'tcx>, - def_id: DefId, - args: ty::CoroutineClosureArgs>, - sig: ty::CoroutineClosureSignature>, -) -> Ty<'tcx> { + goal_region: I::Region, + def_id: I::DefId, + args: ty::CoroutineClosureArgs, + sig: ty::CoroutineClosureSignature, +) -> I::Ty { let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, [ - ty::GenericArg::from(args.kind_ty()), + I::GenericArg::from(args.kind_ty()), Ty::from_closure_kind(tcx, goal_kind).into(), goal_region.into(), sig.tupled_inputs_ty.into(), @@ -643,17 +650,19 @@ fn coroutine_closure_to_ambiguous_coroutine<'tcx>( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( - ecx: &EvalCtxt<'_, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - trait_ref: ty::TraitRef<'tcx>, - object_bound: &'tcx ty::List>, -) -> Vec>> { +pub(in crate::solve) fn predicates_for_object_candidate< + Infcx: InferCtxtLike, + I: Interner, +>( + ecx: &EvalCtxt<'_, Infcx>, + param_env: I::ParamEnv, + trait_ref: ty::TraitRef, + object_bounds: I::BoundExistentialPredicates, +) -> Vec> { let tcx = ecx.interner(); let mut requirements = vec![]; - requirements.extend( - tcx.super_predicates_of(trait_ref.def_id).instantiate(tcx, trait_ref.args).predicates, - ); + requirements + .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { // FIXME(associated_const_equality): Also add associated consts to // the requirements here. @@ -665,19 +674,19 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( } requirements - .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, trait_ref.args)); + .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, &trait_ref.args)); } } let mut replace_projection_with = FxHashMap::default(); - for bound in object_bound { + for bound in object_bounds { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); assert_eq!( old_ty, None, - "{} has two generic parameters: {} and {}", + "{:?} has two generic parameters: {:?} and {:?}", proj.projection_term, proj.term, old_ty.unwrap() @@ -696,20 +705,22 @@ pub(in crate::solve) fn predicates_for_object_candidate<'tcx>( .collect() } -struct ReplaceProjectionWith<'a, 'tcx> { - ecx: &'a EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, - mapping: FxHashMap>, - nested: Vec>>, +struct ReplaceProjectionWith<'a, Infcx: InferCtxtLike, I: Interner> { + ecx: &'a EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, + mapping: FxHashMap>>, + nested: Vec>, } -impl<'tcx> TypeFolder> for ReplaceProjectionWith<'_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl, I: Interner> TypeFolder + for ReplaceProjectionWith<'_, Infcx, I> +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Alias(ty::Projection, alias_ty) = *ty.kind() + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + if let ty::Alias(ty::Projection, alias_ty) = ty.kind() && let Some(replacement) = self.mapping.get(&alias_ty.def_id) { // We may have a case where our object type's projection bound is higher-ranked, diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 24e10722448cc..680e9e961d171 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,23 +1,44 @@ -use crate::{ConstVid, EffectVid, FloatVid, IntVid, Interner, RegionVid, TyVid, UniverseIndex}; +use crate::fold::TypeFoldable; +use crate::{self as ty, Interner}; pub trait InferCtxtLike { type Interner: Interner; fn interner(&self) -> Self::Interner; - fn universe_of_ty(&self, ty: TyVid) -> Option; - fn universe_of_lt(&self, lt: RegionVid) -> Option; - fn universe_of_ct(&self, ct: ConstVid) -> Option; + fn universe_of_ty(&self, ty: ty::TyVid) -> Option; + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; + fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> ::Ty; - fn opportunistic_resolve_int_var(&self, vid: IntVid) -> ::Ty; - fn opportunistic_resolve_float_var(&self, vid: FloatVid) -> ::Ty; - fn opportunistic_resolve_ct_var(&self, vid: ConstVid) -> ::Const; + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; + fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; + fn opportunistic_resolve_float_var( + &self, + vid: ty::FloatVid, + ) -> ::Ty; + fn opportunistic_resolve_ct_var( + &self, + vid: ty::ConstVid, + ) -> ::Const; fn opportunistic_resolve_effect_var( &self, - vid: EffectVid, + vid: ty::EffectVid, ) -> ::Const; - fn opportunistic_resolve_lt_var(&self, vid: RegionVid) -> ::Region; + fn opportunistic_resolve_lt_var( + &self, + vid: ty::RegionVid, + ) -> ::Region; fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + + fn instantiate_binder_with_infer + Copy>( + &self, + value: ty::Binder, + ) -> T; + + fn enter_forall + Copy, U>( + &self, + value: ty::Binder, + f: impl FnOnce(T) -> U, + ) -> U; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 2fc765f1c8fae..bd88c4291e200 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -29,6 +29,8 @@ pub trait Ty>: { fn new_bool(interner: I) -> Self; + fn new_u8(interner: I) -> Self; + fn new_infer(interner: I, var: ty::InferTy) -> Self; fn new_var(interner: I, var: ty::TyVid) -> Self; @@ -39,6 +41,18 @@ pub trait Ty>: fn new_alias(interner: I, kind: ty::AliasTyKind, alias_ty: ty::AliasTy) -> Self; + fn new_projection( + interner: I, + def_id: I::DefId, + args: impl IntoIterator>, + ) -> Self { + Ty::new_alias( + interner, + ty::AliasTyKind::Projection, + ty::AliasTy::new(interner, def_id, args), + ) + } + fn new_error(interner: I, guar: I::ErrorGuaranteed) -> Self; fn new_adt(interner: I, adt_def: I::AdtDef, args: I::GenericArgs) -> Self; @@ -75,6 +89,12 @@ pub trait Ty>: It: Iterator, T: CollectAndApply; + fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; + + fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; + + fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn tuple_fields(self) -> I::Tys; fn to_opt_closure_kind(self) -> Option; @@ -83,11 +103,17 @@ pub trait Ty>: fn from_coroutine_closure_kind(interner: I, kind: ty::ClosureKind) -> Self; - fn new_fn_def(interner: I, def_id: I::DefId, args: I::GenericArgs) -> Self; - - fn new_fn_ptr(interner: I, sig: ty::Binder>) -> Self; - - fn new_pat(interner: I, ty: Self, pat: I::Pat) -> Self; + fn is_ty_var(self) -> bool { + matches!(self.kind(), ty::Infer(ty::TyVar(_))) + } + + fn fn_sig(self, interner: I) -> ty::Binder> { + match self.kind() { + ty::FnPtr(sig) => sig, + ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args), + _ => todo!("TODO:"), + } + } } pub trait Tys>: @@ -122,7 +148,6 @@ pub trait Region>: + Into + IntoKind> + Flags - + TypeVisitable + Relate { fn new_bound(interner: I, debruijn: ty::DebruijnIndex, var: I::BoundRegion) -> Self; @@ -164,6 +189,25 @@ pub trait GenericsOf> { fn count(&self) -> usize; } +pub trait GenericArg>: + Copy + + Debug + + Hash + + Eq + + IntoKind> + + TypeVisitable + + Relate + + From + + From + + From +{ +} + +pub trait Term>: + Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate +{ +} + pub trait GenericArgs>: Copy + Debug @@ -172,7 +216,6 @@ pub trait GenericArgs>: + IntoIterator + Deref> + Default - + TypeFoldable + Relate { fn type_at(self, i: usize) -> I::Ty; @@ -188,6 +231,16 @@ pub trait GenericArgs>: fn split_closure_args(self) -> ty::ClosureArgsParts; fn split_coroutine_closure_args(self) -> ty::CoroutineClosureArgsParts; fn split_coroutine_args(self) -> ty::CoroutineArgsParts; + + fn as_closure(self) -> ty::ClosureArgs { + ty::ClosureArgs { args: self } + } + fn as_coroutine_closure(self) -> ty::CoroutineClosureArgs { + ty::CoroutineClosureArgs { args: self } + } + fn as_coroutine(self) -> ty::CoroutineArgs { + ty::CoroutineArgs { args: self } + } } pub trait Predicate>: @@ -198,7 +251,10 @@ pub trait Predicate>: + TypeSuperVisitable + TypeSuperFoldable + Flags + + UpcastFrom + UpcastFrom> + + UpcastFrom> + + UpcastFrom>> { fn is_coinductive(self, interner: I) -> bool; } @@ -208,6 +264,7 @@ pub trait Clause>: + Debug + Hash + Eq + + TypeFoldable // FIXME: Remove these, uplift the `Upcast` impls. + UpcastFrom>> + UpcastFrom>> @@ -242,8 +299,17 @@ pub trait ParamLike { pub trait AdtDef: Copy + Debug + Hash + Eq { fn def_id(self) -> I::DefId; + + fn is_phantom_data(self) -> bool; + + // FIXME: perhaps use `all_fields` and expose `FieldDef`. + fn all_field_tys(self, interner: I) -> ty::EarlyBinder>; + + fn sized_constraint(self, interner: I) -> Option>; } pub trait Features: Copy { fn generic_const_exprs(self) -> bool; + + fn coroutine_clone(self) -> bool; } diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index b7f412ecb8ea9..ad983cc41871f 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -1,3 +1,4 @@ +use rustc_ast_ir::Movability; use smallvec::SmallVec; use std::fmt::Debug; use std::hash::Hash; @@ -31,20 +32,8 @@ pub trait Interner: type GenericArgs: GenericArgs; type GenericArgsSlice: Copy + Debug + Hash + Eq + Deref; - type GenericArg: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeVisitable - + Relate; - type Term: Copy - + Debug - + Hash - + Eq - + IntoKind> - + TypeFoldable - + Relate; + type GenericArg: GenericArg; + type Term: Term; type BoundVarKinds: Copy + Debug @@ -74,7 +63,12 @@ pub trait Interner: // Things stored inside of tys type ErrorGuaranteed: Copy + Debug + Hash + Eq; - type BoundExistentialPredicates: Copy + Debug + Hash + Eq + Relate; + type BoundExistentialPredicates: Copy + + Debug + + Hash + + Eq + + Relate + + IntoIterator>>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; type Safety: Safety + TypeFoldable + Relate; @@ -153,6 +147,34 @@ pub trait Interner: type Features: Features; fn features(self) -> Self::Features; + + fn bound_coroutine_hidden_types( + self, + def_id: Self::DefId, + ) -> impl Iterator>>; + + fn fn_sig( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>>; + + fn coroutine_movability(self, def_id: Self::DefId) -> Movability; + + fn coroutine_for_closure(self, def_id: Self::DefId) -> Self::DefId; + + fn generics_require_sized_self(self, def_id: Self::DefId) -> bool; + + fn item_bounds( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn super_predicates_of( + self, + def_id: Self::DefId, + ) -> ty::EarlyBinder>; + + fn has_target_features(self, def_id: Self::DefId) -> bool; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` From e82db89b4dbf0ddcc67f7804a01c322c761415b4 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 17:48:37 -0400 Subject: [PATCH 13/18] Finish uplifting all of structural_traits --- compiler/rustc_infer/src/infer/at.rs | 44 +++ .../src/infer/error_reporting/mod.rs | 2 + compiler/rustc_infer/src/infer/mod.rs | 75 ++++- compiler/rustc_middle/src/ty/context.rs | 23 +- compiler/rustc_middle/src/ty/predicate.rs | 9 + .../src/solve/assembly/structural_traits.rs | 37 +-- .../src/solve/eval_ctxt/mod.rs | 293 ++++++++---------- .../rustc_trait_selection/src/solve/mod.rs | 11 - .../src/solve/normalizes_to/mod.rs | 2 +- compiler/rustc_type_ir/src/infcx.rs | 30 +- compiler/rustc_type_ir/src/inherent.rs | 50 +++ compiler/rustc_type_ir/src/interner.rs | 5 + compiler/rustc_type_ir/src/lang_items.rs | 8 + compiler/rustc_type_ir/src/lib.rs | 1 + 14 files changed, 385 insertions(+), 205 deletions(-) create mode 100644 compiler/rustc_type_ir/src/lang_items.rs diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 01bd732a4cd84..2d06a7c693ff3 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -225,6 +225,50 @@ impl<'a, 'tcx> At<'a, 'tcx> { } } + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn relate_no_trace( + self, + expected: T, + variance: ty::Variance, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.sub().relate_with_variance( + variance, + ty::VarianceDiagInfo::default(), + expected, + actual, + )?; + Ok(fields.goals) + } + + /// Used in the new solver since we don't care about tracking an `ObligationCause`. + pub fn eq_structurally_relating_aliases_no_trace( + self, + expected: T, + actual: T, + ) -> Result>>, NoSolution> + where + T: Relate>, + { + let mut fields = CombineFields::new( + self.infcx, + TypeTrace::dummy(self.cause), + self.param_env, + DefineOpaqueTypes::Yes, + ); + fields.equate(StructurallyRelateAliases::Yes).relate(expected, actual)?; + Ok(fields.goals) + } + /// Computes the least-upper-bound, or mutual supertype, of two /// values. The order of the arguments doesn't matter, but since /// this can result in an error (e.g., if asked to compute LUB of diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index ed483c6cbeb41..d8a2857a11d13 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1707,6 +1707,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } + infer::DummyPair => (false, Mismatch::Fixed("values")), }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2275,6 +2276,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } + infer::DummyPair => None, } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 46f18bd77a0ee..e95949b92a96e 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -11,7 +11,7 @@ pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; pub use ValuePairs::*; -use crate::infer::relate::RelateResult; +use crate::infer::relate::{Relate, RelateResult}; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; use error_reporting::TypeErrCtxt; use free_regions::RegionRelations; @@ -35,6 +35,7 @@ use rustc_middle::infer::unify_key::{ConstVidKey, EffectVidKey}; use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult}; use rustc_middle::mir::ConstraintCategory; use rustc_middle::traits::select; +use rustc_middle::traits::solve::{Goal, NoSolution}; use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; @@ -352,29 +353,21 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } - fn universe_of_ct(&self, ct: ConstVid) -> Option { - // Same issue as with `universe_of_ty` - match self.probe_const_var(ct) { + fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { + match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { Err(universe) => Some(universe), Ok(_) => None, } } - fn universe_of_lt(&self, lt: ty::RegionVid) -> Option { - match self.inner.borrow_mut().unwrap_region_constraints().probe_value(lt) { + fn universe_of_ct(&self, ct: ConstVid) -> Option { + // Same issue as with `universe_of_ty` + match self.probe_const_var(ct) { Err(universe) => Some(universe), Ok(_) => None, } } - fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { - self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) - } - - fn defining_opaque_types(&self) -> &'tcx ty::List { - self.defining_opaque_types - } - fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { match self.probe_ty_var(vid) { Ok(ty) => ty, @@ -406,6 +399,26 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } + fn opportunistic_resolve_lt_var(&self, vid: ty::RegionVid) -> ty::Region<'tcx> { + self.inner.borrow_mut().unwrap_region_constraints().opportunistic_resolve_var(self.tcx, vid) + } + + fn defining_opaque_types(&self) -> &'tcx ty::List { + self.defining_opaque_types + } + + fn next_ty_infer(&self) -> Ty<'tcx> { + self.next_ty_var(DUMMY_SP) + } + + fn next_const_infer(&self) -> ty::Const<'tcx> { + self.next_const_var(DUMMY_SP) + } + + fn fresh_args_for_item(&self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { + self.fresh_args_for_item(DUMMY_SP, def_id) + } + fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder<'tcx, T>, @@ -417,13 +430,40 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { ) } - fn enter_forall + Copy, U>( + fn enter_forall> + Copy, U>( &self, value: ty::Binder<'tcx, T>, f: impl FnOnce(T) -> U, ) -> U { self.enter_forall(value, f) } + + fn relate>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env).relate_no_trace(lhs, variance, rhs) + } + + fn eq_structurally_relating_aliases>>( + &self, + param_env: ty::ParamEnv<'tcx>, + lhs: T, + rhs: T, + ) -> Result>>, NoSolution> { + self.at(&ObligationCause::dummy(), param_env) + .eq_structurally_relating_aliases_no_trace(lhs, rhs) + } + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable>, + { + self.resolve_vars_if_possible(value) + } } /// See the `error_reporting` module for more details. @@ -436,6 +476,7 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), + DummyPair, } impl<'tcx> ValuePairs<'tcx> { @@ -1858,6 +1899,10 @@ impl<'tcx> TypeTrace<'tcx> { values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } + + fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { + TypeTrace { cause: cause.clone(), values: ValuePairs::DummyPair } + } } impl<'tcx> SubregionOrigin<'tcx> { diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 98c60ffee1252..ebcb47966eb3f 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -70,9 +70,9 @@ use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx}; use rustc_target::spec::abi; use rustc_type_ir::fold::TypeFoldable; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::TyKind::*; -use rustc_type_ir::WithCachedTypeInfo; -use rustc_type_ir::{CollectAndApply, Interner, TypeFlags}; +use rustc_type_ir::{CollectAndApply, Interner, TypeFlags, WithCachedTypeInfo}; use tracing::{debug, instrument}; use std::assert_matches::assert_matches; @@ -302,6 +302,25 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn has_target_features(self, def_id: DefId) -> bool { !self.codegen_fn_attrs(def_id).target_features.is_empty() } + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> DefId { + self.require_lang_item( + match lang_item { + TraitSolverLangItem::Future => hir::LangItem::Future, + TraitSolverLangItem::FutureOutput => hir::LangItem::FutureOutput, + TraitSolverLangItem::AsyncFnKindHelper => hir::LangItem::AsyncFnKindHelper, + TraitSolverLangItem::AsyncFnKindUpvars => hir::LangItem::AsyncFnKindUpvars, + }, + None, + ) + } + + fn associated_type_def_ids(self, def_id: DefId) -> impl Iterator { + self.associated_items(def_id) + .in_definition_order() + .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) + .map(|assoc_item| assoc_item.def_id) + } } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 785aa8d456fc6..0f63490ea01c0 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -51,6 +51,14 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> } } +impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { + type Kind = ty::Binder<'tcx, ty::PredicateKind<'tcx>>; + + fn kind(self) -> Self::Kind { + self.kind() + } +} + impl<'tcx> rustc_type_ir::visit::Flags for Predicate<'tcx> { fn flags(&self) -> TypeFlags { self.0.flags @@ -120,6 +128,7 @@ impl<'tcx> Predicate<'tcx> { /// unsoundly accept some programs. See #91068. #[inline] pub fn allow_normalization(self) -> bool { + // Keep this in sync with the one in `rustc_type_ir::inherent`! match self.kind().skip_binder() { PredicateKind::Clause(ClauseKind::WellFormed(_)) | PredicateKind::AliasRelate(..) diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index c90b458d7b1a4..f232ddcf79708 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -6,6 +6,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_next_trait_solver::solve::{Goal, NoSolution}; use rustc_type_ir::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_type_ir::inherent::*; +use rustc_type_ir::lang_items::TraitSolverLangItem; use rustc_type_ir::{self as ty, InferCtxtLike, Interner, Upcast}; use rustc_type_ir_macros::{TypeFoldable_Generic, TypeVisitable_Generic}; @@ -428,7 +429,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable { let bound_sig = self_ty.fn_sig(tcx); let sig = bound_sig.skip_binder(); - let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None); + let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future); // `FnDef` and `FnPtr` only implement `AsyncFn*` when their // return type implements `Future`. let nested = vec![ @@ -460,7 +461,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( args: ty::CoroutineClosureArgs, sig: ty::CoroutineClosureSignature, ) -> I::Ty { - let upvars_projection_def_id = tcx.require_lang_item(LangItem::AsyncFnKindUpvars, None); + let upvars_projection_def_id = tcx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( tcx, upvars_projection_def_id, @@ -663,19 +664,19 @@ pub(in crate::solve) fn predicates_for_object_candidate< let mut requirements = vec![]; requirements .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, &trait_ref.args)); - for item in tcx.associated_items(trait_ref.def_id).in_definition_order() { - // FIXME(associated_const_equality): Also add associated consts to - // the requirements here. - if item.kind == ty::AssocKind::Type { - // associated types that require `Self: Sized` do not show up in the built-in - // implementation of `Trait for dyn Trait`, and can be dropped here. - if tcx.generics_require_sized_self(item.def_id) { - continue; - } - requirements - .extend(tcx.item_bounds(item.def_id).iter_instantiated(tcx, &trait_ref.args)); + // FIXME(associated_const_equality): Also add associated consts to + // the requirements here. + for associated_type_def_id in tcx.associated_type_def_ids(trait_ref.def_id) { + // associated types that require `Self: Sized` do not show up in the built-in + // implementation of `Trait for dyn Trait`, and can be dropped here. + if tcx.generics_require_sized_self(associated_type_def_id) { + continue; } + + requirements.extend( + tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, &trait_ref.args), + ); } let mut replace_projection_with = FxHashMap::default(); diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index 43013a01069e5..d35101b29f940 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -1,9 +1,6 @@ use rustc_data_structures::stack::ensure_sufficient_stack; use rustc_hir::def_id::DefId; -use rustc_infer::infer::at::ToTrace; -use rustc_infer::infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferCtxt, InferOk, TyCtxtInferExt, -}; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; use rustc_infer::traits::query::NoSolution; use rustc_infer::traits::solve::{MaybeCause, NestedNormalizationGoals}; use rustc_infer::traits::ObligationCause; @@ -15,11 +12,12 @@ use rustc_middle::traits::solve::{ use rustc_middle::ty::AliasRelationDirection; use rustc_middle::ty::TypeFolder; use rustc_middle::ty::{ - self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + self, InferCtxtLike, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable, TypeVisitableExt, }; use rustc_span::DUMMY_SP; use rustc_type_ir::fold::TypeSuperFoldable; +use rustc_type_ir::inherent::*; +use rustc_type_ir::relate::Relate; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; @@ -456,28 +454,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } } - #[instrument(level = "trace", skip(self))] - pub(super) fn add_normalizes_to_goal(&mut self, mut goal: Goal<'tcx, ty::NormalizesTo<'tcx>>) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); - self.nested_goals.normalizes_to_goals.push(goal); - } - - #[instrument(level = "debug", skip(self))] - pub(super) fn add_goal( - &mut self, - source: GoalSource, - mut goal: Goal<'tcx, ty::Predicate<'tcx>>, - ) { - goal.predicate = goal - .predicate - .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); - self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); - self.nested_goals.goals.push((source, goal)); - } - // Recursively evaluates all the goals added to this `EvalCtxt` to completion, returning // the certainty of all the goals. #[instrument(level = "trace", skip(self))] @@ -600,30 +576,65 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { pub(super) fn interner(&self) -> I { self.infcx.interner() } -} -impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - pub(super) fn next_ty_infer(&mut self) -> Ty<'tcx> { - let ty = self.infcx.next_ty_var(DUMMY_SP); + #[instrument(level = "trace", skip(self))] + pub(super) fn add_normalizes_to_goal( + &mut self, + mut goal: ir::solve::Goal>, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_normalizes_to_goal(self.infcx, self.max_input_universe, goal); + self.nested_goals.normalizes_to_goals.push(goal); + } + + #[instrument(level = "debug", skip(self))] + pub(super) fn add_goal( + &mut self, + source: GoalSource, + mut goal: ir::solve::Goal, + ) { + goal.predicate = goal + .predicate + .fold_with(&mut ReplaceAliasWithInfer { ecx: self, param_env: goal.param_env }); + self.inspect.add_goal(self.infcx, self.max_input_universe, source, goal); + self.nested_goals.goals.push((source, goal)); + } + + #[instrument(level = "trace", skip(self, goals))] + pub(super) fn add_goals( + &mut self, + source: GoalSource, + goals: impl IntoIterator>, + ) { + for goal in goals { + self.add_goal(source, goal); + } + } + + pub(super) fn next_ty_infer(&mut self) -> I::Ty { + let ty = self.infcx.next_ty_infer(); self.inspect.add_var_value(ty); ty } - pub(super) fn next_const_infer(&mut self) -> ty::Const<'tcx> { - let ct = self.infcx.next_const_var(DUMMY_SP); + pub(super) fn next_const_infer(&mut self) -> I::Const { + let ct = self.infcx.next_const_infer(); self.inspect.add_var_value(ct); ct } /// Returns a ty infer or a const infer depending on whether `kind` is a `Ty` or `Const`. /// If `kind` is an integer inference variable this will still return a ty infer var. - pub(super) fn next_term_infer_of_kind(&mut self, kind: ty::Term<'tcx>) -> ty::Term<'tcx> { - match kind.unpack() { - ty::TermKind::Ty(_) => self.next_ty_infer().into(), - ty::TermKind::Const(_) => self.next_const_infer().into(), + pub(super) fn next_term_infer_of_kind(&mut self, kind: I::Term) -> I::Term { + match kind.kind() { + ir::TermKind::Ty(_) => self.next_ty_infer().into(), + ir::TermKind::Const(_) => self.next_const_infer().into(), } } + /* TODO: /// Is the projection predicate is of the form `exists ::Assoc = T`. /// /// This is the case if the `term` does not occur in any other part of the predicate @@ -631,18 +642,18 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self), ret)] pub(super) fn term_is_fully_unconstrained( &self, - goal: Goal<'tcx, ty::NormalizesTo<'tcx>>, + goal: ir::solve::Goal>, ) -> bool { - let universe_of_term = match goal.predicate.term.unpack() { - ty::TermKind::Ty(ty) => { - if let &ty::Infer(ty::TyVar(vid)) = ty.kind() { + let universe_of_term = match goal.predicate.term.kind() { + ir::TermKind::Ty(ty) => { + if let ir::Infer(ir::TyVar(vid)) = ty.kind() { self.infcx.universe_of_ty(vid).unwrap() } else { return false; } } - ty::TermKind::Const(ct) => { - if let ty::ConstKind::Infer(ty::InferConst::Var(vid)) = ct.kind() { + ir::TermKind::Const(ct) => { + if let ir::ConstKind::Infer(ir::InferConst::Var(vid)) = ct.kind() { self.infcx.universe_of_ct(vid).unwrap() } else { return false; @@ -650,14 +661,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } }; - struct ContainsTermOrNotNameable<'a, 'tcx> { - term: ty::Term<'tcx>, - universe_of_term: ty::UniverseIndex, - infcx: &'a InferCtxt<'tcx>, + struct ContainsTermOrNotNameable<'a, Infcx: InferCtxtLike, I: Interner> { + term: I::Term, + universe_of_term: ir::UniverseIndex, + infcx: &'a Infcx, } - impl<'a, 'tcx> ContainsTermOrNotNameable<'a, 'tcx> { - fn check_nameable(&self, universe: ty::UniverseIndex) -> ControlFlow<()> { + impl, I: Interner> ContainsTermOrNotNameable<'_, Infcx, I> { + fn check_nameable(&self, universe: ir::UniverseIndex) -> ControlFlow<()> { if self.universe_of_term.can_name(universe) { ControlFlow::Continue(()) } else { @@ -666,12 +677,14 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - impl<'tcx> TypeVisitor> for ContainsTermOrNotNameable<'_, 'tcx> { + impl, I: Interner> TypeVisitor + for ContainsTermOrNotNameable<'_, Infcx, I> + { type Result = ControlFlow<()>; - fn visit_ty(&mut self, t: Ty<'tcx>) -> Self::Result { - match *t.kind() { - ty::Infer(ty::TyVar(vid)) => { - if let ty::TermKind::Ty(term) = self.term.unpack() + fn visit_ty(&mut self, t: I::Ty) -> Self::Result { + match t.kind() { + ir::Infer(ir::TyVar(vid)) => { + if let ir::TermKind::Ty(term) = self.term.kind() && let Some(term_vid) = term.ty_vid() && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) { @@ -680,7 +693,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.check_nameable(self.infcx.universe_of_ty(vid).unwrap()) } } - ty::Placeholder(p) => self.check_nameable(p.universe), + ir::Placeholder(p) => self.check_nameable(p.universe()), _ => { if t.has_non_region_infer() || t.has_placeholders() { t.super_visit_with(self) @@ -691,11 +704,11 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { } } - fn visit_const(&mut self, c: ty::Const<'tcx>) -> Self::Result { + fn visit_const(&mut self, c: I::Const) -> Self::Result { match c.kind() { - ty::ConstKind::Infer(ty::InferConst::Var(vid)) => { - if let ty::TermKind::Const(term) = self.term.unpack() - && let ty::ConstKind::Infer(ty::InferConst::Var(term_vid)) = term.kind() + ir::ConstKind::Infer(ir::InferConst::Var(vid)) => { + if let ir::TermKind::Const(term) = self.term.kind() + && let ir::ConstKind::Infer(ir::InferConst::Var(term_vid)) = term.kind() && self.infcx.root_const_var(vid) == self.infcx.root_const_var(term_vid) { ControlFlow::Break(()) @@ -703,7 +716,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { self.check_nameable(self.infcx.universe_of_ct(vid).unwrap()) } } - ty::ConstKind::Placeholder(p) => self.check_nameable(p.universe), + ir::ConstKind::Placeholder(p) => self.check_nameable(p.universe()), _ => { if c.has_non_region_infer() || c.has_placeholders() { c.super_visit_with(self) @@ -723,25 +736,16 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() } + */ #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq>( + pub(super) fn eq>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + self.relate(param_env, lhs, ir::Variance::Invariant, rhs) } /// This should be used when relating a rigid alias with another type. @@ -752,10 +756,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn relate_rigid_alias_non_alias( &mut self, - param_env: ty::ParamEnv<'tcx>, - alias: ty::AliasTerm<'tcx>, - variance: ty::Variance, - term: ty::Term<'tcx>, + param_env: I::ParamEnv, + alias: ir::AliasTerm, + variance: ir::Variance, + term: I::Term, ) -> Result<(), NoSolution> { // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. @@ -770,12 +774,10 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { // Alternatively we could modify `Equate` for this case by adding another // variant to `StructurallyRelateAliases`. let identity_args = self.fresh_args_for_item(alias.def_id); - let rigid_ctor = ty::AliasTerm::new(tcx, alias.def_id, identity_args); + let rigid_ctor = ir::AliasTerm::new(tcx, alias.def_id, identity_args); let ctor_term = rigid_ctor.to_term(tcx); - let InferOk { value: (), obligations } = self - .infcx - .at(&ObligationCause::dummy(), param_env) - .eq_structurally_relating_aliases(term, ctor_term)?; + let obligations = + self.infcx.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); self.relate(param_env, alias, variance, rigid_ctor) } else { @@ -787,58 +789,38 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// unconstrained "return value" or when we're sure that all aliases in /// the types are rigid. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_structurally_relating_aliases>( + pub(super) fn eq_structurally_relating_aliases>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, ) -> Result<(), NoSolution> { - let cause = ObligationCause::dummy(); - let InferOk { value: (), obligations } = - self.infcx.at(&cause, param_env).eq_structurally_relating_aliases(lhs, rhs)?; - assert!(obligations.is_empty()); + let result = self.infcx.eq_structurally_relating_aliases(param_env, lhs, rhs)?; + assert_eq!(result, vec![]); Ok(()) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn sub>( + pub(super) fn sub>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, sub: T, sup: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .sub(DefineOpaqueTypes::Yes, sub, sup) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to subtype"); - NoSolution - }) + self.relate(param_env, sub, ir::Variance::Covariant, sup) } #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn relate>( + pub(super) fn relate>( &mut self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, - variance: ty::Variance, + variance: ir::Variance, rhs: T, ) -> Result<(), NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .relate(DefineOpaqueTypes::Yes, lhs, variance, rhs) - .map(|InferOk { value: (), obligations }| { - self.add_goals(GoalSource::Misc, obligations.into_iter().map(|o| o.into())); - }) - .map_err(|e| { - trace!(?e, "failed to relate"); - NoSolution - }) + let goals = self.infcx.relate(param_env, lhs, variance, rhs)?; + self.add_goals(GoalSource::Misc, goals); + Ok(()) } /// Equates two values returning the nested goals without adding them @@ -847,58 +829,47 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// If possible, try using `eq` instead which automatically handles nested /// goals correctly. #[instrument(level = "trace", skip(self, param_env), ret)] - pub(super) fn eq_and_get_goals>( + pub(super) fn eq_and_get_goals>( &self, - param_env: ty::ParamEnv<'tcx>, + param_env: I::ParamEnv, lhs: T, rhs: T, - ) -> Result>>, NoSolution> { - self.infcx - .at(&ObligationCause::dummy(), param_env) - // New solver ignores DefineOpaqueTypes, so choose Yes for consistency - .eq(DefineOpaqueTypes::Yes, lhs, rhs) - .map(|InferOk { value: (), obligations }| { - obligations.into_iter().map(|o| o.into()).collect() - }) - .map_err(|e| { - trace!(?e, "failed to equate"); - NoSolution - }) + ) -> Result>, NoSolution> { + self.infcx.relate(param_env, lhs, ir::Variance::Invariant, rhs) } - pub(super) fn instantiate_binder_with_infer> + Copy>( + pub(super) fn instantiate_binder_with_infer + Copy>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, ) -> T { - self.infcx.instantiate_binder_with_fresh_vars( - DUMMY_SP, - BoundRegionConversionTime::HigherRankedType, - value, - ) + self.infcx.instantiate_binder_with_infer(value) } - pub(super) fn enter_forall> + Copy, U>( + pub(super) fn enter_forall + Copy, U>( &self, - value: ty::Binder<'tcx, T>, + value: ir::Binder, f: impl FnOnce(T) -> U, ) -> U { self.infcx.enter_forall(value, f) } + pub(super) fn resolve_vars_if_possible(&self, value: T) -> T where - T: TypeFoldable>, + T: TypeFoldable, { self.infcx.resolve_vars_if_possible(value) } - pub(super) fn fresh_args_for_item(&mut self, def_id: DefId) -> ty::GenericArgsRef<'tcx> { - let args = self.infcx.fresh_args_for_item(DUMMY_SP, def_id); + pub(super) fn fresh_args_for_item(&mut self, def_id: I::DefId) -> I::GenericArgs { + let args = self.infcx.fresh_args_for_item(def_id); for arg in args { self.inspect.add_var_value(arg); } args } +} +impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { pub(super) fn register_ty_outlives(&self, ty: Ty<'tcx>, lt: ty::Region<'tcx>) { self.infcx.register_region_obligation_with_cause(ty, lt, &ObligationCause::dummy()); } @@ -1096,28 +1067,36 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { /// /// This is a performance optimization to more eagerly detect cycles during trait /// solving. See tests/ui/traits/next-solver/cycles/cycle-modulo-ambig-aliases.rs. -struct ReplaceAliasWithInfer<'me, 'a, 'tcx> { - ecx: &'me mut EvalCtxt<'a, InferCtxt<'tcx>>, - param_env: ty::ParamEnv<'tcx>, +struct ReplaceAliasWithInfer<'me, 'a, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + ecx: &'me mut EvalCtxt<'a, Infcx>, + param_env: I::ParamEnv, } -impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { - fn interner(&self) -> TyCtxt<'tcx> { +impl TypeFolder for ReplaceAliasWithInfer<'_, '_, Infcx, I> +where + Infcx: InferCtxtLike, + I: Interner, +{ + fn interner(&self) -> I { self.ecx.interner() } - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match *ty.kind() { - ty::Alias(..) if !ty.has_escaping_bound_vars() => { + fn fold_ty(&mut self, ty: I::Ty) -> I::Ty { + match ty.kind() { + ir::Alias(..) if !ty.has_escaping_bound_vars() => { let infer_ty = self.ecx.next_ty_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ty.into(), infer_ty.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ty } @@ -1125,18 +1104,18 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> { + fn fold_const(&mut self, ct: I::Const) -> I::Const { match ct.kind() { - ty::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { + ir::ConstKind::Unevaluated(..) if !ct.has_escaping_bound_vars() => { let infer_ct = self.ecx.next_const_infer(); - let normalizes_to = ty::PredicateKind::AliasRelate( + let normalizes_to = ir::PredicateKind::AliasRelate( ct.into(), infer_ct.into(), AliasRelationDirection::Equate, ); self.ecx.add_goal( GoalSource::Misc, - Goal::new(self.interner(), self.param_env, normalizes_to), + ir::solve::Goal::new(self.interner(), self.param_env, normalizes_to), ); infer_ct } @@ -1144,7 +1123,7 @@ impl<'tcx> TypeFolder> for ReplaceAliasWithInfer<'_, '_, 'tcx> { } } - fn fold_predicate(&mut self, predicate: ty::Predicate<'tcx>) -> ty::Predicate<'tcx> { + fn fold_predicate(&mut self, predicate: I::Predicate) -> I::Predicate { if predicate.allow_normalization() { predicate.super_fold_with(self) } else { predicate } } } diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index c47b01949641b..fdcf4ff11e468 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -235,17 +235,6 @@ impl<'a, 'tcx> EvalCtxt<'a, InferCtxt<'tcx>> { } impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { - #[instrument(level = "trace", skip(self, goals))] - fn add_goals( - &mut self, - source: GoalSource, - goals: impl IntoIterator>>, - ) { - for goal in goals { - self.add_goal(source, goal); - } - } - /// Try to merge multiple possible ways to prove a goal, if that is not possible returns `None`. /// /// In this case we tend to flounder and return ambiguity by calling `[EvalCtxt::flounder]`. diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 50253d815283a..821e1e767369f 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { self.set_is_normalizes_to_goal(); - debug_assert!(self.term_is_fully_unconstrained(goal)); + // debug_assert!(self.term_is_fully_unconstrained(goal)); TODO: let normalize_result = self .probe(|&result| ProbeKind::TryNormalizeNonRigid { result }) .enter(|this| this.normalize_at_least_one_step(goal)); diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 680e9e961d171..4fb1069ff6610 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -1,7 +1,9 @@ use crate::fold::TypeFoldable; +use crate::relate::Relate; +use crate::solve::{Goal, NoSolution}; use crate::{self as ty, Interner}; -pub trait InferCtxtLike { +pub trait InferCtxtLike: Sized { type Interner: Interner; fn interner(&self) -> Self::Interner; @@ -31,6 +33,13 @@ pub trait InferCtxtLike { fn defining_opaque_types(&self) -> ::DefiningOpaqueTypes; + fn next_ty_infer(&self) -> ::Ty; + fn next_const_infer(&self) -> ::Const; + fn fresh_args_for_item( + &self, + def_id: ::DefId, + ) -> ::GenericArgs; + fn instantiate_binder_with_infer + Copy>( &self, value: ty::Binder, @@ -41,4 +50,23 @@ pub trait InferCtxtLike { value: ty::Binder, f: impl FnOnce(T) -> U, ) -> U; + + fn relate>( + &self, + param_env: ::ParamEnv, + lhs: T, + variance: ty::Variance, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn eq_structurally_relating_aliases>( + &self, + param_env: ::ParamEnv, + lhs: T, + rhs: T, + ) -> Result::Predicate>>, NoSolution>; + + fn resolve_vars_if_possible(&self, value: T) -> T + where + T: TypeFoldable; } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index bd88c4291e200..b2231d145357f 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -183,6 +183,10 @@ pub trait Const>: fn new_unevaluated(interner: I, uv: ty::UnevaluatedConst) -> Self; fn new_expr(interner: I, expr: I::ExprConst) -> Self; + + fn is_ct_var(self) -> bool { + matches!(self.kind(), ty::ConstKind::Infer(ty::InferConst::Var(_))) + } } pub trait GenericsOf> { @@ -206,6 +210,28 @@ pub trait GenericArg>: pub trait Term>: Copy + Debug + Hash + Eq + IntoKind> + TypeFoldable + Relate { + fn as_type(&self) -> Option { + if let ty::TermKind::Ty(ty) = self.kind() { Some(ty) } else { None } + } + + fn expect_type(&self) -> I::Ty { + self.as_type().expect("expected a type, but found a const") + } + + fn as_const(&self) -> Option { + if let ty::TermKind::Const(c) = self.kind() { Some(c) } else { None } + } + + fn expect_const(&self) -> I::Const { + self.as_const().expect("expected a const, but found a type") + } + + fn is_infer(self) -> bool { + match self.kind() { + ty::TermKind::Ty(ty) => ty.is_ty_var(), + ty::TermKind::Const(ct) => ct.is_ct_var(), + } + } } pub trait GenericArgs>: @@ -251,12 +277,36 @@ pub trait Predicate>: + TypeSuperVisitable + TypeSuperFoldable + Flags + + UpcastFrom> + + UpcastFrom>> + + UpcastFrom> + + UpcastFrom>> + UpcastFrom + UpcastFrom> + UpcastFrom> + UpcastFrom>> + + IntoKind>> { fn is_coinductive(self, interner: I) -> bool; + + fn allow_normalization(self) -> bool { + match self.kind().skip_binder() { + ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) + | ty::PredicateKind::AliasRelate(..) + | ty::PredicateKind::NormalizesTo(..) => false, + ty::PredicateKind::Clause(ty::ClauseKind::Trait(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) + | ty::PredicateKind::ObjectSafe(_) + | ty::PredicateKind::Subtype(_) + | ty::PredicateKind::Coerce(_) + | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) + | ty::PredicateKind::ConstEquate(_, _) + | ty::PredicateKind::Ambiguous => true, + } + } } pub trait Clause>: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index ad983cc41871f..f4f7a6e901c66 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -7,6 +7,7 @@ use std::ops::Deref; use crate::fold::TypeFoldable; use crate::inherent::*; use crate::ir_print::IrPrint; +use crate::lang_items::TraitSolverLangItem; use crate::relate::Relate; use crate::solve::inspect::CanonicalGoalEvaluationStep; use crate::visit::{Flags, TypeSuperVisitable, TypeVisitable}; @@ -175,6 +176,10 @@ pub trait Interner: ) -> ty::EarlyBinder>; fn has_target_features(self, def_id: Self::DefId) -> bool; + + fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; + + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl Iterator; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` diff --git a/compiler/rustc_type_ir/src/lang_items.rs b/compiler/rustc_type_ir/src/lang_items.rs new file mode 100644 index 0000000000000..9a3b324fcd765 --- /dev/null +++ b/compiler/rustc_type_ir/src/lang_items.rs @@ -0,0 +1,8 @@ +/// Lang items used by the new trait solver. This can be mapped to whatever internal +/// representation of `LangItem`s used in the underlying compiler implementation. +pub enum TraitSolverLangItem { + Future, + FutureOutput, + AsyncFnKindHelper, + AsyncFnKindUpvars, +} diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs index a76e278cc05d0..7f0c3df381daf 100644 --- a/compiler/rustc_type_ir/src/lib.rs +++ b/compiler/rustc_type_ir/src/lib.rs @@ -32,6 +32,7 @@ pub mod error; pub mod fold; pub mod inherent; pub mod ir_print; +pub mod lang_items; pub mod lift; pub mod relate; pub mod solve; From a2fb2ebc177cc4fa5933e72f3a81791e9b0b0083 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 12 Jun 2024 18:35:51 -0400 Subject: [PATCH 14/18] Fix some TODOs --- compiler/rustc_infer/src/infer/mod.rs | 8 +++++++ compiler/rustc_middle/src/ty/context.rs | 8 +++++++ .../src/solve/eval_ctxt/mod.rs | 7 +++--- .../src/solve/normalizes_to/mod.rs | 2 +- compiler/rustc_type_ir/src/infcx.rs | 3 +++ compiler/rustc_type_ir/src/inherent.rs | 22 ++++++++++++++++--- compiler/rustc_type_ir/src/interner.rs | 4 ++-- 7 files changed, 44 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index e95949b92a96e..6f40b9f72954c 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -368,6 +368,14 @@ impl<'tcx> ty::InferCtxtLike for InferCtxt<'tcx> { } } + fn root_ty_var(&self, var: TyVid) -> TyVid { + self.root_var(var) + } + + fn root_const_var(&self, var: ConstVid) -> ConstVid { + self.root_const_var(var) + } + fn opportunistic_resolve_ty_var(&self, vid: TyVid) -> Ty<'tcx> { match self.probe_ty_var(vid) { Ok(ty) => ty, diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index ebcb47966eb3f..849e10a952bd5 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -324,12 +324,20 @@ impl<'tcx> Interner for TyCtxt<'tcx> { } impl<'tcx> rustc_type_ir::inherent::Abi> for abi::Abi { + fn rust() -> Self { + abi::Abi::Rust + } + fn is_rust(self) -> bool { matches!(self, abi::Abi::Rust) } } impl<'tcx> rustc_type_ir::inherent::Safety> for hir::Safety { + fn safe() -> Self { + hir::Safety::Safe + } + fn is_safe(self) -> bool { matches!(self, hir::Safety::Safe) } diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs index d35101b29f940..860c580374d13 100644 --- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/mod.rs @@ -18,6 +18,7 @@ use rustc_span::DUMMY_SP; use rustc_type_ir::fold::TypeSuperFoldable; use rustc_type_ir::inherent::*; use rustc_type_ir::relate::Relate; +use rustc_type_ir::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor}; use rustc_type_ir::{self as ir, CanonicalVarValues, Interner}; use rustc_type_ir_macros::{Lift_Generic, TypeFoldable_Generic, TypeVisitable_Generic}; use std::ops::ControlFlow; @@ -634,7 +635,6 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { } } - /* TODO: /// Is the projection predicate is of the form `exists ::Assoc = T`. /// /// This is the case if the `term` does not occur in any other part of the predicate @@ -685,8 +685,8 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { match t.kind() { ir::Infer(ir::TyVar(vid)) => { if let ir::TermKind::Ty(term) = self.term.kind() - && let Some(term_vid) = term.ty_vid() - && self.infcx.root_var(vid) == self.infcx.root_var(term_vid) + && let ir::Infer(ir::TyVar(term_vid)) = term.kind() + && self.infcx.root_ty_var(vid) == self.infcx.root_ty_var(term_vid) { ControlFlow::Break(()) } else { @@ -736,7 +736,6 @@ impl, I: Interner> EvalCtxt<'_, Infcx> { goal.predicate.alias.visit_with(&mut visitor).is_continue() && goal.param_env.visit_with(&mut visitor).is_continue() } - */ #[instrument(level = "trace", skip(self, param_env), ret)] pub(super) fn eq>( diff --git a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs index 821e1e767369f..50253d815283a 100644 --- a/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/normalizes_to/mod.rs @@ -31,7 +31,7 @@ impl<'tcx> EvalCtxt<'_, InferCtxt<'tcx>> { goal: Goal<'tcx, NormalizesTo<'tcx>>, ) -> QueryResult<'tcx> { self.set_is_normalizes_to_goal(); - // debug_assert!(self.term_is_fully_unconstrained(goal)); TODO: + debug_assert!(self.term_is_fully_unconstrained(goal)); let normalize_result = self .probe(|&result| ProbeKind::TryNormalizeNonRigid { result }) .enter(|this| this.normalize_at_least_one_step(goal)); diff --git a/compiler/rustc_type_ir/src/infcx.rs b/compiler/rustc_type_ir/src/infcx.rs index 4fb1069ff6610..92a717a0d9efb 100644 --- a/compiler/rustc_type_ir/src/infcx.rs +++ b/compiler/rustc_type_ir/src/infcx.rs @@ -12,6 +12,9 @@ pub trait InferCtxtLike: Sized { fn universe_of_lt(&self, lt: ty::RegionVid) -> Option; fn universe_of_ct(&self, ct: ty::ConstVid) -> Option; + fn root_ty_var(&self, var: ty::TyVid) -> ty::TyVid; + fn root_const_var(&self, var: ty::ConstVid) -> ty::ConstVid; + fn opportunistic_resolve_ty_var(&self, vid: ty::TyVid) -> ::Ty; fn opportunistic_resolve_int_var(&self, vid: ty::IntVid) -> ::Ty; fn opportunistic_resolve_float_var( diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index b2231d145357f..3f919d4b87609 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -111,7 +111,19 @@ pub trait Ty>: match self.kind() { ty::FnPtr(sig) => sig, ty::FnDef(def_id, args) => interner.fn_sig(def_id).instantiate(interner, &args), - _ => todo!("TODO:"), + ty::Error(_) => { + // ignore errors (#54954) + ty::Binder::dummy(ty::FnSig { + inputs_and_output: Default::default(), + c_variadic: false, + safety: I::Safety::safe(), + abi: I::Abi::rust(), + }) + } + ty::Closure(..) => panic!( + "to get the signature of a closure, use `args.as_closure().sig()` not `fn_sig()`", + ), + _ => panic!("Ty::fn_sig() called on non-fn type: {:?}", self), } } } @@ -129,12 +141,16 @@ pub trait Tys>: fn split_inputs_and_output(self) -> (I::FnInputTys, I::Ty); } -pub trait Abi>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Abi>: Copy + Debug + Hash + Eq + Relate { + fn rust() -> Self; + /// Whether this ABI is `extern "Rust"`. fn is_rust(self) -> bool; } -pub trait Safety>: Copy + Debug + Hash + Eq + TypeVisitable { +pub trait Safety>: Copy + Debug + Hash + Eq + Relate { + fn safe() -> Self; + fn is_safe(self) -> bool; fn prefix_str(self) -> &'static str; diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index f4f7a6e901c66..bcf6c9b1a0ec0 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -72,8 +72,8 @@ pub trait Interner: + IntoIterator>>; type AllocId: Copy + Debug + Hash + Eq; type Pat: Copy + Debug + Hash + Eq + Debug + Relate; - type Safety: Safety + TypeFoldable + Relate; - type Abi: Abi + TypeFoldable + Relate; + type Safety: Safety; + type Abi: Abi; // Kinds of consts type Const: Const; From c8e42065f0f1d1a5cdb29c4279b1f2c25bc8737b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 13 Jun 2024 09:47:42 -0400 Subject: [PATCH 15/18] Address nits - Remove the ValuePairs glob import - Make DummyPairs -> ValuePairs::Dummy and make it bug more - Fix WC - Make interner return `impl IntoIterator`s --- compiler/rustc_infer/src/infer/at.rs | 37 +++++++++------ .../src/infer/error_reporting/mod.rs | 22 +++++---- compiler/rustc_infer/src/infer/mod.rs | 11 ++--- compiler/rustc_middle/src/ty/context.rs | 8 ++-- compiler/rustc_middle/src/ty/predicate.rs | 4 ++ .../src/solve/assembly/structural_traits.rs | 46 +++++++++++-------- .../src/solve/inspect/build.rs | 7 +-- compiler/rustc_type_ir/src/inherent.rs | 20 +------- compiler/rustc_type_ir/src/interner.rs | 8 ++-- 9 files changed, 85 insertions(+), 78 deletions(-) diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs index 2d06a7c693ff3..5e9c3c64e39ed 100644 --- a/compiler/rustc_infer/src/infer/at.rs +++ b/compiler/rustc_infer/src/infer/at.rs @@ -347,7 +347,7 @@ impl<'tcx> ToTrace<'tcx> for Ty<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -359,7 +359,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Region<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Regions(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -372,7 +375,7 @@ impl<'tcx> ToTrace<'tcx> for Const<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -388,13 +391,13 @@ impl<'tcx> ToTrace<'tcx> for ty::GenericArg<'tcx> { cause: cause.clone(), values: match (a.unpack(), b.unpack()) { (GenericArgKind::Lifetime(a), GenericArgKind::Lifetime(b)) => { - Regions(ExpectedFound::new(a_is_expected, a, b)) + ValuePairs::Regions(ExpectedFound::new(a_is_expected, a, b)) } (GenericArgKind::Type(a), GenericArgKind::Type(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } (GenericArgKind::Const(a), GenericArgKind::Const(b)) => { - Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) + ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())) } ( @@ -423,7 +426,10 @@ impl<'tcx> ToTrace<'tcx> for ty::Term<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Terms(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -436,7 +442,7 @@ impl<'tcx> ToTrace<'tcx> for ty::TraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -450,7 +456,7 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTy<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } } @@ -462,7 +468,10 @@ impl<'tcx> ToTrace<'tcx> for ty::AliasTerm<'tcx> { a: Self, b: Self, ) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: Aliases(ExpectedFound::new(a_is_expected, a, b)) } + TypeTrace { + cause: cause.clone(), + values: ValuePairs::Aliases(ExpectedFound::new(a_is_expected, a, b)), + } } } @@ -475,7 +484,7 @@ impl<'tcx> ToTrace<'tcx> for ty::FnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new( + values: ValuePairs::PolySigs(ExpectedFound::new( a_is_expected, ty::Binder::dummy(a), ty::Binder::dummy(b), @@ -493,7 +502,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyFnSig<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: PolySigs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::PolySigs(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -507,7 +516,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialTraitRef<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialTraitRef(ExpectedFound::new(a_is_expected, a, b)), } } } @@ -521,7 +530,7 @@ impl<'tcx> ToTrace<'tcx> for ty::PolyExistentialProjection<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::ExistentialProjection(ExpectedFound::new(a_is_expected, a, b)), } } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index d8a2857a11d13..7fb07a5d30c43 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -1707,7 +1707,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ValuePairs::ExistentialProjection(_) => { (false, Mismatch::Fixed("existential projection")) } - infer::DummyPair => (false, Mismatch::Fixed("values")), + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } }; let Some(vals) = self.values_str(values) else { // Derived error. Cancel the emitter. @@ -2251,12 +2253,12 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { values: ValuePairs<'tcx>, ) -> Option<(DiagStyledString, DiagStyledString, Option)> { match values { - infer::Regions(exp_found) => self.expected_found_str(exp_found), - infer::Terms(exp_found) => self.expected_found_str_term(exp_found), - infer::Aliases(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), - infer::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), - infer::TraitRefs(exp_found) => { + ValuePairs::Regions(exp_found) => self.expected_found_str(exp_found), + ValuePairs::Terms(exp_found) => self.expected_found_str_term(exp_found), + ValuePairs::Aliases(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialTraitRef(exp_found) => self.expected_found_str(exp_found), + ValuePairs::ExistentialProjection(exp_found) => self.expected_found_str(exp_found), + ValuePairs::TraitRefs(exp_found) => { let pretty_exp_found = ty::error::ExpectedFound { expected: exp_found.expected.print_trait_sugared(), found: exp_found.found.print_trait_sugared(), @@ -2268,7 +2270,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ret => ret, } } - infer::PolySigs(exp_found) => { + ValuePairs::PolySigs(exp_found) => { let exp_found = self.resolve_vars_if_possible(exp_found); if exp_found.references_error() { return None; @@ -2276,7 +2278,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { let (exp, fnd) = self.cmp_fn_sig(&exp_found.expected, &exp_found.found); Some((exp, fnd, None)) } - infer::DummyPair => None, + ValuePairs::Dummy => { + bug!("do not expect to report a type error from a ValuePairs::Dummy") + } } } diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index 6f40b9f72954c..dcf415e720fb5 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -9,7 +9,6 @@ pub use rustc_middle::ty::IntVarValue; pub use BoundRegionConversionTime::*; pub use RegionVariableOrigin::*; pub use SubregionOrigin::*; -pub use ValuePairs::*; use crate::infer::relate::{Relate, RelateResult}; use crate::traits::{self, ObligationCause, ObligationInspector, PredicateObligation, TraitEngine}; @@ -484,7 +483,7 @@ pub enum ValuePairs<'tcx> { PolySigs(ExpectedFound>), ExistentialTraitRef(ExpectedFound>), ExistentialProjection(ExpectedFound>), - DummyPair, + Dummy, } impl<'tcx> ValuePairs<'tcx> { @@ -1880,7 +1879,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } @@ -1892,7 +1891,7 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: TraitRefs(ExpectedFound::new(a_is_expected, a, b)), + values: ValuePairs::TraitRefs(ExpectedFound::new(a_is_expected, a, b)), } } @@ -1904,12 +1903,12 @@ impl<'tcx> TypeTrace<'tcx> { ) -> TypeTrace<'tcx> { TypeTrace { cause: cause.clone(), - values: Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), + values: ValuePairs::Terms(ExpectedFound::new(a_is_expected, a.into(), b.into())), } } fn dummy(cause: &ObligationCause<'tcx>) -> TypeTrace<'tcx> { - TypeTrace { cause: cause.clone(), values: ValuePairs::DummyPair } + TypeTrace { cause: cause.clone(), values: ValuePairs::Dummy } } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 849e10a952bd5..3651c990c9792 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -263,7 +263,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn bound_coroutine_hidden_types( self, def_id: DefId, - ) -> impl Iterator>>> { + ) -> impl IntoIterator>>> { self.bound_coroutine_hidden_types(def_id) } @@ -286,14 +286,14 @@ impl<'tcx> Interner for TyCtxt<'tcx> { fn item_bounds( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { self.item_bounds(def_id).map_bound(IntoIterator::into_iter) } fn super_predicates_of( self, def_id: DefId, - ) -> ty::EarlyBinder<'tcx, impl Iterator>> { + ) -> ty::EarlyBinder<'tcx, impl IntoIterator>> { ty::EarlyBinder::bind( self.super_predicates_of(def_id).instantiate_identity(self).predicates.into_iter(), ) @@ -315,7 +315,7 @@ impl<'tcx> Interner for TyCtxt<'tcx> { ) } - fn associated_type_def_ids(self, def_id: DefId) -> impl Iterator { + fn associated_type_def_ids(self, def_id: DefId) -> impl IntoIterator { self.associated_items(def_id) .in_definition_order() .filter(|assoc_item| matches!(assoc_item.kind, ty::AssocKind::Type)) diff --git a/compiler/rustc_middle/src/ty/predicate.rs b/compiler/rustc_middle/src/ty/predicate.rs index 0f63490ea01c0..ae36f2624ca5f 100644 --- a/compiler/rustc_middle/src/ty/predicate.rs +++ b/compiler/rustc_middle/src/ty/predicate.rs @@ -49,6 +49,10 @@ impl<'tcx> rustc_type_ir::inherent::Predicate> for Predicate<'tcx> fn is_coinductive(self, interner: TyCtxt<'tcx>) -> bool { self.is_coinductive(interner) } + + fn allow_normalization(self) -> bool { + self.allow_normalization() + } } impl<'tcx> rustc_type_ir::inherent::IntoKind for Predicate<'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs index f232ddcf79708..d6074617cafe7 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs @@ -17,13 +17,14 @@ use crate::solve::EvalCtxt; // For types with an "existential" binder, i.e. coroutine witnesses, we also // instantiate the binder with placeholders eagerly. #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); match ty.kind() { ty::Uint(_) @@ -79,6 +80,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) + .into_iter() .map(|bty| bty.instantiate(tcx, &args)) .collect()), @@ -101,13 +103,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait< } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ match ty.kind() { // impl Sized for u*, i*, bool, f*, FnDef, FnPtr, *(const/mut) T, char, &mut? T, [T; N], dyn* Trait, ! // impl Sized for Coroutine, CoroutineWitness, Closure, CoroutineClosure @@ -168,13 +171,14 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_sized_trait< } #[instrument(level = "trace", skip(ecx), ret)] -pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait( ecx: &EvalCtxt<'_, Infcx>, ty: I::Ty, -) -> Result>, NoSolution> { +) -> Result>, NoSolution> +where + Infcx: InferCtxtLike, + I: Interner, +{ match ty.kind() { // impl Copy/Clone for FnDef, FnPtr ty::FnDef(..) | ty::FnPtr(_) | ty::Error(_) => Ok(vec![]), @@ -239,6 +243,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_copy_clone_trait< ty::CoroutineWitness(def_id, args) => Ok(ecx .interner() .bound_coroutine_hidden_types(def_id) + .into_iter() .map(|bty| bty.instantiate(ecx.interner(), &args)) .collect()), } @@ -651,15 +656,16 @@ fn coroutine_closure_to_ambiguous_coroutine( // This is unsound in general and once that is fixed, we don't need to // normalize eagerly here. See https://github.com/lcnr/solver-woes/issues/9 // for more details. -pub(in crate::solve) fn predicates_for_object_candidate< - Infcx: InferCtxtLike, - I: Interner, ->( +pub(in crate::solve) fn predicates_for_object_candidate( ecx: &EvalCtxt<'_, Infcx>, param_env: I::ParamEnv, trait_ref: ty::TraitRef, object_bounds: I::BoundExistentialPredicates, -) -> Vec> { +) -> Vec> +where + Infcx: InferCtxtLike, + I: Interner, +{ let tcx = ecx.interner(); let mut requirements = vec![]; requirements diff --git a/compiler/rustc_trait_selection/src/solve/inspect/build.rs b/compiler/rustc_trait_selection/src/solve/inspect/build.rs index 84c04900ae484..35750598bc740 100644 --- a/compiler/rustc_trait_selection/src/solve/inspect/build.rs +++ b/compiler/rustc_trait_selection/src/solve/inspect/build.rs @@ -34,10 +34,11 @@ use rustc_type_ir::{self as ty, InferCtxtLike, Interner}; /// trees. At the end of trait solving `ProofTreeBuilder::finalize` /// is called to recursively convert the whole structure to a /// finished proof tree. -pub(in crate::solve) struct ProofTreeBuilder< +pub(in crate::solve) struct ProofTreeBuilder::Interner> +where Infcx: InferCtxtLike, - I: Interner = ::Interner, -> { + I: Interner, +{ _infcx: PhantomData, state: Option>>, } diff --git a/compiler/rustc_type_ir/src/inherent.rs b/compiler/rustc_type_ir/src/inherent.rs index 3f919d4b87609..6b84592978a26 100644 --- a/compiler/rustc_type_ir/src/inherent.rs +++ b/compiler/rustc_type_ir/src/inherent.rs @@ -305,24 +305,8 @@ pub trait Predicate>: { fn is_coinductive(self, interner: I) -> bool; - fn allow_normalization(self) -> bool { - match self.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::WellFormed(_)) - | ty::PredicateKind::AliasRelate(..) - | ty::PredicateKind::NormalizesTo(..) => false, - ty::PredicateKind::Clause(ty::ClauseKind::Trait(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::RegionOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::TypeOutlives(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::Projection(_)) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstArgHasType(..)) - | ty::PredicateKind::ObjectSafe(_) - | ty::PredicateKind::Subtype(_) - | ty::PredicateKind::Coerce(_) - | ty::PredicateKind::Clause(ty::ClauseKind::ConstEvaluatable(_)) - | ty::PredicateKind::ConstEquate(_, _) - | ty::PredicateKind::Ambiguous => true, - } - } + // FIXME: Eventually uplift the impl out of rustc and make this defaulted. + fn allow_normalization(self) -> bool; } pub trait Clause>: diff --git a/compiler/rustc_type_ir/src/interner.rs b/compiler/rustc_type_ir/src/interner.rs index bcf6c9b1a0ec0..a2b71e1fc2575 100644 --- a/compiler/rustc_type_ir/src/interner.rs +++ b/compiler/rustc_type_ir/src/interner.rs @@ -152,7 +152,7 @@ pub trait Interner: fn bound_coroutine_hidden_types( self, def_id: Self::DefId, - ) -> impl Iterator>>; + ) -> impl IntoIterator>>; fn fn_sig( self, @@ -168,18 +168,18 @@ pub trait Interner: fn item_bounds( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>; fn super_predicates_of( self, def_id: Self::DefId, - ) -> ty::EarlyBinder>; + ) -> ty::EarlyBinder>; fn has_target_features(self, def_id: Self::DefId) -> bool; fn require_lang_item(self, lang_item: TraitSolverLangItem) -> Self::DefId; - fn associated_type_def_ids(self, def_id: Self::DefId) -> impl Iterator; + fn associated_type_def_ids(self, def_id: Self::DefId) -> impl IntoIterator; } /// Imagine you have a function `F: FnOnce(&[T]) -> R`, plus an iterator `iter` From a1667a98e8eda4e1043e731a392ca543858af44a Mon Sep 17 00:00:00 2001 From: Nilstrieb <48135649+Nilstrieb@users.noreply.github.com> Date: Mon, 10 Jun 2024 20:49:52 +0200 Subject: [PATCH 16/18] Fix Miri sysroot for `x run` Miri no longer respects `MIRI_SYSROOT` and wants to be treated like a REAL rustc, with `--sysroot`. *pats Miri* sure Miri, just for you :3. --- src/bootstrap/src/core/build_steps/run.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/bootstrap/src/core/build_steps/run.rs b/src/bootstrap/src/core/build_steps/run.rs index 354eb2b600381..9268b335db7c2 100644 --- a/src/bootstrap/src/core/build_steps/run.rs +++ b/src/bootstrap/src/core/build_steps/run.rs @@ -149,12 +149,14 @@ impl Step for Miri { &[], ); miri.add_rustc_lib_path(builder); - // Forward arguments. miri.arg("--").arg("--target").arg(target.rustc_target_arg()); - miri.args(builder.config.args()); // miri tests need to know about the stage sysroot - miri.env("MIRI_SYSROOT", &miri_sysroot); + miri.arg("--sysroot").arg(miri_sysroot); + + // Forward arguments. This may contain further arguments to the program + // after another --, so this must be at the end. + miri.args(builder.config.args()); let mut miri = Command::from(miri); builder.run(&mut miri); From b316033dd812f138b069b957cba443047cd71c3d Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 11:15:55 +0200 Subject: [PATCH 17/18] rename CompileTimeInterpreter -> CompileTimeMachine, CompileTimeEvalContext -> CompileTimeInterpCx to match the terms used in the shared interpreter infrastructure --- .../rustc_const_eval/src/const_eval/error.rs | 4 ++-- .../src/const_eval/eval_queries.rs | 22 +++++++++---------- .../src/const_eval/machine.rs | 12 +++++----- .../src/const_eval/valtrees.rs | 16 +++++++------- .../rustc_const_eval/src/interpret/intern.rs | 2 +- .../rustc_const_eval/src/interpret/util.rs | 6 ++--- .../src/util/caller_location.rs | 4 ++-- .../src/util/check_validity_requirement.rs | 4 ++-- 8 files changed, 35 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 923b9ddf9afbb..94f4ae2556de5 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::TyCtxt; use rustc_middle::ty::{layout::LayoutError, ConstInt}; use rustc_span::{Span, Symbol}; -use super::CompileTimeInterpreter; +use super::CompileTimeMachine; use crate::errors::{self, FrameNote, ReportErrorExt}; use crate::interpret::{err_inval, err_machine_stop}; use crate::interpret::{ErrorHandled, Frame, InterpError, InterpErrorInfo, MachineStopType}; @@ -160,7 +160,7 @@ where // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, - machine: &CompileTimeInterpreter<'tcx>, + machine: &CompileTimeMachine<'tcx>, lint: &'static rustc_session::lint::Lint, decorator: impl FnOnce(Vec) -> L, ) where diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 36f468d3308a8..88a1503ee89c8 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -17,7 +17,7 @@ use rustc_span::def_id::LocalDefId; use rustc_span::{Span, DUMMY_SP}; use rustc_target::abi::{self, Abi}; -use super::{CanAccessMutGlobal, CompileTimeEvalContext, CompileTimeInterpreter}; +use super::{CanAccessMutGlobal, CompileTimeInterpCx, CompileTimeMachine}; use crate::const_eval::CheckAlignment; use crate::errors::ConstEvalError; use crate::errors::{self, DanglingPtrInFinal}; @@ -32,7 +32,7 @@ use crate::CTRL_C_RECEIVED; // Returns a pointer to where the result lives #[instrument(level = "trace", skip(ecx, body))] fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, cid: GlobalId<'tcx>, body: &'tcx mir::Body<'tcx>, ) -> InterpResult<'tcx, R> { @@ -139,13 +139,13 @@ pub(crate) fn mk_eval_cx_to_read_const_val<'tcx>( root_span: Span, param_env: ty::ParamEnv<'tcx>, can_access_mut_global: CanAccessMutGlobal, -) -> CompileTimeEvalContext<'tcx> { +) -> CompileTimeInterpCx<'tcx> { debug!("mk_eval_cx: {:?}", param_env); InterpCx::new( tcx, root_span, param_env, - CompileTimeInterpreter::new(can_access_mut_global, CheckAlignment::No), + CompileTimeMachine::new(can_access_mut_global, CheckAlignment::No), ) } @@ -156,7 +156,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( param_env: ty::ParamEnv<'tcx>, val: mir::ConstValue<'tcx>, ty: Ty<'tcx>, -) -> Option<(CompileTimeEvalContext<'tcx>, OpTy<'tcx>)> { +) -> Option<(CompileTimeInterpCx<'tcx>, OpTy<'tcx>)> { let ecx = mk_eval_cx_to_read_const_val(tcx.tcx, tcx.span, param_env, CanAccessMutGlobal::No); let op = ecx.const_val_to_op(val, ty, None).ok()?; Some((ecx, op)) @@ -170,7 +170,7 @@ pub fn mk_eval_cx_for_const_val<'tcx>( /// encounter an `Indirect` they cannot handle. #[instrument(skip(ecx), level = "debug")] pub(super) fn op_to_const<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, op: &OpTy<'tcx>, for_diagnostics: bool, ) -> ConstValue<'tcx> { @@ -328,14 +328,14 @@ pub trait InterpretationResult<'tcx> { /// evaluation query. fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self; } impl<'tcx> InterpretationResult<'tcx> for ConstAlloc<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - _ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + _ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { ConstAlloc { alloc_id: mplace.ptr().provenance.unwrap().alloc_id(), ty: mplace.layout.ty } } @@ -383,7 +383,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( // they do not have to behave "as if" they were evaluated at runtime. // For consts however we want to ensure they behave "as if" they were evaluated at runtime, // so we have to reject reading mutable global memory. - CompileTimeInterpreter::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), + CompileTimeMachine::new(CanAccessMutGlobal::from(is_static), CheckAlignment::Error), ); let res = ecx.load_mir(cid.instance.def, cid.promoted); res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, body)).map_err(|error| { @@ -417,7 +417,7 @@ fn eval_in_interpreter<'tcx, R: InterpretationResult<'tcx>>( #[inline(always)] fn const_validate_mplace<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, mplace: &MPlaceTy<'tcx>, cid: GlobalId<'tcx>, ) -> Result<(), ErrorHandled> { @@ -447,7 +447,7 @@ fn const_validate_mplace<'tcx>( #[inline(always)] fn report_validation_error<'tcx>( - ecx: &InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &InterpCx<'tcx, CompileTimeMachine<'tcx>>, error: InterpErrorInfo<'tcx>, alloc_id: AllocId, ) -> ErrorHandled { diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 79a161d3f03d7..0dbb6a95376dd 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -44,7 +44,7 @@ const TINY_LINT_TERMINATOR_LIMIT: usize = 20; const PROGRESS_INDICATOR_START: usize = 4_000_000; /// Extra machine state for CTFE, and the Machine instance -pub struct CompileTimeInterpreter<'tcx> { +pub struct CompileTimeMachine<'tcx> { /// The number of terminators that have been evaluated. /// /// This is used to produce lints informing the user that the compiler is not stuck. @@ -89,12 +89,12 @@ impl From for CanAccessMutGlobal { } } -impl<'tcx> CompileTimeInterpreter<'tcx> { +impl<'tcx> CompileTimeMachine<'tcx> { pub(crate) fn new( can_access_mut_global: CanAccessMutGlobal, check_alignment: CheckAlignment, ) -> Self { - CompileTimeInterpreter { + CompileTimeMachine { num_evaluated_steps: 0, stack: Vec::new(), can_access_mut_global, @@ -163,7 +163,7 @@ impl interpret::AllocMap for FxIndexMap { } } -pub(crate) type CompileTimeEvalContext<'tcx> = InterpCx<'tcx, CompileTimeInterpreter<'tcx>>; +pub(crate) type CompileTimeInterpCx<'tcx> = InterpCx<'tcx, CompileTimeMachine<'tcx>>; #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum MemoryKind { @@ -195,7 +195,7 @@ impl interpret::MayLeak for ! { } } -impl<'tcx> CompileTimeEvalContext<'tcx> { +impl<'tcx> CompileTimeInterpCx<'tcx> { fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) { let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span); let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo()); @@ -369,7 +369,7 @@ impl<'tcx> CompileTimeEvalContext<'tcx> { } } -impl<'tcx> interpret::Machine<'tcx> for CompileTimeInterpreter<'tcx> { +impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); type MemoryKind = MemoryKind; diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 66993476bef43..2e8ad445cf5e8 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -9,7 +9,7 @@ use rustc_target::abi::{Abi, VariantIdx}; use tracing::{debug, instrument, trace}; use super::eval_queries::{mk_eval_cx_to_read_const_val, op_to_const}; -use super::machine::CompileTimeEvalContext; +use super::machine::CompileTimeInterpCx; use super::{ValTreeCreationError, ValTreeCreationResult, VALTREE_MAX_NODES}; use crate::const_eval::CanAccessMutGlobal; use crate::errors::MaxNumNodesInConstErr; @@ -21,7 +21,7 @@ use crate::interpret::{ #[instrument(skip(ecx), level = "debug")] fn branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, n: usize, variant: Option, @@ -59,7 +59,7 @@ fn branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn slice_branches<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -77,7 +77,7 @@ fn slice_branches<'tcx>( #[instrument(skip(ecx), level = "debug")] fn const_to_valtree_inner<'tcx>( - ecx: &CompileTimeEvalContext<'tcx>, + ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, num_nodes: &mut usize, ) -> ValTreeCreationResult<'tcx> { @@ -219,7 +219,7 @@ fn reconstruct_place_meta<'tcx>( #[instrument(skip(ecx), level = "debug", ret)] fn create_valtree_place<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, layout: TyAndLayout<'tcx>, valtree: ty::ValTree<'tcx>, ) -> MPlaceTy<'tcx> { @@ -364,7 +364,7 @@ pub fn valtree_to_const_value<'tcx>( /// Put a valtree into memory and return a reference to that. fn valtree_to_ref<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, valtree: ty::ValTree<'tcx>, pointee_ty: Ty<'tcx>, ) -> Immediate { @@ -380,7 +380,7 @@ fn valtree_to_ref<'tcx>( #[instrument(skip(ecx), level = "debug")] fn valtree_into_mplace<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>, valtree: ty::ValTree<'tcx>, ) { @@ -457,6 +457,6 @@ fn valtree_into_mplace<'tcx>( } } -fn dump_place<'tcx>(ecx: &CompileTimeEvalContext<'tcx>, place: &MPlaceTy<'tcx>) { +fn dump_place<'tcx>(ecx: &CompileTimeInterpCx<'tcx>, place: &MPlaceTy<'tcx>) { trace!("{:?}", ecx.dump_place(&PlaceTy::from(place.clone()))); } diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs index 3066e0933d94d..8b0a2afa4d669 100644 --- a/compiler/rustc_const_eval/src/interpret/intern.rs +++ b/compiler/rustc_const_eval/src/interpret/intern.rs @@ -45,7 +45,7 @@ pub trait HasStaticRootDefId { fn static_def_id(&self) -> Option; } -impl HasStaticRootDefId for const_eval::CompileTimeInterpreter<'_> { +impl HasStaticRootDefId for const_eval::CompileTimeMachine<'_> { fn static_def_id(&self) -> Option { Some(self.static_root_ids?.1) } diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs index 10fd6399b9a37..f6537ed6ea9ed 100644 --- a/compiler/rustc_const_eval/src/interpret/util.rs +++ b/compiler/rustc_const_eval/src/interpret/util.rs @@ -1,4 +1,4 @@ -use crate::const_eval::{CompileTimeEvalContext, CompileTimeInterpreter, InterpretationResult}; +use crate::const_eval::{CompileTimeInterpCx, CompileTimeMachine, InterpretationResult}; use rustc_hir::def_id::LocalDefId; use rustc_middle::mir; use rustc_middle::mir::interpret::{Allocation, InterpResult, Pointer}; @@ -84,7 +84,7 @@ where impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> { fn make_result( mplace: MPlaceTy<'tcx>, - ecx: &mut InterpCx<'tcx, CompileTimeInterpreter<'tcx>>, + ecx: &mut InterpCx<'tcx, CompileTimeMachine<'tcx>>, ) -> Self { let alloc_id = mplace.ptr().provenance.unwrap().alloc_id(); let alloc = ecx.memory.alloc_map.swap_remove(&alloc_id).unwrap().1; @@ -93,7 +93,7 @@ impl<'tcx> InterpretationResult<'tcx> for mir::interpret::ConstAllocation<'tcx> } pub(crate) fn create_static_alloc<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, static_def_id: LocalDefId, layout: TyAndLayout<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx>> { diff --git a/compiler/rustc_const_eval/src/util/caller_location.rs b/compiler/rustc_const_eval/src/util/caller_location.rs index 62c5f8734a249..3b07bee2d9c27 100644 --- a/compiler/rustc_const_eval/src/util/caller_location.rs +++ b/compiler/rustc_const_eval/src/util/caller_location.rs @@ -7,12 +7,12 @@ use rustc_middle::ty::{self, Mutability}; use rustc_span::symbol::Symbol; use tracing::trace; -use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeEvalContext}; +use crate::const_eval::{mk_eval_cx_to_read_const_val, CanAccessMutGlobal, CompileTimeInterpCx}; use crate::interpret::*; /// Allocate a `const core::panic::Location` with the provided filename and line/column numbers. fn alloc_caller_location<'tcx>( - ecx: &mut CompileTimeEvalContext<'tcx>, + ecx: &mut CompileTimeInterpCx<'tcx>, filename: Symbol, line: u32, col: u32, diff --git a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs index 68fb122a765da..daf57285ebe6d 100644 --- a/compiler/rustc_const_eval/src/util/check_validity_requirement.rs +++ b/compiler/rustc_const_eval/src/util/check_validity_requirement.rs @@ -3,7 +3,7 @@ use rustc_middle::ty::layout::{LayoutCx, LayoutError, LayoutOf, TyAndLayout, Val use rustc_middle::ty::{ParamEnv, ParamEnvAnd, Ty, TyCtxt}; use rustc_target::abi::{Abi, FieldsShape, Scalar, Variants}; -use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeInterpreter}; +use crate::const_eval::{CanAccessMutGlobal, CheckAlignment, CompileTimeMachine}; use crate::interpret::{InterpCx, MemoryKind, OpTy}; /// Determines if this type permits "raw" initialization by just transmuting some memory into an @@ -45,7 +45,7 @@ fn might_permit_raw_init_strict<'tcx>( tcx: TyCtxt<'tcx>, kind: ValidityRequirement, ) -> Result> { - let machine = CompileTimeInterpreter::new(CanAccessMutGlobal::No, CheckAlignment::Error); + let machine = CompileTimeMachine::new(CanAccessMutGlobal::No, CheckAlignment::Error); let mut cx = InterpCx::new(tcx, rustc_span::DUMMY_SP, ParamEnv::reveal_all(), machine); From 54e24c15736e7602fe4d84641ac6d5c973397114 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Thu, 13 Jun 2024 11:30:24 +0200 Subject: [PATCH 18/18] const-eval: make lint scope computation consistent --- .../rustc_const_eval/src/const_eval/error.rs | 12 ++------- .../src/const_eval/eval_queries.rs | 2 +- .../src/const_eval/machine.rs | 14 ++++++++-- .../src/interpret/eval_context.rs | 27 +++++++------------ 4 files changed, 25 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs index 94f4ae2556de5..b17dc7f3ddde6 100644 --- a/compiler/rustc_const_eval/src/const_eval/error.rs +++ b/compiler/rustc_const_eval/src/const_eval/error.rs @@ -1,7 +1,6 @@ use std::mem; use rustc_errors::{DiagArgName, DiagArgValue, DiagMessage, Diagnostic, IntoDiagArg}; -use rustc_hir::CRATE_HIR_ID; use rustc_middle::mir::interpret::{Provenance, ReportedErrorInfo}; use rustc_middle::mir::AssertKind; use rustc_middle::query::TyCtxtAt; @@ -156,7 +155,7 @@ where } } -/// Emit a lint from a const-eval situation. +/// Emit a lint from a const-eval situation, with a backtrace. // Even if this is unused, please don't remove it -- chances are we will need to emit a lint during const-eval again in the future! pub(super) fn lint<'tcx, L>( tcx: TyCtxtAt<'tcx>, @@ -168,12 +167,5 @@ pub(super) fn lint<'tcx, L>( { let (span, frames) = get_span_and_frames(tcx, &machine.stack); - tcx.emit_node_span_lint( - lint, - // We use the root frame for this so the crate that defines the const defines whether the - // lint is emitted. - machine.stack.first().and_then(|frame| frame.lint_root()).unwrap_or(CRATE_HIR_ID), - span, - decorator(frames), - ); + tcx.emit_node_span_lint(lint, machine.best_lint_scope(*tcx), span, decorator(frames)); } diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs index 88a1503ee89c8..4b8145eb4855b 100644 --- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs +++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs @@ -114,7 +114,7 @@ fn eval_body_using_ecx<'tcx, R: InterpretationResult<'tcx>>( let err_diag = errors::MutablePtrInFinal { span: ecx.tcx.span, kind: intern_kind }; ecx.tcx.emit_node_span_lint( lint::builtin::CONST_EVAL_MUTABLE_PTR_IN_FINAL_VALUE, - ecx.best_lint_scope(), + ecx.machine.best_lint_scope(*ecx.tcx), err_diag.span, err_diag, ) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 0dbb6a95376dd..4f6df857142cf 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -9,12 +9,13 @@ use rustc_data_structures::fx::IndexEntry; use rustc_hir::def_id::DefId; use rustc_hir::def_id::LocalDefId; use rustc_hir::LangItem; +use rustc_hir::{self as hir, CRATE_HIR_ID}; use rustc_middle::bug; use rustc_middle::mir; use rustc_middle::mir::AssertMessage; use rustc_middle::query::TyCtxtAt; -use rustc_middle::ty; use rustc_middle::ty::layout::{FnAbiOf, TyAndLayout}; +use rustc_middle::ty::{self, TyCtxt}; use rustc_session::lint::builtin::WRITES_THROUGH_IMMUTABLE_POINTER; use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; @@ -369,6 +370,15 @@ impl<'tcx> CompileTimeInterpCx<'tcx> { } } +impl<'tcx> CompileTimeMachine<'tcx> { + #[inline(always)] + /// Find the first stack frame that is within the current crate, if any. + /// Otherwise, return the crate's HirId + pub fn best_lint_scope(&self, tcx: TyCtxt<'tcx>) -> hir::HirId { + self.stack.iter().find_map(|frame| frame.lint_root(tcx)).unwrap_or(CRATE_HIR_ID) + } +} + impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { compile_time_machine!(<'tcx>); @@ -600,7 +610,7 @@ impl<'tcx> interpret::Machine<'tcx> for CompileTimeMachine<'tcx> { // By default, we stop after a million steps, but the user can disable this lint // to be able to run until the heat death of the universe or power loss, whichever // comes first. - let hir_id = ecx.best_lint_scope(); + let hir_id = ecx.machine.best_lint_scope(*ecx.tcx); let is_error = ecx .tcx .lint_level_at_node( diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 6357219750816..4d93038a81e44 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -4,7 +4,6 @@ use std::{fmt, mem}; use either::{Either, Left, Right}; use tracing::{debug, info, info_span, instrument, trace}; -use hir::CRATE_HIR_ID; use rustc_errors::DiagCtxt; use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData}; use rustc_index::IndexVec; @@ -271,13 +270,18 @@ impl<'tcx, Prov: Provenance, Extra> Frame<'tcx, Prov, Extra> { } } - pub fn lint_root(&self) -> Option { - self.current_source_info().and_then(|source_info| { - match &self.body.source_scopes[source_info.scope].local_data { + pub fn lint_root(&self, tcx: TyCtxt<'tcx>) -> Option { + // We first try to get a HirId via the current source scope, + // and fall back to `body.source`. + self.current_source_info() + .and_then(|source_info| match &self.body.source_scopes[source_info.scope].local_data { mir::ClearCrossCrate::Set(data) => Some(data.lint_root), mir::ClearCrossCrate::Clear => None, - } - }) + }) + .or_else(|| { + let def_id = self.body.source.def_id().as_local(); + def_id.map(|def_id| tcx.local_def_id_to_hir_id(def_id)) + }) } /// Returns the address of the buffer where the locals are stored. This is used by `Place` as a @@ -509,17 +513,6 @@ impl<'tcx, M: Machine<'tcx>> InterpCx<'tcx, M> { self.stack().last().map_or(self.tcx.span, |f| f.current_span()) } - /// Find the first stack frame that is within the current crate, if any; - /// otherwise return the crate's HirId. - #[inline(always)] - pub fn best_lint_scope(&self) -> hir::HirId { - self.stack() - .iter() - .find_map(|frame| frame.body.source.def_id().as_local()) - .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id)) - } - - #[inline(always)] pub(crate) fn stack(&self) -> &[Frame<'tcx, M::Provenance, M::FrameExtra>] { M::stack(self) }