aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/traits/chalk
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/traits/chalk')
-rw-r--r--crates/hir_ty/src/traits/chalk/mapping.rs238
1 files changed, 121 insertions, 117 deletions
diff --git a/crates/hir_ty/src/traits/chalk/mapping.rs b/crates/hir_ty/src/traits/chalk/mapping.rs
index d969527dc..aef6b8a15 100644
--- a/crates/hir_ty/src/traits/chalk/mapping.rs
+++ b/crates/hir_ty/src/traits/chalk/mapping.rs
@@ -7,15 +7,14 @@ use chalk_ir::{cast::Cast, fold::shift::Shift, interner::HasInterner, LifetimeDa
7use chalk_solve::rust_ir; 7use chalk_solve::rust_ir;
8 8
9use base_db::salsa::InternKey; 9use base_db::salsa::InternKey;
10use hir_def::{AssocContainerId, GenericDefId, Lookup, TypeAliasId}; 10use hir_def::{GenericDefId, TypeAliasId};
11 11
12use crate::{ 12use crate::{
13 db::HirDatabase, 13 db::HirDatabase,
14 from_assoc_type_id,
15 primitive::UintTy, 14 primitive::UintTy,
16 traits::{Canonical, Obligation}, 15 traits::{Canonical, DomainGoal},
17 AliasTy, CallableDefId, FnPointer, GenericPredicate, InEnvironment, OpaqueTy, 16 AliasTy, CallableDefId, FnPointer, InEnvironment, OpaqueTy, ProjectionTy,
18 ProjectionPredicate, ProjectionTy, Scalar, Substitution, TraitRef, Ty, 17 QuantifiedWhereClause, Scalar, Substitution, TraitRef, Ty, TypeWalk, WhereClause,
19}; 18};
20 19
21use super::interner::*; 20use super::interner::*;
@@ -95,10 +94,10 @@ impl ToChalk for Ty {
95 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner), 94 TyKind::Placeholder(idx) => idx.to_ty::<Interner>(&Interner),
96 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner), 95 TyKind::BoundVar(idx) => chalk_ir::TyKind::BoundVar(idx).intern(&Interner),
97 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"), 96 TyKind::InferenceVar(..) => panic!("uncanonicalized infer ty"),
98 TyKind::Dyn(predicates) => { 97 TyKind::Dyn(dyn_ty) => {
99 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter( 98 let where_clauses = chalk_ir::QuantifiedWhereClauses::from_iter(
100 &Interner, 99 &Interner,
101 predicates.iter().filter(|p| !p.is_error()).cloned().map(|p| p.to_chalk(db)), 100 dyn_ty.bounds.value.interned().iter().cloned().map(|p| p.to_chalk(db)),
102 ); 101 );
103 let bounded_ty = chalk_ir::DynTy { 102 let bounded_ty = chalk_ir::DynTy {
104 bounds: make_binders(where_clauses, 1), 103 bounds: make_binders(where_clauses, 1),
@@ -144,13 +143,17 @@ impl ToChalk for Ty {
144 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown, 143 chalk_ir::TyKind::InferenceVar(_iv, _kind) => TyKind::Unknown,
145 chalk_ir::TyKind::Dyn(where_clauses) => { 144 chalk_ir::TyKind::Dyn(where_clauses) => {
146 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1); 145 assert_eq!(where_clauses.bounds.binders.len(&Interner), 1);
147 let predicates = where_clauses 146 let bounds = where_clauses
148 .bounds 147 .bounds
149 .skip_binders() 148 .skip_binders()
150 .iter(&Interner) 149 .iter(&Interner)
151 .map(|c| from_chalk(db, c.clone())) 150 .map(|c| from_chalk(db, c.clone()));
152 .collect(); 151 TyKind::Dyn(crate::DynTy {
153 TyKind::Dyn(predicates) 152 bounds: crate::Binders::new(
153 1,
154 crate::QuantifiedWhereClauses::from_iter(&Interner, bounds),
155 ),
156 })
154 } 157 }
155 158
156 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)), 159 chalk_ir::TyKind::Adt(adt_id, subst) => TyKind::Adt(adt_id, from_chalk(db, subst)),
@@ -239,15 +242,15 @@ impl ToChalk for TraitRef {
239 type Chalk = chalk_ir::TraitRef<Interner>; 242 type Chalk = chalk_ir::TraitRef<Interner>;
240 243
241 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> { 244 fn to_chalk(self: TraitRef, db: &dyn HirDatabase) -> chalk_ir::TraitRef<Interner> {
242 let trait_id = self.trait_.to_chalk(db); 245 let trait_id = self.trait_id;
243 let substitution = self.substs.to_chalk(db); 246 let substitution = self.substitution.to_chalk(db);
244 chalk_ir::TraitRef { trait_id, substitution } 247 chalk_ir::TraitRef { trait_id, substitution }
245 } 248 }
246 249
247 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self { 250 fn from_chalk(db: &dyn HirDatabase, trait_ref: chalk_ir::TraitRef<Interner>) -> Self {
248 let trait_ = from_chalk(db, trait_ref.trait_id); 251 let trait_id = trait_ref.trait_id;
249 let substs = from_chalk(db, trait_ref.substitution); 252 let substs = from_chalk(db, trait_ref.substitution);
250 TraitRef { trait_, substs } 253 TraitRef { trait_id, substitution: substs }
251 } 254 }
252} 255}
253 256
@@ -304,50 +307,26 @@ impl ToChalk for TypeAliasAsValue {
304 } 307 }
305} 308}
306 309
307impl ToChalk for GenericPredicate { 310impl ToChalk for WhereClause {
308 type Chalk = chalk_ir::QuantifiedWhereClause<Interner>; 311 type Chalk = chalk_ir::WhereClause<Interner>;
309 312
310 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::QuantifiedWhereClause<Interner> { 313 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::WhereClause<Interner> {
311 match self { 314 match self {
312 GenericPredicate::Implemented(trait_ref) => { 315 WhereClause::Implemented(trait_ref) => {
313 let chalk_trait_ref = trait_ref.to_chalk(db); 316 chalk_ir::WhereClause::Implemented(trait_ref.to_chalk(db))
314 let chalk_trait_ref = chalk_trait_ref.shifted_in(&Interner);
315 make_binders(chalk_ir::WhereClause::Implemented(chalk_trait_ref), 0)
316 }
317 GenericPredicate::Projection(projection_pred) => {
318 let ty = projection_pred.ty.to_chalk(db).shifted_in(&Interner);
319 let projection = projection_pred.projection_ty.to_chalk(db).shifted_in(&Interner);
320 let alias = chalk_ir::AliasTy::Projection(projection);
321 make_binders(chalk_ir::WhereClause::AliasEq(chalk_ir::AliasEq { alias, ty }), 0)
322 } 317 }
323 GenericPredicate::Error => panic!("tried passing GenericPredicate::Error to Chalk"), 318 WhereClause::AliasEq(alias_eq) => chalk_ir::WhereClause::AliasEq(alias_eq.to_chalk(db)),
324 } 319 }
325 } 320 }
326 321
327 fn from_chalk( 322 fn from_chalk(
328 db: &dyn HirDatabase, 323 db: &dyn HirDatabase,
329 where_clause: chalk_ir::QuantifiedWhereClause<Interner>, 324 where_clause: chalk_ir::WhereClause<Interner>,
330 ) -> GenericPredicate { 325 ) -> WhereClause {
331 // we don't produce any where clauses with binders and can't currently deal with them 326 match where_clause {
332 match where_clause 327 chalk_ir::WhereClause::Implemented(tr) => WhereClause::Implemented(from_chalk(db, tr)),
333 .skip_binders() 328 chalk_ir::WhereClause::AliasEq(alias_eq) => {
334 .clone() 329 WhereClause::AliasEq(from_chalk(db, alias_eq))
335 .shifted_out(&Interner)
336 .expect("unexpected bound vars in where clause")
337 {
338 chalk_ir::WhereClause::Implemented(tr) => {
339 GenericPredicate::Implemented(from_chalk(db, tr))
340 }
341 chalk_ir::WhereClause::AliasEq(projection_eq) => {
342 let projection_ty = from_chalk(
343 db,
344 match projection_eq.alias {
345 chalk_ir::AliasTy::Projection(p) => p,
346 _ => unimplemented!(),
347 },
348 );
349 let ty = from_chalk(db, projection_eq.ty);
350 GenericPredicate::Projection(ProjectionPredicate { projection_ty, ty })
351 } 330 }
352 331
353 chalk_ir::WhereClause::LifetimeOutlives(_) => { 332 chalk_ir::WhereClause::LifetimeOutlives(_) => {
@@ -383,29 +362,67 @@ impl ToChalk for ProjectionTy {
383 } 362 }
384 } 363 }
385} 364}
365impl ToChalk for OpaqueTy {
366 type Chalk = chalk_ir::OpaqueTy<Interner>;
367
368 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
369 chalk_ir::OpaqueTy {
370 opaque_ty_id: self.opaque_ty_id,
371 substitution: self.substitution.to_chalk(db),
372 }
373 }
374
375 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
376 OpaqueTy {
377 opaque_ty_id: chalk.opaque_ty_id,
378 substitution: from_chalk(db, chalk.substitution),
379 }
380 }
381}
382
383impl ToChalk for AliasTy {
384 type Chalk = chalk_ir::AliasTy<Interner>;
385
386 fn to_chalk(self, db: &dyn HirDatabase) -> Self::Chalk {
387 match self {
388 AliasTy::Projection(projection_ty) => {
389 chalk_ir::AliasTy::Projection(projection_ty.to_chalk(db))
390 }
391 AliasTy::Opaque(opaque_ty) => chalk_ir::AliasTy::Opaque(opaque_ty.to_chalk(db)),
392 }
393 }
394
395 fn from_chalk(db: &dyn HirDatabase, chalk: Self::Chalk) -> Self {
396 match chalk {
397 chalk_ir::AliasTy::Projection(projection_ty) => {
398 AliasTy::Projection(from_chalk(db, projection_ty))
399 }
400 chalk_ir::AliasTy::Opaque(opaque_ty) => AliasTy::Opaque(from_chalk(db, opaque_ty)),
401 }
402 }
403}
386 404
387impl ToChalk for ProjectionPredicate { 405impl ToChalk for AliasEq {
388 type Chalk = chalk_ir::AliasEq<Interner>; 406 type Chalk = chalk_ir::AliasEq<Interner>;
389 407
390 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> { 408 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::AliasEq<Interner> {
391 chalk_ir::AliasEq { 409 chalk_ir::AliasEq { alias: self.alias.to_chalk(db), ty: self.ty.to_chalk(db) }
392 alias: chalk_ir::AliasTy::Projection(self.projection_ty.to_chalk(db)),
393 ty: self.ty.to_chalk(db),
394 }
395 } 410 }
396 411
397 fn from_chalk(_db: &dyn HirDatabase, _normalize: chalk_ir::AliasEq<Interner>) -> Self { 412 fn from_chalk(db: &dyn HirDatabase, alias_eq: chalk_ir::AliasEq<Interner>) -> Self {
398 unimplemented!() 413 AliasEq { alias: from_chalk(db, alias_eq.alias), ty: from_chalk(db, alias_eq.ty) }
399 } 414 }
400} 415}
401 416
402impl ToChalk for Obligation { 417impl ToChalk for DomainGoal {
403 type Chalk = chalk_ir::DomainGoal<Interner>; 418 type Chalk = chalk_ir::DomainGoal<Interner>;
404 419
405 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> { 420 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::DomainGoal<Interner> {
406 match self { 421 match self {
407 Obligation::Trait(tr) => tr.to_chalk(db).cast(&Interner), 422 DomainGoal::Holds(WhereClause::Implemented(tr)) => tr.to_chalk(db).cast(&Interner),
408 Obligation::Projection(pr) => pr.to_chalk(db).cast(&Interner), 423 DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => {
424 alias_eq.to_chalk(db).cast(&Interner)
425 }
409 } 426 }
410 } 427 }
411 428
@@ -422,35 +439,12 @@ where
422 type Chalk = chalk_ir::Canonical<T::Chalk>; 439 type Chalk = chalk_ir::Canonical<T::Chalk>;
423 440
424 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> { 441 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Canonical<T::Chalk> {
425 let kinds = self.kinds.iter().map(|&tk| {
426 chalk_ir::CanonicalVarKind::new(
427 chalk_ir::VariableKind::Ty(tk),
428 chalk_ir::UniverseIndex::ROOT,
429 )
430 });
431 let value = self.value.to_chalk(db); 442 let value = self.value.to_chalk(db);
432 chalk_ir::Canonical { 443 chalk_ir::Canonical { value, binders: self.binders }
433 value,
434 binders: chalk_ir::CanonicalVarKinds::from_iter(&Interner, kinds),
435 }
436 } 444 }
437 445
438 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> { 446 fn from_chalk(db: &dyn HirDatabase, canonical: chalk_ir::Canonical<T::Chalk>) -> Canonical<T> {
439 let kinds = canonical 447 Canonical { binders: canonical.binders, value: from_chalk(db, canonical.value) }
440 .binders
441 .iter(&Interner)
442 .map(|k| match k.kind {
443 chalk_ir::VariableKind::Ty(tk) => tk,
444 // HACK: Chalk can sometimes return new lifetime variables. We
445 // want to just skip them, but to not mess up the indices of
446 // other variables, we'll just create a new type variable in
447 // their place instead. This should not matter (we never see the
448 // actual *uses* of the lifetime variable).
449 chalk_ir::VariableKind::Lifetime => chalk_ir::TyVariableKind::General,
450 chalk_ir::VariableKind::Const(_) => panic!("unexpected const from Chalk"),
451 })
452 .collect();
453 Canonical { kinds, value: from_chalk(db, canonical.value) }
454 } 448 }
455} 449}
456 450
@@ -461,10 +455,7 @@ where
461 type Chalk = chalk_ir::InEnvironment<T::Chalk>; 455 type Chalk = chalk_ir::InEnvironment<T::Chalk>;
462 456
463 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> { 457 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::InEnvironment<T::Chalk> {
464 chalk_ir::InEnvironment { 458 chalk_ir::InEnvironment { environment: self.environment, goal: self.goal.to_chalk(db) }
465 environment: self.environment.env.clone(),
466 goal: self.value.to_chalk(db),
467 }
468 } 459 }
469 460
470 fn from_chalk( 461 fn from_chalk(
@@ -475,6 +466,29 @@ where
475 } 466 }
476} 467}
477 468
469impl<T: ToChalk> ToChalk for crate::Binders<T>
470where
471 T::Chalk: chalk_ir::interner::HasInterner<Interner = Interner>,
472{
473 type Chalk = chalk_ir::Binders<T::Chalk>;
474
475 fn to_chalk(self, db: &dyn HirDatabase) -> chalk_ir::Binders<T::Chalk> {
476 chalk_ir::Binders::new(
477 chalk_ir::VariableKinds::from_iter(
478 &Interner,
479 std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
480 .take(self.num_binders),
481 ),
482 self.value.to_chalk(db),
483 )
484 }
485
486 fn from_chalk(db: &dyn HirDatabase, binders: chalk_ir::Binders<T::Chalk>) -> crate::Binders<T> {
487 let (v, b) = binders.into_value_and_skipped_binders();
488 crate::Binders::new(b.len(&Interner), from_chalk(db, v))
489 }
490}
491
478pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T> 492pub(super) fn make_binders<T>(value: T, num_vars: usize) -> chalk_ir::Binders<T>
479where 493where
480 T: HasInterner<Interner = Interner>, 494 T: HasInterner<Interner = Interner>,
@@ -497,10 +511,6 @@ pub(super) fn convert_where_clauses(
497 let generic_predicates = db.generic_predicates(def); 511 let generic_predicates = db.generic_predicates(def);
498 let mut result = Vec::with_capacity(generic_predicates.len()); 512 let mut result = Vec::with_capacity(generic_predicates.len());
499 for pred in generic_predicates.iter() { 513 for pred in generic_predicates.iter() {
500 if pred.value.is_error() {
501 // skip errored predicates completely
502 continue;
503 }
504 result.push(pred.clone().subst(substs).to_chalk(db)); 514 result.push(pred.clone().subst(substs).to_chalk(db));
505 } 515 }
506 result 516 result
@@ -508,49 +518,43 @@ pub(super) fn convert_where_clauses(
508 518
509pub(super) fn generic_predicate_to_inline_bound( 519pub(super) fn generic_predicate_to_inline_bound(
510 db: &dyn HirDatabase, 520 db: &dyn HirDatabase,
511 pred: &GenericPredicate, 521 pred: &QuantifiedWhereClause,
512 self_ty: &Ty, 522 self_ty: &Ty,
513) -> Option<rust_ir::InlineBound<Interner>> { 523) -> Option<chalk_ir::Binders<rust_ir::InlineBound<Interner>>> {
514 // An InlineBound is like a GenericPredicate, except the self type is left out. 524 // An InlineBound is like a GenericPredicate, except the self type is left out.
515 // We don't have a special type for this, but Chalk does. 525 // We don't have a special type for this, but Chalk does.
516 match pred { 526 let self_ty_shifted_in = self_ty.clone().shift_bound_vars(DebruijnIndex::ONE);
517 GenericPredicate::Implemented(trait_ref) => { 527 match &pred.value {
518 if &trait_ref.substs[0] != self_ty { 528 WhereClause::Implemented(trait_ref) => {
529 if trait_ref.self_type_parameter() != &self_ty_shifted_in {
519 // we can only convert predicates back to type bounds if they 530 // we can only convert predicates back to type bounds if they
520 // have the expected self type 531 // have the expected self type
521 return None; 532 return None;
522 } 533 }
523 let args_no_self = trait_ref.substs[1..] 534 let args_no_self = trait_ref.substitution[1..]
524 .iter() 535 .iter()
525 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 536 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
526 .collect(); 537 .collect();
527 let trait_bound = 538 let trait_bound = rust_ir::TraitBound { trait_id: trait_ref.trait_id, args_no_self };
528 rust_ir::TraitBound { trait_id: trait_ref.trait_.to_chalk(db), args_no_self }; 539 Some(make_binders(rust_ir::InlineBound::TraitBound(trait_bound), pred.num_binders))
529 Some(rust_ir::InlineBound::TraitBound(trait_bound))
530 } 540 }
531 GenericPredicate::Projection(proj) => { 541 WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
532 if &proj.projection_ty.substitution[0] != self_ty { 542 if projection_ty.self_type_parameter() != &self_ty_shifted_in {
533 return None; 543 return None;
534 } 544 }
535 let trait_ = match from_assoc_type_id(proj.projection_ty.associated_ty_id) 545 let trait_ = projection_ty.trait_(db);
536 .lookup(db.upcast()) 546 let args_no_self = projection_ty.substitution[1..]
537 .container
538 {
539 AssocContainerId::TraitId(t) => t,
540 _ => panic!("associated type not in trait"),
541 };
542 let args_no_self = proj.projection_ty.substitution[1..]
543 .iter() 547 .iter()
544 .map(|ty| ty.clone().to_chalk(db).cast(&Interner)) 548 .map(|ty| ty.clone().to_chalk(db).cast(&Interner))
545 .collect(); 549 .collect();
546 let alias_eq_bound = rust_ir::AliasEqBound { 550 let alias_eq_bound = rust_ir::AliasEqBound {
547 value: proj.ty.clone().to_chalk(db), 551 value: ty.clone().to_chalk(db),
548 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self }, 552 trait_bound: rust_ir::TraitBound { trait_id: trait_.to_chalk(db), args_no_self },
549 associated_ty_id: proj.projection_ty.associated_ty_id, 553 associated_ty_id: projection_ty.associated_ty_id,
550 parameters: Vec::new(), // FIXME we don't support generic associated types yet 554 parameters: Vec::new(), // FIXME we don't support generic associated types yet
551 }; 555 };
552 Some(rust_ir::InlineBound::AliasEqBound(alias_eq_bound)) 556 Some(make_binders(rust_ir::InlineBound::AliasEqBound(alias_eq_bound), pred.num_binders))
553 } 557 }
554 GenericPredicate::Error => None, 558 _ => None,
555 } 559 }
556} 560}