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.rs | 77 |
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())) +} |