diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-17 13:56:22 +0000 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-02-17 13:56:22 +0000 |
commit | f937d11ad892036fa93b25a2c19d10dcebe4ab24 (patch) | |
tree | 71f3719509f3fb46f5d2ce5a93da42ea67b23b70 | |
parent | edd4c1d8a6c270fe39ae881c23c722c658c87c32 (diff) | |
parent | 3c7c7e5a04306f8b68dffef2b5ca84628ed81ce2 (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.rs | 36 | ||||
-rw-r--r-- | crates/ra_hir/src/code_model_impl/function.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/expr.rs | 9 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir/src/ids.rs | 3 | ||||
-rw-r--r-- | crates/ra_hir/src/impl_block.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir/src/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 65 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/method_resolution.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_generic_chain.snap | 54 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics.snap | 39 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/snapshots/tests__infer_impl_generics_with_autoderef.snap | 16 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 52 | ||||
-rw-r--r-- | crates/ra_ide_api/src/completion/complete_dot.rs | 2 | ||||
-rw-r--r-- | crates/ra_syntax/src/ast/generated.rs | 5 | ||||
-rw-r--r-- | crates/ra_syntax/src/grammar.ron | 4 |
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 | ||
532 | impl Docs for Const { | 548 | impl 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 | ||
549 | impl Docs for Static { | 569 | impl 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 | ||
591 | impl Docs for Type { | 625 | impl 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; | |||
3 | use ra_syntax::ast::{self, NameOwner}; | 3 | use ra_syntax::ast::{self, NameOwner}; |
4 | 4 | ||
5 | use crate::{ | 5 | use 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 | ||
12 | impl 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 | |||
22 | impl FnSignature { | 11 | impl 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 | }; |
17 | use crate::ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}; | 17 | use crate::{ path::GenericArgs, ty::primitive::{UintTy, UncertainIntTy, UncertainFloatTy}}; |
18 | 18 | ||
19 | pub use self::scope::{ExprScopes, ScopesWithSyntaxMapping, ScopeEntryWithSyntax}; | 19 | pub 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 | ||
8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; | 8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner}; |
9 | 9 | ||
10 | use crate::{db::PersistentHirDatabase, Name, AsName, Function, Struct, Enum, Trait, Type}; | 10 | use 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)] |
22 | pub struct GenericParams { | 22 | pub 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 | } |
34 | impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type); | 36 | impl_froms!(GenericDef: Function, Struct, Enum, Trait, Type, ImplBlock); |
35 | 37 | ||
36 | impl GenericParams { | 38 | impl 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}; | |||
9 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; | 9 | use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; |
10 | 10 | ||
11 | use crate::{ | 11 | use 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 | ||
19 | use crate::code_model_api::{Module, ModuleSource}; | 19 | use 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)] |
42 | pub struct ImplBlock { | 42 | pub 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 | ||
131 | impl GenericArgs { | 131 | impl 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 | ||
668 | fn make_substs(generics: &GenericParams) -> Substs { | 679 | fn 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 | ||
672 | fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { | 688 | fn 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 | --- |
2 | created: "2019-01-27T14:52:29.938713255+00:00" | 2 | created: "2019-02-16T20:53:59.655361804Z" |
3 | creator: [email protected] | 3 | creator: [email protected] |
4 | expression: "&result" | ||
5 | source: crates/ra_hir/src/ty/tests.rs | 4 | source: crates/ra_hir/src/ty/tests.rs |
5 | expression: "&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 | --- | ||
2 | created: "2019-02-16T21:58:14.029368845Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&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 | --- | ||
2 | created: "2019-02-17T13:35:06.385679926Z" | ||
3 | creator: [email protected] | ||
4 | source: crates/ra_hir/src/ty/tests.rs | ||
5 | expression: "&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] |
510 | fn infer_impl_generics() { | ||
511 | check_inference( | ||
512 | "infer_impl_generics", | ||
513 | r#" | ||
514 | struct A<T1, T2> { | ||
515 | x: T1, | ||
516 | y: T2, | ||
517 | } | ||
518 | impl<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 | |||
530 | fn 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] | ||
542 | fn infer_impl_generics_with_autoderef() { | ||
543 | check_inference( | ||
544 | "infer_impl_generics_with_autoderef", | ||
545 | r#" | ||
546 | enum Option<T> { | ||
547 | Some(T), | ||
548 | None, | ||
549 | } | ||
550 | impl<T> Option<T> { | ||
551 | fn as_ref(&self) -> Option<&T> {} | ||
552 | } | ||
553 | fn test(o: Option<u32>) { | ||
554 | (&o).as_ref(); | ||
555 | o.as_ref(); | ||
556 | } | ||
557 | "#, | ||
558 | ); | ||
559 | } | ||
560 | |||
561 | #[test] | ||
510 | fn infer_generic_chain() { | 562 | fn 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 | ||
65 | fn complete_methods(acc: &mut Completions, ctx: &CompletionContext, receiver: Ty) { | 65 | fn 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 | ||
1355 | impl ast::TypeParamsOwner for ImplBlock {} | ||
1355 | impl ImplBlock { | 1356 | impl 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"]), |