diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 159 |
1 files changed, 103 insertions, 56 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 6ead3846a..a83842b0f 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -86,78 +86,125 @@ 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_type_relative_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 | ty: Ty, |
93 | None => return Ty::Unknown, | 93 | remaining_segments: &[PathSegment], |
94 | }; | 94 | ) -> Ty { |
95 | if remaining_segments.len() == 1 { | ||
96 | // resolve unselected assoc types | ||
97 | let segment = &remaining_segments[0]; | ||
98 | Ty::select_associated_type(db, resolver, ty, segment) | ||
99 | } else if remaining_segments.len() > 1 { | ||
100 | // FIXME report error (ambiguous associated type) | ||
101 | Ty::Unknown | ||
102 | } else { | ||
103 | ty | ||
104 | } | ||
105 | } | ||
95 | 106 | ||
96 | let typable: TypableDef = match resolution { | 107 | pub(crate) fn from_partly_resolved_hir_path( |
108 | db: &impl HirDatabase, | ||
109 | resolver: &Resolver, | ||
110 | resolution: TypeNs, | ||
111 | resolved_segment: &PathSegment, | ||
112 | remaining_segments: &[PathSegment], | ||
113 | ) -> Ty { | ||
114 | let ty = match resolution { | ||
97 | TypeNs::Trait(trait_) => { | 115 | TypeNs::Trait(trait_) => { |
98 | let segment = match remaining_index { | 116 | let trait_ref = |
99 | None => path.segments.last().expect("resolved path has at least one element"), | 117 | TraitRef::from_resolved_path(db, resolver, trait_, resolved_segment, None); |
100 | Some(i) => &path.segments[i - 1], | 118 | return if remaining_segments.len() == 1 { |
101 | }; | 119 | let segment = &remaining_segments[0]; |
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | 120 | match trait_ref |
103 | return if let Some(remaining_index) = remaining_index { | 121 | .trait_ |
104 | if remaining_index == path.segments.len() - 1 { | 122 | .associated_type_by_name_including_super_traits(db, &segment.name) |
105 | let segment = &path.segments[remaining_index]; | 123 | { |
106 | match trait_ref | 124 | Some(associated_ty) => { |
107 | .trait_ | 125 | // FIXME handle type parameters on the segment |
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | 126 | Ty::Projection(ProjectionTy { |
109 | { | 127 | associated_ty, |
110 | Some(associated_ty) => { | 128 | parameters: trait_ref.substs, |
111 | // FIXME handle type parameters on the segment | 129 | }) |
112 | Ty::Projection(ProjectionTy { | 130 | } |
113 | associated_ty, | 131 | None => { |
114 | parameters: trait_ref.substs, | 132 | // FIXME: report error (associated type not found) |
115 | }) | 133 | Ty::Unknown |
116 | } | ||
117 | None => { | ||
118 | // associated type not found | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | 134 | } |
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | 135 | } |
136 | } else if remaining_segments.len() > 1 { | ||
137 | // FIXME report error (ambiguous associated type) | ||
138 | Ty::Unknown | ||
126 | } else { | 139 | } else { |
127 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) | 140 | Ty::Dyn(Arc::new([GenericPredicate::Implemented(trait_ref)])) |
128 | }; | 141 | }; |
129 | } | 142 | } |
130 | TypeNs::GenericParam(idx) => { | 143 | TypeNs::GenericParam(idx) => { |
131 | if remaining_index.is_some() { | 144 | // FIXME: maybe return name in resolution? |
132 | // e.g. T::Item | 145 | let name = resolved_segment.name.clone(); |
133 | return Ty::Unknown; | 146 | Ty::Param { idx, name } |
134 | } | ||
135 | return Ty::Param { | ||
136 | idx, | ||
137 | // FIXME: maybe return name in resolution? | ||
138 | name: path | ||
139 | .as_ident() | ||
140 | .expect("generic param should be single-segment path") | ||
141 | .clone(), | ||
142 | }; | ||
143 | } | ||
144 | TypeNs::SelfType(impl_block) => { | ||
145 | if remaining_index.is_some() { | ||
146 | // e.g. Self::Item | ||
147 | return Ty::Unknown; | ||
148 | } | ||
149 | return impl_block.target_ty(db); | ||
150 | } | 147 | } |
148 | TypeNs::SelfType(impl_block) => impl_block.target_ty(db), | ||
151 | 149 | ||
152 | TypeNs::Adt(it) => it.into(), | 150 | TypeNs::Adt(it) => Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()), |
153 | TypeNs::BuiltinType(it) => it.into(), | 151 | TypeNs::BuiltinType(it) => { |
154 | TypeNs::TypeAlias(it) => it.into(), | 152 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) |
153 | } | ||
154 | TypeNs::TypeAlias(it) => { | ||
155 | Ty::from_hir_path_inner(db, resolver, resolved_segment, it.into()) | ||
156 | } | ||
155 | // FIXME: report error | 157 | // FIXME: report error |
156 | TypeNs::EnumVariant(_) => return Ty::Unknown, | 158 | TypeNs::EnumVariant(_) => return Ty::Unknown, |
157 | }; | 159 | }; |
158 | 160 | ||
161 | Ty::from_type_relative_path(db, resolver, ty, remaining_segments) | ||
162 | } | ||
163 | |||
164 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | ||
165 | // Resolve the path (in type namespace) | ||
166 | if let crate::PathKind::Type(type_ref) = &path.kind { | ||
167 | let ty = Ty::from_hir(db, resolver, &type_ref); | ||
168 | let remaining_segments = &path.segments[..]; | ||
169 | return Ty::from_type_relative_path(db, resolver, ty, remaining_segments); | ||
170 | } | ||
171 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { | ||
172 | Some(it) => it, | ||
173 | None => return Ty::Unknown, | ||
174 | }; | ||
175 | let (resolved_segment, remaining_segments) = match remaining_index { | ||
176 | None => ( | ||
177 | path.segments.last().expect("resolved path has at least one element"), | ||
178 | &[] as &[PathSegment], | ||
179 | ), | ||
180 | Some(i) => (&path.segments[i - 1], &path.segments[i..]), | ||
181 | }; | ||
182 | Ty::from_partly_resolved_hir_path( | ||
183 | db, | ||
184 | resolver, | ||
185 | resolution, | ||
186 | resolved_segment, | ||
187 | remaining_segments, | ||
188 | ) | ||
189 | } | ||
190 | |||
191 | fn select_associated_type( | ||
192 | _db: &impl HirDatabase, | ||
193 | _resolver: &Resolver, | ||
194 | _self_ty: Ty, | ||
195 | _segment: &PathSegment, | ||
196 | ) -> Ty { | ||
197 | Ty::Unknown | ||
198 | } | ||
199 | |||
200 | fn from_hir_path_inner( | ||
201 | db: &impl HirDatabase, | ||
202 | resolver: &Resolver, | ||
203 | segment: &PathSegment, | ||
204 | typable: TypableDef, | ||
205 | ) -> Ty { | ||
159 | let ty = db.type_for_def(typable, Namespace::Types); | 206 | let ty = db.type_for_def(typable, Namespace::Types); |
160 | let substs = Ty::substs_from_path(db, resolver, path, typable); | 207 | let substs = Ty::substs_from_path_segment(db, resolver, segment, typable); |
161 | ty.subst(&substs) | 208 | ty.subst(&substs) |
162 | } | 209 | } |
163 | 210 | ||