aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbors[bot] <bors[bot]@users.noreply.github.com>2019-02-17 13:56:22 +0000
committerbors[bot] <bors[bot]@users.noreply.github.com>2019-02-17 13:56:22 +0000
commitf937d11ad892036fa93b25a2c19d10dcebe4ab24 (patch)
tree71f3719509f3fb46f5d2ce5a93da42ea67b23b70
parentedd4c1d8a6c270fe39ae881c23c722c658c87c32 (diff)
parent3c7c7e5a04306f8b68dffef2b5ca84628ed81ce2 (diff)
Merge #843
843: Impl generics r=matklad a=flodiebold This handles type parameters on impls when typing method calls. ~One remaining problem is that the autoderefs aren't applied during the unification of the method receiver type with the actual receiver type, which means that the type parameters are only correctly inferred if no autoderefs happened.~ Co-authored-by: Florian Diebold <[email protected]>
-rw-r--r--crates/ra_hir/src/code_model_api.rs36
-rw-r--r--crates/ra_hir/src/code_model_impl/function.rs13
-rw-r--r--crates/ra_hir/src/expr.rs9
-rw-r--r--crates/ra_hir/src/generics.rs42
-rw-r--r--crates/ra_hir/src/ids.rs3
-rw-r--r--crates/ra_hir/src/impl_block.rs20
-rw-r--r--crates/ra_hir/src/path.rs2
-rw-r--r--crates/ra_hir/src/ty.rs65
-rw-r--r--crates/ra_hir/src/ty/method_resolution.rs12
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap54
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap39
-rw-r--r--crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap16
-rw-r--r--crates/ra_hir/src/ty/tests.rs52
-rw-r--r--crates/ra_ide_api/src/completion/complete_dot.rs2
-rw-r--r--crates/ra_syntax/src/ast/generated.rs5
-rw-r--r--crates/ra_syntax/src/grammar.ron4
16 files changed, 290 insertions, 84 deletions
diff --git a/crates/ra_hir/src/code_model_api.rs b/crates/ra_hir/src/code_model_api.rs
index 99f004905..26ebc445b 100644
--- a/crates/ra_hir/src/code_model_api.rs
+++ b/crates/ra_hir/src/code_model_api.rs
@@ -463,7 +463,7 @@ impl Function {
463 self.id.source(db) 463 self.id.source(db)
464 } 464 }
465 465
466 pub fn module(&self, db: &impl HirDatabase) -> Module { 466 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
467 self.id.module(db) 467 self.id.module(db)
468 } 468 }
469 469
@@ -497,6 +497,12 @@ impl Function {
497 db.generic_params((*self).into()) 497 db.generic_params((*self).into())
498 } 498 }
499 499
500 /// The containing impl block, if this is a method.
501 pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
502 let module_impls = db.impls_in_module(self.module(db));
503 ImplBlock::containing(module_impls, (*self).into())
504 }
505
500 // TODO: move to a more general type for 'body-having' items 506 // TODO: move to a more general type for 'body-having' items
501 /// Builds a resolver for code inside this item. 507 /// Builds a resolver for code inside this item.
502 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 508 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
@@ -527,6 +533,16 @@ impl Const {
527 pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) { 533 pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) {
528 self.id.source(db) 534 self.id.source(db)
529 } 535 }
536
537 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
538 self.id.module(db)
539 }
540
541 /// The containing impl block, if this is a method.
542 pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
543 let module_impls = db.impls_in_module(self.module(db));
544 ImplBlock::containing(module_impls, (*self).into())
545 }
530} 546}
531 547
532impl Docs for Const { 548impl Docs for Const {
@@ -544,6 +560,10 @@ impl Static {
544 pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) { 560 pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) {
545 self.id.source(db) 561 self.id.source(db)
546 } 562 }
563
564 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
565 self.id.module(db)
566 }
547} 567}
548 568
549impl Docs for Static { 569impl Docs for Static {
@@ -562,6 +582,10 @@ impl Trait {
562 self.id.source(db) 582 self.id.source(db)
563 } 583 }
564 584
585 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
586 self.id.module(db)
587 }
588
565 pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> { 589 pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
566 db.generic_params((*self).into()) 590 db.generic_params((*self).into())
567 } 591 }
@@ -586,6 +610,16 @@ impl Type {
586 pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> { 610 pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
587 db.generic_params((*self).into()) 611 db.generic_params((*self).into())
588 } 612 }
613
614 pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
615 self.id.module(db)
616 }
617
618 /// The containing impl block, if this is a method.
619 pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
620 let module_impls = db.impls_in_module(self.module(db));
621 ImplBlock::containing(module_impls, (*self).into())
622 }
589} 623}
590 624
591impl Docs for Type { 625impl Docs for Type {
diff --git a/crates/ra_hir/src/code_model_impl/function.rs b/crates/ra_hir/src/code_model_impl/function.rs
index b9438fdb7..c401528c6 100644
--- a/crates/ra_hir/src/code_model_impl/function.rs
+++ b/crates/ra_hir/src/code_model_impl/function.rs
@@ -3,22 +3,11 @@ use std::sync::Arc;
3use ra_syntax::ast::{self, NameOwner}; 3use ra_syntax::ast::{self, NameOwner};
4 4
5use crate::{ 5use crate::{
6 HirDatabase, Name, AsName, Function, FnSignature, 6 Name, AsName, Function, FnSignature,
7 type_ref::{TypeRef, Mutability}, 7 type_ref::{TypeRef, Mutability},
8 PersistentHirDatabase, 8 PersistentHirDatabase,
9 impl_block::ImplBlock,
10}; 9};
11 10
12impl Function {
13 // TODO impl_block should probably also be part of the code model API?
14
15 /// The containing impl block, if this is a method.
16 pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option<ImplBlock> {
17 let module_impls = db.impls_in_module(self.module(db));
18 ImplBlock::containing(module_impls, (*self).into())
19 }
20}
21
22impl FnSignature { 11impl FnSignature {
23 pub(crate) fn fn_signature_query( 12 pub(crate) fn fn_signature_query(
24 db: &impl PersistentHirDatabase, 13 db: &impl PersistentHirDatabase,
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::{
14 name::AsName, 14 name::AsName,
15 type_ref::{Mutability, TypeRef}, 15 type_ref::{Mutability, TypeRef},
16}; 16};
17use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; 17use crate::{ path::GenericArgs, ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}};
18 18
19pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; 19pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax};
20 20
@@ -193,6 +193,7 @@ pub enum Expr {
193 receiver: ExprId, 193 receiver: ExprId,
194 method_name: Name, 194 method_name: Name,
195 args: Vec<ExprId>, 195 args: Vec<ExprId>,
196 generic_args: Option<GenericArgs>,
196 }, 197 },
197 Match { 198 Match {
198 expr: ExprId, 199 expr: ExprId,
@@ -597,7 +598,11 @@ impl ExprCollector {
597 Vec::new() 598 Vec::new()
598 }; 599 };
599 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing); 600 let method_name = e.name_ref().map(|nr| nr.as_name()).unwrap_or_else(Name::missing);
600 self.alloc_expr(Expr::MethodCall { receiver, method_name, args }, syntax_ptr) 601 let generic_args = e.type_arg_list().and_then(GenericArgs::from_ast);
602 self.alloc_expr(
603 Expr::MethodCall { receiver, method_name, args, generic_args },
604 syntax_ptr,
605 )
601 } 606 }
602 ast::ExprKind::MatchExpr(e) => { 607 ast::ExprKind::MatchExpr(e) => {
603 let expr = self.collect_expr_opt(e.expr()); 608 let expr = self.collect_expr_opt(e.expr());
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs
index c72360f44..fcc513353 100644
--- a/crates/ra_hir/src/generics.rs
+++ b/crates/ra_hir/src/generics.rs
@@ -7,7 +7,7 @@ use std::sync::Arc;
7 7
8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; 8use ra_syntax::ast::{self, NameOwner, TypeParamsOwner};
9 9
10use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type}; 10use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type, ImplBlock};
11 11
12/// Data about a generic parameter (to a function, struct, impl, ...). 12/// Data about a generic parameter (to a function, struct, impl, ...).
13#[derive(Clone, PartialEq, Eq, Debug)] 13#[derive(Clone, PartialEq, Eq, Debug)]
@@ -20,6 +20,7 @@ pub struct GenericParam {
20/// Data about the generic parameters of a function, struct, impl, etc. 20/// Data about the generic parameters of a function, struct, impl, etc.
21#[derive(Clone, PartialEq, Eq, Debug, Default)] 21#[derive(Clone, PartialEq, Eq, Debug, Default)]
22pub struct GenericParams { 22pub struct GenericParams {
23 pub(crate) parent_params: Option<Arc<GenericParams>>,
23 pub(crate) params: Vec<GenericParam>, 24 pub(crate) params: Vec<GenericParam>,
24} 25}
25 26
@@ -30,8 +31,9 @@ pub enum GenericDef {
30 Enum(Enum), 31 Enum(Enum),
31 Trait(Trait), 32 Trait(Trait),
32 Type(Type), 33 Type(Type),
34 ImplBlock(ImplBlock),
33} 35}
34impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type); 36impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type, ImplBlock);
35 37
36impl GenericParams { 38impl GenericParams {
37 pub(crate) fn generic_params_query( 39 pub(crate) fn generic_params_query(
@@ -39,27 +41,36 @@ impl GenericParams {
39 def: GenericDef, 41 def: GenericDef,
40 ) -> Arc<GenericParams> { 42 ) -> Arc<GenericParams> {
41 let mut generics = GenericParams::default(); 43 let mut generics = GenericParams::default();
44 let parent = match def {
45 GenericDef::Function(it) => it.impl_block(db),
46 GenericDef::Type(it) => it.impl_block(db),
47 GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None,
48 GenericDef::ImplBlock(_) => None,
49 };
50 generics.parent_params = parent.map(|p| p.generic_params(db));
51 let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32;
42 match def { 52 match def {
43 GenericDef::Function(it) => generics.fill(&*it.source(db).1), 53 GenericDef::Function(it) => generics.fill(&*it.source(db).1, start),
44 GenericDef::Struct(it) => generics.fill(&*it.source(db).1), 54 GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
45 GenericDef::Enum(it) => generics.fill(&*it.source(db).1), 55 GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
46 GenericDef::Trait(it) => generics.fill(&*it.source(db).1), 56 GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start),
47 GenericDef::Type(it) => generics.fill(&*it.source(db).1), 57 GenericDef::Type(it) => generics.fill(&*it.source(db).1, start),
58 GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
48 } 59 }
49 60
50 Arc::new(generics) 61 Arc::new(generics)
51 } 62 }
52 63
53 fn fill(&mut self, node: &impl TypeParamsOwner) { 64 fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) {
54 if let Some(params) = node.type_param_list() { 65 if let Some(params) = node.type_param_list() {
55 self.fill_params(params) 66 self.fill_params(params, start)
56 } 67 }
57 } 68 }
58 69
59 fn fill_params(&mut self, params: &ast::TypeParamList) { 70 fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) {
60 for (idx, type_param) in params.type_params().enumerate() { 71 for (idx, type_param) in params.type_params().enumerate() {
61 let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); 72 let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing);
62 let param = GenericParam { idx: idx as u32, name }; 73 let param = GenericParam { idx: idx as u32 + start, name };
63 self.params.push(param); 74 self.params.push(param);
64 } 75 }
65 } 76 }
@@ -67,4 +78,13 @@ impl GenericParams {
67 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { 78 pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
68 self.params.iter().find(|p| &p.name == name) 79 self.params.iter().find(|p| &p.name == name)
69 } 80 }
81
82 pub fn count_parent_params(&self) -> usize {
83 self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0)
84 }
85
86 pub fn count_params_including_parent(&self) -> usize {
87 let parent_count = self.count_parent_params();
88 parent_count + self.params.len()
89 }
70} 90}
diff --git a/crates/ra_hir/src/ids.rs b/crates/ra_hir/src/ids.rs
index 3e11dd6ad..6df037859 100644
--- a/crates/ra_hir/src/ids.rs
+++ b/crates/ra_hir/src/ids.rs
@@ -9,7 +9,6 @@ use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast};
9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; 9use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
10 10
11use crate::{ 11use crate::{
12 HirDatabase,
13 Module, 12 Module,
14 PersistentHirDatabase, 13 PersistentHirDatabase,
15}; 14};
@@ -215,7 +214,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
215 N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned(); 214 N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
216 (loc.raw.file_id, ast) 215 (loc.raw.file_id, ast)
217 } 216 }
218 fn module(self, db: &impl HirDatabase) -> Module { 217 fn module(self, db: &impl PersistentHirDatabase) -> Module {
219 let int = Self::interner(db.as_ref()); 218 let int = Self::interner(db.as_ref());
220 let loc = int.id2loc(self); 219 let loc = int.id2loc(self);
221 loc.module 220 loc.module
diff --git a/crates/ra_hir/src/impl_block.rs b/crates/ra_hir/src/impl_block.rs
index 4d8bdf33a..7ecf8c368 100644
--- a/crates/ra_hir/src/impl_block.rs
+++ b/crates/ra_hir/src/impl_block.rs
@@ -13,7 +13,7 @@ use crate::{
13 type_ref::TypeRef, 13 type_ref::TypeRef,
14 ids::LocationCtx, 14 ids::LocationCtx,
15 resolve::Resolver, 15 resolve::Resolver,
16 ty::Ty, 16 ty::Ty, generics::GenericParams
17}; 17};
18 18
19use crate::code_model_api::{Module, ModuleSource}; 19use crate::code_model_api::{Module, ModuleSource};
@@ -38,7 +38,7 @@ impl ImplSourceMap {
38 } 38 }
39} 39}
40 40
41#[derive(Debug, Clone, Copy, PartialEq, Eq)] 41#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
42pub struct ImplBlock { 42pub struct ImplBlock {
43 module: Module, 43 module: Module,
44 impl_id: ImplId, 44 impl_id: ImplId,
@@ -58,7 +58,7 @@ impl ImplBlock {
58 } 58 }
59 59
60 /// Returns the syntax of the impl block 60 /// Returns the syntax of the impl block
61 pub fn source(&self, db: &impl HirDatabase) -> (HirFileId, TreeArc<ast::ImplBlock>) { 61 pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ImplBlock>) {
62 let source_map = db.impls_in_module_source_map(self.module); 62 let source_map = db.impls_in_module_source_map(self.module);
63 let (file_id, source) = self.module.definition_source(db); 63 let (file_id, source) = self.module.definition_source(db);
64 (file_id, source_map.get(&source, self.impl_id)) 64 (file_id, source_map.get(&source, self.impl_id))
@@ -72,11 +72,11 @@ impl ImplBlock {
72 self.module 72 self.module
73 } 73 }
74 74
75 pub fn target_trait_ref(&self, db: &impl HirDatabase) -> Option<TypeRef> { 75 pub fn target_trait_ref(&self, db: &impl PersistentHirDatabase) -> Option<TypeRef> {
76 db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned() 76 db.impls_in_module(self.module).impls[self.impl_id].target_trait().cloned()
77 } 77 }
78 78
79 pub fn target_type(&self, db: &impl HirDatabase) -> TypeRef { 79 pub fn target_type(&self, db: &impl PersistentHirDatabase) -> TypeRef {
80 db.impls_in_module(self.module).impls[self.impl_id].target_type().clone() 80 db.impls_in_module(self.module).impls[self.impl_id].target_type().clone()
81 } 81 }
82 82
@@ -96,13 +96,19 @@ impl ImplBlock {
96 None 96 None
97 } 97 }
98 98
99 pub fn items(&self, db: &impl HirDatabase) -> Vec<ImplItem> { 99 pub fn items(&self, db: &impl PersistentHirDatabase) -> Vec<ImplItem> {
100 db.impls_in_module(self.module).impls[self.impl_id].items().to_vec() 100 db.impls_in_module(self.module).impls[self.impl_id].items().to_vec()
101 } 101 }
102 102
103 pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
104 db.generic_params((*self).into())
105 }
106
103 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { 107 pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
104 let r = self.module().resolver(db); 108 let r = self.module().resolver(db);
105 // TODO: add generics 109 // add generic params, if present
110 let p = self.generic_params(db);
111 let r = if !p.params.is_empty() { r.push_generic_params_scope(p) } else { r };
106 let r = r.push_impl_block_scope(self.clone()); 112 let r = r.push_impl_block_scope(self.clone());
107 r 113 r
108 } 114 }
diff --git a/crates/ra_hir/src/path.rs b/crates/ra_hir/src/path.rs
index 8ed54607a..6ca373e34 100644
--- a/crates/ra_hir/src/path.rs
+++ b/crates/ra_hir/src/path.rs
@@ -129,7 +129,7 @@ impl Path {
129} 129}
130 130
131impl GenericArgs { 131impl GenericArgs {
132 fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> { 132 pub(crate) fn from_ast(node: &ast::TypeArgList) -> Option<GenericArgs> {
133 let mut args = Vec::new(); 133 let mut args = Vec::new();
134 for type_arg in node.type_args() { 134 for type_arg in node.type_args() {
135 let type_ref = TypeRef::from_ast_opt(type_arg.type_ref()); 135 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 f28a7e731..562ad1f49 100644
--- a/crates/ra_hir/src/ty.rs
+++ b/crates/ra_hir/src/ty.rs
@@ -165,6 +165,17 @@ impl Substs {
165 pub fn empty() -> Substs { 165 pub fn empty() -> Substs {
166 Substs(Arc::new([])) 166 Substs(Arc::new([]))
167 } 167 }
168
169 /// Replaces the end of the substitutions by other ones.
170 pub(crate) fn replace_tail(self, replace_by: Vec<Ty>) -> Substs {
171 // again missing Arc::make_mut_slice...
172 let len = replace_by.len().min(self.0.len());
173 let parent_len = self.0.len() - len;
174 let mut result = Vec::with_capacity(parent_len + len);
175 result.extend(self.0.iter().take(parent_len).cloned());
176 result.extend(replace_by);
177 Substs(result.into())
178 }
168} 179}
169 180
170/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs). 181/// A type. This is based on the `TyKind` enum in rustc (librustc/ty/sty.rs).
@@ -421,7 +432,8 @@ impl Ty {
421 (var.parent_enum(db).generic_params(db), segment) 432 (var.parent_enum(db).generic_params(db), segment)
422 } 433 }
423 }; 434 };
424 // substs_from_path 435 let parent_param_count = def_generics.count_parent_params();
436 substs.extend((0..parent_param_count).map(|_| Ty::Unknown));
425 if let Some(generic_args) = &segment.args_and_bindings { 437 if let Some(generic_args) = &segment.args_and_bindings {
426 // if args are provided, it should be all of them, but we can't rely on that 438 // if args are provided, it should be all of them, but we can't rely on that
427 let param_count = def_generics.params.len(); 439 let param_count = def_generics.params.len();
@@ -436,9 +448,8 @@ impl Ty {
436 } 448 }
437 // add placeholders for args that were not provided 449 // add placeholders for args that were not provided
438 // TODO: handle defaults 450 // TODO: handle defaults
439 let supplied_params = 451 let supplied_params = substs.len();
440 segment.args_and_bindings.as_ref().map(|ga| ga.args.len()).unwrap_or(0); 452 for _ in supplied_params..def_generics.count_params_including_parent() {
441 for _ in supplied_params..def_generics.params.len() {
442 substs.push(Ty::Unknown); 453 substs.push(Ty::Unknown);
443 } 454 }
444 assert_eq!(substs.len(), def_generics.params.len()); 455 assert_eq!(substs.len(), def_generics.params.len());
@@ -666,7 +677,12 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty {
666} 677}
667 678
668fn make_substs(generics: &GenericParams) -> Substs { 679fn make_substs(generics: &GenericParams) -> Substs {
669 Substs(generics.params.iter().map(|_p| Ty::Unknown).collect::<Vec<_>>().into()) 680 Substs(
681 (0..generics.count_params_including_parent())
682 .map(|_p| Ty::Unknown)
683 .collect::<Vec<_>>()
684 .into(),
685 )
670} 686}
671 687
672fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 688fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {
@@ -1362,15 +1378,34 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1362 } 1378 }
1363 ret_ty 1379 ret_ty
1364 } 1380 }
1365 Expr::MethodCall { receiver, args, method_name } => { 1381 Expr::MethodCall { receiver, args, method_name, generic_args } => {
1366 let receiver_ty = self.infer_expr(*receiver, &Expectation::none()); 1382 let receiver_ty = self.infer_expr(*receiver, &Expectation::none());
1367 let resolved = receiver_ty.clone().lookup_method(self.db, method_name); 1383 let resolved = receiver_ty.clone().lookup_method(self.db, method_name);
1368 let method_ty = match resolved { 1384 let (derefed_receiver_ty, method_ty, def_generics) = match resolved {
1369 Some(func) => { 1385 Some((ty, func)) => {
1370 self.write_method_resolution(tgt_expr, func); 1386 self.write_method_resolution(tgt_expr, func);
1371 self.db.type_for_def(func.into()) 1387 (ty, self.db.type_for_def(func.into()), Some(func.generic_params(self.db)))
1388 }
1389 None => (Ty::Unknown, receiver_ty, None),
1390 };
1391 // handle provided type arguments
1392 let method_ty = if let Some(generic_args) = generic_args {
1393 // if args are provided, it should be all of them, but we can't rely on that
1394 let param_count = def_generics.map(|g| g.params.len()).unwrap_or(0);
1395 let mut new_substs = Vec::with_capacity(generic_args.args.len());
1396 for arg in generic_args.args.iter().take(param_count) {
1397 match arg {
1398 GenericArg::Type(type_ref) => {
1399 let ty = self.make_ty(type_ref);
1400 new_substs.push(ty);
1401 }
1402 }
1372 } 1403 }
1373 None => Ty::Unknown, 1404 let substs = method_ty.substs().unwrap_or_else(Substs::empty);
1405 let substs = substs.replace_tail(new_substs);
1406 method_ty.apply_substs(substs)
1407 } else {
1408 method_ty
1374 }; 1409 };
1375 let method_ty = self.insert_type_vars(method_ty); 1410 let method_ty = self.insert_type_vars(method_ty);
1376 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty { 1411 let (expected_receiver_ty, param_tys, ret_ty) = match &method_ty {
@@ -1394,9 +1429,13 @@ impl<'a, D: HirDatabase> InferenceContext<'a, D> {
1394 } 1429 }
1395 _ => (Ty::Unknown, Vec::new(), Ty::Unknown), 1430 _ => (Ty::Unknown, Vec::new(), Ty::Unknown),
1396 }; 1431 };
1397 // TODO we would have to apply the autoderef/autoref steps here 1432 // Apply autoref so the below unification works correctly
1398 // to get the correct receiver type to unify... 1433 let actual_receiver_ty = match expected_receiver_ty {
1399 self.unify(&expected_receiver_ty, &receiver_ty); 1434 Ty::Ref(_, mutability) => Ty::Ref(Arc::new(derefed_receiver_ty), mutability),
1435 _ => derefed_receiver_ty,
1436 };
1437 self.unify(&expected_receiver_ty, &actual_receiver_ty);
1438
1400 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown)); 1439 let param_iter = param_tys.into_iter().chain(repeat(Ty::Unknown));
1401 for (arg, param) in args.iter().zip(param_iter) { 1440 for (arg, param) in args.iter().zip(param_iter) {
1402 self.infer_expr(*arg, &Expectation::has_type(param)); 1441 self.infer_expr(*arg, &Expectation::has_type(param));
diff --git a/crates/ra_hir/src/ty/method_resolution.rs b/crates/ra_hir/src/ty/method_resolution.rs
index 8d1076774..94b757af2 100644
--- a/crates/ra_hir/src/ty/method_resolution.rs
+++ b/crates/ra_hir/src/ty/method_resolution.rs
@@ -118,11 +118,13 @@ impl Ty {
118 // TODO: cache this as a query? 118 // TODO: cache this as a query?
119 // - if so, what signature? (TyFingerprint, Name)? 119 // - if so, what signature? (TyFingerprint, Name)?
120 // - or maybe cache all names and def_ids of methods per fingerprint? 120 // - or maybe cache all names and def_ids of methods per fingerprint?
121 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<Function> { 121 /// Look up the method with the given name, returning the actual autoderefed
122 self.iterate_methods(db, |f| { 122 /// receiver type (but without autoref applied yet).
123 pub fn lookup_method(self, db: &impl HirDatabase, name: &Name) -> Option<(Ty, Function)> {
124 self.iterate_methods(db, |ty, f| {
123 let sig = f.signature(db); 125 let sig = f.signature(db);
124 if sig.name() == name && sig.has_self_param() { 126 if sig.name() == name && sig.has_self_param() {
125 Some(f) 127 Some((ty.clone(), f))
126 } else { 128 } else {
127 None 129 None
128 } 130 }
@@ -134,7 +136,7 @@ impl Ty {
134 pub fn iterate_methods<T>( 136 pub fn iterate_methods<T>(
135 self, 137 self,
136 db: &impl HirDatabase, 138 db: &impl HirDatabase,
137 mut callback: impl FnMut(Function) -> Option<T>, 139 mut callback: impl FnMut(&Ty, Function) -> Option<T>,
138 ) -> Option<T> { 140 ) -> Option<T> {
139 // For method calls, rust first does any number of autoderef, and then one 141 // For method calls, rust first does any number of autoderef, and then one
140 // autoref (i.e. when the method takes &self or &mut self). We just ignore 142 // autoref (i.e. when the method takes &self or &mut self). We just ignore
@@ -156,7 +158,7 @@ impl Ty {
156 for item in impl_block.items(db) { 158 for item in impl_block.items(db) {
157 match item { 159 match item {
158 ImplItem::Method(f) => { 160 ImplItem::Method(f) => {
159 if let Some(result) = callback(f) { 161 if let Some(result) = callback(&derefed_ty, f) {
160 return Some(result); 162 return Some(result);
161 } 163 }
162 } 164 }
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
index 626f31252..d1ce87b0a 100644
--- a/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap
@@ -1,36 +1,36 @@
1--- 1---
2created: "2019-01-27T14:52:29.938713255+00:00" 2created: "2019-02-16T20:53:59.655361804Z"
3creator: [email protected] 3creator: [email protected]
4expression: "&result"
5source: crates/ra_hir/src/ty/tests.rs 4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6--- 6---
7[53; 57) 'self': A<[unknown]> 7[53; 57) 'self': A<T2>
8[65; 87) '{ ... }': [unknown] 8[65; 87) '{ ... }': T2
9[75; 79) 'self': A<[unknown]> 9[75; 79) 'self': A<T2>
10[75; 81) 'self.x': [unknown] 10[75; 81) 'self.x': T2
11[99; 100) 't': T 11[99; 100) 't': T
12[110; 115) '{ t }': T 12[110; 115) '{ t }': T
13[112; 113) 't': T 13[112; 113) 't': T
14[135; 261) '{ ....x() }': i128 14[135; 261) '{ ....x() }': i128
15[146; 147) 'x': i32 15[146; 147) 'x': i128
16[150; 151) '1': i32 16[150; 151) '1': i128
17[162; 163) 'y': i32 17[162; 163) 'y': i128
18[166; 168) 'id': fn id<i32>(T) -> T 18[166; 168) 'id': fn id<i128>(T) -> T
19[166; 171) 'id(x)': i32 19[166; 171) 'id(x)': i128
20[169; 170) 'x': i32 20[169; 170) 'x': i128
21[182; 183) 'a': A<i32> 21[182; 183) 'a': A<i128>
22[186; 200) 'A { x: id(y) }': A<i32> 22[186; 200) 'A { x: id(y) }': A<i128>
23[193; 195) 'id': fn id<i32>(T) -> T 23[193; 195) 'id': fn id<i128>(T) -> T
24[193; 198) 'id(y)': i32 24[193; 198) 'id(y)': i128
25[196; 197) 'y': i32 25[196; 197) 'y': i128
26[211; 212) 'z': i32 26[211; 212) 'z': i128
27[215; 217) 'id': fn id<i32>(T) -> T 27[215; 217) 'id': fn id<i128>(T) -> T
28[215; 222) 'id(a.x)': i32 28[215; 222) 'id(a.x)': i128
29[218; 219) 'a': A<i32> 29[218; 219) 'a': A<i128>
30[218; 221) 'a.x': i32 30[218; 221) 'a.x': i128
31[233; 234) 'b': A<i32> 31[233; 234) 'b': A<i128>
32[237; 247) 'A { x: z }': A<i32> 32[237; 247) 'A { x: z }': A<i128>
33[244; 245) 'z': i32 33[244; 245) 'z': i128
34[254; 255) 'b': A<i32> 34[254; 255) 'b': A<i128>
35[254; 259) 'b.x()': i128 35[254; 259) 'b.x()': i128
36 36
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
new file mode 100644
index 000000000..44f00a52e
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap
@@ -0,0 +1,39 @@
1---
2created: "2019-02-16T21:58:14.029368845Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[74; 78) 'self': A<X, Y>
8[85; 107) '{ ... }': X
9[95; 99) 'self': A<X, Y>
10[95; 101) 'self.x': X
11[117; 121) 'self': A<X, Y>
12[128; 150) '{ ... }': Y
13[138; 142) 'self': A<X, Y>
14[138; 144) 'self.y': Y
15[163; 167) 'self': A<X, Y>
16[169; 170) 't': T
17[188; 223) '{ ... }': (X, Y, T)
18[198; 217) '(self.....y, t)': (X, Y, T)
19[199; 203) 'self': A<X, Y>
20[199; 205) 'self.x': X
21[207; 211) 'self': A<X, Y>
22[207; 213) 'self.y': Y
23[215; 216) 't': T
24[245; 342) '{ ...(1); }': ()
25[255; 256) 'a': A<u64, i64>
26[259; 281) 'A { x:...1i64 }': A<u64, i64>
27[266; 270) '1u64': u64
28[275; 279) '1i64': i64
29[287; 288) 'a': A<u64, i64>
30[287; 292) 'a.x()': u64
31[298; 299) 'a': A<u64, i64>
32[298; 303) 'a.y()': i64
33[309; 310) 'a': A<u64, i64>
34[309; 319) 'a.z(1i128)': (u64, i64, i128)
35[313; 318) '1i128': i128
36[325; 326) 'a': A<u64, i64>
37[325; 339) 'a.z::<u128>(1)': (u64, i64, u128)
38[337; 338) '1': u128
39
diff --git a/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap
new file mode 100644
index 000000000..f609eaf7c
--- /dev/null
+++ b/crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap
@@ -0,0 +1,16 @@
1---
2created: "2019-02-17T13:35:06.385679926Z"
3creator: [email protected]
4source: crates/ra_hir/src/ty/tests.rs
5expression: "&result"
6---
7[78; 82) 'self': &Option<T>
8[98; 100) '{}': ()
9[111; 112) 'o': Option<u32>
10[127; 165) '{ ...f(); }': ()
11[133; 146) '(&o).as_ref()': Option<&u32>
12[134; 136) '&o': &Option<u32>
13[135; 136) 'o': Option<u32>
14[152; 153) 'o': Option<u32>
15[152; 162) 'o.as_ref()': Option<&u32>
16
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs
index 203f1fe4d..5eb9c4f5b 100644
--- a/crates/ra_hir/src/ty/tests.rs
+++ b/crates/ra_hir/src/ty/tests.rs
@@ -507,6 +507,58 @@ fn test() {
507} 507}
508 508
509#[test] 509#[test]
510fn infer_impl_generics() {
511 check_inference(
512 "infer_impl_generics",
513 r#"
514struct A<T1, T2> {
515 x: T1,
516 y: T2,
517}
518impl<Y, X> A<X, Y> {
519 fn x(self) -> X {
520 self.x
521 }
522 fn y(self) -> Y {
523 self.y
524 }
525 fn z<T>(self, t: T) -> (X, Y, T) {
526 (self.x, self.y, t)
527 }
528}
529
530fn test() -> i128 {
531 let a = A { x: 1u64, y: 1i64 };
532 a.x();
533 a.y();
534 a.z(1i128);
535 a.z::<u128>(1);
536}
537"#,
538 );
539}
540
541#[test]
542fn infer_impl_generics_with_autoderef() {
543 check_inference(
544 "infer_impl_generics_with_autoderef",
545 r#"
546enum Option<T> {
547 Some(T),
548 None,
549}
550impl<T> Option<T> {
551 fn as_ref(&self) -> Option<&T> {}
552}
553fn test(o: Option<u32>) {
554 (&o).as_ref();
555 o.as_ref();
556}
557"#,
558 );
559}
560
561#[test]
510fn infer_generic_chain() { 562fn infer_generic_chain() {
511 check_inference( 563 check_inference(
512 "infer_generic_chain", 564 "infer_generic_chain",
diff --git a/crates/ra_ide_api/src/completion/complete_dot.rs b/crates/ra_ide_api/src/completion/complete_dot.rs
index be839345f..20fa323ce 100644
--- a/crates/ra_ide_api/src/completion/complete_dot.rs
+++ b/crates/ra_ide_api/src/completion/complete_dot.rs
@@ -63,7 +63,7 @@ fn complete_fields(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty)
63} 63}
64 64
65fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { 65fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) {
66 receiver.iterate_methods(ctx.db, |func| { 66 receiver.iterate_methods(ctx.db, |_ty, func| {
67 let sig = func.signature(ctx.db); 67 let sig = func.signature(ctx.db);
68 if sig.has_self_param() { 68 if sig.has_self_param() {
69 CompletionItem::new( 69 CompletionItem::new(
diff --git a/crates/ra_syntax/src/ast/generated.rs b/crates/ra_syntax/src/ast/generated.rs
index 7c5e8ce5e..dd91b5063 100644
--- a/crates/ra_syntax/src/ast/generated.rs
+++ b/crates/ra_syntax/src/ast/generated.rs
@@ -1352,6 +1352,7 @@ impl ToOwned for ImplBlock {
1352} 1352}
1353 1353
1354 1354
1355impl ast::TypeParamsOwner for ImplBlock {}
1355impl ImplBlock { 1356impl ImplBlock {
1356 pub fn item_list(&self) -> Option<&ItemList> { 1357 pub fn item_list(&self) -> Option<&ItemList> {
1357 super::child_opt(self) 1358 super::child_opt(self)
@@ -2094,6 +2095,10 @@ impl MethodCallExpr {
2094 pub fn name_ref(&self) -> Option<&NameRef> { 2095 pub fn name_ref(&self) -> Option<&NameRef> {
2095 super::child_opt(self) 2096 super::child_opt(self)
2096 } 2097 }
2098
2099 pub fn type_arg_list(&self) -> Option<&TypeArgList> {
2100 super::child_opt(self)
2101 }
2097} 2102}
2098 2103
2099// Module 2104// Module
diff --git a/crates/ra_syntax/src/grammar.ron b/crates/ra_syntax/src/grammar.ron
index 304bc5909..27a123681 100644
--- a/crates/ra_syntax/src/grammar.ron
+++ b/crates/ra_syntax/src/grammar.ron
@@ -322,7 +322,7 @@ Grammar(
322 ], 322 ],
323 options: ["TypeRef"] 323 options: ["TypeRef"]
324 ), 324 ),
325 "ImplBlock": (options: ["ItemList"]), 325 "ImplBlock": (options: ["ItemList"], traits: ["TypeParamsOwner"]),
326 326
327 "ParenType": (options: ["TypeRef"]), 327 "ParenType": (options: ["TypeRef"]),
328 "TupleType": ( collections: [["fields", "TypeRef"]] ), 328 "TupleType": ( collections: [["fields", "TypeRef"]] ),
@@ -431,7 +431,7 @@ Grammar(
431 ), 431 ),
432 "MethodCallExpr": ( 432 "MethodCallExpr": (
433 traits: ["ArgListOwner"], 433 traits: ["ArgListOwner"],
434 options: [ "Expr", "NameRef" ], 434 options: [ "Expr", "NameRef", "TypeArgList" ],
435 ), 435 ),
436 "IndexExpr": (), 436 "IndexExpr": (),
437 "FieldExpr": (options: ["Expr", "NameRef"]), 437 "FieldExpr": (options: ["Expr", "NameRef"]),