aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir_ty/src/utils.rs
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2020-02-09 11:35:08 +0000
committerGitHub <[email protected]>2020-02-09 11:35:08 +0000
commit01836a0f35fa163025c64cabe1d0c34bb4f69c92 (patch)
treeaa1a3cf97173b2885f8b6d23002c73196f9a0b61 /crates/ra_hir_ty/src/utils.rs
parent961a69b88f923d4477ca4f746a793217a0cc8576 (diff)
parenteefe02ce6e1750b771cf99125429358e87485745 (diff)
Merge #3050
3050: Refactor type parameters, implement argument position impl trait r=matklad a=flodiebold I wanted to implement APIT by lowering to type parameters because we need to do that anyway for correctness and don't need Chalk support for it; this grew into some more wide-ranging refactoring of how type parameters are handled :sweat_smile: - use Ty::Bound instead of Ty::Param to represent polymorphism, and explicitly count binders. This gets us closer to Chalk's way of doing things, and means that we now only use Param as a placeholder for an unknown type, e.g. within a generic function. I.e. we're never using Param in a situation where we want to substitute it, and the method to do that is gone; `subst` now always works on bound variables. (This changes how the types of generic functions print; previously, you'd get something like `fn identity<i32>(T) -> T`, but now we display the substituted signature `fn identity<i32>(i32) -> i32`, which I think makes more sense.) - once we do this, it's more natural to represent `Param` by a globally unique ID; the use of indices was mostly to make substituting easier. This also means we fix the bug where `Param` loses its name when going through Chalk. - I would actually like to rename `Param` to `Placeholder` to better reflect its use and get closer to Chalk, but I'll leave that to a follow-up. - introduce a context for type lowering, to allow lowering `impl Trait` to different things depending on where we are. And since we have that, we can also lower type parameters directly to variables instead of placeholders. Also, we'll be able to use this later to collect diagnostics. - implement argument position impl trait by lowering it to type parameters. I've realized that this is necessary to correctly implement it; e.g. consider `fn foo(impl Display) -> impl Something`. It's observable that the return type of e.g. `foo(1u32)` unifies with itself, but doesn't unify with e.g. `foo(1i32)`; so the return type needs to be parameterized by the argument type. This fixes a few bugs as well: - type parameters 'losing' their name when they go through Chalk, as mentioned above (i.e. getting `[missing name]` somewhere) - impl trait not being considered as implementing the super traits (very noticeable for the `db` in RA) - the fact that argument impl trait was only turned into variables when the function got called caused type mismatches when the function was used as a value (fixes a few type mismatches in RA) The one thing I'm not so happy with here is how we're lowering `impl Trait` types to variables; since `TypeRef`s don't have an identity currently, we just count how many of them we have seen while going through the function signature. That's quite fragile though, since we have to do it while desugaring generics and while lowering the type signature, and in the exact same order in both cases. We could consider either giving only `TypeRef::ImplTrait` a local id, or maybe just giving all `TypeRef`s an identity after all (we talked about this before)... Follow-up tasks: - handle return position impl trait; we basically need to create a variable and some trait obligations for that variable - rename `Param` to `Placeholder` Co-authored-by: Florian Diebold <[email protected]> Co-authored-by: Florian Diebold <[email protected]>
Diffstat (limited to 'crates/ra_hir_ty/src/utils.rs')
-rw-r--r--crates/ra_hir_ty/src/utils.rs91
1 files changed, 68 insertions, 23 deletions
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs
index 0b1806a84..508ae9046 100644
--- a/crates/ra_hir_ty/src/utils.rs
+++ b/crates/ra_hir_ty/src/utils.rs
@@ -2,10 +2,11 @@
2//! query, but can't be computed directly from `*Data` (ie, which need a `db`). 2//! query, but can't be computed directly from `*Data` (ie, which need a `db`).
3use std::sync::Arc; 3use std::sync::Arc;
4 4
5use hir_def::generics::WherePredicateTarget;
5use hir_def::{ 6use hir_def::{
6 adt::VariantData, 7 adt::VariantData,
7 db::DefDatabase, 8 db::DefDatabase,
8 generics::{GenericParams, TypeParamData}, 9 generics::{GenericParams, TypeParamData, TypeParamProvenance},
9 path::Path, 10 path::Path,
10 resolver::{HasResolver, TypeNs}, 11 resolver::{HasResolver, TypeNs},
11 type_ref::TypeRef, 12 type_ref::TypeRef,
@@ -19,11 +20,18 @@ fn direct_super_traits(db: &impl DefDatabase, trait_: TraitId) -> Vec<TraitId> {
19 // lifetime problems, but since there usually shouldn't be more than a 20 // lifetime problems, but since there usually shouldn't be more than a
20 // few direct traits this should be fine (we could even use some kind of 21 // few direct traits this should be fine (we could even use some kind of
21 // SmallVec if performance is a concern) 22 // SmallVec if performance is a concern)
22 db.generic_params(trait_.into()) 23 let generic_params = db.generic_params(trait_.into());
24 let trait_self = generic_params.find_trait_self_param();
25 generic_params
23 .where_predicates 26 .where_predicates
24 .iter() 27 .iter()
25 .filter_map(|pred| match &pred.type_ref { 28 .filter_map(|pred| match &pred.target {
26 TypeRef::Path(p) if p == &Path::from(name![Self]) => pred.bound.as_path(), 29 WherePredicateTarget::TypeRef(TypeRef::Path(p)) if p == &Path::from(name![Self]) => {
30 pred.bound.as_path()
31 }
32 WherePredicateTarget::TypeParam(local_id) if Some(*local_id) == trait_self => {
33 pred.bound.as_path()
34 }
27 _ => None, 35 _ => None,
28 }) 36 })
29 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) { 37 .filter_map(|path| match resolver.resolve_path_in_type_ns_fully(db, path.mod_path()) {
@@ -95,41 +103,77 @@ pub(crate) struct Generics {
95} 103}
96 104
97impl Generics { 105impl Generics {
98 pub(crate) fn iter<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a { 106 pub(crate) fn iter<'a>(
107 &'a self,
108 ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
99 self.parent_generics 109 self.parent_generics
100 .as_ref() 110 .as_ref()
101 .into_iter() 111 .into_iter()
102 .flat_map(|it| it.params.types.iter()) 112 .flat_map(|it| {
103 .chain(self.params.types.iter()) 113 it.params
104 .enumerate() 114 .types
105 .map(|(i, (_local_id, p))| (i as u32, p)) 115 .iter()
116 .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
117 })
118 .chain(
119 self.params
120 .types
121 .iter()
122 .map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p)),
123 )
106 } 124 }
107 125
108 pub(crate) fn iter_parent<'a>(&'a self) -> impl Iterator<Item = (u32, &'a TypeParamData)> + 'a { 126 pub(crate) fn iter_parent<'a>(
109 self.parent_generics 127 &'a self,
110 .as_ref() 128 ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
111 .into_iter() 129 self.parent_generics.as_ref().into_iter().flat_map(|it| {
112 .flat_map(|it| it.params.types.iter()) 130 it.params
113 .enumerate() 131 .types
114 .map(|(i, (_local_id, p))| (i as u32, p)) 132 .iter()
133 .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
134 })
115 } 135 }
116 136
117 pub(crate) fn len(&self) -> usize { 137 pub(crate) fn len(&self) -> usize {
118 self.len_split().0 138 self.len_split().0
119 } 139 }
140
120 /// (total, parents, child) 141 /// (total, parents, child)
121 pub(crate) fn len_split(&self) -> (usize, usize, usize) { 142 pub(crate) fn len_split(&self) -> (usize, usize, usize) {
122 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len()); 143 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
123 let child = self.params.types.len(); 144 let child = self.params.types.len();
124 (parent + child, parent, child) 145 (parent + child, parent, child)
125 } 146 }
126 pub(crate) fn param_idx(&self, param: TypeParamId) -> u32 { 147
127 self.find_param(param).0 148 /// (parent total, self param, type param list, impl trait)
149 pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize) {
150 let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
151 let self_params = self
152 .params
153 .types
154 .iter()
155 .filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf)
156 .count();
157 let list_params = self
158 .params
159 .types
160 .iter()
161 .filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList)
162 .count();
163 let impl_trait_params = self
164 .params
165 .types
166 .iter()
167 .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait)
168 .count();
169 (parent, self_params, list_params, impl_trait_params)
128 } 170 }
129 pub(crate) fn param_name(&self, param: TypeParamId) -> Name { 171
130 self.find_param(param).1.name.clone() 172 pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<u32> {
173 Some(self.find_param(param)?.0)
131 } 174 }
132 fn find_param(&self, param: TypeParamId) -> (u32, &TypeParamData) { 175
176 fn find_param(&self, param: TypeParamId) -> Option<(u32, &TypeParamData)> {
133 if param.parent == self.def { 177 if param.parent == self.def {
134 let (idx, (_local_id, data)) = self 178 let (idx, (_local_id, data)) = self
135 .params 179 .params
@@ -139,9 +183,10 @@ impl Generics {
139 .find(|(_, (idx, _))| *idx == param.local_id) 183 .find(|(_, (idx, _))| *idx == param.local_id)
140 .unwrap(); 184 .unwrap();
141 let (_total, parent_len, _child) = self.len_split(); 185 let (_total, parent_len, _child) = self.len_split();
142 return ((parent_len + idx) as u32, data); 186 Some(((parent_len + idx) as u32, data))
187 } else {
188 self.parent_generics.as_ref().and_then(|g| g.find_param(param))
143 } 189 }
144 self.parent_generics.as_ref().unwrap().find_param(param)
145 } 190 }
146} 191}
147 192