From a1bda3fc084bb6aa4979282b4907db9885fac9af Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 16 Feb 2019 23:05:57 +0100 Subject: Handle generic args for method calls --- crates/ra_hir/src/expr.rs | 9 +++-- crates/ra_hir/src/path.rs | 2 +- crates/ra_hir/src/ty.rs | 38 +++++++++++++++++++--- .../ty/snapshots/tests__infer_impl_generics.snap | 6 ++-- 4 files changed, 45 insertions(+), 10 deletions(-) (limited to 'crates/ra_hir') diff --git a/crates/ra_hir/src/expr.rs b/crates/ra_hir/src/expr.rs index 4e73590d0..e9db8282f 100644 --- a/crates/ra_hir/src/expr.rs +++ b/crates/ra_hir/src/expr.rs @@ -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, + generic_args: Option, }, 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()); diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs index 8ed54607a..83bbbb741 100644 --- a/crates/ra_hir/src/path.rs +++ b/crates/ra_hir/src/path.rs @@ -129,7 +129,7 @@ impl Path { } impl GenericArgs { - fn from_ast(node: &ast::TypeArgList) -> Option { + pub fn from_ast(node: &ast::TypeArgList) -> Option { let mut args = Vec::new(); for type_arg in node.type_args() { let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index db0a20514..f32c77faf 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -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) -> 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), + }; + // 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); + } + } } - None => Ty::Unknown, + 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 { diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap index eabbe52fd..44f00a52e 100644 --- a/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap +++ b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap @@ -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 -[325; 339) 'a.z::(1)': (u64, i64, i32) -[337; 338) '1': i32 +[325; 339) 'a.z::(1)': (u64, i64, u128) +[337; 338) '1': u128 -- cgit v1.2.3