mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-27 20:42:04 +00:00
Initial implementation of generics for method calls
This commit is contained in:
parent
3bd47c0285
commit
67e40e431a
2 changed files with 72 additions and 13 deletions
|
@ -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)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue