From 2a6a42329f79d3c2a42f23ca9fb68aba511a2bc1 Mon Sep 17 00:00:00 2001 From: surechen Date: Tue, 25 Jun 2024 10:00:30 +0800 Subject: [PATCH 01/14] Change E0369 diagnostic give note information for foreign items. Make it easy for developers to understand why the binop cannot be applied. fixes #125631 --- .../rustc_hir_typeck/src/method/suggest.rs | 102 +++++++++++++----- tests/ui/array-slice-vec/vec-res-add.stderr | 5 + tests/ui/autoderef-full-lval.stderr | 12 +++ .../binary-op-not-allowed-issue-125631.rs | 16 +++ .../binary-op-not-allowed-issue-125631.stderr | 75 +++++++++++++ tests/ui/binop/binop-bitxor-str.stderr | 5 + tests/ui/error-codes/E0067.stderr | 6 ++ tests/ui/issues/issue-14915.stderr | 6 ++ tests/ui/minus-string.stderr | 5 + tests/ui/pattern/pattern-tyvar-2.stderr | 5 + .../ui/typeck/assign-non-lval-derefmut.stderr | 8 ++ 11 files changed, 219 insertions(+), 26 deletions(-) create mode 100644 tests/ui/binop/binary-op-not-allowed-issue-125631.rs create mode 100644 tests/ui/binop/binary-op-not-allowed-issue-125631.stderr diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 6a44d2afc15ca..ff066bb9edeb9 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2788,32 +2788,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { errors: Vec>, suggest_derive: bool, ) { - let all_local_types_needing_impls = - errors.iter().all(|e| match e.obligation.predicate.kind().skip_binder() { + let preds: Vec<_> = errors + .iter() + .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => { match pred.self_ty().kind() { - ty::Adt(def, _) => def.did().is_local(), - _ => false, + ty::Adt(_, _) => Some(pred), + _ => None, } } - _ => false, - }); - let mut preds: Vec<_> = errors - .iter() - .filter_map(|e| match e.obligation.predicate.kind().skip_binder() { - ty::PredicateKind::Clause(ty::ClauseKind::Trait(pred)) => Some(pred), _ => None, }) .collect(); - preds.sort_by_key(|pred| pred.trait_ref.to_string()); - let def_ids = preds + + // Note for local items and foreign items respectively. + let (mut local_preds, mut foreign_preds): (Vec<_>, Vec<_>) = + preds.iter().partition(|&pred| { + if let ty::Adt(def, _) = pred.self_ty().kind() { + def.did().is_local() + } else { + false + } + }); + + local_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + let local_def_ids = local_preds .iter() .filter_map(|pred| match pred.self_ty().kind() { ty::Adt(def, _) => Some(def.did()), _ => None, }) .collect::>(); - let mut spans: MultiSpan = def_ids + let mut local_spans: MultiSpan = local_def_ids .iter() .filter_map(|def_id| { let span = self.tcx.def_span(*def_id); @@ -2821,11 +2827,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }) .collect::>() .into(); - - for pred in &preds { + for pred in &local_preds { match pred.self_ty().kind() { - ty::Adt(def, _) if def.did().is_local() => { - spans.push_span_label( + ty::Adt(def, _) => { + local_spans.push_span_label( self.tcx.def_span(def.did()), format!("must implement `{}`", pred.trait_ref.print_trait_sugared()), ); @@ -2833,24 +2838,69 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => {} } } - - if all_local_types_needing_impls && spans.primary_span().is_some() { - let msg = if preds.len() == 1 { + if local_spans.primary_span().is_some() { + let msg = if local_preds.len() == 1 { format!( "an implementation of `{}` might be missing for `{}`", - preds[0].trait_ref.print_trait_sugared(), - preds[0].self_ty() + local_preds[0].trait_ref.print_trait_sugared(), + local_preds[0].self_ty() ) } else { format!( "the following type{} would have to `impl` {} required trait{} for this \ operation to be valid", - pluralize!(def_ids.len()), - if def_ids.len() == 1 { "its" } else { "their" }, - pluralize!(preds.len()), + pluralize!(local_def_ids.len()), + if local_def_ids.len() == 1 { "its" } else { "their" }, + pluralize!(local_preds.len()), + ) + }; + err.span_note(local_spans, msg); + } + + foreign_preds.sort_by_key(|pred: &&ty::TraitPredicate<'_>| pred.trait_ref.to_string()); + let foreign_def_ids = foreign_preds + .iter() + .filter_map(|pred| match pred.self_ty().kind() { + ty::Adt(def, _) => Some(def.did()), + _ => None, + }) + .collect::>(); + let mut foreign_spans: MultiSpan = foreign_def_ids + .iter() + .filter_map(|def_id| { + let span = self.tcx.def_span(*def_id); + if span.is_dummy() { None } else { Some(span) } + }) + .collect::>() + .into(); + for pred in &foreign_preds { + match pred.self_ty().kind() { + ty::Adt(def, _) => { + foreign_spans.push_span_label( + self.tcx.def_span(def.did()), + format!("not implement `{}`", pred.trait_ref.print_trait_sugared()), + ); + } + _ => {} + } + } + if foreign_spans.primary_span().is_some() { + let msg = if foreign_preds.len() == 1 { + format!( + "the foreign item type `{}` doesn't implement `{}`", + foreign_preds[0].self_ty(), + foreign_preds[0].trait_ref.print_trait_sugared() + ) + } else { + format!( + "the foreign item type{} {} implement required trait{} for this \ + operation to be valid", + pluralize!(foreign_def_ids.len()), + if foreign_def_ids.len() > 1 { "don't" } else { "doesn't" }, + pluralize!(foreign_preds.len()), ) }; - err.span_note(spans, msg); + err.span_note(foreign_spans, msg); } let preds: Vec<_> = errors diff --git a/tests/ui/array-slice-vec/vec-res-add.stderr b/tests/ui/array-slice-vec/vec-res-add.stderr index cf5796f7e4a4a..34fd69426a8bb 100644 --- a/tests/ui/array-slice-vec/vec-res-add.stderr +++ b/tests/ui/array-slice-vec/vec-res-add.stderr @@ -5,6 +5,11 @@ LL | let k = i + j; | - ^ - Vec | | | Vec + | +note: the foreign item type `Vec` doesn't implement `Add` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: not implement `Add` error: aborting due to 1 previous error diff --git a/tests/ui/autoderef-full-lval.stderr b/tests/ui/autoderef-full-lval.stderr index 9921ce7c15440..d90238a7fb210 100644 --- a/tests/ui/autoderef-full-lval.stderr +++ b/tests/ui/autoderef-full-lval.stderr @@ -5,6 +5,12 @@ LL | let z: isize = a.x + b.y; | --- ^ --- Box | | | Box + | +note: the foreign item type `Box` doesn't implement `Add` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add` error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:21:33 @@ -13,6 +19,12 @@ LL | let answer: isize = forty.a + two.a; | ------- ^ ----- Box | | | Box + | +note: the foreign item type `Box` doesn't implement `Add` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add` error: aborting due to 2 previous errors diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.rs b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs new file mode 100644 index 0000000000000..8827bbb003b14 --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.rs @@ -0,0 +1,16 @@ +use std::io::{Error, ErrorKind}; +use std::thread; + +struct T1; +struct T2; + +fn main() { + (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "2"), thread::current()) + == (Error::new(ErrorKind::Other, "2"), thread::current()); + //~^ERROR binary operation `==` cannot be applied to type + (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2) + == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2); + //~^ERROR binary operation `==` cannot be applied to type +} diff --git a/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr new file mode 100644 index 0000000000000..1cf75bbc1a570 --- /dev/null +++ b/tests/ui/binop/binary-op-not-allowed-issue-125631.stderr @@ -0,0 +1,75 @@ +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, T1, {integer})` + --> $DIR/binary-op-not-allowed-issue-125631.rs:8:48 + | +LL | (Error::new(ErrorKind::Other, "1"), T1, 1) == (Error::new(ErrorKind::Other, "1"), T1, 2); + | ------------------------------------------ ^^ ------------------------------------------ (std::io::Error, T1, {integer}) + | | + | (std::io::Error, T1, {integer}) + | +note: an implementation of `PartialEq` might be missing for `T1` + --> $DIR/binary-op-not-allowed-issue-125631.rs:4:1 + | +LL | struct T1; + | ^^^^^^^^^ must implement `PartialEq` +note: the foreign item type `std::io::Error` doesn't implement `PartialEq` + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` +help: consider annotating `T1` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T1; + | + +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread)` + --> $DIR/binary-op-not-allowed-issue-125631.rs:11:9 + | +LL | (Error::new(ErrorKind::Other, "2"), thread::current()) + | ------------------------------------------------------ (std::io::Error, Thread) +LL | == (Error::new(ErrorKind::Other, "2"), thread::current()); + | ^^ ------------------------------------------------------ (std::io::Error, Thread) + | +note: the foreign item types don't implement required traits for this operation to be valid + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` + --> $SRC_DIR/std/src/thread/mod.rs:LL:COL + | + = note: not implement `PartialEq` + +error[E0369]: binary operation `==` cannot be applied to type `(std::io::Error, Thread, T1, T2)` + --> $DIR/binary-op-not-allowed-issue-125631.rs:14:9 + | +LL | (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2) + | -------------------------------------------------------------- (std::io::Error, Thread, T1, T2) +LL | == (Error::new(ErrorKind::Other, "4"), thread::current(), T1, T2); + | ^^ -------------------------------------------------------------- (std::io::Error, Thread, T1, T2) + | +note: the following types would have to `impl` their required traits for this operation to be valid + --> $DIR/binary-op-not-allowed-issue-125631.rs:4:1 + | +LL | struct T1; + | ^^^^^^^^^ must implement `PartialEq` +LL | struct T2; + | ^^^^^^^^^ must implement `PartialEq` +note: the foreign item types don't implement required traits for this operation to be valid + --> $SRC_DIR/std/src/io/error.rs:LL:COL + | + = note: not implement `PartialEq` + --> $SRC_DIR/std/src/thread/mod.rs:LL:COL + | + = note: not implement `PartialEq` +help: consider annotating `T1` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T1; + | +help: consider annotating `T2` with `#[derive(PartialEq)]` + | +LL + #[derive(PartialEq)] +LL | struct T2; + | + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0369`. diff --git a/tests/ui/binop/binop-bitxor-str.stderr b/tests/ui/binop/binop-bitxor-str.stderr index 20b1ecc5a939e..9d9ec6c5af6be 100644 --- a/tests/ui/binop/binop-bitxor-str.stderr +++ b/tests/ui/binop/binop-bitxor-str.stderr @@ -5,6 +5,11 @@ LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } | --------------- ^ --------------- String | | | String + | +note: the foreign item type `String` doesn't implement `BitXor` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + | + = note: not implement `BitXor` error: aborting due to 1 previous error diff --git a/tests/ui/error-codes/E0067.stderr b/tests/ui/error-codes/E0067.stderr index ec0358cb7dfe6..71b7208054423 100644 --- a/tests/ui/error-codes/E0067.stderr +++ b/tests/ui/error-codes/E0067.stderr @@ -5,6 +5,12 @@ LL | LinkedList::new() += 1; | -----------------^^^^^ | | | cannot use `+=` on type `LinkedList<_>` + | +note: the foreign item type `LinkedList<_>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL + ::: $SRC_DIR/alloc/src/collections/linked_list.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/tests/ui/issues/issue-14915.stderr b/tests/ui/issues/issue-14915.stderr index 279f5772d21d3..3558bd651c62a 100644 --- a/tests/ui/issues/issue-14915.stderr +++ b/tests/ui/issues/issue-14915.stderr @@ -5,6 +5,12 @@ LL | println!("{}", x + 1); | - ^ - {integer} | | | Box + | +note: the foreign item type `Box` doesn't implement `Add<{integer}>` + --> $SRC_DIR/alloc/src/boxed.rs:LL:COL + ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL + | + = note: not implement `Add<{integer}>` error: aborting due to 1 previous error diff --git a/tests/ui/minus-string.stderr b/tests/ui/minus-string.stderr index 105274ee7d0e8..cf63ec2441670 100644 --- a/tests/ui/minus-string.stderr +++ b/tests/ui/minus-string.stderr @@ -3,6 +3,11 @@ error[E0600]: cannot apply unary operator `-` to type `String` | LL | fn main() { -"foo".to_string(); } | ^^^^^^^^^^^^^^^^^^ cannot apply unary operator `-` + | +note: the foreign item type `String` doesn't implement `Neg` + --> $SRC_DIR/alloc/src/string.rs:LL:COL + | + = note: not implement `Neg` error: aborting due to 1 previous error diff --git a/tests/ui/pattern/pattern-tyvar-2.stderr b/tests/ui/pattern/pattern-tyvar-2.stderr index c6540e795589f..be52fa8b23943 100644 --- a/tests/ui/pattern/pattern-tyvar-2.stderr +++ b/tests/ui/pattern/pattern-tyvar-2.stderr @@ -5,6 +5,11 @@ LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; | - ^ - {integer} | | | Vec + | +note: the foreign item type `Vec` doesn't implement `Mul<{integer}>` + --> $SRC_DIR/alloc/src/vec/mod.rs:LL:COL + | + = note: not implement `Mul<{integer}>` error: aborting due to 1 previous error diff --git a/tests/ui/typeck/assign-non-lval-derefmut.stderr b/tests/ui/typeck/assign-non-lval-derefmut.stderr index b26d16da01521..ce0ff1d957b53 100644 --- a/tests/ui/typeck/assign-non-lval-derefmut.stderr +++ b/tests/ui/typeck/assign-non-lval-derefmut.stderr @@ -19,6 +19,10 @@ LL | x.lock().unwrap() += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | +note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *x.lock().unwrap() += 1; @@ -47,6 +51,10 @@ LL | y += 1; | | | cannot use `+=` on type `MutexGuard<'_, usize>` | +note: the foreign item type `MutexGuard<'_, usize>` doesn't implement `AddAssign<{integer}>` + --> $SRC_DIR/std/src/sync/mutex.rs:LL:COL + | + = note: not implement `AddAssign<{integer}>` help: `+=` can be used on `usize` if you dereference the left-hand side | LL | *y += 1; From d9a34232888629efb8226a9c791b40a384986ef8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 25 Jun 2024 12:02:55 +0200 Subject: [PATCH 02/14] miri: make sure we can find link_section statics even for the local crate --- compiler/rustc_passes/src/reachable.rs | 12 ++---------- .../miri/tests/pass/tls/win_tls_callback.rs | 16 ++++++++++++++++ .../miri/tests/pass/tls/win_tls_callback.stderr | 1 + 3 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 src/tools/miri/tests/pass/tls/win_tls_callback.rs create mode 100644 src/tools/miri/tests/pass/tls/win_tls_callback.stderr diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 6dd8eaf7e6734..da4435ebebe87 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -30,7 +30,7 @@ use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::intravisit::{self, Visitor}; use rustc_hir::Node; use rustc_middle::bug; -use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; +use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::middle::privacy::{self, Level}; use rustc_middle::mir::interpret::{ConstAllocation, ErrorHandled, GlobalAlloc}; use rustc_middle::query::Providers; @@ -178,15 +178,7 @@ impl<'tcx> ReachableContext<'tcx> { if !self.any_library { // If we are building an executable, only explicitly extern // types need to be exported. - let codegen_attrs = if self.tcx.def_kind(search_item).has_codegen_attrs() { - self.tcx.codegen_fn_attrs(search_item) - } else { - CodegenFnAttrs::EMPTY - }; - let is_extern = codegen_attrs.contains_extern_indicator(); - let std_internal = - codegen_attrs.flags.contains(CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL); - if is_extern || std_internal { + if has_custom_linkage(self.tcx, search_item) { self.reachable_symbols.insert(search_item); } } else { diff --git a/src/tools/miri/tests/pass/tls/win_tls_callback.rs b/src/tools/miri/tests/pass/tls/win_tls_callback.rs new file mode 100644 index 0000000000000..99a8de29e9170 --- /dev/null +++ b/src/tools/miri/tests/pass/tls/win_tls_callback.rs @@ -0,0 +1,16 @@ +//! Ensure that we call Windows TLS callbacks in the local crate. +//@only-target-windows +// Calling eprintln in the callback seems to (re-)initialize some thread-local storage +// and then leak the memory allocated for that. Let's just ignore these leaks, +// that's not what this test is about. +//@compile-flags: -Zmiri-ignore-leaks + +#[link_section = ".CRT$XLB"] +#[used] // Miri only considers explicitly `#[used]` statics for `lookup_link_section` +pub static CALLBACK: unsafe extern "system" fn(*const (), u32, *const ()) = tls_callback; + +unsafe extern "system" fn tls_callback(_h: *const (), _dw_reason: u32, _pv: *const ()) { + eprintln!("in tls_callback"); +} + +fn main() {} diff --git a/src/tools/miri/tests/pass/tls/win_tls_callback.stderr b/src/tools/miri/tests/pass/tls/win_tls_callback.stderr new file mode 100644 index 0000000000000..8479558954456 --- /dev/null +++ b/src/tools/miri/tests/pass/tls/win_tls_callback.stderr @@ -0,0 +1 @@ +in tls_callback From b6074fffd1d1a8d1eee4e3b9e9431761761b80c1 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Tue, 25 Jun 2024 19:03:39 +0300 Subject: [PATCH 03/14] resolve: Tweak some naming around import ambiguities --- .../src/effective_visibilities.rs | 2 +- compiler/rustc_resolve/src/imports.rs | 74 ++++++++----------- compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 14 ++-- 4 files changed, 42 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs index aab4a3366daa5..dabed23883866 100644 --- a/compiler/rustc_resolve/src/effective_visibilities.rs +++ b/compiler/rustc_resolve/src/effective_visibilities.rs @@ -99,7 +99,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> { // is the maximum value among visibilities of bindings corresponding to that def id. for (binding, eff_vis) in visitor.import_effective_visibilities.iter() { let NameBindingKind::Import { import, .. } = binding.kind else { unreachable!() }; - if !binding.is_ambiguity() { + if !binding.is_ambiguity_recursive() { if let Some(node_id) = import.id() { r.effective_visibilities.update_eff_vis(r.local_def_id(node_id), eff_vis, r.tcx) } diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 96a4647b94281..3896fe4c4fa64 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -325,8 +325,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } match (old_binding.is_glob_import(), binding.is_glob_import()) { (true, true) => { - // FIXME: remove `!binding.is_ambiguity()` after delete the warning ambiguity. - if !binding.is_ambiguity() + // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. + if !binding.is_ambiguity_recursive() && let NameBindingKind::Import { import: old_import, .. } = old_binding.kind && let NameBindingKind::Import { import, .. } = binding.kind @@ -337,21 +337,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { // imported from the same glob-import statement. resolution.binding = Some(binding); } else if res != old_binding.res() { - let binding = if warn_ambiguity { - this.warn_ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding) - } else { - this.ambiguity(AmbiguityKind::GlobVsGlob, old_binding, binding) - }; - resolution.binding = Some(binding); + resolution.binding = Some(this.new_ambiguity_binding( + AmbiguityKind::GlobVsGlob, + old_binding, + binding, + warn_ambiguity, + )); } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { // We are glob-importing the same item but with greater visibility. resolution.binding = Some(binding); - } else if binding.is_ambiguity() { - resolution.binding = - Some(self.arenas.alloc_name_binding(NameBindingData { - warn_ambiguity: true, - ..(*binding).clone() - })); + } else if binding.is_ambiguity_recursive() { + resolution.binding = Some(this.new_warn_ambiguity_binding(binding)); } } (old_glob @ true, false) | (old_glob @ false, true) => { @@ -361,24 +357,26 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { && nonglob_binding.expansion != LocalExpnId::ROOT && glob_binding.res() != nonglob_binding.res() { - resolution.binding = Some(this.ambiguity( + resolution.binding = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsExpanded, nonglob_binding, glob_binding, + false, )); } else { resolution.binding = Some(nonglob_binding); } - if let Some(old_binding) = resolution.shadowed_glob { - assert!(old_binding.is_glob_import()); - if glob_binding.res() != old_binding.res() { - resolution.shadowed_glob = Some(this.ambiguity( + if let Some(old_shadowed_glob) = resolution.shadowed_glob { + assert!(old_shadowed_glob.is_glob_import()); + if glob_binding.res() != old_shadowed_glob.res() { + resolution.shadowed_glob = Some(this.new_ambiguity_binding( AmbiguityKind::GlobVsGlob, - old_binding, + old_shadowed_glob, glob_binding, + false, )); - } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { + } else if !old_shadowed_glob.vis.is_at_least(binding.vis, this.tcx) { resolution.shadowed_glob = Some(glob_binding); } } else { @@ -397,29 +395,21 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { }) } - fn ambiguity( + fn new_ambiguity_binding( &self, - kind: AmbiguityKind, + ambiguity_kind: AmbiguityKind, primary_binding: NameBinding<'a>, secondary_binding: NameBinding<'a>, + warn_ambiguity: bool, ) -> NameBinding<'a> { - self.arenas.alloc_name_binding(NameBindingData { - ambiguity: Some((secondary_binding, kind)), - ..(*primary_binding).clone() - }) + let ambiguity = Some((secondary_binding, ambiguity_kind)); + let data = NameBindingData { ambiguity, warn_ambiguity, ..*primary_binding }; + self.arenas.alloc_name_binding(data) } - fn warn_ambiguity( - &self, - kind: AmbiguityKind, - primary_binding: NameBinding<'a>, - secondary_binding: NameBinding<'a>, - ) -> NameBinding<'a> { - self.arenas.alloc_name_binding(NameBindingData { - ambiguity: Some((secondary_binding, kind)), - warn_ambiguity: true, - ..(*primary_binding).clone() - }) + fn new_warn_ambiguity_binding(&self, binding: NameBinding<'a>) -> NameBinding<'a> { + assert!(binding.is_ambiguity_recursive()); + self.arenas.alloc_name_binding(NameBindingData { warn_ambiguity: true, ..*binding }) } // Use `f` to mutate the resolution of the name in the module. @@ -1381,8 +1371,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { target_bindings[ns].get(), ) { Ok(other_binding) => { - is_redundant = - binding.res() == other_binding.res() && !other_binding.is_ambiguity(); + is_redundant = binding.res() == other_binding.res() + && !other_binding.is_ambiguity_recursive(); if is_redundant { redundant_span[ns] = Some((other_binding.span, other_binding.is_import())); @@ -1455,7 +1445,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { .resolution(import.parent_scope.module, key) .borrow() .binding() - .is_some_and(|binding| binding.is_warn_ambiguity()); + .is_some_and(|binding| binding.warn_ambiguity_recursive()); let _ = self.try_define( import.parent_scope.module, key, @@ -1480,7 +1470,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { module.for_each_child(self, |this, ident, _, binding| { let res = binding.res().expect_non_local(); - let error_ambiguity = binding.is_ambiguity() && !binding.warn_ambiguity; + let error_ambiguity = binding.is_ambiguity_recursive() && !binding.warn_ambiguity; if res != def::Res::Err && !error_ambiguity { let mut reexport_chain = SmallVec::new(); let mut next_binding = binding; diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5ab6ba23a7da6..66a1c05289b7d 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3730,7 +3730,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> { let ls_binding = self.maybe_resolve_ident_in_lexical_scope(ident, ValueNS)?; let (res, binding) = match ls_binding { LexicalScopeBinding::Item(binding) - if is_syntactic_ambiguity && binding.is_ambiguity() => + if is_syntactic_ambiguity && binding.is_ambiguity_recursive() => { // For ambiguous bindings we don't know all their definitions and cannot check // whether they can be shadowed by fresh bindings or not, so force an error. diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 3a831a7f19e06..94cdce1025fe5 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -694,10 +694,12 @@ impl<'a> fmt::Debug for Module<'a> { } /// Records a possibly-private value, type, or module definition. -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] struct NameBindingData<'a> { kind: NameBindingKind<'a>, ambiguity: Option<(NameBinding<'a>, AmbiguityKind)>, + /// Produce a warning instead of an error when reporting ambiguities inside this binding. + /// May apply to indirect ambiguities under imports, so `ambiguity.is_some()` is not required. warn_ambiguity: bool, expansion: LocalExpnId, span: Span, @@ -718,7 +720,7 @@ impl<'a> ToNameBinding<'a> for NameBinding<'a> { } } -#[derive(Clone, Debug)] +#[derive(Clone, Copy, Debug)] enum NameBindingKind<'a> { Res(Res), Module(Module<'a>), @@ -830,18 +832,18 @@ impl<'a> NameBindingData<'a> { } } - fn is_ambiguity(&self) -> bool { + fn is_ambiguity_recursive(&self) -> bool { self.ambiguity.is_some() || match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_ambiguity(), + NameBindingKind::Import { binding, .. } => binding.is_ambiguity_recursive(), _ => false, } } - fn is_warn_ambiguity(&self) -> bool { + fn warn_ambiguity_recursive(&self) -> bool { self.warn_ambiguity || match self.kind { - NameBindingKind::Import { binding, .. } => binding.is_warn_ambiguity(), + NameBindingKind::Import { binding, .. } => binding.warn_ambiguity_recursive(), _ => false, } } From 6ba0a84df9172ea01f3c3661b4d8364e5a79ba69 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 14:27:43 -0400 Subject: [PATCH 04/14] rewrite lto-empty to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/lto-empty/Makefile | 13 ------------- tests/run-make/lto-empty/rmake.rs | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 14 deletions(-) delete mode 100644 tests/run-make/lto-empty/Makefile create mode 100644 tests/run-make/lto-empty/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 07073ef5d40c7..7c882d3ce15f5 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -97,7 +97,6 @@ run-make/long-linker-command-lines-cmd-exe/Makefile run-make/long-linker-command-lines/Makefile run-make/longjmp-across-rust/Makefile run-make/lto-dylib-dep/Makefile -run-make/lto-empty/Makefile run-make/lto-linkage-used-attr/Makefile run-make/lto-no-link-whole-rlib/Makefile run-make/lto-smoke-c/Makefile diff --git a/tests/run-make/lto-empty/Makefile b/tests/run-make/lto-empty/Makefile deleted file mode 100644 index 1b795c4b73805..0000000000000 --- a/tests/run-make/lto-empty/Makefile +++ /dev/null @@ -1,13 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -all: cdylib-fat cdylib-thin - -cdylib-fat: - $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat - $(RUSTC) lib.rs -C lto=fat -C opt-level=3 -C incremental=$(TMPDIR)/inc-fat - -cdylib-thin: - $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin - $(RUSTC) lib.rs -C lto=thin -C opt-level=3 -C incremental=$(TMPDIR)/inc-thin - diff --git a/tests/run-make/lto-empty/rmake.rs b/tests/run-make/lto-empty/rmake.rs new file mode 100644 index 0000000000000..7146d6e10ef9e --- /dev/null +++ b/tests/run-make/lto-empty/rmake.rs @@ -0,0 +1,17 @@ +// Compiling Rust code twice in a row with "fat" link-time-optimizations used to cause +// an internal compiler error (ICE). This was due to how the compiler would cache some modules +// to make subsequent compilations faster, at least one of which was required for LTO to link +// into. After this was patched in #63956, this test checks that the bug does not make +// a resurgence. +// See https://github.com/rust-lang/rust/issues/63349 + +//@ ignore-cross-compile + +use run_make_support::rustc; + +fn main() { + rustc().input("lib.rs").arg("-Clto=fat").opt_level("3").incremental("inc-fat").run(); + rustc().input("lib.rs").arg("-Clto=fat").opt_level("3").incremental("inc-fat").run(); + rustc().input("lib.rs").arg("-Clto=thin").opt_level("3").incremental("inc-thin").run(); + rustc().input("lib.rs").arg("-Clto=thin").opt_level("3").incremental("inc-thin").run(); +} From fe2406bcef7d0c51a39537283c7c151c8a2da238 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 14:45:49 -0400 Subject: [PATCH 05/14] rewrite invalid-so to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/invalid-so/Makefile | 7 ------- tests/run-make/invalid-so/rmake.rs | 17 +++++++++++++++++ 3 files changed, 17 insertions(+), 8 deletions(-) delete mode 100644 tests/run-make/invalid-so/Makefile create mode 100644 tests/run-make/invalid-so/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 7c882d3ce15f5..560fd5c586eec 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -55,7 +55,6 @@ run-make/incr-foreign-head-span/Makefile run-make/interdependent-c-libraries/Makefile run-make/intrinsic-unreachable/Makefile run-make/invalid-library/Makefile -run-make/invalid-so/Makefile run-make/issue-107094/Makefile run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile diff --git a/tests/run-make/invalid-so/Makefile b/tests/run-make/invalid-so/Makefile deleted file mode 100644 index e36c7040bc6ca..0000000000000 --- a/tests/run-make/invalid-so/Makefile +++ /dev/null @@ -1,7 +0,0 @@ -include ../tools.mk - -DYLIB_NAME := $(shell echo | $(RUSTC) --crate-name foo --crate-type dylib --print file-names -) - -all: - echo >> $(TMPDIR)/$(DYLIB_NAME) - $(RUSTC) --crate-type lib --extern foo=$(TMPDIR)/$(DYLIB_NAME) bar.rs 2>&1 | $(CGREP) 'invalid metadata files for crate `foo`' diff --git a/tests/run-make/invalid-so/rmake.rs b/tests/run-make/invalid-so/rmake.rs new file mode 100644 index 0000000000000..5cfda05334eb1 --- /dev/null +++ b/tests/run-make/invalid-so/rmake.rs @@ -0,0 +1,17 @@ +// When a fake library was given to the compiler, it would +// result in an obscure and unhelpful error message. This test +// creates a false "foo" dylib, and checks that the standard error +// explains that the file exists, but that its metadata is incorrect. +// See https://github.com/rust-lang/rust/pull/88368 + +use run_make_support::{dynamic_lib_name, fs_wrapper, rustc}; + +fn main() { + fs_wrapper::create_file(dynamic_lib_name("foo")); + rustc() + .crate_type("lib") + .extern_("foo", dynamic_lib_name("foo")) + .input("bar.rs") + .run_fail() + .assert_stderr_contains("invalid metadata files for crate `foo`"); +} From ee529b72f911250a4c5b717f42fb955cdc08aad5 Mon Sep 17 00:00:00 2001 From: Oneirical Date: Tue, 25 Jun 2024 15:02:19 -0400 Subject: [PATCH 06/14] rewrite and rename issue-20626 to rmake --- .../tidy/src/allowed_run_make_makefiles.txt | 1 - tests/run-make/issue-20626/Makefile | 9 --------- .../foo.rs | 0 .../rmake.rs | 16 ++++++++++++++++ 4 files changed, 16 insertions(+), 10 deletions(-) delete mode 100644 tests/run-make/issue-20626/Makefile rename tests/run-make/{issue-20626 => raw-fn-pointer-opt-undefined-behavior}/foo.rs (100%) create mode 100644 tests/run-make/raw-fn-pointer-opt-undefined-behavior/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 560fd5c586eec..cb68589d8a4c2 100644 --- a/src/tools/tidy/src/allowed_run_make_makefiles.txt +++ b/src/tools/tidy/src/allowed_run_make_makefiles.txt @@ -60,7 +60,6 @@ run-make/issue-109934-lto-debuginfo/Makefile run-make/issue-14698/Makefile run-make/issue-15460/Makefile run-make/issue-18943/Makefile -run-make/issue-20626/Makefile run-make/issue-22131/Makefile run-make/issue-25581/Makefile run-make/issue-26006/Makefile diff --git a/tests/run-make/issue-20626/Makefile b/tests/run-make/issue-20626/Makefile deleted file mode 100644 index 63eee910a9c3a..0000000000000 --- a/tests/run-make/issue-20626/Makefile +++ /dev/null @@ -1,9 +0,0 @@ -# ignore-cross-compile -include ../tools.mk - -# Test output to be four -# The original error only occurred when printing, not when comparing using assert! - -all: - $(RUSTC) foo.rs -O - [ `$(call RUN,foo)` = "4" ] diff --git a/tests/run-make/issue-20626/foo.rs b/tests/run-make/raw-fn-pointer-opt-undefined-behavior/foo.rs similarity index 100% rename from tests/run-make/issue-20626/foo.rs rename to tests/run-make/raw-fn-pointer-opt-undefined-behavior/foo.rs diff --git a/tests/run-make/raw-fn-pointer-opt-undefined-behavior/rmake.rs b/tests/run-make/raw-fn-pointer-opt-undefined-behavior/rmake.rs new file mode 100644 index 0000000000000..61cf559a8fe7a --- /dev/null +++ b/tests/run-make/raw-fn-pointer-opt-undefined-behavior/rmake.rs @@ -0,0 +1,16 @@ +// Despite the absence of any unsafe Rust code, foo.rs in this test would, +// because of the raw function pointer, +// cause undefined behavior and fail to print the expected result, "4" - +// only when activating optimizations (opt-level 2). This test checks +// that this bug does not make a resurgence. +// Note that the bug cannot be observed in an assert_eq!, only in the stdout. +// See https://github.com/rust-lang/rust/issues/20626 + +//@ ignore-cross-compile + +use run_make_support::{run, rustc}; + +fn main() { + rustc().input("foo.rs").opt().run(); + run("foo").assert_stdout_equals("4"); +} From 6402909f42566cfee84b8b66aec409adfcfc1e85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Tue, 25 Jun 2024 19:55:06 +0000 Subject: [PATCH 07/14] delay bug in RPITIT refinement checking with resolution errors --- .../src/check/compare_impl_item/refine.rs | 8 +++---- .../in-trait/refine-resolution-errors.rs | 23 +++++++++++++++++++ .../in-trait/refine-resolution-errors.stderr | 16 +++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/refine-resolution-errors.rs create mode 100644 tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index 6cdbd692f73be..ad3324f79e271 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -171,10 +171,10 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( } // Resolve any lifetime variables that may have been introduced during normalization. let Ok((trait_bounds, impl_bounds)) = infcx.fully_resolve((trait_bounds, impl_bounds)) else { - // This code path is not reached in any tests, but may be reachable. If - // this is triggered, it should be converted to `delayed_bug` and the - // triggering case turned into a test. - tcx.dcx().bug("encountered errors when checking RPITIT refinement (resolution)"); + // If resolution didn't fully complete, we cannot continue checking RPITIT refinement, and + // delay a bug as the original code contains load-bearing errors. + tcx.dcx().delayed_bug("encountered errors when checking RPITIT refinement (resolution)"); + return; }; // For quicker lookup, use an `IndexSet` (we don't use one earlier because diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs new file mode 100644 index 0000000000000..a9936c7bc3fee --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.rs @@ -0,0 +1,23 @@ +// This is a non-regression test for issue #126670 where RPITIT refinement checking encountered +// errors during resolution and ICEd. + +//@ edition: 2018 + +pub trait Mirror { + type Assoc; +} +impl Mirror for () { + //~^ ERROR the type parameter `T` is not constrained + type Assoc = T; +} + +pub trait First { + async fn first() -> <() as Mirror>::Assoc; + //~^ ERROR type annotations needed +} + +impl First for () { + async fn first() {} +} + +fn main() {} diff --git a/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr new file mode 100644 index 0000000000000..0f5573dda04c1 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/refine-resolution-errors.stderr @@ -0,0 +1,16 @@ +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/refine-resolution-errors.rs:9:6 + | +LL | impl Mirror for () { + | ^ unconstrained type parameter + +error[E0282]: type annotations needed + --> $DIR/refine-resolution-errors.rs:15:5 + | +LL | async fn first() -> <() as Mirror>::Assoc; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ cannot infer type + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0207, E0282. +For more information about an error, try `rustc --explain E0207`. From 133e7b10a45bddd4ef5ba265d848ce0a1976e8ae Mon Sep 17 00:00:00 2001 From: The 8472 Date: Sun, 23 Jun 2024 22:16:22 +0200 Subject: [PATCH 08/14] fix Drop items getting leaked in Filter::next_chunk The optimization only makes sense for non-drop elements anyway. Use the default implementation for items that are Drop instead. It also simplifies the implementation. --- library/core/src/iter/adapters/filter.rs | 88 ++++++++++++------------ 1 file changed, 43 insertions(+), 45 deletions(-) diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index ca23d1b13a88b..1c99f3938e270 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -3,7 +3,7 @@ use crate::iter::{adapters::SourceIter, FusedIterator, InPlaceIterable, TrustedF use crate::num::NonZero; use crate::ops::Try; use core::array; -use core::mem::{ManuallyDrop, MaybeUninit}; +use core::mem::MaybeUninit; use core::ops::ControlFlow; /// An iterator that filters the elements of `iter` with `predicate`. @@ -27,6 +27,41 @@ impl Filter { } } +impl Filter +where + I: Iterator, + P: FnMut(&I::Item) -> bool, +{ + #[inline] + fn next_chunk_dropless( + &mut self, + ) -> Result<[I::Item; N], array::IntoIter> { + let mut array: [MaybeUninit; N] = [const { MaybeUninit::uninit() }; N]; + let mut initialized = 0; + + let result = self.iter.try_for_each(|element| { + let idx = initialized; + initialized = idx + (self.predicate)(&element) as usize; + + // SAFETY: Loop conditions ensure the index is in bounds. + unsafe { array.get_unchecked_mut(idx) }.write(element); + + if initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } + }); + + match result { + ControlFlow::Break(()) => { + // SAFETY: The loop above is only explicitly broken when the array has been fully initialized + Ok(unsafe { MaybeUninit::array_assume_init(array) }) + } + ControlFlow::Continue(()) => { + // SAFETY: The range is in bounds since the loop breaks when reaching N elements. + Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) + } + } + } +} + #[stable(feature = "core_impl_debug", since = "1.9.0")] impl fmt::Debug for Filter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -64,52 +99,15 @@ where fn next_chunk( &mut self, ) -> Result<[Self::Item; N], array::IntoIter> { - let mut array: [MaybeUninit; N] = [const { MaybeUninit::uninit() }; N]; - - struct Guard<'a, T> { - array: &'a mut [MaybeUninit], - initialized: usize, - } - - impl Drop for Guard<'_, T> { - #[inline] - fn drop(&mut self) { - if const { crate::mem::needs_drop::() } { - // SAFETY: self.initialized is always <= N, which also is the length of the array. - unsafe { - core::ptr::drop_in_place(MaybeUninit::slice_assume_init_mut( - self.array.get_unchecked_mut(..self.initialized), - )); - } - } + let fun = const { + if crate::mem::needs_drop::() { + array::iter_next_chunk:: + } else { + Self::next_chunk_dropless:: } - } - - let mut guard = Guard { array: &mut array, initialized: 0 }; - - let result = self.iter.try_for_each(|element| { - let idx = guard.initialized; - guard.initialized = idx + (self.predicate)(&element) as usize; - - // SAFETY: Loop conditions ensure the index is in bounds. - unsafe { guard.array.get_unchecked_mut(idx) }.write(element); - - if guard.initialized < N { ControlFlow::Continue(()) } else { ControlFlow::Break(()) } - }); + }; - let guard = ManuallyDrop::new(guard); - - match result { - ControlFlow::Break(()) => { - // SAFETY: The loop above is only explicitly broken when the array has been fully initialized - Ok(unsafe { MaybeUninit::array_assume_init(array) }) - } - ControlFlow::Continue(()) => { - let initialized = guard.initialized; - // SAFETY: The range is in bounds since the loop breaks when reaching N elements. - Err(unsafe { array::IntoIter::new_unchecked(array, 0..initialized) }) - } - } + fun(self) } #[inline] From 2be2d77c501730caedae8db2f0a0f02db57ae505 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Mon, 24 Jun 2024 19:56:22 +0200 Subject: [PATCH 09/14] add comments explaining optimizations for Filter::next_chunk --- library/core/src/iter/adapters/filter.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/library/core/src/iter/adapters/filter.rs b/library/core/src/iter/adapters/filter.rs index 1c99f3938e270..ba49070329c22 100644 --- a/library/core/src/iter/adapters/filter.rs +++ b/library/core/src/iter/adapters/filter.rs @@ -41,8 +41,9 @@ where let result = self.iter.try_for_each(|element| { let idx = initialized; + // branchless index update combined with unconditionally copying the value even when + // it is filtered reduces branching and dependencies in the loop. initialized = idx + (self.predicate)(&element) as usize; - // SAFETY: Loop conditions ensure the index is in bounds. unsafe { array.get_unchecked_mut(idx) }.write(element); @@ -99,6 +100,7 @@ where fn next_chunk( &mut self, ) -> Result<[Self::Item; N], array::IntoIter> { + // avoid codegen for the dead branch let fun = const { if crate::mem::needs_drop::() { array::iter_next_chunk:: From 0d7aef9738b25ed4f84d11deb0add8d5345613b0 Mon Sep 17 00:00:00 2001 From: The 8472 Date: Tue, 25 Jun 2024 23:22:27 +0200 Subject: [PATCH 10/14] regression test for leaks in the the Filter::next_chunk implementation previously next_chunk would forget items rejected by the filter --- library/core/tests/iter/adapters/filter.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/library/core/tests/iter/adapters/filter.rs b/library/core/tests/iter/adapters/filter.rs index a2050d89d8564..167851e33336e 100644 --- a/library/core/tests/iter/adapters/filter.rs +++ b/library/core/tests/iter/adapters/filter.rs @@ -1,4 +1,5 @@ use core::iter::*; +use std::rc::Rc; #[test] fn test_iterator_filter_count() { @@ -50,3 +51,15 @@ fn test_double_ended_filter() { assert_eq!(it.next().unwrap(), &2); assert_eq!(it.next_back(), None); } + +#[test] +fn test_next_chunk_does_not_leak() { + let drop_witness: [_; 5] = std::array::from_fn(|_| Rc::new(())); + + let v = (0..5).map(|i| drop_witness[i].clone()).collect::>(); + let _ = v.into_iter().filter(|_| false).next_chunk::<1>(); + + for ref w in drop_witness { + assert_eq!(Rc::strong_count(w), 1); + } +} From 275d922dab9c98d3a8f01f79d3f2381f26a4a99b Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 21 Jun 2024 12:39:55 -0400 Subject: [PATCH 11/14] Rename tcx to cx --- .../src/solve/alias_relate.rs | 6 +- .../src/solve/assembly/mod.rs | 85 ++++---- .../src/solve/assembly/structural_traits.rs | 112 +++++----- .../src/solve/eval_ctxt/mod.rs | 22 +- .../src/solve/inspect/build.rs | 4 +- .../rustc_next_trait_solver/src/solve/mod.rs | 12 +- .../src/solve/normalizes_to/inherent.rs | 18 +- .../src/solve/normalizes_to/mod.rs | 199 +++++++++--------- .../src/solve/normalizes_to/opaque_types.rs | 6 +- .../src/solve/normalizes_to/weak_types.rs | 10 +- .../src/solve/project_goals.rs | 6 +- .../src/solve/search_graph.rs | 60 +++--- .../src/solve/trait_goals.rs | 140 ++++++------ 13 files changed, 333 insertions(+), 347 deletions(-) diff --git a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs index 5a95f4edf1915..d8c1dc8b4e9f3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs +++ b/compiler/rustc_next_trait_solver/src/solve/alias_relate.rs @@ -32,14 +32,14 @@ where &mut self, goal: Goal, ) -> QueryResult { - let tcx = self.cx(); + let cx = self.cx(); let Goal { param_env, predicate: (lhs, rhs, direction) } = goal; debug_assert!(lhs.to_alias_term().is_some() || rhs.to_alias_term().is_some()); // Structurally normalize the lhs. let lhs = if let Some(alias) = lhs.to_alias_term() { let term = self.next_term_infer_of_kind(lhs); - self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term })); + self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); term } else { lhs @@ -48,7 +48,7 @@ where // Structurally normalize the rhs. let rhs = if let Some(alias) = rhs.to_alias_term() { let term = self.next_term_infer_of_kind(rhs); - self.add_normalizes_to_goal(goal.with(tcx, ty::NormalizesTo { alias, term })); + self.add_normalizes_to_goal(goal.with(cx, ty::NormalizesTo { alias, term })); term } else { rhs diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs index ee7279a43b2cf..21439530c08f6 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/mod.rs @@ -36,11 +36,11 @@ where { fn self_ty(self) -> I::Ty; - fn trait_ref(self, tcx: I) -> ty::TraitRef; + fn trait_ref(self, cx: I) -> ty::TraitRef; - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self; + fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self; - fn trait_def_id(self, tcx: I) -> I::DefId; + fn trait_def_id(self, cx: I) -> I::DefId; /// Try equating an assumption predicate against a goal's predicate. If it /// holds, then execute the `then` callback, which should do any additional @@ -82,7 +82,7 @@ where assumption: I::Clause, ) -> Result, NoSolution> { Self::probe_and_match_goal_against_assumption(ecx, source, goal, assumption, |ecx| { - let tcx = ecx.cx(); + let cx = ecx.cx(); let ty::Dynamic(bounds, _, _) = goal.predicate.self_ty().kind() else { panic!("expected object type in `probe_and_consider_object_bound_candidate`"); }; @@ -91,7 +91,7 @@ where structural_traits::predicates_for_object_candidate( ecx, goal.param_env, - goal.predicate.trait_ref(tcx), + goal.predicate.trait_ref(cx), bounds, ), ); @@ -340,15 +340,15 @@ where goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.cx(); - tcx.for_each_relevant_impl( - goal.predicate.trait_def_id(tcx), + let cx = self.cx(); + cx.for_each_relevant_impl( + goal.predicate.trait_def_id(cx), goal.predicate.self_ty(), |impl_def_id| { // For every `default impl`, there's always a non-default `impl` // that will *also* apply. There's no reason to register a candidate // for this impl, since it is *not* proof that the trait goal holds. - if tcx.impl_is_default(impl_def_id) { + if cx.impl_is_default(impl_def_id) { return; } @@ -366,8 +366,8 @@ where goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.cx(); - let trait_def_id = goal.predicate.trait_def_id(tcx); + let cx = self.cx(); + let trait_def_id = goal.predicate.trait_def_id(cx); // N.B. When assembling built-in candidates for lang items that are also // `auto` traits, then the auto trait candidate that is assembled in @@ -378,47 +378,47 @@ where // `solve::trait_goals` instead. let result = if let Err(guar) = goal.predicate.error_reported() { G::consider_error_guaranteed_candidate(self, guar) - } else if tcx.trait_is_auto(trait_def_id) { + } else if cx.trait_is_auto(trait_def_id) { G::consider_auto_trait_candidate(self, goal) - } else if tcx.trait_is_alias(trait_def_id) { + } else if cx.trait_is_alias(trait_def_id) { G::consider_trait_alias_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Sized) { G::consider_builtin_sized_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) - || tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Copy) + || cx.is_lang_item(trait_def_id, TraitSolverLangItem::Clone) { G::consider_builtin_copy_clone_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointerLike) { G::consider_builtin_pointer_like_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FnPtrTrait) { G::consider_builtin_fn_ptr_trait_candidate(self, goal) } else if let Some(kind) = self.cx().fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_fn_trait_candidates(self, goal, kind) } else if let Some(kind) = self.cx().async_fn_trait_kind_from_def_id(trait_def_id) { G::consider_builtin_async_fn_trait_candidates(self, goal, kind) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncFnKindHelper) { G::consider_builtin_async_fn_kind_helper_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Tuple) { G::consider_builtin_tuple_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::PointeeTrait) { G::consider_builtin_pointee_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Future) { G::consider_builtin_future_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Iterator) { G::consider_builtin_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::FusedIterator) { G::consider_builtin_fused_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncIterator) { G::consider_builtin_async_iterator_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Coroutine) { G::consider_builtin_coroutine_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::DiscriminantKind) { G::consider_builtin_discriminant_kind_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::AsyncDestruct) { G::consider_builtin_async_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Destruct) { G::consider_builtin_destruct_candidate(self, goal) - } else if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { + } else if cx.is_lang_item(trait_def_id, TraitSolverLangItem::TransmuteTrait) { G::consider_builtin_transmute_candidate(self, goal) } else { Err(NoSolution) @@ -428,7 +428,7 @@ where // There may be multiple unsize candidates for a trait with several supertraits: // `trait Foo: Bar + Bar` and `dyn Foo: Unsize>` - if tcx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) { + if cx.is_lang_item(trait_def_id, TraitSolverLangItem::Unsize) { candidates.extend(G::consider_structural_builtin_unsize_candidates(self, goal)); } } @@ -557,8 +557,8 @@ where goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.cx(); - if !tcx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(tcx)) { + let cx = self.cx(); + if !cx.trait_may_be_implemented_via_object(goal.predicate.trait_def_id(cx)) { return; } @@ -596,7 +596,7 @@ where }; // Do not consider built-in object impls for non-object-safe types. - if bounds.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { + if bounds.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { return; } @@ -614,7 +614,7 @@ where self, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, - bound.with_self_ty(tcx, self_ty), + bound.with_self_ty(cx, self_ty), )); } } @@ -624,14 +624,13 @@ where // since we don't need to look at any supertrait or anything if we are doing // a projection goal. if let Some(principal) = bounds.principal() { - let principal_trait_ref = principal.with_self_ty(tcx, self_ty); - for (idx, assumption) in D::elaborate_supertraits(tcx, principal_trait_ref).enumerate() - { + let principal_trait_ref = principal.with_self_ty(cx, self_ty); + for (idx, assumption) in D::elaborate_supertraits(cx, principal_trait_ref).enumerate() { candidates.extend(G::probe_and_consider_object_bound_candidate( self, CandidateSource::BuiltinImpl(BuiltinImplSource::Object(idx)), goal, - assumption.upcast(tcx), + assumption.upcast(cx), )); } } @@ -649,11 +648,11 @@ where goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.cx(); + let cx = self.cx(); candidates.extend(self.probe_trait_candidate(CandidateSource::CoherenceUnknowable).enter( |ecx| { - let trait_ref = goal.predicate.trait_ref(tcx); + let trait_ref = goal.predicate.trait_ref(cx); if ecx.trait_ref_is_knowable(goal.param_env, trait_ref)? { Err(NoSolution) } else { @@ -678,9 +677,9 @@ where goal: Goal, candidates: &mut Vec>, ) { - let tcx = self.cx(); + let cx = self.cx(); let trait_goal: Goal> = - goal.with(tcx, goal.predicate.trait_ref(tcx)); + goal.with(cx, goal.predicate.trait_ref(cx)); let mut trait_candidates_from_env = vec![]; self.probe(|_| ProbeKind::ShadowedEnvProbing).enter(|ecx| { diff --git a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs index 2df039c766cf5..0cef8d9f4bc34 100644 --- a/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs +++ b/compiler/rustc_next_trait_solver/src/solve/assembly/structural_traits.rs @@ -23,7 +23,7 @@ where D: SolverDelegate, I: Interner, { - let tcx = ecx.cx(); + let cx = ecx.cx(); match ty.kind() { ty::Uint(_) | ty::Int(_) @@ -36,7 +36,7 @@ where | 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, Ty::new_u8(tcx)))]), + ty::Str => Ok(vec![ty::Binder::dummy(Ty::new_slice(cx, Ty::new_u8(cx)))]), ty::Dynamic(..) | ty::Param(..) @@ -79,21 +79,21 @@ where .cx() .bound_coroutine_hidden_types(def_id) .into_iter() - .map(|bty| bty.instantiate(tcx, args)) + .map(|bty| bty.instantiate(cx, 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_field_tys(tcx).iter_instantiated(tcx, args).map(ty::Binder::dummy).collect()) + Ok(def.all_field_tys(cx).iter_instantiated(cx, 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(cx.type_of(def_id).instantiate(cx, args))]) } } } @@ -247,18 +247,18 @@ where // 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: I, + cx: I, self_ty: I::Ty, goal_kind: ty::ClosureKind, ) -> 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.has_target_features(def_id) { + let sig = cx.fn_sig(def_id); + if sig.skip_binder().is_fn_trait_compatible() && !cx.has_target_features(def_id) { Ok(Some( - sig.instantiate(tcx, args) - .map_bound(|sig| (Ty::new_tup(tcx, sig.inputs().as_slice()), sig.output())), + sig.instantiate(cx, args) + .map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), )) } else { Err(NoSolution) @@ -268,7 +268,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable { if sig.is_fn_trait_compatible() { Ok(Some( - sig.map_bound(|sig| (Ty::new_tup(tcx, sig.inputs().as_slice()), sig.output())), + sig.map_bound(|sig| (Ty::new_tup(cx, sig.inputs().as_slice()), sig.output())), )) } else { Err(NoSolution) @@ -323,10 +323,10 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable { // 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: I, + cx: I, self_ty: I::Ty, goal_kind: ty::ClosureKind, env_region: I::Region, @@ -422,9 +422,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable { - let bound_sig = self_ty.fn_sig(tcx); + let bound_sig = self_ty.fn_sig(cx); let sig = bound_sig.skip_binder(); - let future_trait_def_id = tcx.require_lang_item(TraitSolverLangItem::Future); + let future_trait_def_id = cx.require_lang_item(TraitSolverLangItem::Future); // `FnDef` and `FnPtr` only implement `AsyncFn*` when their // return type implements `Future`. let nested = vec![ bound_sig - .rebind(ty::TraitRef::new(tcx, future_trait_def_id, [sig.output()])) - .upcast(tcx), + .rebind(ty::TraitRef::new(cx, future_trait_def_id, [sig.output()])) + .upcast(cx), ]; - let future_output_def_id = tcx.require_lang_item(TraitSolverLangItem::FutureOutput); - let future_output_ty = Ty::new_projection(tcx, future_output_def_id, [sig.output()]); + let future_output_def_id = cx.require_lang_item(TraitSolverLangItem::FutureOutput); + let future_output_ty = Ty::new_projection(cx, future_output_def_id, [sig.output()]); Ok(( bound_sig.rebind(AsyncCallableRelevantTypes { - tupled_inputs_ty: Ty::new_tup(tcx, sig.inputs().as_slice()), + tupled_inputs_ty: Ty::new_tup(cx, sig.inputs().as_slice()), output_coroutine_ty: sig.output(), coroutine_return_ty: future_output_ty, }), @@ -483,13 +481,13 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable( - tcx: I, + cx: I, goal_kind: ty::ClosureKind, goal_region: I::Region, def_id: I::DefId, @@ -573,9 +571,9 @@ fn coroutine_closure_to_certain_coroutine( sig: ty::CoroutineClosureSignature, ) -> I::Ty { sig.to_coroutine_given_kind_and_upvars( - tcx, + cx, args.parent_args(), - tcx.coroutine_for_closure(def_id), + cx.coroutine_for_closure(def_id), goal_kind, goal_region, args.tupled_upvars_ty(), @@ -589,20 +587,20 @@ fn coroutine_closure_to_certain_coroutine( /// /// Note that we do not also push a `AsyncFnKindHelper` goal here. fn coroutine_closure_to_ambiguous_coroutine( - tcx: I, + cx: I, goal_kind: ty::ClosureKind, 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(TraitSolverLangItem::AsyncFnKindUpvars); + let upvars_projection_def_id = cx.require_lang_item(TraitSolverLangItem::AsyncFnKindUpvars); let tupled_upvars_ty = Ty::new_projection( - tcx, + cx, upvars_projection_def_id, [ I::GenericArg::from(args.kind_ty()), - Ty::from_closure_kind(tcx, goal_kind).into(), + Ty::from_closure_kind(cx, goal_kind).into(), goal_region.into(), sig.tupled_inputs_ty.into(), args.tupled_upvars_ty().into(), @@ -610,10 +608,10 @@ fn coroutine_closure_to_ambiguous_coroutine( ], ); sig.to_coroutine( - tcx, + cx, args.parent_args(), - Ty::from_closure_kind(tcx, goal_kind), - tcx.coroutine_for_closure(def_id), + Ty::from_closure_kind(cx, goal_kind), + cx.coroutine_for_closure(def_id), tupled_upvars_ty, ) } @@ -668,28 +666,28 @@ where D: SolverDelegate, I: Interner, { - let tcx = ecx.cx(); + let cx = ecx.cx(); let mut requirements = vec![]; requirements - .extend(tcx.super_predicates_of(trait_ref.def_id).iter_instantiated(tcx, trait_ref.args)); + .extend(cx.super_predicates_of(trait_ref.def_id).iter_instantiated(cx, 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) { + for associated_type_def_id in cx.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) { + if cx.generics_require_sized_self(associated_type_def_id) { continue; } requirements - .extend(tcx.item_bounds(associated_type_def_id).iter_instantiated(tcx, trait_ref.args)); + .extend(cx.item_bounds(associated_type_def_id).iter_instantiated(cx, trait_ref.args)); } let mut replace_projection_with = HashMap::default(); for bound in object_bounds.iter() { if let ty::ExistentialPredicate::Projection(proj) = bound.skip_binder() { - let proj = proj.with_self_ty(tcx, trait_ref.self_ty()); + let proj = proj.with_self_ty(cx, trait_ref.self_ty()); let old_ty = replace_projection_with.insert(proj.def_id(), bound.rebind(proj)); assert_eq!( old_ty, @@ -709,7 +707,7 @@ where folder .nested .into_iter() - .chain(folded_requirements.into_iter().map(|clause| Goal::new(tcx, param_env, clause))) + .chain(folded_requirements.into_iter().map(|clause| Goal::new(cx, param_env, clause))) .collect() } diff --git a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs index 04dce2780b07b..87342eefb33e5 100644 --- a/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/eval_ctxt/mod.rs @@ -239,14 +239,14 @@ where /// This function takes care of setting up the inference context, setting the anchor, /// and registering opaques from the canonicalized input. fn enter_canonical( - tcx: I, + cx: I, search_graph: &'a mut search_graph::SearchGraph, canonical_input: CanonicalInput, canonical_goal_evaluation: &mut ProofTreeBuilder, f: impl FnOnce(&mut EvalCtxt<'_, D>, Goal) -> R, ) -> R { let (ref delegate, input, var_values) = - SolverDelegate::build_with_canonical(tcx, search_graph.solver_mode(), &canonical_input); + SolverDelegate::build_with_canonical(cx, search_graph.solver_mode(), &canonical_input); let mut ecx = EvalCtxt { delegate, @@ -292,9 +292,9 @@ where /// Instead of calling this function directly, use either [EvalCtxt::evaluate_goal] /// if you're inside of the solver or [SolverDelegateEvalExt::evaluate_root_goal] if you're /// outside of it. - #[instrument(level = "debug", skip(tcx, search_graph, goal_evaluation), ret)] + #[instrument(level = "debug", skip(cx, search_graph, goal_evaluation), ret)] fn evaluate_canonical_goal( - tcx: I, + cx: I, search_graph: &'a mut search_graph::SearchGraph, canonical_input: CanonicalInput, goal_evaluation: &mut ProofTreeBuilder, @@ -307,12 +307,12 @@ where // The actual solver logic happens in `ecx.compute_goal`. let result = ensure_sufficient_stack(|| { search_graph.with_new_goal( - tcx, + cx, canonical_input, &mut canonical_goal_evaluation, |search_graph, canonical_goal_evaluation| { EvalCtxt::enter_canonical( - tcx, + cx, search_graph, canonical_input, canonical_goal_evaluation, @@ -506,7 +506,7 @@ where /// /// Goals for the next step get directly added to the nested goals of the `EvalCtxt`. fn evaluate_added_goals_step(&mut self) -> Result, NoSolution> { - let tcx = self.cx(); + let cx = self.cx(); let mut goals = core::mem::take(&mut self.nested_goals); // If this loop did not result in any progress, what's our final certainty. @@ -516,7 +516,7 @@ where // RHS does not affect projection candidate assembly. let unconstrained_rhs = self.next_term_infer_of_kind(goal.predicate.term); let unconstrained_goal = goal.with( - tcx, + cx, ty::NormalizesTo { alias: goal.predicate.alias, term: unconstrained_rhs }, ); @@ -777,7 +777,7 @@ where // NOTE: this check is purely an optimization, the structural eq would // always fail if the term is not an inference variable. if term.is_infer() { - let tcx = self.cx(); + let cx = self.cx(); // We need to relate `alias` to `term` treating only the outermost // constructor as rigid, relating any contained generic arguments as // normal. We do this by first structurally equating the `term` @@ -787,8 +787,8 @@ where // 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_from_args(tcx, alias.def_id, identity_args); - let ctor_term = rigid_ctor.to_term(tcx); + let rigid_ctor = ty::AliasTerm::new_from_args(cx, alias.def_id, identity_args); + let ctor_term = rigid_ctor.to_term(cx); let obligations = self.delegate.eq_structurally_relating_aliases(param_env, term, ctor_term)?; debug_assert!(obligations.is_empty()); diff --git a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs index 4fc58e06d67dc..b50676e8d5327 100644 --- a/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs +++ b/compiler/rustc_next_trait_solver/src/solve/inspect/build.rs @@ -323,13 +323,13 @@ impl, I: Interner> ProofTreeBuilder { pub fn finalize_canonical_goal_evaluation( &mut self, - tcx: I, + cx: I, ) -> Option { self.as_mut().map(|this| match this { DebugSolver::CanonicalGoalEvaluation(evaluation) => { let final_revision = mem::take(&mut evaluation.final_revision).unwrap(); let final_revision = - tcx.intern_canonical_goal_evaluation_step(final_revision.finalize()); + cx.intern_canonical_goal_evaluation_step(final_revision.finalize()); let kind = WipCanonicalGoalEvaluationKind::Interned { final_revision }; assert_eq!(evaluation.kind.replace(kind), None); final_revision diff --git a/compiler/rustc_next_trait_solver/src/solve/mod.rs b/compiler/rustc_next_trait_solver/src/solve/mod.rs index e29ae7ac0a26c..24055d6cd832b 100644 --- a/compiler/rustc_next_trait_solver/src/solve/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/mod.rs @@ -34,7 +34,7 @@ use crate::delegate::SolverDelegate; /// How many fixpoint iterations we should attempt inside of the solver before bailing /// with overflow. /// -/// We previously used `tcx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this. +/// We previously used `cx.recursion_limit().0.checked_ilog2().unwrap_or(0)` for this. /// However, it feels unlikely that uncreasing the recursion limit by a power of two /// to get one more itereation is every useful or desirable. We now instead used a constant /// here. If there ever ends up some use-cases where a bigger number of fixpoint iterations @@ -285,7 +285,7 @@ where } fn response_no_constraints_raw( - tcx: I, + cx: I, max_universe: ty::UniverseIndex, variables: I::CanonicalVars, certainty: Certainty, @@ -294,10 +294,10 @@ fn response_no_constraints_raw( max_universe, variables, value: Response { - var_values: ty::CanonicalVarValues::make_identity(tcx, variables), - // FIXME: maybe we should store the "no response" version in tcx, like - // we do for tcx.types and stuff. - external_constraints: tcx.mk_external_constraints(ExternalConstraintsData::default()), + var_values: ty::CanonicalVarValues::make_identity(cx, variables), + // FIXME: maybe we should store the "no response" version in cx, like + // we do for cx.types and stuff. + external_constraints: cx.mk_external_constraints(ExternalConstraintsData::default()), certainty, }, defining_opaque_types: Default::default(), diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs index 004ecf2d2c4f7..25e8708a3322c 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/inherent.rs @@ -19,21 +19,21 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.cx(); - let inherent = goal.predicate.alias.expect_ty(tcx); + let cx = self.cx(); + let inherent = goal.predicate.alias.expect_ty(cx); - let impl_def_id = tcx.parent(inherent.def_id); + let impl_def_id = cx.parent(inherent.def_id); let impl_args = self.fresh_args_for_item(impl_def_id); // Equate impl header and add impl where clauses self.eq( goal.param_env, inherent.self_ty(), - tcx.type_of(impl_def_id).instantiate(tcx, impl_args), + cx.type_of(impl_def_id).instantiate(cx, impl_args), )?; // Equate IAT with the RHS of the project goal - let inherent_args = inherent.rebase_inherent_args_onto_impl(impl_args, tcx); + let inherent_args = inherent.rebase_inherent_args_onto_impl(impl_args, cx); // Check both where clauses on the impl and IAT // @@ -43,12 +43,12 @@ where // and I don't think the assoc item where-bounds are allowed to be coinductive. self.add_goals( GoalSource::Misc, - tcx.predicates_of(inherent.def_id) - .iter_instantiated(tcx, inherent_args) - .map(|pred| goal.with(tcx, pred)), + cx.predicates_of(inherent.def_id) + .iter_instantiated(cx, inherent_args) + .map(|pred| goal.with(cx, pred)), ); - let normalized = tcx.type_of(inherent.def_id).instantiate(tcx, inherent_args); + let normalized = cx.type_of(inherent.def_id).instantiate(cx, inherent_args); self.instantiate_normalizes_to_term(goal, normalized.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs index bc5233c4887fa..4e8cb4384f462 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/mod.rs @@ -84,16 +84,16 @@ where self.self_ty() } - fn trait_ref(self, tcx: I) -> ty::TraitRef { - self.alias.trait_ref(tcx) + fn trait_ref(self, cx: I) -> ty::TraitRef { + self.alias.trait_ref(cx) } - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(tcx, self_ty) + fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_self_ty(cx, self_ty) } - fn trait_def_id(self, tcx: I) -> I::DefId { - self.trait_def_id(tcx) + fn trait_def_id(self, cx: I) -> I::DefId { + self.trait_def_id(cx) } fn probe_and_match_goal_against_assumption( @@ -105,7 +105,7 @@ where ) -> Result, NoSolution> { if let Some(projection_pred) = assumption.as_projection_clause() { if projection_pred.projection_def_id() == goal.predicate.def_id() { - let tcx = ecx.cx(); + let cx = ecx.cx(); ecx.probe_trait_candidate(source).enter(|ecx| { let assumption_projection_pred = ecx.instantiate_binder_with_infer(projection_pred); @@ -120,9 +120,9 @@ where // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.own_predicates_of(goal.predicate.def_id()) - .iter_instantiated(tcx, goal.predicate.alias.args) - .map(|pred| goal.with(tcx, pred)), + cx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(cx, goal.predicate.alias.args) + .map(|pred| goal.with(cx, pred)), ); then(ecx) @@ -140,19 +140,19 @@ where goal: Goal>, impl_def_id: I::DefId, ) -> Result, NoSolution> { - let tcx = ecx.cx(); + let cx = ecx.cx(); - let goal_trait_ref = goal.predicate.alias.trait_ref(tcx); - let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); + let goal_trait_ref = goal.predicate.alias.trait_ref(cx); + let impl_trait_ref = cx.impl_trait_ref(impl_def_id); if !ecx.cx().args_may_unify_deep( - goal.predicate.alias.trait_ref(tcx).args, + goal.predicate.alias.trait_ref(cx).args, impl_trait_ref.skip_binder().args, ) { return Err(NoSolution); } // We have to ignore negative impls when projecting. - let impl_polarity = tcx.impl_polarity(impl_def_id); + let impl_polarity = cx.impl_polarity(impl_def_id); match impl_polarity { ty::ImplPolarity::Negative => return Err(NoSolution), ty::ImplPolarity::Reservation => { @@ -163,22 +163,22 @@ where ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); - let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); ecx.eq(goal.param_env, goal_trait_ref, impl_trait_ref)?; - let where_clause_bounds = tcx + let where_clause_bounds = cx .predicates_of(impl_def_id) - .iter_instantiated(tcx, impl_args) - .map(|pred| goal.with(tcx, pred)); + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); // Add GAT where clauses from the trait's definition ecx.add_goals( GoalSource::Misc, - tcx.own_predicates_of(goal.predicate.def_id()) - .iter_instantiated(tcx, goal.predicate.alias.args) - .map(|pred| goal.with(tcx, pred)), + cx.own_predicates_of(goal.predicate.def_id()) + .iter_instantiated(cx, goal.predicate.alias.args) + .map(|pred| goal.with(cx, pred)), ); // In case the associated item is hidden due to specialization, we have to @@ -195,21 +195,21 @@ where }; let error_response = |ecx: &mut EvalCtxt<'_, D>, msg: &str| { - let guar = tcx.delay_bug(msg); - let error_term = match goal.predicate.alias.kind(tcx) { - ty::AliasTermKind::ProjectionTy => Ty::new_error(tcx, guar).into(), - ty::AliasTermKind::ProjectionConst => Const::new_error(tcx, guar).into(), + let guar = cx.delay_bug(msg); + let error_term = match goal.predicate.alias.kind(cx) { + ty::AliasTermKind::ProjectionTy => Ty::new_error(cx, guar).into(), + ty::AliasTermKind::ProjectionConst => Const::new_error(cx, guar).into(), kind => panic!("expected projection, found {kind:?}"), }; ecx.instantiate_normalizes_to_term(goal, error_term); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }; - if !tcx.has_item_definition(target_item_def_id) { + if !cx.has_item_definition(target_item_def_id) { return error_response(ecx, "missing item"); } - let target_container_def_id = tcx.parent(target_item_def_id); + let target_container_def_id = cx.parent(target_item_def_id); // Getting the right args here is complex, e.g. given: // - a goal ` as Trait>::Assoc` @@ -229,22 +229,22 @@ where target_container_def_id, )?; - if !tcx.check_args_compatible(target_item_def_id, target_args) { + if !cx.check_args_compatible(target_item_def_id, target_args) { return error_response(ecx, "associated item has mismatched arguments"); } // Finally we construct the actual value of the associated type. - let term = match goal.predicate.alias.kind(tcx) { + let term = match goal.predicate.alias.kind(cx) { ty::AliasTermKind::ProjectionTy => { - tcx.type_of(target_item_def_id).map_bound(|ty| ty.into()) + cx.type_of(target_item_def_id).map_bound(|ty| ty.into()) } ty::AliasTermKind::ProjectionConst => { - if tcx.features().associated_const_equality() { + if cx.features().associated_const_equality() { panic!("associated const projection is not supported yet") } else { ty::EarlyBinder::bind( Const::new_error_with_message( - tcx, + cx, "associated const projection is not supported yet", ) .into(), @@ -254,7 +254,7 @@ where kind => panic!("expected projection, found {kind:?}"), }; - ecx.instantiate_normalizes_to_term(goal, term.instantiate(tcx, target_args)); + ecx.instantiate_normalizes_to_term(goal, term.instantiate(cx, target_args)); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -316,10 +316,10 @@ where goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.cx(); + let cx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, + cx, goal.predicate.self_ty(), goal_kind, )? { @@ -329,19 +329,19 @@ where } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output .map_bound(|(inputs, output)| ty::ProjectionPredicate { projection_term: ty::AliasTerm::new( - tcx, + cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs], ), term: output.into(), }) - .upcast(tcx); + .upcast(cx); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -350,7 +350,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, - [(GoalSource::ImplWhereBound, goal.with(tcx, output_is_sized_pred))], + [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], ) } @@ -359,27 +359,23 @@ where goal: Goal, goal_kind: ty::ClosureKind, ) -> Result, NoSolution> { - let tcx = ecx.cx(); + let cx = ecx.cx(); let env_region = match goal_kind { ty::ClosureKind::Fn | ty::ClosureKind::FnMut => goal.predicate.alias.args.region_at(2), // Doesn't matter what this region is - ty::ClosureKind::FnOnce => Region::new_static(tcx), + ty::ClosureKind::FnOnce => Region::new_static(cx), }; let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( - tcx, + cx, goal.predicate.self_ty(), goal_kind, env_region, )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty: output_ty, .. }| { - ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Sized), - [output_ty], - ) + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output_ty]) }, ); @@ -390,23 +386,23 @@ where output_coroutine_ty, coroutine_return_ty, }| { - let (projection_term, term) = if tcx + let (projection_term, term) = if cx .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallOnceFuture) { ( ty::AliasTerm::new( - tcx, + cx, goal.predicate.def_id(), [goal.predicate.self_ty(), tupled_inputs_ty], ), output_coroutine_ty.into(), ) - } else if tcx + } else if cx .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CallRefFuture) { ( ty::AliasTerm::new( - tcx, + cx, goal.predicate.def_id(), [ I::GenericArg::from(goal.predicate.self_ty()), @@ -416,13 +412,13 @@ where ), output_coroutine_ty.into(), ) - } else if tcx.is_lang_item( + } else if cx.is_lang_item( goal.predicate.def_id(), TraitSolverLangItem::AsyncFnOnceOutput, ) { ( ty::AliasTerm::new( - tcx, + cx, goal.predicate.def_id(), [ I::GenericArg::from(goal.predicate.self_ty()), @@ -440,7 +436,7 @@ where ty::ProjectionPredicate { projection_term, term } }, ) - .upcast(tcx); + .upcast(cx); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) @@ -449,9 +445,9 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, - [goal.with(tcx, output_is_sized_pred)] + [goal.with(cx, output_is_sized_pred)] .into_iter() - .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))) + .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred))) .map(|goal| (GoalSource::ImplWhereBound, goal)), ) } @@ -514,8 +510,8 @@ where ecx: &mut EvalCtxt<'_, D>, goal: Goal, ) -> Result, NoSolution> { - let tcx = ecx.cx(); - let metadata_def_id = tcx.require_lang_item(TraitSolverLangItem::Metadata); + let cx = ecx.cx(); + let metadata_def_id = cx.require_lang_item(TraitSolverLangItem::Metadata); assert_eq!(metadata_def_id, goal.predicate.def_id()); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { let metadata_ty = match goal.predicate.self_ty().kind() { @@ -537,16 +533,16 @@ where | ty::CoroutineWitness(..) | ty::Never | ty::Foreign(..) - | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(tcx), + | ty::Dynamic(_, _, ty::DynStar) => Ty::new_unit(cx), - ty::Error(e) => Ty::new_error(tcx, e), + ty::Error(e) => Ty::new_error(cx, e), - ty::Str | ty::Slice(_) => Ty::new_usize(tcx), + ty::Str | ty::Slice(_) => Ty::new_usize(cx), ty::Dynamic(_, _, ty::Dyn) => { - let dyn_metadata = tcx.require_lang_item(TraitSolverLangItem::DynMetadata); - tcx.type_of(dyn_metadata) - .instantiate(tcx, &[I::GenericArg::from(goal.predicate.self_ty())]) + let dyn_metadata = cx.require_lang_item(TraitSolverLangItem::DynMetadata); + cx.type_of(dyn_metadata) + .instantiate(cx, &[I::GenericArg::from(goal.predicate.self_ty())]) } ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => { @@ -555,26 +551,26 @@ where // FIXME(ptr_metadata): This impl overlaps with the other impls and shouldn't // exist. Instead, `Pointee` should be a supertrait of `Sized`. let sized_predicate = ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Sized), + cx, + cx.require_lang_item(TraitSolverLangItem::Sized), [I::GenericArg::from(goal.predicate.self_ty())], ); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? - ecx.add_goal(GoalSource::Misc, goal.with(tcx, sized_predicate)); - Ty::new_unit(tcx) + ecx.add_goal(GoalSource::Misc, goal.with(cx, sized_predicate)); + Ty::new_unit(cx) } - ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(tcx) { - None => Ty::new_unit(tcx), + ty::Adt(def, args) if def.is_struct() => match def.struct_tail_ty(cx) { + None => Ty::new_unit(cx), Some(tail_ty) => { - Ty::new_projection(tcx, metadata_def_id, [tail_ty.instantiate(tcx, args)]) + Ty::new_projection(cx, metadata_def_id, [tail_ty.instantiate(cx, args)]) } }, - ty::Adt(_, _) => Ty::new_unit(tcx), + ty::Adt(_, _) => Ty::new_unit(cx), ty::Tuple(elements) => match elements.last() { - None => Ty::new_unit(tcx), - Some(tail_ty) => Ty::new_projection(tcx, metadata_def_id, [tail_ty]), + None => Ty::new_unit(cx), + Some(tail_ty) => Ty::new_projection(cx, metadata_def_id, [tail_ty]), }, ty::Infer( @@ -601,8 +597,8 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_async(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -616,7 +612,7 @@ where projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } - .upcast(tcx), + .upcast(cx), // Technically, we need to check that the future type is Sized, // but that's already proven by the coroutine being WF. [], @@ -633,8 +629,8 @@ where }; // Coroutines are not Iterators unless they come from `gen` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_gen(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -648,7 +644,7 @@ where projection_term: ty::AliasTerm::new(ecx.cx(), goal.predicate.def_id(), [self_ty]), term, } - .upcast(tcx), + .upcast(cx), // Technically, we need to check that the iterator type is Sized, // but that's already proven by the generator being WF. [], @@ -672,8 +668,8 @@ where }; // Coroutines are not AsyncIterators unless they come from `gen` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_async_gen(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -682,12 +678,12 @@ where // Take `AsyncIterator` and turn it into the corresponding // coroutine yield ty `Poll>`. let wrapped_expected_ty = Ty::new_adt( - tcx, - tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Poll)), - tcx.mk_args(&[Ty::new_adt( - tcx, - tcx.adt_def(tcx.require_lang_item(TraitSolverLangItem::Option)), - tcx.mk_args(&[expected_ty.into()]), + cx, + cx.adt_def(cx.require_lang_item(TraitSolverLangItem::Poll)), + cx.mk_args(&[Ty::new_adt( + cx, + cx.adt_def(cx.require_lang_item(TraitSolverLangItem::Option)), + cx.mk_args(&[expected_ty.into()]), ) .into()]), ); @@ -708,18 +704,17 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.cx(); - if !tcx.is_general_coroutine(def_id) { + let cx = ecx.cx(); + if !cx.is_general_coroutine(def_id) { return Err(NoSolution); } let coroutine = args.as_coroutine(); - let term = if tcx - .is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn) + let term = if cx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineReturn) { coroutine.return_ty().into() - } else if tcx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) { + } else if cx.is_lang_item(goal.predicate.def_id(), TraitSolverLangItem::CoroutineYield) { coroutine.yield_ty().into() } else { panic!("unexpected associated item `{:?}` for `{self_ty:?}`", goal.predicate.def_id()) @@ -737,7 +732,7 @@ where ), term, } - .upcast(tcx), + .upcast(cx), // Technically, we need to check that the coroutine type is Sized, // but that's already proven by the coroutine being WF. [], @@ -884,29 +879,29 @@ where impl_trait_ref: rustc_type_ir::TraitRef, target_container_def_id: I::DefId, ) -> Result { - let tcx = self.cx(); + let cx = self.cx(); Ok(if target_container_def_id == impl_trait_ref.def_id { // Default value from the trait definition. No need to rebase. goal.predicate.alias.args } else if target_container_def_id == impl_def_id { // Same impl, no need to fully translate, just a rebase from // the trait is sufficient. - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, impl_args) + goal.predicate.alias.args.rebase_onto(cx, impl_trait_ref.def_id, impl_args) } else { let target_args = self.fresh_args_for_item(target_container_def_id); let target_trait_ref = - tcx.impl_trait_ref(target_container_def_id).instantiate(tcx, target_args); + cx.impl_trait_ref(target_container_def_id).instantiate(cx, target_args); // Relate source impl to target impl by equating trait refs. self.eq(goal.param_env, impl_trait_ref, target_trait_ref)?; // Also add predicates since they may be needed to constrain the // target impl's params. self.add_goals( GoalSource::Misc, - tcx.predicates_of(target_container_def_id) - .iter_instantiated(tcx, target_args) - .map(|pred| goal.with(tcx, pred)), + cx.predicates_of(target_container_def_id) + .iter_instantiated(cx, target_args) + .map(|pred| goal.with(cx, pred)), ); - goal.predicate.alias.args.rebase_onto(tcx, impl_trait_ref.def_id, target_args) + goal.predicate.alias.args.rebase_onto(cx, impl_trait_ref.def_id, target_args) }) } } diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs index a16f9e64f2f74..120f96d24bda3 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/opaque_types.rs @@ -18,7 +18,7 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.cx(); + let cx = self.cx(); let opaque_ty = goal.predicate.alias; let expected = goal.predicate.term.as_type().expect("no such thing as an opaque const"); @@ -86,7 +86,7 @@ where } (Reveal::All, _) => { // FIXME: Add an assertion that opaque type storage is empty. - let actual = tcx.type_of(opaque_ty.def_id).instantiate(tcx, opaque_ty.args); + let actual = cx.type_of(opaque_ty.def_id).instantiate(cx, opaque_ty.args); self.eq(goal.param_env, expected, actual)?; self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } @@ -98,7 +98,7 @@ where /// /// FIXME: Interner argument is needed to constrain the `I` parameter. pub fn uses_unique_placeholders_ignoring_regions( - _interner: I, + _cx: I, args: I::GenericArgs, ) -> Result<(), NotUniqueParam> { let mut seen = GrowableBitSet::default(); diff --git a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs index ca90bc17cc7d8..14e68dd52b6c1 100644 --- a/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs +++ b/compiler/rustc_next_trait_solver/src/solve/normalizes_to/weak_types.rs @@ -18,18 +18,18 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.cx(); + let cx = self.cx(); let weak_ty = goal.predicate.alias; // Check where clauses self.add_goals( GoalSource::Misc, - tcx.predicates_of(weak_ty.def_id) - .iter_instantiated(tcx, weak_ty.args) - .map(|pred| goal.with(tcx, pred)), + cx.predicates_of(weak_ty.def_id) + .iter_instantiated(cx, weak_ty.args) + .map(|pred| goal.with(cx, pred)), ); - let actual = tcx.type_of(weak_ty.def_id).instantiate(tcx, weak_ty.args); + let actual = cx.type_of(weak_ty.def_id).instantiate(cx, weak_ty.args); self.instantiate_normalizes_to_term(goal, actual.into()); self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) diff --git a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs index a430dbb408c5c..d945288007174 100644 --- a/compiler/rustc_next_trait_solver/src/solve/project_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/project_goals.rs @@ -14,10 +14,10 @@ where &mut self, goal: Goal>, ) -> QueryResult { - let tcx = self.cx(); - let projection_term = goal.predicate.projection_term.to_term(tcx); + let cx = self.cx(); + let projection_term = goal.predicate.projection_term.to_term(cx); let goal = goal.with( - tcx, + cx, ty::PredicateKind::AliasRelate( projection_term, goal.predicate.term, diff --git a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs index d3ad55d6491b0..2cd3b10f56adb 100644 --- a/compiler/rustc_next_trait_solver/src/solve/search_graph.rs +++ b/compiler/rustc_next_trait_solver/src/solve/search_graph.rs @@ -164,7 +164,7 @@ impl SearchGraph { /// the remaining depth of all nested goals to prevent hangs /// in case there is exponential blowup. fn allowed_depth_for_nested( - tcx: I, + cx: I, stack: &IndexVec>, ) -> Option { if let Some(last) = stack.raw.last() { @@ -178,18 +178,18 @@ impl SearchGraph { SolverLimit(last.available_depth.0 - 1) }) } else { - Some(SolverLimit(tcx.recursion_limit())) + Some(SolverLimit(cx.recursion_limit())) } } fn stack_coinductive_from( - tcx: I, + cx: I, stack: &IndexVec>, head: StackDepth, ) -> bool { stack.raw[head.index()..] .iter() - .all(|entry| entry.input.value.goal.predicate.is_coinductive(tcx)) + .all(|entry| entry.input.value.goal.predicate.is_coinductive(cx)) } // When encountering a solver cycle, the result of the current goal @@ -247,8 +247,8 @@ impl SearchGraph { /// so we use a separate cache. Alternatively we could use /// a single cache and share it between coherence and ordinary /// trait solving. - pub(super) fn global_cache(&self, tcx: I) -> I::EvaluationCache { - tcx.evaluation_cache(self.mode) + pub(super) fn global_cache(&self, cx: I) -> I::EvaluationCache { + cx.evaluation_cache(self.mode) } /// Probably the most involved method of the whole solver. @@ -257,24 +257,24 @@ impl SearchGraph { /// handles caching, overflow, and coinductive cycles. pub(super) fn with_new_goal>( &mut self, - tcx: I, + cx: I, input: CanonicalInput, inspect: &mut ProofTreeBuilder, mut prove_goal: impl FnMut(&mut Self, &mut ProofTreeBuilder) -> QueryResult, ) -> QueryResult { self.check_invariants(); // Check for overflow. - let Some(available_depth) = Self::allowed_depth_for_nested(tcx, &self.stack) else { + let Some(available_depth) = Self::allowed_depth_for_nested(cx, &self.stack) else { if let Some(last) = self.stack.raw.last_mut() { last.encountered_overflow = true; } inspect .canonical_goal_evaluation_kind(inspect::WipCanonicalGoalEvaluationKind::Overflow); - return Self::response_no_constraints(tcx, input, Certainty::overflow(true)); + return Self::response_no_constraints(cx, input, Certainty::overflow(true)); }; - if let Some(result) = self.lookup_global_cache(tcx, input, available_depth, inspect) { + if let Some(result) = self.lookup_global_cache(cx, input, available_depth, inspect) { debug!("global cache hit"); return result; } @@ -287,12 +287,12 @@ impl SearchGraph { if let Some(entry) = cache_entry .with_coinductive_stack .as_ref() - .filter(|p| Self::stack_coinductive_from(tcx, &self.stack, p.head)) + .filter(|p| Self::stack_coinductive_from(cx, &self.stack, p.head)) .or_else(|| { cache_entry .with_inductive_stack .as_ref() - .filter(|p| !Self::stack_coinductive_from(tcx, &self.stack, p.head)) + .filter(|p| !Self::stack_coinductive_from(cx, &self.stack, p.head)) }) { debug!("provisional cache hit"); @@ -315,7 +315,7 @@ impl SearchGraph { inspect.canonical_goal_evaluation_kind( inspect::WipCanonicalGoalEvaluationKind::CycleInStack, ); - let is_coinductive_cycle = Self::stack_coinductive_from(tcx, &self.stack, stack_depth); + let is_coinductive_cycle = Self::stack_coinductive_from(cx, &self.stack, stack_depth); let usage_kind = if is_coinductive_cycle { HasBeenUsed::COINDUCTIVE_CYCLE } else { @@ -328,9 +328,9 @@ impl SearchGraph { return if let Some(result) = self.stack[stack_depth].provisional_result { result } else if is_coinductive_cycle { - Self::response_no_constraints(tcx, input, Certainty::Yes) + Self::response_no_constraints(cx, input, Certainty::Yes) } else { - Self::response_no_constraints(tcx, input, Certainty::overflow(false)) + Self::response_no_constraints(cx, input, Certainty::overflow(false)) }; } else { // No entry, we push this goal on the stack and try to prove it. @@ -355,9 +355,9 @@ impl SearchGraph { // not tracked by the cache key and from outside of this anon task, it // must not be added to the global cache. Notably, this is the case for // trait solver cycles participants. - let ((final_entry, result), dep_node) = tcx.with_cached_task(|| { + let ((final_entry, result), dep_node) = cx.with_cached_task(|| { for _ in 0..FIXPOINT_STEP_LIMIT { - match self.fixpoint_step_in_task(tcx, input, inspect, &mut prove_goal) { + match self.fixpoint_step_in_task(cx, input, inspect, &mut prove_goal) { StepResult::Done(final_entry, result) => return (final_entry, result), StepResult::HasChanged => debug!("fixpoint changed provisional results"), } @@ -366,17 +366,17 @@ impl SearchGraph { debug!("canonical cycle overflow"); let current_entry = self.pop_stack(); debug_assert!(current_entry.has_been_used.is_empty()); - let result = Self::response_no_constraints(tcx, input, Certainty::overflow(false)); + let result = Self::response_no_constraints(cx, input, Certainty::overflow(false)); (current_entry, result) }); - let proof_tree = inspect.finalize_canonical_goal_evaluation(tcx); + let proof_tree = inspect.finalize_canonical_goal_evaluation(cx); // We're now done with this goal. In case this goal is involved in a larger cycle // do not remove it from the provisional cache and update its provisional result. // We only add the root of cycles to the global cache. if let Some(head) = final_entry.non_root_cycle_participant { - let coinductive_stack = Self::stack_coinductive_from(tcx, &self.stack, head); + let coinductive_stack = Self::stack_coinductive_from(cx, &self.stack, head); let entry = self.provisional_cache.get_mut(&input).unwrap(); entry.stack_depth = None; @@ -396,8 +396,8 @@ impl SearchGraph { // participant is on the stack. This is necessary to prevent unstable // results. See the comment of `StackEntry::cycle_participants` for // more details. - self.global_cache(tcx).insert( - tcx, + self.global_cache(cx).insert( + cx, input, proof_tree, reached_depth, @@ -418,15 +418,15 @@ impl SearchGraph { /// this goal. fn lookup_global_cache>( &mut self, - tcx: I, + cx: I, input: CanonicalInput, available_depth: SolverLimit, inspect: &mut ProofTreeBuilder, ) -> Option> { let CacheData { result, proof_tree, additional_depth, encountered_overflow } = self - .global_cache(tcx) + .global_cache(cx) // FIXME: Awkward `Limit -> usize -> Limit`. - .get(tcx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; + .get(cx, input, self.stack.iter().map(|e| e.input), available_depth.0)?; // If we're building a proof tree and the current cache entry does not // contain a proof tree, we do not use the entry but instead recompute @@ -467,7 +467,7 @@ impl SearchGraph { /// point we are done. fn fixpoint_step_in_task( &mut self, - tcx: I, + cx: I, input: CanonicalInput, inspect: &mut ProofTreeBuilder, prove_goal: &mut F, @@ -506,9 +506,9 @@ impl SearchGraph { let reached_fixpoint = if let Some(r) = stack_entry.provisional_result { r == result } else if stack_entry.has_been_used == HasBeenUsed::COINDUCTIVE_CYCLE { - Self::response_no_constraints(tcx, input, Certainty::Yes) == result + Self::response_no_constraints(cx, input, Certainty::Yes) == result } else if stack_entry.has_been_used == HasBeenUsed::INDUCTIVE_CYCLE { - Self::response_no_constraints(tcx, input, Certainty::overflow(false)) == result + Self::response_no_constraints(cx, input, Certainty::overflow(false)) == result } else { false }; @@ -528,11 +528,11 @@ impl SearchGraph { } fn response_no_constraints( - tcx: I, + cx: I, goal: CanonicalInput, certainty: Certainty, ) -> QueryResult { - Ok(super::response_no_constraints_raw(tcx, goal.max_universe, goal.variables, certainty)) + Ok(super::response_no_constraints_raw(cx, goal.max_universe, goal.variables, certainty)) } #[allow(rustc::potential_query_instability)] diff --git a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs index 9746c836aff55..2bc9d35c2b020 100644 --- a/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs +++ b/compiler/rustc_next_trait_solver/src/solve/trait_goals.rs @@ -30,8 +30,8 @@ where self.trait_ref } - fn with_self_ty(self, tcx: I, self_ty: I::Ty) -> Self { - self.with_self_ty(tcx, self_ty) + fn with_self_ty(self, cx: I, self_ty: I::Ty) -> Self { + self.with_self_ty(cx, self_ty) } fn trait_def_id(self, _: I) -> I::DefId { @@ -43,18 +43,17 @@ where goal: Goal>, impl_def_id: I::DefId, ) -> Result, NoSolution> { - let tcx = ecx.cx(); + let cx = ecx.cx(); - let impl_trait_ref = tcx.impl_trait_ref(impl_def_id); - if !tcx - .args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) + let impl_trait_ref = cx.impl_trait_ref(impl_def_id); + if !cx.args_may_unify_deep(goal.predicate.trait_ref.args, impl_trait_ref.skip_binder().args) { return Err(NoSolution); } // An upper bound of the certainty of this goal, used to lower the certainty // of reservation impl to ambiguous during coherence. - let impl_polarity = tcx.impl_polarity(impl_def_id); + let impl_polarity = cx.impl_polarity(impl_def_id); let maximal_certainty = match (impl_polarity, goal.predicate.polarity) { // In intercrate mode, this is ambiguous. But outside of intercrate, // it's not a real impl. @@ -77,13 +76,13 @@ where ecx.probe_trait_candidate(CandidateSource::Impl(impl_def_id)).enter(|ecx| { let impl_args = ecx.fresh_args_for_item(impl_def_id); ecx.record_impl_args(impl_args); - let impl_trait_ref = impl_trait_ref.instantiate(tcx, impl_args); + let impl_trait_ref = impl_trait_ref.instantiate(cx, impl_args); ecx.eq(goal.param_env, goal.predicate.trait_ref, impl_trait_ref)?; - let where_clause_bounds = tcx + let where_clause_bounds = cx .predicates_of(impl_def_id) - .iter_instantiated(tcx, impl_args) - .map(|pred| goal.with(tcx, pred)); + .iter_instantiated(cx, impl_args) + .map(|pred| goal.with(cx, pred)); ecx.add_goals(GoalSource::ImplWhereBound, where_clause_bounds); ecx.evaluate_added_goals_and_make_canonical_response(maximal_certainty) @@ -181,13 +180,13 @@ where return Err(NoSolution); } - let tcx = ecx.cx(); + let cx = ecx.cx(); ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc).enter(|ecx| { - let nested_obligations = tcx + let nested_obligations = cx .predicates_of(goal.predicate.def_id()) - .iter_instantiated(tcx, goal.predicate.trait_ref.args) - .map(|p| goal.with(tcx, p)); + .iter_instantiated(cx, goal.predicate.trait_ref.args) + .map(|p| goal.with(cx, p)); // FIXME(-Znext-solver=coinductive): Should this be `GoalSource::ImplWhereBound`? ecx.add_goals(GoalSource::Misc, nested_obligations); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) @@ -232,13 +231,13 @@ where return Err(NoSolution); } - let tcx = ecx.cx(); + let cx = ecx.cx(); // But if there are inference variables, we have to wait until it's resolved. if (goal.param_env, goal.predicate.self_ty()).has_non_region_infer() { return ecx.forced_ambiguity(MaybeCause::Ambiguity); } - if tcx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) { + if cx.layout_is_pointer_like(goal.param_env, goal.predicate.self_ty()) { ecx.probe_builtin_trait_candidate(BuiltinImplSource::Misc) .enter(|ecx| ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)) } else { @@ -286,10 +285,10 @@ where return Err(NoSolution); } - let tcx = ecx.cx(); + let cx = ecx.cx(); let tupled_inputs_and_output = match structural_traits::extract_tupled_inputs_and_output_from_callable( - tcx, + cx, goal.predicate.self_ty(), goal_kind, )? { @@ -299,14 +298,14 @@ where } }; let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| { - ty::TraitRef::new(tcx, tcx.require_lang_item(TraitSolverLangItem::Sized), [output]) + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [output]) }); let pred = tupled_inputs_and_output .map_bound(|(inputs, _)| { - ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) + ty::TraitRef::new(cx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs]) }) - .upcast(tcx); + .upcast(cx); // A built-in `Fn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( @@ -314,7 +313,7 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, - [(GoalSource::ImplWhereBound, goal.with(tcx, output_is_sized_pred))], + [(GoalSource::ImplWhereBound, goal.with(cx, output_is_sized_pred))], ) } @@ -327,20 +326,20 @@ where return Err(NoSolution); } - let tcx = ecx.cx(); + let cx = ecx.cx(); let (tupled_inputs_and_output_and_coroutine, nested_preds) = structural_traits::extract_tupled_inputs_and_output_from_async_callable( - tcx, + cx, goal.predicate.self_ty(), goal_kind, // This region doesn't matter because we're throwing away the coroutine type - Region::new_static(tcx), + Region::new_static(cx), )?; let output_is_sized_pred = tupled_inputs_and_output_and_coroutine.map_bound( |AsyncCallableRelevantTypes { output_coroutine_ty, .. }| { ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Sized), + cx, + cx.require_lang_item(TraitSolverLangItem::Sized), [output_coroutine_ty], ) }, @@ -349,12 +348,12 @@ where let pred = tupled_inputs_and_output_and_coroutine .map_bound(|AsyncCallableRelevantTypes { tupled_inputs_ty, .. }| { ty::TraitRef::new( - tcx, + cx, goal.predicate.def_id(), [goal.predicate.self_ty(), tupled_inputs_ty], ) }) - .upcast(tcx); + .upcast(cx); // A built-in `AsyncFn` impl only holds if the output is sized. // (FIXME: technically we only need to check this if the type is a fn ptr...) Self::probe_and_consider_implied_clause( @@ -362,9 +361,9 @@ where CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, pred, - [goal.with(tcx, output_is_sized_pred)] + [goal.with(cx, output_is_sized_pred)] .into_iter() - .chain(nested_preds.into_iter().map(|pred| goal.with(tcx, pred))) + .chain(nested_preds.into_iter().map(|pred| goal.with(cx, pred))) .map(|goal| (GoalSource::ImplWhereBound, goal)), ) } @@ -437,8 +436,8 @@ where }; // Coroutines are not futures unless they come from `async` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_async(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_async(def_id) { return Err(NoSolution); } @@ -463,8 +462,8 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_gen(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -489,8 +488,8 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_gen(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_gen(def_id) { return Err(NoSolution); } @@ -513,8 +512,8 @@ where }; // Coroutines are not iterators unless they come from `gen` desugaring - let tcx = ecx.cx(); - if !tcx.coroutine_is_async_gen(def_id) { + let cx = ecx.cx(); + if !cx.coroutine_is_async_gen(def_id) { return Err(NoSolution); } @@ -540,8 +539,8 @@ where }; // `async`-desugared coroutines do not implement the coroutine trait - let tcx = ecx.cx(); - if !tcx.is_general_coroutine(def_id) { + let cx = ecx.cx(); + if !cx.is_general_coroutine(def_id) { return Err(NoSolution); } @@ -550,8 +549,8 @@ where ecx, CandidateSource::BuiltinImpl(BuiltinImplSource::Misc), goal, - ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()]) - .upcast(tcx), + ty::TraitRef::new(cx, goal.predicate.def_id(), [self_ty, coroutine.resume_ty()]) + .upcast(cx), // Technically, we need to check that the coroutine types are Sized, // but that's already proven by the coroutine being WF. [], @@ -727,7 +726,7 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Vec> { - let tcx = self.cx(); + let cx = self.cx(); let Goal { predicate: (a_ty, _b_ty), .. } = goal; let mut responses = vec![]; @@ -745,7 +744,7 @@ where )); } else if let Some(a_principal) = a_data.principal() { for new_a_principal in - D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(tcx, a_ty)).skip(1) + D::elaborate_supertraits(self.cx(), a_principal.with_self_ty(cx, a_ty)).skip(1) { responses.extend(self.consider_builtin_upcast_to_principal( goal, @@ -755,7 +754,7 @@ where b_data, b_region, Some(new_a_principal.map_bound(|trait_ref| { - ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref) + ty::ExistentialTraitRef::erase_self_ty(cx, trait_ref) })), )); } @@ -770,11 +769,11 @@ where b_data: I::BoundExistentialPredicates, b_region: I::Region, ) -> Result, NoSolution> { - let tcx = self.cx(); + let cx = self.cx(); let Goal { predicate: (a_ty, _), .. } = goal; // Can only unsize to an object-safe trait. - if b_data.principal_def_id().is_some_and(|def_id| !tcx.trait_is_object_safe(def_id)) { + if b_data.principal_def_id().is_some_and(|def_id| !cx.trait_is_object_safe(def_id)) { return Err(NoSolution); } @@ -783,24 +782,20 @@ where // (i.e. the principal, all of the associated types match, and any auto traits) ecx.add_goals( GoalSource::ImplWhereBound, - b_data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))), + b_data.iter().map(|pred| goal.with(cx, pred.with_self_ty(cx, a_ty))), ); // The type must be `Sized` to be unsized. ecx.add_goal( GoalSource::ImplWhereBound, goal.with( - tcx, - ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Sized), - [a_ty], - ), + cx, + ty::TraitRef::new(cx, cx.require_lang_item(TraitSolverLangItem::Sized), [a_ty]), ), ); // The type must outlive the lifetime of the `dyn` we're unsizing into. - ecx.add_goal(GoalSource::Misc, goal.with(tcx, ty::OutlivesPredicate(a_ty, b_region))); + ecx.add_goal(GoalSource::Misc, goal.with(cx, ty::OutlivesPredicate(a_ty, b_region))); ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } @@ -941,28 +936,28 @@ where a_args: I::GenericArgs, b_args: I::GenericArgs, ) -> Result, NoSolution> { - let tcx = self.cx(); + let cx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; - let unsizing_params = tcx.unsizing_params_for_adt(def.def_id()); + let unsizing_params = cx.unsizing_params_for_adt(def.def_id()); // We must be unsizing some type parameters. This also implies // that the struct has a tail field. if unsizing_params.is_empty() { return Err(NoSolution); } - let tail_field_ty = def.struct_tail_ty(tcx).unwrap(); + let tail_field_ty = def.struct_tail_ty(cx).unwrap(); - let a_tail_ty = tail_field_ty.instantiate(tcx, a_args); - let b_tail_ty = tail_field_ty.instantiate(tcx, b_args); + let a_tail_ty = tail_field_ty.instantiate(cx, a_args); + let b_tail_ty = tail_field_ty.instantiate(cx, b_args); // Instantiate just the unsizing params from B into A. The type after // this instantiation must be equal to B. This is so we don't unsize // unrelated type parameters. - let new_a_args = tcx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| { + let new_a_args = cx.mk_args_from_iter(a_args.iter().enumerate().map(|(i, a)| { if unsizing_params.contains(i as u32) { b_args.get(i).unwrap() } else { a } })); - let unsized_a_ty = Ty::new_adt(tcx, def, new_a_args); + let unsized_a_ty = Ty::new_adt(cx, def, new_a_args); // Finally, we require that `TailA: Unsize` for the tail field // types. @@ -970,10 +965,10 @@ where self.add_goal( GoalSource::ImplWhereBound, goal.with( - tcx, + cx, ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Unsize), + cx, + cx.require_lang_item(TraitSolverLangItem::Unsize), [a_tail_ty, b_tail_ty], ), ), @@ -998,25 +993,24 @@ where a_tys: I::Tys, b_tys: I::Tys, ) -> Result, NoSolution> { - let tcx = self.cx(); + let cx = self.cx(); let Goal { predicate: (_a_ty, b_ty), .. } = goal; let (&a_last_ty, a_rest_tys) = a_tys.split_last().unwrap(); let b_last_ty = b_tys.last().unwrap(); // Instantiate just the tail field of B., and require that they're equal. - let unsized_a_ty = - Ty::new_tup_from_iter(tcx, a_rest_tys.iter().copied().chain([b_last_ty])); + let unsized_a_ty = Ty::new_tup_from_iter(cx, a_rest_tys.iter().copied().chain([b_last_ty])); self.eq(goal.param_env, unsized_a_ty, b_ty)?; // Similar to ADTs, require that we can unsize the tail. self.add_goal( GoalSource::ImplWhereBound, goal.with( - tcx, + cx, ty::TraitRef::new( - tcx, - tcx.require_lang_item(TraitSolverLangItem::Unsize), + cx, + cx.require_lang_item(TraitSolverLangItem::Unsize), [a_last_ty, b_last_ty], ), ), From efa48bfaf314529e81757ca27cff70d97be6e9d4 Mon Sep 17 00:00:00 2001 From: DianQK Date: Thu, 20 Jun 2024 21:35:09 +0800 Subject: [PATCH 12/14] Bump black, ruff and platformdirs Mainly because I encountered the following error, and we have no reason to prevent our upgrade. ``` ERROR: pip's dependency resolver does not currently take into account all the packages that are installed. This behaviour is the source of the following dependency conflicts. virtualenv 20.25.3 requires platformdirs<5,>=3.9.1, but you have platformdirs 3.6.0 which is incompatible. ``` --- src/tools/tidy/config/requirements.in | 4 +- src/tools/tidy/config/requirements.txt | 91 +++++++++++++------------- src/tools/tidy/config/ruff.toml | 23 +++---- src/tools/tidy/src/ext_tool_checks.rs | 3 +- 4 files changed, 60 insertions(+), 61 deletions(-) diff --git a/src/tools/tidy/config/requirements.in b/src/tools/tidy/config/requirements.in index 047617c65598f..833d62a864b13 100644 --- a/src/tools/tidy/config/requirements.in +++ b/src/tools/tidy/config/requirements.in @@ -6,5 +6,5 @@ # Note: this generation step should be run with the oldest supported python # version (currently 3.9) to ensure backward compatibility -black==23.3.0 -ruff==0.0.272 +black==24.4.2 +ruff==0.4.9 diff --git a/src/tools/tidy/config/requirements.txt b/src/tools/tidy/config/requirements.txt index a53c98cac7a06..d5236868ad17c 100644 --- a/src/tools/tidy/config/requirements.txt +++ b/src/tools/tidy/config/requirements.txt @@ -4,32 +4,29 @@ # # pip-compile --generate-hashes --strip-extras src/tools/tidy/config/requirements.in # -black==23.3.0 \ - --hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \ - --hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \ - --hash=sha256:11c410f71b876f961d1de77b9699ad19f939094c3a677323f43d7a29855fe326 \ - --hash=sha256:1c7b8d606e728a41ea1ccbd7264677e494e87cf630e399262ced92d4a8dac940 \ - --hash=sha256:1d06691f1eb8de91cd1b322f21e3bfc9efe0c7ca1f0e1eb1db44ea367dff656b \ - --hash=sha256:3238f2aacf827d18d26db07524e44741233ae09a584273aa059066d644ca7b30 \ - --hash=sha256:32daa9783106c28815d05b724238e30718f34155653d4d6e125dc7daec8e260c \ - --hash=sha256:35d1381d7a22cc5b2be2f72c7dfdae4072a3336060635718cc7e1ede24221d6c \ - --hash=sha256:3a150542a204124ed00683f0db1f5cf1c2aaaa9cc3495b7a3b5976fb136090ab \ - --hash=sha256:48f9d345675bb7fbc3dd85821b12487e1b9a75242028adad0333ce36ed2a6d27 \ - --hash=sha256:50cb33cac881766a5cd9913e10ff75b1e8eb71babf4c7104f2e9c52da1fb7de2 \ - --hash=sha256:562bd3a70495facf56814293149e51aa1be9931567474993c7942ff7d3533961 \ - --hash=sha256:67de8d0c209eb5b330cce2469503de11bca4085880d62f1628bd9972cc3366b9 \ - --hash=sha256:6b39abdfb402002b8a7d030ccc85cf5afff64ee90fa4c5aebc531e3ad0175ddb \ - --hash=sha256:6f3c333ea1dd6771b2d3777482429864f8e258899f6ff05826c3a4fcc5ce3f70 \ - --hash=sha256:714290490c18fb0126baa0fca0a54ee795f7502b44177e1ce7624ba1c00f2331 \ - --hash=sha256:7c3eb7cea23904399866c55826b31c1f55bbcd3890ce22ff70466b907b6775c2 \ - --hash=sha256:92c543f6854c28a3c7f39f4d9b7694f9a6eb9d3c5e2ece488c327b6e7ea9b266 \ - --hash=sha256:a6f6886c9869d4daae2d1715ce34a19bbc4b95006d20ed785ca00fa03cba312d \ - --hash=sha256:a8a968125d0a6a404842fa1bf0b349a568634f856aa08ffaff40ae0dfa52e7c6 \ - --hash=sha256:c7ab5790333c448903c4b721b59c0d80b11fe5e9803d8703e84dcb8da56fec1b \ - --hash=sha256:e114420bf26b90d4b9daa597351337762b63039752bdf72bf361364c1aa05925 \ - --hash=sha256:e198cf27888ad6f4ff331ca1c48ffc038848ea9f031a3b40ba36aced7e22f2c8 \ - --hash=sha256:ec751418022185b0c1bb7d7736e6933d40bbb14c14a0abcf9123d1b159f98dd4 \ - --hash=sha256:f0bd2f4a58d6666500542b26354978218a9babcdc972722f4bf90779524515f3 +black==24.4.2 \ + --hash=sha256:257d724c2c9b1660f353b36c802ccece186a30accc7742c176d29c146df6e474 \ + --hash=sha256:37aae07b029fa0174d39daf02748b379399b909652a806e5708199bd93899da1 \ + --hash=sha256:415e686e87dbbe6f4cd5ef0fbf764af7b89f9057b97c908742b6008cc554b9c0 \ + --hash=sha256:48a85f2cb5e6799a9ef05347b476cce6c182d6c71ee36925a6c194d074336ef8 \ + --hash=sha256:7768a0dbf16a39aa5e9a3ded568bb545c8c2727396d063bbaf847df05b08cd96 \ + --hash=sha256:7e122b1c4fb252fd85df3ca93578732b4749d9be076593076ef4d07a0233c3e1 \ + --hash=sha256:88c57dc656038f1ab9f92b3eb5335ee9b021412feaa46330d5eba4e51fe49b04 \ + --hash=sha256:8e537d281831ad0e71007dcdcbe50a71470b978c453fa41ce77186bbe0ed6021 \ + --hash=sha256:98e123f1d5cfd42f886624d84464f7756f60ff6eab89ae845210631714f6db94 \ + --hash=sha256:accf49e151c8ed2c0cdc528691838afd217c50412534e876a19270fea1e28e2d \ + --hash=sha256:b1530ae42e9d6d5b670a34db49a94115a64596bc77710b1d05e9801e62ca0a7c \ + --hash=sha256:b9176b9832e84308818a99a561e90aa479e73c523b3f77afd07913380ae2eab7 \ + --hash=sha256:bdde6f877a18f24844e381d45e9947a49e97933573ac9d4345399be37621e26c \ + --hash=sha256:be8bef99eb46d5021bf053114442914baeb3649a89dc5f3a555c88737e5e98fc \ + --hash=sha256:bf10f7310db693bb62692609b397e8d67257c55f949abde4c67f9cc574492cc7 \ + --hash=sha256:c872b53057f000085da66a19c55d68f6f8ddcac2642392ad3a355878406fbd4d \ + --hash=sha256:d36ed1124bb81b32f8614555b34cc4259c3fbc7eec17870e8ff8ded335b58d8c \ + --hash=sha256:da33a1a5e49c4122ccdfd56cd021ff1ebc4a1ec4e2d01594fef9b6f267a9e741 \ + --hash=sha256:dd1b5a14e417189db4c7b64a6540f31730713d173f0b63e55fabd52d61d8fdce \ + --hash=sha256:e151054aa00bad1f4e1f04919542885f89f5f7d086b8a59e5000e6c616896ffb \ + --hash=sha256:eaea3008c281f1038edb473c1aa8ed8143a5535ff18f978a318f10302b254063 \ + --hash=sha256:ef703f83fc32e131e9bcc0a5094cfe85599e7109f896fe8bc96cc402f3eb4b6e # via -r src/tools/tidy/config/requirements.in click==8.1.3 \ --hash=sha256:7682dc8afb30297001674575ea00d1814d808d6a36af415a82bd481d37ba7b8e \ @@ -47,28 +44,28 @@ pathspec==0.11.1 \ --hash=sha256:2798de800fa92780e33acca925945e9a19a133b715067cf165b8866c15a31687 \ --hash=sha256:d8af70af76652554bd134c22b3e8a1cc46ed7d91edcdd721ef1a0c51a84a5293 # via black -platformdirs==3.6.0 \ - --hash=sha256:57e28820ca8094678b807ff529196506d7a21e17156cb1cddb3e74cebce54640 \ - --hash=sha256:ffa199e3fbab8365778c4a10e1fbf1b9cd50707de826eb304b50e57ec0cc8d38 +platformdirs==4.2.2 \ + --hash=sha256:2d7a1657e36a80ea911db832a8a6ece5ee53d8de21edd5cc5879af6530b1bfee \ + --hash=sha256:38b7b51f512eed9e84a22788b4bce1de17c0adb134d6becb09836e37d8654cd3 # via black -ruff==0.0.272 \ - --hash=sha256:06b8ee4eb8711ab119db51028dd9f5384b44728c23586424fd6e241a5b9c4a3b \ - --hash=sha256:1609b864a8d7ee75a8c07578bdea0a7db75a144404e75ef3162e0042bfdc100d \ - --hash=sha256:19643d448f76b1eb8a764719072e9c885968971bfba872e14e7257e08bc2f2b7 \ - --hash=sha256:273a01dc8c3c4fd4c2af7ea7a67c8d39bb09bce466e640dd170034da75d14cab \ - --hash=sha256:27b2ea68d2aa69fff1b20b67636b1e3e22a6a39e476c880da1282c3e4bf6ee5a \ - --hash=sha256:48eccf225615e106341a641f826b15224b8a4240b84269ead62f0afd6d7e2d95 \ - --hash=sha256:677284430ac539bb23421a2b431b4ebc588097ef3ef918d0e0a8d8ed31fea216 \ - --hash=sha256:691d72a00a99707a4e0b2846690961157aef7b17b6b884f6b4420a9f25cd39b5 \ - --hash=sha256:86bc788245361a8148ff98667da938a01e1606b28a45e50ac977b09d3ad2c538 \ - --hash=sha256:905ff8f3d6206ad56fcd70674453527b9011c8b0dc73ead27618426feff6908e \ - --hash=sha256:9c4bfb75456a8e1efe14c52fcefb89cfb8f2a0d31ed8d804b82c6cf2dc29c42c \ - --hash=sha256:a37ec80e238ead2969b746d7d1b6b0d31aa799498e9ba4281ab505b93e1f4b28 \ - --hash=sha256:ae9b57546e118660175d45d264b87e9b4c19405c75b587b6e4d21e6a17bf4fdf \ - --hash=sha256:bd2bbe337a3f84958f796c77820d55ac2db1e6753f39d1d1baed44e07f13f96d \ - --hash=sha256:d5a208f8ef0e51d4746930589f54f9f92f84bb69a7d15b1de34ce80a7681bc00 \ - --hash=sha256:dc406e5d756d932da95f3af082814d2467943631a587339ee65e5a4f4fbe83eb \ - --hash=sha256:ee76b4f05fcfff37bd6ac209d1370520d509ea70b5a637bdf0a04d0c99e13dff +ruff==0.4.9 \ + --hash=sha256:06b60f91bfa5514bb689b500a25ba48e897d18fea14dce14b48a0c40d1635893 \ + --hash=sha256:0e8e7b95673f22e0efd3571fb5b0cf71a5eaaa3cc8a776584f3b2cc878e46bff \ + --hash=sha256:2d45ddc6d82e1190ea737341326ecbc9a61447ba331b0a8962869fcada758505 \ + --hash=sha256:4555056049d46d8a381f746680db1c46e67ac3b00d714606304077682832998e \ + --hash=sha256:5d5460f789ccf4efd43f265a58538a2c24dbce15dbf560676e430375f20a8198 \ + --hash=sha256:673bddb893f21ab47a8334c8e0ea7fd6598ecc8e698da75bcd12a7b9d0a3206e \ + --hash=sha256:732dd550bfa5d85af8c3c6cbc47ba5b67c6aed8a89e2f011b908fc88f87649db \ + --hash=sha256:784d3ec9bd6493c3b720a0b76f741e6c2d7d44f6b2be87f5eef1ae8cc1d54c84 \ + --hash=sha256:78de3fdb95c4af084087628132336772b1c5044f6e710739d440fc0bccf4d321 \ + --hash=sha256:8064590fd1a50dcf4909c268b0e7c2498253273309ad3d97e4a752bb9df4f521 \ + --hash=sha256:88bffe9c6a454bf8529f9ab9091c99490578a593cc9f9822b7fc065ee0712a06 \ + --hash=sha256:8c1aff58c31948cc66d0b22951aa19edb5af0a3af40c936340cd32a8b1ab7438 \ + --hash=sha256:98ec2775fd2d856dc405635e5ee4ff177920f2141b8e2d9eb5bd6efd50e80317 \ + --hash=sha256:b262ed08d036ebe162123170b35703aaf9daffecb698cd367a8d585157732991 \ + --hash=sha256:e0a22c4157e53d006530c902107c7f550b9233e9706313ab57b892d7197d8e52 \ + --hash=sha256:e91175fbe48f8a2174c9aad70438fe9cb0a5732c4159b2a10a3565fea2d94cde \ + --hash=sha256:f1cb0828ac9533ba0135d148d214e284711ede33640465e706772645483427e3 # via -r src/tools/tidy/config/requirements.in tomli==2.0.1 \ --hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \ diff --git a/src/tools/tidy/config/ruff.toml b/src/tools/tidy/config/ruff.toml index cf89ffd9ac73f..c87c17f783312 100644 --- a/src/tools/tidy/config/ruff.toml +++ b/src/tools/tidy/config/ruff.toml @@ -1,17 +1,7 @@ # Configuration for ruff python linter, run as part of tidy external tools -# B (bugbear), E (pycodestyle, standard), EXE (executables) F (flakes, standard) -# ERM for error messages would be beneficial at some point -select = ["B", "E", "EXE", "F"] - -ignore = [ - "E501", # line-too-long - "F403", # undefined-local-with-import-star - "F405", # undefined-local-with-import-star-usage -] - # lowest possible for ruff -target-version = "py37" +target-version = "py39" # Ignore all submodules extend-exclude = [ @@ -41,3 +31,14 @@ extend-exclude = [ "../library/backtrace/", "../src/tools/rustc-perf/", ] + +[lint] +# B (bugbear), E (pycodestyle, standard), EXE (executables) F (flakes, standard) +# ERM for error messages would be beneficial at some point +select = ["B", "E", "EXE", "F"] + +ignore = [ + "E501", # line-too-long + "F403", # undefined-local-with-import-star + "F405", # undefined-local-with-import-star-usage +] diff --git a/src/tools/tidy/src/ext_tool_checks.rs b/src/tools/tidy/src/ext_tool_checks.rs index 995ad58cb6219..e9dd6c66f6447 100644 --- a/src/tools/tidy/src/ext_tool_checks.rs +++ b/src/tools/tidy/src/ext_tool_checks.rs @@ -110,12 +110,13 @@ fn check_impl( } let mut args = merge_args(&cfg_args_ruff, &file_args_ruff); + args.insert(0, "check".as_ref()); let res = py_runner(py_path.as_ref().unwrap(), "ruff", &args); if res.is_err() && show_diff { eprintln!("\npython linting failed! Printing diff suggestions:"); - args.insert(0, "--diff".as_ref()); + args.insert(1, "--diff".as_ref()); let _ = py_runner(py_path.as_ref().unwrap(), "ruff", &args); } // Rethrow error From cf0251d92ced77d926a2292df96cb9ad3ce14f97 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Mon, 17 Jun 2024 18:47:09 +1000 Subject: [PATCH 13/14] Fix a span in `parse_ty_bare_fn`. It currently goes one token too far. Example: line 259 of `tests/ui/abi/compatibility.rs`: ``` test_abi_compatible!(fn_fn, fn(), fn(i32) -> i32); ``` This commit changes the span for the second element from `fn(),` to `fn()`, i.e. removes the extraneous comma. --- compiler/rustc_ast/src/ast.rs | 3 ++- compiler/rustc_parse/src/parser/ty.rs | 2 +- tests/ui/rust-2024/safe-outside-extern.gated.stderr | 2 +- tests/ui/rust-2024/safe-outside-extern.ungated.stderr | 2 +- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index 30c54ef2d3c41..4a3ce0e0c3066 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -2126,7 +2126,8 @@ pub struct BareFnTy { pub ext: Extern, pub generic_params: ThinVec, pub decl: P, - /// Span of the `fn(...) -> ...` part. + /// Span of the `[unsafe] [extern] fn(...) -> ...` part, i.e. everything + /// after the generic params (if there are any, e.g. `for<'a>`). pub decl_span: Span, } diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index fcd623b477f5d..d2043c353fed9 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -608,7 +608,7 @@ impl<'a> Parser<'a> { self.dcx().emit_err(FnPointerCannotBeAsync { span: whole_span, qualifier: span }); } // FIXME(gen_blocks): emit a similar error for `gen fn()` - let decl_span = span_start.to(self.token.span); + let decl_span = span_start.to(self.prev_token.span); Ok(TyKind::BareFn(P(BareFnTy { ext, safety, generic_params: params, decl, decl_span }))) } diff --git a/tests/ui/rust-2024/safe-outside-extern.gated.stderr b/tests/ui/rust-2024/safe-outside-extern.gated.stderr index ea7aa1814459d..18a3361f35b8e 100644 --- a/tests/ui/rust-2024/safe-outside-extern.gated.stderr +++ b/tests/ui/rust-2024/safe-outside-extern.gated.stderr @@ -26,7 +26,7 @@ error: function pointers cannot be declared with `safe` safety qualifier --> $DIR/safe-outside-extern.rs:24:14 | LL | type FnPtr = safe fn(i32, i32) -> i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr index 908f5b504eb23..9ea6d451e8c47 100644 --- a/tests/ui/rust-2024/safe-outside-extern.ungated.stderr +++ b/tests/ui/rust-2024/safe-outside-extern.ungated.stderr @@ -26,7 +26,7 @@ error: function pointers cannot be declared with `safe` safety qualifier --> $DIR/safe-outside-extern.rs:24:14 | LL | type FnPtr = safe fn(i32, i32) -> i32; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0658]: `unsafe extern {}` blocks and `safe` keyword are experimental --> $DIR/safe-outside-extern.rs:4:1 From 0addda65788642c9967cd151eff953be1ddee32f Mon Sep 17 00:00:00 2001 From: yukang Date: Wed, 26 Jun 2024 08:44:59 +0800 Subject: [PATCH 14/14] Fix bad replacement for unsafe extern block suggestion --- compiler/rustc_ast_passes/src/ast_validation.rs | 2 +- compiler/rustc_ast_passes/src/errors.rs | 2 +- tests/ui/parser/fn-header-semantic-fail.stderr | 16 ++++++++++------ .../ui/parser/no-const-fn-in-extern-block.stderr | 8 +++++--- tests/ui/parser/unsafe-foreign-mod-2.stderr | 8 +++++--- ...-on-unadorned-extern-block.edition2021.stderr | 16 ++++++++++------ ...-on-unadorned-extern-block.edition2024.stderr | 16 ++++++++++------ .../unsafe-on-extern-block-issue-126756.fixed | 10 ++++++++++ .../unsafe-on-extern-block-issue-126756.rs | 10 ++++++++++ .../unsafe-on-extern-block-issue-126756.stderr | 13 +++++++++++++ 10 files changed, 75 insertions(+), 26 deletions(-) create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs create mode 100644 tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs index 79717c969d79a..6cff5392f958a 100644 --- a/compiler/rustc_ast_passes/src/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -464,7 +464,7 @@ impl<'a> AstValidator<'a> { { self.dcx().emit_err(errors::InvalidSafetyOnExtern { item_span: span, - block: self.current_extern_span(), + block: self.current_extern_span().shrink_to_lo(), }); } } diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs index 96c476b271c60..965d8fac712ae 100644 --- a/compiler/rustc_ast_passes/src/errors.rs +++ b/compiler/rustc_ast_passes/src/errors.rs @@ -221,7 +221,7 @@ pub enum ExternBlockSuggestion { pub struct InvalidSafetyOnExtern { #[primary_span] pub item_span: Span, - #[suggestion(code = "", applicability = "maybe-incorrect")] + #[suggestion(code = "unsafe ", applicability = "machine-applicable", style = "verbose")] pub block: Span, } diff --git a/tests/ui/parser/fn-header-semantic-fail.stderr b/tests/ui/parser/fn-header-semantic-fail.stderr index 29404f1793ba8..b519ddbe2b436 100644 --- a/tests/ui/parser/fn-header-semantic-fail.stderr +++ b/tests/ui/parser/fn-header-semantic-fail.stderr @@ -81,11 +81,13 @@ LL | async fn fe1(); error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/fn-header-semantic-fail.rs:47:9 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -LL | async fn fe1(); LL | unsafe fn fe2(); | ^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: functions in `extern` blocks cannot have qualifiers --> $DIR/fn-header-semantic-fail.rs:48:9 @@ -135,11 +137,13 @@ LL | const async unsafe extern "C" fn fe5(); error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/fn-header-semantic-fail.rs:50:9 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -... LL | const async unsafe extern "C" fn fe5(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: functions cannot be both `const` and `async` --> $DIR/fn-header-semantic-fail.rs:50:9 diff --git a/tests/ui/parser/no-const-fn-in-extern-block.stderr b/tests/ui/parser/no-const-fn-in-extern-block.stderr index f575acc839d1c..8c23824a70888 100644 --- a/tests/ui/parser/no-const-fn-in-extern-block.stderr +++ b/tests/ui/parser/no-const-fn-in-extern-block.stderr @@ -18,11 +18,13 @@ LL | const unsafe fn bar(); error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/no-const-fn-in-extern-block.rs:4:5 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -... LL | const unsafe fn bar(); | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/parser/unsafe-foreign-mod-2.stderr b/tests/ui/parser/unsafe-foreign-mod-2.stderr index e59352395ed6e..77a383d5efa26 100644 --- a/tests/ui/parser/unsafe-foreign-mod-2.stderr +++ b/tests/ui/parser/unsafe-foreign-mod-2.stderr @@ -13,11 +13,13 @@ LL | extern "C" unsafe { error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/unsafe-foreign-mod-2.rs:4:5 | -LL | extern "C" unsafe { - | ----------------- help: add unsafe to this `extern` block -... LL | unsafe fn foo(); | ^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" unsafe { + | ++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr index 411cf48b4866a..e90613357b1ca 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2021.stderr @@ -1,20 +1,24 @@ error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -LL | LL | safe static TEST1: i32; | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -... LL | safe fn test1(i: i32); | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr index b634adc299960..1207ee158cc13 100644 --- a/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr +++ b/tests/ui/rust-2024/unsafe-extern-blocks/safe-unsafe-on-unadorned-extern-block.edition2024.stderr @@ -13,20 +13,24 @@ LL | | } error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:10:5 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -LL | LL | safe static TEST1: i32; | ^^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: items in unadorned `extern` blocks cannot have safety qualifiers --> $DIR/safe-unsafe-on-unadorned-extern-block.rs:12:5 | -LL | extern "C" { - | ---------- help: add unsafe to this `extern` block -... LL | safe fn test1(i: i32); | ^^^^^^^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ error: aborting due to 3 previous errors diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed new file mode 100644 index 0000000000000..2ff595cc44d1e --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.fixed @@ -0,0 +1,10 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![allow(dead_code)] + +unsafe extern "C" { + unsafe fn foo(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs new file mode 100644 index 0000000000000..6fe43f7a5b46d --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.rs @@ -0,0 +1,10 @@ +//@ run-rustfix + +#![feature(unsafe_extern_blocks)] +#![allow(dead_code)] + +extern "C" { + unsafe fn foo(); //~ ERROR items in unadorned `extern` blocks cannot have safety qualifiers +} + +fn main() {} diff --git a/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr new file mode 100644 index 0000000000000..05d23d001ada7 --- /dev/null +++ b/tests/ui/rust-2024/unsafe-extern-blocks/unsafe-on-extern-block-issue-126756.stderr @@ -0,0 +1,13 @@ +error: items in unadorned `extern` blocks cannot have safety qualifiers + --> $DIR/unsafe-on-extern-block-issue-126756.rs:7:5 + | +LL | unsafe fn foo(); + | ^^^^^^^^^^^^^^^^ + | +help: add unsafe to this `extern` block + | +LL | unsafe extern "C" { + | ++++++ + +error: aborting due to 1 previous error +