Skip to content

Commit 95673d1

Browse files
authored
Merge pull request #119 from tmandry/GAT-step2
Refactors LowerWhereClause to permit multiple domain goals from a single AST where clause. For implementing GATs (#116).
2 parents df7e0b1 + f709901 commit 95673d1

File tree

2 files changed

+97
-33
lines changed

2 files changed

+97
-33
lines changed

src/ir/lowering/mod.rs

+74-33
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ use std::collections::BTreeMap;
33
use chalk_parse::ast::*;
44
use lalrpop_intern::intern;
55

6-
use cast::Cast;
6+
use cast::{Cast, Caster};
77
use errors::*;
88
use ir::{self, Anonymize, ToParameter};
9+
use itertools::Itertools;
910
use solve::SolverChoice;
1011

1112
mod test;
@@ -205,7 +206,7 @@ impl LowerProgram for Program {
205206
impl_data.insert(item_id, d.lower_impl(&empty_env)?);
206207
}
207208
Item::Clause(ref clause) => {
208-
custom_clauses.push(clause.lower_clause(&empty_env)?);
209+
custom_clauses.extend(clause.lower_clause(&empty_env)?);
209210
}
210211
}
211212
}
@@ -412,26 +413,31 @@ trait LowerWhereClauseVec<T> {
412413

413414
impl LowerWhereClauseVec<ir::DomainGoal> for [WhereClause] {
414415
fn lower(&self, env: &Env) -> Result<Vec<ir::DomainGoal>> {
415-
self.iter().map(|wc| wc.lower(env)).collect()
416+
self.iter().flat_map(|wc| wc.lower(env).apply_result()).collect()
416417
}
417418
}
418419

419420
impl LowerWhereClauseVec<ir::QuantifiedDomainGoal> for [QuantifiedWhereClause] {
420421
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedDomainGoal>> {
421-
self.iter().map(|wc| wc.lower(env)).collect()
422+
self.iter()
423+
.flat_map(|wc| match wc.lower(env) {
424+
Ok(v) => v.into_iter().map(Ok).collect(),
425+
Err(e) => vec![Err(e)],
426+
})
427+
.collect()
422428
}
423429
}
424430

425431
trait LowerWhereClause<T> {
426-
fn lower(&self, env: &Env) -> Result<T>;
432+
fn lower(&self, env: &Env) -> Result<Vec<T>>;
427433
}
428434

429435
/// Lowers a where-clause in the context of a clause (i.e. in "negative"
430436
/// position); this is limited to the kinds of where-clauses users can actually
431437
/// type in Rust and well-formedness checks.
432438
impl LowerWhereClause<ir::DomainGoal> for WhereClause {
433-
fn lower(&self, env: &Env) -> Result<ir::DomainGoal> {
434-
Ok(match self {
439+
fn lower(&self, env: &Env) -> Result<Vec<ir::DomainGoal>> {
440+
let goal = match self {
435441
WhereClause::Implemented { trait_ref } => {
436442
ir::DomainGoal::Holds(ir::WhereClauseAtom::Implemented(trait_ref.lower(env)?))
437443
}
@@ -478,17 +484,18 @@ impl LowerWhereClause<ir::DomainGoal> for WhereClause {
478484
target: target.lower(env)?
479485
})
480486
}
481-
})
487+
};
488+
Ok(vec![goal])
482489
}
483490
}
484491

485492
impl LowerWhereClause<ir::QuantifiedDomainGoal> for QuantifiedWhereClause {
486-
fn lower(&self, env: &Env) -> Result<ir::QuantifiedDomainGoal> {
493+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedDomainGoal>> {
487494
let parameter_kinds = self.parameter_kinds.iter().map(|pk| pk.lower());
488495
let binders = env.in_binders(parameter_kinds, |env| {
489496
Ok(self.where_clause.lower(env)?)
490497
})?;
491-
Ok(binders)
498+
Ok(binders.into_iter().collect())
492499
}
493500
}
494501

@@ -497,7 +504,7 @@ impl LowerWhereClause<ir::QuantifiedDomainGoal> for QuantifiedWhereClause {
497504
/// can appear, because it includes all the sorts of things that the compiler
498505
/// must verify.
499506
impl LowerWhereClause<ir::LeafGoal> for WhereClause {
500-
fn lower(&self, env: &Env) -> Result<ir::LeafGoal> {
507+
fn lower(&self, env: &Env) -> Result<Vec<ir::LeafGoal>> {
501508
Ok(match *self {
502509
WhereClause::Implemented { .. }
503510
| WhereClause::ProjectionEq { .. }
@@ -507,17 +514,17 @@ impl LowerWhereClause<ir::LeafGoal> for WhereClause {
507514
| WhereClause::TyFromEnv { .. }
508515
| WhereClause::TraitRefFromEnv { .. }
509516
| WhereClause::Derefs { .. } => {
510-
let g: ir::DomainGoal = self.lower(env)?;
511-
g.cast()
517+
let goals: Vec<ir::DomainGoal> = self.lower(env)?;
518+
goals.into_iter().casted().collect()
512519
}
513-
WhereClause::UnifyTys { ref a, ref b } => ir::EqGoal {
520+
WhereClause::UnifyTys { ref a, ref b } => vec![ir::EqGoal {
514521
a: ir::ParameterKind::Ty(a.lower(env)?),
515522
b: ir::ParameterKind::Ty(b.lower(env)?),
516-
}.cast(),
517-
WhereClause::UnifyLifetimes { ref a, ref b } => ir::EqGoal {
523+
}.cast()],
524+
WhereClause::UnifyLifetimes { ref a, ref b } => vec![ir::EqGoal {
518525
a: ir::ParameterKind::Lifetime(a.lower(env)?),
519526
b: ir::ParameterKind::Lifetime(b.lower(env)?),
520-
}.cast(),
527+
}.cast()],
521528
WhereClause::TraitInScope { trait_name } => {
522529
let id = match env.lookup(trait_name)? {
523530
NameLookup::Type(id) => id,
@@ -528,7 +535,7 @@ impl LowerWhereClause<ir::LeafGoal> for WhereClause {
528535
bail!(ErrorKind::NotTrait(trait_name));
529536
}
530537

531-
ir::DomainGoal::InScope(id).cast()
538+
vec![ir::DomainGoal::InScope(id).cast()]
532539
}
533540
})
534541
}
@@ -831,13 +838,14 @@ impl LowerImpl for Impl {
831838
}
832839

833840
trait LowerClause {
834-
fn lower_clause(&self, env: &Env) -> Result<ir::ProgramClause>;
841+
fn lower_clause(&self, env: &Env) -> Result<Vec<ir::ProgramClause>>;
835842
}
836843

837844
impl LowerClause for Clause {
838-
fn lower_clause(&self, env: &Env) -> Result<ir::ProgramClause> {
839-
let implication = env.in_binders(self.all_parameters(), |env| {
840-
let consequence: ir::DomainGoal = self.consequence.lower(env)?;
845+
fn lower_clause(&self, env: &Env) -> Result<Vec<ir::ProgramClause>> {
846+
let implications = env.in_binders(self.all_parameters(), |env| {
847+
let consequences: Vec<ir::DomainGoal> = self.consequence.lower(env)?;
848+
841849
let mut conditions: Vec<ir::Goal> = self.conditions
842850
.iter()
843851
.map(|g| g.lower(env).map(|g| *g))
@@ -848,17 +856,27 @@ impl LowerClause for Clause {
848856
// therefore reverse.
849857
conditions.reverse();
850858

851-
Ok(ir::ProgramClauseImplication {
852-
consequence,
853-
conditions,
854-
})
859+
let implications = consequences
860+
.into_iter()
861+
.map(|consequence| ir::ProgramClauseImplication {
862+
consequence,
863+
conditions: conditions.clone(),
864+
})
865+
.collect::<Vec<_>>();
866+
Ok(implications)
855867
})?;
856868

857-
if implication.binders.is_empty() {
858-
Ok(ir::ProgramClause::Implies(implication.value))
859-
} else {
860-
Ok(ir::ProgramClause::ForAll(implication))
861-
}
869+
let clauses = implications
870+
.into_iter()
871+
.map(|implication: ir::Binders<ir::ProgramClauseImplication>| {
872+
if implication.binders.is_empty() {
873+
ir::ProgramClause::Implies(implication.value)
874+
} else {
875+
ir::ProgramClause::ForAll(implication)
876+
}
877+
})
878+
.collect();
879+
Ok(clauses)
862880
}
863881
}
864882

@@ -968,15 +986,22 @@ impl<'k> LowerGoal<Env<'k>> for Goal {
968986
// `if (FromEnv(T: Trait)) { ... /* this part is untouched */ ... }`.
969987
let where_clauses: Result<Vec<_>> =
970988
wc.into_iter()
971-
.map(|wc| Ok(wc.lower_clause(env)?.into_from_env_clause()))
989+
.flat_map(|wc| wc.lower_clause(env).apply_result())
990+
.map(|result| result.map(|wc| wc.into_from_env_clause()))
972991
.collect();
973992
Ok(Box::new(ir::Goal::Implies(where_clauses?, g.lower(env)?)))
974993
}
975994
Goal::And(g1, g2) => {
976995
Ok(Box::new(ir::Goal::And(g1.lower(env)?, g2.lower(env)?)))
977996
}
978997
Goal::Not(g) => Ok(Box::new(ir::Goal::Not(g.lower(env)?))),
979-
Goal::Leaf(wc) => Ok(Box::new(ir::Goal::Leaf(wc.lower(env)?))),
998+
Goal::Leaf(wc) => {
999+
// A where clause can lower to multiple leaf goals; wrap these in Goal::And.
1000+
let leaves = wc.lower(env)?.into_iter().map(ir::Goal::Leaf);
1001+
let goal = leaves.fold1(|goal, leaf| ir::Goal::And(Box::new(goal), Box::new(leaf)))
1002+
.expect("at least one goal");
1003+
Ok(Box::new(goal))
1004+
}
9801005
}
9811006
}
9821007
}
@@ -1006,3 +1031,19 @@ impl LowerQuantifiedGoal for Goal {
10061031
Ok(Box::new(ir::Goal::Quantified(quantifier_kind, subgoal)))
10071032
}
10081033
}
1034+
1035+
/// Lowers Result<Vec<T>> -> Vec<Result<T>>.
1036+
trait ApplyResult {
1037+
type Output;
1038+
fn apply_result(self) -> Self::Output;
1039+
}
1040+
1041+
impl<T> ApplyResult for Result<Vec<T>> {
1042+
type Output = Vec<Result<T>>;
1043+
fn apply_result(self) -> Self::Output {
1044+
match self {
1045+
Ok(v) => v.into_iter().map(Ok).collect(),
1046+
Err(e) => vec![Err(e)],
1047+
}
1048+
}
1049+
}

src/ir/mod.rs

+23
Original file line numberDiff line numberDiff line change
@@ -687,6 +687,29 @@ impl<T> Binders<T> {
687687
}
688688
}
689689

690+
/// Allows iterating over a Binders<Vec<T>>, for instance.
691+
/// Each element will include the same set of parameter bounds.
692+
impl<V: IntoIterator> IntoIterator for Binders<V> {
693+
type Item = Binders<<V as IntoIterator>::Item>;
694+
type IntoIter = BindersIntoIterator<V>;
695+
696+
fn into_iter(self) -> Self::IntoIter {
697+
BindersIntoIterator { iter: self.value.into_iter(), binders: self.binders }
698+
}
699+
}
700+
701+
pub struct BindersIntoIterator<V: IntoIterator> {
702+
iter: <V as IntoIterator>::IntoIter,
703+
binders: Vec<ParameterKind<()>>,
704+
}
705+
706+
impl<V: IntoIterator> Iterator for BindersIntoIterator<V> {
707+
type Item = Binders<<V as IntoIterator>::Item>;
708+
fn next(&mut self) -> Option<Self::Item> {
709+
self.iter.next().map(|v| Binders { binders: self.binders.clone(), value: v })
710+
}
711+
}
712+
690713
/// Represents one clause of the form `consequence :- conditions` where
691714
/// `conditions = cond_1 && cond_2 && ...` is the conjunction of the individual
692715
/// conditions.

0 commit comments

Comments
 (0)