From 983f6b97872d4dc2b7aaf2f9b088d433904e2f0e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Wed, 21 Jun 2023 02:22:55 +0000 Subject: [PATCH 1/3] Normalize opaques with escaping bound vars --- compiler/rustc_trait_selection/src/traits/project.rs | 6 +----- .../rustc_trait_selection/src/traits/query/normalize.rs | 7 +------ 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index c84c75cecdfe3..8440cbdecad1c 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -500,10 +500,7 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx // to make sure we don't forget to fold the substs regardless. match kind { - // This is really important. While we *can* handle this, this has - // severe performance implications for large opaque types with - // late-bound regions. See `issue-88862` benchmark. - ty::Opaque if !data.substs.has_escaping_bound_vars() => { + ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.super_fold_with(self), @@ -529,7 +526,6 @@ impl<'a, 'b, 'tcx> TypeFolder> for AssocTypeNormalizer<'a, 'b, 'tcx } } } - ty::Opaque => ty.super_fold_with(self), ty::Projection if !data.has_escaping_bound_vars() => { // This branch is *mostly* just an optimization: when we don't diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs index 1b6e92946c4be..edad519cec29e 100644 --- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -211,10 +211,7 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> // Wrap this in a closure so we don't accidentally return from the outer function let res = match kind { - // This is really important. While we *can* handle this, this has - // severe performance implications for large opaque types with - // late-bound regions. See `issue-88862` benchmark. - ty::Opaque if !data.substs.has_escaping_bound_vars() => { + ty::Opaque => { // Only normalize `impl Trait` outside of type inference, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty.try_super_fold_with(self)?, @@ -255,8 +252,6 @@ impl<'cx, 'tcx> FallibleTypeFolder> for QueryNormalizer<'cx, 'tcx> } } - ty::Opaque => ty.try_super_fold_with(self)?, - ty::Projection | ty::Inherent | ty::Weak => { // See note in `rustc_trait_selection::traits::project` From 75a8f681837c70051e0200a14f58ae07dbe58e66 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Jun 2023 21:50:44 +0000 Subject: [PATCH 2/3] Remove unnecessary DefineOpaqueTypes::Bubble from codegen --- compiler/rustc_traits/src/codegen.rs | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs index 5f84acc8a0473..ef50fa23caf2b 100644 --- a/compiler/rustc_traits/src/codegen.rs +++ b/compiler/rustc_traits/src/codegen.rs @@ -5,7 +5,7 @@ use rustc_infer::infer::TyCtxtInferExt; use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _}; -use rustc_middle::traits::{CodegenObligationError, DefiningAnchor}; +use rustc_middle::traits::CodegenObligationError; use rustc_middle::ty::{self, TyCtxt}; use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt; use rustc_trait_selection::traits::{ @@ -29,13 +29,7 @@ pub fn codegen_select_candidate<'tcx>( // Do the initial selection for the obligation. This yields the // shallow result we are looking for -- that is, what specific impl. - let infcx = tcx - .infer_ctxt() - .ignoring_regions() - .with_opaque_type_inference(DefiningAnchor::Bubble) - .build(); - //~^ HACK `Bubble` is required for - // this test to pass: type-alias-impl-trait/assoc-projection-ice.rs + let infcx = tcx.infer_ctxt().ignoring_regions().build(); let mut selcx = SelectionContext::new(&infcx); let obligation_cause = ObligationCause::dummy(); @@ -79,10 +73,5 @@ pub fn codegen_select_candidate<'tcx>( let impl_source = infcx.resolve_vars_if_possible(impl_source); let impl_source = infcx.tcx.erase_regions(impl_source); - // Opaque types may have gotten their hidden types constrained, but we can ignore them safely - // as they will get constrained elsewhere, too. - // (ouz-a) This is required for `type-alias-impl-trait/assoc-projection-ice.rs` to pass - let _ = infcx.take_opaque_types(); - Ok(&*tcx.arena.alloc(impl_source)) } From bfc6ca8207a0fda58a89ee7a9d2d109efdce5ab1 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 23 Jun 2023 22:00:55 +0000 Subject: [PATCH 3/3] More tests --- .../normalize-opaque-with-bound-vars.rs | 64 +++++++++++++++++++ .../normalize-opaque-with-bound-vars.rs | 27 ++++++++ 2 files changed, 91 insertions(+) create mode 100644 tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs create mode 100644 tests/ui/impl-trait/normalize-opaque-with-bound-vars.rs diff --git a/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs b/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs new file mode 100644 index 0000000000000..c4008f2b7e7ad --- /dev/null +++ b/tests/ui/async-await/in-trait/normalize-opaque-with-bound-vars.rs @@ -0,0 +1,64 @@ +// build-pass +// edition:2021 +// compile-flags: -Cdebuginfo=2 + +// We were not normalizing opaques with escaping bound vars during codegen, +// leading to later errors during debuginfo computation. + +#![feature(async_fn_in_trait)] + +#[derive(Clone, Copy)] +pub struct SharedState {} + +pub trait State { + async fn execute(self, shared_state: &SharedState); +} + +pub trait StateComposer { + fn and_then(self, map_fn: F) -> AndThen + where + Self: State + Sized, + T: State, + F: FnOnce() -> T, + { + AndThen { previous: self, map_fn } + } +} + +impl StateComposer for T where T: State {} +pub struct AndThen { + previous: T, + map_fn: F, +} + +impl State for AndThen +where + T: State, + U: State, + F: FnOnce() -> U, +{ + async fn execute(self, shared_state: &SharedState) + where + Self: Sized, + { + self.previous.execute(shared_state).await; + (self.map_fn)().execute(shared_state).await + } +} + +pub struct SomeState {} + +impl State for SomeState { + async fn execute(self, shared_state: &SharedState) {} +} + +pub fn main() { + let shared_state = SharedState {}; + async { + SomeState {} + .and_then(|| SomeState {}) + .and_then(|| SomeState {}) + .execute(&shared_state) + .await; + }; +} diff --git a/tests/ui/impl-trait/normalize-opaque-with-bound-vars.rs b/tests/ui/impl-trait/normalize-opaque-with-bound-vars.rs new file mode 100644 index 0000000000000..1025c2c7e8ad7 --- /dev/null +++ b/tests/ui/impl-trait/normalize-opaque-with-bound-vars.rs @@ -0,0 +1,27 @@ +// build-pass +// edition:2021 +// compile-flags: -Cdebuginfo=2 + +// We were not normalizing opaques with escaping bound vars during codegen, +// leading to later linker errors because of differences in mangled symbol name. + +fn func() -> impl Sized {} + +trait Trait<'a> { + type Assoc; + + fn call() { + let _ = async { + let _value = func::(); + std::future::ready(()).await + }; + } +} + +impl Trait<'static> for () { + type Assoc = (); +} + +fn main() { + <()>::call(); +}