diff options
author | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-20 10:52:15 +0100 |
---|---|---|
committer | bors[bot] <bors[bot]@users.noreply.github.com> | 2019-05-20 10:52:15 +0100 |
commit | 3894eb77d8c06acda68f6c267315063b1c9960e8 (patch) | |
tree | d6f33d4f6647cea3ec63b48e3b14b7897890db94 /crates/ra_hir/src | |
parent | 5edddae523184462d779d5a347ca1c5be5832044 (diff) | |
parent | 3fc344b9f16ad481e87198da72052dd7ddfc88be (diff) |
Merge #1286
1286: Add infer for generic default type r=flodiebold a=edwin0cheng
This PR add infer support for generic default type:
```
struct Gen<T=u32> {
val: T
}
```
* add the (unresolved) defaults from the definition to GenericParams
* add a query generic_defaults that resolves those defaults to types and returns a Substs
* add the missing type in `substs_from_path_segment`
* add tests
based on the idea in this [comment](https://github.com/rust-analyzer/rust-analyzer/issues/1099#issuecomment-484206279)
Co-authored-by: Edwin Cheng <[email protected]>
Diffstat (limited to 'crates/ra_hir/src')
-rw-r--r-- | crates/ra_hir/src/db.rs | 5 | ||||
-rw-r--r-- | crates/ra_hir/src/generics.rs | 13 | ||||
-rw-r--r-- | crates/ra_hir/src/ty.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 54 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 29 |
5 files changed, 86 insertions, 17 deletions
diff --git a/crates/ra_hir/src/db.rs b/crates/ra_hir/src/db.rs index 8e827d4f5..bda02d3cc 100644 --- a/crates/ra_hir/src/db.rs +++ b/crates/ra_hir/src/db.rs | |||
@@ -11,7 +11,7 @@ use crate::{ | |||
11 | DefWithBody, Trait, | 11 | DefWithBody, Trait, |
12 | ids, | 12 | ids, |
13 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, | 13 | nameres::{Namespace, ImportSourceMap, RawItems, CrateDefMap}, |
14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor, GenericPredicate}, | 14 | ty::{InferenceResult, Ty, method_resolution::CrateImplBlocks, TypableDef, CallableDef, FnSig, TypeCtor, GenericPredicate, Substs}, |
15 | adt::{StructData, EnumData}, | 15 | adt::{StructData, EnumData}, |
16 | impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, | 16 | impl_block::{ModuleImplBlocks, ImplSourceMap, ImplBlock}, |
17 | generics::{GenericParams, GenericDef}, | 17 | generics::{GenericParams, GenericDef}, |
@@ -141,6 +141,9 @@ pub trait HirDatabase: DefDatabase { | |||
141 | #[salsa::invoke(crate::ty::generic_predicates)] | 141 | #[salsa::invoke(crate::ty::generic_predicates)] |
142 | fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; | 142 | fn generic_predicates(&self, def: GenericDef) -> Arc<[GenericPredicate]>; |
143 | 143 | ||
144 | #[salsa::invoke(crate::ty::generic_defaults)] | ||
145 | fn generic_defaults(&self, def: GenericDef) -> Substs; | ||
146 | |||
144 | #[salsa::invoke(crate::expr::body_with_source_map_query)] | 147 | #[salsa::invoke(crate::expr::body_with_source_map_query)] |
145 | fn body_with_source_map( | 148 | fn body_with_source_map( |
146 | &self, | 149 | &self, |
diff --git a/crates/ra_hir/src/generics.rs b/crates/ra_hir/src/generics.rs index c29b96f50..a635c7184 100644 --- a/crates/ra_hir/src/generics.rs +++ b/crates/ra_hir/src/generics.rs | |||
@@ -5,7 +5,7 @@ | |||
5 | 5 | ||
6 | use std::sync::Arc; | 6 | use std::sync::Arc; |
7 | 7 | ||
8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner}; | 8 | use ra_syntax::ast::{self, NameOwner, TypeParamsOwner, TypeBoundsOwner, DefaultTypeParamOwner}; |
9 | 9 | ||
10 | use crate::{ | 10 | use crate::{ |
11 | db::{ HirDatabase, DefDatabase}, | 11 | db::{ HirDatabase, DefDatabase}, |
@@ -18,6 +18,7 @@ pub struct GenericParam { | |||
18 | // FIXME: give generic params proper IDs | 18 | // FIXME: give generic params proper IDs |
19 | pub(crate) idx: u32, | 19 | pub(crate) idx: u32, |
20 | pub(crate) name: Name, | 20 | pub(crate) name: Name, |
21 | pub(crate) default: Option<Path>, | ||
21 | } | 22 | } |
22 | 23 | ||
23 | /// Data about the generic parameters of a function, struct, impl, etc. | 24 | /// Data about the generic parameters of a function, struct, impl, etc. |
@@ -68,7 +69,11 @@ impl GenericParams { | |||
68 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), | 69 | GenericDef::Enum(it) => generics.fill(&*it.source(db).1, start), |
69 | GenericDef::Trait(it) => { | 70 | GenericDef::Trait(it) => { |
70 | // traits get the Self type as an implicit first type parameter | 71 | // traits get the Self type as an implicit first type parameter |
71 | generics.params.push(GenericParam { idx: start, name: Name::self_type() }); | 72 | generics.params.push(GenericParam { |
73 | idx: start, | ||
74 | name: Name::self_type(), | ||
75 | default: None, | ||
76 | }); | ||
72 | generics.fill(&*it.source(db).1, start + 1); | 77 | generics.fill(&*it.source(db).1, start + 1); |
73 | } | 78 | } |
74 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), | 79 | GenericDef::TypeAlias(it) => generics.fill(&*it.source(db).1, start), |
@@ -90,7 +95,9 @@ impl GenericParams { | |||
90 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { | 95 | fn fill_params(&mut self, params: &ast::TypeParamList, start: u32) { |
91 | for (idx, type_param) in params.type_params().enumerate() { | 96 | for (idx, type_param) in params.type_params().enumerate() { |
92 | let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); | 97 | let name = type_param.name().map(AsName::as_name).unwrap_or_else(Name::missing); |
93 | let param = GenericParam { idx: idx as u32 + start, name: name.clone() }; | 98 | let default = type_param.default_type().and_then(|t| t.path()).and_then(Path::from_ast); |
99 | |||
100 | let param = GenericParam { idx: idx as u32 + start, name: name.clone(), default }; | ||
94 | self.params.push(param); | 101 | self.params.push(param); |
95 | 102 | ||
96 | let type_ref = TypeRef::Path(name.into()); | 103 | let type_ref = TypeRef::Path(name.into()); |
diff --git a/crates/ra_hir/src/ty.rs b/crates/ra_hir/src/ty.rs index cfe07156b..9a65bf567 100644 --- a/crates/ra_hir/src/ty.rs +++ b/crates/ra_hir/src/ty.rs | |||
@@ -19,7 +19,7 @@ use std::{fmt, mem}; | |||
19 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; | 19 | use crate::{Name, AdtDef, type_ref::Mutability, db::HirDatabase, Trait, GenericParams}; |
20 | use display::{HirDisplay, HirFormatter}; | 20 | use display::{HirDisplay, HirFormatter}; |
21 | 21 | ||
22 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates}; | 22 | pub(crate) use lower::{TypableDef, type_for_def, type_for_field, callable_item_sig, generic_predicates, generic_defaults}; |
23 | pub(crate) use infer::{infer, InferenceResult, InferTy}; | 23 | pub(crate) use infer::{infer, InferenceResult, InferTy}; |
24 | pub use lower::CallableDef; | 24 | pub use lower::CallableDef; |
25 | 25 | ||
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 09d26ce5a..8a8cc2a24 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -18,7 +18,7 @@ use crate::{ | |||
18 | nameres::Namespace, | 18 | nameres::Namespace, |
19 | resolve::{Resolver, Resolution}, | 19 | resolve::{Resolver, Resolution}, |
20 | path::{PathSegment, GenericArg}, | 20 | path::{PathSegment, GenericArg}, |
21 | generics::{GenericParams, HasGenericParams}, | 21 | generics::{HasGenericParams}, |
22 | adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef} | 22 | adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef} |
23 | }; | 23 | }; |
24 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate}; | 24 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate}; |
@@ -120,15 +120,15 @@ impl Ty { | |||
120 | segment: &PathSegment, | 120 | segment: &PathSegment, |
121 | resolved: TypableDef, | 121 | resolved: TypableDef, |
122 | ) -> Substs { | 122 | ) -> Substs { |
123 | let def_generics = match resolved { | 123 | let def_generic: Option<GenericDef> = match resolved { |
124 | TypableDef::Function(func) => func.generic_params(db), | 124 | TypableDef::Function(func) => Some(func.into()), |
125 | TypableDef::Struct(s) => s.generic_params(db), | 125 | TypableDef::Struct(s) => Some(s.into()), |
126 | TypableDef::Enum(e) => e.generic_params(db), | 126 | TypableDef::Enum(e) => Some(e.into()), |
127 | TypableDef::EnumVariant(var) => var.parent_enum(db).generic_params(db), | 127 | TypableDef::EnumVariant(var) => Some(var.parent_enum(db).into()), |
128 | TypableDef::TypeAlias(t) => t.generic_params(db), | 128 | TypableDef::TypeAlias(t) => Some(t.into()), |
129 | TypableDef::Const(_) | TypableDef::Static(_) => GenericParams::default().into(), | 129 | TypableDef::Const(_) | TypableDef::Static(_) => None, |
130 | }; | 130 | }; |
131 | substs_from_path_segment(db, resolver, segment, &def_generics, false) | 131 | substs_from_path_segment(db, resolver, segment, def_generic, false) |
132 | } | 132 | } |
133 | 133 | ||
134 | /// Collect generic arguments from a path into a `Substs`. See also | 134 | /// Collect generic arguments from a path into a `Substs`. See also |
@@ -172,10 +172,12 @@ pub(super) fn substs_from_path_segment( | |||
172 | db: &impl HirDatabase, | 172 | db: &impl HirDatabase, |
173 | resolver: &Resolver, | 173 | resolver: &Resolver, |
174 | segment: &PathSegment, | 174 | segment: &PathSegment, |
175 | def_generics: &GenericParams, | 175 | def_generic: Option<GenericDef>, |
176 | add_self_param: bool, | 176 | add_self_param: bool, |
177 | ) -> Substs { | 177 | ) -> Substs { |
178 | let mut substs = Vec::new(); | 178 | let mut substs = Vec::new(); |
179 | let def_generics = def_generic.map(|def| def.generic_params(db)).unwrap_or_default(); | ||
180 | |||
179 | let parent_param_count = def_generics.count_parent_params(); | 181 | let parent_param_count = def_generics.count_parent_params(); |
180 | substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); | 182 | substs.extend(iter::repeat(Ty::Unknown).take(parent_param_count)); |
181 | if add_self_param { | 183 | if add_self_param { |
@@ -199,12 +201,24 @@ pub(super) fn substs_from_path_segment( | |||
199 | } | 201 | } |
200 | } | 202 | } |
201 | // add placeholders for args that were not provided | 203 | // add placeholders for args that were not provided |
202 | // FIXME: handle defaults | ||
203 | let supplied_params = substs.len(); | 204 | let supplied_params = substs.len(); |
204 | for _ in supplied_params..def_generics.count_params_including_parent() { | 205 | for _ in supplied_params..def_generics.count_params_including_parent() { |
205 | substs.push(Ty::Unknown); | 206 | substs.push(Ty::Unknown); |
206 | } | 207 | } |
207 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); | 208 | assert_eq!(substs.len(), def_generics.count_params_including_parent()); |
209 | |||
210 | // handle defaults | ||
211 | if let Some(def_generic) = def_generic { | ||
212 | let default_substs = db.generic_defaults(def_generic); | ||
213 | assert_eq!(substs.len(), default_substs.len()); | ||
214 | |||
215 | for (i, default_ty) in default_substs.iter().enumerate() { | ||
216 | if substs[i] == Ty::Unknown { | ||
217 | substs[i] = default_ty.clone(); | ||
218 | } | ||
219 | } | ||
220 | } | ||
221 | |||
208 | Substs(substs.into()) | 222 | Substs(substs.into()) |
209 | } | 223 | } |
210 | 224 | ||
@@ -249,7 +263,7 @@ impl TraitRef { | |||
249 | resolved: Trait, | 263 | resolved: Trait, |
250 | ) -> Substs { | 264 | ) -> Substs { |
251 | let segment = path.segments.last().expect("path should have at least one segment"); | 265 | let segment = path.segments.last().expect("path should have at least one segment"); |
252 | substs_from_path_segment(db, resolver, segment, &resolved.generic_params(db), true) | 266 | substs_from_path_segment(db, resolver, segment, Some(resolved.into()), true) |
253 | } | 267 | } |
254 | 268 | ||
255 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { | 269 | pub(crate) fn for_trait(db: &impl HirDatabase, trait_: Trait) -> TraitRef { |
@@ -331,6 +345,22 @@ pub(crate) fn generic_predicates( | |||
331 | predicates.into() | 345 | predicates.into() |
332 | } | 346 | } |
333 | 347 | ||
348 | /// Resolve the default type params from generics | ||
349 | pub(crate) fn generic_defaults(db: &impl HirDatabase, def: GenericDef) -> Substs { | ||
350 | let resolver = def.resolver(db); | ||
351 | let generic_params = def.generic_params(db); | ||
352 | |||
353 | let defaults = generic_params | ||
354 | .params_including_parent() | ||
355 | .into_iter() | ||
356 | .map(|p| { | ||
357 | p.default.as_ref().map_or(Ty::Unknown, |path| Ty::from_hir_path(db, &resolver, path)) | ||
358 | }) | ||
359 | .collect::<Vec<_>>(); | ||
360 | |||
361 | Substs(defaults.into()) | ||
362 | } | ||
363 | |||
334 | fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { | 364 | fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { |
335 | let signature = def.signature(db); | 365 | let signature = def.signature(db); |
336 | let resolver = def.resolver(db); | 366 | let resolver = def.resolver(db); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index f8364203d..cd24faba5 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -1449,6 +1449,35 @@ fn test() { | |||
1449 | } | 1449 | } |
1450 | 1450 | ||
1451 | #[test] | 1451 | #[test] |
1452 | fn infer_associated_method_generics_with_default_param() { | ||
1453 | assert_snapshot_matches!( | ||
1454 | infer(r#" | ||
1455 | struct Gen<T=u32> { | ||
1456 | val: T | ||
1457 | } | ||
1458 | |||
1459 | impl<T> Gen<T> { | ||
1460 | pub fn make() -> Gen<T> { | ||
1461 | loop { } | ||
1462 | } | ||
1463 | } | ||
1464 | |||
1465 | fn test() { | ||
1466 | let a = Gen::make(); | ||
1467 | } | ||
1468 | "#), | ||
1469 | @r###" | ||
1470 | [80; 104) '{ ... }': ! | ||
1471 | [90; 98) 'loop { }': ! | ||
1472 | [95; 98) '{ }': () | ||
1473 | [118; 146) '{ ...e(); }': () | ||
1474 | [128; 129) 'a': Gen<u32> | ||
1475 | [132; 141) 'Gen::make': fn make<u32>() -> Gen<T> | ||
1476 | [132; 143) 'Gen::make()': Gen<u32>"### | ||
1477 | ); | ||
1478 | } | ||
1479 | |||
1480 | #[test] | ||
1452 | fn infer_associated_method_generics_without_args() { | 1481 | fn infer_associated_method_generics_without_args() { |
1453 | assert_snapshot_matches!( | 1482 | assert_snapshot_matches!( |
1454 | infer(r#" | 1483 | infer(r#" |