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 | 123 |
1 files changed, 68 insertions, 55 deletions
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs index 06f8307eb0..d1391ad24e 100644 --- a/crates/hir-ty/src/infer/closure.rs +++ b/crates/hir-ty/src/infer/closure.rs @@ -7,14 +7,13 @@ use std::{iter, mem, ops::ControlFlow}; use hir_def::{ TraitId, hir::{ClosureKind, ExprId, PatId}, - lang_item::LangItem, type_ref::TypeRefId, }; use rustc_type_ir::{ ClosureArgs, ClosureArgsParts, CoroutineArgs, CoroutineArgsParts, CoroutineClosureArgs, CoroutineClosureArgsParts, Interner, TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor, - inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, SliceLike, Ty as _}, + inherent::{BoundExistentialPredicates, GenericArgs as _, IntoKind, Ty as _}, }; use tracing::debug; @@ -23,15 +22,13 @@ use crate::{ db::{InternedClosure, InternedCoroutine}, infer::{BreakableKind, Diverges, coerce::CoerceMany}, next_solver::{ - AliasTy, Binder, BoundRegionKind, BoundVarKind, BoundVarKinds, ClauseKind, DbInterner, - ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, PolyProjectionPredicate, Predicate, - PredicateKind, SolverDefId, Ty, TyKind, + AliasTy, Binder, ClauseKind, DbInterner, ErrorGuaranteed, FnSig, GenericArgs, PolyFnSig, + PolyProjectionPredicate, Predicate, PredicateKind, SolverDefId, Ty, TyKind, abi::Safety, infer::{ BoundRegionConversionTime, InferOk, InferResult, traits::{ObligationCause, PredicateObligations}, }, - util::explicit_item_bounds, }, traits::FnTrait, }; @@ -71,20 +68,20 @@ impl<'db> InferenceContext<'_, 'db> { let ClosureSignatures { bound_sig, liberated_sig } = self.sig_of_closure(arg_types, ret_type, expected_sig); let body_ret_ty = bound_sig.output().skip_binder(); - 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 tupled_upvars_ty = self.types.types.unit; let (id, ty, resume_yield_tys) = match closure_kind { ClosureKind::Coroutine(_) => { let yield_ty = self.table.next_ty_var(); - let resume_ty = liberated_sig.inputs().get(0).unwrap_or(self.types.unit); + let resume_ty = + liberated_sig.inputs().first().copied().unwrap_or(self.types.types.unit); // FIXME: Infer the upvars later. let parts = CoroutineArgsParts { - parent_args, - kind_ty: self.types.unit, + parent_args: parent_args.as_slice(), + kind_ty: self.types.types.unit, resume_ty, yield_ty, return_ty: body_ret_ty, @@ -119,9 +116,19 @@ impl<'db> InferenceContext<'_, 'db> { } None => {} }; + let sig = bound_sig.map_bound(|sig| { + interner.mk_fn_sig( + [Ty::new_tup(interner, sig.inputs())], + sig.output(), + sig.c_variadic, + sig.safety, + sig.abi, + ) + }); + let sig_ty = Ty::new_fn_ptr(interner, sig); // FIXME: Infer the kind later if needed. let parts = ClosureArgsParts { - parent_args, + parent_args: parent_args.as_slice(), closure_kind_ty: Ty::from_closure_kind( interner, expected_kind.unwrap_or(rustc_type_ir::ClosureKind::Fn), @@ -142,9 +149,9 @@ impl<'db> InferenceContext<'_, 'db> { // 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; + let bound_yield_ty = self.types.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; + let resume_ty = self.types.types.unit; // FIXME: Infer the kind later if needed. let closure_kind_ty = Ty::from_closure_kind( @@ -157,26 +164,26 @@ impl<'db> InferenceContext<'_, 'db> { 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)], + interner.mk_fn_sig( + [], + self.types.types.unit, + false, + Safety::Safe, + FnAbi::Rust, ), + self.types.coroutine_captures_by_ref_bound_var_kinds, ), ); let closure_args = CoroutineClosureArgs::new( interner, CoroutineClosureArgsParts { - parent_args, + parent_args: parent_args.as_slice(), 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()), - ], + [resume_ty, Ty::new_tup(interner, sig.inputs())], Ty::new_tup(interner, &[bound_yield_ty, bound_return_ty]), sig.c_variadic, sig.safety, @@ -197,7 +204,7 @@ impl<'db> InferenceContext<'_, 'db> { // Now go through the argument patterns for (arg_pat, arg_ty) in args.iter().zip(bound_sig.skip_binder().inputs()) { - self.infer_top_pat(*arg_pat, arg_ty, None); + self.infer_top_pat(*arg_pat, *arg_ty, None); } // FIXME: lift these out into a struct @@ -221,11 +228,12 @@ impl<'db> InferenceContext<'_, 'db> { } fn fn_trait_kind_from_def_id(&self, trait_id: TraitId) -> Option<rustc_type_ir::ClosureKind> { - let lang_item = self.db.lang_attr(trait_id.into())?; - match lang_item { - LangItem::Fn => Some(rustc_type_ir::ClosureKind::Fn), - LangItem::FnMut => Some(rustc_type_ir::ClosureKind::FnMut), - LangItem::FnOnce => Some(rustc_type_ir::ClosureKind::FnOnce), + match trait_id { + _ if self.lang_items.Fn == Some(trait_id) => Some(rustc_type_ir::ClosureKind::Fn), + _ if self.lang_items.FnMut == Some(trait_id) => Some(rustc_type_ir::ClosureKind::FnMut), + _ if self.lang_items.FnOnce == Some(trait_id) => { + Some(rustc_type_ir::ClosureKind::FnOnce) + } _ => None, } } @@ -234,11 +242,14 @@ impl<'db> InferenceContext<'_, 'db> { &self, trait_id: TraitId, ) -> Option<rustc_type_ir::ClosureKind> { - let lang_item = self.db.lang_attr(trait_id.into())?; - match lang_item { - LangItem::AsyncFn => Some(rustc_type_ir::ClosureKind::Fn), - LangItem::AsyncFnMut => Some(rustc_type_ir::ClosureKind::FnMut), - LangItem::AsyncFnOnce => Some(rustc_type_ir::ClosureKind::FnOnce), + match trait_id { + _ if self.lang_items.AsyncFn == Some(trait_id) => Some(rustc_type_ir::ClosureKind::Fn), + _ if self.lang_items.AsyncFnMut == Some(trait_id) => { + Some(rustc_type_ir::ClosureKind::FnMut) + } + _ if self.lang_items.AsyncFnOnce == Some(trait_id) => { + Some(rustc_type_ir::ClosureKind::FnOnce) + } _ => None, } } @@ -255,8 +266,10 @@ impl<'db> InferenceContext<'_, 'db> { .deduce_closure_signature_from_predicates( expected_ty, closure_kind, - explicit_item_bounds(self.interner(), def_id) - .iter_instantiated(self.interner(), args) + def_id + .expect_opaque_ty() + .predicates(self.db) + .iter_instantiated_copied(self.interner(), args.as_slice()) .map(|clause| clause.as_predicate()), ), TyKind::Dynamic(object_type, ..) => { @@ -363,7 +376,7 @@ impl<'db> InferenceContext<'_, 'db> { _ = self .table .infer_ctxt - .at(&ObligationCause::new(), self.table.trait_env.env) + .at(&ObligationCause::new(), self.table.param_env) .eq(inferred_fnptr_sig, generalized_fnptr_sig) .map(|infer_ok| self.table.register_infer_ok(infer_ok)); @@ -432,21 +445,20 @@ impl<'db> InferenceContext<'_, 'db> { projection: PolyProjectionPredicate<'db>, ) -> Option<PolyFnSig<'db>> { let SolverDefId::TypeAliasId(def_id) = projection.item_def_id() else { unreachable!() }; - let lang_item = self.db.lang_attr(def_id.into()); // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits, // for closures and async closures, respectively. match closure_kind { - ClosureKind::Closure if lang_item == Some(LangItem::FnOnceOutput) => { + ClosureKind::Closure if Some(def_id) == self.lang_items.FnOnceOutput => { self.extract_sig_from_projection(projection) } - ClosureKind::Async if lang_item == Some(LangItem::AsyncFnOnceOutput) => { + ClosureKind::Async if Some(def_id) == self.lang_items.AsyncFnOnceOutput => { self.extract_sig_from_projection(projection) } // It's possible we've passed the closure to a (somewhat out-of-fashion) // `F: FnOnce() -> Fut, Fut: Future<Output = T>` style bound. Let's still // guide inference here, since it's beneficial for the user. - ClosureKind::Async if lang_item == Some(LangItem::FnOnceOutput) => { + ClosureKind::Async if Some(def_id) == self.lang_items.FnOnceOutput => { self.extract_sig_from_projection_and_future_bound(projection) } _ => None, @@ -537,7 +549,7 @@ impl<'db> InferenceContext<'_, 'db> { && let ret_projection = bound.predicate.kind().rebind(ret_projection) && let Some(ret_projection) = ret_projection.no_bound_vars() && let SolverDefId::TypeAliasId(assoc_type) = ret_projection.def_id() - && self.db.lang_attr(assoc_type.into()) == Some(LangItem::FutureOutput) + && Some(assoc_type) == self.lang_items.FutureOutput { return_ty = Some(ret_projection.term.expect_type()); break; @@ -665,7 +677,7 @@ impl<'db> InferenceContext<'_, 'db> { assert!(!expected_sig.skip_binder().has_vars_bound_above(rustc_type_ir::INNERMOST)); let bound_sig = expected_sig.map_bound(|sig| { self.interner().mk_fn_sig( - sig.inputs(), + sig.inputs().iter().copied(), sig.output(), sig.c_variadic, Safety::Safe, @@ -741,29 +753,30 @@ impl<'db> InferenceContext<'_, 'db> { // The liberated version of this signature should be a subtype // of the liberated form of the expectation. - for (supplied_ty, expected_ty) in - iter::zip(supplied_sig.inputs(), expected_sigs.liberated_sig.inputs()) - { + for (supplied_ty, expected_ty) in iter::zip( + supplied_sig.inputs().iter().copied(), + expected_sigs.liberated_sig.inputs().iter().copied(), + ) { // Check that E' = S'. let cause = ObligationCause::new(); - let InferOk { value: (), obligations } = table - .infer_ctxt - .at(&cause, table.trait_env.env) - .eq(expected_ty, supplied_ty)?; + let InferOk { value: (), obligations } = + table.infer_ctxt.at(&cause, table.param_env).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(expected_sigs.liberated_sig.output(), supplied_output_ty)?; + let InferOk { value: (), obligations } = + table + .infer_ctxt + .at(&cause, table.param_env) + .eq(expected_sigs.liberated_sig.output(), supplied_output_ty)?; all_obligations.extend(obligations); let inputs = supplied_sig .inputs() - .into_iter() + .iter() + .copied() .map(|ty| table.infer_ctxt.resolve_vars_if_possible(ty)); expected_sigs.liberated_sig = table.interner().mk_fn_sig( |