Skip to content

Commit 2956a69

Browse files
committed
check negative impls per coherence rules
1 parent b70ee17 commit 2956a69

File tree

3 files changed

+51
-2
lines changed

3 files changed

+51
-2
lines changed

crates/formality-check/src/coherence.rs

Lines changed: 21 additions & 1 deletion
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) {
@@ -54,6 +60,20 @@ impl Check<'_> {
5460
)
5561
}
5662

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+
5777
#[tracing::instrument(level = "Debug", skip(self))]
5878
fn overlap_check(&self, impl_a: &TraitImpl, impl_b: &TraitImpl) -> Fallible<()> {
5979
let mut env = Env::default();

crates/formality-rust/src/grammar.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,12 @@ pub struct NegTraitImplBoundData {
281281
pub where_clauses: Vec<WhereClause>,
282282
}
283283

284+
impl NegTraitImplBoundData {
285+
pub fn trait_ref(&self) -> TraitRef {
286+
self.trait_id.with(&self.self_ty, &self.trait_parameters)
287+
}
288+
}
289+
284290
#[term]
285291
pub enum ImplItem {
286292
#[cast]

tests/coherence_orphan.rs

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use formality::test_program_ok;
44
use formality_macros::test;
55

66
#[test]
7-
fn test_orphan_basic() {
7+
fn test_orphan_CoreTrait_for_CoreStruct_in_Foo() {
88
expect_test::expect![[r#"
99
Err(
1010
Error {
@@ -26,6 +26,29 @@ fn test_orphan_basic() {
2626
));
2727
}
2828

29+
#[test]
30+
fn test_orphan_neg_CoreTrait_for_CoreStruct_in_Foo() {
31+
expect_test::expect![[r#"
32+
Err(
33+
Error {
34+
context: "orphan_check_neg(impl <> ! CoreTrait < > for (rigid (adt CoreStruct)) where [] {})",
35+
source: "failed to prove {@ IsLocal(CoreTrait((rigid (adt CoreStruct))))} given {}, got {}",
36+
},
37+
)
38+
"#]]
39+
.assert_debug_eq(&test_program_ok(
40+
"[
41+
crate core {
42+
trait CoreTrait<> where [] {}
43+
struct CoreStruct<> where [] {}
44+
},
45+
crate foo {
46+
impl<> !CoreTrait<> for CoreStruct<> where [] {}
47+
}
48+
]",
49+
));
50+
}
51+
2952
#[test]
3053
fn test_orphan_mirror_CoreStruct() {
3154
expect_test::expect![[r#"

0 commit comments

Comments
 (0)