Skip to content

Commit cdeb4a6

Browse files
committed
Add support for quantified bounds on GATs
1 parent dc7dbad commit cdeb4a6

File tree

9 files changed

+165
-27
lines changed

9 files changed

+165
-27
lines changed

chalk-parse/src/ast.rs

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

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

+20-6
Original file line numberDiff line numberDiff line change
@@ -275,19 +275,34 @@ pub enum InlineBound {
275275
ProjectionEqBound(ProjectionEqBound),
276276
}
277277

278+
pub type QuantifiedInlineBound = Binders<InlineBound>;
279+
278280
impl InlineBound {
279281
/// Applies the `InlineBound` to `self_ty` and lowers to a [`DomainGoal`].
280282
///
281283
/// Because an `InlineBound` does not know anything about what it's binding,
282284
/// you must provide that type as `self_ty`.
283-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
285+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
284286
match self {
285287
InlineBound::TraitBound(b) => b.into_where_clauses(self_ty),
286288
InlineBound::ProjectionEqBound(b) => b.into_where_clauses(self_ty),
287289
}
288290
}
289291
}
290292

293+
impl QuantifiedInlineBound {
294+
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<QuantifiedWhereClause> {
295+
let self_ty = self_ty.up_shift(self.binders.len());
296+
self.value.into_where_clauses(self_ty).into_iter().map(|wc| {
297+
Binders {
298+
binders: self.binders.clone(),
299+
value: wc,
300+
}
301+
}).collect()
302+
}
303+
}
304+
305+
291306
/// Represents a trait bound on e.g. a type or type parameter.
292307
/// Does not know anything about what it's binding.
293308
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -297,7 +312,7 @@ pub struct TraitBound {
297312
}
298313

299314
impl TraitBound {
300-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
315+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
301316
let trait_ref = self.as_trait_ref(self_ty);
302317
vec![WhereClause::Implemented(trait_ref)]
303318
}
@@ -310,7 +325,6 @@ impl TraitBound {
310325
}
311326
}
312327
}
313-
314328
/// Represents a projection equality bound on e.g. a type or type parameter.
315329
/// Does not know anything about what it's binding.
316330
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
@@ -323,7 +337,7 @@ pub struct ProjectionEqBound {
323337
}
324338

325339
impl ProjectionEqBound {
326-
crate fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
340+
fn into_where_clauses(&self, self_ty: Ty) -> Vec<WhereClause> {
327341
let trait_ref = self.trait_bound.as_trait_ref(self_ty);
328342

329343
let mut parameters = self.parameters.clone();
@@ -361,7 +375,7 @@ pub struct AssociatedTyDatum {
361375
///
362376
/// These must be proven by the implementer, for all possible parameters that
363377
/// would result in a well-formed projection.
364-
crate bounds: Vec<InlineBound>,
378+
crate bounds: Vec<QuantifiedInlineBound>,
365379

366380
/// Where clauses that must hold for the projection to be well-formed.
367381
crate where_clauses: Vec<QuantifiedWhereClause>,
@@ -373,7 +387,7 @@ impl AssociatedTyDatum {
373387
/// ```notrust
374388
/// Implemented(<?0 as Foo>::Item<?1>: Sized)
375389
/// ```
376-
crate fn bounds_on_self(&self) -> Vec<WhereClause> {
390+
crate fn bounds_on_self(&self) -> Vec<QuantifiedWhereClause> {
377391
let parameters = self.parameter_kinds
378392
.anonymize()
379393
.iter()

src/ir/lowering.rs

+21-13
Original file line numberDiff line numberDiff line change
@@ -414,17 +414,11 @@ impl LowerWhereClauses for Impl {
414414
}
415415
}
416416

417-
trait LowerWhereClauseVec<T> {
418-
fn lower(&self, env: &Env) -> Result<Vec<T>>;
417+
trait LowerWhereClauseVec {
418+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedWhereClause>>;
419419
}
420420

421-
impl LowerWhereClauseVec<ir::WhereClause> for [WhereClause] {
422-
fn lower(&self, env: &Env) -> Result<Vec<ir::WhereClause>> {
423-
self.iter().flat_map(|wc| wc.lower(env).apply_result()).collect()
424-
}
425-
}
426-
427-
impl LowerWhereClauseVec<ir::QuantifiedWhereClause> for [QuantifiedWhereClause] {
421+
impl LowerWhereClauseVec for [QuantifiedWhereClause] {
428422
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedWhereClause>> {
429423
self.iter()
430424
.flat_map(|wc| match wc.lower(env) {
@@ -723,12 +717,26 @@ impl LowerInlineBound for InlineBound {
723717
}
724718
}
725719

726-
trait LowerInlineBounds {
727-
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>>;
720+
trait LowerQuantifiedInlineBound {
721+
fn lower(&self, env: &Env) -> Result<ir::QuantifiedInlineBound>;
722+
}
723+
724+
impl LowerQuantifiedInlineBound for QuantifiedInlineBound {
725+
fn lower(&self, env: &Env) -> Result<ir::QuantifiedInlineBound> {
726+
let parameter_kinds = self.parameter_kinds.iter().map(|pk| pk.lower());
727+
let binders = env.in_binders(parameter_kinds, |env| {
728+
Ok(self.bound.lower(env)?)
729+
})?;
730+
Ok(binders)
731+
}
732+
}
733+
734+
trait LowerQuantifiedInlineBoundVec {
735+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedInlineBound>>;
728736
}
729737

730-
impl LowerInlineBounds for Vec<InlineBound> {
731-
fn lower(&self, env: &Env) -> Result<Vec<ir::InlineBound>> {
738+
impl LowerQuantifiedInlineBoundVec for [QuantifiedInlineBound] {
739+
fn lower(&self, env: &Env) -> Result<Vec<ir::QuantifiedInlineBound>> {
732740
self.iter()
733741
.map(|b| b.lower(env))
734742
.collect()

src/ir/lowering/test.rs

+28
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! {
@@ -388,6 +403,19 @@ fn duplicate_parameters() {
388403
"duplicate or shadowed parameters"
389404
}
390405
}
406+
407+
lowering_error! {
408+
program {
409+
trait Fn<T> {}
410+
trait Ref<'a, T> {}
411+
412+
trait Foo<'a> {
413+
type Item<T>: forall<'a> Fn<Ref<'a, T>>;
414+
}
415+
} error_msg {
416+
"duplicate parameters"
417+
}
418+
}
391419
}
392420

393421
#[test]

src/rules.rs

+5-3
Original file line numberDiff line numberDiff line change
@@ -717,12 +717,14 @@ impl AssociatedTyDatum {
717717
// FromEnv(<T as Foo>::Assoc: Bounds) :- FromEnv(Self: Foo)
718718
// }
719719
clauses.extend(self.bounds_on_self().into_iter().map(|bound| {
720+
// Same as above in case of higher-ranked inline bounds.
721+
let shift = bound.binders.len();
720722
Binders {
721-
binders: binders.clone(),
723+
binders: bound.binders.iter().chain(binders.iter()).cloned().collect(),
722724
value: ProgramClauseImplication {
723-
consequence: bound.into_from_env_goal(),
725+
consequence: bound.value.clone().into_from_env_goal(),
724726
conditions: vec![
725-
FromEnv::Trait(trait_ref.clone()).cast()
727+
FromEnv::Trait(trait_ref.clone()).up_shift(shift).cast()
726728
],
727729
}
728730
}.cast()

src/rules/wf.rs

+5-3
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

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

+24
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)