diff options
Diffstat (limited to 'crates/ra_hir/src/ty/lower.rs')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 108 |
1 files changed, 53 insertions, 55 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 946e9e9fb..3fdb2ca92 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -19,7 +19,7 @@ use crate::{ | |||
19 | generics::{GenericDef, WherePredicate}, | 19 | generics::{GenericDef, WherePredicate}, |
20 | nameres::Namespace, | 20 | nameres::Namespace, |
21 | path::{GenericArg, PathSegment}, | 21 | path::{GenericArg, PathSegment}, |
22 | resolve::{Resolution, Resolver}, | 22 | resolve::{Resolver, TypeNs}, |
23 | ty::Adt, | 23 | ty::Adt, |
24 | type_ref::{TypeBound, TypeRef}, | 24 | type_ref::{TypeBound, TypeRef}, |
25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, | 25 | BuiltinType, Const, Enum, EnumVariant, Function, ModuleDef, Path, Static, Struct, StructField, |
@@ -88,16 +88,47 @@ impl Ty { | |||
88 | 88 | ||
89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { | 89 | pub(crate) fn from_hir_path(db: &impl HirDatabase, resolver: &Resolver, path: &Path) -> Ty { |
90 | // Resolve the path (in type namespace) | 90 | // Resolve the path (in type namespace) |
91 | let (resolution, remaining_index) = resolver.resolve_path_segments(db, path).into_inner(); | 91 | let (resolution, remaining_index) = match resolver.resolve_path_in_type_ns(db, path) { |
92 | let resolution = resolution.take_types(); | 92 | Some(it) => it, |
93 | 93 | None => return Ty::Unknown, | |
94 | let def = match resolution { | 94 | }; |
95 | Some(Resolution::Def(def)) => def, | 95 | |
96 | Some(Resolution::LocalBinding(..)) => { | 96 | let typable: TypableDef = match resolution { |
97 | // this should never happen | 97 | TypeNs::Trait(trait_) => { |
98 | panic!("path resolved to local binding in type ns"); | 98 | let segment = match remaining_index { |
99 | None => path.segments.last().expect("resolved path has at least one element"), | ||
100 | Some(i) => &path.segments[i - 1], | ||
101 | }; | ||
102 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
103 | return if let Some(remaining_index) = remaining_index { | ||
104 | if remaining_index == path.segments.len() - 1 { | ||
105 | let segment = &path.segments[remaining_index]; | ||
106 | match trait_ref | ||
107 | .trait_ | ||
108 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
109 | { | ||
110 | Some(associated_ty) => { | ||
111 | // FIXME handle type parameters on the segment | ||
112 | Ty::Projection(ProjectionTy { | ||
113 | associated_ty, | ||
114 | parameters: trait_ref.substs, | ||
115 | }) | ||
116 | } | ||
117 | None => { | ||
118 | // associated type not found | ||
119 | Ty::Unknown | ||
120 | } | ||
121 | } | ||
122 | } else { | ||
123 | // FIXME more than one segment remaining, is this possible? | ||
124 | Ty::Unknown | ||
125 | } | ||
126 | } else { | ||
127 | // FIXME dyn Trait without the dyn | ||
128 | Ty::Unknown | ||
129 | }; | ||
99 | } | 130 | } |
100 | Some(Resolution::GenericParam(idx)) => { | 131 | TypeNs::GenericParam(idx) => { |
101 | if remaining_index.is_some() { | 132 | if remaining_index.is_some() { |
102 | // e.g. T::Item | 133 | // e.g. T::Item |
103 | return Ty::Unknown; | 134 | return Ty::Unknown; |
@@ -111,57 +142,24 @@ impl Ty { | |||
111 | .clone(), | 142 | .clone(), |
112 | }; | 143 | }; |
113 | } | 144 | } |
114 | Some(Resolution::SelfType(impl_block)) => { | 145 | TypeNs::SelfType(impl_block) => { |
115 | if remaining_index.is_some() { | 146 | if remaining_index.is_some() { |
116 | // e.g. Self::Item | 147 | // e.g. Self::Item |
117 | return Ty::Unknown; | 148 | return Ty::Unknown; |
118 | } | 149 | } |
119 | return impl_block.target_ty(db); | 150 | return impl_block.target_ty(db); |
120 | } | 151 | } |
121 | None => { | 152 | |
122 | // path did not resolve | 153 | TypeNs::Adt(it) => it.into(), |
123 | return Ty::Unknown; | 154 | TypeNs::BuiltinType(it) => it.into(), |
124 | } | 155 | TypeNs::TypeAlias(it) => it.into(), |
156 | // FIXME: report error | ||
157 | TypeNs::EnumVariant(_) => return Ty::Unknown, | ||
125 | }; | 158 | }; |
126 | 159 | ||
127 | if let ModuleDef::Trait(trait_) = def { | 160 | let ty = db.type_for_def(typable, Namespace::Types); |
128 | let segment = match remaining_index { | 161 | let substs = Ty::substs_from_path(db, resolver, path, typable); |
129 | None => path.segments.last().expect("resolved path has at least one element"), | 162 | ty.subst(&substs) |
130 | Some(i) => &path.segments[i - 1], | ||
131 | }; | ||
132 | let trait_ref = TraitRef::from_resolved_path(db, resolver, trait_, segment, None); | ||
133 | if let Some(remaining_index) = remaining_index { | ||
134 | if remaining_index == path.segments.len() - 1 { | ||
135 | let segment = &path.segments[remaining_index]; | ||
136 | let associated_ty = match trait_ref | ||
137 | .trait_ | ||
138 | .associated_type_by_name_including_super_traits(db, &segment.name) | ||
139 | { | ||
140 | Some(t) => t, | ||
141 | None => { | ||
142 | // associated type not found | ||
143 | return Ty::Unknown; | ||
144 | } | ||
145 | }; | ||
146 | // FIXME handle type parameters on the segment | ||
147 | Ty::Projection(ProjectionTy { associated_ty, parameters: trait_ref.substs }) | ||
148 | } else { | ||
149 | // FIXME more than one segment remaining, is this possible? | ||
150 | Ty::Unknown | ||
151 | } | ||
152 | } else { | ||
153 | // FIXME dyn Trait without the dyn | ||
154 | Ty::Unknown | ||
155 | } | ||
156 | } else { | ||
157 | let typable: TypableDef = match def.into() { | ||
158 | None => return Ty::Unknown, | ||
159 | Some(it) => it, | ||
160 | }; | ||
161 | let ty = db.type_for_def(typable, Namespace::Types); | ||
162 | let substs = Ty::substs_from_path(db, resolver, path, typable); | ||
163 | ty.subst(&substs) | ||
164 | } | ||
165 | } | 163 | } |
166 | 164 | ||
167 | pub(super) fn substs_from_path_segment( | 165 | pub(super) fn substs_from_path_segment( |
@@ -278,8 +276,8 @@ impl TraitRef { | |||
278 | path: &Path, | 276 | path: &Path, |
279 | explicit_self_ty: Option<Ty>, | 277 | explicit_self_ty: Option<Ty>, |
280 | ) -> Option<Self> { | 278 | ) -> Option<Self> { |
281 | let resolved = match resolver.resolve_path_without_assoc_items(db, &path).take_types()? { | 279 | let resolved = match resolver.resolve_path_in_type_ns_fully(db, &path)? { |
282 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 280 | TypeNs::Trait(tr) => tr, |
283 | _ => return None, | 281 | _ => return None, |
284 | }; | 282 | }; |
285 | let segment = path.segments.last().expect("path should have at least one segment"); | 283 | let segment = path.segments.last().expect("path should have at least one segment"); |