Handle impl generics in method calls

This commit is contained in:
Florian Diebold 2019-02-16 22:06:23 +01:00
parent 2af067b391
commit 65bd9bc3a8
7 changed files with 122 additions and 77 deletions

View file

@ -463,7 +463,7 @@ impl Function {
self.id.source(db) self.id.source(db)
} }
pub fn module(&self, db: &impl HirDatabase) -> Module { pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db) self.id.module(db)
} }
@ -497,6 +497,12 @@ impl Function {
db.generic_params((*self).into()) db.generic_params((*self).into())
} }
/// The containing impl block, if this is a method.
pub fn impl_block(&self, db: &impl PersistentHirDatabase) -> Option<ImplBlock> {
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 // TODO: move to a more general type for 'body-having' items
/// Builds a resolver for code inside this item. /// Builds a resolver for code inside this item.
pub fn resolver(&self, db: &impl HirDatabase) -> Resolver { pub fn resolver(&self, db: &impl HirDatabase) -> Resolver {
@ -527,6 +533,16 @@ impl Const {
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) { pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::ConstDef>) {
self.id.source(db) 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<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
} }
impl Docs for Const { impl Docs for Const {
@ -544,6 +560,10 @@ impl Static {
pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) { pub fn source(&self, db: &impl PersistentHirDatabase) -> (HirFileId, TreeArc<ast::StaticDef>) {
self.id.source(db) self.id.source(db)
} }
pub fn module(&self, db: &impl PersistentHirDatabase) -> Module {
self.id.module(db)
}
} }
impl Docs for Static { impl Docs for Static {
@ -562,6 +582,10 @@ impl Trait {
self.id.source(db) 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<GenericParams> { pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into()) db.generic_params((*self).into())
} }
@ -586,6 +610,16 @@ impl Type {
pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> { pub fn generic_params(&self, db: &impl PersistentHirDatabase) -> Arc<GenericParams> {
db.generic_params((*self).into()) 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<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
} }
impl Docs for Type { impl Docs for Type {

View file

@ -3,22 +3,11 @@ use std::sync::Arc;
use ra_syntax::ast::{self, NameOwner}; use ra_syntax::ast::{self, NameOwner};
use crate::{ use crate::{
HirDatabase, Name, AsName, Function, FnSignature, Name, AsName, Function, FnSignature,
type_ref::{TypeRef, Mutability}, type_ref::{TypeRef, Mutability},
PersistentHirDatabase, 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<ImplBlock> {
let module_impls = db.impls_in_module(self.module(db));
ImplBlock::containing(module_impls, (*self).into())
}
}
impl FnSignature { impl FnSignature {
pub(crate) fn fn_signature_query( pub(crate) fn fn_signature_query(
db: &impl PersistentHirDatabase, db: &impl PersistentHirDatabase,

View file

@ -20,6 +20,7 @@ pub struct GenericParam {
/// Data about the generic parameters of a function, struct, impl, etc. /// Data about the generic parameters of a function, struct, impl, etc.
#[derive(Clone, PartialEq, Eq, Debug, Default)] #[derive(Clone, PartialEq, Eq, Debug, Default)]
pub struct GenericParams { pub struct GenericParams {
pub(crate) parent_params: Option<Arc<GenericParams>>,
pub(crate) params: Vec<GenericParam>, pub(crate) params: Vec<GenericParam>,
} }
@ -40,28 +41,36 @@ impl GenericParams {
def: GenericDef, def: GenericDef,
) -> Arc<GenericParams> { ) -> Arc<GenericParams> {
let mut generics = GenericParams::default(); 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 { match def {
GenericDef::Function(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), GenericDef::Struct(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Enum(it) => generics.fill(&*it.source(db).1), GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Trait(it) => generics.fill(&*it.source(db).1), GenericDef::Trait(it) => generics.fill(&*it.source(db).1, start),
GenericDef::Type(it) => generics.fill(&*it.source(db).1), GenericDef::Type(it) => generics.fill(&*it.source(db).1, start),
GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1), GenericDef::ImplBlock(it) => generics.fill(&*it.source(db).1, start),
} }
Arc::new(generics) 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() { 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() { for (idx, type_param) in params.type_params().enumerate() {
let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); 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); self.params.push(param);
} }
} }
@ -69,4 +78,13 @@ impl GenericParams {
pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> { pub(crate) fn find_by_name(&self, name: &Name) -> Option<&GenericParam> {
self.params.iter().find(|p| &p.name == name) 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()
}
} }

View file

@ -9,7 +9,6 @@ use ra_syntax::{TreeArc, SyntaxNode, SourceFile, AstNode, SyntaxNodePtr, ast};
use ra_arena::{Arena, RawId, ArenaId, impl_arena_id}; use ra_arena::{Arena, RawId, ArenaId, impl_arena_id};
use crate::{ use crate::{
HirDatabase,
Module, Module,
PersistentHirDatabase, PersistentHirDatabase,
}; };
@ -215,7 +214,7 @@ pub(crate) trait AstItemDef<N: AstNode>: ArenaId + Clone {
N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned(); N::cast(&syntax).unwrap_or_else(|| panic!("invalid ItemLoc: {:?}", loc.raw)).to_owned();
(loc.raw.file_id, ast) (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 int = Self::interner(db.as_ref());
let loc = int.id2loc(self); let loc = int.id2loc(self);
loc.module loc.module

View file

@ -421,7 +421,8 @@ impl Ty {
(var.parent_enum(db).generic_params(db), segment) (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 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 // if args are provided, it should be all of them, but we can't rely on that
let param_count = def_generics.params.len(); let param_count = def_generics.params.len();
@ -436,9 +437,8 @@ impl Ty {
} }
// add placeholders for args that were not provided // add placeholders for args that were not provided
// TODO: handle defaults // TODO: handle defaults
let supplied_params = let supplied_params = substs.len();
segment.args_and_bindings.as_ref().map(|ga| ga.args.len()).unwrap_or(0); for _ in supplied_params..def_generics.count_params_including_parent() {
for _ in supplied_params..def_generics.params.len() {
substs.push(Ty::Unknown); substs.push(Ty::Unknown);
} }
assert_eq!(substs.len(), def_generics.params.len()); 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 { fn make_substs(generics: &GenericParams) -> Substs {
Substs(generics.params.iter().map(|_p| Ty::Unknown).collect::<Vec<_>>().into()) Substs(
(0..generics.count_params_including_parent())
.map(|_p| Ty::Unknown)
.collect::<Vec<_>>()
.into(),
)
} }
fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty { fn type_for_struct(db: &impl HirDatabase, s: Struct) -> Ty {

View file

@ -1,36 +1,36 @@
--- ---
created: "2019-01-27T14:52:29.938713255+00:00" created: "2019-02-16T20:53:59.655361804Z"
creator: insta@0.5.2 creator: insta@0.6.2
expression: "&result"
source: crates/ra_hir/src/ty/tests.rs source: crates/ra_hir/src/ty/tests.rs
expression: "&result"
--- ---
[53; 57) 'self': A<[unknown]> [53; 57) 'self': A<T2>
[65; 87) '{ ... }': [unknown] [65; 87) '{ ... }': T2
[75; 79) 'self': A<[unknown]> [75; 79) 'self': A<T2>
[75; 81) 'self.x': [unknown] [75; 81) 'self.x': T2
[99; 100) 't': T [99; 100) 't': T
[110; 115) '{ t }': T [110; 115) '{ t }': T
[112; 113) 't': T [112; 113) 't': T
[135; 261) '{ ....x() }': i128 [135; 261) '{ ....x() }': i128
[146; 147) 'x': i32 [146; 147) 'x': i128
[150; 151) '1': i32 [150; 151) '1': i128
[162; 163) 'y': i32 [162; 163) 'y': i128
[166; 168) 'id': fn id<i32>(T) -> T [166; 168) 'id': fn id<i128>(T) -> T
[166; 171) 'id(x)': i32 [166; 171) 'id(x)': i128
[169; 170) 'x': i32 [169; 170) 'x': i128
[182; 183) 'a': A<i32> [182; 183) 'a': A<i128>
[186; 200) 'A { x: id(y) }': A<i32> [186; 200) 'A { x: id(y) }': A<i128>
[193; 195) 'id': fn id<i32>(T) -> T [193; 195) 'id': fn id<i128>(T) -> T
[193; 198) 'id(y)': i32 [193; 198) 'id(y)': i128
[196; 197) 'y': i32 [196; 197) 'y': i128
[211; 212) 'z': i32 [211; 212) 'z': i128
[215; 217) 'id': fn id<i32>(T) -> T [215; 217) 'id': fn id<i128>(T) -> T
[215; 222) 'id(a.x)': i32 [215; 222) 'id(a.x)': i128
[218; 219) 'a': A<i32> [218; 219) 'a': A<i128>
[218; 221) 'a.x': i32 [218; 221) 'a.x': i128
[233; 234) 'b': A<i32> [233; 234) 'b': A<i128>
[237; 247) 'A { x: z }': A<i32> [237; 247) 'A { x: z }': A<i128>
[244; 245) 'z': i32 [244; 245) 'z': i128
[254; 255) 'b': A<i32> [254; 255) 'b': A<i128>
[254; 259) 'b.x()': i128 [254; 259) 'b.x()': i128

View file

@ -1,25 +1,25 @@
--- ---
created: "2019-02-16T19:27:11.573533475Z" created: "2019-02-16T20:53:59.657979128Z"
creator: insta@0.6.2 creator: insta@0.6.2
source: crates/ra_hir/src/ty/tests.rs source: crates/ra_hir/src/ty/tests.rs
expression: "&result" expression: "&result"
--- ---
[74; 78) 'self': A<[unknown], [unknown]> [74; 78) 'self': A<X, Y>
[85; 107) '{ ... }': [unknown] [85; 107) '{ ... }': X
[95; 99) 'self': A<[unknown], [unknown]> [95; 99) 'self': A<X, Y>
[95; 101) 'self.x': [unknown] [95; 101) 'self.x': X
[117; 121) 'self': A<[unknown], [unknown]> [117; 121) 'self': A<X, Y>
[128; 150) '{ ... }': [unknown] [128; 150) '{ ... }': Y
[138; 142) 'self': A<[unknown], [unknown]> [138; 142) 'self': A<X, Y>
[138; 144) 'self.y': [unknown] [138; 144) 'self.y': Y
[163; 167) 'self': A<[unknown], [unknown]> [163; 167) 'self': A<X, Y>
[169; 170) 't': T [169; 170) 't': T
[188; 223) '{ ... }': ([unknown], [unknown], T) [188; 223) '{ ... }': (X, Y, T)
[198; 217) '(self.....y, t)': ([unknown], [unknown], T) [198; 217) '(self.....y, t)': (X, Y, T)
[199; 203) 'self': A<[unknown], [unknown]> [199; 203) 'self': A<X, Y>
[199; 205) 'self.x': [unknown] [199; 205) 'self.x': X
[207; 211) 'self': A<[unknown], [unknown]> [207; 211) 'self': A<X, Y>
[207; 213) 'self.y': [unknown] [207; 213) 'self.y': Y
[215; 216) 't': T [215; 216) 't': T
[245; 342) '{ ...(1); }': () [245; 342) '{ ...(1); }': ()
[255; 256) 'a': A<u64, i64> [255; 256) 'a': A<u64, i64>
@ -27,13 +27,13 @@ expression: "&result"
[266; 270) '1u64': u64 [266; 270) '1u64': u64
[275; 279) '1i64': i64 [275; 279) '1i64': i64
[287; 288) 'a': A<u64, i64> [287; 288) 'a': A<u64, i64>
[287; 292) 'a.x()': [unknown] [287; 292) 'a.x()': u64
[298; 299) 'a': A<u64, i64> [298; 299) 'a': A<u64, i64>
[298; 303) 'a.y()': [unknown] [298; 303) 'a.y()': i64
[309; 310) 'a': A<u64, i64> [309; 310) 'a': A<u64, i64>
[309; 319) 'a.z(1i128)': ([unknown], [unknown], i128) [309; 319) 'a.z(1i128)': (u64, i64, i128)
[313; 318) '1i128': i128 [313; 318) '1i128': i128
[325; 326) 'a': A<u64, i64> [325; 326) 'a': A<u64, i64>
[325; 339) 'a.z::<u128>(1)': ([unknown], [unknown], i32) [325; 339) 'a.z::<u128>(1)': (u64, i64, i32)
[337; 338) '1': i32 [337; 338) '1': i32