Skip to content

Commit b5d9422

Browse files
scalexmtmandry
authored andcommitted
Correctly instantiate where clauses / bounds on GATs in wf.rs
1 parent 9e52a13 commit b5d9422

File tree

6 files changed

+106
-88
lines changed

6 files changed

+106
-88
lines changed

src/fold.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,7 @@ enum_fold!(Constraint[] { LifetimeEq(a, b) });
431431
enum_fold!(Goal[] { Quantified(qkind, subgoal), Implies(wc, subgoal), And(g1, g2), Not(g),
432432
Leaf(wc), CannotProve(a) });
433433
enum_fold!(ProgramClause[] { Implies(a), ForAll(a) });
434+
enum_fold!(InlineBound[] { TraitBound(a), ProjectionEqBound(a) });
434435

435436
macro_rules! struct_fold {
436437
($s:ident $([$($tt_args:tt)*])? { $($name:ident),* $(,)* } $($w:tt)*) => {
@@ -582,4 +583,16 @@ struct_fold!(ConstrainedSubst {
582583
constraints,
583584
});
584585

586+
struct_fold!(TraitBound {
587+
trait_id,
588+
args_no_self,
589+
});
590+
591+
struct_fold!(ProjectionEqBound {
592+
trait_bound,
593+
associated_ty_id,
594+
parameters,
595+
value,
596+
});
597+
585598
// struct_fold!(ApplicationTy { name, parameters }); -- intentionally omitted, folded through Ty

src/ir.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -693,7 +693,9 @@ impl DomainGoal {
693693
/// Same as `into_well_formed_goal` but with the `FromEnv` predicate instead of `WellFormed`.
694694
crate fn into_from_env_goal(self) -> DomainGoal {
695695
match self {
696-
DomainGoal::Holds(wca) => DomainGoal::FromEnv(wca),
696+
DomainGoal::Holds(wca @ WhereClauseAtom::Implemented(..)) => {
697+
DomainGoal::FromEnv(wca)
698+
}
697699
goal => goal,
698700
}
699701
}

src/ir/lowering/test.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -378,3 +378,31 @@ fn duplicate_parameters() {
378378
}
379379
}
380380
}
381+
382+
#[test]
383+
fn external_items() {
384+
lowering_success! {
385+
program {
386+
extern trait Send { }
387+
extern struct Vec<T> { }
388+
}
389+
}
390+
}
391+
392+
#[test]
393+
fn deref_trait() {
394+
lowering_success! {
395+
program {
396+
#[lang_deref] trait Deref { type Target; }
397+
}
398+
}
399+
400+
lowering_error! {
401+
program {
402+
#[lang_deref] trait Deref { }
403+
#[lang_deref] trait DerefDupe { }
404+
} error_msg {
405+
"Duplicate lang item `DerefTrait`"
406+
}
407+
}
408+
}

src/rules.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -536,11 +536,12 @@ impl ir::AssociatedTyDatum {
536536
//
537537
// This is really a family of clauses, one for each where clause.
538538
clauses.extend(self.where_clauses.iter().map(|wc| {
539+
let shift = wc.binders.len();
539540
ir::Binders {
540-
binders: binders.iter().chain(wc.binders.iter()).cloned().collect(),
541+
binders: wc.binders.iter().chain(binders.iter()).cloned().collect(),
541542
value: ir::ProgramClauseImplication {
542543
consequence: wc.value.clone().into_from_env_goal(),
543-
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
544+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).up_shift(shift).cast()],
544545
}
545546
}.cast()
546547
}));

src/rules/wf.rs

Lines changed: 41 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@ use errors::*;
55
use cast::*;
66
use solve::SolverChoice;
77
use itertools::Itertools;
8+
use fold::*;
9+
use fold::shift::Shift;
810

911
mod test;
1012

@@ -209,38 +211,20 @@ impl WfSolver {
209211
let mut input_types = Vec::new();
210212
impl_datum.binders.value.where_clauses.fold(&mut input_types);
211213

212-
// We partition the input types of the type on which we implement the trait in two categories:
213-
// * projection types, e.g. `<T as Iterator>::Item`: we will have to prove that these types
214-
// are well-formed, e.g. that we can show that `T: Iterator` holds
215-
// * any other types, e.g. `HashSet<K>`: we will *assume* that these types are well-formed, e.g.
216-
// we will be able to derive that `K: Hash` holds without writing any where clause.
214+
// We retrieve all the input types of the type on which we implement the trait: we will
215+
// *assume* that these types are well-formed, e.g. we will be able to derive that
216+
// `K: Hash` holds without writing any where clause.
217217
//
218-
// Examples:
218+
// Example:
219219
// ```
220220
// struct HashSet<K> where K: Hash { ... }
221221
//
222222
// impl<K> Foo for HashSet<K> {
223223
// // Inside here, we can rely on the fact that `K: Hash` holds
224224
// }
225225
// ```
226-
//
227-
// ```
228-
// impl<T> Foo for <T as Iterator>::Item {
229-
// // The impl is not well-formed, as an exception we do not assume that
230-
// // `<T as Iterator>::Item` is well-formed and instead want to prove it.
231-
// }
232-
// ```
233-
//
234-
// ```
235-
// impl<T> Foo for <T as Iterator>::Item where T: Iterator {
236-
// // Now ok.
237-
// }
238-
// ```
239226
let mut header_input_types = Vec::new();
240227
trait_ref.fold(&mut header_input_types);
241-
let (header_projection_types, header_other_types): (Vec<_>, Vec<_>) =
242-
header_input_types.into_iter()
243-
.partition(|ty| ty.is_projection());
244228

245229
// Associated type values are special because they can be parametric (independently of
246230
// the impl), so we issue a special goal which is quantified using the binders of the
@@ -259,49 +243,48 @@ impl WfSolver {
259243
let assoc_ty_datum = &self.env.associated_ty_data[&assoc_ty.associated_ty_id];
260244
let bounds = &assoc_ty_datum.bounds;
261245

262-
let trait_datum = &self.env.trait_data[&assoc_ty_datum.trait_id];
263-
264246
let mut input_types = Vec::new();
265247
assoc_ty.value.value.ty.fold(&mut input_types);
266248

267-
let goals = input_types.into_iter()
268-
.map(|ty| DomainGoal::WellFormedTy(ty).cast());
269-
//.chain(bounds.iter()
270-
// .flat_map(|b| b.clone()
271-
// .lower_with_self(assoc_ty.value.value.ty.clone()))
272-
// .map(|g| g.into_well_formed_goal().cast()));
273-
let goal = goals.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)));
274-
//.expect("at least one goal");
275-
let goal = goal //Goal::Implies(hypotheses, Box::new(goal))
276-
.map(|goal| goal.quantify(QuantifierKind::ForAll, assoc_ty.value.binders.clone()));//binders);
277-
278-
// FIXME this is wrong (and test)!
279-
let mut bound_binders = assoc_ty.value.binders.clone();
280-
bound_binders.extend(trait_datum.binders.binders.iter());
249+
let wf_goals =
250+
input_types.into_iter()
251+
.map(|ty| DomainGoal::WellFormedTy(ty));
252+
253+
let trait_ref = trait_ref.up_shift(assoc_ty.value.binders.len());
254+
255+
let all_parameters: Vec<_> =
256+
assoc_ty.value.binders.iter()
257+
.zip(0..)
258+
.map(|p| p.to_parameter())
259+
.chain(trait_ref.parameters.iter().cloned())
260+
.collect();
261+
262+
let bound_goals =
263+
bounds.iter()
264+
.map(|b| Subst::apply(&all_parameters, b))
265+
.flat_map(|b| b.lower_with_self(assoc_ty.value.value.ty.clone()))
266+
.map(|g| g.into_well_formed_goal());
267+
268+
let goals = wf_goals.chain(bound_goals).casted();
269+
let goal = match goals.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf))) {
270+
Some(goal) => goal,
271+
None => return None,
272+
};
281273

282274
let hypotheses =
283275
assoc_ty_datum.where_clauses
284276
.iter()
285-
.chain(impl_datum.binders.value.where_clauses.iter()) // FIXME binders (and test)!
286-
.cloned()
277+
.map(|wc| Subst::apply(&all_parameters, wc))
287278
.map(|wc| wc.map(|bound| bound.into_from_env_goal()))
288279
.casted()
289280
.collect();
290-
let bound_goal = bounds.iter()
291-
.flat_map(|b| b.clone()
292-
.lower_with_self(assoc_ty.value.value.ty.clone()))
293-
.map(|g| g.into_well_formed_goal().cast())
294-
.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)));
295-
let bound_goal = bound_goal.map(|g| {
296-
Goal::Implies(hypotheses, Box::new(g)).quantify(QuantifierKind::ForAll, bound_binders)
297-
});
298-
299-
let goal = goal.into_iter()
300-
.chain(bound_goal.into_iter())
301-
.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)));
302-
println!("{:?}", goal);
303-
304-
goal
281+
282+
let goal = Goal::Implies(
283+
hypotheses,
284+
Box::new(goal)
285+
);
286+
287+
Some(goal.quantify(QuantifierKind::ForAll, assoc_ty.value.binders.clone()))
305288
};
306289

307290
let assoc_ty_goals =
@@ -318,7 +301,6 @@ impl WfSolver {
318301
);
319302
let goals =
320303
input_types.into_iter()
321-
.chain(header_projection_types.into_iter())
322304
.map(|ty| DomainGoal::WellFormedTy(ty).cast())
323305
.chain(assoc_ty_goals)
324306
.chain(Some(trait_ref_wf).cast());
@@ -337,12 +319,14 @@ impl WfSolver {
337319
.cloned()
338320
.map(|wc| wc.map(|bound| bound.into_from_env_goal()))
339321
.casted()
340-
.chain(header_other_types.into_iter().map(|ty| DomainGoal::FromEnvTy(ty).cast()))
322+
.chain(header_input_types.into_iter().map(|ty| DomainGoal::FromEnvTy(ty).cast()))
341323
.collect();
342324

343325
let goal = Goal::Implies(hypotheses, Box::new(goal))
344326
.quantify(QuantifierKind::ForAll, impl_datum.binders.binders.clone());
345327

328+
println!("{:?}", goal);
329+
346330
match self.solver_choice.solve_root_goal(&self.env, &goal.into_closed_goal()).unwrap() {
347331
Some(sol) => sol.is_unique(),
348332
None => false,

src/rules/wf/test.rs

Lines changed: 18 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -438,16 +438,6 @@ fn generic_projection_bound() {
438438
}
439439
}
440440

441-
#[test]
442-
fn external_items() {
443-
lowering_success! {
444-
program {
445-
extern trait Send { }
446-
extern struct Vec<T> { }
447-
}
448-
}
449-
}
450-
451441
#[test]
452442
fn higher_ranked_trait_bounds() {
453443
lowering_error! {
@@ -474,6 +464,24 @@ fn higher_ranked_trait_bounds() {
474464
}
475465
}
476466

467+
#[test]
468+
fn higher_ranked_trait_bound_on_gat() {
469+
lowering_success! {
470+
program {
471+
trait Foo<'a> { }
472+
struct i32 { }
473+
474+
trait Bar<'a> {
475+
type Item<V>: Foo<'a> where forall<'b> V: Foo<'b>;
476+
}
477+
478+
impl<'a> Bar<'a> for i32 {
479+
type Item<V> = V;
480+
}
481+
}
482+
}
483+
}
484+
477485
// See `cyclic_traits`, this is essentially the same but with higher-ranked co-inductive WF goals.
478486
#[test]
479487
fn higher_ranked_cyclic_requirements() {
@@ -511,21 +519,3 @@ fn higher_ranked_cyclic_requirements() {
511519
}
512520
}
513521
}
514-
515-
#[test]
516-
fn deref_trait() {
517-
lowering_success! {
518-
program {
519-
#[lang_deref] trait Deref { type Target; }
520-
}
521-
}
522-
523-
lowering_error! {
524-
program {
525-
#[lang_deref] trait Deref { }
526-
#[lang_deref] trait DerefDupe { }
527-
} error_msg {
528-
"Duplicate lang item `DerefTrait`"
529-
}
530-
}
531-
}

0 commit comments

Comments
 (0)