Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/closure.rs')
| -rw-r--r-- | crates/hir-ty/src/infer/closure.rs | 95 |
1 files changed, 75 insertions, 20 deletions
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 2637ed6b3e..06f8307eb0 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -11,8 +11,9 @@ use hir_def::{ type_ref::TypeRefId, }; use rustc_type_ir::{ - ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, Interner, TypeSuperVisitable, - TypeVisitable, TypeVisitableExt, TypeVisitor, + ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, + CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, + TypeVisitor, inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _}, }; use tracing::debug; @@ -22,11 +23,12 @@ use crate::{ db::{InternedClosure, InternedCoroutine}, infer::{BreakableKind, Diverges, coerce::CoerceMany}, next_solver::{ - AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, - PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind, + AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner, + ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate, + PredicateKind, SolverDefId, Ty, TyKind, abi::Safety, infer::{ - BoundRegionConversionTime, DefineOpaqueTypes, InferOk, InferResult, + BoundRegionConversionTime, InferOk, InferResult, traits::{ObligationCause, PredicateObligations}, }, util::explicit_item_bounds, @@ -72,6 +74,8 @@ impl<'db> InferenceContext<'_, 'db> { let sig_ty = Ty::new_fn_ptr(interner, bound_sig); let parent_args = GenericArgs::identity_for_item(interner, self.generic_def.into()); + // FIXME: Make this an infer var and infer it later. + let tupled_upvars_ty = self.types.unit; let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Coroutine(_) => { let yield_ty = self.table.next_ty_var(); @@ -80,11 +84,11 @@ impl<'db> InferenceContext<'_, 'db> { // FIXME: Infer the upvars later. let parts = CoroutineArgsParts { parent_args, - kind_ty: Ty::new_unit(interner), + kind_ty: self.types.unit, resume_ty, yield_ty, return_ty: body_ret_ty, - tupled_upvars_ty: Ty::new_unit(interner), + tupled_upvars_ty, }; let coroutine_id = @@ -97,9 +101,7 @@ impl<'db> InferenceContext<'_, 'db> { (None, coroutine_ty, Some((resume_ty, yield_ty))) } - // FIXME(next-solver): `ClosureKind::Async` should really be a separate arm that creates a `CoroutineClosure`. - // But for now we treat it as a closure. - ClosureKind::Closure | ClosureKind::Async => { + ClosureKind::Closure => { let closure_id = self.db.intern_closure(InternedClosure(self.owner, tgt_expr)); match expected_kind { Some(kind) => { @@ -117,7 +119,7 @@ impl<'db> InferenceContext<'_, 'db> { } None => {} }; - // FIXME: Infer the kind and the upvars later when needed. + // FIXME: Infer the kind later if needed. let parts = ClosureArgsParts { parent_args, closure_kind_ty: Ty::from_closure_kind( @@ -125,7 +127,7 @@ impl<'db> InferenceContext<'_, 'db> { expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), ), closure_sig_as_fn_ptr_ty: sig_ty, - tupled_upvars_ty: Ty::new_unit(interner), + tupled_upvars_ty, }; let closure_ty = Ty::new_closure( interner, @@ -136,6 +138,61 @@ impl<'db> InferenceContext<'_, 'db> { self.add_current_closure_dependency(closure_id); (Some(closure_id), closure_ty, None) } + ClosureKind::Async => { + // async closures always return the type ascribed after the `->` (if present), + // and yield `()`. + let bound_return_ty = bound_sig.skip_binder().output(); + let bound_yield_ty = self.types.unit; + // rustc uses a special lang item type for the resume ty. I don't believe this can cause us problems. + let resume_ty = self.types.unit; + + // FIXME: Infer the kind later if needed. + let closure_kind_ty = Ty::from_closure_kind( + interner, + expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), + ); + + // FIXME: Infer captures later. + // `for<'env> fn() -> ()`, for no captures. + let coroutine_captures_by_ref_ty = Ty::new_fn_ptr( + interner, + Binder::bind_with_vars( + interner.mk_fn_sig([], self.types.unit, false, Safety::Safe, FnAbi::Rust), + BoundVarKinds::new_from_iter( + interner, + [BoundVarKind::Region(BoundRegionKind::ClosureEnv)], + ), + ), + ); + let closure_args = CoroutineClosureArgs::new( + interner, + CoroutineClosureArgsParts { + parent_args, + closure_kind_ty, + signature_parts_ty: Ty::new_fn_ptr( + interner, + bound_sig.map_bound(|sig| { + interner.mk_fn_sig( + [ + resume_ty, + Ty::new_tup_from_iter(interner, sig.inputs().iter()), + ], + Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]), + sig.c_variadic, + sig.safety, + sig.abi, + ) + }), + ), + tupled_upvars_ty, + coroutine_captures_by_ref_ty, + }, + ); + + let coroutine_id = + self.db.intern_coroutine(InternedCoroutine(self.owner, tgt_expr)).into(); + (None, Ty::new_coroutine_closure(interner, coroutine_id, closure_args.args), None) + } }; // Now go through the argument patterns @@ -307,7 +364,7 @@ impl<'db> InferenceContext<'_, 'db> { .table .infer_ctxt .at(&ObligationCause::new(), self.table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, inferred_fnptr_sig, generalized_fnptr_sig) + .eq(inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); let resolved_sig = @@ -692,18 +749,16 @@ impl<'db> InferenceContext<'_, 'db> { let InferOk { value: (), obligations } = table .infer_ctxt .at(&cause, table.trait_env.env) - .eq(DefineOpaqueTypes::Yes, expected_ty, supplied_ty)?; + .eq(expected_ty, supplied_ty)?; all_obligations.extend(obligations); } let supplied_output_ty = supplied_sig.output(); let cause = ObligationCause::new(); - let InferOk { value: (), obligations } = - table.infer_ctxt.at(&cause, table.trait_env.env).eq( - DefineOpaqueTypes::Yes, - expected_sigs.liberated_sig.output(), - supplied_output_ty, - )?; + let InferOk { value: (), obligations } = table + .infer_ctxt + .at(&cause, table.trait_env.env) + .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; all_obligations.extend(obligations); let inputs = supplied_sig |