1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
use crate::interner::HasInterner;
use crate::zip::{Zip, Zipper};
use crate::*;
pub trait CouldMatch<T: ?Sized + HasInterner> {
    fn could_match(
        &self,
        interner: T::Interner,
        db: &dyn UnificationDatabase<T::Interner>,
        other: &T,
    ) -> bool;
}
#[allow(unreachable_code, unused_variables)]
impl<T, I> CouldMatch<T> for T
where
    T: Zip<I> + ?Sized + HasInterner<Interner = I>,
    I: Interner,
{
    fn could_match(&self, interner: I, db: &dyn UnificationDatabase<I>, other: &T) -> bool {
        return Zip::zip_with(
            &mut MatchZipper { interner, db },
            Variance::Invariant,
            self,
            other,
        )
        .is_ok();
        struct MatchZipper<'i, I> {
            interner: I,
            db: &'i dyn UnificationDatabase<I>,
        }
        impl<'i, I: Interner> Zipper<I> for MatchZipper<'i, I> {
            fn zip_tys(&mut self, variance: Variance, a: &Ty<I>, b: &Ty<I>) -> Fallible<()> {
                let interner = self.interner;
                let matches = |a: &Substitution<I>, b: &Substitution<I>| {
                    a.iter(interner)
                        .zip(b.iter(interner))
                        .all(|(p_a, p_b)| p_a.could_match(interner, self.db, p_b))
                };
                let could_match = match (a.kind(interner), b.kind(interner)) {
                    (TyKind::Adt(id_a, substitution_a), TyKind::Adt(id_b, substitution_b)) => {
                        id_a == id_b
                            && self
                                .zip_substs(
                                    variance,
                                    Some(self.unification_database().adt_variance(*id_a)),
                                    substitution_a.as_slice(interner),
                                    substitution_b.as_slice(interner),
                                )
                                .is_ok()
                    }
                    (
                        TyKind::AssociatedType(assoc_ty_a, substitution_a),
                        TyKind::AssociatedType(assoc_ty_b, substitution_b),
                    ) => assoc_ty_a == assoc_ty_b && matches(substitution_a, substitution_b),
                    (TyKind::Scalar(scalar_a), TyKind::Scalar(scalar_b)) => scalar_a == scalar_b,
                    (TyKind::Str, TyKind::Str) => true,
                    (
                        TyKind::Tuple(arity_a, substitution_a),
                        TyKind::Tuple(arity_b, substitution_b),
                    ) => arity_a == arity_b && matches(substitution_a, substitution_b),
                    (
                        TyKind::OpaqueType(opaque_ty_a, substitution_a),
                        TyKind::OpaqueType(opaque_ty_b, substitution_b),
                    ) => opaque_ty_a == opaque_ty_b && matches(substitution_a, substitution_b),
                    (TyKind::Slice(ty_a), TyKind::Slice(ty_b)) => {
                        ty_a.could_match(interner, self.db, ty_b)
                    }
                    (
                        TyKind::FnDef(fn_def_a, substitution_a),
                        TyKind::FnDef(fn_def_b, substitution_b),
                    ) => {
                        fn_def_a == fn_def_b
                            && self
                                .zip_substs(
                                    variance,
                                    Some(self.unification_database().fn_def_variance(*fn_def_a)),
                                    substitution_a.as_slice(interner),
                                    substitution_b.as_slice(interner),
                                )
                                .is_ok()
                    }
                    (
                        TyKind::Ref(mutability_a, lifetime_a, ty_a),
                        TyKind::Ref(mutability_b, lifetime_b, ty_b),
                    ) => {
                        mutability_a == mutability_b
                            && lifetime_a.could_match(interner, self.db, lifetime_b)
                            && ty_a.could_match(interner, self.db, ty_b)
                    }
                    (TyKind::Raw(mutability_a, ty_a), TyKind::Raw(mutability_b, ty_b)) => {
                        mutability_a == mutability_b && ty_a.could_match(interner, self.db, ty_b)
                    }
                    (TyKind::Never, TyKind::Never) => true,
                    (TyKind::Array(ty_a, const_a), TyKind::Array(ty_b, const_b)) => {
                        ty_a.could_match(interner, self.db, ty_b)
                            && const_a.could_match(interner, self.db, const_b)
                    }
                    (
                        TyKind::Closure(id_a, substitution_a),
                        TyKind::Closure(id_b, substitution_b),
                    ) => id_a == id_b && matches(substitution_a, substitution_b),
                    (
                        TyKind::Generator(generator_a, substitution_a),
                        TyKind::Generator(generator_b, substitution_b),
                    ) => {
                        generator_a == generator_b
                            && self
                                .zip_substs(
                                    variance,
                                    None,
                                    substitution_a.as_slice(interner),
                                    substitution_b.as_slice(interner),
                                )
                                .is_ok()
                    }
                    (
                        TyKind::GeneratorWitness(generator_a, substitution_a),
                        TyKind::GeneratorWitness(generator_b, substitution_b),
                    ) => {
                        generator_a == generator_b
                            && self
                                .zip_substs(
                                    variance,
                                    None,
                                    substitution_a.as_slice(interner),
                                    substitution_b.as_slice(interner),
                                )
                                .is_ok()
                    }
                    (TyKind::Foreign(foreign_ty_a), TyKind::Foreign(foreign_ty_b)) => {
                        foreign_ty_a == foreign_ty_b
                    }
                    (TyKind::Error, TyKind::Error) => true,
                    _ => true,
                };
                if could_match {
                    Ok(())
                } else {
                    Err(NoSolution)
                }
            }
            fn zip_lifetimes(
                &mut self,
                variance: Variance,
                _: &Lifetime<I>,
                _: &Lifetime<I>,
            ) -> Fallible<()> {
                Ok(())
            }
            fn zip_consts(
                &mut self,
                variance: Variance,
                _: &Const<I>,
                _: &Const<I>,
            ) -> Fallible<()> {
                Ok(())
            }
            fn zip_binders<T>(
                &mut self,
                variance: Variance,
                a: &Binders<T>,
                b: &Binders<T>,
            ) -> Fallible<()>
            where
                T: HasInterner + Zip<I>,
            {
                Zip::zip_with(self, variance, &a.value, &b.value)
            }
            fn interner(&self) -> I {
                self.interner
            }
            fn unification_database(&self) -> &dyn UnificationDatabase<I> {
                self.db
            }
        }
    }
}
impl<I: Interner> CouldMatch<DomainGoal<I>> for ProgramClauseData<I> {
    fn could_match(
        &self,
        interner: I,
        db: &dyn UnificationDatabase<I>,
        other: &DomainGoal<I>,
    ) -> bool {
        self.0.value.consequence.could_match(interner, db, other)
    }
}
impl<I: Interner> CouldMatch<DomainGoal<I>> for ProgramClause<I> {
    fn could_match(
        &self,
        interner: I,
        db: &dyn UnificationDatabase<I>,
        other: &DomainGoal<I>,
    ) -> bool {
        self.data(interner).could_match(interner, db, other)
    }
}