Skip to content

Commit 6c2d0f4

Browse files
scalexmtmandry
authored andcommitted
Correctly instantiate where clauses / bounds on GATs in wf.rs
1 parent e655cff commit 6c2d0f4

File tree

6 files changed

+106
-88
lines changed

6 files changed

+106
-88
lines changed

src/fold.rs

+13
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

+3-1
Original file line numberDiff line numberDiff line change
@@ -687,7 +687,9 @@ impl DomainGoal {
687687
/// Same as `into_well_formed_goal` but with the `FromEnv` predicate instead of `WellFormed`.
688688
crate fn into_from_env_goal(self) -> DomainGoal {
689689
match self {
690-
DomainGoal::Holds(wca) => DomainGoal::FromEnv(wca),
690+
DomainGoal::Holds(wca @ WhereClauseAtom::Implemented(..)) => {
691+
DomainGoal::FromEnv(wca)
692+
}
691693
goal => goal,
692694
}
693695
}

src/ir/lowering/test.rs

+28
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

+3-2
Original file line numberDiff line numberDiff line change
@@ -520,11 +520,12 @@ impl ir::AssociatedTyDatum {
520520
//
521521
// This is really a family of clauses, one for each where clause.
522522
clauses.extend(self.where_clauses.iter().map(|wc| {
523+
let shift = wc.binders.len();
523524
ir::Binders {
524-
binders: binders.iter().chain(wc.binders.iter()).cloned().collect(),
525+
binders: wc.binders.iter().chain(binders.iter()).cloned().collect(),
525526
value: ir::ProgramClauseImplication {
526527
consequence: wc.value.clone().into_from_env_goal(),
527-
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).cast()],
528+
conditions: vec![ir::DomainGoal::FromEnvTy(app_ty.clone()).up_shift(shift).cast()],
528529
}
529530
}.cast()
530531
}));

src/rules/wf.rs

+41-57
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

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

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

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

260-
let trait_datum = &self.env.trait_data[&assoc_ty_datum.trait_id];
261-
262244
let mut input_types = Vec::new();
263245
assoc_ty.value.value.ty.fold(&mut input_types);
264246

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

280272
let hypotheses =
281273
assoc_ty_datum.where_clauses
282274
.iter()
283-
.chain(impl_datum.binders.value.where_clauses.iter()) // FIXME binders (and test)!
284-
.cloned()
275+
.map(|wc| Subst::apply(&all_parameters, wc))
285276
.map(|wc| wc.map(|bound| bound.into_from_env_goal()))
286277
.casted()
287278
.collect();
288-
let bound_goal = bounds.iter()
289-
.flat_map(|b| b.clone()
290-
.lower_with_self(assoc_ty.value.value.ty.clone()))
291-
.map(|g| g.into_well_formed_goal().cast())
292-
.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)));
293-
let bound_goal = bound_goal.map(|g| {
294-
Goal::Implies(hypotheses, Box::new(g)).quantify(QuantifierKind::ForAll, bound_binders)
295-
});
296-
297-
let goal = goal.into_iter()
298-
.chain(bound_goal.into_iter())
299-
.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)));
300-
println!("{:?}", goal);
301-
302-
goal
279+
280+
let goal = Goal::Implies(
281+
hypotheses,
282+
Box::new(goal)
283+
);
284+
285+
Some(goal.quantify(QuantifierKind::ForAll, assoc_ty.value.binders.clone()))
303286
};
304287

305288
let assoc_ty_goals =
@@ -316,7 +299,6 @@ impl WfSolver {
316299
);
317300
let goals =
318301
input_types.into_iter()
319-
.chain(header_projection_types.into_iter())
320302
.map(|ty| DomainGoal::WellFormedTy(ty).cast())
321303
.chain(assoc_ty_goals)
322304
.chain(Some(trait_ref_wf).cast());
@@ -335,12 +317,14 @@ impl WfSolver {
335317
.cloned()
336318
.map(|wc| wc.map(|bound| bound.into_from_env_goal()))
337319
.casted()
338-
.chain(header_other_types.into_iter().map(|ty| DomainGoal::FromEnvTy(ty).cast()))
320+
.chain(header_input_types.into_iter().map(|ty| DomainGoal::FromEnvTy(ty).cast()))
339321
.collect();
340322

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

326+
println!("{:?}", goal);
327+
344328
match self.solver_choice.solve_root_goal(&self.env, &goal.into_closed_goal()).unwrap() {
345329
Some(sol) => sol.is_unique(),
346330
None => false,

src/rules/wf/test.rs

+18-28
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)