Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/hir-ty/src/infer/coerce.rs')
-rw-r--r--crates/hir-ty/src/infer/coerce.rs77
1 files changed, 38 insertions, 39 deletions
diff --git a/crates/hir-ty/src/infer/coerce.rs b/crates/hir-ty/src/infer/coerce.rs
index bb9cb1c1ca..e79868f4ae 100644
--- a/crates/hir-ty/src/infer/coerce.rs
+++ b/crates/hir-ty/src/infer/coerce.rs
@@ -46,7 +46,9 @@ use rustc_type_ir::{
BoundVar, DebruijnIndex, TyVid, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
error::TypeError,
- inherent::{Const as _, GenericArg as _, IntoKind, Safety, SliceLike, Ty as _},
+ inherent::{
+ Const as _, GenericArg as _, GenericArgs as _, IntoKind, Safety as _, SliceLike, Ty as _,
+ },
};
use smallvec::{SmallVec, smallvec};
use tracing::{debug, instrument};
@@ -54,7 +56,7 @@ use tracing::{debug, instrument};
use crate::{
Adjust, Adjustment, AutoBorrow, ParamEnvAndCrate, PointerCast, TargetFeatures,
autoderef::Autoderef,
- db::{HirDatabase, InternedClosureId},
+ db::{HirDatabase, InternedClosure, InternedClosureId},
infer::{
AllowTwoPhase, AutoBorrowMutability, InferenceContext, TypeMismatch, expr::ExprIsRead,
},
@@ -63,6 +65,7 @@ use crate::{
Canonical, ClauseKind, CoercePredicate, Const, ConstKind, DbInterner, ErrorGuaranteed,
GenericArgs, ParamEnv, PolyFnSig, PredicateKind, Region, RegionKind, TraitRef, Ty, TyKind,
TypingMode,
+ abi::Safety,
infer::{
DbInternerInferExt, InferCtxt, InferOk, InferResult,
relate::RelateResult,
@@ -71,6 +74,7 @@ use crate::{
},
obligation_ctxt::ObligationCtxt,
},
+ upvars::upvars_mentioned,
utils::TargetFeatureIsSafeInTarget,
};
@@ -893,7 +897,7 @@ where
fn coerce_closure_to_fn(
&mut self,
a: Ty<'db>,
- _closure_def_id_a: InternedClosureId,
+ closure_def_id_a: InternedClosureId,
args_a: GenericArgs<'db>,
b: Ty<'db>,
) -> CoerceResult<'db> {
@@ -901,19 +905,7 @@ where
debug_assert!(self.infcx().shallow_resolve(b) == b);
match b.kind() {
- // FIXME: We need to have an `upvars_mentioned()` query:
- // At this point we haven't done capture analysis, which means
- // that the ClosureArgs just contains an inference variable instead
- // of tuple of captured types.
- //
- // All we care here is if any variable is being captured and not the exact paths,
- // so we check `upvars_mentioned` for root variables being captured.
- TyKind::FnPtr(_, hdr) =>
- // if self
- // .db
- // .upvars_mentioned(closure_def_id_a.expect_local())
- // .is_none_or(|u| u.is_empty()) =>
- {
+ TyKind::FnPtr(_, hdr) if !is_capturing_closure(self.db(), closure_def_id_a) => {
// We coerce the closure, which has fn type
// `extern "rust-call" fn((arg0,arg1,...)) -> _`
// to
@@ -921,10 +913,8 @@ where
// or
// `unsafe fn(arg0,arg1,...) -> _`
let safety = hdr.safety;
- let closure_sig = args_a.closure_sig_untupled().map_bound(|mut sig| {
- sig.safety = hdr.safety;
- sig
- });
+ let closure_sig =
+ self.interner().signature_unclosure(args_a.as_closure().sig(), safety);
let pointer_ty = Ty::new_fn_ptr(self.interner(), closure_sig);
debug!("coerce_closure_to_fn(a={:?}, b={:?}, pty={:?})", a, b, pointer_ty);
self.unify_and(
@@ -1088,14 +1078,12 @@ impl<'db> InferenceContext<'_, 'db> {
// Special-case that coercion alone cannot handle:
// Function items or non-capturing closures of differing IDs or GenericArgs.
let (a_sig, b_sig) = {
- let is_capturing_closure = |_ty: Ty<'db>| {
- // FIXME:
- // if let TyKind::Closure(closure_def_id, _args) = ty.kind() {
- // self.db.upvars_mentioned(closure_def_id.expect_local()).is_some()
- // } else {
- // false
- // }
- false
+ let is_capturing_closure = |ty: Ty<'db>| {
+ if let TyKind::Closure(closure_def_id, _args) = ty.kind() {
+ is_capturing_closure(self.db, closure_def_id.0)
+ } else {
+ false
+ }
};
if is_capturing_closure(prev_ty) || is_capturing_closure(new_ty) {
(None, None)
@@ -1125,23 +1113,28 @@ impl<'db> InferenceContext<'_, 'db> {
}
(TyKind::Closure(_, args), TyKind::FnDef(..)) => {
let b_sig = new_ty.fn_sig(self.table.interner());
- let a_sig = args.closure_sig_untupled().map_bound(|mut sig| {
- sig.safety = b_sig.safety();
- sig
- });
+ let a_sig = self
+ .interner()
+ .signature_unclosure(args.as_closure().sig(), b_sig.safety());
(Some(a_sig), Some(b_sig))
}
(TyKind::FnDef(..), TyKind::Closure(_, args)) => {
let a_sig = prev_ty.fn_sig(self.table.interner());
- let b_sig = args.closure_sig_untupled().map_bound(|mut sig| {
- sig.safety = a_sig.safety();
- sig
- });
+ let b_sig = self
+ .interner()
+ .signature_unclosure(args.as_closure().sig(), a_sig.safety());
(Some(a_sig), Some(b_sig))
}
- (TyKind::Closure(_, args_a), TyKind::Closure(_, args_b)) => {
- (Some(args_a.closure_sig_untupled()), Some(args_b.closure_sig_untupled()))
- }
+ (TyKind::Closure(_, args_a), TyKind::Closure(_, args_b)) => (
+ Some(
+ self.interner()
+ .signature_unclosure(args_a.as_closure().sig(), Safety::Safe),
+ ),
+ Some(
+ self.interner()
+ .signature_unclosure(args_b.as_closure().sig(), Safety::Safe),
+ ),
+ ),
_ => (None, None),
}
}
@@ -1722,3 +1715,9 @@ fn coerce<'db>(
.collect();
Ok((adjustments, ty))
}
+
+fn is_capturing_closure(db: &dyn HirDatabase, closure: InternedClosureId) -> bool {
+ let InternedClosure(owner, expr) = closure.loc(db);
+ upvars_mentioned(db, owner)
+ .is_some_and(|upvars| upvars.get(&expr).is_some_and(|upvars| !upvars.is_empty()))
+}