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 9817186b874cc..a691b008e9d78 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`, 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 0000000000000..6a926534e079b --- /dev/null +++ b/tests/ui/traits/new-solver/auto-with-drop_tracking_mir.fail.stderr @@ -0,0 +1,18 @@ +error[E0277]: `impl Future` cannot be sent between threads safely + --> $DIR/auto-with-drop_tracking_mir.rs:24:13 + | +LL | is_send(foo()); + | ------- ^^^^^ `impl Future` cannot be sent between threads safely + | | + | required by a bound introduced by this call + | + = help: the trait `Send` is not implemented for `impl Future` +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 0000000000000..a5db7c4636b31 --- /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` cannot be sent between threads safely +}