Skip to content

Commit 89f28d4

Browse files
committed
add negative impls
1 parent 9a3f6c6 commit 89f28d4

File tree

7 files changed

+76
-19
lines changed

7 files changed

+76
-19
lines changed

crates/formality-check/src/coherence.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use formality_prove::Env;
33
use formality_rust::grammar::{Crate, TraitImpl};
44
use formality_types::{
55
cast::Downcasted,
6-
grammar::{Fallible, Wcs},
6+
grammar::{Fallible, Wc, Wcs},
77
};
88
use itertools::Itertools;
99

@@ -69,6 +69,27 @@ impl Check<'_> {
6969
return Ok(());
7070
}
7171

72+
// If we can disprove the where clauses, then they do not overlap.
73+
let inverted: Vec<Wc> = a
74+
.where_clauses
75+
.iter()
76+
.chain(&b.where_clauses)
77+
.flat_map(|wc| wc.invert())
78+
.collect();
79+
if inverted.iter().any(|inverted_wc| {
80+
self.prove_goal(
81+
&env,
82+
(
83+
Wcs::all_eq(&trait_ref_a.parameters, &trait_ref_b.parameters),
84+
&a.where_clauses,
85+
&b.where_clauses,
86+
),
87+
inverted_wc,
88+
)
89+
.is_ok()
90+
}) {
91+
return Ok(());
92+
}
7293
bail!("impls may overlap: `{impl_a:?}` vs `{impl_b:?}`")
7394
}
7495
}

crates/formality-check/src/lib.rs

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -5,13 +5,10 @@ use std::collections::VecDeque;
55
use anyhow::bail;
66
use formality_prove::{Decls, Env};
77
use formality_rust::{
8-
grammar::{Crate, CrateItem, Program, WhereClause},
8+
grammar::{Crate, CrateItem, Program},
99
prove::ToWcs,
1010
};
11-
use formality_types::{
12-
cast::Upcast,
13-
grammar::{Fallible, Substitution, Wcs},
14-
};
11+
use formality_types::grammar::{Fallible, Substitution, Wcs};
1512

1613
/// Check all crates in the program. The crates must be in dependency order
1714
/// such that any prefix of the crates is a complete program.
@@ -89,19 +86,14 @@ impl Check<'_> {
8986
}
9087
}
9188

92-
fn prove_goal(
93-
&self,
94-
env: &Env,
95-
assumptions: impl Upcast<Vec<WhereClause>>,
96-
goal: impl ToWcs,
97-
) -> Fallible<()> {
89+
fn prove_goal(&self, env: &Env, assumptions: impl ToWcs, goal: impl ToWcs) -> Fallible<()> {
9890
let goal: Wcs = goal.to_wcs();
99-
let assumptions: Vec<WhereClause> = assumptions.upcast();
91+
let assumptions: Wcs = assumptions.to_wcs();
10092

10193
assert!(env.only_universal_variables());
10294
assert!(env.encloses((&assumptions, &goal)));
10395

104-
let cs = formality_prove::prove(self.decls, env, assumptions.to_wcs(), &goal);
96+
let cs = formality_prove::prove(self.decls, env, &assumptions, &goal);
10597
if cs.iter().any(|c| c.unconditionally_true()) {
10698
return Ok(());
10799
}

crates/formality-check/src/where_clauses.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use formality_prove::Env;
2-
use formality_rust::grammar::{WhereClause, WhereClauseData};
2+
use formality_rust::{
3+
grammar::{WhereClause, WhereClauseData},
4+
prove::ToWcs,
5+
};
36
use formality_types::{
47
cast::Upcast,
58
grammar::{Fallible, Parameter, TraitRef},
@@ -48,7 +51,7 @@ impl super::Check<'_> {
4851
fn prove_parameter_well_formed(
4952
&self,
5053
env: &Env,
51-
assumptions: impl Upcast<Vec<WhereClause>>,
54+
assumptions: impl ToWcs,
5255
parameter: impl Upcast<Parameter>,
5356
) -> Fallible<()> {
5457
let parameter: Parameter = parameter.upcast();
@@ -58,7 +61,7 @@ impl super::Check<'_> {
5861
fn prove_trait_ref_well_formed(
5962
&self,
6063
env: &Env,
61-
assumptions: impl Upcast<Vec<WhereClause>>,
64+
assumptions: impl ToWcs,
6265
trait_ref: impl Upcast<TraitRef>,
6366
) -> Fallible<()> {
6467
let trait_ref: TraitRef = trait_ref.upcast();

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,16 @@ judgment_fn! {
5353
(prove_wc(decls, env, assumptions, Predicate::IsImplemented(trait_ref)) => c.pop_subst(&subst))
5454
)
5555

56+
(
57+
(decls.neg_impl_decls(&trait_ref.trait_id) => i)
58+
(let (env, subst) = env.existential_substitution(&i.binder))
59+
(let i = i.binder.instantiate_with(&subst).unwrap())
60+
(prove(&decls, env, &assumptions, Wcs::all_eq(&trait_ref.parameters, &i.trait_ref.parameters)) => c)
61+
(prove_after(&decls, c, &assumptions, &i.where_clause) => c)
62+
----------------------------- ("impl")
63+
(prove_wc(decls, env, assumptions, Predicate::NotImplemented(trait_ref)) => c.pop_subst(&subst))
64+
)
65+
5666
(
5767
(decls.trait_invariants() => ti)
5868
(let (env, subst) = env.existential_substitution(&ti.binder))

crates/formality-rust/src/grammar.rs

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use formality_types::{
55
cast::Upcast,
66
grammar::{
77
AdtId, AssociatedItemId, Binder, CrateId, Fallible, FieldId, FnId, Lt, Parameter, TraitId,
8-
TraitRef, Ty,
8+
TraitRef, Ty, Wc,
99
},
1010
term::Term,
1111
};
@@ -304,6 +304,23 @@ impl WhereClause {
304304
pub fn data(&self) -> &WhereClauseData {
305305
&self.data
306306
}
307+
308+
pub fn invert(&self) -> Option<Wc> {
309+
match self.data() {
310+
WhereClauseData::IsImplemented(self_ty, trait_id, parameters) => Some(
311+
trait_id
312+
.with(self_ty, parameters)
313+
.not_implemented()
314+
.upcast(),
315+
),
316+
WhereClauseData::Outlives(_, _) => None,
317+
WhereClauseData::ForAll(binder) => {
318+
let (vars, where_clause) = binder.open();
319+
let wc = where_clause.invert()?;
320+
Some(Wc::for_all(&vars, wc))
321+
}
322+
}
323+
}
307324
}
308325

309326
#[term]

crates/formality-rust/src/prove.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,20 @@ where
306306
}
307307
}
308308

309+
impl<A, B, C> ToWcs for (A, B, C)
310+
where
311+
A: ToWcs,
312+
B: ToWcs,
313+
C: ToWcs,
314+
{
315+
fn to_wcs(&self) -> Wcs {
316+
let (a, b, c) = self;
317+
let a = a.to_wcs();
318+
let b = b.to_wcs();
319+
let c = c.to_wcs();
320+
(a, b, c).upcast()
321+
}
322+
}
309323
impl ToWcs for Vec<WhereClause> {
310324
fn to_wcs(&self) -> Wcs {
311325
self.iter().flat_map(|wc| wc.to_wcs()).collect()

tests/hello_world.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ fn test_broken() {
2626
Err(
2727
Error {
2828
context: "check_trait(Foo)",
29-
source: "failed to prove {@ WellFormedTraitRef(Bar(!ty_2, !ty_1))} given [!ty_2 : Bar < !ty_1 >], got {}",
29+
source: "failed to prove {@ WellFormedTraitRef(Bar(!ty_2, !ty_1))} given {Bar(!ty_2, !ty_1)}, got {}",
3030
},
3131
)
3232
"#]].assert_debug_eq(&test_program_ok(PROGRAM_BROKEN));

0 commit comments

Comments
 (0)