Rollup merge of #121857 - compiler-errors:async-closure-signature-deduction, r=oli-obk
Implement async closure signature deduction Self-explanatory from title. Regarding the interaction between signature deduction, fulfillment, and the new trait solver: I'm not worried about implementing closure signature deduction here because: 1. async closures are unstable, and 2. I'm reasonably confident we'll need to support signature deduction in the new solver somehow (i.e. via proof trees, which seem very promising). This is in contrast to #109338, which was closed because it generalizes signature deduction for a *stable* kind of expression (`async {}` blocks and `Future` traits), and which proliferated usage may pose a stabilization hazard for the new solver. I'll be certain to make sure sure we revisit the closure signature deduction problem by the time that async closures are being stabilized (which isn't particularly soon) (edit: Put it into the async closure tracking issue). cc `````@lcnr````` r? `````@oli-obk`````
This commit is contained in:
commit
2875b10a7e
@ -56,18 +56,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
// It's always helpful for inference if we know the kind of
|
// It's always helpful for inference if we know the kind of
|
||||||
// closure sooner rather than later, so first examine the expected
|
// closure sooner rather than later, so first examine the expected
|
||||||
// type, and see if can glean a closure kind from there.
|
// type, and see if can glean a closure kind from there.
|
||||||
let (expected_sig, expected_kind) = match closure.kind {
|
let (expected_sig, expected_kind) = match expected.to_option(self) {
|
||||||
hir::ClosureKind::Closure => match expected.to_option(self) {
|
Some(ty) => self.deduce_closure_signature(
|
||||||
Some(ty) => {
|
self.try_structurally_resolve_type(expr_span, ty),
|
||||||
self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty))
|
closure.kind,
|
||||||
}
|
),
|
||||||
None => (None, None),
|
None => (None, None),
|
||||||
},
|
|
||||||
// We don't want to deduce a signature from `Fn` bounds for coroutines
|
|
||||||
// or coroutine-closures, because the former does not implement `Fn`
|
|
||||||
// ever, and the latter's signature doesn't correspond to the coroutine
|
|
||||||
// type that it returns.
|
|
||||||
hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => (None, None),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
let ClosureSignatures { bound_sig, mut liberated_sig } =
|
let ClosureSignatures { bound_sig, mut liberated_sig } =
|
||||||
@ -323,11 +317,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn deduce_closure_signature(
|
fn deduce_closure_signature(
|
||||||
&self,
|
&self,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
match *expected_ty.kind() {
|
match *expected_ty.kind() {
|
||||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||||
.deduce_closure_signature_from_predicates(
|
.deduce_closure_signature_from_predicates(
|
||||||
expected_ty,
|
expected_ty,
|
||||||
|
closure_kind,
|
||||||
self.tcx
|
self.tcx
|
||||||
.explicit_item_bounds(def_id)
|
.explicit_item_bounds(def_id)
|
||||||
.iter_instantiated_copied(self.tcx, args)
|
.iter_instantiated_copied(self.tcx, args)
|
||||||
@ -336,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::Dynamic(object_type, ..) => {
|
ty::Dynamic(object_type, ..) => {
|
||||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||||
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self);
|
||||||
self.deduce_sig_from_projection(None, pb)
|
self.deduce_sig_from_projection(None, closure_kind, pb)
|
||||||
});
|
});
|
||||||
let kind = object_type
|
let kind = object_type
|
||||||
.principal_def_id()
|
.principal_def_id()
|
||||||
@ -345,12 +341,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
}
|
}
|
||||||
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
|
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
|
||||||
Ty::new_var(self.tcx, self.root_var(vid)),
|
Ty::new_var(self.tcx, self.root_var(vid)),
|
||||||
|
closure_kind,
|
||||||
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
||||||
),
|
),
|
||||||
ty::FnPtr(sig) => {
|
ty::FnPtr(sig) => match closure_kind {
|
||||||
let expected_sig = ExpectedSig { cause_span: None, sig };
|
hir::ClosureKind::Closure => {
|
||||||
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
let expected_sig = ExpectedSig { cause_span: None, sig };
|
||||||
}
|
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
||||||
|
}
|
||||||
|
hir::ClosureKind::Coroutine(_) | hir::ClosureKind::CoroutineClosure(_) => {
|
||||||
|
(None, None)
|
||||||
|
}
|
||||||
|
},
|
||||||
_ => (None, None),
|
_ => (None, None),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -358,6 +360,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn deduce_closure_signature_from_predicates(
|
fn deduce_closure_signature_from_predicates(
|
||||||
&self,
|
&self,
|
||||||
expected_ty: Ty<'tcx>,
|
expected_ty: Ty<'tcx>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
||||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||||
let mut expected_sig = None;
|
let mut expected_sig = None;
|
||||||
@ -386,6 +389,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
span,
|
span,
|
||||||
self.deduce_sig_from_projection(
|
self.deduce_sig_from_projection(
|
||||||
Some(span),
|
Some(span),
|
||||||
|
closure_kind,
|
||||||
bound_predicate.rebind(proj_predicate),
|
bound_predicate.rebind(proj_predicate),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -422,13 +426,22 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
|
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
|
||||||
_ => None,
|
_ => None,
|
||||||
};
|
};
|
||||||
if let Some(closure_kind) =
|
|
||||||
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
|
if let Some(trait_def_id) = trait_def_id {
|
||||||
{
|
let found_kind = match closure_kind {
|
||||||
expected_kind = Some(
|
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
||||||
expected_kind
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
|
||||||
.map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
|
self.tcx.async_fn_trait_kind_from_def_id(trait_def_id)
|
||||||
);
|
}
|
||||||
|
_ => None,
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Some(found_kind) = found_kind {
|
||||||
|
expected_kind = Some(
|
||||||
|
expected_kind
|
||||||
|
.map_or_else(|| found_kind, |current| cmp::min(current, found_kind)),
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -445,14 +458,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|
|||||||
fn deduce_sig_from_projection(
|
fn deduce_sig_from_projection(
|
||||||
&self,
|
&self,
|
||||||
cause_span: Option<Span>,
|
cause_span: Option<Span>,
|
||||||
|
closure_kind: hir::ClosureKind,
|
||||||
projection: ty::PolyProjectionPredicate<'tcx>,
|
projection: ty::PolyProjectionPredicate<'tcx>,
|
||||||
) -> Option<ExpectedSig<'tcx>> {
|
) -> Option<ExpectedSig<'tcx>> {
|
||||||
let tcx = self.tcx;
|
let tcx = self.tcx;
|
||||||
|
|
||||||
let trait_def_id = projection.trait_def_id(tcx);
|
let trait_def_id = projection.trait_def_id(tcx);
|
||||||
// For now, we only do signature deduction based off of the `Fn` traits.
|
|
||||||
if !tcx.is_fn_trait(trait_def_id) {
|
// For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
|
||||||
return None;
|
// for closures and async closures, respectively.
|
||||||
|
match closure_kind {
|
||||||
|
hir::ClosureKind::Closure
|
||||||
|
if self.tcx.fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
|
||||||
|
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async)
|
||||||
|
if self.tcx.async_fn_trait_kind_from_def_id(trait_def_id).is_some() => {}
|
||||||
|
_ => return None,
|
||||||
}
|
}
|
||||||
|
|
||||||
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
let arg_param_ty = projection.skip_binder().projection_ty.args.type_at(1);
|
||||||
|
10
tests/ui/async-await/async-closures/signature-deduction.rs
Normal file
10
tests/ui/async-await/async-closures/signature-deduction.rs
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ edition: 2021
|
||||||
|
|
||||||
|
#![feature(async_closure)]
|
||||||
|
|
||||||
|
async fn foo(x: impl async Fn(&str) -> &str) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
foo(async |x| x);
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user