Skip to content

Commit 959f352

Browse files
authored
Merge pull request #124 from nikomatsakis/assoc-ty-norm
tests around associated type normalization
2 parents ae38718 + 5a164e9 commit 959f352

File tree

216 files changed

+721
-16676
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

216 files changed

+721
-16676
lines changed

Cargo.lock

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,14 @@ expect-test = "1.4.0"
1414
formality-macros = { version = "0.1.0", path = "crates/formality-macros" }
1515
formality-core = { version = "0.1.0", path = "crates/formality-core" }
1616

17+
1718
[dependencies]
1819
anyhow = "1"
1920
clap = { version = "4.0.9", features = ["derive"] }
2021
formality-rust = { version = "0.1.0", path = "crates/formality-rust" }
2122
formality-types = { version = "0.1.0", path = "crates/formality-types" }
2223
formality-check = { version = "0.1.0", path = "crates/formality-check" }
24+
formality-prove = { version = "0.1.0", path = "crates/formality-prove" }
2325

2426
[workspace]
2527
members = [

crates/formality-check/src/coherence.rs

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use anyhow::bail;
22
use fn_error_context::context;
33
use formality_prove::Env;
4-
use formality_rust::grammar::{Crate, TraitImpl};
4+
use formality_rust::grammar::{Crate, NegTraitImpl, TraitImpl};
55
use formality_types::{
66
cast::Downcasted,
77
grammar::{Fallible, Wc, Wcs},
@@ -15,11 +15,17 @@ impl Check<'_> {
1515
let all_crate_impls: Vec<TraitImpl> =
1616
self.program.items_from_all_crates().downcasted().collect();
1717
let current_crate_impls: Vec<TraitImpl> = current_crate.items.iter().downcasted().collect();
18+
let current_crate_neg_impls: Vec<NegTraitImpl> =
19+
current_crate.items.iter().downcasted().collect();
1820

1921
for impl_a in &current_crate_impls {
2022
self.orphan_check(impl_a)?;
2123
}
2224

25+
for impl_a in &current_crate_neg_impls {
26+
self.orphan_check_neg(impl_a)?;
27+
}
28+
2329
// check for duplicate impls in the current crate
2430
for (impl_a, i) in current_crate_impls.iter().zip(0..) {
2531
if current_crate_impls[i + 1..].contains(impl_a) {
@@ -32,6 +38,7 @@ impl Check<'_> {
3238
.iter()
3339
.cartesian_product(&all_crate_impls)
3440
.filter(|(impl_a, impl_b)| impl_a != impl_b)
41+
.filter(|(impl_a, impl_b)| impl_a.trait_id() == impl_b.trait_id())
3542
{
3643
self.overlap_check(impl_a, impl_b)?;
3744
}
@@ -53,6 +60,20 @@ impl Check<'_> {
5360
)
5461
}
5562

63+
#[context("orphan_check_neg({impl_a:?})")]
64+
fn orphan_check_neg(&self, impl_a: &NegTraitImpl) -> Fallible<()> {
65+
let mut env = Env::default();
66+
67+
let a = env.instantiate_universally(&impl_a.binder);
68+
let trait_ref = a.trait_ref();
69+
70+
self.prove_goal(
71+
&env.with_coherence_mode(true),
72+
&a.where_clauses,
73+
trait_ref.is_local(),
74+
)
75+
}
76+
5677
#[tracing::instrument(level = "Debug", skip(self))]
5778
fn overlap_check(&self, impl_a: &TraitImpl, impl_b: &TraitImpl) -> Fallible<()> {
5879
let mut env = Env::default();
@@ -72,25 +93,28 @@ impl Check<'_> {
7293
let trait_ref_a = a.trait_ref();
7394
let trait_ref_b = b.trait_ref();
7495

75-
// If the parameters from the two impls cannot be equal, then they do not overlap.
76-
//
77-
// If we can prove `∀P_a, ∀P_b. not (T_a = T_b, Wc_a, Wc_b)`, then they do not overlap.
78-
if let Ok(()) = self.prove_not_goal(
79-
&env.with_coherence_mode(true),
80-
(&a.where_clauses, &b.where_clauses),
81-
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
82-
) {
83-
return Ok(());
84-
}
96+
assert_eq!(trait_ref_a.trait_id, trait_ref_b.trait_id);
8597

86-
// If we can disprove the where clauses, then they do not overlap.
87-
//
88-
// If we can prove `∀P_a, ∀P_b. not [(T_a = T_b) => (Wc_a, Wc_b)]`, then they do not overlap.
98+
// If we can prove that the parameters cannot be equated *or* the where-clauses don't hold,
99+
// in coherence mode, then they do not overlap.
89100
if let Ok(()) = self.prove_not_goal(
90101
&env.with_coherence_mode(true),
91-
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
92-
(&a.where_clauses, &b.where_clauses),
102+
(),
103+
(
104+
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
105+
&a.where_clauses,
106+
&b.where_clauses,
107+
),
93108
) {
109+
tracing::debug!(
110+
"proved not {:?}",
111+
(
112+
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
113+
&a.where_clauses,
114+
&b.where_clauses,
115+
)
116+
);
117+
94118
return Ok(());
95119
}
96120

@@ -106,18 +130,28 @@ impl Check<'_> {
106130
.chain(&b.where_clauses)
107131
.flat_map(|wc| wc.invert())
108132
.collect();
109-
if inverted.iter().any(|inverted_wc| {
133+
if let Some(inverted_wc) = inverted.iter().find(|inverted_wc| {
110134
self.prove_goal(
111135
&env,
112136
(
113137
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
114138
&a.where_clauses,
115139
&b.where_clauses,
116140
),
117-
inverted_wc,
141+
&inverted_wc,
118142
)
119143
.is_ok()
120144
}) {
145+
tracing::debug!(
146+
"proved {:?} assuming {:?}",
147+
&inverted_wc,
148+
(
149+
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
150+
&a.where_clauses,
151+
&b.where_clauses,
152+
)
153+
);
154+
121155
return Ok(());
122156
}
123157
bail!("impls may overlap: `{impl_a:?}` vs `{impl_b:?}`")

crates/formality-check/src/fns.rs

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,28 @@
11
use formality_prove::Env;
2-
use formality_rust::grammar::{Fn, FnBoundData, WhereClause};
3-
use formality_types::{cast::Upcast, grammar::Fallible};
2+
use formality_rust::{
3+
grammar::{Fn, FnBoundData},
4+
prove::ToWcs,
5+
};
6+
use formality_types::{
7+
grammar::{Fallible, Wcs},
8+
};
49

510
use crate::Check;
611

712
impl Check<'_> {
8-
pub(crate) fn check_free_fn(&self, _f: &Fn) -> Fallible<()> {
9-
todo!()
13+
pub(crate) fn check_free_fn(&self, f: &Fn) -> Fallible<()> {
14+
self.check_fn(&Env::default(), Wcs::t(), f)
1015
}
1116

1217
pub(crate) fn check_fn(
1318
&self,
1419
in_env: &Env,
15-
in_assumptions: &[WhereClause],
20+
in_assumptions: impl ToWcs,
1621
f: &Fn,
1722
) -> Fallible<()> {
23+
let in_assumptions = in_assumptions.to_wcs();
24+
assert!(in_env.only_universal_variables() && in_env.encloses((&in_assumptions, f)));
25+
1826
let mut env = in_env.clone();
1927

2028
let Fn { id: _, binder } = f;
@@ -26,15 +34,15 @@ impl Check<'_> {
2634
body: _,
2735
} = env.instantiate_universally(binder);
2836

29-
let assumptions: Vec<WhereClause> = (in_assumptions, &where_clauses).upcast();
37+
let fn_assumptions: Wcs = (in_assumptions, &where_clauses).to_wcs();
3038

31-
self.prove_where_clauses_well_formed(&env, &assumptions, &where_clauses)?;
39+
self.prove_where_clauses_well_formed(&env, &fn_assumptions, &where_clauses)?;
3240

3341
for input_ty in &input_tys {
34-
self.prove_goal(&env, &assumptions, input_ty.well_formed())?;
42+
self.prove_goal(&env, &fn_assumptions, input_ty.well_formed())?;
3543
}
3644

37-
self.prove_goal(&env, &assumptions, output_ty.well_formed())?;
45+
self.prove_goal(&env, &fn_assumptions, output_ty.well_formed())?;
3846

3947
Ok(())
4048
}

crates/formality-check/src/impls.rs

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
11
use anyhow::bail;
2-
use contracts::requires;
2+
33
use fn_error_context::context;
44
use formality_prove::Env;
5-
use formality_rust::grammar::{
6-
AssociatedTy, AssociatedTyBoundData, AssociatedTyValue, AssociatedTyValueBoundData, Fn,
7-
FnBoundData, ImplItem, NegTraitImpl, NegTraitImplBoundData, TraitBoundData, TraitImpl,
8-
TraitImplBoundData, TraitItem, WhereClause,
5+
use formality_rust::{
6+
grammar::{
7+
AssociatedTy, AssociatedTyBoundData, AssociatedTyValue, AssociatedTyValueBoundData, Fn,
8+
FnBoundData, ImplItem, NegTraitImpl, NegTraitImplBoundData, TraitBoundData, TraitImpl,
9+
TraitImplBoundData, TraitItem,
10+
},
11+
prove::ToWcs,
912
};
1013
use formality_types::{
1114
cast::Downcasted,
1215
grammar::{Binder, Fallible, Relation, Substitution, Wcs},
1316
term::Term,
14-
visit::Visit,
1517
};
1618

1719
impl super::Check<'_> {
@@ -69,16 +71,20 @@ impl super::Check<'_> {
6971
Ok(())
7072
}
7173

72-
#[requires(assumptions.iter().all(|a| a.references_only_placeholder_variables()))]
7374
fn check_trait_impl_item(
7475
&self,
7576
env: &Env,
76-
assumptions: &[WhereClause],
77+
assumptions: impl ToWcs,
7778
trait_items: &[TraitItem],
7879
impl_item: &ImplItem,
7980
) -> Fallible<()> {
81+
let assumptions: Wcs = assumptions.to_wcs();
82+
assert!(
83+
env.only_universal_variables() && env.encloses((&assumptions, trait_items, impl_item))
84+
);
85+
8086
match impl_item {
81-
ImplItem::Fn(v) => self.check_fn_in_impl(env, assumptions, trait_items, v),
87+
ImplItem::Fn(v) => self.check_fn_in_impl(env, &assumptions, trait_items, v),
8288
ImplItem::AssociatedTyValue(v) => {
8389
self.check_associated_ty_value(env, assumptions, trait_items, v)
8490
}
@@ -88,12 +94,13 @@ impl super::Check<'_> {
8894
fn check_fn_in_impl(
8995
&self,
9096
env: &Env,
91-
impl_assumptions: &[WhereClause],
97+
impl_assumptions: impl ToWcs,
9298
trait_items: &[TraitItem],
9399
ii_fn: &Fn,
94100
) -> Fallible<()> {
101+
let impl_assumptions: Wcs = impl_assumptions.to_wcs();
95102
assert!(
96-
env.only_universal_variables() && env.encloses((impl_assumptions, trait_items, ii_fn))
103+
env.only_universal_variables() && env.encloses((&impl_assumptions, trait_items, ii_fn))
97104
);
98105

99106
// Find the corresponding function from the trait:
@@ -108,7 +115,7 @@ impl super::Check<'_> {
108115

109116
tracing::debug!(?ti_fn);
110117

111-
self.check_fn(env, impl_assumptions, ii_fn)?;
118+
self.check_fn(env, &impl_assumptions, ii_fn)?;
112119

113120
let mut env = env.clone();
114121
let (
@@ -128,7 +135,7 @@ impl super::Check<'_> {
128135

129136
self.prove_goal(
130137
&env,
131-
(impl_assumptions, &ti_where_clauses),
138+
(&impl_assumptions, &ti_where_clauses),
132139
&ii_where_clauses,
133140
)?;
134141

@@ -143,27 +150,35 @@ impl super::Check<'_> {
143150
for (ii_input_ty, ti_input_ty) in ii_input_tys.iter().zip(&ti_input_tys) {
144151
self.prove_goal(
145152
&env,
146-
(impl_assumptions, &ii_where_clauses),
153+
(&impl_assumptions, &ii_where_clauses),
147154
Relation::sub(ti_input_ty, ii_input_ty),
148155
)?;
149156
}
150157

151158
self.prove_goal(
152159
&env,
153-
(impl_assumptions, &ii_where_clauses),
160+
(&impl_assumptions, &ii_where_clauses),
154161
Relation::sub(ii_output_ty, ti_output_ty),
155162
)?;
156163

157164
Ok(())
158165
}
159166

167+
#[context("check_associated_ty_value({impl_value:?})")]
160168
fn check_associated_ty_value(
161169
&self,
162170
impl_env: &Env,
163-
impl_assumptions: &[WhereClause],
171+
impl_assumptions: impl ToWcs,
164172
trait_items: &[TraitItem],
165173
impl_value: &AssociatedTyValue,
166174
) -> Fallible<()> {
175+
let impl_assumptions: Wcs = impl_assumptions.to_wcs();
176+
177+
assert!(
178+
impl_env.only_universal_variables()
179+
&& impl_env.encloses((&impl_assumptions, trait_items, impl_value))
180+
);
181+
167182
let AssociatedTyValue { id, binder } = impl_value;
168183

169184
let trait_associated_ty = match trait_items
@@ -190,24 +205,24 @@ impl super::Check<'_> {
190205

191206
self.prove_where_clauses_well_formed(
192207
&env,
193-
(impl_assumptions, &ii_where_clauses),
208+
(&impl_assumptions, &ii_where_clauses),
194209
&ii_where_clauses,
195210
)?;
196211

197212
self.prove_goal(
198213
&env,
199-
(impl_assumptions, &ti_where_clauses),
214+
(&impl_assumptions, &ti_where_clauses),
200215
&ii_where_clauses,
201216
)?;
202217

203218
self.prove_goal(
204219
&env,
205-
(impl_assumptions, &ii_where_clauses),
220+
(&impl_assumptions, &ii_where_clauses),
206221
ii_ty.well_formed(),
207222
)?;
208223

209224
let ensures: Wcs = ti_ensures.iter().map(|e| e.to_wc(&ii_ty)).collect();
210-
self.prove_goal(&env, (impl_assumptions, &ii_where_clauses), ensures)?;
225+
self.prove_goal(&env, (&impl_assumptions, &ii_where_clauses), ensures)?;
211226

212227
Ok(())
213228
}

crates/formality-check/src/where_clauses.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,9 @@ impl super::Check<'_> {
1212
pub(crate) fn prove_where_clauses_well_formed(
1313
&self,
1414
env: &Env,
15-
assumptions: impl Upcast<Vec<WhereClause>>,
15+
assumptions: impl ToWcs,
1616
where_clauses: &[WhereClause],
1717
) -> Fallible<()> {
18-
let assumptions: Vec<WhereClause> = assumptions.upcast();
1918
for where_clause in where_clauses {
2019
self.prove_where_clause_well_formed(env, &assumptions, where_clause)?;
2120
}
@@ -25,10 +24,9 @@ impl super::Check<'_> {
2524
fn prove_where_clause_well_formed(
2625
&self,
2726
in_env: &Env,
28-
assumptions: impl Upcast<Vec<WhereClause>>,
27+
assumptions: impl ToWcs,
2928
where_clause: &WhereClause,
3029
) -> Fallible<()> {
31-
let assumptions: Vec<WhereClause> = assumptions.upcast();
3230
match where_clause.data() {
3331
WhereClauseData::IsImplemented(self_ty, trait_id, parameters) => self
3432
.prove_trait_ref_well_formed(

crates/formality-prove/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,10 @@ mod prove;
66

77
pub use decls::*;
88
pub use prove::prove;
9+
pub use prove::Constraints;
910
pub use prove::Env;
1011

1112
#[cfg(test)]
1213
mod test;
14+
15+
pub mod test_util;

0 commit comments

Comments
 (0)