mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-10-03 07:04:49 +00:00
Refactor FnSig a bit
This commit is contained in:
parent
628b530e92
commit
a9ddaba905
3 changed files with 108 additions and 74 deletions
|
@ -78,7 +78,7 @@ pub enum Ty {
|
|||
/// The definition of the function / constructor.
|
||||
def: CallableDef,
|
||||
/// Parameters and return type
|
||||
sig: Arc<FnSig>,
|
||||
sig: FnSig,
|
||||
/// Substitutions for the generic parameters of the type
|
||||
substs: Substs,
|
||||
},
|
||||
|
@ -91,7 +91,7 @@ pub enum Ty {
|
|||
/// fn foo() -> i32 { 1 }
|
||||
/// let bar: fn() -> i32 = foo;
|
||||
/// ```
|
||||
FnPtr(Arc<FnSig>),
|
||||
FnPtr(FnSig),
|
||||
|
||||
/// The never type `!`.
|
||||
Never,
|
||||
|
@ -128,13 +128,44 @@ impl Substs {
|
|||
pub fn empty() -> Substs {
|
||||
Substs(Arc::new([]))
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = self.0.iter().cloned().collect();
|
||||
for t in &mut v {
|
||||
t.walk_mut(f);
|
||||
}
|
||||
self.0 = v.into();
|
||||
}
|
||||
}
|
||||
|
||||
/// A function signature.
|
||||
#[derive(Clone, PartialEq, Eq, Debug)]
|
||||
pub struct FnSig {
|
||||
input: Vec<Ty>,
|
||||
output: Ty,
|
||||
params_and_return: Arc<[Ty]>,
|
||||
}
|
||||
|
||||
impl FnSig {
|
||||
pub fn from_params_and_return(mut params: Vec<Ty>, ret: Ty) -> FnSig {
|
||||
params.push(ret);
|
||||
FnSig { params_and_return: params.into() }
|
||||
}
|
||||
pub fn params(&self) -> &[Ty] {
|
||||
&self.params_and_return[0..self.params_and_return.len() - 1]
|
||||
}
|
||||
|
||||
pub fn ret(&self) -> &Ty {
|
||||
&self.params_and_return[self.params_and_return.len() - 1]
|
||||
}
|
||||
|
||||
pub fn walk_mut(&mut self, f: &mut impl FnMut(&mut Ty)) {
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = self.params_and_return.iter().cloned().collect();
|
||||
for t in &mut v {
|
||||
t.walk_mut(f);
|
||||
}
|
||||
self.params_and_return = v.into();
|
||||
}
|
||||
}
|
||||
|
||||
impl Ty {
|
||||
|
@ -153,16 +184,16 @@ impl Ty {
|
|||
}
|
||||
}
|
||||
Ty::FnPtr(sig) => {
|
||||
for input in &sig.input {
|
||||
for input in sig.params() {
|
||||
input.walk(f);
|
||||
}
|
||||
sig.output.walk(f);
|
||||
sig.ret().walk(f);
|
||||
}
|
||||
Ty::FnDef { substs, sig, .. } => {
|
||||
for input in &sig.input {
|
||||
for input in sig.params() {
|
||||
input.walk(f);
|
||||
}
|
||||
sig.output.walk(f);
|
||||
sig.ret().walk(f);
|
||||
for t in substs.0.iter() {
|
||||
t.walk(f);
|
||||
}
|
||||
|
@ -199,32 +230,14 @@ impl Ty {
|
|||
*ts = v.into();
|
||||
}
|
||||
Ty::FnPtr(sig) => {
|
||||
let sig_mut = Arc::make_mut(sig);
|
||||
for input in &mut sig_mut.input {
|
||||
input.walk_mut(f);
|
||||
}
|
||||
sig_mut.output.walk_mut(f);
|
||||
sig.walk_mut(f);
|
||||
}
|
||||
Ty::FnDef { substs, sig, .. } => {
|
||||
let sig_mut = Arc::make_mut(sig);
|
||||
for input in &mut sig_mut.input {
|
||||
input.walk_mut(f);
|
||||
}
|
||||
sig_mut.output.walk_mut(f);
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = substs.0.iter().cloned().collect();
|
||||
for t in &mut v {
|
||||
t.walk_mut(f);
|
||||
}
|
||||
substs.0 = v.into();
|
||||
sig.walk_mut(f);
|
||||
substs.walk_mut(f);
|
||||
}
|
||||
Ty::Adt { substs, .. } => {
|
||||
// Without an Arc::make_mut_slice, we can't avoid the clone here:
|
||||
let mut v: Vec<_> = substs.0.iter().cloned().collect();
|
||||
for t in &mut v {
|
||||
t.walk_mut(f);
|
||||
}
|
||||
substs.0 = v.into();
|
||||
substs.walk_mut(f);
|
||||
}
|
||||
Ty::Bool
|
||||
| Ty::Char
|
||||
|
@ -328,8 +341,8 @@ impl HirDisplay for Ty {
|
|||
}
|
||||
Ty::FnPtr(sig) => {
|
||||
write!(f, "fn(")?;
|
||||
f.write_joined(&sig.input, ", ")?;
|
||||
write!(f, ") -> {}", sig.output.display(f.db))?;
|
||||
f.write_joined(sig.params(), ", ")?;
|
||||
write!(f, ") -> {}", sig.ret().display(f.db))?;
|
||||
}
|
||||
Ty::FnDef { def, substs, sig, .. } => {
|
||||
let name = match def {
|
||||
|
@ -347,8 +360,8 @@ impl HirDisplay for Ty {
|
|||
write!(f, ">")?;
|
||||
}
|
||||
write!(f, "(")?;
|
||||
f.write_joined(&sig.input, ", ")?;
|
||||
write!(f, ") -> {}", sig.output.display(f.db))?;
|
||||
f.write_joined(sig.params(), ", ")?;
|
||||
write!(f, ") -> {}", sig.ret().display(f.db))?;
|
||||
}
|
||||
Ty::Adt { def_id, substs, .. } => {
|
||||
let name = match def_id {
|
||||
|
|
|
@ -724,11 +724,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
Expr::Call { callee, args } => {
|
||||
let callee_ty = self.infer_expr(*callee, &Expectation::none());
|
||||
let (param_tys, ret_ty) = match &callee_ty {
|
||||
Ty::FnPtr(sig) => (sig.input.clone(), sig.output.clone()),
|
||||
Ty::FnPtr(sig) => (sig.params().to_vec(), sig.ret().clone()),
|
||||
Ty::FnDef { substs, sig, .. } => {
|
||||
let ret_ty = sig.output.clone().subst(&substs);
|
||||
let ret_ty = sig.ret().clone().subst(&substs);
|
||||
let param_tys =
|
||||
sig.input.iter().map(|ty| ty.clone().subst(&substs)).collect();
|
||||
sig.params().iter().map(|ty| ty.clone().subst(&substs)).collect();
|
||||
(param_tys, ret_ty)
|
||||
}
|
||||
_ => {
|
||||
|
@ -762,19 +762,20 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
|||
let method_ty = self.insert_type_vars(method_ty);
|
||||
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
||||
Ty::FnPtr(sig) => {
|
||||
if !sig.input.is_empty() {
|
||||
(sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone())
|
||||
if !sig.params().is_empty() {
|
||||
(sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), sig.output.clone())
|
||||
(Ty::Unknown, Vec::new(), sig.ret().clone())
|
||||
}
|
||||
}
|
||||
Ty::FnDef { substs, sig, .. } => {
|
||||
let ret_ty = sig.output.clone().subst(&substs);
|
||||
let ret_ty = sig.ret().clone().subst(&substs);
|
||||
|
||||
if !sig.input.is_empty() {
|
||||
let mut arg_iter = sig.input.iter().map(|ty| ty.clone().subst(&substs));
|
||||
let receiver_ty = arg_iter.next().unwrap();
|
||||
(receiver_ty, arg_iter.collect(), ret_ty)
|
||||
if !sig.params().is_empty() {
|
||||
let mut params_iter =
|
||||
sig.params().iter().map(|ty| ty.clone().subst(&substs));
|
||||
let receiver_ty = params_iter.next().unwrap();
|
||||
(receiver_ty, params_iter.collect(), ret_ty)
|
||||
} else {
|
||||
(Ty::Unknown, Vec::new(), ret_ty)
|
||||
}
|
||||
|
|
|
@ -51,12 +51,10 @@ impl Ty {
|
|||
}
|
||||
TypeRef::Placeholder => Ty::Unknown,
|
||||
TypeRef::Fn(params) => {
|
||||
let mut inner_tys =
|
||||
let inner_tys =
|
||||
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
|
||||
let return_ty =
|
||||
inner_tys.pop().expect("TypeRef::Fn should always have at least return type");
|
||||
let sig = FnSig { input: inner_tys, output: return_ty };
|
||||
Ty::FnPtr(Arc::new(sig))
|
||||
let sig = FnSig { params_and_return: inner_tys.into() };
|
||||
Ty::FnPtr(sig)
|
||||
}
|
||||
TypeRef::Error => Ty::Unknown,
|
||||
}
|
||||
|
@ -226,16 +224,20 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty {
|
|||
Ty::from_hir(db, &resolver, type_ref)
|
||||
}
|
||||
|
||||
fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig {
|
||||
let signature = def.signature(db);
|
||||
let resolver = def.resolver(db);
|
||||
let params =
|
||||
signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
|
||||
let ret = Ty::from_hir(db, &resolver, signature.ret_type());
|
||||
FnSig::from_params_and_return(params, ret)
|
||||
}
|
||||
|
||||
/// Build the declared type of a function. This should not need to look at the
|
||||
/// function body.
|
||||
fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
|
||||
let signature = def.signature(db);
|
||||
let resolver = def.resolver(db);
|
||||
let sig = fn_sig_for_fn(db, def);
|
||||
let generics = def.generic_params(db);
|
||||
let input =
|
||||
signature.params().iter().map(|tr| Ty::from_hir(db, &resolver, tr)).collect::<Vec<_>>();
|
||||
let output = Ty::from_hir(db, &resolver, signature.ret_type());
|
||||
let sig = Arc::new(FnSig { input, output });
|
||||
let substs = make_substs(&generics);
|
||||
Ty::FnDef { def: def.into(), sig, substs }
|
||||
}
|
||||
|
@ -256,41 +258,59 @@ fn type_for_static(db: &impl HirDatabase, def: Static) -> Ty {
|
|||
Ty::from_hir(db, &resolver, signature.type_ref())
|
||||
}
|
||||
|
||||
/// Build the type of a tuple struct constructor.
|
||||
fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
|
||||
fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
|
||||
let var_data = def.variant_data(db);
|
||||
let fields = match var_data.fields() {
|
||||
Some(fields) => fields,
|
||||
None => return type_for_struct(db, def), // Unit struct
|
||||
None => panic!("fn_sig_for_struct_constructor called on unit struct"),
|
||||
};
|
||||
let resolver = def.resolver(db);
|
||||
let generics = def.generic_params(db);
|
||||
let input = fields
|
||||
let params = fields
|
||||
.iter()
|
||||
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
|
||||
.collect::<Vec<_>>();
|
||||
let output = type_for_struct(db, def);
|
||||
let sig = Arc::new(FnSig { input, output });
|
||||
let ret = type_for_struct(db, def);
|
||||
FnSig::from_params_and_return(params, ret)
|
||||
}
|
||||
|
||||
/// Build the type of a tuple struct constructor.
|
||||
fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
|
||||
let var_data = def.variant_data(db);
|
||||
if var_data.fields().is_none() {
|
||||
return type_for_struct(db, def); // Unit struct
|
||||
}
|
||||
let sig = fn_sig_for_struct_constructor(db, def);
|
||||
let generics = def.generic_params(db);
|
||||
let substs = make_substs(&generics);
|
||||
Ty::FnDef { def: def.into(), sig, substs }
|
||||
}
|
||||
|
||||
fn fn_sig_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> FnSig {
|
||||
let var_data = def.variant_data(db);
|
||||
let fields = match var_data.fields() {
|
||||
Some(fields) => fields,
|
||||
None => panic!("fn_sig_for_enum_variant_constructor called for unit variant"),
|
||||
};
|
||||
let resolver = def.parent_enum(db).resolver(db);
|
||||
let params = fields
|
||||
.iter()
|
||||
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
|
||||
.collect::<Vec<_>>();
|
||||
let generics = def.parent_enum(db).generic_params(db);
|
||||
let substs = make_substs(&generics);
|
||||
let ret = type_for_enum(db, def.parent_enum(db)).subst(&substs);
|
||||
FnSig::from_params_and_return(params, ret)
|
||||
}
|
||||
|
||||
/// Build the type of a tuple enum variant constructor.
|
||||
fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
|
||||
let var_data = def.variant_data(db);
|
||||
let fields = match var_data.fields() {
|
||||
Some(fields) => fields,
|
||||
None => return type_for_enum(db, def.parent_enum(db)), // Unit variant
|
||||
};
|
||||
let resolver = def.parent_enum(db).resolver(db);
|
||||
if var_data.fields().is_none() {
|
||||
return type_for_enum(db, def.parent_enum(db)); // Unit variant
|
||||
}
|
||||
let sig = fn_sig_for_enum_variant_constructor(db, def);
|
||||
let generics = def.parent_enum(db).generic_params(db);
|
||||
let input = fields
|
||||
.iter()
|
||||
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
|
||||
.collect::<Vec<_>>();
|
||||
let substs = make_substs(&generics);
|
||||
let output = type_for_enum(db, def.parent_enum(db)).subst(&substs);
|
||||
let sig = Arc::new(FnSig { input, output });
|
||||
Ty::FnDef { def: def.into(), sig, substs }
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue