Implement async closure signature deduction
This commit is contained in:
parent
b0696a5160
commit
d74d67c836
@ -56,18 +56,12 @@ pub fn check_expr_closure(
|
||||
// It's always helpful for inference if we know the kind of
|
||||
// closure sooner rather than later, so first examine the expected
|
||||
// type, and see if can glean a closure kind from there.
|
||||
let (expected_sig, expected_kind) = match closure.kind {
|
||||
hir::ClosureKind::Closure => match expected.to_option(self) {
|
||||
Some(ty) => {
|
||||
self.deduce_closure_signature(self.try_structurally_resolve_type(expr_span, ty))
|
||||
}
|
||||
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 (expected_sig, expected_kind) = match expected.to_option(self) {
|
||||
Some(ty) => self.deduce_closure_signature(
|
||||
self.try_structurally_resolve_type(expr_span, ty),
|
||||
closure.kind,
|
||||
),
|
||||
None => (None, None),
|
||||
};
|
||||
|
||||
let ClosureSignatures { bound_sig, mut liberated_sig } =
|
||||
@ -323,11 +317,13 @@ pub fn check_expr_closure(
|
||||
fn deduce_closure_signature(
|
||||
&self,
|
||||
expected_ty: Ty<'tcx>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
match *expected_ty.kind() {
|
||||
ty::Alias(ty::Opaque, ty::AliasTy { def_id, args, .. }) => self
|
||||
.deduce_closure_signature_from_predicates(
|
||||
expected_ty,
|
||||
closure_kind,
|
||||
self.tcx
|
||||
.explicit_item_bounds(def_id)
|
||||
.iter_instantiated_copied(self.tcx, args)
|
||||
@ -336,7 +332,7 @@ fn deduce_closure_signature(
|
||||
ty::Dynamic(object_type, ..) => {
|
||||
let sig = object_type.projection_bounds().find_map(|pb| {
|
||||
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
|
||||
.principal_def_id()
|
||||
@ -345,12 +341,18 @@ fn deduce_closure_signature(
|
||||
}
|
||||
ty::Infer(ty::TyVar(vid)) => self.deduce_closure_signature_from_predicates(
|
||||
Ty::new_var(self.tcx, self.root_var(vid)),
|
||||
closure_kind,
|
||||
self.obligations_for_self_ty(vid).map(|obl| (obl.predicate, obl.cause.span)),
|
||||
),
|
||||
ty::FnPtr(sig) => {
|
||||
let expected_sig = ExpectedSig { cause_span: None, sig };
|
||||
(Some(expected_sig), Some(ty::ClosureKind::Fn))
|
||||
}
|
||||
ty::FnPtr(sig) => match closure_kind {
|
||||
hir::ClosureKind::Closure => {
|
||||
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),
|
||||
}
|
||||
}
|
||||
@ -358,6 +360,7 @@ fn deduce_closure_signature(
|
||||
fn deduce_closure_signature_from_predicates(
|
||||
&self,
|
||||
expected_ty: Ty<'tcx>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
predicates: impl DoubleEndedIterator<Item = (ty::Predicate<'tcx>, Span)>,
|
||||
) -> (Option<ExpectedSig<'tcx>>, Option<ty::ClosureKind>) {
|
||||
let mut expected_sig = None;
|
||||
@ -386,6 +389,7 @@ fn deduce_closure_signature_from_predicates(
|
||||
span,
|
||||
self.deduce_sig_from_projection(
|
||||
Some(span),
|
||||
closure_kind,
|
||||
bound_predicate.rebind(proj_predicate),
|
||||
),
|
||||
);
|
||||
@ -422,13 +426,22 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
ty::PredicateKind::Clause(ty::ClauseKind::Trait(data)) => Some(data.def_id()),
|
||||
_ => None,
|
||||
};
|
||||
if let Some(closure_kind) =
|
||||
trait_def_id.and_then(|def_id| self.tcx.fn_trait_kind_from_def_id(def_id))
|
||||
{
|
||||
expected_kind = Some(
|
||||
expected_kind
|
||||
.map_or_else(|| closure_kind, |current| cmp::min(current, closure_kind)),
|
||||
);
|
||||
|
||||
if let Some(trait_def_id) = trait_def_id {
|
||||
let found_kind = match closure_kind {
|
||||
hir::ClosureKind::Closure => self.tcx.fn_trait_kind_from_def_id(trait_def_id),
|
||||
hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async) => {
|
||||
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 @@ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
|
||||
fn deduce_sig_from_projection(
|
||||
&self,
|
||||
cause_span: Option<Span>,
|
||||
closure_kind: hir::ClosureKind,
|
||||
projection: ty::PolyProjectionPredicate<'tcx>,
|
||||
) -> Option<ExpectedSig<'tcx>> {
|
||||
let tcx = self.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) {
|
||||
return None;
|
||||
|
||||
// For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
|
||||
// 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);
|
||||
|
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…
Reference in New Issue
Block a user