aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_hir/src/ty/traits/chalk.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_hir/src/ty/traits/chalk.rs')
-rw-r--r--crates/ra_hir/src/ty/traits/chalk.rs179
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;
6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName}; 6use chalk_ir::{TypeId, ImplId, TypeKindId, ProjectionTy, Parameter, Identifier, cast::Cast, PlaceholderIndex, UniverseIndex, TypeName};
7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum}; 7use chalk_rust_ir::{AssociatedTyDatum, TraitDatum, StructDatum, ImplDatum};
8 8
9use test_utils::tested_by;
9use ra_db::salsa::{InternId, InternKey}; 10use ra_db::salsa::{InternId, InternKey};
10 11
11use crate::{ 12use 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};
16use super::ChalkContext; 19use super::ChalkContext;
17 20
21/// This represents a trait whose name we could not resolve.
22const UNKNOWN_TRAIT: chalk_ir::TraitId =
23 chalk_ir::TraitId(chalk_ir::RawId { index: u32::max_value() });
24
18pub(super) trait ToChalk { 25pub(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
159impl 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
149fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> { 186fn 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
193fn 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
201fn 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
156impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB> 227impl<'a, DB> chalk_solve::RustIrDatabase for ChalkContext<'a, DB>
157where 228where
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,