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.rs123
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(