Lift FnPointer into a struct

This commit is contained in:
Lukas Wirth 2021-02-28 22:12:07 +01:00
parent 23d7dbfa5e
commit 407196b8c0
9 changed files with 98 additions and 86 deletions

View File

@ -31,9 +31,9 @@
display::{write_bounds_like_dyn_trait_with_prefix, HirDisplayError, HirFormatter},
method_resolution,
traits::{FnTrait, Solution, SolutionVariables},
BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate, InEnvironment,
Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment, Ty, TyDefId,
TyKind,
BoundVar, CallableDefId, CallableSig, Canonical, DebruijnIndex, GenericPredicate,
InEnvironment, Obligation, ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment,
Ty, TyDefId, TyKind,
};
use rustc_hash::FxHashSet;
use stdx::{format_to, impl_from};
@ -1692,7 +1692,7 @@ pub fn is_closure(&self) -> bool {
}
pub fn is_fn(&self) -> bool {
matches!(&self.ty.value, Ty::FnDef(..) | Ty::FnPtr { .. })
matches!(&self.ty.value, Ty::FnDef(..) | Ty::Function { .. })
}
pub fn is_packed(&self, db: &dyn HirDatabase) -> bool {
@ -1974,7 +1974,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
#[derive(Debug)]
pub struct Callable {
ty: Type,
sig: FnSig,
sig: CallableSig,
def: Option<CallableDefId>,
pub(crate) is_bound_method: bool,
}

View File

@ -3,8 +3,8 @@
use std::{borrow::Cow, fmt};
use crate::{
db::HirDatabase, primitive, utils::generics, CallableDefId, FnSig, GenericPredicate, Lifetime,
Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs, TraitRef, Ty,
db::HirDatabase, primitive, utils::generics, CallableDefId, CallableSig, GenericPredicate,
Lifetime, Obligation, OpaqueTy, OpaqueTyId, ProjectionTy, Scalar, Substs, TraitRef, Ty,
};
use arrayvec::ArrayVec;
use hir_def::{
@ -341,8 +341,8 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
write!(f, ")")?;
}
}
Ty::FnPtr { is_varargs, substs, .. } => {
let sig = FnSig::from_fn_ptr_substs(&substs, *is_varargs);
Ty::Function(fn_ptr) => {
let sig = CallableSig::from_fn_ptr(fn_ptr);
sig.hir_fmt(f)?;
}
Ty::FnDef(def, parameters) => {
@ -494,7 +494,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
}
}
}
Ty::Closure { substs, .. } => {
Ty::Closure(.., substs) => {
let sig = substs[0].callable_sig(f.db);
if let Some(sig) = sig {
if sig.params().is_empty() {
@ -571,7 +571,7 @@ fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
}
}
impl HirDisplay for FnSig {
impl HirDisplay for CallableSig {
fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
write!(f, "fn(")?;
f.write_joined(self.params(), ", ")?;

View File

@ -89,14 +89,14 @@ fn coerce_inner(&mut self, mut from_ty: Ty, to_ty: &Ty) -> bool {
| (Ty::Ref(Mutability::Shared, ..), Ty::Ref(Mutability::Mut, ..)) => return false,
// `{function_type}` -> `fn()`
(Ty::FnDef(..), Ty::FnPtr { .. }) => match from_ty.callable_sig(self.db) {
(Ty::FnDef(..), Ty::Function { .. }) => match from_ty.callable_sig(self.db) {
None => return false,
Some(sig) => {
from_ty = Ty::fn_ptr(sig);
}
},
(Ty::Closure { substs, .. }, Ty::FnPtr { .. }) => {
(Ty::Closure(.., substs), Ty::Function { .. }) => {
from_ty = substs[0].clone();
}

View File

@ -18,8 +18,8 @@
primitive::{self, UintTy},
traits::{FnTrait, InEnvironment},
utils::{generics, variant_data, Generics},
Binders, CallableDefId, InferTy, Mutability, Obligation, OpaqueTyId, Rawness, Scalar, Substs,
TraitRef, Ty,
Binders, CallableDefId, FnPointer, FnSig, InferTy, Mutability, Obligation, OpaqueTyId, Rawness,
Scalar, Substs, TraitRef, Ty,
};
use super::{
@ -247,13 +247,12 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
None => self.table.new_type_var(),
};
sig_tys.push(ret_ty.clone());
let sig_ty = Ty::FnPtr {
num_args: sig_tys.len() as u16 - 1,
is_varargs: false,
let sig_ty = Ty::Function(FnPointer {
num_args: sig_tys.len() - 1,
sig: FnSig { variadic: false },
substs: Substs(sig_tys.clone().into()),
};
let closure_ty =
Ty::Closure { def: self.owner, expr: tgt_expr, substs: Substs::single(sig_ty) };
});
let closure_ty = Ty::Closure(self.owner, tgt_expr, Substs::single(sig_ty));
// Eagerly try to relate the closure type with the expected
// type, otherwise we often won't have enough information to

View File

@ -99,6 +99,18 @@ fn walk_mut_binders(
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
pub struct FnSig {
pub variadic: bool,
}
#[derive(Clone, PartialEq, Eq, Debug, Hash)]
pub struct FnPointer {
pub num_args: usize,
pub sig: FnSig,
pub substs: Substs,
}
/// A type.
///
/// See also the `TyKind` enum in rustc (librustc/ty/sty.rs), which represents
@ -166,7 +178,7 @@ pub enum Ty {
///
/// The closure signature is stored in a `FnPtr` type in the first type
/// parameter.
Closure { def: DefWithBodyId, expr: ExprId, substs: Substs },
Closure(DefWithBodyId, ExprId, Substs),
/// Represents a foreign type declared in external blocks.
ForeignType(TypeAliasId),
@ -179,8 +191,7 @@ pub enum Ty {
/// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo;
/// ```
// FIXME make this a Ty variant like in Chalk
FnPtr { num_args: u16, is_varargs: bool, substs: Substs },
Function(FnPointer),
/// A "projection" type corresponds to an (unnormalized)
/// projection like `<P0 as Trait<P1..Pn>>::Foo`. Note that the
@ -535,22 +546,29 @@ pub enum TyKind {
/// A function signature as seen by type inference: Several parameter types and
/// one return type.
#[derive(Clone, PartialEq, Eq, Debug)]
pub struct FnSig {
pub struct CallableSig {
params_and_return: Arc<[Ty]>,
is_varargs: bool,
}
/// A polymorphic function signature.
pub type PolyFnSig = Binders<FnSig>;
pub type PolyFnSig = Binders<CallableSig>;
impl FnSig {
pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> FnSig {
impl CallableSig {
pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty, is_varargs: bool) -> CallableSig {
params.push(ret);
FnSig { params_and_return: params.into(), is_varargs }
CallableSig { params_and_return: params.into(), is_varargs }
}
pub fn from_fn_ptr_substs(substs: &Substs, is_varargs: bool) -> FnSig {
FnSig { params_and_return: Arc::clone(&substs.0), is_varargs }
pub fn from_fn_ptr(fn_ptr: &FnPointer) -> CallableSig {
CallableSig {
params_and_return: Arc::clone(&fn_ptr.substs.0),
is_varargs: fn_ptr.sig.variadic,
}
}
pub fn from_substs(substs: &Substs) -> CallableSig {
CallableSig { params_and_return: Arc::clone(&substs.0), is_varargs: false }
}
pub fn params(&self) -> &[Ty] {
@ -562,7 +580,7 @@ pub fn ret(&self) -> &Ty {
}
}
impl TypeWalk for FnSig {
impl TypeWalk for CallableSig {
fn walk(&self, f: &mut impl FnMut(&Ty)) {
for t in self.params_and_return.iter() {
t.walk(f);
@ -585,12 +603,12 @@ pub fn unit() -> Self {
Ty::Tuple(0, Substs::empty())
}
pub fn fn_ptr(sig: FnSig) -> Self {
Ty::FnPtr {
num_args: sig.params().len() as u16,
is_varargs: sig.is_varargs,
pub fn fn_ptr(sig: CallableSig) -> Self {
Ty::Function(FnPointer {
num_args: sig.params().len(),
sig: FnSig { variadic: sig.is_varargs },
substs: Substs(sig.params_and_return),
}
})
}
pub fn builtin(builtin: BuiltinType) -> Self {
@ -673,7 +691,7 @@ pub fn equals_ctor(&self, other: &Ty) -> bool {
(Ty::OpaqueType(ty_id, ..), Ty::OpaqueType(ty_id2, ..)) => ty_id == ty_id2,
(Ty::AssociatedType(ty_id, ..), Ty::AssociatedType(ty_id2, ..))
| (Ty::ForeignType(ty_id, ..), Ty::ForeignType(ty_id2, ..)) => ty_id == ty_id2,
(Ty::Closure { def, expr, .. }, Ty::Closure { def: def2, expr: expr2, .. }) => {
(Ty::Closure(def, expr, _), Ty::Closure(def2, expr2, _)) => {
expr == expr2 && def == def2
}
(Ty::Ref(mutability, ..), Ty::Ref(mutability2, ..))
@ -681,9 +699,9 @@ pub fn equals_ctor(&self, other: &Ty) -> bool {
mutability == mutability2
}
(
Ty::FnPtr { num_args, is_varargs, .. },
Ty::FnPtr { num_args: num_args2, is_varargs: is_varargs2, .. },
) => num_args == num_args2 && is_varargs == is_varargs2,
Ty::Function(FnPointer { num_args, sig, .. }),
Ty::Function(FnPointer { num_args: num_args2, sig: sig2, .. }),
) => num_args == num_args2 && sig == sig2,
(Ty::Tuple(cardinality, _), Ty::Tuple(cardinality2, _)) => cardinality == cardinality2,
(Ty::Str, Ty::Str) | (Ty::Never, Ty::Never) => true,
(Ty::Scalar(scalar), Ty::Scalar(scalar2)) => scalar == scalar2,
@ -722,17 +740,15 @@ pub fn as_fn_def(&self) -> Option<FunctionId> {
}
}
pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<FnSig> {
pub fn callable_sig(&self, db: &dyn HirDatabase) -> Option<CallableSig> {
match self {
Ty::FnPtr { is_varargs, substs: parameters, .. } => {
Some(FnSig::from_fn_ptr_substs(&parameters, *is_varargs))
}
Ty::Function(fn_ptr) => Some(CallableSig::from_fn_ptr(fn_ptr)),
Ty::FnDef(def, parameters) => {
let sig = db.callable_item_signature(*def);
Some(sig.subst(&parameters))
}
Ty::Closure { substs: parameters, .. } => {
let sig_param = &parameters[0];
Ty::Closure(.., substs) => {
let sig_param = &substs[0];
sig_param.callable_sig(db)
}
_ => None,
@ -751,11 +767,11 @@ pub fn apply_substs(mut self, new_substs: Substs) -> Ty {
| Ty::RawPtr(_, substs)
| Ty::Ref(_, substs)
| Ty::FnDef(_, substs)
| Ty::FnPtr { substs, .. }
| Ty::Function(FnPointer { substs, .. })
| Ty::Tuple(_, substs)
| Ty::OpaqueType(_, substs)
| Ty::AssociatedType(_, substs)
| Ty::Closure { substs, .. } => {
| Ty::Closure(.., substs) => {
assert_eq!(substs.len(), new_substs.len());
*substs = new_substs;
}
@ -774,11 +790,11 @@ pub fn substs(&self) -> Option<&Substs> {
| Ty::RawPtr(_, substs)
| Ty::Ref(_, substs)
| Ty::FnDef(_, substs)
| Ty::FnPtr { substs, .. }
| Ty::Function(FnPointer { substs, .. })
| Ty::Tuple(_, substs)
| Ty::OpaqueType(_, substs)
| Ty::AssociatedType(_, substs)
| Ty::Closure { substs, .. } => Some(substs),
| Ty::Closure(.., substs) => Some(substs),
_ => None,
}
}
@ -791,11 +807,11 @@ pub fn substs_mut(&mut self) -> Option<&mut Substs> {
| Ty::RawPtr(_, substs)
| Ty::Ref(_, substs)
| Ty::FnDef(_, substs)
| Ty::FnPtr { substs, .. }
| Ty::Function(FnPointer { substs, .. })
| Ty::Tuple(_, substs)
| Ty::OpaqueType(_, substs)
| Ty::AssociatedType(_, substs)
| Ty::Closure { substs, .. } => Some(substs),
| Ty::Closure(.., substs) => Some(substs),
_ => None,
}
}

View File

@ -31,9 +31,9 @@
all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
make_mut_slice, variant_data,
},
Binders, BoundVar, DebruijnIndex, FnSig, GenericPredicate, OpaqueTy, OpaqueTyId, PolyFnSig,
ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait, ReturnTypeImplTraits, Substs,
TraitEnvironment, TraitRef, Ty, TypeWalk,
Binders, BoundVar, CallableSig, DebruijnIndex, FnPointer, FnSig, GenericPredicate, OpaqueTy,
OpaqueTyId, PolyFnSig, ProjectionPredicate, ProjectionTy, ReturnTypeImplTrait,
ReturnTypeImplTraits, Substs, TraitEnvironment, TraitRef, Ty, TypeWalk,
};
#[derive(Debug)]
@ -173,8 +173,12 @@ pub fn from_hir_ext(ctx: &TyLoweringContext<'_>, type_ref: &TypeRef) -> (Self, O
}
TypeRef::Placeholder => Ty::Unknown,
TypeRef::Fn(params, is_varargs) => {
let sig = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
Ty::FnPtr { num_args: sig.len() as u16 - 1, is_varargs: *is_varargs, substs: sig }
let substs = Substs(params.iter().map(|tr| Ty::from_hir(ctx, tr)).collect());
Ty::Function(FnPointer {
num_args: substs.len() - 1,
sig: FnSig { variadic: *is_varargs },
substs,
})
}
TypeRef::DynTrait(bounds) => {
let self_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, 0));
@ -1010,7 +1014,7 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
let ret = Ty::from_hir(&ctx_ret, &data.ret_type);
let generics = generics(db.upcast(), def.into());
let num_binders = generics.len();
Binders::new(num_binders, FnSig::from_params_and_return(params, ret, data.is_varargs))
Binders::new(num_binders, CallableSig::from_params_and_return(params, ret, data.is_varargs))
}
/// Build the declared type of a function. This should not need to look at the
@ -1050,7 +1054,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
let params =
fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
let ret = type_for_adt(db, def.into());
Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false))
}
/// Build the type of a tuple struct constructor.
@ -1074,7 +1078,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
let params =
fields.iter().map(|(_, field)| Ty::from_hir(&ctx, &field.type_ref)).collect::<Vec<_>>();
let ret = type_for_adt(db, def.parent.into());
Binders::new(ret.num_binders, FnSig::from_params_and_return(params, ret.value, false))
Binders::new(ret.num_binders, CallableSig::from_params_and_return(params, ret.value, false))
}
/// Build the type of a tuple enum variant constructor.

View File

@ -18,8 +18,8 @@
db::HirDatabase,
primitive::{self, FloatTy, IntTy, UintTy},
utils::all_super_traits,
Canonical, DebruijnIndex, InEnvironment, Scalar, Substs, TraitEnvironment, TraitRef, Ty,
TyKind, TypeWalk,
Canonical, DebruijnIndex, FnPointer, FnSig, InEnvironment, Scalar, Substs, TraitEnvironment,
TraitRef, Ty, TyKind, TypeWalk,
};
/// This is used as a key for indexing impls.
@ -35,7 +35,7 @@ pub enum TyFingerprint {
Dyn(TraitId),
Tuple(usize),
ForeignType(TypeAliasId),
FnPtr { num_args: u16, is_varargs: bool },
FnPtr(usize, FnSig),
}
impl TyFingerprint {
@ -53,9 +53,7 @@ pub(crate) fn for_impl(ty: &Ty) -> Option<TyFingerprint> {
&Ty::Tuple(cardinality, _) => TyFingerprint::Tuple(cardinality),
&Ty::RawPtr(mutability, ..) => TyFingerprint::RawPtr(mutability),
&Ty::ForeignType(alias_id, ..) => TyFingerprint::ForeignType(alias_id),
&Ty::FnPtr { num_args, is_varargs, .. } => {
TyFingerprint::FnPtr { num_args, is_varargs }
}
&Ty::Function(FnPointer { num_args, sig, .. }) => TyFingerprint::FnPtr(num_args, sig),
Ty::Dyn(_) => ty.dyn_trait().map(|trait_| TyFingerprint::Dyn(trait_))?,
_ => return None,
};

View File

@ -19,7 +19,7 @@
display::HirDisplay,
method_resolution::{TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
utils::generics,
BoundVar, CallableDefId, DebruijnIndex, FnSig, GenericPredicate, ProjectionPredicate,
BoundVar, CallableDefId, CallableSig, DebruijnIndex, GenericPredicate, ProjectionPredicate,
ProjectionTy, Substs, TraitRef, Ty,
};
use mapping::{
@ -286,9 +286,8 @@ fn closure_inputs_and_output(
) -> chalk_ir::Binders<rust_ir::FnDefInputsAndOutputDatum<Interner>> {
let sig_ty: Ty =
from_chalk(self.db, substs.at(&Interner, 0).assert_ty_ref(&Interner).clone());
let sig = FnSig::from_fn_ptr_substs(
let sig = CallableSig::from_substs(
&sig_ty.substs().expect("first closure param should be fn ptr"),
false,
);
let io = rust_ir::FnDefInputsAndOutputDatum {
argument_types: sig.params().iter().map(|ty| ty.clone().to_chalk(self.db)).collect(),

View File

@ -16,8 +16,8 @@
db::HirDatabase,
primitive::UintTy,
traits::{Canonical, Obligation},
CallableDefId, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId, ProjectionPredicate,
ProjectionTy, Scalar, Substs, TraitEnvironment, TraitRef, Ty, TyKind,
CallableDefId, FnPointer, FnSig, GenericPredicate, InEnvironment, OpaqueTy, OpaqueTyId,
ProjectionPredicate, ProjectionTy, Scalar, Substs, TraitEnvironment, TraitRef, Ty, TyKind,
};
use super::interner::*;
@ -29,15 +29,11 @@ fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
match self {
Ty::Ref(m, parameters) => ref_to_chalk(db, m, parameters),
Ty::Array(parameters) => array_to_chalk(db, parameters),
Ty::FnPtr { num_args: _, is_varargs, substs } => {
Ty::Function(FnPointer { sig: FnSig { variadic }, substs, .. }) => {
let substitution = chalk_ir::FnSubst(substs.to_chalk(db).shifted_in(&Interner));
chalk_ir::TyKind::Function(chalk_ir::FnPointer {
num_binders: 0,
sig: chalk_ir::FnSig {
abi: (),
safety: chalk_ir::Safety::Safe,
variadic: is_varargs,
},
sig: chalk_ir::FnSig { abi: (), safety: chalk_ir::Safety::Safe, variadic },
substitution,
})
.intern(&Interner)
@ -82,7 +78,7 @@ fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Ty<Interner> {
}
Ty::Never => chalk_ir::TyKind::Never.intern(&Interner),
Ty::Closure { def, expr, substs } => {
Ty::Closure(def, expr, substs) => {
let closure_id = db.intern_closure((def, expr));
let substitution = substs.to_chalk(db);
chalk_ir::TyKind::Closure(closure_id.into(), substitution).intern(&Interner)
@ -164,15 +160,15 @@ fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
..
}) => {
assert_eq!(num_binders, 0);
let parameters: Substs = from_chalk(
let substs: Substs = from_chalk(
db,
substitution.0.shifted_out(&Interner).expect("fn ptr should have no binders"),
);
Ty::FnPtr {
num_args: (parameters.len() - 1) as u16,
is_varargs: variadic,
substs: parameters,
}
Ty::Function(FnPointer {
num_args: (substs.len() - 1),
sig: FnSig { variadic },
substs,
})
}
chalk_ir::TyKind::BoundVar(idx) => Ty::Bound(idx),
chalk_ir::TyKind::InferenceVar(_iv, _kind) => Ty::Unknown,
@ -218,7 +214,7 @@ fn from_chalk(db: &dyn HirDatabase, chalk: chalk_ir::Ty<Interner>) -> Self {
chalk_ir::TyKind::Closure(id, subst) => {
let id: crate::db::ClosureId = id.into();
let (def, expr) = db.lookup_intern_closure(id);
Ty::Closure { def, expr, substs: from_chalk(db, subst) }
Ty::Closure(def, expr, from_chalk(db, subst))
}
chalk_ir::TyKind::Foreign(foreign_def_id) => {