mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-12-27 16:07:46 +00:00
Store closures with "tupled" inputs
And remove it when needed, the opposite of what was previously, where we stored without a tuple and tupled for the solver (because it requires that). Because this is what rustc does, and generally, the closer we follow rustc, the easier our lives become. The weird name `signature_unclosure()` also comes from rustc.
This commit is contained in:
parent
9581ba4daf
commit
7e515fccf8
@ -1383,37 +1383,30 @@ impl<'db> HirDisplay<'db> for Ty<'db> {
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
let sig = substs
|
||||
.split_closure_args_untupled()
|
||||
.closure_sig_as_fn_ptr_ty
|
||||
.callable_sig(interner);
|
||||
if let Some(sig) = sig {
|
||||
let sig = sig.skip_binder();
|
||||
let InternedClosure(def, _) = db.lookup_intern_closure(id);
|
||||
let infer = InferenceResult::for_body(db, def);
|
||||
let (_, kind) = infer.closure_info(id);
|
||||
match f.closure_style {
|
||||
ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
|
||||
ClosureStyle::RANotation => write!(f, "|")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if sig.inputs().is_empty() {
|
||||
} else if f.should_truncate() {
|
||||
write!(f, "{TYPE_HINT_TRUNCATION}")?;
|
||||
} else {
|
||||
f.write_joined(sig.inputs(), ", ")?;
|
||||
};
|
||||
match f.closure_style {
|
||||
ClosureStyle::ImplFn => write!(f, ")")?,
|
||||
ClosureStyle::RANotation => write!(f, "|")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
|
||||
write!(f, " -> ")?;
|
||||
sig.output().hir_fmt(f)?;
|
||||
}
|
||||
let sig = interner.signature_unclosure(substs.as_closure().sig(), Safety::Safe);
|
||||
let sig = sig.skip_binder();
|
||||
let InternedClosure(def, _) = db.lookup_intern_closure(id);
|
||||
let infer = InferenceResult::for_body(db, def);
|
||||
let (_, kind) = infer.closure_info(id);
|
||||
match f.closure_style {
|
||||
ClosureStyle::ImplFn => write!(f, "impl {kind:?}(")?,
|
||||
ClosureStyle::RANotation => write!(f, "|")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if sig.inputs().is_empty() {
|
||||
} else if f.should_truncate() {
|
||||
write!(f, "{TYPE_HINT_TRUNCATION}")?;
|
||||
} else {
|
||||
write!(f, "{{closure}}")?;
|
||||
f.write_joined(sig.inputs(), ", ")?;
|
||||
};
|
||||
match f.closure_style {
|
||||
ClosureStyle::ImplFn => write!(f, ")")?,
|
||||
ClosureStyle::RANotation => write!(f, "|")?,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
if f.closure_style == ClosureStyle::RANotation || !sig.output().is_unit() {
|
||||
write!(f, " -> ")?;
|
||||
sig.output().hir_fmt(f)?;
|
||||
}
|
||||
}
|
||||
TyKind::CoroutineClosure(id, args) => {
|
||||
|
||||
@ -68,7 +68,6 @@ 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.
|
||||
@ -117,6 +116,16 @@ 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.as_slice(),
|
||||
|
||||
@ -15,7 +15,7 @@ use hir_def::{
|
||||
};
|
||||
use rustc_ast_ir::Mutability;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_type_ir::inherent::{IntoKind, Ty as _};
|
||||
use rustc_type_ir::inherent::{GenericArgs as _, IntoKind, Ty as _};
|
||||
use smallvec::{SmallVec, smallvec};
|
||||
use stdx::{format_to, never};
|
||||
use syntax::utils::is_raw_identifier;
|
||||
@ -103,7 +103,7 @@ impl CapturedItem {
|
||||
|
||||
pub fn ty<'db>(&self, db: &'db dyn HirDatabase, subst: GenericArgs<'db>) -> Ty<'db> {
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
self.ty.get().instantiate(interner, subst.split_closure_args_untupled().parent_args)
|
||||
self.ty.get().instantiate(interner, subst.as_closure().parent_args())
|
||||
}
|
||||
|
||||
pub fn kind(&self) -> CaptureKind {
|
||||
|
||||
@ -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};
|
||||
@ -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,
|
||||
@ -921,10 +924,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(
|
||||
@ -1125,23 +1126,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),
|
||||
}
|
||||
}
|
||||
|
||||
@ -14,7 +14,10 @@ use rustc_abi::{
|
||||
TargetDataLayout, WrappingRange,
|
||||
};
|
||||
use rustc_index::IndexVec;
|
||||
use rustc_type_ir::{FloatTy, IntTy, UintTy, inherent::IntoKind};
|
||||
use rustc_type_ir::{
|
||||
FloatTy, IntTy, UintTy,
|
||||
inherent::{GenericArgs as _, IntoKind},
|
||||
};
|
||||
use triomphe::Arc;
|
||||
|
||||
use crate::{
|
||||
@ -335,10 +338,7 @@ pub fn layout_of_ty_query(
|
||||
let fields = captures
|
||||
.iter()
|
||||
.map(|it| {
|
||||
let ty = it
|
||||
.ty
|
||||
.get()
|
||||
.instantiate(interner, args.split_closure_args_untupled().parent_args);
|
||||
let ty = it.ty.get().instantiate(interner, args.as_closure().parent_args());
|
||||
db.layout_of_ty(ty.store(), trait_env.clone())
|
||||
})
|
||||
.collect::<Result<Vec<_>, _>>()?;
|
||||
|
||||
@ -8,6 +8,7 @@ use std::iter;
|
||||
use hir_def::{DefWithBodyId, HasModule};
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_type_ir::inherent::GenericArgs as _;
|
||||
use stdx::never;
|
||||
use triomphe::Arc;
|
||||
|
||||
@ -123,7 +124,7 @@ fn make_fetch_closure_field<'db>(
|
||||
let InternedClosure(def, _) = db.lookup_intern_closure(c);
|
||||
let infer = InferenceResult::for_body(db, def);
|
||||
let (captures, _) = infer.closure_info(c);
|
||||
let parent_subst = subst.split_closure_args_untupled().parent_args;
|
||||
let parent_subst = subst.as_closure().parent_args();
|
||||
let interner = DbInterner::new_no_crate(db);
|
||||
captures.get(f).expect("broken closure field").ty.get().instantiate(interner, parent_subst)
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ use rustc_ast_ir::Mutability;
|
||||
use rustc_hash::{FxHashMap, FxHashSet};
|
||||
use rustc_type_ir::{
|
||||
AliasTyKind,
|
||||
inherent::{AdtDef, IntoKind, Region as _, SliceLike, Ty as _},
|
||||
inherent::{AdtDef, GenericArgs as _, IntoKind, Region as _, SliceLike, Ty as _},
|
||||
};
|
||||
use span::FileId;
|
||||
use stdx::never;
|
||||
@ -731,7 +731,7 @@ impl<'db> Evaluator<'db> {
|
||||
let InternedClosure(def, _) = self.db.lookup_intern_closure(c);
|
||||
let infer = InferenceResult::for_body(self.db, def);
|
||||
let (captures, _) = infer.closure_info(c);
|
||||
let parent_subst = subst.split_closure_args_untupled().parent_args;
|
||||
let parent_subst = subst.as_closure().parent_args();
|
||||
captures
|
||||
.get(f)
|
||||
.expect("broken closure field")
|
||||
@ -2771,7 +2771,7 @@ impl<'db> Evaluator<'db> {
|
||||
TyKind::Closure(closure, subst) => self.exec_closure(
|
||||
closure.0,
|
||||
func_data,
|
||||
GenericArgs::new_from_slice(subst.split_closure_args_untupled().parent_args),
|
||||
GenericArgs::new_from_slice(subst.as_closure().parent_args()),
|
||||
destination,
|
||||
&args[1..],
|
||||
locals,
|
||||
|
||||
@ -19,7 +19,7 @@ use hir_expand::name::Name;
|
||||
use la_arena::ArenaMap;
|
||||
use rustc_apfloat::Float;
|
||||
use rustc_hash::FxHashMap;
|
||||
use rustc_type_ir::inherent::{Const as _, IntoKind, Ty as _};
|
||||
use rustc_type_ir::inherent::{Const as _, GenericArgs as _, IntoKind, Ty as _};
|
||||
use span::{Edition, FileId};
|
||||
use syntax::TextRange;
|
||||
use triomphe::Arc;
|
||||
@ -44,6 +44,7 @@ use crate::{
|
||||
next_solver::{
|
||||
Const, DbInterner, ParamConst, ParamEnv, Region, StoredGenericArgs, StoredTy, TyKind,
|
||||
TypingMode, UnevaluatedConst,
|
||||
abi::Safety,
|
||||
infer::{DbInternerInferExt, InferCtxt},
|
||||
},
|
||||
traits::FnTrait,
|
||||
@ -2138,11 +2139,7 @@ pub fn mir_body_for_closure_query<'db>(
|
||||
.store(),
|
||||
});
|
||||
ctx.result.param_locals.push(closure_local);
|
||||
let Some(sig) =
|
||||
substs.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.callable_sig(ctx.interner())
|
||||
else {
|
||||
implementation_error!("closure has not callable sig");
|
||||
};
|
||||
let sig = ctx.interner().signature_unclosure(substs.as_closure().sig(), Safety::Safe);
|
||||
let resolver_guard = ctx.resolver.update_to_inner_scope(db, owner, expr);
|
||||
let current = ctx.lower_params_and_bindings(
|
||||
args.iter().zip(sig.skip_binder().inputs().iter()).map(|(it, y)| (*it, *y)),
|
||||
|
||||
@ -11,9 +11,9 @@ use std::{hint::unreachable_unchecked, marker::PhantomData, ptr::NonNull};
|
||||
use hir_def::{GenericDefId, GenericParamId};
|
||||
use intern::InternedRef;
|
||||
use rustc_type_ir::{
|
||||
ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder, FnSigTys,
|
||||
GenericTypeVisitable, Interner, TyKind, TyVid, TypeFoldable, TypeFolder, TypeVisitable,
|
||||
TypeVisitor, Variance,
|
||||
ClosureArgs, ConstVid, CoroutineArgs, CoroutineClosureArgs, FallibleTypeFolder,
|
||||
GenericTypeVisitable, Interner, TyVid, TypeFoldable, TypeFolder, TypeVisitable, TypeVisitor,
|
||||
Variance,
|
||||
inherent::{GenericArg as _, GenericsOf, IntoKind, SliceLike, Term as _, Ty as _},
|
||||
relate::{Relate, VarianceDiagInfo},
|
||||
walk::TypeWalker,
|
||||
@ -21,12 +21,11 @@ use rustc_type_ir::{
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::next_solver::{
|
||||
ConstInterned, PolyFnSig, RegionInterned, TyInterned, impl_foldable_for_interned_slice,
|
||||
interned_slice,
|
||||
ConstInterned, RegionInterned, TyInterned, impl_foldable_for_interned_slice, interned_slice,
|
||||
};
|
||||
|
||||
use super::{
|
||||
Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty, Tys,
|
||||
Const, DbInterner, EarlyParamRegion, ErrorGuaranteed, ParamConst, Region, SolverDefId, Ty,
|
||||
generics::Generics,
|
||||
};
|
||||
|
||||
@ -566,33 +565,6 @@ impl<'db> GenericArgs<'db> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn closure_sig_untupled(self) -> PolyFnSig<'db> {
|
||||
let TyKind::FnPtr(inputs_and_output, hdr) =
|
||||
self.split_closure_args_untupled().closure_sig_as_fn_ptr_ty.kind()
|
||||
else {
|
||||
unreachable!("not a function pointer")
|
||||
};
|
||||
inputs_and_output.with(hdr)
|
||||
}
|
||||
|
||||
/// A "sensible" `.split_closure_args()`, where the arguments are not in a tuple.
|
||||
pub fn split_closure_args_untupled(self) -> rustc_type_ir::ClosureArgsParts<DbInterner<'db>> {
|
||||
// FIXME: should use `ClosureSubst` when possible
|
||||
match self.as_slice() {
|
||||
[parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
|
||||
rustc_type_ir::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
|
||||
closure_kind_ty: closure_kind_ty.expect_ty(),
|
||||
tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
unreachable!("unexpected closure sig");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn types(self) -> impl Iterator<Item = Ty<'db>> {
|
||||
self.iter().filter_map(|it| it.as_type())
|
||||
}
|
||||
@ -688,27 +660,9 @@ impl<'db> rustc_type_ir::inherent::GenericArgs<DbInterner<'db>> for GenericArgs<
|
||||
// FIXME: should use `ClosureSubst` when possible
|
||||
match self.as_slice() {
|
||||
[parent_args @ .., closure_kind_ty, sig_ty, tupled_upvars_ty] => {
|
||||
let interner = DbInterner::conjure();
|
||||
// This is stupid, but the next solver expects the first input to actually be a tuple
|
||||
let sig_ty = match sig_ty.expect_ty().kind() {
|
||||
TyKind::FnPtr(sig_tys, header) => Ty::new(
|
||||
interner,
|
||||
TyKind::FnPtr(
|
||||
sig_tys.map_bound(|s| {
|
||||
let inputs = Ty::new_tup(interner, s.inputs());
|
||||
let output = s.output();
|
||||
FnSigTys {
|
||||
inputs_and_output: Tys::new_from_slice(&[inputs, output]),
|
||||
}
|
||||
}),
|
||||
header,
|
||||
),
|
||||
),
|
||||
_ => unreachable!("sig_ty should be last"),
|
||||
};
|
||||
rustc_type_ir::ClosureArgsParts {
|
||||
parent_args,
|
||||
closure_sig_as_fn_ptr_ty: sig_ty,
|
||||
closure_sig_as_fn_ptr_ty: sig_ty.expect_ty(),
|
||||
closure_kind_ty: closure_kind_ty.expect_ty(),
|
||||
tupled_upvars_ty: tupled_upvars_ty.expect_ty(),
|
||||
}
|
||||
|
||||
@ -26,6 +26,7 @@ use rustc_type_ir::{
|
||||
};
|
||||
|
||||
use crate::{
|
||||
FnAbi,
|
||||
db::{HirDatabase, InternedCoroutine},
|
||||
lower::GenericPredicates,
|
||||
next_solver::{
|
||||
@ -495,10 +496,9 @@ impl<'db> Ty<'db> {
|
||||
Some(interner.fn_sig(callable).instantiate(interner, args))
|
||||
}
|
||||
TyKind::FnPtr(sig, hdr) => Some(sig.with(hdr)),
|
||||
TyKind::Closure(_, closure_args) => closure_args
|
||||
.split_closure_args_untupled()
|
||||
.closure_sig_as_fn_ptr_ty
|
||||
.callable_sig(interner),
|
||||
TyKind::Closure(_, closure_args) => {
|
||||
Some(interner.signature_unclosure(closure_args.as_closure().sig(), Safety::Safe))
|
||||
}
|
||||
TyKind::CoroutineClosure(coroutine_id, args) => {
|
||||
Some(args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
|
||||
let unit_ty = Ty::new_unit(interner);
|
||||
@ -1426,3 +1426,22 @@ impl<'db> PlaceholderLike<DbInterner<'db>> for PlaceholderTy {
|
||||
Placeholder { universe: ui, bound: BoundTy { var, kind: BoundTyKind::Anon } }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'db> DbInterner<'db> {
|
||||
/// Given a closure signature, returns an equivalent fn signature. Detuples
|
||||
/// and so forth -- so e.g., if we have a sig with `Fn<(u32, i32)>` then
|
||||
/// you would get a `fn(u32, i32)`.
|
||||
/// `unsafety` determines the unsafety of the fn signature. If you pass
|
||||
/// `Safety::Unsafe` in the previous example, then you would get
|
||||
/// an `unsafe fn (u32, i32)`.
|
||||
/// It cannot convert a closure that requires unsafe.
|
||||
pub fn signature_unclosure(self, sig: PolyFnSig<'db>, safety: Safety) -> PolyFnSig<'db> {
|
||||
sig.map_bound(|s| {
|
||||
let params = match s.inputs()[0].kind() {
|
||||
TyKind::Tuple(params) => params,
|
||||
_ => panic!(),
|
||||
};
|
||||
self.mk_fn_sig(params, s.output(), s.c_variadic, safety, FnAbi::Rust)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user