From a9ddaba905348897606948658798f9f46854acf7 Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 16 Mar 2019 17:21:32 +0100 Subject: Refactor FnSig a bit --- crates/ra_hir/src/ty.rs | 81 +++++++++++++++++++++++++------------------ crates/ra_hir/src/ty/infer.rs | 23 ++++++------ crates/ra_hir/src/ty/lower.rs | 70 ++++++++++++++++++++++++------------- 3 files changed, 104 insertions(+), 70 deletions(-) diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index 884cea52a..31f726f35 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -78,7 +78,7 @@ pub enum Ty { /// The definition of the function / constructor. def: CallableDef, /// Parameters and return type - sig: Arc, + 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), + 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, - output: Ty, + params_and_return: Arc<[Ty]>, +} + +impl FnSig { + pub fn from_params_and_return(mut params: Vec, 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 { diff --git a/crates/ra_hir/src/ty/infer.rs b/crates/ra_hir/src/ty/infer.rs index 268d2c110..2eb73726e 100644 --- a/crates/ra_hir/src/ty/infer.rs +++ b/crates/ra_hir/src/ty/infer.rs @@ -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) } diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index ee4508bb2..7d065203a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs @@ -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::>(); - 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::>(); + 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::>(); - 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::>(); - 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 } } -/// Build the type of a tuple enum variant constructor. -fn type_for_enum_variant_constructor(db: &impl HirDatabase, def: EnumVariant) -> Ty { +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 => return type_for_enum(db, def.parent_enum(db)), // Unit variant + None => panic!("fn_sig_for_enum_variant_constructor called for unit variant"), }; let resolver = def.parent_enum(db).resolver(db); - let generics = def.parent_enum(db).generic_params(db); - let input = fields + let params = fields .iter() .map(|(_, field)| Ty::from_hir(db, &resolver, &field.type_ref)) .collect::>(); + 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); + 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 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 } } -- cgit v1.2.3