From 24ee32cf70468b66da1a45e89422ca64e42c851c Mon Sep 17 00:00:00 2001 From: lcnr Date: Mon, 6 May 2024 16:04:57 +0000 Subject: [PATCH] borrowck: more eagerly prepopulate opaques --- compiler/rustc_borrowck/src/lib.rs | 28 ++++++++ compiler/rustc_borrowck/src/type_check/mod.rs | 71 +------------------ .../rustc_infer/src/infer/opaque_types/mod.rs | 13 ++++ .../dyn-trait-elided-two-inputs-ref-assoc.rs | 3 + .../in-trait/placeholder-implied-bounds.rs | 3 + tests/ui/impl-trait/issues/issue-105826.rs | 3 + ...llegal-upcast-from-impl-opaque.next.stderr | 14 ---- .../illegal-upcast-from-impl-opaque.rs | 29 -------- ... => upcast-defining-opaque.current.stderr} | 6 +- .../trait-upcasting/upcast-defining-opaque.rs | 24 +++++++ 10 files changed, 78 insertions(+), 116 deletions(-) delete mode 100644 tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr delete mode 100644 tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs rename tests/ui/traits/trait-upcasting/{illegal-upcast-from-impl-opaque.current.stderr => upcast-defining-opaque.current.stderr} (62%) create mode 100644 tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 8f4da4ef746..abe57e26af4 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -182,6 +182,12 @@ fn do_mir_borrowck<'tcx>( nll::replace_regions_in_mir(&infcx, param_env, &mut body_owned, &mut promoted); let body = &body_owned; // no further changes + // FIXME(-Znext-solver): A bit dubious that we're only registering + // predefined opaques in the typeck root. + if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { + infcx.register_predefined_opaques_for_next_solver(def); + } + let location_table = LocationTable::new(body); let move_data = MoveData::gather_moves(body, tcx, param_env, |_| true); @@ -488,6 +494,28 @@ impl<'tcx> BorrowckInferCtxt<'tcx> { next_region } + + /// With the new solver we prepopulate the opaque type storage during + /// MIR borrowck with the hidden types from HIR typeck. This is necessary + /// to avoid ambiguities as earlier goals can rely on the hidden type + /// of an opaque which is only constrained by a later goal. + fn register_predefined_opaques_for_next_solver(&self, def_id: LocalDefId) { + let tcx = self.tcx; + // OK to use the identity arguments for each opaque type key, since + // we remap opaques from HIR typeck back to their definition params. + for data in tcx.typeck(def_id).concrete_opaque_types.iter().map(|(k, v)| (*k, *v)) { + // HIR typeck did not infer the regions of the opaque, so we instantiate + // them with fresh inference variables. + let (key, hidden_ty) = tcx.fold_regions(data, |_, _| { + self.next_nll_region_var_in_universe( + NllRegionVariableOrigin::Existential { from_forall: false }, + ty::UniverseIndex::ROOT, + ) + }); + + self.inject_new_hidden_type_unchecked(key, hidden_ty); + } + } } impl<'tcx> Deref for BorrowckInferCtxt<'tcx> { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 65f0cf5afe8..13acc672def 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -24,7 +24,6 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::traits::query::NoSolution; -use rustc_middle::traits::ObligationCause; use rustc_middle::ty::adjustment::PointerCoercion; use rustc_middle::ty::cast::CastTy; use rustc_middle::ty::visit::TypeVisitableExt; @@ -1028,7 +1027,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound: ty::Region<'tcx>, borrowck_context: &'a mut BorrowCheckContext<'a, 'tcx>, ) -> Self { - let mut checker = Self { + Self { infcx, last_span: body.span, body, @@ -1039,74 +1038,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { implicit_region_bound, borrowck_context, reported_errors: Default::default(), - }; - - // FIXME(-Znext-solver): A bit dubious that we're only registering - // predefined opaques in the typeck root. - if infcx.next_trait_solver() && !infcx.tcx.is_typeck_child(body.source.def_id()) { - checker.register_predefined_opaques_for_next_solver(); - } - - checker - } - - pub(super) fn register_predefined_opaques_for_next_solver(&mut self) { - // OK to use the identity arguments for each opaque type key, since - // we remap opaques from HIR typeck back to their definition params. - let opaques: Vec<_> = self - .infcx - .tcx - .typeck(self.body.source.def_id().expect_local()) - .concrete_opaque_types - .iter() - .map(|(k, v)| (*k, *v)) - .collect(); - - let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| { - self.infcx.next_nll_region_var_in_universe( - NllRegionVariableOrigin::Existential { from_forall: false }, - ty::UniverseIndex::ROOT, - ) - }); - - let param_env = self.param_env; - let result = self.fully_perform_op( - Locations::All(self.body.span), - ConstraintCategory::OpaqueType, - CustomTypeOp::new( - |ocx| { - let mut obligations = Vec::new(); - for (opaque_type_key, hidden_ty) in renumbered_opaques { - let cause = ObligationCause::dummy(); - ocx.infcx.insert_hidden_type( - opaque_type_key, - &cause, - param_env, - hidden_ty.ty, - &mut obligations, - )?; - - ocx.infcx.add_item_bounds_for_hidden_type( - opaque_type_key.def_id.to_def_id(), - opaque_type_key.args, - cause, - param_env, - hidden_ty.ty, - &mut obligations, - ); - } - - ocx.register_obligations(obligations); - Ok(()) - }, - "register pre-defined opaques", - ), - ); - - if result.is_err() { - self.infcx - .dcx() - .span_bug(self.body.span, "failed re-defining predefined opaques in mir typeck"); } } diff --git a/compiler/rustc_infer/src/infer/opaque_types/mod.rs b/compiler/rustc_infer/src/infer/opaque_types/mod.rs index 94a546f87ee..b7ee860cf07 100644 --- a/compiler/rustc_infer/src/infer/opaque_types/mod.rs +++ b/compiler/rustc_infer/src/infer/opaque_types/mod.rs @@ -485,6 +485,19 @@ impl<'tcx> InferCtxt<'tcx> { Ok(InferOk { value: (), obligations }) } + /// Insert a hidden type into the opaque type storage, making sure + /// it hasn't previously been defined. This does not emit any + /// constraints and it's the responsibility of the caller to make + /// sure that the item bounds of the opaque are checked. + pub fn inject_new_hidden_type_unchecked( + &self, + opaque_type_key: OpaqueTypeKey<'tcx>, + hidden_ty: OpaqueHiddenType<'tcx>, + ) { + let prev = self.inner.borrow_mut().opaque_types().register(opaque_type_key, hidden_ty); + assert_eq!(prev, None); + } + /// Insert a hidden type into the opaque type storage, equating it /// with any previous entries if necessary. /// diff --git a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs index 2dc19b9ad68..e9706b656f2 100644 --- a/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs +++ b/tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs @@ -2,6 +2,9 @@ // when there are multiple inputs. The `dyn Bar` should default to `+ // 'static`. This used to erroneously generate an error (cc #62517). // +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass trait Foo { diff --git a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs index f7546a05bfd..df03150e29a 100644 --- a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs +++ b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass pub fn main() {} diff --git a/tests/ui/impl-trait/issues/issue-105826.rs b/tests/ui/impl-trait/issues/issue-105826.rs index e3488140dcc..33c5ed5fdeb 100644 --- a/tests/ui/impl-trait/issues/issue-105826.rs +++ b/tests/ui/impl-trait/issues/issue-105826.rs @@ -1,3 +1,6 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) //@ check-pass use std::io::Write; diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr deleted file mode 100644 index 3c2bc0b9190..00000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr +++ /dev/null @@ -1,14 +0,0 @@ -error: internal compiler error: error performing operation: query type op - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -note: - --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1 - | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -query stack during panic: -end of query stack diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs b/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs deleted file mode 100644 index f344474054a..00000000000 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs +++ /dev/null @@ -1,29 +0,0 @@ -//@ revisions: current next -//@[next] compile-flags: -Znext-solver -//@[next] failure-status: 101 -//@[next] known-bug: unknown -//@[next] normalize-stderr-test "note: .*\n\n" -> "" -//@[next] normalize-stderr-test "thread 'rustc' panicked.*\n.*\n" -> "" -//@[next] normalize-stderr-test "(error: internal compiler error: [^:]+):\d+:\d+: " -> "$1:LL:CC: " -//@[next] normalize-stderr-test "delayed at .*" -> "" -//@[next] rustc-env:RUST_BACKTRACE=0 - -#![feature(trait_upcasting, type_alias_impl_trait)] - -trait Super { - type Assoc; -} - -trait Sub: Super {} - -impl Super for T { - type Assoc = i32; -} - -type Foo = impl Sized; - -fn illegal(x: &dyn Sub) -> &dyn Super { - x //[current]~ mismatched types -} - -fn main() {} diff --git a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr similarity index 62% rename from tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr rename to tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr index c54a1c42bad..a259abb28ae 100644 --- a/tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/illegal-upcast-from-impl-opaque.rs:26:5 + --> $DIR/upcast-defining-opaque.rs:21:5 | LL | type Foo = impl Sized; | ---------- the found opaque type LL | -LL | fn illegal(x: &dyn Sub) -> &dyn Super { - | ----------------------- expected `&dyn Super` because of return type +LL | fn upcast(x: &dyn Sub) -> &dyn Super { + | ----------------------- expected `&dyn Super` because of return type LL | x | ^ expected trait `Super`, found trait `Sub` | diff --git a/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs new file mode 100644 index 00000000000..cb1501a94a2 --- /dev/null +++ b/tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs @@ -0,0 +1,24 @@ +//@ revisions: current next +//@[next] compile-flags: -Znext-solver +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] check-pass + +#![feature(trait_upcasting, type_alias_impl_trait)] + +trait Super { + type Assoc; +} + +trait Sub: Super {} + +impl Super for T { + type Assoc = i32; +} + +type Foo = impl Sized; + +fn upcast(x: &dyn Sub) -> &dyn Super { + x //[current]~ mismatched types +} + +fn main() {}