From fd51cc6bc958352c60468a0b68e1e617c45f3706 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 1 Oct 2023 13:47:50 +0000 Subject: [PATCH 01/13] Use DefKind to check for generator. --- compiler/rustc_mir_transform/src/const_prop_lint.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 64e262c6c9359..95d87c288dae1 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -49,8 +49,9 @@ impl<'tcx> MirLint<'tcx> for ConstProp { } let def_id = body.source.def_id().expect_local(); - let is_fn_like = tcx.def_kind(def_id).is_fn_like(); - let is_assoc_const = tcx.def_kind(def_id) == DefKind::AssocConst; + let def_kind = tcx.def_kind(def_id); + let is_fn_like = def_kind.is_fn_like(); + let is_assoc_const = def_kind == DefKind::AssocConst; // Only run const prop on functions, methods, closures and associated constants if !is_fn_like && !is_assoc_const { @@ -59,10 +60,9 @@ impl<'tcx> MirLint<'tcx> for ConstProp { return; } - let is_generator = tcx.type_of(def_id.to_def_id()).instantiate_identity().is_generator(); // FIXME(welseywiser) const prop doesn't work on generators because of query cycles // computing their layout. - if is_generator { + if let DefKind::Generator = def_kind { trace!("ConstProp skipped for generator {:?}", def_id); return; } From 7e1ecff56eda38a7e5b2b68745aea91dd7c57bd7 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 1 Oct 2023 13:48:29 +0000 Subject: [PATCH 02/13] Do not check for impossible predicates in const-prop lint. --- .../src/const_prop_lint.rs | 37 ------------------- 1 file changed, 37 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 95d87c288dae1..66e63a7b1568c 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -22,7 +22,6 @@ use rustc_middle::ty::{ }; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout}; -use rustc_trait_selection::traits; use crate::const_prop::CanConstProp; use crate::const_prop::ConstPropMachine; @@ -67,42 +66,6 @@ impl<'tcx> MirLint<'tcx> for ConstProp { return; } - // Check if it's even possible to satisfy the 'where' clauses - // for this item. - // This branch will never be taken for any normal function. - // However, it's possible to `#!feature(trivial_bounds)]` to write - // a function with impossible to satisfy clauses, e.g.: - // `fn foo() where String: Copy {}` - // - // We don't usually need to worry about this kind of case, - // since we would get a compilation error if the user tried - // to call it. However, since we can do const propagation - // even without any calls to the function, we need to make - // sure that it even makes sense to try to evaluate the body. - // If there are unsatisfiable where clauses, then all bets are - // off, and we just give up. - // - // We manually filter the predicates, skipping anything that's not - // "global". We are in a potentially generic context - // (e.g. we are evaluating a function without substituting generic - // parameters, so this filtering serves two purposes: - // - // 1. We skip evaluating any predicates that we would - // never be able prove are unsatisfiable (e.g. `` - // 2. We avoid trying to normalize predicates involving generic - // parameters (e.g. `::MyItem`). This can confuse - // the normalization code (leading to cycle errors), since - // it's usually never invoked in this way. - let predicates = tcx - .predicates_of(def_id.to_def_id()) - .predicates - .iter() - .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None }); - if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) { - trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id); - return; - } - trace!("ConstProp starting for {:?}", def_id); // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold From b1bef90d4fd7d20d106a6e814195a07d9b7fedc8 Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 1 Oct 2023 13:49:19 +0000 Subject: [PATCH 03/13] Rename lint pass. --- compiler/rustc_mir_transform/src/const_prop_lint.rs | 12 ++++++------ compiler/rustc_mir_transform/src/lib.rs | 2 +- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index 66e63a7b1568c..b51bfe8c6ab1f 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -34,9 +34,9 @@ use crate::MirLint; /// Severely regress performance. const MAX_ALLOC_LIMIT: u64 = 1024; -pub struct ConstProp; +pub struct ConstPropLint; -impl<'tcx> MirLint<'tcx> for ConstProp { +impl<'tcx> MirLint<'tcx> for ConstPropLint { fn run_lint(&self, tcx: TyCtxt<'tcx>, body: &Body<'tcx>) { if body.tainted_by_errors.is_some() { return; @@ -55,18 +55,18 @@ impl<'tcx> MirLint<'tcx> for ConstProp { // Only run const prop on functions, methods, closures and associated constants if !is_fn_like && !is_assoc_const { // skip anon_const/statics/consts because they'll be evaluated by miri anyway - trace!("ConstProp skipped for {:?}", def_id); + trace!("ConstPropLint skipped for {:?}", def_id); return; } // FIXME(welseywiser) const prop doesn't work on generators because of query cycles // computing their layout. if let DefKind::Generator = def_kind { - trace!("ConstProp skipped for generator {:?}", def_id); + trace!("ConstPropLint skipped for generator {:?}", def_id); return; } - trace!("ConstProp starting for {:?}", def_id); + trace!("ConstPropLint starting for {:?}", def_id); // FIXME(oli-obk, eddyb) Optimize locals (or even local paths) to hold // constants, instead of just checking for const-folding succeeding. @@ -75,7 +75,7 @@ impl<'tcx> MirLint<'tcx> for ConstProp { let mut linter = ConstPropagator::new(body, tcx); linter.visit_body(body); - trace!("ConstProp done for {:?}", def_id); + trace!("ConstPropLint done for {:?}", def_id); } } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 754f2ee837682..de1e6e39abb42 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -494,7 +494,7 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &elaborate_box_derefs::ElaborateBoxDerefs, &generator::StateTransform, &add_retag::AddRetag, - &Lint(const_prop_lint::ConstProp), + &Lint(const_prop_lint::ConstPropLint), ]; pm::run_passes_no_validate(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::Initial))); } From 465a82f51ab2ed9d94ef713c642a9b68ceffbabd Mon Sep 17 00:00:00 2001 From: Camille GILLOT Date: Sun, 1 Oct 2023 14:03:27 +0000 Subject: [PATCH 04/13] Remove outdated comment. --- compiler/rustc_mir_transform/src/lib.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index de1e6e39abb42..1af07fab75f62 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -552,8 +552,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) { &const_prop::ConstProp, &gvn::GVN, &dataflow_const_prop::DataflowConstProp, - // - // Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0. &const_debuginfo::ConstDebugInfo, &o1(simplify_branches::SimplifyConstCondition::AfterConstProp), &early_otherwise_branch::EarlyOtherwiseBranch, From 5087bb104688c068d593520e345ba5c0e0dc35ac Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Sep 2023 06:34:52 +0000 Subject: [PATCH 05/13] Relate AliasTy considering variance --- compiler/rustc_middle/src/ty/relate.rs | 34 ++++++++----------- .../impl-trait/in-trait/opaque-variances.rs | 14 ++++++++ 2 files changed, 29 insertions(+), 19 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/opaque-variances.rs diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index e9d763afa68a0..b28c2eafa6d41 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -8,6 +8,7 @@ use crate::ty::error::{ExpectedFound, TypeError}; use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable}; use crate::ty::{GenericArg, GenericArgKind, GenericArgsRef}; use rustc_hir as hir; +use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_target::spec::abi; use std::iter; @@ -273,7 +274,20 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { if a.def_id != b.def_id { Err(TypeError::ProjectionMismatched(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relation.relate(a.args, b.args)?; + let args = match relation.tcx().def_kind(a.def_id) { + DefKind::OpaqueTy => relate_args_with_variances( + relation, + a.def_id, + relation.tcx().variances_of(a.def_id), + a.args, + b.args, + false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle + )?, + DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => { + relation.relate(a.args, b.args)? + } + def => bug!("unknown alias DefKind: {def:?}"), + }; Ok(relation.tcx().mk_alias_ty(a.def_id, args)) } } @@ -536,24 +550,6 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( Ok(Ty::new_fn_ptr(tcx, fty)) } - // The args of opaque types may not all be invariant, so we have - // to treat them separately from other aliases. - ( - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, args: a_args, .. }), - &ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, args: b_args, .. }), - ) if a_def_id == b_def_id => { - let opt_variances = tcx.variances_of(a_def_id); - let args = relate_args_with_variances( - relation, - a_def_id, - opt_variances, - a_args, - b_args, - false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle - )?; - Ok(Ty::new_opaque(tcx, a_def_id, args)) - } - // Alias tend to mostly already be handled downstream due to normalization. (&ty::Alias(a_kind, a_data), &ty::Alias(b_kind, b_data)) => { let alias_ty = relation.relate(a_data, b_data)?; diff --git a/tests/ui/impl-trait/in-trait/opaque-variances.rs b/tests/ui/impl-trait/in-trait/opaque-variances.rs new file mode 100644 index 0000000000000..60bfab0deb582 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/opaque-variances.rs @@ -0,0 +1,14 @@ +// check-pass +// compile-flags: -Ztrait-solver=next + +fn foo<'a: 'a>(x: &'a Vec) -> impl Sized { + () +} + +fn main() { + // in NLL, we want to make sure that the `'a` subst of `foo` does not get + // related between `x` and the RHS of the assignment. That would require + // that the temp is live for the lifetime of the variable `x`, which of + // course is not necessary since `'a` is not captured by the RPIT. + let x = foo(&Vec::new()); +} From cdef3b12deb37edfc6b27ab05ef23faa777b35c3 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Sep 2023 06:35:33 +0000 Subject: [PATCH 06/13] Remove unnecessary relate impl --- compiler/rustc_middle/src/ty/relate.rs | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index b28c2eafa6d41..1827ea7cbb455 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -831,19 +831,6 @@ impl<'tcx> Relate<'tcx> for Term<'tcx> { } } -impl<'tcx> Relate<'tcx> for ty::ProjectionPredicate<'tcx> { - fn relate>( - relation: &mut R, - a: ty::ProjectionPredicate<'tcx>, - b: ty::ProjectionPredicate<'tcx>, - ) -> RelateResult<'tcx, ty::ProjectionPredicate<'tcx>> { - Ok(ty::ProjectionPredicate { - projection_ty: relation.relate(a.projection_ty, b.projection_ty)?, - term: relation.relate(a.term, b.term)?, - }) - } -} - /////////////////////////////////////////////////////////////////////////// // Error handling From be29d22eab8d3808aad5ecd6c14a9b618352736f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 28 Sep 2023 06:37:35 +0000 Subject: [PATCH 07/13] Make it clear that args default to being related invariantly --- compiler/rustc_infer/src/infer/equate.rs | 2 +- compiler/rustc_infer/src/infer/generalize.rs | 2 +- compiler/rustc_middle/src/ty/relate.rs | 20 ++++++++++---------- 3 files changed, 12 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs index 665297da20f89..5d929394eb04c 100644 --- a/compiler/rustc_infer/src/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -56,7 +56,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> { // performing trait matching (which then performs equality // unification). - relate::relate_args(self, a_arg, b_arg) + relate::relate_args_invariantly(self, a_arg, b_arg) } fn relate_with_variance>( diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs index dd7f8d3544155..c1e65ffe0a652 100644 --- a/compiler/rustc_infer/src/infer/generalize.rs +++ b/compiler/rustc_infer/src/infer/generalize.rs @@ -183,7 +183,7 @@ where // Avoid fetching the variance if we are in an invariant // context; no need, and it can induce dependency cycles // (e.g., #41849). - relate::relate_args(self, a_subst, b_subst) + relate::relate_args_invariantly(self, a_subst, b_subst) } else { let tcx = self.tcx(); let opt_variances = tcx.variances_of(item_def_id); diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs index 1827ea7cbb455..96268006353cc 100644 --- a/compiler/rustc_middle/src/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -135,7 +135,7 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>( } #[inline] -pub fn relate_args<'tcx, R: TypeRelation<'tcx>>( +pub fn relate_args_invariantly<'tcx, R: TypeRelation<'tcx>>( relation: &mut R, a_arg: GenericArgsRef<'tcx>, b_arg: GenericArgsRef<'tcx>, @@ -284,7 +284,7 @@ impl<'tcx> Relate<'tcx> for ty::AliasTy<'tcx> { false, // do not fetch `type_of(a_def_id)`, as it will cause a cycle )?, DefKind::AssocTy | DefKind::AssocConst | DefKind::TyAlias => { - relation.relate(a.args, b.args)? + relate_args_invariantly(relation, a.args, b.args)? } def => bug!("unknown alias DefKind: {def:?}"), }; @@ -329,7 +329,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::TraitRef::new(relation.tcx(), a.def_id, args)) } } @@ -345,7 +345,7 @@ impl<'tcx> Relate<'tcx> for ty::ExistentialTraitRef<'tcx> { if a.def_id != b.def_id { Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id))) } else { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ExistentialTraitRef { def_id: a.def_id, args }) } } @@ -463,7 +463,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Generator types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_generator(tcx, a_id, args, movability)) } @@ -473,7 +473,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All GeneratorWitness types with the same id represent // the (anonymous) type of the same generator expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_generator_witness(tcx, a_id, args)) } @@ -481,7 +481,7 @@ pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>( // All Closure types with the same id represent // the (anonymous) type of the same closure expression. So // all of their regions should be equated. - let args = relation.relate(a_args, b_args)?; + let args = relate_args_invariantly(relation, a_args, b_args)?; Ok(Ty::new_closure(tcx, a_id, &args)) } @@ -705,7 +705,7 @@ impl<'tcx> Relate<'tcx> for ty::ClosureArgs<'tcx> { a: ty::ClosureArgs<'tcx>, b: ty::ClosureArgs<'tcx>, ) -> RelateResult<'tcx, ty::ClosureArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::ClosureArgs { args }) } } @@ -716,7 +716,7 @@ impl<'tcx> Relate<'tcx> for ty::GeneratorArgs<'tcx> { a: ty::GeneratorArgs<'tcx>, b: ty::GeneratorArgs<'tcx>, ) -> RelateResult<'tcx, ty::GeneratorArgs<'tcx>> { - let args = relate_args(relation, a.args, b.args)?; + let args = relate_args_invariantly(relation, a.args, b.args)?; Ok(ty::GeneratorArgs { args }) } } @@ -727,7 +727,7 @@ impl<'tcx> Relate<'tcx> for GenericArgsRef<'tcx> { a: GenericArgsRef<'tcx>, b: GenericArgsRef<'tcx>, ) -> RelateResult<'tcx, GenericArgsRef<'tcx>> { - relate_args(relation, a, b) + relate_args_invariantly(relation, a, b) } } From 966f27977a888b332ff007f615c45e509e70576e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 4 Oct 2023 23:55:52 +0000 Subject: [PATCH 08/13] Structurally normalize async fn return type in deduce_future_output_from_obligations --- compiler/rustc_hir_typeck/src/closure.rs | 16 ++++++++++------ .../normalize-async-closure-in-trait.rs | 11 +++++++++++ 2 files changed, 21 insertions(+), 6 deletions(-) create mode 100644 tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index e426b937542ea..d4d62a40328da 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -688,8 +688,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { span_bug!(self.tcx.def_span(expr_def_id), "async fn generator outside of a fn") }); + let closure_span = self.tcx.def_span(expr_def_id); let ret_ty = ret_coercion.borrow().expected_ty(); - let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); + let ret_ty = self.try_structurally_resolve_type(closure_span, ret_ty); let get_future_output = |predicate: ty::Predicate<'tcx>, span| { // Search for a pending obligation like @@ -711,8 +712,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; - let span = self.tcx.def_span(expr_def_id); - let output_ty = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => { self.obligations_for_self_ty(ret_vid).find_map(|obligation| { @@ -726,17 +725,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .find_map(|(p, s)| get_future_output(p.as_predicate(), s))?, ty::Error(_) => return None, _ => span_bug!( - span, + closure_span, "async fn generator return type not an inference variable: {ret_ty}" ), }; - let output_ty = self.normalize(span, output_ty); + let output_ty = self.normalize(closure_span, output_ty); // async fn that have opaque types in their return type need to redo the conversion to inference variables // as they fetch the still opaque version from the signature. let InferOk { value: output_ty, obligations } = self - .replace_opaque_types_with_inference_vars(output_ty, body_def_id, span, self.param_env); + .replace_opaque_types_with_inference_vars( + output_ty, + body_def_id, + closure_span, + self.param_env, + ); self.register_predicates(obligations); Some(output_ty) diff --git a/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs new file mode 100644 index 0000000000000..b6200096a8921 --- /dev/null +++ b/tests/ui/traits/new-solver/normalize-async-closure-in-trait.rs @@ -0,0 +1,11 @@ +// compile-flags: -Ztrait-solver=next +// check-pass +// edition:2021 + +#![feature(async_fn_in_trait)] + +trait Foo { + async fn bar() {} +} + +fn main() {} From dfbb1bfc892d442cd9456f52ebc99a95c7dfbdcd Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Oct 2023 00:05:04 +0000 Subject: [PATCH 09/13] Also closures --- compiler/rustc_hir_typeck/src/closure.rs | 4 +++- .../deduce-closure-signature-after-normalization.rs | 12 ++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d4d62a40328da..e506c150f7d39 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -56,7 +56,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // closure sooner rather than later, so first examine the expected // type, and see if can glean a closure kind from there. let (expected_sig, expected_kind) = match expected.to_option(self) { - Some(ty) => self.deduce_closure_signature(ty), + Some(ty) => { + self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty)) + } None => (None, None), }; let body = self.tcx.hir().body(closure.body); diff --git a/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs new file mode 100644 index 0000000000000..d67fc65032ca7 --- /dev/null +++ b/tests/ui/traits/new-solver/deduce-closure-signature-after-normalization.rs @@ -0,0 +1,12 @@ +// compile-flags: -Ztrait-solver=next +// check-pass + +#![feature(return_position_impl_trait_in_trait)] + +trait Foo { + fn test() -> impl Fn(u32) -> u32 { + |x| x.count_ones() + } +} + +fn main() {} From 50b6f46f719bdba477ebb481f3cfe903507f3199 Mon Sep 17 00:00:00 2001 From: Deadbeef Date: Wed, 11 Oct 2023 08:25:08 +0000 Subject: [PATCH 10/13] small cleanup --- compiler/rustc_ast_lowering/src/item.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs index edc1e2f0b84d9..5bfc956aba198 100644 --- a/compiler/rustc_ast_lowering/src/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -1623,12 +1623,10 @@ impl<'hir> LoweringContext<'_, 'hir> { .lower_generic_params(bound_generic_params, hir::GenericParamSource::Binder), bounded_ty: self .lower_ty(bounded_ty, &ImplTraitContext::Disallowed(ImplTraitPosition::Bound)), - bounds: self.arena.alloc_from_iter(bounds.iter().map(|bound| { - self.lower_param_bound( - bound, - &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), - ) - })), + bounds: self.lower_param_bounds( + bounds, + &ImplTraitContext::Disallowed(ImplTraitPosition::Bound), + ), span: self.lower_span(*span), origin: PredicateOrigin::WhereClause, }), From a314707867141365e862624419b04788694b9169 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Oct 2023 11:33:31 +0200 Subject: [PATCH 11/13] Prevent showing methods from blanket impls of not available foreign traits to show up in the search results --- src/librustdoc/formats/cache.rs | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index b916baecc1407..36d32837ddf3e 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -310,7 +310,19 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { for_: clean::Type::BorrowedRef { type_, .. }, .. } => type_.def_id(&self.cache), - ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache), + ParentStackItem::Impl { for_, trait_, .. } => { + if let Some(trait_) = trait_ { + let trait_did = trait_.def_id(); + // If this is a foreign trait impl but the trait documentation + // is not available, we should not allow the methods to show up + // in the search results. + if !trait_did.is_local() && self.tcx.is_private_dep(trait_did.krate) + { + return None; + } + } + for_.def_id(&self.cache) + } ParentStackItem::Type(item_id) => item_id.as_def_id(), }; let path = did From efac0b9c024ebd960fe0e22ea06c0c6030759bf1 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Oct 2023 11:33:51 +0200 Subject: [PATCH 12/13] Add regression test for #115480 --- tests/rustdoc-js/auxiliary/equivalent.rs | 15 +++++++++++++++ tests/rustdoc-js/search-non-local-trait-impl.js | 9 +++++++++ tests/rustdoc-js/search-non-local-trait-impl.rs | 8 ++++++++ 3 files changed, 32 insertions(+) create mode 100644 tests/rustdoc-js/auxiliary/equivalent.rs create mode 100644 tests/rustdoc-js/search-non-local-trait-impl.js create mode 100644 tests/rustdoc-js/search-non-local-trait-impl.rs diff --git a/tests/rustdoc-js/auxiliary/equivalent.rs b/tests/rustdoc-js/auxiliary/equivalent.rs new file mode 100644 index 0000000000000..a19b5a2d44df2 --- /dev/null +++ b/tests/rustdoc-js/auxiliary/equivalent.rs @@ -0,0 +1,15 @@ +use std::borrow::Borrow; + +pub trait Equivalent { + fn equivalent(&self, key: &K) -> bool; +} + +impl Equivalent for Q +where + Q: Eq, + K: Borrow, +{ + fn equivalent(&self, key: &K) -> bool { + PartialEq::eq(self, key.borrow()) + } +} diff --git a/tests/rustdoc-js/search-non-local-trait-impl.js b/tests/rustdoc-js/search-non-local-trait-impl.js new file mode 100644 index 0000000000000..9ebeceb69f902 --- /dev/null +++ b/tests/rustdoc-js/search-non-local-trait-impl.js @@ -0,0 +1,9 @@ +// exact-check + +// This test ensures that methods from blanket impls of not available foreign traits +// don't show up in the search results. + +const EXPECTED = { + 'query': 'equivalent', + 'others': [], +}; diff --git a/tests/rustdoc-js/search-non-local-trait-impl.rs b/tests/rustdoc-js/search-non-local-trait-impl.rs new file mode 100644 index 0000000000000..462b75b0b1326 --- /dev/null +++ b/tests/rustdoc-js/search-non-local-trait-impl.rs @@ -0,0 +1,8 @@ +// aux-crate:priv:equivalent=equivalent.rs +// compile-flags: -Zunstable-options --extern equivalent +// edition:2018 + +extern crate equivalent; + +#[derive(Clone, PartialEq, Eq, Debug)] +pub struct LayoutError; From 2d37b00e24bfb1051e4a1d587bf766378d19e9b7 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 11 Oct 2023 11:41:09 +0200 Subject: [PATCH 13/13] Handle private dep at the same level as masked crates --- src/librustdoc/formats/cache.rs | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 36d32837ddf3e..4ccb5f2be346b 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -221,16 +221,23 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { _ => self.cache.stripped_mod, }; + #[inline] + fn is_from_private_dep(tcx: TyCtxt<'_>, cache: &Cache, def_id: DefId) -> bool { + let krate = def_id.krate; + + cache.masked_crates.contains(&krate) || tcx.is_private_dep(krate) + } + // If the impl is from a masked crate or references something from a // masked crate then remove it completely. if let clean::ImplItem(ref i) = *item.kind && (self.cache.masked_crates.contains(&item.item_id.krate()) || i.trait_ .as_ref() - .map_or(false, |t| self.cache.masked_crates.contains(&t.def_id().krate)) + .map_or(false, |t| is_from_private_dep(self.tcx, self.cache, t.def_id())) || i.for_ .def_id(self.cache) - .map_or(false, |d| self.cache.masked_crates.contains(&d.krate))) + .map_or(false, |d| is_from_private_dep(self.tcx, self.cache, d))) { return None; } @@ -310,19 +317,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { for_: clean::Type::BorrowedRef { type_, .. }, .. } => type_.def_id(&self.cache), - ParentStackItem::Impl { for_, trait_, .. } => { - if let Some(trait_) = trait_ { - let trait_did = trait_.def_id(); - // If this is a foreign trait impl but the trait documentation - // is not available, we should not allow the methods to show up - // in the search results. - if !trait_did.is_local() && self.tcx.is_private_dep(trait_did.krate) - { - return None; - } - } - for_.def_id(&self.cache) - } + ParentStackItem::Impl { for_, .. } => for_.def_id(&self.cache), ParentStackItem::Type(item_id) => item_id.as_def_id(), }; let path = did