about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMatthias Krüger <matthias.krueger@famsik.de>2023-04-06 18:42:57 +0200
committerGitHub <noreply@github.com>2023-04-06 18:42:57 +0200
commitc86c9339e6991dbf9a9a4ae210492e94b142a728 (patch)
tree65c76c7e34cc6c4c0248794d0ac4183c1e163edf
parent3e21d6875f90eb0bc12833f73f56ec30cad6c1bd (diff)
parent4a4fc3bb5b1efe6857cf5d6c0b554ff36b966996 (diff)
downloadrust-c86c9339e6991dbf9a9a4ae210492e94b142a728.tar.gz
rust-c86c9339e6991dbf9a9a4ae210492e94b142a728.zip
Rollup merge of #109755 - compiler-errors:new-solver-generator-witness-mir, r=cjgillot
Implement support for `GeneratorWitnessMIR` in new solver

r? ```@cjgillot```

I mostly want this to cut down the number of failing UI tests when running the UI test suite with `--compare-mode=next-solver`, but there doesn't seem like much reason to block implementing this since it adds minimal complexity to the existing structural traits impl in the new solver.

If others are against adding this for some reason, then maybe we should just make `GeneratorWitnessMIR` return `NoSolution` for these traits. Anything but an ICE please :smile_cat: :ice_cube:
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs49
-rw-r--r--tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr18
-rw-r--r--tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs26
3 files changed, 90 insertions, 3 deletions
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
index fcb965dd725..4a3b7e42bac 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals/structural_traits.rs
@@ -1,7 +1,9 @@
 use rustc_data_structures::fx::FxHashMap;
 use rustc_hir::{def_id::DefId, Movability, Mutability};
 use rustc_infer::traits::query::NoSolution;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable};
+use rustc_middle::ty::{
+    self, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
+};
 
 use crate::solve::EvalCtxt;
 
@@ -60,7 +62,16 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
 
         ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()),
 
-        ty::GeneratorWitnessMIR(..) => todo!(),
+        ty::GeneratorWitnessMIR(def_id, substs) => Ok(ecx
+            .tcx()
+            .generator_hidden_types(def_id)
+            .map(|bty| {
+                ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
+                    tcx,
+                    bty.subst(tcx, substs),
+                ))
+            })
+            .collect()),
 
         // For `PhantomData<T>`, we pass `T`.
         ty::Adt(def, substs) if def.is_phantom_data() => Ok(vec![substs.type_at(0)]),
@@ -76,6 +87,29 @@ pub(super) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
     }
 }
 
+fn replace_erased_lifetimes_with_bound_vars<'tcx>(
+    tcx: TyCtxt<'tcx>,
+    ty: Ty<'tcx>,
+) -> ty::Binder<'tcx, Ty<'tcx>> {
+    debug_assert!(!ty.has_late_bound_regions());
+    let mut counter = 0;
+    let ty = tcx.fold_regions(ty, |mut r, current_depth| {
+        if let ty::ReErased = r.kind() {
+            let br = ty::BoundRegion {
+                var: ty::BoundVar::from_u32(counter),
+                kind: ty::BrAnon(counter, None),
+            };
+            counter += 1;
+            r = tcx.mk_re_late_bound(current_depth, br);
+        }
+        r
+    });
+    let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
+        (0..counter).map(|i| ty::BoundVariableKind::Region(ty::BrAnon(i, None))),
+    );
+    ty::Binder::bind_with_vars(ty, bound_vars)
+}
+
 pub(super) fn instantiate_constituent_tys_for_sized_trait<'tcx>(
     ecx: &EvalCtxt<'_, 'tcx>,
     ty: Ty<'tcx>,
@@ -178,7 +212,16 @@ pub(super) fn instantiate_constituent_tys_for_copy_clone_trait<'tcx>(
 
         ty::GeneratorWitness(types) => Ok(ecx.instantiate_binder_with_placeholders(types).to_vec()),
 
-        ty::GeneratorWitnessMIR(..) => todo!(),
+        ty::GeneratorWitnessMIR(def_id, substs) => Ok(ecx
+            .tcx()
+            .generator_hidden_types(def_id)
+            .map(|bty| {
+                ecx.instantiate_binder_with_placeholders(replace_erased_lifetimes_with_bound_vars(
+                    ecx.tcx(),
+                    bty.subst(ecx.tcx(), substs),
+                ))
+            })
+            .collect()),
     }
 }
 
diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr
new file mode 100644
index 00000000000..6a926534e07
--- /dev/null
+++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr
@@ -0,0 +1,18 @@
+error[E0277]: `impl Future<Output = ()>` cannot be sent between threads safely
+  --> $DIR/auto-with-drop_tracking_mir.rs:24:13
+   |
+LL |     is_send(foo());
+   |     ------- ^^^^^ `impl Future<Output = ()>` cannot be sent between threads safely
+   |     |
+   |     required by a bound introduced by this call
+   |
+   = help: the trait `Send` is not implemented for `impl Future<Output = ()>`
+note: required by a bound in `is_send`
+  --> $DIR/auto-with-drop_tracking_mir.rs:23:24
+   |
+LL |     fn is_send(_: impl Send) {}
+   |                        ^^^^ required by this bound in `is_send`
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs
new file mode 100644
index 00000000000..a5db7c4636b
--- /dev/null
+++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.rs
@@ -0,0 +1,26 @@
+// compile-flags: -Ztrait-solver=next -Zdrop-tracking-mir
+// edition: 2021
+// revisions: pass fail
+//[pass] check-pass
+
+#![feature(negative_impls)]
+
+struct NotSync;
+impl !Sync for NotSync {}
+
+async fn foo() {
+    #[cfg(pass)]
+    let x = &();
+    #[cfg(fail)]
+    let x = &NotSync;
+    bar().await;
+    drop(x);
+}
+
+async fn bar() {}
+
+fn main() {
+    fn is_send(_: impl Send) {}
+    is_send(foo());
+    //[fail]~^ ERROR `impl Future<Output = ()>` cannot be sent between threads safely
+}