about summary refs log tree commit diff
diff options
context:
space:
mode:
authorlcnr <rust@lcnr.de>2024-05-06 16:04:57 +0000
committerlcnr <rust@lcnr.de>2024-05-06 16:04:57 +0000
commit24ee32cf70468b66da1a45e89422ca64e42c851c (patch)
tree5122346cb139c2ffef5c6d364f8b8d83e797ca34
parent5f044f352884cc627a0d6216581f68d9e045a7b4 (diff)
downloadrust-24ee32cf70468b66da1a45e89422ca64e42c851c.tar.gz
rust-24ee32cf70468b66da1a45e89422ca64e42c851c.zip
borrowck: more eagerly prepopulate opaques
-rw-r--r--compiler/rustc_borrowck/src/lib.rs28
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs71
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/mod.rs13
-rw-r--r--tests/ui/impl-trait/dyn-trait-elided-two-inputs-ref-assoc.rs3
-rw-r--r--tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs3
-rw-r--r--tests/ui/impl-trait/issues/issue-105826.rs3
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.next.stderr14
-rw-r--r--tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.rs29
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-defining-opaque.current.stderr (renamed from tests/ui/traits/trait-upcasting/illegal-upcast-from-impl-opaque.current.stderr)6
-rw-r--r--tests/ui/traits/trait-upcasting/upcast-defining-opaque.rs24
10 files changed, 78 insertions, 116 deletions
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<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-   |
-note: 
-  --> $DIR/illegal-upcast-from-impl-opaque.rs:25:1
-   |
-LL | fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
-   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-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<T: ?Sized> Super for T {
-    type Assoc = i32;
-}
-
-type Foo = impl Sized;
-
-fn illegal(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
-    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
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<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
-   |                                         ----------------------- expected `&dyn Super<Assoc = i32>` because of return type
+LL | fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+   |                                        ----------------------- expected `&dyn Super<Assoc = i32>` 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<T: ?Sized> Super for T {
+    type Assoc = i32;
+}
+
+type Foo = impl Sized;
+
+fn upcast(x: &dyn Sub<Assoc = Foo>) -> &dyn Super<Assoc = i32> {
+    x //[current]~ mismatched types
+}
+
+fn main() {}