Skip to content

Commit c29c033

Browse files
committed
Add GAT rules that don't involve bounds
1 parent 3408f36 commit c29c033

File tree

1 file changed

+72
-29
lines changed

1 file changed

+72
-29
lines changed

src/rules.rs

Lines changed: 72 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use cast::{Cast, Caster};
22
use fold::shift::Shift;
33
use ir::{self, ToParameter};
4+
use std::iter;
45

56
mod default;
67
mod wf;
@@ -181,12 +182,14 @@ impl ir::AssociatedTyValue {
181182
program: &ir::Program,
182183
impl_datum: &ir::ImplDatum,
183184
) -> Vec<ir::ProgramClause> {
185+
let associated_ty = &program.associated_ty_data[&self.associated_ty_id];
186+
184187
// Begin with the innermost parameters (`'a`) and then add those from impl (`T`).
185188
let all_binders: Vec<_> = self.value
186189
.binders
187190
.iter()
191+
.chain(impl_datum.binders.binders.iter())
188192
.cloned()
189-
.chain(impl_datum.binders.binders.iter().cloned())
190193
.collect();
191194

192195
// Assemble the full list of conditions for projection to be valid.
@@ -200,7 +203,9 @@ impl ir::AssociatedTyValue {
200203
.trait_ref
201204
.trait_ref()
202205
.up_shift(self.value.len());
203-
let conditions: Vec<ir::Goal> = vec![impl_trait_ref.clone().cast()];
206+
let conditions: Vec<ir::Goal> =
207+
iter::once(impl_trait_ref.clone().cast())
208+
.chain(associated_ty.where_clauses.iter().cloned().casted()).collect();
204209

205210
// Bound parameters + `Self` type of the trait-ref
206211
let parameters: Vec<_> = {
@@ -233,14 +238,12 @@ impl ir::AssociatedTyValue {
233238
binders: all_binders.clone(),
234239
value: ir::ProgramClauseImplication {
235240
consequence: normalize_goal.clone(),
236-
conditions: conditions.clone(),
241+
conditions: conditions,
237242
},
238243
}.cast();
239244

240245
let unselected_projection = ir::UnselectedProjectionTy {
241-
type_name: program.associated_ty_data[&self.associated_ty_id]
242-
.name
243-
.clone(),
246+
type_name: associated_ty.name.clone(),
244247
parameters: parameters,
245248
};
246249

@@ -410,23 +413,22 @@ impl ir::AssociatedTyDatum {
410413
// equality" rules. There are always two; one for a successful normalization,
411414
// and one for the "fallback" notion of equality.
412415
//
413-
// Given:
416+
// Given: (here, `'a` and `T` represent zero or more parameters)
414417
//
415418
// trait Foo {
416-
// type Assoc;
419+
// type Assoc<'a, T>: Bounds where WC;
417420
// }
418421
//
419422
// we generate the 'fallback' rule:
420423
//
421-
// forall<T> {
422-
// ProjectionEq(<T as Foo>::Assoc = (Foo::Assoc)<T>) :-
423-
// T: Foo
424+
// forall<Self, 'a, T> {
425+
// ProjectionEq(<Self as Foo>::Assoc<'a, T> = (Foo::Assoc<'a, T>)<Self>).
424426
// }
425427
//
426428
// and
427429
//
428-
// forall<T> {
429-
// ProjectionEq(<T as Foo>::Assoc = U) :-
430+
// forall<Self, 'a, T, U> {
431+
// ProjectionEq(<T as Foo>::Assoc<'a, T> = U) :-
430432
// Normalize(<T as Foo>::Assoc -> U)
431433
// }
432434
//
@@ -473,37 +475,76 @@ impl ir::AssociatedTyDatum {
473475
};
474476
let app_ty = ir::Ty::Apply(app);
475477

478+
let projection_eq = ir::ProjectionEq {
479+
projection: projection.clone(),
480+
ty: app_ty.clone(),
481+
};
482+
476483
let mut clauses = vec![];
477484

478-
// forall<T> {
479-
// ProjectionEq(<T as Foo>::Assoc = (Foo::Assoc)<T>) :-
480-
// T: Foo
485+
// Fallback rule. The solver uses this to move between the projection
486+
// and skolemized type.
487+
//
488+
// forall<Self> {
489+
// ProjectionEq(<Self as Foo>::Assoc = (Foo::Assoc)<Self>).
481490
// }
482491
clauses.push(ir::Binders {
483492
binders: binders.clone(),
484493
value: ir::ProgramClauseImplication {
485-
consequence: ir::ProjectionEq {
486-
projection: projection.clone(),
487-
ty: app_ty.clone(),
488-
}.cast(),
489-
conditions: vec![trait_ref.clone().cast()],
494+
consequence: projection_eq.clone().cast(),
495+
conditions: vec![],
490496
},
491497
}.cast());
492498

493-
// The above application type is always well-formed, and `<T as Foo>::Assoc` will
494-
// unify with `(Foo::Assoc)<T>` only if `T: Foo`, because of the above rule, so we have:
499+
// Well-formedness of projection type.
495500
//
496-
// forall<T> {
497-
// WellFormed((Foo::Assoc)<T>).
501+
// forall<Self> {
502+
// WellFormed((Foo::Assoc)<Self>) :- Self: Foo, WC.
498503
// }
499504
clauses.push(ir::Binders {
500505
binders: binders.clone(),
501506
value: ir::ProgramClauseImplication {
502-
consequence: ir::DomainGoal::WellFormedTy(app_ty).cast(),
503-
conditions: vec![],
507+
consequence: ir::DomainGoal::WellFormedTy(app_ty.clone()).cast(),
508+
conditions: iter::once(trait_ref.clone().cast())
509+
.chain(self.where_clauses.iter().cloned().casted())
510+
.collect(),
504511
},
505512
}.cast());
506513

514+
// Assuming well-formedness of projection type means we can assume
515+
// the trait ref as well.
516+
//
517+
// Currently we do not use this rule in chalk (it's used in fn bodies),
518+
// but it's here for completeness.
519+
//
520+
// forall<Self> {
521+
// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)<Self>).
522+
// }
523+
clauses.push(ir::Binders {
524+
binders: binders.clone(),
525+
value: ir::ProgramClauseImplication {
526+
consequence: ir::DomainGoal::FromEnv(trait_ref.clone().cast()),
527+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
528+
}
529+
}.cast());
530+
531+
// Reverse rule for where clauses.
532+
//
533+
// forall<Self> {
534+
// FromEnv(WC) :- FromEnv((Foo::Assoc)<Self>).
535+
// }
536+
//
537+
// This is really a family of clauses, one for each where clause.
538+
clauses.extend(self.where_clauses.iter().map(|wc| {
539+
ir::Binders {
540+
binders: binders.iter().chain(wc.binders.iter()).cloned().collect(),
541+
value: ir::ProgramClauseImplication {
542+
consequence: wc.value.clone().into_from_env_goal(),
543+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
544+
}
545+
}.cast()
546+
}));
547+
507548
// add new type parameter U
508549
let mut binders = binders;
509550
binders.push(ir::ParameterKind::Ty(()));
@@ -515,9 +556,11 @@ impl ir::AssociatedTyDatum {
515556
// `ProjectionEq(<T as Foo>::Assoc = U)`
516557
let projection_eq = ir::ProjectionEq { projection: projection.clone(), ty };
517558

518-
// forall<T> {
559+
// Projection equality rule from above.
560+
//
561+
// forall<T, U> {
519562
// ProjectionEq(<T as Foo>::Assoc = U) :-
520-
// Normalize(<T as Foo>::Assoc -> U)
563+
// Normalize(<T as Foo>::Assoc -> U).
521564
// }
522565
clauses.push(ir::Binders {
523566
binders: binders.clone(),

0 commit comments

Comments
 (0)