Skip to content

Commit fe53d35

Browse files
committed
Converting back to overlap instead of disjoint so that we workaround
the implementation of `not` and produce `Ambiguous` when we expect to. Needed to delete a test because it would no longer lower now that the overlap check works correctly.
1 parent db6b0ca commit fe53d35

File tree

5 files changed

+22
-52
lines changed

5 files changed

+22
-52
lines changed

src/coherence/solve.rs

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use ir::*;
77
use cast::*;
88
use solve::{SolverChoice, Solution};
99

10-
struct DisjointSolver {
10+
struct OverlapSolver {
1111
env: Arc<ProgramEnvironment>,
1212
solver_choice: SolverChoice,
1313
}
@@ -21,7 +21,7 @@ impl Program {
2121
where
2222
F: FnMut(ItemId, ItemId),
2323
{
24-
let mut solver = DisjointSolver {
24+
let mut solver = OverlapSolver {
2525
env: Arc::new(self.environment()),
2626
solver_choice,
2727
};
@@ -65,7 +65,7 @@ impl Program {
6565
// Check if the impls overlap, then if they do, check if one specializes
6666
// the other. Note that specialization can only run one way - if both
6767
// specialization checks return *either* true or false, that's an error.
68-
if !solver.disjoint(lhs, rhs) {
68+
if solver.overlap(lhs, rhs) {
6969
match (solver.specializes(lhs, rhs), solver.specializes(rhs, lhs)) {
7070
(true, false) => record_specialization(l_id, r_id),
7171
(false, true) => record_specialization(r_id, l_id),
@@ -82,36 +82,36 @@ impl Program {
8282
}
8383
}
8484

85-
impl DisjointSolver {
86-
// Test if two impls are disjoint. If the test does not succeed, there is an overlap.
85+
impl OverlapSolver {
86+
// Test if the set of types that these two impls apply to overlap. If the test succeeds, these
87+
// two impls overlap.
8788
//
8889
// We combine the binders of the two impls & treat them as existential
8990
// quantifiers. Then we attempt to unify the input types to the trait provided
9091
// by each impl, as well as prove that the where clauses from both impls all
91-
// hold. At the end, we negate the query because we only want to return `true` if
92-
// it is provable that there is no overlap.
92+
// hold.
9393
//
9494
// Examples:
9595
//
9696
// Impls:
9797
// impl<T> Foo for T { }
9898
// impl Foo for i32 { }
9999
// Generates:
100-
// compatible { not { exists<T> { T = i32 } } }
100+
// compatible { exists<T> { T = i32 } }
101101
//
102102
// Impls:
103103
// impl<T1, U> Foo<T1> for Vec<U> { }
104104
// impl<T2> Foo<T2> for Vec<i32> { }
105105
// Generates:
106-
// compatible { not { exists<T1, U, T2> { Vec<U> = Vec<i32>, T1 = T2 } } }
106+
// compatible { exists<T1, U, T2> { Vec<U> = Vec<i32>, T1 = T2 } }
107107
//
108108
// Impls:
109109
// impl<T> Foo for Vec<T> where T: Bar { }
110110
// impl<U> Foo for Vec<U> where U: Baz { }
111111
// Generates:
112-
// compatible { not { exists<T, U> { Vec<T> = Vec<U>, T: Bar, U: Baz } } }
112+
// compatible { exists<T, U> { Vec<T> = Vec<U>, T: Bar, U: Baz } }
113113
//
114-
fn disjoint(&self, lhs: &ImplDatum, rhs: &ImplDatum) -> bool {
114+
fn overlap(&self, lhs: &ImplDatum, rhs: &ImplDatum) -> bool {
115115
debug_heading!("overlaps(lhs={:#?}, rhs={:#?})", lhs, rhs);
116116

117117
let lhs_len = lhs.binders.len();
@@ -150,19 +150,19 @@ impl DisjointSolver {
150150
.fold1(|goal, leaf| Goal::And(Box::new(goal), Box::new(leaf)))
151151
.expect("Every trait takes at least one input type")
152152
.quantify(QuantifierKind::Exists, binders)
153-
.negate()
154153
.compatible();
155154

156155
let canonical_goal = &goal.into_closed_goal();
157156
let solution = self.solver_choice
158157
.solve_root_goal(&self.env, canonical_goal)
159158
.unwrap(); // internal errors in the solver are fatal
160159
let result = match solution {
161-
// Goal was proven with a unique solution, so impls are disjoint
162-
Some(Solution::Unique(_)) => true,
160+
// Goal was proven with a unique solution, so an impl was found that causes these two
161+
// to overlap
162+
Some(Solution::Unique(_)) |
163163
// Goal was ambiguous, so there *may* be overlap
164-
Some(Solution::Ambig(_)) |
165-
// Goal cannot be proven, so impls definitely overlap
164+
Some(Solution::Ambig(_)) => true,
165+
// Goal cannot be proven, so impls are disjoint
166166
None => false,
167167
};
168168
debug!("overlaps: result = {:?}", result);

src/coherence/test.rs

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -62,21 +62,18 @@ fn two_blanket_impls() {
6262
}
6363

6464
#[test]
65-
// FIXME This should be an error
66-
// We currently assume a closed universe always, but overlaps checking should
67-
// assume an open universe - what if a client implemented both Bar and Baz
68-
//
69-
// In other words, this should have the same behavior as the two_blanket_impls
70-
// test.
7165
fn two_blanket_impls_open_ended() {
72-
lowering_success! {
66+
lowering_error! {
7367
program {
7468
trait Foo { }
7569
trait Bar { }
7670
trait Baz { }
7771
impl<T> Foo for T where T: Bar { }
7872
impl<T> Foo for T where T: Baz { }
7973
}
74+
error_msg {
75+
"overlapping impls of trait \"Foo\""
76+
}
8077
}
8178
}
8279

src/ir.rs

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1102,11 +1102,6 @@ impl Goal {
11021102
)
11031103
}
11041104

1105-
/// Takes a goal `G` and turns it into `not { G }`
1106-
crate fn negate(self) -> Self {
1107-
Goal::Not(Box::new(self))
1108-
}
1109-
11101105
/// Takes a goal `G` and turns it into `compatible { G }`
11111106
crate fn compatible(self) -> Self {
11121107
// compatible { G } desugars into: forall<T> { if (Compatible, DownstreamType(T)) { G } }

src/solve/slg/test.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -744,10 +744,10 @@ fn example_3_3_EWFS() {
744744
delayed_literals: DelayedLiteralSet {
745745
delayed_literals: {
746746
Negative(
747-
TableIndex(4)
747+
TableIndex(1)
748748
),
749749
Negative(
750-
TableIndex(1)
750+
TableIndex(6)
751751
)
752752
}
753753
}

src/solve/test.rs

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1936,28 +1936,6 @@ fn mixed_semantics() {
19361936
}
19371937
}
19381938

1939-
#[test]
1940-
fn partial_overlap_1() {
1941-
test! {
1942-
program {
1943-
trait Marker {}
1944-
trait Foo {}
1945-
trait Bar {}
1946-
1947-
impl<T> Marker for T where T: Foo {}
1948-
impl<T> Marker for T where T: Bar {}
1949-
}
1950-
1951-
goal {
1952-
forall<T> {
1953-
if (T: Foo; T: Bar) { T: Marker }
1954-
}
1955-
} yields {
1956-
"Unique"
1957-
}
1958-
}
1959-
}
1960-
19611939
#[test]
19621940
fn partial_overlap_2() {
19631941
test! {

0 commit comments

Comments
 (0)