Handle generic args for method calls
This commit is contained in:
parent
65bd9bc3a8
commit
a1bda3fc08
@ -14,7 +14,7 @@ use crate::{
|
||||
name::AsName,
|
||||
type_ref::{Mutability, TypeRef},
|
||||
};
|
||||
use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy};
|
||||
use crate::{ path::GenericArgs, ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}};
|
||||
|
||||
pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
|
||||
|
||||
@ -193,6 +193,7 @@ pub enum Expr {
|
||||
receiver: ExprId,
|
||||
method_name: Name,
|
||||
args: Vec<ExprId>,
|
||||
generic_args: Option<GenericArgs>,
|
||||
},
|
||||
Match {
|
||||
expr: ExprId,
|
||||
@ -597,7 +598,11 @@ impl ExprCollector {
|
||||
Vec::new()
|
||||
};
|
||||
let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
|
||||
self.alloc_expr(Expr::MethodCall { receiver, method_name, args }, syntax_ptr)
|
||||
let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
|
||||
self.alloc_expr(
|
||||
Expr::MethodCall { receiver, method_name, args, generic_args },
|
||||
syntax_ptr,
|
||||
)
|
||||
}
|
||||
ast::ExprKind::MatchExpr(e) => {
|
||||
let expr = self.collect_expr_opt(e.expr());
|
||||
|
@ -129,7 +129,7 @@ impl Path {
|
||||
}
|
||||
|
||||
impl GenericArgs {
|
||||
fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
|
||||
pub fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
|
||||
let mut args = Vec::new();
|
||||
for type_arg in node.type_args() {
|
||||
let type_ref = TypeRef::from_ast_opt(type_arg.type_ref());
|
||||
|
@ -165,6 +165,17 @@ impl Substs {
|
||||
pub fn empty() -> Substs {
|
||||
Substs(Arc::new([]))
|
||||
}
|
||||
|
||||
/// Replaces the end of the substitutions by other ones.
|
||||
pub(crate) fn replace_tail(self, replace_by: Vec<Ty>) -> Substs {
|
||||
// again missing Arc::make_mut_slice...
|
||||
let len = replace_by.len().min(self.0.len());
|
||||
let parent_len = self.0.len() - len;
|
||||
let mut result = Vec::with_capacity(parent_len + len);
|
||||
result.extend(self.0.iter().take(parent_len).cloned());
|
||||
result.extend(replace_by);
|
||||
Substs(result.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
|
||||
@ -1367,15 +1378,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
|
||||
}
|
||||
ret_ty
|
||||
}
|
||||
Expr::MethodCall { receiver, args, method_name } => {
|
||||
Expr::MethodCall { receiver, args, method_name, generic_args } => {
|
||||
let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
|
||||
let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
|
||||
let method_ty = match resolved {
|
||||
let (method_ty, def_generics) = match resolved {
|
||||
Some(func) => {
|
||||
self.write_method_resolution(tgt_expr, func);
|
||||
self.db.type_for_def(func.into())
|
||||
(self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
|
||||
}
|
||||
None => Ty::Unknown,
|
||||
None => (Ty::Unknown, None),
|
||||
};
|
||||
// handle provided type arguments
|
||||
let method_ty = if let Some(generic_args) = generic_args {
|
||||
// if args are provided, it should be all of them, but we can't rely on that
|
||||
let param_count = def_generics.map(|g| g.params.len()).unwrap_or(0);
|
||||
let mut new_substs = Vec::with_capacity(generic_args.args.len());
|
||||
for arg in generic_args.args.iter().take(param_count) {
|
||||
match arg {
|
||||
GenericArg::Type(type_ref) => {
|
||||
let ty = self.make_ty(type_ref);
|
||||
new_substs.push(ty);
|
||||
}
|
||||
}
|
||||
}
|
||||
let substs = method_ty.substs().unwrap_or_else(Substs::empty);
|
||||
let substs = substs.replace_tail(new_substs);
|
||||
method_ty.apply_substs(substs)
|
||||
} else {
|
||||
method_ty
|
||||
};
|
||||
let method_ty = self.insert_type_vars(method_ty);
|
||||
let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
|
||||
|
@ -1,5 +1,5 @@
|
||||
---
|
||||
created: "2019-02-16T20:53:59.657979128Z"
|
||||
created: "2019-02-16T21:58:14.029368845Z"
|
||||
creator: insta@0.6.2
|
||||
source: crates/ra_hir/src/ty/tests.rs
|
||||
expression: "&result"
|
||||
@ -34,6 +34,6 @@ expression: "&result"
|
||||
[309; 319) 'a.z(1i128)': (u64, i64, i128)
|
||||
[313; 318) '1i128': i128
|
||||
[325; 326) 'a': A<u64, i64>
|
||||
[325; 339) 'a.z::<u128>(1)': (u64, i64, i32)
|
||||
[337; 338) '1': i32
|
||||
[325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
|
||||
[337; 338) '1': u128
|
||||
|
||||
|
@ -2095,6 +2095,10 @@ impl MethodCallExpr {
|
||||
pub fn name_ref(&self) -> Option<&NameRef> {
|
||||
super::child_opt(self)
|
||||
}
|
||||
|
||||
pub fn type_arg_list(&self) -> Option<&TypeArgList> {
|
||||
super::child_opt(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Module
|
||||
|
@ -431,7 +431,7 @@ Grammar(
|
||||
),
|
||||
"MethodCallExpr": (
|
||||
traits: ["ArgListOwner"],
|
||||
options: [ "Expr", "NameRef" ],
|
||||
options: [ "Expr", "NameRef", "TypeArgList" ],
|
||||
),
|
||||
"IndexExpr": (),
|
||||
"FieldExpr": (options: ["Expr", "NameRef"]),
|
||||
|
Loading…
x
Reference in New Issue
Block a user