Skip to content

Commit 575b0ec

Browse files
committed
Clean up program_clauses_that_could_match
- Use a single match on the TyKind for Implemented goals - Normalize TyKind::Alias self types
1 parent dc29a79 commit 575b0ec

File tree

3 files changed

+225
-59
lines changed

3 files changed

+225
-59
lines changed

chalk-ir/src/lib.rs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,12 +1346,7 @@ impl<I: Interner> AliasTy<I> {
13461346
/// Gets the type parameters of the `Self` type in this alias type.
13471347
pub fn self_type_parameter(&self, interner: &I) -> Ty<I> {
13481348
match self {
1349-
AliasTy::Projection(projection_ty) => projection_ty
1350-
.substitution
1351-
.iter(interner)
1352-
.find_map(move |p| p.ty(interner))
1353-
.unwrap()
1354-
.clone(),
1349+
AliasTy::Projection(projection_ty) => projection_ty.self_type_parameter(interner),
13551350
_ => todo!(),
13561351
}
13571352
}
@@ -1368,6 +1363,17 @@ pub struct ProjectionTy<I: Interner> {
13681363

13691364
impl<I: Interner> Copy for ProjectionTy<I> where I::InternedSubstitution: Copy {}
13701365

1366+
impl<I: Interner> ProjectionTy<I> {
1367+
/// Gets the type parameters of the `Self` type in this alias type.
1368+
pub fn self_type_parameter(&self, interner: &I) -> Ty<I> {
1369+
self.substitution
1370+
.iter(interner)
1371+
.find_map(move |p| p.ty(interner))
1372+
.unwrap()
1373+
.clone()
1374+
}
1375+
}
1376+
13711377
/// An opaque type `opaque type T<..>: Trait = HiddenTy`.
13721378
#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)]
13731379
pub struct OpaqueTy<I: Interner> {

chalk-solve/src/clauses.rs

Lines changed: 149 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -389,20 +389,56 @@ fn program_clauses_that_could_match<I: Interner>(
389389

390390
match goal {
391391
DomainGoal::Holds(WhereClause::Implemented(trait_ref)) => {
392-
let trait_id = trait_ref.trait_id;
392+
let self_ty = trait_ref.self_type_parameter(interner);
393393

394+
let trait_id = trait_ref.trait_id;
394395
let trait_datum = db.trait_datum(trait_id);
395396

396-
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
397-
let self_ty = trait_ref.self_type_parameter(interner);
397+
match self_ty.kind(interner) {
398+
TyKind::Alias(alias) => {
399+
// An alias could normalize to anything, including `dyn trait`
400+
// or an opaque type, so push a clause that asks for the
401+
// self type to be normalized and return.
402+
push_alias_implemented_clause(builder, trait_ref, alias);
403+
return Ok(clauses);
404+
}
398405

399-
if let TyKind::Alias(AliasTy::Opaque(opaque_ty)) = self_ty.kind(interner) {
400-
if trait_datum.is_auto_trait() {
401-
push_auto_trait_impls_opaque(builder, trait_id, opaque_ty.opaque_ty_id)
406+
_ if self_ty.is_general_var(interner, binders) => {
407+
if trait_datum.is_non_enumerable_trait() || trait_datum.is_auto_trait() {
408+
return Err(Floundered);
402409
}
403-
} else if self_ty.is_general_var(interner, binders) {
404-
return Err(Floundered);
405410
}
411+
412+
TyKind::OpaqueType(opaque_ty_id, _) => {
413+
db.opaque_ty_data(*opaque_ty_id)
414+
.to_program_clauses(builder, environment);
415+
}
416+
417+
TyKind::Dyn(_) => {
418+
// If the self type is a `dyn trait` type, generate program-clauses
419+
// that indicates that it implements its own traits.
420+
// FIXME: This is presently rather wasteful, in that we don't check that the
421+
// these program clauses we are generating are actually relevant to the goal
422+
// `goal` that we are actually *trying* to prove (though there is some later
423+
// code that will screen out irrelevant stuff).
424+
//
425+
// In other words, if we were trying to prove `Implemented(dyn
426+
// Fn(&u8): Clone)`, we would still generate two clauses that are
427+
// totally irrelevant to that goal, because they let us prove other
428+
// things but not `Clone`.
429+
dyn_ty::build_dyn_self_ty_clauses(db, builder, self_ty.clone())
430+
}
431+
432+
// We don't actually do anything here, but we need to record the types when logging
433+
TyKind::Adt(adt_id, _) => {
434+
let _ = db.adt_datum(*adt_id);
435+
}
436+
437+
TyKind::FnDef(fn_def_id, _) => {
438+
let _ = db.fn_def_datum(*fn_def_id);
439+
}
440+
441+
_ => {}
406442
}
407443

408444
// This is needed for the coherence related impls, as well
@@ -429,42 +465,6 @@ fn program_clauses_that_could_match<I: Interner>(
429465
})?;
430466
}
431467

432-
// If the self type is a `dyn trait` type, generate program-clauses
433-
// that indicates that it implements its own traits.
434-
// FIXME: This is presently rather wasteful, in that we don't check that the
435-
// these program clauses we are generating are actually relevant to the goal
436-
// `goal` that we are actually *trying* to prove (though there is some later
437-
// code that will screen out irrelevant stuff).
438-
//
439-
// In other words, if we were trying to prove `Implemented(dyn
440-
// Fn(&u8): Clone)`, we would still generate two clauses that are
441-
// totally irrelevant to that goal, because they let us prove other
442-
// things but not `Clone`.
443-
let self_ty = trait_ref.self_type_parameter(interner);
444-
if let TyKind::Dyn(_) = self_ty.kind(interner) {
445-
dyn_ty::build_dyn_self_ty_clauses(db, builder, self_ty.clone())
446-
}
447-
448-
match self_ty.kind(interner) {
449-
TyKind::OpaqueType(opaque_ty_id, _)
450-
| TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => {
451-
db.opaque_ty_data(*opaque_ty_id)
452-
.to_program_clauses(builder, environment);
453-
}
454-
_ => {}
455-
}
456-
457-
// We don't actually do anything here, but we need to record the types it when logging
458-
match self_ty.kind(interner) {
459-
TyKind::Adt(adt_id, _) => {
460-
let _ = db.adt_datum(*adt_id);
461-
}
462-
TyKind::FnDef(fn_def_id, _) => {
463-
let _ = db.fn_def_datum(*fn_def_id);
464-
}
465-
_ => {}
466-
}
467-
468468
if let Some(well_known) = trait_datum.well_known {
469469
builtin_traits::add_builtin_program_clauses(
470470
db, builder, well_known, trait_ref, binders,
@@ -478,21 +478,26 @@ fn program_clauses_that_could_match<I: Interner>(
478478
.self_type_parameter(interner);
479479

480480
match trait_self_ty.kind(interner) {
481-
TyKind::OpaqueType(opaque_ty_id, _)
482-
| TyKind::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => {
481+
TyKind::Alias(alias) => {
482+
// An alias could normalize to anything, including an
483+
// opaque type, so push a clause that asks for the self
484+
// type to be normalized and return.
485+
push_alias_alias_eq_clause(builder, proj, &alias_eq.ty, alias);
486+
return Ok(clauses);
487+
}
488+
TyKind::OpaqueType(opaque_ty_id, _) => {
483489
db.opaque_ty_data(*opaque_ty_id)
484490
.to_program_clauses(builder, environment);
485491
}
492+
// If the self type is a `dyn trait` type, generate program-clauses
493+
// for any associated type bindings it contains.
494+
// FIXME: see the fixme for the analogous code for Implemented goals.
495+
TyKind::Dyn(_) => {
496+
dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone())
497+
}
486498
_ => {}
487499
}
488500

489-
// If the self type is a `dyn trait` type, generate program-clauses
490-
// for any associated type bindings it contains.
491-
// FIXME: see the fixme for the analogous code for Implemented goals.
492-
if let TyKind::Dyn(_) = trait_self_ty.kind(interner) {
493-
dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone())
494-
}
495-
496501
db.associated_ty_data(proj.associated_ty_id)
497502
.to_program_clauses(builder, environment)
498503
}
@@ -708,6 +713,97 @@ fn push_program_clauses_for_associated_type_values_in_impls_of<I: Interner>(
708713
}
709714
}
710715

716+
fn push_alias_implemented_clause<I: Interner>(
717+
builder: &mut ClauseBuilder<'_, I>,
718+
trait_ref: &TraitRef<I>,
719+
alias: &AliasTy<I>,
720+
) {
721+
let interner = builder.interner();
722+
assert_eq!(
723+
*trait_ref.self_type_parameter(interner).kind(interner),
724+
TyKind::Alias(alias.clone())
725+
);
726+
727+
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
728+
729+
// forall<..., T> {
730+
// <X as Y>::Z: Trait :- T: Trait, <X as Y>::Z == T
731+
// }
732+
builder.push_binders(&binders, |builder, bound_var| {
733+
let fresh_self_subst = Substitution::from_iter(
734+
interner,
735+
std::iter::once(bound_var.clone().cast(interner)).chain(
736+
trait_ref.substitution.as_slice(interner)[1..]
737+
.iter()
738+
.cloned(),
739+
),
740+
);
741+
let fresh_self_trait_ref = TraitRef {
742+
trait_id: trait_ref.trait_id,
743+
substitution: fresh_self_subst,
744+
};
745+
builder.push_clause(
746+
DomainGoal::Holds(WhereClause::Implemented(trait_ref.clone())),
747+
&[
748+
DomainGoal::Holds(WhereClause::Implemented(fresh_self_trait_ref)),
749+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
750+
alias: alias.clone(),
751+
ty: bound_var,
752+
})),
753+
],
754+
);
755+
});
756+
}
757+
758+
fn push_alias_alias_eq_clause<I: Interner>(
759+
builder: &mut ClauseBuilder<'_, I>,
760+
projection_ty: &ProjectionTy<I>,
761+
ty: &Ty<I>,
762+
alias: &AliasTy<I>,
763+
) {
764+
let interner = builder.interner();
765+
assert_eq!(
766+
*projection_ty.self_type_parameter(interner).kind(interner),
767+
TyKind::Alias(alias.clone())
768+
);
769+
770+
let binders = Binders::with_fresh_type_var(interner, |ty_var| ty_var);
771+
772+
// forall<..., T> {
773+
// <<X as Y>::A as Z>::B == U :- <T as Z>::B == U, <X as Y>::A == T
774+
// }
775+
builder.push_binders(&binders, |builder, bound_var| {
776+
let fresh_self_subst = Substitution::from_iter(
777+
interner,
778+
std::iter::once(bound_var.clone().cast(interner)).chain(
779+
projection_ty.substitution.as_slice(interner)[1..]
780+
.iter()
781+
.cloned(),
782+
),
783+
);
784+
let fresh_alias = AliasTy::Projection(ProjectionTy {
785+
associated_ty_id: projection_ty.associated_ty_id,
786+
substitution: fresh_self_subst,
787+
});
788+
builder.push_clause(
789+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
790+
alias: AliasTy::Projection(projection_ty.clone()),
791+
ty: ty.clone(),
792+
})),
793+
&[
794+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
795+
alias: fresh_alias,
796+
ty: ty.clone(),
797+
})),
798+
DomainGoal::Holds(WhereClause::AliasEq(AliasEq {
799+
alias: alias.clone(),
800+
ty: bound_var,
801+
})),
802+
],
803+
);
804+
});
805+
}
806+
711807
/// Examine `T` and push clauses that may be relevant to proving the
712808
/// following sorts of goals (and maybe others):
713809
///

tests/test/projection.rs

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1043,3 +1043,67 @@ fn guidance_for_projection_on_flounder() {
10431043
}
10441044
}
10451045
}
1046+
1047+
#[test]
1048+
fn projection_to_dyn() {
1049+
test! {
1050+
program {
1051+
trait AsDyn {
1052+
type Dyn;
1053+
}
1054+
1055+
#[object_safe]
1056+
trait Debug {}
1057+
1058+
impl AsDyn for () {
1059+
type Dyn = dyn Debug + 'static;
1060+
}
1061+
}
1062+
1063+
goal {
1064+
<() as AsDyn>::Dyn: Debug
1065+
} yields {
1066+
"Unique; substitution [], lifetime constraints []"
1067+
}
1068+
}
1069+
}
1070+
1071+
#[test]
1072+
fn projection_to_opaque() {
1073+
test! {
1074+
program {
1075+
#[non_enumerable]
1076+
trait Debug {
1077+
type Output;
1078+
}
1079+
1080+
impl Debug for () {
1081+
type Output = ();
1082+
}
1083+
1084+
opaque type OpaqueDebug: Debug<Output = ()> = ();
1085+
1086+
struct A {}
1087+
1088+
trait AsProj {
1089+
type Proj;
1090+
}
1091+
1092+
impl AsProj for A {
1093+
type Proj = OpaqueDebug;
1094+
}
1095+
}
1096+
1097+
goal {
1098+
<A as AsProj>::Proj: Debug
1099+
} yields {
1100+
"Unique; substitution [], lifetime constraints []"
1101+
}
1102+
1103+
goal {
1104+
<<A as AsProj>::Proj as Debug>::Output = ()
1105+
} yields {
1106+
"Unique; substitution [], lifetime constraints []"
1107+
}
1108+
}
1109+
}

0 commit comments

Comments
 (0)