Initial implementation of generics for method calls

This commit is contained in:
Marcus Klaas de Vries 2019-01-25 22:18:13 +01:00
parent 3bd47c0285
commit 67e40e431a
2 changed files with 72 additions and 13 deletions

View file

@ -424,6 +424,10 @@ impl Function {
self.id.module(db) self.id.module(db)
} }
pub fn name(&self, db: &impl HirDatabase) -> Name {
self.signature(db).name.clone()
}
pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> { pub fn body_syntax_mapping(&self, db: &impl HirDatabase) -> Arc<BodySyntaxMapping> {
db.body_syntax_mapping(*self) db.body_syntax_mapping(*self)
} }

View file

@ -185,7 +185,7 @@ pub enum Ty {
/// Structures, enumerations and unions. /// Structures, enumerations and unions.
Adt { Adt {
/// The DefId of the struct/enum. /// The definition of the struct/enum.
def_id: AdtDef, def_id: AdtDef,
/// The name, for displaying. /// The name, for displaying.
name: Name, name: Name,
@ -219,7 +219,14 @@ pub enum Ty {
/// fn foo() -> i32 { 1 } /// fn foo() -> i32 { 1 }
/// let bar = foo; // bar: fn() -> i32 {foo} /// let bar = foo; // bar: fn() -> i32 {foo}
/// ``` /// ```
FnDef(Function, Substs), FnDef {
// Function definition
def: Function,
/// For display
name: Name,
/// Substitutions for the generic parameters of the type
substs: Substs
},
/// A pointer to a function. Written as `fn() -> i32`. /// A pointer to a function. Written as `fn() -> i32`.
/// ///
@ -497,7 +504,7 @@ impl Ty {
} }
sig_mut.output.walk_mut(f); sig_mut.output.walk_mut(f);
} }
Ty::FnDef(_, substs) | Ty::Adt { substs, .. } => { Ty::FnDef { substs, .. } | Ty::Adt { substs, .. } => {
// Without an Arc::make_mut_slice, we can't avoid the clone here: // Without an Arc::make_mut_slice, we can't avoid the clone here:
let mut v: Vec<_> = substs.0.iter().cloned().collect(); let mut v: Vec<_> = substs.0.iter().cloned().collect();
for t in &mut v { for t in &mut v {
@ -536,7 +543,11 @@ impl Ty {
name, name,
substs, substs,
}, },
Ty::FnDef(func, _) => Ty::FnDef(func, substs), Ty::FnDef { def, name, .. } => Ty::FnDef {
def,
name,
substs,
},
_ => self, _ => self,
} }
} }
@ -592,7 +603,6 @@ impl fmt::Display for Ty {
.to_fmt(f) .to_fmt(f)
} }
} }
Ty::FnDef(_func, _substs) => write!(f, "FNDEF-IMPLEMENT-ME"),
Ty::FnPtr(sig) => { Ty::FnPtr(sig) => {
join(sig.input.iter()) join(sig.input.iter())
.surround_with("fn(", ")") .surround_with("fn(", ")")
@ -600,6 +610,19 @@ impl fmt::Display for Ty {
.to_fmt(f)?; .to_fmt(f)?;
write!(f, " -> {}", sig.output) write!(f, " -> {}", sig.output)
} }
Ty::FnDef { name, substs, .. } => {
// don't have access to the param types here :-(
// we could store them in the def, but not sure if it
// is worth it
write!(f, "fn {}", name)?;
if substs.0.len() > 0 {
join(substs.0.iter())
.surround_with("<", ">")
.separator(", ")
.to_fmt(f)?;
}
Ok(())
}
Ty::Adt { name, substs, .. } => { Ty::Adt { name, substs, .. } => {
write!(f, "{}", name)?; write!(f, "{}", name)?;
if substs.0.len() > 0 { if substs.0.len() > 0 {
@ -624,7 +647,12 @@ impl fmt::Display for Ty {
fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty { fn type_for_fn(db: &impl HirDatabase, f: Function) -> Ty {
let generics = f.generic_params(db); let generics = f.generic_params(db);
let substs = make_substs(&generics); let substs = make_substs(&generics);
Ty::FnDef(f.into(), substs) let name = f.name(db);
Ty::FnDef {
def: f.into(),
name,
substs
}
} }
fn get_func_sig(db: &impl HirDatabase, f: Function) -> FnSig { fn get_func_sig(db: &impl HirDatabase, f: Function) -> FnSig {
@ -1355,16 +1383,18 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
Ty::Unknown Ty::Unknown
} }
Expr::Call { callee, args } => { Expr::Call { callee, args } => {
// TODO: we should use turbofish hints like this:
// f::<u32>(x)
let callee_ty = self.infer_expr(*callee, &Expectation::none()); let callee_ty = self.infer_expr(*callee, &Expectation::none());
// FIXME: so manu unnecessary clones // FIXME: so manu unnecessary clones
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.input.clone(), sig.output.clone()),
Ty::FnDef(func, substs) => { Ty::FnDef { def, substs, .. } => {
let fn_sig = func.signature(self.db); let fn_sig = def.signature(self.db);
// TODO: get input and return types from the fn_sig. // TODO: get input and return types from the fn_sig.
// it contains typerefs which we can make into proper tys // it contains typerefs which we can make into proper tys
let sig = get_func_sig(self.db, *func); let sig = get_func_sig(self.db, *def);
( (
sig.input sig.input
.iter() .iter()
@ -1405,16 +1435,41 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
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.len() > 0 { if sig.input.len() > 0 {
(&sig.input[0], &sig.input[1..], sig.output.clone()) (sig.input[0].clone(), sig.input[1..].iter().cloned().collect(), sig.output.clone())
} else { } else {
(&Ty::Unknown, &[][..], sig.output.clone()) (Ty::Unknown, Vec::new(), sig.output.clone())
} }
} }
_ => (&Ty::Unknown, &[][..], Ty::Unknown), Ty::FnDef { def, substs, .. } => {
// TODO: fix deduplication with Expr::Call block above
// TODO: fix the ridiculous number of clones
let fn_sig = def.signature(self.db);
// TODO: get input and return types from the fn_sig.
// it contains typerefs which we can make into proper tys
// check that len > 0
let sig = get_func_sig(self.db, *def);
if sig.input.len() > 0 {
(
sig.input[0].clone().subst(&substs),
sig.input[1..]
.iter()
.map(|ty| ty.clone().subst(&substs))
.collect(),
sig.output.clone().subst(&substs),
)
} else {
(Ty::Unknown, Vec::new(), sig.output.clone())
}
}
_ => (Ty::Unknown, Vec::new(), Ty::Unknown),
}; };
// TODO we would have to apply the autoderef/autoref steps here // TODO we would have to apply the autoderef/autoref steps here
// to get the correct receiver type to unify... // to get the correct receiver type to unify...
self.unify(expected_receiver_ty, &receiver_ty); //
// TODO: zip param_tys.chain(iter::repeat(Ty::Unknown)) above then its not so bad
// that we clone
self.unify(&expected_receiver_ty, &receiver_ty);
for (i, arg) in args.iter().enumerate() { for (i, arg) in args.iter().enumerate() {
self.infer_expr( self.infer_expr(
*arg, *arg,