-
Notifications
You must be signed in to change notification settings - Fork 13.4k
Allow generators to impl Clone/Copy #95137
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
8700f69
5fca814
0451205
0e8c69e
43f42d2
960bdcc
c32400f
cf91768
251b92a
0cccb99
2688d75
69168f1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1887,8 +1887,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
ty::Dynamic(..) | ||
| ty::Str | ||
| ty::Slice(..) | ||
| ty::Generator(..) | ||
| ty::GeneratorWitness(..) | ||
| ty::Generator(_, _, hir::Movability::Static) | ||
| ty::Foreign(..) | ||
| ty::Ref(_, _, hir::Mutability::Mut) => None, | ||
|
||
|
@@ -1897,6 +1896,43 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { | |
Where(obligation.predicate.rebind(tys.iter().collect())) | ||
} | ||
|
||
ty::Generator(_, substs, hir::Movability::Movable) => { | ||
if self.tcx().features().generator_clone { | ||
let resolved_upvars = | ||
self.infcx.shallow_resolve(substs.as_generator().tupled_upvars_ty()); | ||
let resolved_witness = | ||
self.infcx.shallow_resolve(substs.as_generator().witness()); | ||
if resolved_upvars.is_ty_var() || resolved_witness.is_ty_var() { | ||
// Not yet resolved. | ||
Ambiguous | ||
} else { | ||
let all = substs | ||
.as_generator() | ||
.upvar_tys() | ||
.chain(iter::once(substs.as_generator().witness())) | ||
.collect::<Vec<_>>(); | ||
Comment on lines
+1909
to
+1913
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not due to this PR, but I really wish we had ways to track where an inference var got resolved and then bubble this span up here. In the current design there is no way to point at the local that causes the generator to stop being clone/copy, all we can do is keep pointing at the entire generator :( |
||
Where(obligation.predicate.rebind(all)) | ||
} | ||
} else { | ||
None | ||
} | ||
} | ||
|
||
ty::GeneratorWitness(binder) => { | ||
let witness_tys = binder.skip_binder(); | ||
for witness_ty in witness_tys.iter() { | ||
let resolved = self.infcx.shallow_resolve(witness_ty); | ||
if resolved.is_ty_var() { | ||
return Ambiguous; | ||
} | ||
} | ||
// (*) binder moved here | ||
let all_vars = self.tcx().mk_bound_variable_kinds( | ||
obligation.predicate.bound_vars().iter().chain(binder.bound_vars().iter()), | ||
); | ||
Where(ty::Binder::bind_with_vars(witness_tys.to_vec(), all_vars)) | ||
} | ||
|
||
ty::Closure(_, substs) => { | ||
// (*) binder moved here | ||
let ty = self.infcx.shallow_resolve(substs.as_closure().tupled_upvars_ty()); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
// edition:2021 | ||
// gate-test-generator_clone | ||
// Verifies that feature(generator_clone) doesn't allow async blocks to be cloned/copied. | ||
|
||
#![feature(generators, generator_clone)] | ||
|
||
use std::future::ready; | ||
|
||
struct NonClone; | ||
|
||
fn main() { | ||
let inner_non_clone = async { | ||
let non_clone = NonClone; | ||
let () = ready(()).await; | ||
drop(non_clone); | ||
}; | ||
check_copy(&inner_non_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&inner_non_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
|
||
let non_clone = NonClone; | ||
let outer_non_clone = async move { | ||
drop(non_clone); | ||
}; | ||
check_copy(&outer_non_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&outer_non_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
|
||
let maybe_copy_clone = async move {}; | ||
check_copy(&maybe_copy_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&maybe_copy_clone); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
|
||
let inner_non_clone_fn = the_inner_non_clone_fn(); | ||
check_copy(&inner_non_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&inner_non_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
|
||
let outer_non_clone_fn = the_outer_non_clone_fn(NonClone); | ||
check_copy(&outer_non_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&outer_non_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
|
||
let maybe_copy_clone_fn = the_maybe_copy_clone_fn(); | ||
check_copy(&maybe_copy_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Copy` is not satisfied | ||
check_clone(&maybe_copy_clone_fn); | ||
//~^ ERROR the trait bound `impl Future<Output = ()>: Clone` is not satisfied | ||
} | ||
|
||
async fn the_inner_non_clone_fn() { | ||
let non_clone = NonClone; | ||
let () = ready(()).await; | ||
drop(non_clone); | ||
} | ||
|
||
async fn the_outer_non_clone_fn(non_clone: NonClone) { | ||
let () = ready(()).await; | ||
drop(non_clone); | ||
} | ||
|
||
async fn the_maybe_copy_clone_fn() { | ||
} | ||
|
||
fn check_copy<T: Copy>(_x: &T) {} | ||
fn check_clone<T: Clone>(_x: &T) {} |
Uh oh!
There was an error while loading. Please reload this page.