Skip to content

Commit 3691f7c

Browse files
Extend well-formedness check of ADTs to include where-clauses (#148)
* Extend well-formedness check of ADTs to include where-clauses * Update adt_wf.rs --------- Co-authored-by: Niko Matsakis <niko@alum.mit.edu>
1 parent d5825b0 commit 3691f7c

File tree

5 files changed

+124
-6
lines changed

5 files changed

+124
-6
lines changed

crates/formality-prove/src/decls.rs

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ pub struct Decls {
1515
pub neg_impl_decls: Vec<NegImplDecl>,
1616
pub alias_eq_decls: Vec<AliasEqDecl>,
1717
pub alias_bound_decls: Vec<AliasBoundDecl>,
18+
pub adt_decls: Vec<AdtDecl>,
1819
pub local_trait_ids: Set<TraitId>,
1920
pub local_adt_ids: Set<AdtId>,
2021
}
@@ -70,6 +71,13 @@ impl Decls {
7071
&self.alias_bound_decls
7172
}
7273

74+
pub fn adt_decl(&self, adt_id: &AdtId) -> &AdtDecl {
75+
let mut v: Vec<_> = self.adt_decls.iter().filter(|t| t.id == *adt_id).collect();
76+
assert!(!v.is_empty(), "no ADT named `{adt_id:?}`");
77+
assert!(v.len() <= 1, "multiple ADTs named `{adt_id:?}`");
78+
v.pop().unwrap()
79+
}
80+
7381
/// Return the set of "trait invariants" for all traits.
7482
/// See [`TraitDecl::trait_invariants`].
7583
pub fn trait_invariants(&self) -> Set<TraitInvariant> {
@@ -87,6 +95,7 @@ impl Decls {
8795
neg_impl_decls: vec![],
8896
alias_eq_decls: vec![],
8997
alias_bound_decls: vec![],
98+
adt_decls: vec![],
9099
local_trait_ids: set![],
91100
local_adt_ids: set![],
92101
}
@@ -257,3 +266,23 @@ pub struct AliasBoundDeclBoundData {
257266
pub ensures: Binder<Wc>,
258267
pub where_clause: Wcs,
259268
}
269+
270+
/// An "ADT declaration" declares an ADT name, its generics, and its where-clauses.
271+
/// It doesn't capture the ADT fields, yet.
272+
///
273+
/// In Rust syntax, it covers the `struct Foo<X> where X: Bar` part of the declaration, but not what appears in the `{...}`.
274+
#[term(adt $id $binder)]
275+
pub struct AdtDecl {
276+
/// The name of the ADT.
277+
pub id: AdtId,
278+
279+
/// The binder here captures the generics of the ADT.
280+
pub binder: Binder<AdtDeclBoundData>,
281+
}
282+
283+
/// The "bound data" for a [`AdtDecl`][].
284+
#[term(where $where_clause)]
285+
pub struct AdtDeclBoundData {
286+
/// The where-clauses declared on the ADT,
287+
pub where_clause: Wcs,
288+
}

crates/formality-prove/src/prove/prove_wf.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use formality_types::grammar::{
33
AliasName, AliasTy, ConstData, Parameter, Parameters, RigidName, RigidTy, UniversalVar, Wcs,
44
};
55

6-
use crate::{decls::Decls, prove::combinators::for_all};
6+
use crate::{
7+
decls::Decls,
8+
prove::{combinators::for_all, prove_after::prove_after},
9+
};
710

811
use super::{constraints::Constraints, env::Env};
912

@@ -41,8 +44,11 @@ judgment_fn! {
4144

4245
(
4346
(for_all(&decls, &env, &assumptions, &parameters, &prove_wf) => c)
47+
(let t = decls.adt_decl(&adt_id))
48+
(let t = t.binder.instantiate_with(&parameters).unwrap())
49+
(prove_after(&decls, c, &assumptions, t.where_clause) => c)
4450
--- ("ADT")
45-
(prove_wf(decls, env, assumptions, RigidTy { name: RigidName::AdtId(_), parameters }) => c)
51+
(prove_wf(decls, env, assumptions, RigidTy { name: RigidName::AdtId(adt_id), parameters }) => c)
4652
)
4753

4854
(

crates/formality-prove/src/test.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod adt_wf;
12
mod eq_assumptions;
23
mod eq_partial_eq;
34
mod exists_constraints;
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
use expect_test::expect;
2+
use formality_core::test;
3+
use formality_types::{
4+
grammar::{Parameter, Relation, Wcs},
5+
rust::term,
6+
};
7+
8+
use crate::{decls::Decls, prove::prove};
9+
10+
fn decls() -> Decls {
11+
Decls {
12+
trait_decls: vec![term("trait Foo<ty Self> where {}")],
13+
impl_decls: vec![term("impl<> Foo(u32) where {}")],
14+
adt_decls: vec![term("adt X<ty T> where {Foo(T)}")],
15+
..Decls::empty()
16+
}
17+
}
18+
19+
#[test]
20+
fn well_formed_adt() {
21+
let assumptions: Wcs = Wcs::t();
22+
let goal: Parameter = term("X<u32>");
23+
let constraints = prove(decls(), (), assumptions, Relation::WellFormed(goal));
24+
expect![[r#"
25+
{
26+
Constraints {
27+
env: Env {
28+
variables: [],
29+
coherence_mode: false,
30+
},
31+
known_true: true,
32+
substitution: {},
33+
},
34+
}
35+
"#]]
36+
.assert_debug_eq(&constraints);
37+
}
38+
39+
#[test]
40+
fn not_well_formed_adt() {
41+
let assumptions: Wcs = Wcs::t();
42+
let goal: Parameter = term("X<u64>");
43+
let constraints = prove(decls(), (), assumptions, Relation::WellFormed(goal));
44+
expect![[r#"
45+
{}
46+
"#]]
47+
.assert_debug_eq(&constraints);
48+
}

crates/formality-rust/src/prove.rs

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use crate::grammar::{
2-
AssociatedTy, AssociatedTyBoundData, AssociatedTyValue, AssociatedTyValueBoundData, Crate,
3-
CrateItem, ImplItem, NegTraitImpl, NegTraitImplBoundData, Program, Trait, TraitBoundData,
4-
TraitImpl, TraitImplBoundData, TraitItem, WhereBound, WhereBoundData, WhereClause,
5-
WhereClauseData,
2+
Adt, AdtBoundData, AssociatedTy, AssociatedTyBoundData, AssociatedTyValue,
3+
AssociatedTyValueBoundData, Crate, CrateItem, ImplItem, NegTraitImpl, NegTraitImplBoundData,
4+
Program, Trait, TraitBoundData, TraitImpl, TraitImplBoundData, TraitItem, WhereBound,
5+
WhereBoundData, WhereClause, WhereClauseData,
66
};
77
use formality_core::{seq, Set, To, Upcast, Upcasted};
88
use formality_prove as prove;
@@ -22,6 +22,7 @@ impl Program {
2222
neg_impl_decls: self.neg_impl_decls(),
2323
alias_eq_decls: self.alias_eq_decls(),
2424
alias_bound_decls: self.alias_bound_decls(),
25+
adt_decls: self.adt_decls(),
2526
local_trait_ids: self.local_trait_ids(),
2627
local_adt_ids: self.local_adt_ids(),
2728
}
@@ -56,6 +57,10 @@ impl Program {
5657
.collect()
5758
}
5859

60+
fn adt_decls(&self) -> Vec<prove::AdtDecl> {
61+
self.crates.iter().flat_map(|c| c.adt_decls()).collect()
62+
}
63+
5964
fn local_trait_ids(&self) -> Set<TraitId> {
6065
self.crates
6166
.last()
@@ -279,6 +284,35 @@ impl Crate {
279284
.collect()
280285
}
281286

287+
fn adt_decls(&self) -> Vec<prove::AdtDecl> {
288+
self.items
289+
.iter()
290+
.flat_map(|item| match item {
291+
CrateItem::Struct(s) => Some(s.to_adt()),
292+
CrateItem::Enum(e) => Some(e.to_adt()),
293+
_ => None,
294+
})
295+
.map(|Adt { id, binder }| {
296+
let (
297+
vars,
298+
AdtBoundData {
299+
where_clauses,
300+
variants: _,
301+
},
302+
) = binder.open();
303+
prove::AdtDecl {
304+
id: id.clone(),
305+
binder: Binder::new(
306+
vars,
307+
prove::AdtDeclBoundData {
308+
where_clause: where_clauses.iter().flat_map(|wc| wc.to_wcs()).collect(),
309+
},
310+
),
311+
}
312+
})
313+
.collect()
314+
}
315+
282316
fn adt_ids(&self) -> Set<AdtId> {
283317
self.items
284318
.iter()

0 commit comments

Comments
 (0)