diff options
author | Florian Diebold <[email protected]> | 2019-09-15 11:50:57 +0100 |
---|---|---|
committer | Florian Diebold <[email protected]> | 2019-09-17 18:47:45 +0100 |
commit | 406280e52f20e25af609d947efbed8b352ca1249 (patch) | |
tree | 3e7e5e284dd323173581b2c8618304f6125791b2 /crates/ra_hir/src/ty/lower.rs | |
parent | 828d60574f8ecbc33fe4987913c6f713e41af1ae (diff) |
Refactor associated item resolution more
When resolving an associated item in value namespace, use the `Ty` lowering code
for the segments before the last instead of replicating it.
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 119 |
1 files changed, 66 insertions, 53 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 62e4ed0f4..e29b68f1a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -86,81 +86,94 @@ impl Ty { | |||
86 | } | 86 | } |
87 | } | 87 | } |
88 | 88 | ||
89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 89 | pub(crate) fn from_partly_resolved_hir_path( |
90 | // Resolve the path (in type namespace) | 90 | db: &impl HirDatabase, |
91 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | 91 | resolver: &Resolver, |
92 | Some(it) => it, | 92 | resolution: TypeNs, |
93 | None => return Ty::Unknown, | 93 | resolved_segment: &PathSegment, |
94 | }; | 94 | remaining_segments: &[PathSegment], |
95 | 95 | ) -> Ty { | |
96 | let ty = match resolution { | 96 | let ty = match resolution { |
97 | TypeNs::Trait(trait_) => { | 97 | TypeNs::Trait(trait_) => { |
98 | let segment = match remaining_index { | 98 | let trait_ref = |
99 | None => path.segments.last().expect("resolved path has at least one element"), | 99 | TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); |
100 | Some(i) => &path.segments[i - 1], | 100 | return if remaining_segments.len() == 1 { |
101 | }; | 101 | let segment = &remaining_segments[0]; |
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | 102 | match trait_ref |
103 | return if let Some(remaining_index) = remaining_index { | 103 | .trait_ |
104 | if remaining_index == path.segments.len() - 1 { | 104 | .associated_type_by_name_including_super_traits(db, &segment.name) |
105 | let segment = &path.segments[remaining_index]; | 105 | { |
106 | match trait_ref | 106 | Some(associated_ty) => { |
107 | .trait_ | 107 | // FIXME handle type parameters on the segment |
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | 108 | Ty::Projection(ProjectionTy { |
109 | { | 109 | associated_ty, |
110 | Some(associated_ty) => { | 110 | parameters: trait_ref.substs, |
111 | // FIXME handle type parameters on the segment | 111 | }) |
112 | Ty::Projection(ProjectionTy { | 112 | } |
113 | associated_ty, | 113 | None => { |
114 | parameters: trait_ref.substs, | 114 | // associated type not found (FIXME: report error) |
115 | }) | 115 | Ty::Unknown |
116 | } | ||
117 | None => { | ||
118 | // associated type not found (FIXME: report error) | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | 116 | } |
122 | } else { | ||
123 | // FIXME report error (ambiguous associated type) | ||
124 | Ty::Unknown | ||
125 | } | 117 | } |
118 | } else if remaining_segments.len() > 1 { | ||
119 | // FIXME report error (ambiguous associated type) | ||
120 | Ty::Unknown | ||
126 | } else { | 121 | } else { |
127 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) | 122 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) |
128 | }; | 123 | }; |
129 | } | 124 | } |
130 | TypeNs::GenericParam(idx) => { | 125 | TypeNs::GenericParam(idx) => { |
131 | // FIXME: maybe return name in resolution? | 126 | // FIXME: maybe return name in resolution? |
132 | let name = match remaining_index { | 127 | let name = resolved_segment.name.clone(); |
133 | None => path | ||
134 | .as_ident() | ||
135 | .expect("generic param should be single-segment path") | ||
136 | .clone(), | ||
137 | Some(idx) => path.segments[idx - 1].name.clone(), | ||
138 | }; | ||
139 | Ty::Param { idx, name } | 128 | Ty::Param { idx, name } |
140 | } | 129 | } |
141 | TypeNs::SelfType(impl_block) => impl_block.target_ty(db), | 130 | TypeNs::SelfType(impl_block) => impl_block.target_ty(db), |
142 | 131 | ||
143 | TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 132 | TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), |
144 | TypeNs::BuiltinType(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 133 | TypeNs::BuiltinType(it) => { |
145 | TypeNs::TypeAlias(it) => Ty::from_hir_path_inner(db, resolver, path, it.into()), | 134 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) |
135 | } | ||
136 | TypeNs::TypeAlias(it) => { | ||
137 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) | ||
138 | } | ||
146 | // FIXME: report error | 139 | // FIXME: report error |
147 | TypeNs::EnumVariant(_) => return Ty::Unknown, | 140 | TypeNs::EnumVariant(_) => return Ty::Unknown, |
148 | }; | 141 | }; |
149 | 142 | ||
150 | if let Some(remaining_index) = remaining_index { | 143 | if remaining_segments.len() == 1 { |
151 | // resolve unselected assoc types | 144 | // resolve unselected assoc types |
152 | if remaining_index == path.segments.len() - 1 { | 145 | let segment = &remaining_segments[0]; |
153 | let segment = &path.segments[remaining_index]; | 146 | Ty::select_associated_type(db, resolver, ty, segment) |
154 | Ty::select_associated_type(db, resolver, ty, segment) | 147 | } else if remaining_segments.len() > 1 { |
155 | } else { | 148 | // FIXME report error (ambiguous associated type) |
156 | // FIXME report error (ambiguous associated type) | 149 | Ty::Unknown |
157 | Ty::Unknown | ||
158 | } | ||
159 | } else { | 150 | } else { |
160 | ty | 151 | ty |
161 | } | 152 | } |
162 | } | 153 | } |
163 | 154 | ||
155 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | ||
156 | // Resolve the path (in type namespace) | ||
157 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | ||
158 | Some(it) => it, | ||
159 | None => return Ty::Unknown, | ||
160 | }; | ||
161 | let (resolved_segment, remaining_segments) = match remaining_index { | ||
162 | None => ( | ||
163 | path.segments.last().expect("resolved path has at least one element"), | ||
164 | &[] as &[PathSegment], | ||
165 | ), | ||
166 | Some(i) => (&path.segments[i - 1], &path.segments[i..]), | ||
167 | }; | ||
168 | Ty::from_partly_resolved_hir_path( | ||
169 | db, | ||
170 | resolver, | ||
171 | resolution, | ||
172 | resolved_segment, | ||
173 | remaining_segments, | ||
174 | ) | ||
175 | } | ||
176 | |||
164 | fn select_associated_type( | 177 | fn select_associated_type( |
165 | db: &impl HirDatabase, | 178 | db: &impl HirDatabase, |
166 | resolver: &Resolver, | 179 | resolver: &Resolver, |
@@ -190,11 +203,11 @@ impl Ty { | |||
190 | fn from_hir_path_inner( | 203 | fn from_hir_path_inner( |
191 | db: &impl HirDatabase, | 204 | db: &impl HirDatabase, |
192 | resolver: &Resolver, | 205 | resolver: &Resolver, |
193 | path: &Path, | 206 | segment: &PathSegment, |
194 | typable: TypableDef, | 207 | typable: TypableDef, |
195 | ) -> Ty { | 208 | ) -> Ty { |
196 | let ty = db.type_for_def(typable, Namespace::Types); | 209 | let ty = db.type_for_def(typable, Namespace::Types); |
197 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 210 | let substs = Ty::substs_from_path_segment(db, resolver, segment, typable); |
198 | ty.subst(&substs) | 211 | ty.subst(&substs) |
199 | } | 212 | } |
200 | 213 | ||