diff options
Diffstat (limited to 'crates/ra_hir/src/ty/traits')
-rw-r--r-- | crates/ra_hir/src/ty/traits/chalk.rs | 179 |
1 files changed, 157 insertions, 22 deletions
diff --git a/crates/ra_hir/src/ty/traits/chalk.rs b/crates/ra_hir/src/ty/traits/chalk.rs index 8b77d21b4..78440b258 100644 --- a/crates/ra_hir/src/ty/traits/chalk.rs +++ b/crates/ra_hir/src/ty/traits/chalk.rs | |||
@@ -6,15 +6,22 @@ use log::debug; | |||
6 | use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; | 6 | use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; |
7 | use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; | 7 | use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; |
8 | 8 | ||
9 | use test_utils::tested_by; | ||
9 | use ra_db::salsa::{InternId, InternKey}; | 10 | use ra_db::salsa::{InternId, InternKey}; |
10 | 11 | ||
11 | use crate::{ | 12 | use crate::{ |
12 | Trait, HasGenericParams, ImplBlock, | 13 | Trait, HasGenericParams, ImplBlock, |
13 | db::HirDatabase, | 14 | db::HirDatabase, |
14 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs}, | 15 | ty::{TraitRef, Ty, ApplicationTy, TypeCtor, Substs, GenericPredicate, CallableDef}, |
16 | ty::display::HirDisplay, | ||
17 | generics::GenericDef, | ||
15 | }; | 18 | }; |
16 | use super::ChalkContext; | 19 | use super::ChalkContext; |
17 | 20 | ||
21 | /// This represents a trait whose name we could not resolve. | ||
22 | const UNKNOWN_TRAIT: chalk_ir::TraitId = | ||
23 | chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() }); | ||
24 | |||
18 | pub(super) trait ToChalk { | 25 | pub(super) trait ToChalk { |
19 | type Chalk; | 26 | type Chalk; |
20 | fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; | 27 | fn to_chalk(self, db: &impl HirDatabase) -> Self::Chalk; |
@@ -45,7 +52,10 @@ impl ToChalk for Ty { | |||
45 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), | 52 | Ty::Infer(_infer_ty) => panic!("uncanonicalized infer ty"), |
46 | // FIXME this is clearly incorrect, but probably not too incorrect | 53 | // FIXME this is clearly incorrect, but probably not too incorrect |
47 | // and I'm not sure what to actually do with Ty::Unknown | 54 | // and I'm not sure what to actually do with Ty::Unknown |
48 | Ty::Unknown => PlaceholderIndex { ui: UniverseIndex::ROOT, idx: 0 }.to_ty(), | 55 | // maybe an alternative would be `for<T> T`? (meaningless in rust, but expressible in chalk's Ty) |
56 | Ty::Unknown => { | ||
57 | PlaceholderIndex { ui: UniverseIndex::ROOT, idx: usize::max_value() }.to_ty() | ||
58 | } | ||
49 | } | 59 | } |
50 | } | 60 | } |
51 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { | 61 | fn from_chalk(db: &impl HirDatabase, chalk: chalk_ir::Ty) -> Self { |
@@ -146,6 +156,33 @@ impl ToChalk for ImplBlock { | |||
146 | } | 156 | } |
147 | } | 157 | } |
148 | 158 | ||
159 | impl ToChalk for GenericPredicate { | ||
160 | type Chalk = chalk_ir::QuantifiedWhereClause; | ||
161 | |||
162 | fn to_chalk(self, db: &impl HirDatabase) -> chalk_ir::QuantifiedWhereClause { | ||
163 | match self { | ||
164 | GenericPredicate::Implemented(trait_ref) => { | ||
165 | make_binders(chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db)), 0) | ||
166 | } | ||
167 | GenericPredicate::Error => { | ||
168 | let impossible_trait_ref = chalk_ir::TraitRef { | ||
169 | trait_id: UNKNOWN_TRAIT, | ||
170 | parameters: vec![Ty::Unknown.to_chalk(db).cast()], | ||
171 | }; | ||
172 | make_binders(chalk_ir::WhereClause::Implemented(impossible_trait_ref), 0) | ||
173 | } | ||
174 | } | ||
175 | } | ||
176 | |||
177 | fn from_chalk( | ||
178 | _db: &impl HirDatabase, | ||
179 | _where_clause: chalk_ir::QuantifiedWhereClause, | ||
180 | ) -> GenericPredicate { | ||
181 | // This should never need to be called | ||
182 | unimplemented!() | ||
183 | } | ||
184 | } | ||
185 | |||
149 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | 186 | fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { |
150 | chalk_ir::Binders { | 187 | chalk_ir::Binders { |
151 | value, | 188 | value, |
@@ -153,6 +190,40 @@ fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { | |||
153 | } | 190 | } |
154 | } | 191 | } |
155 | 192 | ||
193 | fn blacklisted_trait(db: &impl HirDatabase, trait_: Trait) -> bool { | ||
194 | let name = trait_.name(db).unwrap_or_else(crate::Name::missing).to_string(); | ||
195 | match &*name { | ||
196 | "Send" | "Sync" | "Sized" | "Fn" | "FnMut" | "FnOnce" => true, | ||
197 | _ => false, | ||
198 | } | ||
199 | } | ||
200 | |||
201 | fn convert_where_clauses( | ||
202 | db: &impl HirDatabase, | ||
203 | def: GenericDef, | ||
204 | substs: &Substs, | ||
205 | ) -> Vec<chalk_ir::QuantifiedWhereClause> { | ||
206 | let generic_predicates = db.generic_predicates(def); | ||
207 | let mut result = Vec::with_capacity(generic_predicates.len()); | ||
208 | for pred in generic_predicates.iter() { | ||
209 | if pred.is_error() { | ||
210 | // HACK: Return just the single predicate (which is always false | ||
211 | // anyway), otherwise Chalk can easily get into slow situations | ||
212 | return vec![pred.clone().subst(substs).to_chalk(db)]; | ||
213 | } | ||
214 | match pred { | ||
215 | GenericPredicate::Implemented(trait_ref) => { | ||
216 | if blacklisted_trait(db, trait_ref.trait_) { | ||
217 | continue; | ||
218 | } | ||
219 | } | ||
220 | _ => {} | ||
221 | } | ||
222 | result.push(pred.clone().subst(substs).to_chalk(db)); | ||
223 | } | ||
224 | result | ||
225 | } | ||
226 | |||
156 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> | 227 | impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> |
157 | where | 228 | where |
158 | DB: HirDatabase, | 229 | DB: HirDatabase, |
@@ -162,18 +233,36 @@ where | |||
162 | } | 233 | } |
163 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { | 234 | fn trait_datum(&self, trait_id: chalk_ir::TraitId) -> Arc<TraitDatum> { |
164 | debug!("trait_datum {:?}", trait_id); | 235 | debug!("trait_datum {:?}", trait_id); |
236 | if trait_id == UNKNOWN_TRAIT { | ||
237 | let trait_datum_bound = chalk_rust_ir::TraitDatumBound { | ||
238 | trait_ref: chalk_ir::TraitRef { | ||
239 | trait_id: UNKNOWN_TRAIT, | ||
240 | parameters: vec![chalk_ir::Ty::BoundVar(0).cast()], | ||
241 | }, | ||
242 | associated_ty_ids: Vec::new(), | ||
243 | where_clauses: Vec::new(), | ||
244 | flags: chalk_rust_ir::TraitFlags { | ||
245 | auto: false, | ||
246 | marker: false, | ||
247 | upstream: true, | ||
248 | fundamental: false, | ||
249 | }, | ||
250 | }; | ||
251 | return Arc::new(TraitDatum { binders: make_binders(trait_datum_bound, 1) }); | ||
252 | } | ||
165 | let trait_: Trait = from_chalk(self.db, trait_id); | 253 | let trait_: Trait = from_chalk(self.db, trait_id); |
254 | debug!("trait {:?} = {:?}", trait_id, trait_.name(self.db)); | ||
166 | let generic_params = trait_.generic_params(self.db); | 255 | let generic_params = trait_.generic_params(self.db); |
167 | let bound_vars = Substs::bound_vars(&generic_params); | 256 | let bound_vars = Substs::bound_vars(&generic_params); |
168 | let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); | 257 | let trait_ref = trait_.trait_ref(self.db).subst(&bound_vars).to_chalk(self.db); |
169 | let flags = chalk_rust_ir::TraitFlags { | 258 | let flags = chalk_rust_ir::TraitFlags { |
259 | auto: trait_.is_auto(self.db), | ||
260 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), | ||
170 | // FIXME set these flags correctly | 261 | // FIXME set these flags correctly |
171 | auto: false, | ||
172 | marker: false, | 262 | marker: false, |
173 | upstream: trait_.module(self.db).krate(self.db) != Some(self.krate), | ||
174 | fundamental: false, | 263 | fundamental: false, |
175 | }; | 264 | }; |
176 | let where_clauses = Vec::new(); // FIXME add where clauses | 265 | let where_clauses = convert_where_clauses(self.db, trait_.into(), &bound_vars); |
177 | let associated_ty_ids = Vec::new(); // FIXME add associated tys | 266 | let associated_ty_ids = Vec::new(); // FIXME add associated tys |
178 | let trait_datum_bound = | 267 | let trait_datum_bound = |
179 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; | 268 | chalk_rust_ir::TraitDatumBound { trait_ref, where_clauses, flags, associated_ty_ids }; |
@@ -183,23 +272,51 @@ where | |||
183 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { | 272 | fn struct_datum(&self, struct_id: chalk_ir::StructId) -> Arc<StructDatum> { |
184 | debug!("struct_datum {:?}", struct_id); | 273 | debug!("struct_datum {:?}", struct_id); |
185 | let type_ctor = from_chalk(self.db, struct_id); | 274 | let type_ctor = from_chalk(self.db, struct_id); |
275 | debug!("struct {:?} = {:?}", struct_id, type_ctor); | ||
186 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor | 276 | // FIXME might be nicer if we can create a fake GenericParams for the TypeCtor |
187 | // FIXME extract this to a method on Ty | 277 | // FIXME extract this to a method on Ty |
188 | let (num_params, upstream) = match type_ctor { | 278 | let (num_params, where_clauses, upstream) = match type_ctor { |
189 | TypeCtor::Bool | 279 | TypeCtor::Bool |
190 | | TypeCtor::Char | 280 | | TypeCtor::Char |
191 | | TypeCtor::Int(_) | 281 | | TypeCtor::Int(_) |
192 | | TypeCtor::Float(_) | 282 | | TypeCtor::Float(_) |
193 | | TypeCtor::Never | 283 | | TypeCtor::Never |
194 | | TypeCtor::Str => (0, true), | 284 | | TypeCtor::Str => (0, vec![], true), |
195 | TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => (1, true), | 285 | TypeCtor::Slice | TypeCtor::Array | TypeCtor::RawPtr(_) | TypeCtor::Ref(_) => { |
196 | TypeCtor::FnPtr { num_args } => (num_args as usize + 1, true), | 286 | (1, vec![], true) |
197 | TypeCtor::Tuple { cardinality } => (cardinality as usize, true), | 287 | } |
198 | TypeCtor::FnDef(_) => unimplemented!(), | 288 | TypeCtor::FnPtr { num_args } => (num_args as usize + 1, vec![], true), |
289 | TypeCtor::Tuple { cardinality } => (cardinality as usize, vec![], true), | ||
290 | TypeCtor::FnDef(callable) => { | ||
291 | tested_by!(trait_resolution_on_fn_type); | ||
292 | let krate = match callable { | ||
293 | CallableDef::Function(f) => f.module(self.db).krate(self.db), | ||
294 | CallableDef::Struct(s) => s.module(self.db).krate(self.db), | ||
295 | CallableDef::EnumVariant(v) => { | ||
296 | v.parent_enum(self.db).module(self.db).krate(self.db) | ||
297 | } | ||
298 | }; | ||
299 | let generic_def: GenericDef = match callable { | ||
300 | CallableDef::Function(f) => f.into(), | ||
301 | CallableDef::Struct(s) => s.into(), | ||
302 | CallableDef::EnumVariant(v) => v.parent_enum(self.db).into(), | ||
303 | }; | ||
304 | let generic_params = generic_def.generic_params(self.db); | ||
305 | let bound_vars = Substs::bound_vars(&generic_params); | ||
306 | let where_clauses = convert_where_clauses(self.db, generic_def, &bound_vars); | ||
307 | ( | ||
308 | generic_params.count_params_including_parent(), | ||
309 | where_clauses, | ||
310 | krate != Some(self.krate), | ||
311 | ) | ||
312 | } | ||
199 | TypeCtor::Adt(adt) => { | 313 | TypeCtor::Adt(adt) => { |
200 | let generic_params = adt.generic_params(self.db); | 314 | let generic_params = adt.generic_params(self.db); |
315 | let bound_vars = Substs::bound_vars(&generic_params); | ||
316 | let where_clauses = convert_where_clauses(self.db, adt.into(), &bound_vars); | ||
201 | ( | 317 | ( |
202 | generic_params.count_params_including_parent(), | 318 | generic_params.count_params_including_parent(), |
319 | where_clauses, | ||
203 | adt.krate(self.db) != Some(self.krate), | 320 | adt.krate(self.db) != Some(self.krate), |
204 | ) | 321 | ) |
205 | } | 322 | } |
@@ -209,7 +326,6 @@ where | |||
209 | // FIXME set fundamental flag correctly | 326 | // FIXME set fundamental flag correctly |
210 | fundamental: false, | 327 | fundamental: false, |
211 | }; | 328 | }; |
212 | let where_clauses = Vec::new(); // FIXME add where clauses | ||
213 | let self_ty = chalk_ir::ApplicationTy { | 329 | let self_ty = chalk_ir::ApplicationTy { |
214 | name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), | 330 | name: TypeName::TypeKindId(type_ctor.to_chalk(self.db).into()), |
215 | parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), | 331 | parameters: (0..num_params).map(|i| chalk_ir::Ty::BoundVar(i).cast()).collect(), |
@@ -237,10 +353,23 @@ where | |||
237 | } else { | 353 | } else { |
238 | chalk_rust_ir::ImplType::External | 354 | chalk_rust_ir::ImplType::External |
239 | }; | 355 | }; |
356 | let where_clauses = convert_where_clauses(self.db, impl_block.into(), &bound_vars); | ||
357 | let negative = impl_block.is_negative(self.db); | ||
358 | debug!( | ||
359 | "impl {:?}: {}{} where {:?}", | ||
360 | impl_id, | ||
361 | if negative { "!" } else { "" }, | ||
362 | trait_ref.display(self.db), | ||
363 | where_clauses | ||
364 | ); | ||
365 | let trait_ref = trait_ref.to_chalk(self.db); | ||
240 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { | 366 | let impl_datum_bound = chalk_rust_ir::ImplDatumBound { |
241 | // FIXME handle negative impls (impl !Sync for Foo) | 367 | trait_ref: if negative { |
242 | trait_ref: chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref.to_chalk(self.db)), | 368 | chalk_rust_ir::PolarizedTraitRef::Negative(trait_ref) |
243 | where_clauses: Vec::new(), // FIXME add where clauses | 369 | } else { |
370 | chalk_rust_ir::PolarizedTraitRef::Positive(trait_ref) | ||
371 | }, | ||
372 | where_clauses, | ||
244 | associated_ty_values: Vec::new(), // FIXME add associated type values | 373 | associated_ty_values: Vec::new(), // FIXME add associated type values |
245 | impl_type, | 374 | impl_type, |
246 | }; | 375 | }; |
@@ -249,16 +378,22 @@ where | |||
249 | } | 378 | } |
250 | fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { | 379 | fn impls_for_trait(&self, trait_id: chalk_ir::TraitId) -> Vec<ImplId> { |
251 | debug!("impls_for_trait {:?}", trait_id); | 380 | debug!("impls_for_trait {:?}", trait_id); |
252 | let trait_ = from_chalk(self.db, trait_id); | 381 | if trait_id == UNKNOWN_TRAIT { |
253 | self.db | 382 | return Vec::new(); |
383 | } | ||
384 | let trait_: Trait = from_chalk(self.db, trait_id); | ||
385 | let blacklisted = blacklisted_trait(self.db, trait_); | ||
386 | if blacklisted { | ||
387 | return Vec::new(); | ||
388 | } | ||
389 | let result: Vec<_> = self | ||
390 | .db | ||
254 | .impls_for_trait(self.krate, trait_) | 391 | .impls_for_trait(self.krate, trait_) |
255 | .iter() | 392 | .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)) | 393 | .map(|impl_block| impl_block.to_chalk(self.db)) |
261 | .collect() | 394 | .collect(); |
395 | debug!("impls_for_trait returned {} impls", result.len()); | ||
396 | result | ||
262 | } | 397 | } |
263 | fn impl_provided_for( | 398 | fn impl_provided_for( |
264 | &self, | 399 | &self, |