diff options
Diffstat (limited to 'crates/ra_hir/src/ty')
-rw-r--r-- | crates/ra_hir/src/ty/lower.rs | 53 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/tests.rs | 41 | ||||
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 68 |
3 files changed, 138 insertions, 24 deletions
diff --git a/crates/ra_hir/src/ty/lower.rs b/crates/ra_hir/src/ty/lower.rs index 8bab7e54b..09d26ce5a 100644 --- a/crates/ra_hir/src/ty/lower.rs +++ b/crates/ra_hir/src/ty/lower.rs | |||
@@ -5,6 +5,7 @@ | |||
5 | //! - Building the type for an item: This happens through the `type_for_def` query. | 5 | //! - Building the type for an item: This happens through the `type_for_def` query. |
6 | //! | 6 | //! |
7 | //! This usually involves resolving names, collecting generic arguments etc. | 7 | //! This usually involves resolving names, collecting generic arguments etc. |
8 | use std::sync::Arc; | ||
8 | use std::iter; | 9 | use std::iter; |
9 | 10 | ||
10 | use crate::{ | 11 | use crate::{ |
@@ -18,9 +19,9 @@ use crate::{ | |||
18 | resolve::{Resolver, Resolution}, | 19 | resolve::{Resolver, Resolution}, |
19 | path::{PathSegment, GenericArg}, | 20 | path::{PathSegment, GenericArg}, |
20 | generics::{GenericParams, HasGenericParams}, | 21 | generics::{GenericParams, HasGenericParams}, |
21 | adt::VariantDef, Trait | 22 | adt::VariantDef, Trait, generics::{ WherePredicate, GenericDef} |
22 | }; | 23 | }; |
23 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef}; | 24 | use super::{Ty, primitive, FnSig, Substs, TypeCtor, TraitRef, GenericPredicate}; |
24 | 25 | ||
25 | impl Ty { | 26 | impl Ty { |
26 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { | 27 | pub(crate) fn from_hir(db: &impl HirDatabase, resolver: &Resolver, type_ref: &TypeRef) -> Self { |
@@ -208,16 +209,12 @@ pub(super) fn substs_from_path_segment( | |||
208 | } | 209 | } |
209 | 210 | ||
210 | impl TraitRef { | 211 | impl TraitRef { |
211 | pub(crate) fn from_hir( | 212 | pub(crate) fn from_path( |
212 | db: &impl HirDatabase, | 213 | db: &impl HirDatabase, |
213 | resolver: &Resolver, | 214 | resolver: &Resolver, |
214 | type_ref: &TypeRef, | 215 | path: &Path, |
215 | explicit_self_ty: Option<Ty>, | 216 | explicit_self_ty: Option<Ty>, |
216 | ) -> Option<Self> { | 217 | ) -> Option<Self> { |
217 | let path = match type_ref { | ||
218 | TypeRef::Path(path) => path, | ||
219 | _ => return None, | ||
220 | }; | ||
221 | let resolved = match resolver.resolve_path(db, &path).take_types()? { | 218 | let resolved = match resolver.resolve_path(db, &path).take_types()? { |
222 | Resolution::Def(ModuleDef::Trait(tr)) => tr, | 219 | Resolution::Def(ModuleDef::Trait(tr)) => tr, |
223 | _ => return None, | 220 | _ => return None, |
@@ -232,6 +229,19 @@ impl TraitRef { | |||
232 | Some(TraitRef { trait_: resolved, substs }) | 229 | Some(TraitRef { trait_: resolved, substs }) |
233 | } | 230 | } |
234 | 231 | ||
232 | pub(crate) fn from_hir( | ||
233 | db: &impl HirDatabase, | ||
234 | resolver: &Resolver, | ||
235 | type_ref: &TypeRef, | ||
236 | explicit_self_ty: Option<Ty>, | ||
237 | ) -> Option<Self> { | ||
238 | let path = match type_ref { | ||
239 | TypeRef::Path(path) => path, | ||
240 | _ => return None, | ||
241 | }; | ||
242 | TraitRef::from_path(db, resolver, path, explicit_self_ty) | ||
243 | } | ||
244 | |||
235 | fn substs_from_path( | 245 | fn substs_from_path( |
236 | db: &impl HirDatabase, | 246 | db: &impl HirDatabase, |
237 | resolver: &Resolver, | 247 | resolver: &Resolver, |
@@ -246,6 +256,15 @@ impl TraitRef { | |||
246 | let substs = Substs::identity(&trait_.generic_params(db)); | 256 | let substs = Substs::identity(&trait_.generic_params(db)); |
247 | TraitRef { trait_, substs } | 257 | TraitRef { trait_, substs } |
248 | } | 258 | } |
259 | |||
260 | pub(crate) fn for_where_predicate( | ||
261 | db: &impl HirDatabase, | ||
262 | resolver: &Resolver, | ||
263 | pred: &WherePredicate, | ||
264 | ) -> Option<TraitRef> { | ||
265 | let self_ty = Ty::from_hir(db, resolver, &pred.type_ref); | ||
266 | TraitRef::from_path(db, resolver, &pred.trait_ref, Some(self_ty)) | ||
267 | } | ||
249 | } | 268 | } |
250 | 269 | ||
251 | /// Build the declared type of an item. This depends on the namespace; e.g. for | 270 | /// Build the declared type of an item. This depends on the namespace; e.g. for |
@@ -294,6 +313,24 @@ pub(crate) fn type_for_field(db: &impl HirDatabase, field: StructField) -> Ty { | |||
294 | Ty::from_hir(db, &resolver, type_ref) | 313 | Ty::from_hir(db, &resolver, type_ref) |
295 | } | 314 | } |
296 | 315 | ||
316 | /// Resolve the where clause(s) of an item with generics. | ||
317 | pub(crate) fn generic_predicates( | ||
318 | db: &impl HirDatabase, | ||
319 | def: GenericDef, | ||
320 | ) -> Arc<[GenericPredicate]> { | ||
321 | let resolver = def.resolver(db); | ||
322 | let generic_params = def.generic_params(db); | ||
323 | let predicates = generic_params | ||
324 | .where_predicates | ||
325 | .iter() | ||
326 | .map(|pred| { | ||
327 | TraitRef::for_where_predicate(db, &resolver, pred) | ||
328 | .map_or(GenericPredicate::Error, GenericPredicate::Implemented) | ||
329 | }) | ||
330 | .collect::<Vec<_>>(); | ||
331 | predicates.into() | ||
332 | } | ||
333 | |||
297 | fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { | 334 | fn fn_sig_for_fn(db: &impl HirDatabase, def: Function) -> FnSig { |
298 | let signature = def.signature(db); | 335 | let signature = def.signature(db); |
299 | let resolver = def.resolver(db); | 336 | let resolver = def.resolver(db); |
diff --git a/crates/ra_hir/src/ty/tests.rs b/crates/ra_hir/src/ty/tests.rs index a38fe35c7..c3edf42b1 100644 --- a/crates/ra_hir/src/ty/tests.rs +++ b/crates/ra_hir/src/ty/tests.rs | |||
@@ -2510,12 +2510,47 @@ fn method_resolution_where_clause_not_met() { | |||
2510 | trait Clone {} | 2510 | trait Clone {} |
2511 | trait Trait { fn foo(self) -> u128; } | 2511 | trait Trait { fn foo(self) -> u128; } |
2512 | struct S; | 2512 | struct S; |
2513 | impl S { fn foo(self) -> i8 { 0 } } | 2513 | impl<T> Trait for T where T: Clone {} |
2514 | impl<T> Trait for T where T: Clone { fn foo(self) -> u128 { 0 } } | ||
2515 | fn test() { (&S).foo()<|>; } | 2514 | fn test() { (&S).foo()<|>; } |
2516 | "#, | 2515 | "#, |
2517 | ); | 2516 | ); |
2518 | assert_eq!(t, "i8"); | 2517 | // This is also to make sure that we don't resolve to the foo method just |
2518 | // because that's the only method named foo we can find, which would make | ||
2519 | // the below tests not work | ||
2520 | assert_eq!(t, "{unknown}"); | ||
2521 | } | ||
2522 | |||
2523 | #[test] | ||
2524 | fn method_resolution_where_clause_1() { | ||
2525 | let t = type_at( | ||
2526 | r#" | ||
2527 | //- /main.rs | ||
2528 | trait Clone {} | ||
2529 | trait Trait { fn foo(self) -> u128; } | ||
2530 | struct S; | ||
2531 | impl Clone for S {}; | ||
2532 | impl<T> Trait for T where T: Clone {} | ||
2533 | fn test() { S.foo()<|>; } | ||
2534 | "#, | ||
2535 | ); | ||
2536 | assert_eq!(t, "u128"); | ||
2537 | } | ||
2538 | |||
2539 | #[test] | ||
2540 | fn method_resolution_where_clause_2() { | ||
2541 | let t = type_at( | ||
2542 | r#" | ||
2543 | //- /main.rs | ||
2544 | trait Into<T> { fn into(self) -> T; } | ||
2545 | trait From<T> { fn from(other: T) -> Self; } | ||
2546 | struct S1; | ||
2547 | struct S2; | ||
2548 | impl From<S2> for S1 {}; | ||
2549 | impl<T, U> Into<U> for T where U: From<T> {} | ||
2550 | fn test() { S2.into()<|>; } | ||
2551 | "#, | ||
2552 | ); | ||
2553 | assert_eq!(t, "S1"); | ||
2519 | } | 2554 | } |
2520 | 2555 | ||
2521 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { | 2556 | fn type_at_pos(db: &MockDatabase, pos: FilePosition) -> String { |
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 8b77d21b4..2772a0432 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -11,7 +11,7 @@ use ra_db::salsa::{InternId, InternKey}; | |||
11 | use crate::{ | 11 | use crate::{ |
12 | Trait, HasGenericParams, ImplBlock, | 12 | Trait, HasGenericParams, ImplBlock, |
13 | db::HirDatabase, | 13 | db::HirDatabase, |
14 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, | 14 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate}, generics::GenericDef, |
15 | }; | 15 | }; |
16 | use super::ChalkContext; | 16 | use super::ChalkContext; |
17 | 17 | ||
@@ -146,6 +146,27 @@ impl ToChalk for ImplBlock { | |||
146 | } | 146 | } |
147 | } | 147 | } |
148 | 148 | ||
149 | impl ToChalk for GenericPredicate { | ||
150 | type Chalk = chalk_ir::QuantifiedWhereClause; | ||
151 | |||
152 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { | ||
153 | match self { | ||
154 | GenericPredicate::Implemented(trait_ref) => { | ||
155 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | ||
156 | } | ||
157 | GenericPredicate::Error => panic!("Trying to pass errored where clause to Chalk"), | ||
158 | } | ||
159 | } | ||
160 | |||
161 | fn from_chalk( | ||
162 | _db: &impl HirDatabase, | ||
163 | _where_clause: chalk_ir::QuantifiedWhereClause, | ||
164 | ) -> GenericPredicate { | ||
165 | // This should never need to be called | ||
166 | unimplemented!() | ||
167 | } | ||
168 | } | ||
169 | |||
149 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 170 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { |
150 | chalk_ir::Binders { | 171 | chalk_ir::Binders { |
151 | value, | 172 | value, |
@@ -153,6 +174,25 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | |||
153 | } | 174 | } |
154 | } | 175 | } |
155 | 176 | ||
177 | fn convert_where_clauses( | ||
178 | db: &impl HirDatabase, | ||
179 | def: GenericDef, | ||
180 | substs: &Substs, | ||
181 | ) -> (Vec<chalk_ir::QuantifiedWhereClause>, bool) { | ||
182 | let generic_predicates = db.generic_predicates(def); | ||
183 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
184 | let mut has_error = false; | ||
185 | for pred in generic_predicates.iter() { | ||
186 | // FIXME: it would probably be nicer if we could just convert errored predicates to a where clause that is never true... | ||
187 | if pred.is_error() { | ||
188 | has_error = true; | ||
189 | } else { | ||
190 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
191 | } | ||
192 | } | ||
193 | (result, has_error) | ||
194 | } | ||
195 | |||
156 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | 196 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> |
157 | where | 197 | where |
158 | DB: HirDatabase, | 198 | DB: HirDatabase, |
@@ -173,7 +213,7 @@ where | |||
173 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), | 213 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), |
174 | fundamental: false, | 214 | fundamental: false, |
175 | }; | 215 | }; |
176 | let where_clauses = Vec::new(); // FIXME add where clauses | 216 | let (where_clauses, _) = convert_where_clauses(self.db, trait_.into(), &bound_vars); |
177 | let associated_ty_ids = Vec::new(); // FIXME add associated tys | 217 | let associated_ty_ids = Vec::new(); // FIXME add associated tys |
178 | let trait_datum_bound = | 218 | let trait_datum_bound = |
179 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; | 219 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; |
@@ -185,21 +225,26 @@ where | |||
185 | let type_ctor = from_chalk(self.db, struct_id); | 225 | let type_ctor = from_chalk(self.db, struct_id); |
186 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor | 226 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor |
187 | // FIXME extract this to a method on Ty | 227 | // FIXME extract this to a method on Ty |
188 | let (num_params, upstream) = match type_ctor { | 228 | let (num_params, where_clauses, upstream) = match type_ctor { |
189 | TypeCtor::Bool | 229 | TypeCtor::Bool |
190 | | TypeCtor::Char | 230 | | TypeCtor::Char |
191 | | TypeCtor::Int(_) | 231 | | TypeCtor::Int(_) |
192 | | TypeCtor::Float(_) | 232 | | TypeCtor::Float(_) |
193 | | TypeCtor::Never | 233 | | TypeCtor::Never |
194 | | TypeCtor::Str => (0, true), | 234 | | TypeCtor::Str => (0, vec![], true), |
195 | TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true), | 235 | TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => { |
196 | TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true), | 236 | (1, vec![], true) |
197 | TypeCtor::Tuple { cardinality } => (cardinality as usize, true), | 237 | } |
238 | TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true), | ||
239 | TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true), | ||
198 | TypeCtor::FnDef(_) => unimplemented!(), | 240 | TypeCtor::FnDef(_) => unimplemented!(), |
199 | TypeCtor::Adt(adt) => { | 241 | TypeCtor::Adt(adt) => { |
200 | let generic_params = adt.generic_params(self.db); | 242 | let generic_params = adt.generic_params(self.db); |
243 | let bound_vars = Substs::bound_vars(&generic_params); | ||
244 | let (where_clauses, _) = convert_where_clauses(self.db, adt.into(), &bound_vars); | ||
201 | ( | 245 | ( |
202 | generic_params.count_params_including_parent(), | 246 | generic_params.count_params_including_parent(), |
247 | where_clauses, | ||
203 | adt.krate(self.db) != Some(self.krate), | 248 | adt.krate(self.db) != Some(self.krate), |
204 | ) | 249 | ) |
205 | } | 250 | } |
@@ -209,7 +254,6 @@ where | |||
209 | // FIXME set fundamental flag correctly | 254 | // FIXME set fundamental flag correctly |
210 | fundamental: false, | 255 | fundamental: false, |
211 | }; | 256 | }; |
212 | let where_clauses = Vec::new(); // FIXME add where clauses | ||
213 | let self_ty = chalk_ir::ApplicationTy { | 257 | let self_ty = chalk_ir::ApplicationTy { |
214 | name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), | 258 | name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), |
215 | parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), | 259 | parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), |
@@ -237,10 +281,12 @@ where | |||
237 | } else { | 281 | } else { |
238 | chalk_rust_ir::ImplType::External | 282 | chalk_rust_ir::ImplType::External |
239 | }; | 283 | }; |
284 | let (where_clauses, where_clause_error) = | ||
285 | convert_where_clauses(self.db, impl_block.into(), &bound_vars); | ||
240 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | 286 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { |
241 | // FIXME handle negative impls (impl !Sync for Foo) | 287 | // FIXME handle negative impls (impl !Sync for Foo) |
242 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), | 288 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), |
243 | where_clauses: Vec::new(), // FIXME add where clauses | 289 | where_clauses, |
244 | associated_ty_values: Vec::new(), // FIXME add associated type values | 290 | associated_ty_values: Vec::new(), // FIXME add associated type values |
245 | impl_type, | 291 | impl_type, |
246 | }; | 292 | }; |
@@ -253,10 +299,6 @@ where | |||
253 | self.db | 299 | self.db |
254 | .impls_for_trait(self.krate, trait_) | 300 | .impls_for_trait(self.krate, trait_) |
255 | .iter() | 301 | .iter() |
256 | // FIXME temporary hack -- as long as we're not lowering where clauses | ||
257 | // correctly, ignore impls with them completely so as to not treat | ||
258 | // impl<T> Trait for T where T: ... as a blanket impl on all types | ||
259 | .filter(|impl_block| impl_block.generic_params(self.db).where_predicates.is_empty()) | ||
260 | .map(|impl_block| impl_block.to_chalk(self.db)) | 302 | .map(|impl_block| impl_block.to_chalk(self.db)) |
261 | .collect() | 303 | .collect() |
262 | } | 304 | } |