From c513c3b9a5deffac243b7bed3d339bd4e380dc1d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Mon, 20 Mar 2023 17:42:04 +0000 Subject: [PATCH 1/7] Remove outdated comments --- library/alloc/src/collections/btree/mod.rs | 1 - library/alloc/src/collections/btree/set.rs | 5 ----- library/std/src/collections/hash/set.rs | 7 ------- 3 files changed, 13 deletions(-) diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 7552f2fc04ce8..c7d0144de30cb 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -13,7 +13,6 @@ pub mod set; mod set_val; mod split; -#[doc(hidden)] trait Recover { type Key; diff --git a/library/alloc/src/collections/btree/set.rs b/library/alloc/src/collections/btree/set.rs index 4ddb211925202..4de30d40825e7 100644 --- a/library/alloc/src/collections/btree/set.rs +++ b/library/alloc/src/collections/btree/set.rs @@ -1,6 +1,3 @@ -// This is pretty much entirely stolen from TreeSet, since BTreeMap has an identical interface -// to TreeMap - use crate::vec::Vec; use core::borrow::Borrow; use core::cmp::Ordering::{self, Equal, Greater, Less}; @@ -18,8 +15,6 @@ use super::Recover; use crate::alloc::{Allocator, Global}; -// FIXME(conventions): implement bounded iterators - /// An ordered set based on a B-Tree. /// /// See [`BTreeMap`]'s documentation for a detailed discussion of this collection's performance diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index b59f89d321c47..837a18bff6087 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -12,13 +12,6 @@ use crate::ops::{BitAnd, BitOr, BitXor, Sub}; use super::map::{map_try_reserve_error, RandomState}; -// Future Optimization (FIXME!) -// ============================ -// -// Iteration over zero sized values is a noop. There is no need -// for `bucket.val` in the case of HashSet. I suppose we would need HKT -// to get rid of it properly. - /// A [hash set] implemented as a `HashMap` where the value is `()`. /// /// As with the [`HashMap`] type, a `HashSet` requires that the elements From 8126ccb77d5d7edd242a9f9566364b70f0a7b0a6 Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 21 Mar 2023 15:27:08 +0800 Subject: [PATCH 2/7] Return equal for two identical projections --- compiler/rustc_hir_typeck/src/upvar.rs | 6 ++---- tests/ui/closures/issue-109188.rs | 22 ++++++++++++++++++++++ tests/ui/closures/issue-109188.stderr | 19 +++++++++++++++++++ 3 files changed, 43 insertions(+), 4 deletions(-) create mode 100644 tests/ui/closures/issue-109188.rs create mode 100644 tests/ui/closures/issue-109188.stderr diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 4a432328c4d1b..90947912a19d6 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -712,10 +712,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - unreachable!( - "we captured two identical projections: capture1 = {:?}, capture2 = {:?}", - capture1, capture2 - ); + // return Equal for two identical projections + std::cmp::Ordering::Equal }); } diff --git a/tests/ui/closures/issue-109188.rs b/tests/ui/closures/issue-109188.rs new file mode 100644 index 0000000000000..cae1ced9958a7 --- /dev/null +++ b/tests/ui/closures/issue-109188.rs @@ -0,0 +1,22 @@ +enum Either { + One(X), + Two(X), +} + +struct X(Y); + +struct Y; + +fn consume_fnmut(f: &dyn FnMut()) { + f(); +} + +fn move_into_fnmut() { + let x = move_into_fnmut(); + consume_fnmut(&|| { + let Either::One(_t) = x; //~ ERROR mismatched types + let Either::Two(_t) = x; //~ ERROR mismatched types + }); +} + +fn main() { } diff --git a/tests/ui/closures/issue-109188.stderr b/tests/ui/closures/issue-109188.stderr new file mode 100644 index 0000000000000..d52b516294f99 --- /dev/null +++ b/tests/ui/closures/issue-109188.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:17:13 + | +LL | let Either::One(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error[E0308]: mismatched types + --> $DIR/issue-109188.rs:18:13 + | +LL | let Either::Two(_t) = x; + | ^^^^^^^^^^^^^^^ - this expression has type `()` + | | + | expected `()`, found `Either` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. From 7bffe945af456df6ad3294bdf82a67d727880adc Mon Sep 17 00:00:00 2001 From: yukang Date: Tue, 21 Mar 2023 20:05:34 +0800 Subject: [PATCH 3/7] add delay_span_bug --- compiler/rustc_hir_typeck/src/upvar.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 90947912a19d6..4847bddc38d18 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -712,7 +712,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - // return Equal for two identical projections + self.tcx.sess.delay_span_bug( + closure_span, + &format!( + "two identical projections: ({:?}, {:?})", + capture1.place.projections, capture2.place.projections + ), + ); std::cmp::Ordering::Equal }); } From a34c92760c4ced5eff6ac9a3d8cabab1ec200b0d Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 22 Mar 2023 17:13:00 +0000 Subject: [PATCH 4/7] Implement non-const Destruct trait in new solver --- .../rustc_trait_selection/src/solve/assembly.rs | 7 +++++++ .../src/solve/project_goals.rs | 7 +++++++ .../rustc_trait_selection/src/solve/trait_goals.rs | 14 ++++++++++++++ tests/ui/traits/new-solver/destruct.rs | 13 +++++++++++++ 4 files changed, 41 insertions(+) create mode 100644 tests/ui/traits/new-solver/destruct.rs diff --git a/compiler/rustc_trait_selection/src/solve/assembly.rs b/compiler/rustc_trait_selection/src/solve/assembly.rs index 76cde1a669225..f9cb56655ae86 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly.rs @@ -209,6 +209,11 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable> + Copy + Eq { ecx: &mut EvalCtxt<'_, 'tcx>, goal: Goal<'tcx, Self>, ) -> QueryResult<'tcx>; + + fn consider_builtin_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx>; } impl<'tcx> EvalCtxt<'_, 'tcx> { @@ -336,6 +341,8 @@ impl<'tcx> EvalCtxt<'_, 'tcx> { G::consider_builtin_unsize_candidate(self, goal) } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) { G::consider_builtin_discriminant_kind_candidate(self, goal) + } else if lang_items.destruct_trait() == Some(trait_def_id) { + G::consider_builtin_destruct_candidate(self, goal) } else { Err(NoSolution) }; diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs index 93d77c39f9580..df821a2913a93 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs @@ -483,6 +483,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) }) } + + fn consider_builtin_destruct_candidate( + _ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + bug!("`Destruct` does not have an associated type: {:?}", goal); + } } /// This behavior is also implemented in `rustc_ty_utils` and in the old `project` code. diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index 8ab55c79fc450..29b7ab61c7cf8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -513,6 +513,20 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { // `DiscriminantKind` is automatically implemented for every type. ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) } + + fn consider_builtin_destruct_candidate( + ecx: &mut EvalCtxt<'_, 'tcx>, + goal: Goal<'tcx, Self>, + ) -> QueryResult<'tcx> { + if !goal.param_env.is_const() { + // `Destruct` is automatically implemented for every type in + // non-const environments. + ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes) + } else { + // FIXME(-Ztrait-solver=next): Implement this when we get const working in the new solver + Err(NoSolution) + } + } } impl<'tcx> EvalCtxt<'_, 'tcx> { diff --git a/tests/ui/traits/new-solver/destruct.rs b/tests/ui/traits/new-solver/destruct.rs new file mode 100644 index 0000000000000..30d7777b78aa0 --- /dev/null +++ b/tests/ui/traits/new-solver/destruct.rs @@ -0,0 +1,13 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(const_trait_impl)] + +fn foo(_: impl std::marker::Destruct) {} + +struct MyAdt; + +fn main() { + foo(1); + foo(MyAdt); +} From 8390c61690186ddc45f97684732c8d3b6458cc44 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 22 Mar 2023 18:26:33 +0000 Subject: [PATCH 5/7] Drive-by: Add -Ztrait-solver=next to canonical int var test --- tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs index 3f7316a2279d3..4b013983a4a84 100644 --- a/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs +++ b/tests/ui/traits/new-solver/canonical-int-var-eq-in-response.rs @@ -1,3 +1,4 @@ +// compile-flags: -Ztrait-solver=next // check-pass trait Mirror { From 3a7977e3ca65ae8b6da8d81f475189333c149ac4 Mon Sep 17 00:00:00 2001 From: Kai Luo Date: Thu, 23 Mar 2023 16:33:54 +0800 Subject: [PATCH 6/7] Link against libc++ on AIX --- compiler/rustc_llvm/build.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 9fe59a1d8261b..f8e9ec535e456 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -333,6 +333,7 @@ fn main() { } else if target.contains("darwin") || target.contains("freebsd") || target.contains("windows-gnullvm") + || target.contains("aix") { "c++" } else if target.contains("netbsd") && llvm_static_stdcpp.is_some() { From d4d1cc4db6e0fb1f5427fcbece7b04bfb7952d9e Mon Sep 17 00:00:00 2001 From: Nathan Fenner Date: Thu, 23 Mar 2023 20:24:37 -0700 Subject: [PATCH 7/7] Make helper functions private --- .../src/fn_ctxt/adjust_fulfillment_errors.rs | 62 +++++++++---------- 1 file changed, 30 insertions(+), 32 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs index d64492e503db0..a148742c1cb9c 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs @@ -302,7 +302,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .iter() .filter(|field| { let field_ty = field.ty(self.tcx, identity_substs); - Self::find_param_in_ty(field_ty.into(), param_to_point_at) + find_param_in_ty(field_ty.into(), param_to_point_at) }) .collect(); @@ -348,7 +348,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .inputs() .iter() .enumerate() - .filter(|(_, ty)| Self::find_param_in_ty((**ty).into(), param_to_point_at)) + .filter(|(_, ty)| find_param_in_ty((**ty).into(), param_to_point_at)) .collect(); // If there's one field that references the given generic, great! if let [(idx, _)] = args_referencing_param.as_slice() @@ -571,8 +571,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Find out which of `in_ty_elements` refer to `param`. // FIXME: It may be better to take the first if there are multiple, // just so that the error points to a smaller expression. - let Some((drill_expr, drill_ty)) = Self::is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { - Self::find_param_in_ty((*in_ty_elem).into(), param) + let Some((drill_expr, drill_ty)) = is_iterator_singleton(expr_elements.iter().zip( in_ty_elements.iter()).filter(|(_expr_elem, in_ty_elem)| { + find_param_in_ty((*in_ty_elem).into(), param) })) else { // The param is not mentioned, or it is mentioned in multiple indexes. return Err(expr); @@ -620,10 +620,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -729,10 +729,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We need to know which of the generic parameters mentions our target param. // We expect that at least one of them does, since it is expected to be mentioned. let Some((drill_generic_index, generic_argument_type)) = - Self::is_iterator_singleton( + is_iterator_singleton( in_ty_adt_generic_args.iter().enumerate().filter( |(_index, in_ty_generic)| { - Self::find_param_in_ty(*in_ty_generic, param) + find_param_in_ty(*in_ty_generic, param) }, ), ) else { @@ -771,14 +771,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // outer contextual information. // (1) Find the (unique) field index which mentions the type in our constraint: - let Some((field_index, field_type)) = Self::is_iterator_singleton( + let Some((field_index, field_type)) = is_iterator_singleton( in_ty_adt .variant_with_id(variant_def_id) .fields .iter() .map(|field| field.ty(self.tcx, *in_ty_adt_generic_args)) .enumerate() - .filter(|(_index, field_type)| Self::find_param_in_ty((*field_type).into(), param)) + .filter(|(_index, field_type)| find_param_in_ty((*field_type).into(), param)) ) else { return Err(expr); }; @@ -811,20 +811,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Err(expr) } +} - // FIXME: This can be made into a private, non-impl function later. - /// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references - /// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. - pub fn find_param_in_ty( - ty: ty::GenericArg<'tcx>, - param_to_point_at: ty::GenericArg<'tcx>, - ) -> bool { - let mut walk = ty.walk(); - while let Some(arg) = walk.next() { - if arg == param_to_point_at { - return true; - } - if let ty::GenericArgKind::Type(ty) = arg.unpack() +/// Traverses the given ty (either a `ty::Ty` or a `ty::GenericArg`) and searches for references +/// to the given `param_to_point_at`. Returns `true` if it finds any use of the param. +fn find_param_in_ty<'tcx>( + ty: ty::GenericArg<'tcx>, + param_to_point_at: ty::GenericArg<'tcx>, +) -> bool { + let mut walk = ty.walk(); + while let Some(arg) = walk.next() { + if arg == param_to_point_at { + return true; + } + if let ty::GenericArgKind::Type(ty) = arg.unpack() && let ty::Alias(ty::Projection, ..) = ty.kind() { // This logic may seem a bit strange, but typically when @@ -835,16 +835,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // in some UI tests. walk.skip_current_subtree(); } - } - false } + false +} - // FIXME: This can be made into a private, non-impl function later. - /// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. - pub fn is_iterator_singleton(mut iterator: impl Iterator) -> Option { - match (iterator.next(), iterator.next()) { - (_, Some(_)) => None, - (first, _) => first, - } +/// Returns `Some(iterator.next())` if it has exactly one item, and `None` otherwise. +fn is_iterator_singleton(mut iterator: impl Iterator) -> Option { + match (iterator.next(), iterator.next()) { + (_, Some(_)) => None, + (first, _) => first, } }