Don't rely on upvars being assigned just because coroutine-closure kind is assigned
This commit is contained in:
parent
ab5bda1aa7
commit
6f96d7d012
6 changed files with 75 additions and 36 deletions
|
@ -2231,7 +2231,7 @@ impl<'tcx> Ty<'tcx> {
|
||||||
pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
|
pub fn tuple_fields(self) -> &'tcx List<Ty<'tcx>> {
|
||||||
match self.kind() {
|
match self.kind() {
|
||||||
Tuple(args) => args,
|
Tuple(args) => args,
|
||||||
_ => bug!("tuple_fields called on non-tuple"),
|
_ => bug!("tuple_fields called on non-tuple: {self:?}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -292,7 +292,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
|
||||||
let kind_ty = args.kind_ty();
|
let kind_ty = args.kind_ty();
|
||||||
let sig = args.coroutine_closure_sig().skip_binder();
|
let sig = args.coroutine_closure_sig().skip_binder();
|
||||||
|
|
||||||
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind()
|
||||||
|
&& !args.tupled_upvars_ty().is_ty_var()
|
||||||
|
{
|
||||||
if !closure_kind.extends(goal_kind) {
|
if !closure_kind.extends(goal_kind) {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
@ -401,7 +403,9 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
|
||||||
let kind_ty = args.kind_ty();
|
let kind_ty = args.kind_ty();
|
||||||
let sig = args.coroutine_closure_sig().skip_binder();
|
let sig = args.coroutine_closure_sig().skip_binder();
|
||||||
let mut nested = vec![];
|
let mut nested = vec![];
|
||||||
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
let coroutine_ty = if let Some(closure_kind) = kind_ty.to_opt_closure_kind()
|
||||||
|
&& !args.tupled_upvars_ty().is_ty_var()
|
||||||
|
{
|
||||||
if !closure_kind.extends(goal_kind) {
|
if !closure_kind.extends(goal_kind) {
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
}
|
}
|
||||||
|
|
|
@ -487,6 +487,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
|
||||||
bug!();
|
bug!();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Bail if the upvars haven't been constrained.
|
||||||
|
if tupled_upvars_ty.expect_ty().is_ty_var() {
|
||||||
|
return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
|
||||||
|
}
|
||||||
|
|
||||||
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
let Some(closure_kind) = closure_fn_kind_ty.expect_ty().to_opt_closure_kind() else {
|
||||||
// We don't need to worry about the self type being an infer var.
|
// We don't need to worry about the self type being an infer var.
|
||||||
return Err(NoSolution);
|
return Err(NoSolution);
|
||||||
|
|
|
@ -1601,7 +1601,10 @@ fn confirm_closure_candidate<'cx, 'tcx>(
|
||||||
// If we know the kind and upvars, use that directly.
|
// If we know the kind and upvars, use that directly.
|
||||||
// Otherwise, defer to `AsyncFnKindHelper::Upvars` to delay
|
// Otherwise, defer to `AsyncFnKindHelper::Upvars` to delay
|
||||||
// the projection, like the `AsyncFn*` traits do.
|
// the projection, like the `AsyncFn*` traits do.
|
||||||
let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind() {
|
let output_ty = if let Some(_) = kind_ty.to_opt_closure_kind()
|
||||||
|
// Fall back to projection if upvars aren't constrained
|
||||||
|
&& !args.tupled_upvars_ty().is_ty_var()
|
||||||
|
{
|
||||||
sig.to_coroutine_given_kind_and_upvars(
|
sig.to_coroutine_given_kind_and_upvars(
|
||||||
tcx,
|
tcx,
|
||||||
args.parent_args(),
|
args.parent_args(),
|
||||||
|
@ -1731,7 +1734,10 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
|
||||||
|
|
||||||
let term = match item_name {
|
let term = match item_name {
|
||||||
sym::CallOnceFuture | sym::CallRefFuture => {
|
sym::CallOnceFuture | sym::CallRefFuture => {
|
||||||
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
|
if let Some(closure_kind) = kind_ty.to_opt_closure_kind()
|
||||||
|
// Fall back to projection if upvars aren't constrained
|
||||||
|
&& !args.tupled_upvars_ty().is_ty_var()
|
||||||
|
{
|
||||||
if !closure_kind.extends(goal_kind) {
|
if !closure_kind.extends(goal_kind) {
|
||||||
bug!("we should not be confirming if the closure kind is not met");
|
bug!("we should not be confirming if the closure kind is not met");
|
||||||
}
|
}
|
||||||
|
|
|
@ -400,14 +400,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ty::CoroutineClosure(def_id, args) => {
|
ty::CoroutineClosure(def_id, args) => {
|
||||||
|
let args = args.as_coroutine_closure();
|
||||||
let is_const = self.tcx().is_const_fn_raw(def_id);
|
let is_const = self.tcx().is_const_fn_raw(def_id);
|
||||||
match self.infcx.closure_kind(self_ty) {
|
if let Some(closure_kind) = self.infcx.closure_kind(self_ty)
|
||||||
Some(closure_kind) => {
|
// Ambiguity if upvars haven't been constrained yet
|
||||||
let no_borrows = match self
|
&& !args.tupled_upvars_ty().is_ty_var()
|
||||||
.infcx
|
|
||||||
.shallow_resolve(args.as_coroutine_closure().tupled_upvars_ty())
|
|
||||||
.kind()
|
|
||||||
{
|
{
|
||||||
|
let no_borrows = match args.tupled_upvars_ty().kind() {
|
||||||
ty::Tuple(tys) => tys.is_empty(),
|
ty::Tuple(tys) => tys.is_empty(),
|
||||||
ty::Error(_) => false,
|
ty::Error(_) => false,
|
||||||
_ => bug!("tuple_fields called on non-tuple"),
|
_ => bug!("tuple_fields called on non-tuple"),
|
||||||
|
@ -425,8 +424,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
} else if kind == ty::ClosureKind::FnOnce {
|
} else if kind == ty::ClosureKind::FnOnce {
|
||||||
candidates.vec.push(ClosureCandidate { is_const });
|
candidates.vec.push(ClosureCandidate { is_const });
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
None => {
|
|
||||||
if kind == ty::ClosureKind::FnOnce {
|
if kind == ty::ClosureKind::FnOnce {
|
||||||
candidates.vec.push(ClosureCandidate { is_const });
|
candidates.vec.push(ClosureCandidate { is_const });
|
||||||
} else {
|
} else {
|
||||||
|
@ -435,7 +433,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
ty::Infer(ty::TyVar(_)) => {
|
ty::Infer(ty::TyVar(_)) => {
|
||||||
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
|
debug!("assemble_unboxed_closure_candidates: ambiguous self-type");
|
||||||
candidates.ambiguous = true;
|
candidates.ambiguous = true;
|
||||||
|
|
|
@ -0,0 +1,27 @@
|
||||||
|
//@ edition: 2021
|
||||||
|
//@ check-pass
|
||||||
|
//@ revisions: current next
|
||||||
|
//@ ignore-compare-mode-next-solver (explicit revisions)
|
||||||
|
//@[next] compile-flags: -Znext-solver
|
||||||
|
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
|
fn constrain<T: async FnOnce()>(t: T) -> T {
|
||||||
|
t
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_once<T>(f: impl FnOnce() -> T) -> T {
|
||||||
|
f()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn async_call_once<T>(f: impl async FnOnce() -> T) -> T {
|
||||||
|
f().await
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let c = constrain(async || {});
|
||||||
|
call_once(c);
|
||||||
|
|
||||||
|
let c = constrain(async || {});
|
||||||
|
async_call_once(c);
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue