Refactor FnSig a bit

This commit is contained in:
Florian Diebold 2019-03-16 17:21:32 +01:00
parent 628b530e92
commit a9ddaba905
3 changed files with 108 additions and 74 deletions

View file

@ -78,7 +78,7 @@ pub enum Ty {
/// The definition of the function / constructor. /// The definition of the function / constructor.
def: CallableDef, def: CallableDef,
/// Parameters and return type /// Parameters and return type
sig: Arc<FnSig>, sig: FnSig,
/// Substitutions for the generic parameters of the type /// Substitutions for the generic parameters of the type
substs: Substs, substs: Substs,
}, },
@ -91,7 +91,7 @@ pub enum Ty {
/// fn foo() -> i32 { 1 } /// fn foo() -> i32 { 1 }
/// let bar: fn() -> i32 = foo; /// let bar: fn() -> i32 = foo;
/// ``` /// ```
FnPtr(Arc<FnSig>), FnPtr(FnSig),
/// The never type `!`. /// The never type `!`.
Never, Never,
@ -128,13 +128,44 @@ impl Substs {
pub fn empty() -> Substs { pub fn empty() -> Substs {
Substs(Arc::new([])) 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. /// A function signature.
#[derive(Clone, PartialEq, Eq, Debug)] #[derive(Clone, PartialEq, Eq, Debug)]
pub struct FnSig { pub struct FnSig {
input: Vec<Ty>, params_and_return: Arc<[Ty]>,
output: 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 { impl Ty {
@ -153,16 +184,16 @@ impl Ty {
} }
} }
Ty::FnPtr(sig) => { Ty::FnPtr(sig) => {
for input in &sig.input { for input in sig.params() {
input.walk(f); input.walk(f);
} }
sig.output.walk(f); sig.ret().walk(f);
} }
Ty::FnDef { substs, sig, .. } => { Ty::FnDef { substs, sig, .. } => {
for input in &sig.input { for input in sig.params() {
input.walk(f); input.walk(f);
} }
sig.output.walk(f); sig.ret().walk(f);
for t in substs.0.iter() { for t in substs.0.iter() {
t.walk(f); t.walk(f);
} }
@ -199,32 +230,14 @@ impl Ty {
*ts = v.into(); *ts = v.into();
} }
Ty::FnPtr(sig) => { Ty::FnPtr(sig) => {
let sig_mut = Arc::make_mut(sig); sig.walk_mut(f);
for input in &mut sig_mut.input {
input.walk_mut(f);
}
sig_mut.output.walk_mut(f);
} }
Ty::FnDef { substs, sig, .. } => { Ty::FnDef { substs, sig, .. } => {
let sig_mut = Arc::make_mut(sig); sig.walk_mut(f);
for input in &mut sig_mut.input { substs.walk_mut(f);
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();
} }
Ty::Adt { substs, .. } => { Ty::Adt { substs, .. } => {
// Without an Arc::make_mut_slice, we can't avoid the clone here: substs.walk_mut(f);
let mut v: Vec<_> = substs.0.iter().cloned().collect();
for t in &mut v {
t.walk_mut(f);
}
substs.0 = v.into();
} }
Ty::Bool Ty::Bool
| Ty::Char | Ty::Char
@ -328,8 +341,8 @@ impl HirDisplay for Ty {
} }
Ty::FnPtr(sig) => { Ty::FnPtr(sig) => {
write!(f, "fn(")?; write!(f, "fn(")?;
f.write_joined(&sig.input, ", ")?; f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.output.display(f.db))?; write!(f, ") -> {}", sig.ret().display(f.db))?;
} }
Ty::FnDef { def, substs, sig, .. } => { Ty::FnDef { def, substs, sig, .. } => {
let name = match def { let name = match def {
@ -347,8 +360,8 @@ impl HirDisplay for Ty {
write!(f, ">")?; write!(f, ">")?;
} }
write!(f, "(")?; write!(f, "(")?;
f.write_joined(&sig.input, ", ")?; f.write_joined(sig.params(), ", ")?;
write!(f, ") -> {}", sig.output.display(f.db))?; write!(f, ") -> {}", sig.ret().display(f.db))?;
} }
Ty::Adt { def_id, substs, .. } => { Ty::Adt { def_id, substs, .. } => {
let name = match def_id { let name = match def_id {

View file

@ -724,11 +724,11 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Expr::Call { callee, args } => { Expr::Call { callee, args } => {
let callee_ty = self.infer_expr(*callee, &Expectation::none()); let callee_ty = self.infer_expr(*callee, &Expectation::none());
let (param_tys, ret_ty) = match &callee_ty { 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, .. } => { Ty::FnDef { substs, sig, .. } => {
let ret_ty = sig.output.clone().subst(&substs); let ret_ty = sig.ret().clone().subst(&substs);
let param_tys = 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) (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 method_ty = self.insert_type_vars(method_ty);
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
Ty::FnPtr(sig) => { Ty::FnPtr(sig) => {
if !sig.input.is_empty() { if !sig.params().is_empty() {
(sig.input[0].clone(), sig.input[1..].to_vec(), sig.output.clone()) (sig.params()[0].clone(), sig.params()[1..].to_vec(), sig.ret().clone())
} else { } else {
(Ty::Unknown, Vec::new(), sig.output.clone()) (Ty::Unknown, Vec::new(), sig.ret().clone())
} }
} }
Ty::FnDef { substs, sig, .. } => { 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() { if !sig.params().is_empty() {
let mut arg_iter = sig.input.iter().map(|ty| ty.clone().subst(&substs)); let mut params_iter =
let receiver_ty = arg_iter.next().unwrap(); sig.params().iter().map(|ty| ty.clone().subst(&substs));
(receiver_ty, arg_iter.collect(), ret_ty) let receiver_ty = params_iter.next().unwrap();
(receiver_ty, params_iter.collect(), ret_ty)
} else { } else {
(Ty::Unknown, Vec::new(), ret_ty) (Ty::Unknown, Vec::new(), ret_ty)
} }

View file

@ -51,12 +51,10 @@ impl Ty {
} }
TypeRef::Placeholder => Ty::Unknown, TypeRef::Placeholder => Ty::Unknown,
TypeRef::Fn(params) => { TypeRef::Fn(params) => {
let mut inner_tys = let inner_tys =
params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>(); params.iter().map(|tr| Ty::from_hir(db, resolver, tr)).collect::<Vec<_>>();
let return_ty = let sig = FnSig { params_and_return: inner_tys.into() };
inner_tys.pop().expect("TypeRef::Fn should always have at least return type"); Ty::FnPtr(sig)
let sig = FnSig { input: inner_tys, output: return_ty };
Ty::FnPtr(Arc::new(sig))
} }
TypeRef::Error => Ty::Unknown, 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) 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 /// Build the declared type of a function. This should not need to look at the
/// function body. /// function body.
fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
let signature = def.signature(db); let sig = fn_sig_for_fn(db, def);
let resolver = def.resolver(db);
let generics = def.generic_params(db); 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); let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), sig, substs } 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()) Ty::from_hir(db, &resolver, signature.type_ref())
} }
/// Build the type of a tuple struct constructor. fn fn_sig_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> FnSig {
fn type_for_struct_constructor(db: &impl HirDatabase, def: Struct) -> Ty {
let var_data = def.variant_data(db); let var_data = def.variant_data(db);
let fields = match var_data.fields() { let fields = match var_data.fields() {
Some(fields) => 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 resolver = def.resolver(db);
let generics = def.generic_params(db); let params = fields
let input = fields
.iter() .iter()
.map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref))
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let output = type_for_struct(db, def); let ret = type_for_struct(db, def);
let sig = Arc::new(FnSig { input, output }); 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); let substs = make_substs(&generics);
Ty::FnDef { def: def.into(), sig, substs } 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. /// Build the type of a tuple enum variant constructor.
fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty { fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty {
let var_data = def.variant_data(db); let var_data = def.variant_data(db);
let fields = match var_data.fields() { if var_data.fields().is_none() {
Some(fields) => fields, return type_for_enum(db, def.parent_enum(db)); // Unit variant
None => return type_for_enum(db, def.parent_enum(db)), // Unit variant }
}; let sig = fn_sig_for_enum_variant_constructor(db, def);
let resolver = def.parent_enum(db).resolver(db);
let generics = def.parent_enum(db).generic_params(db); 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 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 } Ty::FnDef { def: def.into(), sig, substs }
} }