From 65bd9bc3a800e09f52a315cf98e86c120c366c2c Mon Sep 17 00:00:00 2001 From: Florian Diebold Date: Sat, 16 Feb 2019 22:06:23 +0100 Subject: Handle impl generics in method calls --- crates/ra_hir/src/code_model_api.rs | 36 ++++++++++++++- crates/ra_hir/src/code_model_impl/function.rs | 13 +----- crates/ra_hir/src/generics.rs | 38 +++++++++++---- crates/ra_hir/src/ids.rs | 3 +- crates/ra_hir/src/ty.rs | 15 ++++-- .../ty/snapshots/tests__infer_generic_chain.snap | 54 +++++++++++----------- .../ty/snapshots/tests__infer_impl_generics.snap | 40 ++++++++-------- 7 files changed, 122 insertions(+), 77 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 { self.id.source(db) } - pub fn module(&self, db: &impl HirDatabase) -> Module { + pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { self.id.module(db) } @@ -497,6 +497,12 @@ impl Function { db.generic_params((*self).into()) } + /// The containing impl block, if this is a method. + pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option { + let module_impls = db.impls_in_module(self.module(db)); + ImplBlock::containing(module_impls, (*self).into()) + } + // TODO: move to a more general type for 'body-having' items /// Builds a resolver for code inside this item. pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { @@ -527,6 +533,16 @@ impl Const { pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc) { self.id.source(db) } + + pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { + self.id.module(db) + } + + /// The containing impl block, if this is a method. + pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option { + let module_impls = db.impls_in_module(self.module(db)); + ImplBlock::containing(module_impls, (*self).into()) + } } impl Docs for Const { @@ -544,6 +560,10 @@ impl Static { pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc) { self.id.source(db) } + + pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { + self.id.module(db) + } } impl Docs for Static { @@ -562,6 +582,10 @@ impl Trait { self.id.source(db) } + pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { + self.id.module(db) + } + pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc { db.generic_params((*self).into()) } @@ -586,6 +610,16 @@ impl Type { pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc { db.generic_params((*self).into()) } + + pub fn module(&self, db: &impl PersistentHirDatabase) -> Module { + self.id.module(db) + } + + /// The containing impl block, if this is a method. + pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option { + let module_impls = db.impls_in_module(self.module(db)); + ImplBlock::containing(module_impls, (*self).into()) + } } 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; use ra_syntax::ast::{self, NameOwner}; use crate::{ - HirDatabase, Name, AsName, Function, FnSignature, + Name, AsName, Function, FnSignature, type_ref::{TypeRef, Mutability}, PersistentHirDatabase, - impl_block::ImplBlock, }; -impl Function { - // TODO impl_block should probably also be part of the code model API? - - /// The containing impl block, if this is a method. - pub(crate) fn impl_block(&self, db: &impl HirDatabase) -> Option { - let module_impls = db.impls_in_module(self.module(db)); - ImplBlock::containing(module_impls, (*self).into()) - } -} - impl FnSignature { pub(crate) fn fn_signature_query( db: &impl PersistentHirDatabase, diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index 6ae0ead1b..fcc513353 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs @@ -20,6 +20,7 @@ pub struct GenericParam { /// Data about the generic parameters of a function, struct, impl, etc. #[derive(Clone, PartialEq, Eq, Debug, Default)] pub struct GenericParams { + pub(crate) parent_params: Option>, pub(crate) params: Vec, } @@ -40,28 +41,36 @@ impl GenericParams { def: GenericDef, ) -> Arc { let mut generics = GenericParams::default(); + let parent = match def { + GenericDef::Function(it) => it.impl_block(db), + GenericDef::Type(it) => it.impl_block(db), + GenericDef::Struct(_) | GenericDef::Enum(_) | GenericDef::Trait(_) => None, + GenericDef::ImplBlock(_) => None, + }; + generics.parent_params = parent.map(|p| p.generic_params(db)); + let start = generics.parent_params.as_ref().map(|p| p.params.len()).unwrap_or(0) as u32; match def { - GenericDef::Function(it) => generics.fill(&*it.source(db).1), - GenericDef::Struct(it) => generics.fill(&*it.source(db).1), - GenericDef::Enum(it) => generics.fill(&*it.source(db).1), - GenericDef::Trait(it) => generics.fill(&*it.source(db).1), - GenericDef::Type(it) => generics.fill(&*it.source(db).1), - GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1), + GenericDef::Function(it) => generics.fill(&*it.source(db).1, start), + GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start), + GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), + GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start), + GenericDef::Type(it) => generics.fill(&*it.source(db).1, start), + GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start), } Arc::new(generics) } - fn fill(&mut self, node: &impl TypeParamsOwner) { + fn fill(&mut self, node: &impl TypeParamsOwner, start: u32) { if let Some(params) = node.type_param_list() { - self.fill_params(params) + self.fill_params(params, start) } } - fn fill_params(&mut self, params: &ast::TypeParamList) { + fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { for (idx, type_param) in params.type_params().enumerate() { let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); - let param = GenericParam { idx: idx as u32, name }; + let param = GenericParam { idx: idx as u32 + start, name }; self.params.push(param); } } @@ -69,4 +78,13 @@ impl GenericParams { pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { self.params.iter().find(|p| &p.name == name) } + + pub fn count_parent_params(&self) -> usize { + self.parent_params.as_ref().map(|p| p.count_params_including_parent()).unwrap_or(0) + } + + pub fn count_params_including_parent(&self) -> usize { + let parent_count = self.count_parent_params(); + parent_count + self.params.len() + } } 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}; use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; use crate::{ - HirDatabase, Module, PersistentHirDatabase, }; @@ -215,7 +214,7 @@ pub(crate) trait AstItemDef: ArenaId + Clone { N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned(); (loc.raw.file_id, ast) } - fn module(self, db: &impl HirDatabase) -> Module { + fn module(self, db: &impl PersistentHirDatabase) -> Module { let int = Self::interner(db.as_ref()); let loc = int.id2loc(self); loc.module diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index f28a7e731..db0a20514 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs @@ -421,7 +421,8 @@ impl Ty { (var.parent_enum(db).generic_params(db), segment) } }; - // substs_from_path + let parent_param_count = def_generics.count_parent_params(); + substs.extend((0..parent_param_count).map(|_| Ty::Unknown)); if let Some(generic_args) = &segment.args_and_bindings { // if args are provided, it should be all of them, but we can't rely on that let param_count = def_generics.params.len(); @@ -436,9 +437,8 @@ impl Ty { } // add placeholders for args that were not provided // TODO: handle defaults - let supplied_params = - segment.args_and_bindings.as_ref().map(|ga| ga.args.len()).unwrap_or(0); - for _ in supplied_params..def_generics.params.len() { + let supplied_params = substs.len(); + for _ in supplied_params..def_generics.count_params_including_parent() { substs.push(Ty::Unknown); } assert_eq!(substs.len(), def_generics.params.len()); @@ -666,7 +666,12 @@ fn type_for_fn(db: &impl HirDatabase, def: Function) -> Ty { } fn make_substs(generics: &GenericParams) -> Substs { - Substs(generics.params.iter().map(|_p| Ty::Unknown).collect::>().into()) + Substs( + (0..generics.count_params_including_parent()) + .map(|_p| Ty::Unknown) + .collect::>() + .into(), + ) } fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { 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 @@ --- -created: "2019-01-27T14:52:29.938713255+00:00" -creator: insta@0.5.2 -expression: "&result" +created: "2019-02-16T20:53:59.655361804Z" +creator: insta@0.6.2 source: crates/ra_hir/src/ty/tests.rs +expression: "&result" --- -[53; 57) 'self': A<[unknown]> -[65; 87) '{ ... }': [unknown] -[75; 79) 'self': A<[unknown]> -[75; 81) 'self.x': [unknown] +[53; 57) 'self': A +[65; 87) '{ ... }': T2 +[75; 79) 'self': A +[75; 81) 'self.x': T2 [99; 100) 't': T [110; 115) '{ t }': T [112; 113) 't': T [135; 261) '{ ....x() }': i128 -[146; 147) 'x': i32 -[150; 151) '1': i32 -[162; 163) 'y': i32 -[166; 168) 'id': fn id(T) -> T -[166; 171) 'id(x)': i32 -[169; 170) 'x': i32 -[182; 183) 'a': A -[186; 200) 'A { x: id(y) }': A -[193; 195) 'id': fn id(T) -> T -[193; 198) 'id(y)': i32 -[196; 197) 'y': i32 -[211; 212) 'z': i32 -[215; 217) 'id': fn id(T) -> T -[215; 222) 'id(a.x)': i32 -[218; 219) 'a': A -[218; 221) 'a.x': i32 -[233; 234) 'b': A -[237; 247) 'A { x: z }': A -[244; 245) 'z': i32 -[254; 255) 'b': A +[146; 147) 'x': i128 +[150; 151) '1': i128 +[162; 163) 'y': i128 +[166; 168) 'id': fn id(T) -> T +[166; 171) 'id(x)': i128 +[169; 170) 'x': i128 +[182; 183) 'a': A +[186; 200) 'A { x: id(y) }': A +[193; 195) 'id': fn id(T) -> T +[193; 198) 'id(y)': i128 +[196; 197) 'y': i128 +[211; 212) 'z': i128 +[215; 217) 'id': fn id(T) -> T +[215; 222) 'id(a.x)': i128 +[218; 219) 'a': A +[218; 221) 'a.x': i128 +[233; 234) 'b': A +[237; 247) 'A { x: z }': A +[244; 245) 'z': i128 +[254; 255) 'b': A [254; 259) 'b.x()': i128 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 99df39fc2..eabbe52fd 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,25 +1,25 @@ --- -created: "2019-02-16T19:27:11.573533475Z" +created: "2019-02-16T20:53:59.657979128Z" creator: insta@0.6.2 source: crates/ra_hir/src/ty/tests.rs expression: "&result" --- -[74; 78) 'self': A<[unknown], [unknown]> -[85; 107) '{ ... }': [unknown] -[95; 99) 'self': A<[unknown], [unknown]> -[95; 101) 'self.x': [unknown] -[117; 121) 'self': A<[unknown], [unknown]> -[128; 150) '{ ... }': [unknown] -[138; 142) 'self': A<[unknown], [unknown]> -[138; 144) 'self.y': [unknown] -[163; 167) 'self': A<[unknown], [unknown]> +[74; 78) 'self': A +[85; 107) '{ ... }': X +[95; 99) 'self': A +[95; 101) 'self.x': X +[117; 121) 'self': A +[128; 150) '{ ... }': Y +[138; 142) 'self': A +[138; 144) 'self.y': Y +[163; 167) 'self': A [169; 170) 't': T -[188; 223) '{ ... }': ([unknown], [unknown], T) -[198; 217) '(self.....y, t)': ([unknown], [unknown], T) -[199; 203) 'self': A<[unknown], [unknown]> -[199; 205) 'self.x': [unknown] -[207; 211) 'self': A<[unknown], [unknown]> -[207; 213) 'self.y': [unknown] +[188; 223) '{ ... }': (X, Y, T) +[198; 217) '(self.....y, t)': (X, Y, T) +[199; 203) 'self': A +[199; 205) 'self.x': X +[207; 211) 'self': A +[207; 213) 'self.y': Y [215; 216) 't': T [245; 342) '{ ...(1); }': () [255; 256) 'a': A @@ -27,13 +27,13 @@ expression: "&result" [266; 270) '1u64': u64 [275; 279) '1i64': i64 [287; 288) 'a': A -[287; 292) 'a.x()': [unknown] +[287; 292) 'a.x()': u64 [298; 299) 'a': A -[298; 303) 'a.y()': [unknown] +[298; 303) 'a.y()': i64 [309; 310) 'a': A -[309; 319) 'a.z(1i128)': ([unknown], [unknown], i128) +[309; 319) 'a.z(1i128)': (u64, i64, i128) [313; 318) '1i128': i128 [325; 326) 'a': A -[325; 339) 'a.z::(1)': ([unknown], [unknown], i32) +[325; 339) 'a.z::(1)': (u64, i64, i32) [337; 338) '1': i32 -- cgit v1.2.3