Skip to content

Commit d9ffab3

Browse files
committed
Add GAT rules that don't involve bounds
1 parent 011ffe8 commit d9ffab3

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

@@ -394,23 +397,22 @@ impl ir::AssociatedTyDatum {
394397
// equality" rules. There are always two; one for a successful normalization,
395398
// and one for the "fallback" notion of equality.
396399
//
397-
// Given:
400+
// Given: (here, `'a` and `T` represent zero or more parameters)
398401
//
399402
// trait Foo {
400-
// type Assoc;
403+
// type Assoc<'a, T>: Bounds where WC;
401404
// }
402405
//
403406
// we generate the 'fallback' rule:
404407
//
405-
// forall<T> {
406-
// ProjectionEq(<T as Foo>::Assoc = (Foo::Assoc)<T>) :-
407-
// T: Foo
408+
// forall<Self, 'a, T> {
409+
// ProjectionEq(<Self as Foo>::Assoc<'a, T> = (Foo::Assoc<'a, T>)<Self>).
408410
// }
409411
//
410412
// and
411413
//
412-
// forall<T> {
413-
// ProjectionEq(<T as Foo>::Assoc = U) :-
414+
// forall<Self, 'a, T, U> {
415+
// ProjectionEq(<T as Foo>::Assoc<'a, T> = U) :-
414416
// Normalize(<T as Foo>::Assoc -> U)
415417
// }
416418
//
@@ -457,37 +459,76 @@ impl ir::AssociatedTyDatum {
457459
};
458460
let app_ty = ir::Ty::Apply(app);
459461

462+
let projection_eq = ir::ProjectionEq {
463+
projection: projection.clone(),
464+
ty: app_ty.clone(),
465+
};
466+
460467
let mut clauses = vec![];
461468

462-
// forall<T> {
463-
// ProjectionEq(<T as Foo>::Assoc = (Foo::Assoc)<T>) :-
464-
// T: Foo
469+
// Fallback rule. The solver uses this to move between the projection
470+
// and skolemized type.
471+
//
472+
// forall<Self> {
473+
// ProjectionEq(<Self as Foo>::Assoc = (Foo::Assoc)<Self>).
465474
// }
466475
clauses.push(ir::Binders {
467476
binders: binders.clone(),
468477
value: ir::ProgramClauseImplication {
469-
consequence: ir::ProjectionEq {
470-
projection: projection.clone(),
471-
ty: app_ty.clone(),
472-
}.cast(),
473-
conditions: vec![trait_ref.clone().cast()],
478+
consequence: projection_eq.clone().cast(),
479+
conditions: vec![],
474480
},
475481
}.cast());
476482

477-
// The above application type is always well-formed, and `<T as Foo>::Assoc` will
478-
// unify with `(Foo::Assoc)<T>` only if `T: Foo`, because of the above rule, so we have:
483+
// Well-formedness of projection type.
479484
//
480-
// forall<T> {
481-
// WellFormed((Foo::Assoc)<T>).
485+
// forall<Self> {
486+
// WellFormed((Foo::Assoc)<Self>) :- Self: Foo, WC.
482487
// }
483488
clauses.push(ir::Binders {
484489
binders: binders.clone(),
485490
value: ir::ProgramClauseImplication {
486-
consequence: ir::DomainGoal::WellFormedTy(app_ty).cast(),
487-
conditions: vec![],
491+
consequence: ir::DomainGoal::WellFormedTy(app_ty.clone()).cast(),
492+
conditions: iter::once(trait_ref.clone().cast())
493+
.chain(self.where_clauses.iter().cloned().casted())
494+
.collect(),
488495
},
489496
}.cast());
490497

498+
// Assuming well-formedness of projection type means we can assume
499+
// the trait ref as well.
500+
//
501+
// Currently we do not use this rule in chalk (it's used in fn bodies),
502+
// but it's here for completeness.
503+
//
504+
// forall<Self> {
505+
// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)<Self>).
506+
// }
507+
clauses.push(ir::Binders {
508+
binders: binders.clone(),
509+
value: ir::ProgramClauseImplication {
510+
consequence: ir::DomainGoal::FromEnv(trait_ref.clone().cast()),
511+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
512+
}
513+
}.cast());
514+
515+
// Reverse rule for where clauses.
516+
//
517+
// forall<Self> {
518+
// FromEnv(WC) :- FromEnv((Foo::Assoc)<Self>).
519+
// }
520+
//
521+
// This is really a family of clauses, one for each where clause.
522+
clauses.extend(self.where_clauses.iter().map(|wc| {
523+
ir::Binders {
524+
binders: binders.iter().chain(wc.binders.iter()).cloned().collect(),
525+
value: ir::ProgramClauseImplication {
526+
consequence: wc.value.clone().into_from_env_goal(),
527+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
528+
}
529+
}.cast()
530+
}));
531+
491532
// add new type parameter U
492533
let mut binders = binders;
493534
binders.push(ir::ParameterKind::Ty(()));
@@ -499,9 +540,11 @@ impl ir::AssociatedTyDatum {
499540
// `ProjectionEq(<T as Foo>::Assoc = U)`
500541
let projection_eq = ir::ProjectionEq { projection: projection.clone(), ty };
501542

502-
// forall<T> {
543+
// Projection equality rule from above.
544+
//
545+
// forall<T, U> {
503546
// ProjectionEq(<T as Foo>::Assoc = U) :-
504-
// Normalize(<T as Foo>::Assoc -> U)
547+
// Normalize(<T as Foo>::Assoc -> U).
505548
// }
506549
clauses.push(ir::Binders {
507550
binders: binders.clone(),

0 commit comments

Comments
 (0)