Skip to content

Commit 9510f05

Browse files
committed
Add support for quantified bounds on GATs
1 parent d67e569 commit 9510f05

File tree

9 files changed

+165
-27
lines changed

9 files changed

+165
-27
lines changed

chalk-parse/src/ast.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ pub struct TraitFlags {
6262
pub struct AssocTyDefn {
6363
pub name: Identifier,
6464
pub parameter_kinds: Vec<ParameterKind>,
65-
pub bounds: Vec<InlineBound>,
65+
pub bounds: Vec<QuantifiedInlineBound>,
6666
pub where_clauses: Vec<QuantifiedWhereClause>,
6767
}
6868

@@ -85,6 +85,12 @@ pub enum InlineBound {
8585
ProjectionEqBound(ProjectionEqBound),
8686
}
8787

88+
#[derive(Clone, PartialEq, Eq, Debug)]
89+
pub struct QuantifiedInlineBound {
90+
pub parameter_kinds: Vec<ParameterKind>,
91+
pub bound: InlineBound,
92+
}
93+
8894
#[derive(Clone, PartialEq, Eq, Debug)]
8995
/// Represents a trait bound on e.g. a type or type parameter.
9096
/// Does not know anything about what it's binding.

chalk-parse/src/parser.lalrpop

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ TraitDefn: TraitDefn = {
7474
};
7575

7676
AssocTyDefn: AssocTyDefn = {
77-
"type" <name:Id> <p:Angle<ParameterKind>> <b:(":" <Plus<InlineBound>>)?>
77+
"type" <name:Id> <p:Angle<ParameterKind>> <b:(":" <Plus<QuantifiedInlineBound>>)?>
7878
<w:QuantifiedWhereClauses> ";" =>
7979
{
8080
AssocTyDefn {
@@ -114,6 +114,18 @@ ProjectionEqBound: ProjectionEqBound = {
114114
}
115115
};
116116

117+
QuantifiedInlineBound: QuantifiedInlineBound = {
118+
<b:InlineBound> => QuantifiedInlineBound {
119+
parameter_kinds: vec![],
120+
bound: b,
121+
},
122+
123+
"forall" "<" <pk:Comma<ParameterKind>> ">" <b:InlineBound> => QuantifiedInlineBound {
124+
parameter_kinds: pk,
125+
bound: b,
126+
},
127+
};
128+
117129
Impl: Impl = {
118130
"impl" <p:Angle<ParameterKind>> <mark:"!"?> <t:Id> <a:Angle<Parameter>> "for" <s:Ty>
119131
<w:QuantifiedWhereClauses> "{" <assoc:AssocTyValue*> "}" =>

src/ir.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -268,19 +268,34 @@ pub enum InlineBound {
268268
ProjectionEqBound(ProjectionEqBound),
269269
}
270270

271+
pub type QuantifiedInlineBound = Binders<InlineBound>;
272+
271273
impl InlineBound {
272274
/// Applies the `InlineBound` to `self_ty` and lowers to a [`DomainGoal`].
273275
///
274276
/// Because an `InlineBound` does not know anything about what it's binding,
275277
/// you must provide that type as `self_ty`.
276-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
278+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
277279
match self {
278280
InlineBound::TraitBound(b) => b.into_where_clauses(self_ty),
279281
InlineBound::ProjectionEqBound(b) => b.into_where_clauses(self_ty),
280282
}
281283
}
282284
}
283285

286+
impl QuantifiedInlineBound {
287+
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<QuantifiedWhereClause> {
288+
let self_ty = self_ty.up_shift(self.binders.len());
289+
self.value.into_where_clauses(self_ty).into_iter().map(|wc| {
290+
Binders {
291+
binders: self.binders.clone(),
292+
value: wc,
293+
}
294+
}).collect()
295+
}
296+
}
297+
298+
284299
/// Represents a trait bound on e.g. a type or type parameter.
285300
/// Does not know anything about what it's binding.
286301
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -290,7 +305,7 @@ pub struct TraitBound {
290305
}
291306

292307
impl TraitBound {
293-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
308+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
294309
let trait_ref = self.as_trait_ref(self_ty);
295310
vec![WhereClause::Implemented(trait_ref)]
296311
}
@@ -303,7 +318,6 @@ impl TraitBound {
303318
}
304319
}
305320
}
306-
307321
/// Represents a projection equality bound on e.g. a type or type parameter.
308322
/// Does not know anything about what it's binding.
309323
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -316,7 +330,7 @@ pub struct ProjectionEqBound {
316330
}
317331

318332
impl ProjectionEqBound {
319-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
333+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
320334
let trait_ref = self.trait_bound.as_trait_ref(self_ty);
321335

322336
let mut parameters = self.parameters.clone();
@@ -354,7 +368,7 @@ pub struct AssociatedTyDatum {
354368
///
355369
/// These must be proven by the implementer, for all possible parameters that
356370
/// would result in a well-formed projection.
357-
crate bounds: Vec<InlineBound>,
371+
crate bounds: Vec<QuantifiedInlineBound>,
358372

359373
/// Where clauses that must hold for the projection to be well-formed.
360374
crate where_clauses: Vec<QuantifiedWhereClause>,
@@ -366,7 +380,7 @@ impl AssociatedTyDatum {
366380
/// ```notrust
367381
/// Implemented(<?0 as Foo>::Item<?1>: Sized)
368382
/// ```
369-
crate fn bounds_on_self(&self) -> Vec<WhereClause> {
383+
crate fn bounds_on_self(&self) -> Vec<QuantifiedWhereClause> {
370384
let parameters = self.parameter_kinds
371385
.anonymize()
372386
.iter()

src/ir/lowering.rs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -412,17 +412,11 @@ impl LowerWhereClauses for Impl {
412412
}
413413
}
414414

415-
trait LowerWhereClauseVec<T> {
416-
fn lower(&self, env: &Env) -> Result<Vec<T>>;
415+
trait LowerWhereClauseVec {
416+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedWhereClause>>;
417417
}
418418

419-
impl LowerWhereClauseVec<ir::WhereClause> for [WhereClause] {
420-
fn lower(&self, env: &Env) -> Result<Vec<ir::WhereClause>> {
421-
self.iter().flat_map(|wc| wc.lower(env).apply_result()).collect()
422-
}
423-
}
424-
425-
impl LowerWhereClauseVec<ir::QuantifiedWhereClause> for [QuantifiedWhereClause] {
419+
impl LowerWhereClauseVec for [QuantifiedWhereClause] {
426420
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedWhereClause>> {
427421
self.iter()
428422
.flat_map(|wc| match wc.lower(env) {
@@ -712,12 +706,26 @@ impl LowerInlineBound for InlineBound {
712706
}
713707
}
714708

715-
trait LowerInlineBounds {
716-
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>>;
709+
trait LowerQuantifiedInlineBound {
710+
fn lower(&self, env: &Env) -> Result<ir::QuantifiedInlineBound>;
711+
}
712+
713+
impl LowerQuantifiedInlineBound for QuantifiedInlineBound {
714+
fn lower(&self, env: &Env) -> Result<ir::QuantifiedInlineBound> {
715+
let parameter_kinds = self.parameter_kinds.iter().map(|pk| pk.lower());
716+
let binders = env.in_binders(parameter_kinds, |env| {
717+
Ok(self.bound.lower(env)?)
718+
})?;
719+
Ok(binders)
720+
}
721+
}
722+
723+
trait LowerQuantifiedInlineBoundVec {
724+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedInlineBound>>;
717725
}
718726

719-
impl LowerInlineBounds for Vec<InlineBound> {
720-
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>> {
727+
impl LowerQuantifiedInlineBoundVec for [QuantifiedInlineBound] {
728+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedInlineBound>> {
721729
self.iter()
722730
.map(|b| b.lower(env))
723731
.collect()

src/ir/lowering/test.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,21 @@ fn gat_parse() {
354354
}
355355
}
356356

357+
#[test]
358+
fn gat_higher_ranked_bound() {
359+
lowering_success! {
360+
program {
361+
trait Fn<T> {}
362+
trait Ref<'a, T> {}
363+
trait Sized {}
364+
365+
trait Foo {
366+
type Item<T>: forall<'a> Fn<Ref<'a, T>> + Sized;
367+
}
368+
}
369+
}
370+
}
371+
357372
#[test]
358373
fn duplicate_parameters() {
359374
lowering_error! {
@@ -377,6 +392,19 @@ fn duplicate_parameters() {
377392
"duplicate parameters"
378393
}
379394
}
395+
396+
lowering_error! {
397+
program {
398+
trait Fn<T> {}
399+
trait Ref<'a, T> {}
400+
401+
trait Foo<'a> {
402+
type Item<T>: forall<'a> Fn<Ref<'a, T>>;
403+
}
404+
} error_msg {
405+
"duplicate parameters"
406+
}
407+
}
380408
}
381409

382410
#[test]

src/rules.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -614,12 +614,14 @@ impl AssociatedTyDatum {
614614
// FromEnv(<T as Foo>::Assoc: Bounds) :- FromEnv(Self: Foo)
615615
// }
616616
clauses.extend(self.bounds_on_self().into_iter().map(|bound| {
617+
// Same as above in case of higher-ranked inline bounds.
618+
let shift = bound.binders.len();
617619
Binders {
618-
binders: binders.clone(),
620+
binders: bound.binders.iter().chain(binders.iter()).cloned().collect(),
619621
value: ProgramClauseImplication {
620-
consequence: bound.into_from_env_goal(),
622+
consequence: bound.value.clone().into_from_env_goal(),
621623
conditions: vec![
622-
FromEnv::Trait(trait_ref.clone()).cast()
624+
FromEnv::Trait(trait_ref.clone()).up_shift(shift).cast()
623625
],
624626
}
625627
}.cast()

src/rules/wf.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,8 @@ impl WfSolver {
216216

217217
let wf_goals =
218218
input_types.into_iter()
219-
.map(|ty| DomainGoal::WellFormed(WellFormed::Ty(ty)));
219+
.map(|ty| DomainGoal::WellFormed(WellFormed::Ty(ty)))
220+
.casted();
220221

221222
let trait_ref = trait_ref.up_shift(assoc_ty.value.binders.len());
222223

@@ -233,9 +234,10 @@ impl WfSolver {
233234
bounds.iter()
234235
.map(|b| Subst::apply(&all_parameters, b))
235236
.flat_map(|b| b.into_where_clauses(assoc_ty.value.value.ty.clone()))
236-
.map(|g| g.into_well_formed_goal());
237+
.map(|wc| wc.map(|bound| bound.into_well_formed_goal()))
238+
.casted();
237239

238-
let goals = wf_goals.chain(bound_goals).casted();
240+
let goals = wf_goals.chain(bound_goals);
239241
let goal = match goals.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf))) {
240242
Some(goal) => goal,
241243
None => return None,

src/rules/wf/test.rs

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -519,3 +519,45 @@ fn higher_ranked_cyclic_requirements() {
519519
}
520520
}
521521
}
522+
523+
#[test]
524+
fn higher_ranked_inline_bound_on_gat() {
525+
lowering_success! {
526+
program {
527+
trait Fn<T> { }
528+
struct Ref<'a, T> { }
529+
struct i32 {}
530+
531+
struct fn<T> { }
532+
533+
impl<'a, T> Fn<Ref<'a, T>> for for<'b> fn<Ref<'b, T>> { }
534+
535+
trait Bar {
536+
type Item<T>: forall<'a> Fn<Ref<'a, T>>;
537+
}
538+
539+
impl Bar for i32 {
540+
type Item<T> = for<'a> fn<Ref<'a, T>>;
541+
}
542+
}
543+
}
544+
545+
lowering_error! {
546+
program {
547+
trait Fn<T, U> { }
548+
struct i32 {}
549+
550+
struct fn<T, U> { }
551+
552+
trait Bar {
553+
type Item<T>: forall<U> Fn<T, U>;
554+
}
555+
556+
impl Bar for i32 {
557+
type Item<T> = fn<T, i32>;
558+
}
559+
} error_msg {
560+
"trait impl for \"Bar\" does not meet well-formedness requirements"
561+
}
562+
}
563+
}

src/solve/test.rs

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -798,6 +798,30 @@ fn gat_implied_bounds() {
798798
"No possible solution"
799799
}
800800
}
801+
802+
test! {
803+
program {
804+
trait Fn<T> { }
805+
struct Ref<'a, T> { }
806+
trait Sized { }
807+
808+
trait Foo {
809+
type Item<T>: forall<'a> Fn<Ref<'a, T>> + Sized;
810+
}
811+
}
812+
813+
goal {
814+
forall<Type> {
815+
if (Type: Foo) {
816+
forall<'a, T> {
817+
<Type as Foo>::Item<T>: Fn<Ref<'a, T>>
818+
}
819+
}
820+
}
821+
} yields {
822+
"Unique"
823+
}
824+
}
801825
}
802826

803827
#[test]

0 commit comments

Comments
 (0)