1use crate::ast;
4
5pub trait TypeInfo {
7 fn subtype(&self, other: &Self) -> bool;
9}
10
11impl TypeInfo for ast::SequenceType {
12 fn subtype(&self, other: &ast::SequenceType) -> bool {
14 match (self, other) {
15 (ast::SequenceType::Empty, ast::SequenceType::Empty) => true,
16 (ast::SequenceType::Empty, ast::SequenceType::Item(ast::Item { occurrence, .. })) => {
17 match occurrence {
18 ast::Occurrence::Option => true,
19 ast::Occurrence::Many => true,
20 ast::Occurrence::One => false,
21 ast::Occurrence::NonEmpty => false,
22 }
23 }
24 (ast::SequenceType::Item(_), ast::SequenceType::Empty) => false,
25 (
26 ast::SequenceType::Item(ast::Item {
27 item_type: a_item_type,
28 occurrence: a_occurrence,
29 }),
30 ast::SequenceType::Item(ast::Item {
31 item_type: b_item_type,
32 occurrence: b_occurrence,
33 }),
34 ) => match (a_occurrence, b_occurrence) {
35 (ast::Occurrence::Option, ast::Occurrence::Option) => {
36 a_item_type.subtype(b_item_type)
37 }
38 (ast::Occurrence::Option, ast::Occurrence::Many) => {
39 a_item_type.subtype(b_item_type)
40 }
41 (ast::Occurrence::Option, ast::Occurrence::One) => false,
42 (ast::Occurrence::Option, ast::Occurrence::NonEmpty) => false,
43 (ast::Occurrence::Many, ast::Occurrence::Option) => false,
44 (ast::Occurrence::Many, ast::Occurrence::Many) => a_item_type.subtype(b_item_type),
45 (ast::Occurrence::Many, ast::Occurrence::One) => false,
46 (ast::Occurrence::Many, ast::Occurrence::NonEmpty) => false,
47 (ast::Occurrence::One, ast::Occurrence::Option) => a_item_type.subtype(b_item_type),
48 (ast::Occurrence::One, ast::Occurrence::Many) => a_item_type.subtype(b_item_type),
49 (ast::Occurrence::One, ast::Occurrence::One) => a_item_type.subtype(b_item_type),
50 (ast::Occurrence::One, ast::Occurrence::NonEmpty) => {
51 a_item_type.subtype(b_item_type)
52 }
53 (ast::Occurrence::NonEmpty, ast::Occurrence::Option) => false,
54 (ast::Occurrence::NonEmpty, ast::Occurrence::Many) => {
55 a_item_type.subtype(b_item_type)
56 }
57 (ast::Occurrence::NonEmpty, ast::Occurrence::One) => false,
58 (ast::Occurrence::NonEmpty, ast::Occurrence::NonEmpty) => {
59 a_item_type.subtype(b_item_type)
60 }
61 },
62 }
63 }
64}
65
66impl TypeInfo for ast::ItemType {
67 fn subtype(&self, other: &ast::ItemType) -> bool {
69 match (self, other) {
70 (ast::ItemType::AtomicOrUnionType(a), ast::ItemType::AtomicOrUnionType(b)) => {
73 a.derives_from(*b)
74 }
75 (_, ast::ItemType::Item) => true,
81 (ast::ItemType::KindTest(_), ast::ItemType::KindTest(ast::KindTest::Any)) => true,
83 (
85 ast::ItemType::KindTest(ast::KindTest::Text),
86 ast::ItemType::KindTest(ast::KindTest::Text),
87 ) => true,
88 (
90 ast::ItemType::KindTest(ast::KindTest::Comment),
91 ast::ItemType::KindTest(ast::KindTest::Comment),
92 ) => true,
93 (
95 ast::ItemType::KindTest(ast::KindTest::NamespaceNode),
96 ast::ItemType::KindTest(ast::KindTest::NamespaceNode),
97 ) => true,
98 (
102 ast::ItemType::KindTest(ast::KindTest::PI(_)),
103 ast::ItemType::KindTest(ast::KindTest::PI(None)),
104 ) => true,
105 (
108 ast::ItemType::KindTest(ast::KindTest::PI(Some(a))),
109 ast::ItemType::KindTest(ast::KindTest::PI(Some(b))),
110 ) => a == b,
111 (
114 ast::ItemType::KindTest(ast::KindTest::Document(_)),
115 ast::ItemType::KindTest(ast::KindTest::Document(None)),
116 ) => true,
117 (
120 ast::ItemType::KindTest(ast::KindTest::Document(Some(a))),
121 ast::ItemType::KindTest(ast::KindTest::Document(Some(b))),
122 ) => a.subtype(b),
123 (
125 ast::ItemType::KindTest(ast::KindTest::Element(_)),
126 ast::ItemType::KindTest(ast::KindTest::Element(None)),
127 ) => true,
128 (
130 ast::ItemType::KindTest(ast::KindTest::Element(Some(a))),
131 ast::ItemType::KindTest(ast::KindTest::Element(Some(b))),
132 ) => a.subtype(b),
133 (
139 ast::ItemType::KindTest(ast::KindTest::SchemaElement(_)),
140 ast::ItemType::KindTest(ast::KindTest::SchemaElement(_)),
141 ) => false,
142 (
145 ast::ItemType::KindTest(ast::KindTest::Attribute(_)),
146 ast::ItemType::KindTest(ast::KindTest::Attribute(None)),
147 ) => true,
148 (
150 ast::ItemType::KindTest(ast::KindTest::Attribute(Some(a))),
151 ast::ItemType::KindTest(ast::KindTest::Attribute(Some(b))),
152 ) => a.subtype(b),
153 (
157 ast::ItemType::KindTest(ast::KindTest::SchemaAttribute(_)),
158 ast::ItemType::KindTest(ast::KindTest::SchemaAttribute(_)),
159 ) => false,
160 (
162 ast::ItemType::FunctionTest(_),
163 ast::ItemType::FunctionTest(ast::FunctionTest::AnyFunctionTest),
164 ) => true,
165 (
167 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(a)),
168 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(b)),
169 ) => a.subtype(b),
170 (ast::ItemType::MapTest(_), ast::ItemType::MapTest(ast::MapTest::AnyMapTest)) => true,
172 (
175 ast::ItemType::MapTest(ast::MapTest::TypedMapTest(a_typed_map_test)),
176 ast::ItemType::MapTest(ast::MapTest::TypedMapTest(b_typed_map_test)),
177 ) => a_typed_map_test.as_ref().subtype(b_typed_map_test.as_ref()),
178 (
181 ast::ItemType::MapTest(_),
182 ast::ItemType::FunctionTest(ast::FunctionTest::AnyFunctionTest),
183 ) => true,
184
185 (
189 ast::ItemType::MapTest(_),
190 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(
191 typed_function_test,
192 )),
193 ) if typed_function_test.as_ref() == &map_function_test() => true,
194 (
196 ast::ItemType::ArrayTest(_),
197 ast::ItemType::ArrayTest(ast::ArrayTest::AnyArrayTest),
198 ) => true,
199 (
201 ast::ItemType::ArrayTest(ast::ArrayTest::TypedArrayTest(a_typed_array_test)),
202 ast::ItemType::ArrayTest(ast::ArrayTest::TypedArrayTest(b_typed_array_test)),
203 ) if a_typed_array_test
204 .as_ref()
205 .subtype(b_typed_array_test.as_ref()) =>
206 {
207 true
208 }
209 (
212 ast::ItemType::ArrayTest(_),
213 ast::ItemType::FunctionTest(ast::FunctionTest::AnyFunctionTest),
214 ) => true,
215
216 (
219 ast::ItemType::ArrayTest(_),
220 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(
221 typed_function_test,
222 )),
223 ) if typed_function_test.as_ref() == &array_function_test() => true,
224 (
227 ast::ItemType::MapTest(ast::MapTest::TypedMapTest(typed_map_test)),
228 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(
229 typed_function_test,
230 )),
231 ) => {
232 typed_function_test.parameter_types.len() == 1
233 && typed_function_test.parameter_types[0]
234 == ast::SequenceType::Item(ast::Item {
235 item_type: ast::ItemType::AtomicOrUnionType(
236 xee_schema_type::Xs::AnyAtomicType,
237 ),
238 occurrence: ast::Occurrence::One,
239 })
240 && is_type_question_mark(
241 &typed_map_test.value_type,
242 &typed_function_test.return_type,
243 )
244 }
245 (
247 ast::ItemType::ArrayTest(ast::ArrayTest::TypedArrayTest(a_sequence_type)),
248 ast::ItemType::FunctionTest(ast::FunctionTest::TypedFunctionTest(
249 typed_function_test,
250 )),
251 ) => {
252 typed_function_test.parameter_types.len() == 1
253 && typed_function_test.parameter_types[0]
254 == ast::SequenceType::Item(ast::Item {
255 item_type: ast::ItemType::AtomicOrUnionType(
256 xee_schema_type::Xs::Integer,
257 ),
258 occurrence: ast::Occurrence::One,
259 })
260 && a_sequence_type.item_type == typed_function_test.return_type
261 }
262 _ => false,
263 }
264 }
265}
266
267fn is_type_question_mark(a: &ast::SequenceType, b: &ast::SequenceType) -> bool {
270 match (a, b) {
271 (ast::SequenceType::Empty, ast::SequenceType::Empty) => true,
272 (ast::SequenceType::Item(a_item), ast::SequenceType::Item(b_item)) => {
273 if a_item != b_item {
274 return false;
275 }
276 match &b_item.occurrence {
277 ast::Occurrence::One => false,
278 ast::Occurrence::NonEmpty => false,
279 ast::Occurrence::Option => true,
280 ast::Occurrence::Many => true,
281 }
282 }
283 _ => false,
284 }
285}
286
287fn map_function_test() -> ast::TypedFunctionTest {
288 map_function_test_with_return_type(&ast::SequenceType::Item(ast::Item {
289 item_type: ast::ItemType::Item,
290 occurrence: ast::Occurrence::Many,
291 }))
292}
293
294fn map_function_test_with_return_type(return_type: &ast::SequenceType) -> ast::TypedFunctionTest {
295 ast::TypedFunctionTest {
296 parameter_types: vec![ast::SequenceType::Item(ast::Item {
297 item_type: ast::ItemType::AtomicOrUnionType(xee_schema_type::Xs::AnyAtomicType),
298 occurrence: ast::Occurrence::One,
299 })],
300 return_type: return_type.clone(),
301 }
302}
303
304fn array_function_test() -> ast::TypedFunctionTest {
305 ast::TypedFunctionTest {
306 parameter_types: vec![ast::SequenceType::Item(ast::Item {
307 item_type: ast::ItemType::AtomicOrUnionType(xee_schema_type::Xs::Integer),
308 occurrence: ast::Occurrence::One,
309 })],
310 return_type: ast::SequenceType::Item(ast::Item {
311 item_type: ast::ItemType::Item,
312 occurrence: ast::Occurrence::Many,
313 }),
314 }
315}
316
317impl TypeInfo for ast::DocumentTest {
318 fn subtype(&self, other: &ast::DocumentTest) -> bool {
319 match (self, other) {
320 (ast::DocumentTest::Element(..), ast::DocumentTest::Element(None)) => true,
322 (
323 ast::DocumentTest::Element(Some(a_element_or_attribute_test)),
324 ast::DocumentTest::Element(Some(b_element_or_attribute_test)),
325 ) => a_element_or_attribute_test.subtype(b_element_or_attribute_test),
326 _ => false,
328 }
329 }
330}
331
332impl TypeInfo for ast::ElementOrAttributeTest {
333 fn subtype(&self, other: &ast::ElementOrAttributeTest) -> bool {
334 match (self, other) {
335 (
340 ast::ElementOrAttributeTest {
341 name_or_wildcard: ast::NameOrWildcard::Name(a_name),
342 ..
343 },
344 ast::ElementOrAttributeTest {
345 name_or_wildcard: ast::NameOrWildcard::Name(b_name),
346 type_name:
347 None
348 | Some(ast::TypeName {
349 name: xee_schema_type::Xs::AnyType,
350 can_be_nilled: true,
351 }),
352 },
353 ) => a_name == b_name,
354 (
358 ast::ElementOrAttributeTest {
359 name_or_wildcard: ast::NameOrWildcard::Name(a_name),
360 type_name:
361 Some(ast::TypeName {
362 name: a_type_name,
363 can_be_nilled: false,
364 }),
365 },
366 ast::ElementOrAttributeTest {
367 name_or_wildcard: ast::NameOrWildcard::Name(b_name),
368 type_name:
369 Some(ast::TypeName {
370 name: b_type_name,
371 can_be_nilled: false,
372 }),
373 },
374 ) => a_name == b_name && a_type_name.derives_from(*b_type_name),
375 (
379 ast::ElementOrAttributeTest {
380 name_or_wildcard: ast::NameOrWildcard::Name(a_name),
381 type_name:
382 Some(ast::TypeName {
383 name: a_type_name, ..
384 }),
385 },
386 ast::ElementOrAttributeTest {
387 name_or_wildcard: ast::NameOrWildcard::Name(b_name),
388 type_name:
389 Some(ast::TypeName {
390 name: b_type_name,
391 can_be_nilled: true,
392 }),
393 },
394 ) => a_name == b_name && a_type_name.derives_from(*b_type_name),
395 (
399 ast::ElementOrAttributeTest {
400 type_name:
401 Some(ast::TypeName {
402 name: a_type_name,
403 can_be_nilled: false,
404 }),
405 ..
406 },
407 ast::ElementOrAttributeTest {
408 name_or_wildcard: ast::NameOrWildcard::Wildcard,
409 type_name:
410 Some(ast::TypeName {
411 name: b_type_name,
412 can_be_nilled: false,
413 }),
414 },
415 ) => a_type_name.derives_from(*b_type_name),
416 (
420 ast::ElementOrAttributeTest {
421 type_name:
422 Some(ast::TypeName {
423 name: a_type_name, ..
424 }),
425 ..
426 },
427 ast::ElementOrAttributeTest {
428 name_or_wildcard: ast::NameOrWildcard::Wildcard,
429 type_name:
430 Some(ast::TypeName {
431 name: b_type_name,
432 can_be_nilled: true,
433 }),
434 },
435 ) => a_type_name.derives_from(*b_type_name),
436 _ => false,
437 }
438 }
439}
440
441impl TypeInfo for ast::TypedFunctionTest {
442 fn subtype(&self, other: &ast::TypedFunctionTest) -> bool {
443 if self.parameter_types.len() != other.parameter_types.len() {
449 return false;
450 }
451
452 if !self.return_type.subtype(&other.return_type) {
454 return false;
455 }
456
457 for (a, b) in self
458 .parameter_types
459 .iter()
460 .zip(other.parameter_types.iter())
461 {
462 if !b.subtype(a) {
464 return false;
465 }
466 }
467 true
468 }
469}
470
471impl TypeInfo for ast::TypedMapTest {
472 fn subtype(&self, other: &ast::TypedMapTest) -> bool {
473 self.key_type.derives_from(other.key_type) && self.value_type.subtype(&other.value_type)
474 }
475}
476
477impl TypeInfo for ast::TypedArrayTest {
478 fn subtype(&self, other: &ast::TypedArrayTest) -> bool {
479 self.item_type.subtype(&other.item_type)
480 }
481}