1use source_map::SpanWithSource;
4
5use crate::{
6 context::{GeneralContext, InformationChain},
7 features::{
8 objects::{self, SpecialObject},
9 operations::MathematicalOrBitwiseOperation,
10 },
11 Constant, Environment, PropertyValue, TypeId,
12};
13
14use super::{
15 generics::{
16 chain::{GenericChain, GenericChainLink, SpecialGenericChainLink},
17 contributions::{ContributionDepth, Contributions, CovariantContribution, TriMap},
18 generic_type_arguments::GenericArguments,
19 },
20 get_constraint,
21 intrinsics::{self, apply_string_intrinsic},
22 logical::{BasedOnKey, Logical, LogicalOrValid, NeedsCalculation, PropertyOn},
23 printing::print_type,
24 properties::PropertyKey,
25 properties::{get_properties_on_single_type2, get_property_unbound, Publicity},
26 Constructor, ObjectNature, PartiallyAppliedGenerics, PolyNature, Type, TypeStore,
27};
28
29pub use super::{NonEqualityReason, PropertyError};
30
31#[derive(Debug)]
33pub enum SubTypeResult {
34 IsSubType,
35 IsNotSubType(NonEqualityReason),
36}
37
38impl SubTypeResult {
39 #[must_use]
40 pub fn is_mismatch(&self) -> bool {
41 matches!(self, Self::IsNotSubType(..))
42 }
43
44 #[must_use]
45 pub fn is_subtype(&self) -> bool {
46 matches!(self, Self::IsSubType)
47 }
48}
49
50#[derive(Clone, Copy)]
51pub enum SubTypingMode {
52 Contravariant { depth: u8 },
59 Covariant {
66 position: SpanWithSource,
68 },
69}
70
71impl Default for SubTypingMode {
72 fn default() -> Self {
73 Self::Contravariant { depth: 0 }
74 }
75}
76
77impl SubTypingMode {
79 pub(crate) fn one_deeper(self) -> SubTypingMode {
80 match self {
81 SubTypingMode::Contravariant { depth } => Self::Contravariant { depth: depth + 1 },
82 o @ SubTypingMode::Covariant { .. } => o,
83 }
84 }
85
86 pub(crate) fn one_shallower(self) -> SubTypingMode {
87 match self {
88 SubTypingMode::Contravariant { depth } => {
89 Self::Contravariant { depth: depth.saturating_sub(1) }
90 }
91 o @ SubTypingMode::Covariant { .. } => o,
92 }
93 }
94}
95
96mod musing {
97 use crate::TypeId;
98
99 enum _AddPropertyConstraint {
100 No,
102 Yes,
104 OnlyFor(Vec<TypeId>),
106 }
107}
108
109#[derive(Debug, Clone, Copy)]
110pub struct SubTypingOptions {
111 pub allow_errors: bool,
113}
114
115impl Default for SubTypingOptions {
116 fn default() -> Self {
117 Self { allow_errors: true }
118 }
119}
120
121impl SubTypingOptions {
122 #[must_use]
123 pub fn satisfies() -> Self {
124 Self { allow_errors: false }
125 }
126}
127
128pub fn type_is_subtype_object(
130 base_type: TypeId,
131 ty: TypeId,
132 environment: &mut Environment,
133 types: &mut TypeStore,
134) -> SubTypeResult {
135 let mut state = State {
136 already_checked: Vec::new(),
137 mode: SubTypingMode::default(),
138 contributions: None,
139 others: SubTypingOptions { allow_errors: true },
140 object_constraints: Some(Vec::new()),
141 };
142
143 let result = type_is_subtype(base_type, ty, &mut state, environment, types);
144
145 environment.add_object_constraints(state.object_constraints.unwrap().into_iter(), types);
146 result
149}
150
151pub fn type_is_subtype(
156 base_type: TypeId,
157 ty: TypeId,
158 state: &mut State,
159 information: &impl InformationChain,
160 types: &TypeStore,
161) -> SubTypeResult {
162 type_is_subtype_with_generics(
163 (base_type, GenericChain::None),
164 (ty, GenericChain::None),
165 state,
166 information,
167 types,
168 )
169}
170
171pub type AlreadyChecked = Vec<(TypeId, TypeId)>;
173
174pub struct State<'a> {
177 pub already_checked: AlreadyChecked,
179 pub mode: SubTypingMode,
180 pub contributions: Option<Contributions<'a>>,
182 pub object_constraints: Option<Vec<(TypeId, TypeId)>>,
184 pub others: SubTypingOptions,
185}
186
187pub type StateSavePoint = [u16; 4];
188
189impl<'a> State<'a> {
190 #[must_use]
192 pub fn produce_save_point(&self) -> StateSavePoint {
193 let contributions = self.contributions.as_ref();
194 [
195 self.already_checked.len() as u16,
196 contributions.map_or(0, |c| c.staging_covariant.len().try_into().unwrap()),
197 contributions.map_or(0, |c| c.staging_contravariant.len().try_into().unwrap()),
198 self.object_constraints.as_ref().map_or(0, |c| c.len().try_into().unwrap()),
199 ]
200 }
201
202 pub fn reset(&mut self, last: StateSavePoint) {
204 let [already_checked, contributions_covariant, contributions_contravariant, object_constraint_count] =
205 last;
206
207 let _ = self.already_checked.drain((already_checked as usize)..);
208 if let Some(ref mut contributions) = self.contributions {
209 let _ =
210 contributions.staging_covariant.drop_range((contributions_covariant as usize)..);
211 let _ = contributions
212 .staging_contravariant
213 .drop_range((contributions_contravariant as usize)..);
214 }
215 if let Some(ref mut object_constraints) = self.object_constraints {
216 let _ = object_constraints.drain((object_constraint_count as usize)..);
217 }
218 }
219}
220
221pub(crate) fn type_is_subtype_with_generics(
222 (base_type, base_type_arguments): (TypeId, GenericChain),
223 (ty, ty_structure_arguments): (TypeId, GenericChain),
224 state: &mut State,
225 information: &impl InformationChain,
226 types: &TypeStore,
227) -> SubTypeResult {
228 {
229 let debug = true;
230 crate::utilities::notify!(
231 "Checking {} :>= {}, with {:?}",
232 print_type(base_type, types, information, debug),
233 print_type(ty, types, information, debug),
234 base_type_arguments
235 );
236 }
237
238 if base_type == TypeId::ANY_TYPE || ty == TypeId::NEVER_TYPE {
239 return SubTypeResult::IsSubType;
240 }
241
242 if base_type == ty {
243 return SubTypeResult::IsSubType;
244 }
245
246 {
247 if state.already_checked.iter().any(|(a, b)| *a == base_type && *b == ty) {
249 crate::utilities::notify!("Subtyping recursion");
250 return SubTypeResult::IsSubType;
251 }
252
253 state.already_checked.push((base_type, ty));
254 }
255
256 let supertype = types.get_type_by_id(base_type);
257 let subtype = types.get_type_by_id(ty);
258
259 match subtype {
261 Type::Narrowed { narrowed_to: right, .. } | Type::AliasTo { to: right, .. } => {
262 let result = type_is_subtype_with_generics(
263 (base_type, base_type_arguments),
264 (*right, ty_structure_arguments),
265 state,
266 information,
267 types,
268 );
269 return if let (Type::Narrowed { from, .. }, _, true) =
273 (subtype, &result, super::helpers::is_not_of_constant(*right, types))
274 {
275 type_is_subtype_with_generics(
276 (base_type, base_type_arguments),
277 (*from, ty_structure_arguments),
278 state,
279 information,
280 types,
281 )
282 } else {
283 result
284 };
285 }
286 Type::Or(left, right) => {
287 let right = *right;
288 let left_result = type_is_subtype_with_generics(
290 (base_type, base_type_arguments),
291 (*left, ty_structure_arguments),
292 state,
293 information,
294 types,
295 );
296
297 return if let SubTypeResult::IsSubType = left_result {
298 type_is_subtype_with_generics(
299 (base_type, base_type_arguments),
300 (right, ty_structure_arguments),
301 state,
302 information,
303 types,
304 )
305 } else {
306 left_result
308 };
309 }
310 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
311 on: on @ TypeId::NOT_RESTRICTION,
312 arguments: _,
313 }) => {
314 match *on {
315 TypeId::NOT_RESTRICTION => {
316 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
319 }
320 _ => unreachable!(),
321 }
322 }
323 t @ (Type::RootPolyType(..) | Type::Constructor(..)) => {
324 if let Type::RootPolyType(PolyNature::Error(to)) = t {
325 crate::utilities::notify!("Here {:?}", state.others.allow_errors);
327 return if state.others.allow_errors && *to == TypeId::ANY_TYPE {
328 SubTypeResult::IsSubType
329 } else {
330 type_is_subtype(base_type, *to, state, information, types)
331 };
332 }
333
334 if let Some(arg) = ty_structure_arguments.and_then(|tas| tas.get_argument_covariant(ty))
337 {
338 return match arg {
339 CovariantContribution::TypeId(ty) => type_is_subtype_with_generics(
340 (base_type, base_type_arguments),
341 (ty, ty_structure_arguments),
342 state,
343 information,
344 types,
345 ),
346 CovariantContribution::String(string) => {
347 let contributions =
348 state.contributions.as_mut().map(|n| &mut n.staging_contravariant);
349 let matches = slice_matches_type(
350 (base_type, base_type_arguments),
351 &string,
352 contributions,
353 information,
354 types,
355 false,
356 );
357 if matches {
358 SubTypeResult::IsSubType
359 } else {
360 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
361 }
362 }
363 CovariantContribution::SliceOf(s, (l, r)) => todo!("{:?}", (s, (l, r))),
364 CovariantContribution::CaseInsensitive(ci) => todo!("{:?}", ci),
365 CovariantContribution::Number(n) => {
366 let contributions =
367 state.contributions.as_mut().map(|n| &mut n.staging_contravariant);
368 let matches = number_matches_type(
369 (base_type, base_type_arguments),
370 n,
371 contributions,
372 information,
373 types,
374 );
375 if matches {
376 SubTypeResult::IsSubType
377 } else {
378 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
379 }
380 }
381 };
382 }
383
384 if let SubTypingMode::Covariant { position: _ } = state.mode {
385 crate::utilities::notify!("Here covariant parameter chaos?");
386 }
391
392 let right_constraint = get_constraint(ty, types).unwrap();
395
396 let left_is_operator_right_is_not =
407 supertype.is_operator() && !types.get_type_by_id(right_constraint).is_operator();
408
409 let edge_case = left_is_operator_right_is_not
412 || matches!(
413 supertype,
414 Type::RootPolyType(rpt)
415 if rpt.is_substitutable()
416 ) || matches!(supertype, Type::Constructor(..))
417 || base_type_arguments
418 .and_then(|args| args.get_argument_covariant(base_type))
419 .is_some();
420 if !edge_case {
421 let result = type_is_subtype_with_generics(
422 (base_type, base_type_arguments),
423 (right_constraint, ty_structure_arguments),
424 state,
425 information,
426 types,
427 );
428
429 return if result.is_mismatch()
431 && matches!(subtype, Type::RootPolyType(root) if root.is_inferrable())
432 {
433 crate::utilities::notify!("Setting inferred request");
434 SubTypeResult::IsSubType
436 } else {
437 result
438 };
439 }
440 }
441 Type::PartiallyAppliedGenerics(..) => {}
442 _ => (),
443 }
444
445 match supertype {
446 Type::FunctionReference(left_func)
447 | Type::SpecialObject(SpecialObject::Function(left_func, _)) => subtype_function(
448 (*left_func, base_type_arguments),
449 (subtype, ty, ty_structure_arguments),
450 state,
451 information,
452 types,
453 ),
454 Type::Constant(lhs) => {
455 if let Type::Constant(rhs) = subtype {
456 if lhs == rhs {
457 SubTypeResult::IsSubType
458 } else {
459 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
460 }
461 } else {
462 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
465 }
466 }
467 Type::Object(ObjectNature::AnonymousTypeAnnotation(properties)) => subtype_properties(
468 (base_type, properties.iter(), base_type_arguments),
469 (ty, ty_structure_arguments),
470 state,
471 information,
472 types,
473 ),
474 Type::Object(ObjectNature::RealDeal) => {
475 crate::utilities::notify!(
476 "what {:?} (subtyping where LHS = ObjectNature::RealDeal)",
477 ty
478 );
479
480 subtype_floating_properties(
481 (base_type, base_type_arguments),
482 (ty, ty_structure_arguments),
483 state,
484 information,
485 types,
486 )
487 }
488 Type::And(left, right) => {
489 let right = *right;
490 let left_result = type_is_subtype_with_generics(
492 (*left, base_type_arguments),
493 (ty, ty_structure_arguments),
494 state,
495 information,
496 types,
497 );
498
499 if let SubTypeResult::IsSubType = left_result {
500 type_is_subtype_with_generics(
501 (right, base_type_arguments),
502 (ty, ty_structure_arguments),
503 state,
504 information,
505 types,
506 )
507 } else {
508 left_result
510 }
511 }
512 Type::Or(left, right) => {
513 let right = *right;
514 let save_point = state.produce_save_point();
515
516 let left_result = type_is_subtype_with_generics(
517 (*left, base_type_arguments),
518 (ty, ty_structure_arguments),
519 state,
520 information,
521 types,
522 );
523
524 if let SubTypeResult::IsSubType = left_result {
525 if state.contributions.is_some() {
526 let _res = type_is_subtype_with_generics(
528 (right, base_type_arguments),
529 (ty, ty_structure_arguments),
530 state,
531 information,
532 types,
533 );
534 }
535 SubTypeResult::IsSubType
536 } else {
537 state.reset(save_point);
539
540 type_is_subtype_with_generics(
541 (right, base_type_arguments),
542 (ty, ty_structure_arguments),
543 state,
544 information,
545 types,
546 )
547 }
548 }
549 Type::RootPolyType(nature) => {
550 if let PolyNature::Error(_) = nature {
551 return SubTypeResult::IsSubType;
552 }
553
554 let base_arg =
556 base_type_arguments.and_then(|args| args.get_argument_covariant(base_type));
557
558 if let Some(base_arg) = base_arg {
559 match base_arg {
560 CovariantContribution::TypeId(base_arg) => type_is_subtype_with_generics(
561 (base_arg, base_type_arguments),
562 (ty, ty_structure_arguments),
563 state,
564 information,
565 types,
566 ),
567 CovariantContribution::String(left_string) => {
568 if let Type::Constant(Constant::String(right_string)) = subtype {
569 if &left_string == right_string {
570 SubTypeResult::IsSubType
571 } else {
572 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
573 }
574 } else {
575 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
576 }
577 }
578 CovariantContribution::SliceOf(s, (l, r)) => todo!("{:?}", (s, (l, r))),
579 CovariantContribution::CaseInsensitive(ci) => todo!("{:?}", (ci)),
580 CovariantContribution::Number(n) => {
581 unreachable!("{:?}", n)
582 }
593 }
594 } else if let Some(ref mut contributions) = state.contributions {
595 match state.mode {
596 SubTypingMode::Contravariant { depth } => {
597 crate::utilities::notify!(
600 "contributions.parent={:?}",
601 contributions.parent
602 );
603
604 let result = if let Some(under) =
605 contributions.get_standard_restriction(base_type)
606 {
607 type_is_subtype_with_generics(
608 (under, GenericChain::None),
609 (ty, ty_structure_arguments),
610 state,
611 information,
612 types,
613 )
614 } else {
615 type_is_subtype_with_generics(
616 (nature.get_constraint(), GenericChain::None),
617 (ty, ty_structure_arguments),
618 state,
619 information,
620 types,
621 )
622 };
623
624 state
625 .contributions
626 .as_mut()
627 .unwrap()
628 .staging_contravariant
629 .insert(base_type, (ty.into(), depth));
630
631 result
632 }
633 SubTypingMode::Covariant { position } => {
634 state
635 .contributions
636 .as_mut()
637 .unwrap()
638 .staging_covariant
639 .insert(base_type, (ty, position));
640
641 SubTypeResult::IsSubType
643 }
644 }
645 } else {
646 if let Type::Constructor(c) = subtype {
649 crate::utilities::notify!("TODO right hand side maybe okay");
650 if c.get_constraint() == base_type {
651 return SubTypeResult::IsSubType;
652 }
653 }
654 if let PolyNature::FunctionGeneric { .. } = nature {
655 fn check_and_includes(expecting: TypeId, rhs: &Type) -> bool {
657 if let Type::And(left, right) = rhs {
658 *left == expecting || *right == expecting
659 } else {
660 false
661 }
662 }
663
664 return if check_and_includes(base_type, subtype) {
665 SubTypeResult::IsSubType
666 } else {
667 SubTypeResult::IsNotSubType(NonEqualityReason::GenericParameterMismatch)
669 };
670 }
671
672 crate::utilities::notify!(
673 "Subtyping LHS={:?} against RHS, without setting type arguments",
674 nature
675 );
676
677 let constraint = get_constraint(base_type, types).unwrap();
678
679 type_is_subtype_with_generics(
680 (constraint, base_type_arguments),
681 (ty, ty_structure_arguments),
682 state,
683 information,
684 types,
685 )
686 }
687 }
688 Type::Narrowed { narrowed_to, .. } => {
689 crate::utilities::notify!("Narrowed on Left?");
690 type_is_subtype_with_generics(
691 (*narrowed_to, base_type_arguments),
692 (ty, ty_structure_arguments),
693 state,
694 information,
695 types,
696 )
697 }
698 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics { on, arguments }) => {
699 match *on {
700 TypeId::READONLY_RESTRICTION => {
701 crate::utilities::notify!("TODO temp readonly inner check");
702 let inner = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
703 return if let Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
708 on: TypeId::READONLY_RESTRICTION,
709 arguments,
710 }) = subtype
711 {
712 let ty = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
713 type_is_subtype_with_generics(
714 (inner, ty_structure_arguments),
715 (ty, base_type_arguments),
716 state,
717 information,
718 types,
719 )
720 } else if information
721 .get_chain_of_info()
722 .any(|info| info.frozen.contains_key(&ty))
723 || matches!(subtype, Type::Constant(_))
724 || matches!(
725 ty,
726 TypeId::STRING_TYPE | TypeId::BOOLEAN_TYPE | TypeId::NUMBER_TYPE
727 ) {
728 type_is_subtype_with_generics(
729 (inner, ty_structure_arguments),
730 (ty, base_type_arguments),
731 state,
732 information,
733 types,
734 )
735 } else {
736 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
738 };
739 }
740 TypeId::EXCLUSIVE_RESTRICTION => {
741 let inner = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
742 return type_is_subtype_with_generics(
743 (
744 inner,
745 Some(GenericChainLink::SpecialGenericChainLink {
746 parent_link: ty_structure_arguments.as_ref(),
747 special: SpecialGenericChainLink::Exclusive,
748 }),
749 ),
750 (ty, base_type_arguments),
751 state,
752 information,
753 types,
754 );
755 }
756 TypeId::NOT_RESTRICTION => {
757 let inner = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
758 let result = super::disjoint::types_are_disjoint(
761 ty,
762 inner,
763 &mut state.already_checked,
764 information,
765 types,
766 );
767 return if result {
769 SubTypeResult::IsSubType
770 } else {
771 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
772 };
773 }
774 TypeId::STRING_CAPITALIZE
776 | TypeId::STRING_UNCAPITALIZE
777 | TypeId::STRING_LOWERCASE
778 | TypeId::STRING_UPPERCASE => {
779 if let Type::Constant(Constant::String(rs)) = subtype {
780 let contributions =
781 state.contributions.as_mut().map(|n| &mut n.staging_contravariant);
782 let matches = slice_matches_type(
783 (base_type, base_type_arguments),
784 rs,
785 contributions,
786 information,
787 types,
788 false,
789 );
790 return if matches {
791 SubTypeResult::IsSubType
792 } else {
793 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
795 };
796 }
797 }
798 TypeId::LITERAL_RESTRICTION => {
800 let inner = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
801 return if let Type::Constant(_)
802 | Type::Object(ObjectNature::RealDeal)
803 | Type::SpecialObject(..) = subtype
804 {
805 type_is_subtype_with_generics(
806 (inner, base_type_arguments),
807 (ty, ty_structure_arguments),
808 state,
809 information,
810 types,
811 )
812 } else {
813 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
816 };
817 }
818 TypeId::NO_INFER => {
819 let on = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
820 let current_contributing =
821 state.contributions.as_ref().map(|c| c.staging_contravariant.len());
822 let result = type_is_subtype_with_generics(
823 (on, base_type_arguments),
824 (ty, ty_structure_arguments),
825 state,
826 information,
827 types,
828 );
829 if let (Some(contributions), Some(current_contributing)) =
831 (state.contributions.as_mut(), current_contributing)
832 {
833 let _ =
834 contributions.staging_contravariant.drop_range(current_contributing..);
835 }
836 return result;
837 }
838 TypeId::MULTIPLE_OF => {
839 let argument =
840 arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
841
842 let right_multiple = crate::types::intrinsics::get_multiple(ty, types);
843 return if let (
844 Type::Constant(Constant::Number(argument)),
845 Some(Type::Constant(Constant::Number(right_multiple))),
846 ) = (
847 types.get_type_by_id(argument),
848 right_multiple.map(|right_multiple| types.get_type_by_id(right_multiple)),
849 ) {
850 if (right_multiple % argument) == 0. {
851 SubTypeResult::IsSubType
852 } else {
853 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
854 }
855 } else {
856 crate::utilities::notify!("TODO multiple of {:?}", (argument, ty, subtype));
857 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
858 };
859 }
860 TypeId::GREATER_THAN => {
861 let argument =
862 arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
863 let argument_type = types.get_type_by_id(argument);
864 return if let (
865 Type::Constant(Constant::Number(value)),
866 Type::Constant(Constant::Number(subtype_number)),
867 ) = (argument_type, subtype)
868 {
869 if subtype_number > value {
870 SubTypeResult::IsSubType
871 } else {
872 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
873 }
874 } else if let Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
875 on: TypeId::GREATER_THAN,
876 arguments,
877 }) = subtype
878 {
879 let subtype_argument =
880 arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
881 if argument == subtype_argument {
883 SubTypeResult::IsSubType
884 } else {
885 let subtype_argument = types.get_type_by_id(subtype_argument);
886 if let (
887 Type::Constant(Constant::Number(subtype_number)),
888 Type::Constant(Constant::Number(value)),
889 ) = (argument_type, subtype_argument)
890 {
891 if subtype_number > value {
892 SubTypeResult::IsSubType
893 } else {
894 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
895 }
896 } else {
897 crate::utilities::notify!("Here");
898 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
899 }
900 }
901 } else {
902 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
903 };
904 }
905 TypeId::LESS_THAN => {
906 let argument =
907 arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
908 let argument_type = types.get_type_by_id(argument);
909 return if let (
910 Type::Constant(Constant::Number(value)),
911 Type::Constant(Constant::Number(subtype_number)),
912 ) = (argument_type, subtype)
913 {
914 if subtype_number < value {
915 SubTypeResult::IsSubType
916 } else {
917 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
918 }
919 } else if let Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
920 on: TypeId::GREATER_THAN,
921 arguments,
922 }) = subtype
923 {
924 let subtype_argument =
925 arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
926 if argument == subtype_argument {
928 SubTypeResult::IsSubType
929 } else {
930 let subtype_argument = types.get_type_by_id(subtype_argument);
931 if let (
932 Type::Constant(Constant::Number(subtype_number)),
933 Type::Constant(Constant::Number(value)),
934 ) = (argument_type, subtype_argument)
935 {
936 if subtype_number < value {
937 SubTypeResult::IsSubType
938 } else {
939 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
940 }
941 } else {
942 crate::utilities::notify!("Here");
943 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
944 }
945 }
946 } else {
947 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
948 };
949 }
950 TypeId::CASE_INSENSITIVE => {
951 if let Type::Constant(Constant::String(rs)) = subtype {
952 let contributions =
953 state.contributions.as_mut().map(|n| &mut n.staging_contravariant);
954 let matches = slice_matches_type(
956 (base_type, base_type_arguments),
957 rs,
958 contributions,
959 information,
960 types,
961 false,
962 );
963
964 return if matches {
965 SubTypeResult::IsSubType
966 } else {
967 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
969 };
970 }
971 }
972 _ => {}
973 }
974
975 if let Some(lookup) = types.lookup_generic_map.get(on) {
976 fn get_structure_generics_on(
977 r#type: &Type,
978 expected: TypeId,
979 ) -> Option<&GenericArguments> {
980 match r#type {
981 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
982 on,
983 arguments,
984 }) if expected == *on => Some(arguments),
985 _ => None,
986 }
987 }
988
989 if let Some(ref mut object_constraints) = state.object_constraints {
990 object_constraints.push((ty, base_type));
991 }
992 return if let Some(sgs) = get_structure_generics_on(subtype, *on) {
995 match (arguments, sgs) {
996 (
997 GenericArguments::ExplicitRestrictions(left),
998 GenericArguments::ExplicitRestrictions(right),
999 ) => {
1000 for (lk, (lv, _)) in left.iter() {
1001 let (rv, _) = right.get(lk).unwrap();
1002 let argument_is_subtype = type_is_subtype_with_generics(
1003 (*lv, base_type_arguments),
1004 (*rv, ty_structure_arguments),
1005 state,
1006 information,
1007 types,
1008 );
1009 if let err @ SubTypeResult::IsNotSubType(_) = argument_is_subtype {
1010 return err;
1011 }
1012 }
1013 SubTypeResult::IsSubType
1014 }
1015 pair => todo!("{:?}", pair),
1016 }
1017 } else if let Type::Object(super::ObjectNature::RealDeal) = subtype {
1018 let prototype =
1019 information.get_chain_of_info().find_map(|info| info.prototypes.get(&ty));
1020
1021 crate::utilities::notify!("prototype is {:?}", prototype);
1022
1023 if prototype.is_some_and(|prototype| prototype == on) {
1024 for (argument, lookup) in lookup.iter() {
1025 let backing_type =
1027 arguments.get_structure_restriction(*argument).unwrap();
1028 for value in lookup.calculate_lookup(information, types, ty) {
1029 let type_is_subtype =
1030 type_is_subtype(backing_type, value, state, information, types);
1031 if let e @ SubTypeResult::IsNotSubType(_) = type_is_subtype {
1032 return e;
1033 }
1034 }
1035 }
1036 SubTypeResult::IsSubType
1037 } else {
1038 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1039 }
1040 } else {
1041 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1042 };
1043 }
1044
1045 if let TypeId::ARRAY_TYPE = *on {
1046 let backing_type = arguments
1047 .get_structure_restriction(TypeId::T_TYPE)
1048 .expect("array T argument not set ?");
1049
1050 crate::utilities::notify!(
1051 "Array type is {}",
1052 print_type(backing_type, types, information, false)
1053 );
1054
1055 if let Type::Object(_) = subtype {
1057 if let Some(ref mut object_constraints) = state.object_constraints {
1070 object_constraints.push((ty, base_type));
1071 }
1072
1073 SubTypeResult::IsSubType
1074 } else if let Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
1075 on: TypeId::ARRAY_TYPE,
1076 arguments: right_arguments,
1077 }) = subtype
1078 {
1079 let left_arg = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
1080 let right_arg =
1081 right_arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
1082
1083 crate::utilities::notify!("{:?} :> {:?}", left_arg, right_arg);
1084
1085 type_is_subtype_with_generics(
1087 (left_arg, base_type_arguments),
1088 (right_arg, ty_structure_arguments),
1089 state,
1090 information,
1091 types,
1092 )
1093 } else {
1094 crate::utilities::notify!("Not array-ish {:?}", subtype);
1095 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1096 }
1097 } else {
1098 fn is_arguments_cyclic(a: &GenericArguments) -> bool {
1099 if let GenericArguments::ExplicitRestrictions(arguments) = a {
1100 arguments.iter().any(|(left, (right, _))| left == right)
1101 } else {
1102 false
1103 }
1104 }
1105 if is_arguments_cyclic(arguments) {
1107 let GenericArguments::ExplicitRestrictions(arguments) = arguments else {
1108 unreachable!();
1109 };
1110
1111 let filtered: crate::Map<_, _> = arguments
1112 .iter()
1113 .filter(|(left, (right, _))| left != right)
1114 .copied()
1115 .collect();
1116 let refe = GenericArguments::ExplicitRestrictions(filtered);
1117 let base_type_arguments =
1118 GenericChainLink::append(base_type, base_type_arguments.as_ref(), &refe);
1119
1120 type_is_subtype_with_generics(
1121 (*on, base_type_arguments),
1122 (ty, ty_structure_arguments),
1123 state,
1124 information,
1125 types,
1126 )
1127 } else {
1128 let base_type_arguments = GenericChainLink::append(
1129 base_type,
1130 base_type_arguments.as_ref(),
1131 arguments,
1132 );
1133
1134 type_is_subtype_with_generics(
1135 (*on, base_type_arguments),
1136 (ty, ty_structure_arguments),
1137 state,
1138 information,
1139 types,
1140 )
1141 }
1142 }
1143 }
1144 Type::Constructor(cst) => match cst {
1145 Constructor::BinaryOperator {
1147 operator: crate::types::MathematicalOrBitwiseOperation::Add,
1148 result: TypeId::STRING_TYPE,
1149 ..
1150 } => {
1151 if let Type::Constant(Constant::String(rs)) = subtype {
1152 let matches = slice_matches_type(
1153 (base_type, base_type_arguments),
1154 rs,
1155 state.contributions.as_mut().map(|n| &mut n.staging_contravariant),
1156 information,
1157 types,
1158 false,
1159 );
1160 if matches {
1161 SubTypeResult::IsSubType
1162 } else {
1163 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1165 }
1166 } else if let Type::Constructor(Constructor::BinaryOperator {
1167 operator: crate::types::MathematicalOrBitwiseOperation::Add,
1168 result: TypeId::STRING_TYPE,
1169 ..
1170 }) = subtype
1171 {
1172 crate::utilities::notify!("TODO test prefixes");
1173 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1174 } else {
1175 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1176 }
1177 }
1178 Constructor::BinaryOperator {
1179 operator: crate::types::MathematicalOrBitwiseOperation::Add,
1180 result: TypeId::NUMBER_TYPE,
1181 ..
1182 } => {
1183 crate::utilities::notify!("TODO here!");
1184 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1185 }
1186 Constructor::BinaryOperator { .. } | Constructor::CanonicalRelationOperator { .. } => {
1187 unreachable!("invalid constructor on LHS")
1188 }
1189 Constructor::TypeOperator(_) => todo!(),
1190 Constructor::TypeExtends(_) => todo!(),
1191 Constructor::Image { on: _, with: _, result } => {
1192 crate::utilities::notify!("Here");
1193 type_is_subtype_with_generics(
1194 (*result, base_type_arguments),
1195 (ty, ty_structure_arguments),
1196 state,
1197 information,
1198 types,
1199 )
1200 }
1201 Constructor::ConditionalResult {
1202 condition,
1203 truthy_result: _,
1204 otherwise_result,
1205 result_union: result,
1206 } => {
1207 if let (
1209 Type::Constructor(Constructor::TypeExtends(extends)),
1210 TypeId::NEVER_TYPE,
1211 Type::Constructor(Constructor::ConditionalResult {
1212 condition: rhs_condition,
1213 truthy_result: _,
1214 otherwise_result: TypeId::NEVER_TYPE,
1215 result_union: _,
1216 }),
1217 ) = (types.get_type_by_id(*condition), *otherwise_result, subtype)
1218 {
1219 if extends.equal_to_rhs(*rhs_condition, types) {
1220 SubTypeResult::IsSubType
1221 } else {
1222 crate::utilities::notify!(
1223 "Here {:?}",
1224 types.get_type_by_id(*rhs_condition)
1225 );
1226 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1227 }
1228 } else {
1229 crate::utilities::notify!("Here {:?}", subtype);
1230
1231 type_is_subtype_with_generics(
1232 (*result, base_type_arguments),
1233 (ty, ty_structure_arguments),
1234 state,
1235 information,
1236 types,
1237 )
1238 }
1239 }
1240 Constructor::Property { on, under, result: _, mode: _ } => {
1241 if let Type::Constructor(Constructor::Property {
1244 on: r_on,
1245 under: r_under,
1246 result: _,
1247 mode: _,
1248 }) = subtype
1249 {
1250 if on == r_on && under == r_under {
1251 return SubTypeResult::IsSubType;
1252 }
1253 }
1254
1255 if let Some(on) = base_type_arguments.and_then(|args| args.get_single_argument(*on))
1264 {
1265 let new_under;
1266 let under = if let PropertyKey::Type(original) = under {
1267 crate::utilities::notify!(
1269 "original={:?}, bta={:?}",
1270 original,
1271 base_type_arguments
1272 );
1273 let original = *original;
1283 new_under = if let Some(under) = base_type_arguments
1284 .and_then(|args| args.get_argument_covariant(original))
1285 {
1286 under.into_property_key()
1287 } else {
1288 crate::utilities::notify!(
1289 "Could not find key type {:?} {:?}",
1290 original,
1291 base_type_arguments
1292 );
1293 PropertyKey::from_type(original, types)
1294 };
1295 &new_under
1296 } else {
1297 under
1298 };
1299
1300 crate::utilities::notify!(
1301 "Here got under={:?}, on={:?}",
1302 under,
1303 types.get_type_by_id(on)
1304 );
1305 let property = get_property_unbound(
1306 (on, base_type_arguments),
1307 (Publicity::Public, under, ty_structure_arguments),
1308 false,
1309 information,
1310 types,
1311 );
1312 if let Ok(LogicalOrValid::Logical(property)) = property {
1313 crate::utilities::notify!("Here 3");
1314 match property {
1315 Logical::Pure(property) => {
1316 crate::utilities::notify!("Here 4 {:?}", property);
1317 let property_value = property.as_get_type(types);
1318 return type_is_subtype_with_generics(
1319 (property_value, base_type_arguments),
1320 (ty, ty_structure_arguments),
1321 state,
1322 information,
1323 types,
1324 );
1325 }
1326 Logical::BasedOnKey(BasedOnKey::Right(PropertyOn { on, key })) => {
1327 crate::utilities::notify!("TODO {:?}", (on, key));
1328 }
1354 value => {
1355 crate::utilities::notify!("TODO not checking with {:?}", value);
1356 } }
1360 }
1361 } else {
1362 crate::utilities::notify!(
1363 "Could not find argument for {:?}",
1364 (on, base_type_arguments)
1365 );
1366 }
1367 crate::utilities::notify!("Here *on={:?}", types.get_type_by_id(*on));
1397 crate::utilities::notify!("Mismatched property");
1398
1399 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1400 }
1401 Constructor::Awaited { .. } => todo!(),
1402 Constructor::KeyOf(on) => {
1403 if let Type::Constant(crate::Constant::String(s)) = subtype {
1404 let get_property_unbound = get_property_unbound(
1405 (*on, base_type_arguments),
1406 (
1407 Publicity::Public,
1408 &PropertyKey::String(std::borrow::Cow::Borrowed(s)),
1409 ty_structure_arguments,
1410 ),
1411 false,
1412 information,
1413 types,
1414 );
1415 if get_property_unbound.is_ok() {
1416 SubTypeResult::IsSubType
1417 } else {
1418 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1419 }
1420 } else {
1421 crate::utilities::notify!("TODO keyof stuff");
1422 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1423 }
1424 }
1425 },
1426 Type::AliasTo { to, parameters, name: _ } => {
1427 let base_structure_arguments = if let Some(parameters) = parameters {
1428 crate::utilities::notify!("Skipping looking at parameters {:?}", parameters);
1429 base_type_arguments
1430 } else {
1431 base_type_arguments
1432 };
1433
1434 type_is_subtype_with_generics(
1435 (*to, base_structure_arguments),
1436 (ty, ty_structure_arguments),
1437 state,
1438 information,
1439 types,
1440 )
1441 }
1442 Type::Class { .. } => match subtype {
1444 Type::Constant(constant) => {
1445 if constant.get_backing_type() == base_type {
1446 SubTypeResult::IsSubType
1447 } else {
1448 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1449 }
1450 }
1451 Type::Object(..) => {
1452 if let Some(prototype) =
1454 information.get_chain_of_info().find_map(|info| info.prototypes.get(&ty))
1455 {
1456 if *prototype == base_type {
1457 SubTypeResult::IsSubType
1458 } else {
1459 crate::utilities::notify!(
1460 "Mismatched prototype {:?} != {:?}",
1461 prototype,
1462 base_type
1463 );
1464 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1465 }
1466 } else {
1467 crate::utilities::notify!("No prototype");
1468 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1469 }
1470 }
1471 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics { on, arguments }) => {
1472 let into = arguments.clone();
1473 let right =
1474 (*on, GenericChainLink::append(ty, ty_structure_arguments.as_ref(), &into));
1475 type_is_subtype_with_generics(
1476 (base_type, base_type_arguments),
1477 right,
1478 state,
1479 information,
1480 types,
1481 )
1482 }
1483 Type::And(left, right) => {
1484 let left_result = type_is_subtype_with_generics(
1486 (base_type, base_type_arguments),
1487 (*left, ty_structure_arguments),
1488 state,
1489 information,
1490 types,
1491 );
1492
1493 if let SubTypeResult::IsSubType = left_result {
1494 left_result
1495 } else {
1496 type_is_subtype_with_generics(
1497 (base_type, base_type_arguments),
1498 (*right, ty_structure_arguments),
1499 state,
1500 information,
1501 types,
1502 )
1503 }
1504 }
1505 Type::SpecialObject(SpecialObject::Function(..)) | Type::FunctionReference(..)
1506 if base_type == TypeId::FUNCTION_TYPE =>
1507 {
1508 SubTypeResult::IsSubType
1509 }
1510 _ty => {
1511 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1513 }
1514 },
1515 Type::Interface { .. } => {
1516 if matches!(base_type, TypeId::UNDEFINED_TYPE | TypeId::NULL_TYPE | TypeId::NEVER_TYPE)
1519 {
1520 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
1521 }
1522
1523 match subtype {
1525 Type::Constant(constant) => {
1526 if constant.get_backing_type() == base_type {
1527 SubTypeResult::IsSubType
1528 } else {
1529 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1530 }
1531 }
1532 Type::Object(..) => subtype_floating_properties(
1533 (base_type, base_type_arguments),
1534 (ty, ty_structure_arguments),
1535 state,
1536 information,
1537 types,
1538 ),
1539 Type::SpecialObject(SpecialObject::Function(..)) => {
1540 crate::utilities::notify!("TODO implement function checking");
1541 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1542 }
1543 Type::And(a, b) => {
1544 crate::utilities::notify!("Here LHS interface, RHS and");
1546 if *a == base_type || *b == base_type {
1547 SubTypeResult::IsSubType
1548 } else {
1549 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1550 }
1551 }
1552 Type::Or(_left, _right) => {
1553 unreachable!()
1554 }
1555 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics { on, arguments }) => {
1556 let into = arguments.clone();
1557 let append =
1558 GenericChainLink::append(ty, ty_structure_arguments.as_ref(), &into);
1559 type_is_subtype_with_generics(
1560 (base_type, base_type_arguments),
1561 (*on, append),
1562 state,
1563 information,
1564 types,
1565 )
1566 }
1567 Type::FunctionReference(_)
1568 | Type::SpecialObject(_)
1569 | Type::Class { .. }
1570 | Type::AliasTo { .. }
1571 | Type::Interface { .. } => {
1572 crate::utilities::notify!("supertype={:?}, subtype={:?}", supertype, subtype);
1573 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1575 }
1576 Type::Narrowed { .. } | Type::Constructor(..) | Type::RootPolyType(..) => {
1577 let arg =
1578 base_type_arguments.and_then(|args| args.get_argument_covariant(base_type));
1579
1580 crate::utilities::notify!("TODO {:?}", arg);
1581 SubTypeResult::IsSubType
1582
1583 }
1614 }
1615 }
1616 Type::SpecialObject(SpecialObject::Null) => {
1617 crate::utilities::notify!("rhs={:?}", subtype);
1618 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
1619 }
1620 Type::SpecialObject(_) => todo!(),
1621 }
1622}
1623
1624fn subtype_function(
1625 (left_func, base_type_arguments): (crate::FunctionId, GenericChain),
1626 (subtype, ty, subtypepe_arguments): (&Type, TypeId, GenericChain),
1627 state: &mut State,
1628 information: &impl InformationChain,
1629 types: &TypeStore,
1630) -> SubTypeResult {
1631 let right_func = if let Type::FunctionReference(right_func)
1632 | Type::SpecialObject(SpecialObject::Function(right_func, _)) = subtype
1633 {
1634 right_func
1635 } else if let Some(constraint) = get_constraint(ty, types) {
1636 let subtype = types.get_type_by_id(constraint);
1638 if let Type::FunctionReference(right_func)
1639 | Type::SpecialObject(SpecialObject::Function(right_func, _)) = subtype
1640 {
1641 right_func
1642 } else {
1643 crate::utilities::notify!("Not function after constraint!! {:?}", subtype);
1644 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
1645 }
1646 } else {
1647 crate::utilities::notify!("Not function!! {:?}", subtype);
1648 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
1649 };
1650
1651 let left_func = types.functions.get(&left_func).unwrap();
1652 let right_func = types.functions.get(right_func).unwrap();
1653
1654 for (idx, lhs_param) in left_func.parameters.parameters.iter().enumerate() {
1655 if let Some((right_param_ty, position)) =
1656 right_func.parameters.get_parameter_type_at_index(idx)
1657 {
1658 let last_mode =
1659 std::mem::replace(&mut state.mode, SubTypingMode::Covariant { position });
1660
1661 let result = type_is_subtype_with_generics(
1663 (right_param_ty, subtypepe_arguments),
1664 (lhs_param.ty, base_type_arguments),
1665 state,
1666 information,
1667 types,
1668 );
1669
1670 if let err @ SubTypeResult::IsNotSubType(_) = result {
1671 let lhs = print_type(right_param_ty, types, information, true);
1672 let rhs = print_type(lhs_param.ty, types, information, true);
1673 crate::utilities::notify!(
1674 "Parameter invalid rhs ({:?} {:?}) <- lhs ({:?} {:?})",
1675 rhs,
1676 subtypepe_arguments,
1677 lhs,
1678 base_type_arguments
1679 );
1680 return err;
1682 }
1683
1684 state.mode = last_mode;
1685 } else {
1686 }
1692 }
1693
1694 if TypeId::VOID_TYPE == left_func.return_type {
1698 SubTypeResult::IsSubType
1699 } else {
1700 let type_is_subtype_with_generics = type_is_subtype_with_generics(
1701 (left_func.return_type, base_type_arguments),
1702 (right_func.return_type, subtypepe_arguments),
1703 state,
1704 information,
1705 types,
1706 );
1707
1708 if type_is_subtype_with_generics.is_mismatch() {
1709 crate::utilities::notify!("return type invalid");
1710 }
1711
1712 type_is_subtype_with_generics
1713 }
1714}
1715
1716fn subtype_floating_properties(
1717 (base_type, base_type_arguments): (TypeId, GenericChain),
1718 (ty, subtypepe_arguments): (TypeId, GenericChain),
1719 state: &mut State,
1720 information: &impl InformationChain,
1721 types: &TypeStore,
1722) -> SubTypeResult {
1723 let reversed_flattened_properties_on_base = information
1724 .get_chain_of_info()
1725 .filter_map(|info| info.current_properties.get(&base_type).map(|v| v.iter().rev()))
1726 .flatten();
1727
1728 subtype_properties(
1729 (base_type, reversed_flattened_properties_on_base, base_type_arguments),
1730 (ty, subtypepe_arguments),
1731 state,
1732 information,
1733 types,
1734 )
1735}
1736
1737fn subtype_properties<'a, T>(
1738 (base_type, base_properties, base_type_arguments): (TypeId, T, GenericChain),
1739 (ty, subtypepe_arguments): (TypeId, GenericChain),
1740 state: &mut State,
1741 information: &impl InformationChain,
1742 types: &TypeStore,
1743) -> SubTypeResult
1744where
1745 T: Iterator<Item = &'a (Publicity, PropertyKey<'static>, PropertyValue)> + 'a,
1746{
1747 state.mode = state.mode.one_deeper();
1749 let mut property_errors = Vec::new();
1750
1751 for (publicity, key, lhs_property) in base_properties {
1753 let holding_key;
1759 let key = match key {
1760 PropertyKey::Type(key_ty) => {
1761 if let Some(base_type_arguments) = base_type_arguments {
1762 let key_ty =
1763 base_type_arguments.get_single_argument(*key_ty).unwrap_or(*key_ty);
1764 holding_key = PropertyKey::from_type(key_ty, types);
1765 &holding_key
1766 } else {
1767 key
1768 }
1769 }
1770 PropertyKey::String(_) => key,
1771 };
1772
1773 let result = check_lhs_property_is_super_type_of_rhs(
1774 (*publicity, key),
1775 (lhs_property, base_type_arguments, false),
1776 (ty, subtypepe_arguments),
1777 state,
1778 information,
1779 types,
1780 );
1781
1782 if let Err(err) = result {
1783 property_errors.push((key.into_owned(), err));
1784 }
1785 }
1786
1787 state.mode = state.mode.one_shallower();
1788
1789 if property_errors.is_empty() {
1790 if let Type::Interface { extends: Some(extends), .. } = types.get_type_by_id(base_type) {
1791 let extends_result = type_is_subtype_with_generics(
1792 (*extends, base_type_arguments),
1793 (ty, subtypepe_arguments),
1794 state,
1795 information,
1796 types,
1797 );
1798 if let e @ SubTypeResult::IsNotSubType(_) = extends_result {
1799 return e;
1800 }
1801 }
1802
1803 if base_type_arguments.is_some_and(|base| base.exclusive_mode()) {
1805 use crate::types::properties;
1806
1807 let get_properties = properties::get_properties_on_single_type(
1808 ty,
1809 types,
1810 information,
1811 false,
1812 TypeId::ANY_TYPE,
1813 );
1814
1815 for (publicity, key, _value) in get_properties {
1817 let result = properties::get_property_unbound(
1818 (base_type, base_type_arguments),
1819 (publicity, &key, None),
1820 true,
1821 information,
1822 types,
1823 );
1824
1825 if result.is_err() {
1827 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
1829 }
1830 }
1831 }
1832
1833 if let Some(ref mut object_constraints) = state.object_constraints {
1835 let base_type = if let Some(GenericChainLink::PartiallyAppliedGenericArgumentsLink {
1836 ref from,
1837 parent_link,
1838 value: _,
1839 }) = base_type_arguments
1840 {
1841 if parent_link.is_some() {
1842 crate::utilities::notify!("TODO recursive get_from");
1843 }
1844 *from
1845 } else {
1846 base_type
1847 };
1848 object_constraints.push((ty, base_type));
1849 }
1850
1851 SubTypeResult::IsSubType
1852 } else {
1853 SubTypeResult::IsNotSubType(NonEqualityReason::PropertiesInvalid {
1854 errors: property_errors,
1855 })
1856 }
1857}
1858
1859fn check_lhs_property_is_super_type_of_rhs(
1860 (publicity, key): (Publicity, &PropertyKey<'_>),
1861 (lhs_property, base_type_arguments, optional): (&PropertyValue, GenericChain, bool),
1862 (ty, subtypepe_arguments): (TypeId, GenericChain),
1863 state: &mut State,
1864 information: &impl InformationChain,
1865 types: &TypeStore,
1866) -> Result<(), PropertyError> {
1867 match lhs_property {
1868 PropertyValue::Value(lhs_value) => {
1869 let right_result = get_property_unbound(
1870 (ty, subtypepe_arguments),
1871 (publicity, key, base_type_arguments),
1872 false,
1873 information,
1874 types,
1875 );
1876
1877 match right_result {
1887 Ok(LogicalOrValid::Logical(res)) => {
1888 let res = check_logical_property(
1889 (*lhs_value, base_type_arguments, optional),
1890 (res, subtypepe_arguments),
1891 state,
1892 information,
1893 types,
1894 );
1895 match res {
1896 SubTypeResult::IsSubType => Ok(()),
1897 SubTypeResult::IsNotSubType(err) => Err(PropertyError::Invalid {
1898 expected: *lhs_value,
1899 found: TypeId::UNIMPLEMENTED_ERROR_TYPE,
1901 mismatch: err,
1902 }),
1903 }
1904 }
1905 Ok(LogicalOrValid::NeedsCalculation(NeedsCalculation::Proxy(
1907 objects::Proxy { handler, over },
1908 _,
1909 ))) => {
1910 crate::utilities::notify!("TODO set as well?");
1911 let get_handler = get_property_unbound(
1912 (handler, subtypepe_arguments),
1913 (
1914 Publicity::Public,
1915 &PropertyKey::String(std::borrow::Cow::Borrowed("get")),
1916 base_type_arguments,
1917 ),
1918 false,
1919 information,
1920 types,
1921 );
1922
1923 if let Ok(LogicalOrValid::Logical(Logical::Pure(get_res))) = get_handler {
1924 let function = get_res.as_get_type(types);
1925 if let Type::SpecialObject(SpecialObject::Function(id, _)) =
1926 types.get_type_by_id(function)
1927 {
1928 let function = types.get_function_from_id(*id);
1929 let mut map = crate::Map::new();
1930 if let Some((first, _)) =
1932 function.parameters.get_parameter_type_at_index(0)
1933 {
1934 map.insert(first, (CovariantContribution::TypeId(over), 0));
1935 }
1936 if let Some((second, _)) =
1937 function.parameters.get_parameter_type_at_index(1)
1938 {
1939 map.insert(
1940 second,
1941 (CovariantContribution::from(key.clone().into_owned()), 0),
1942 );
1943 }
1944 if let Some((third, _)) =
1945 function.parameters.get_parameter_type_at_index(2)
1946 {
1947 map.insert(third, (CovariantContribution::TypeId(handler), 0));
1948 }
1949
1950 let subtypepe_arguments = Some(GenericChainLink::MappedPropertyLink {
1951 parent_link: subtypepe_arguments.as_ref(),
1952 value: &map,
1953 });
1954
1955 let result = type_is_subtype_with_generics(
1956 (*lhs_value, base_type_arguments),
1957 (function.return_type, subtypepe_arguments),
1958 state,
1959 information,
1960 types,
1961 );
1962 if let SubTypeResult::IsSubType = result {
1963 Ok(())
1964 } else {
1965 Err(PropertyError::Missing)
1967 }
1968 } else {
1969 crate::utilities::notify!("{:?}", get_res);
1970
1971 check_lhs_property_is_super_type_of_rhs(
1972 (publicity, key),
1973 (lhs_property, base_type_arguments, optional),
1974 (handler, subtypepe_arguments),
1975 state,
1976 information,
1977 types,
1978 )
1979 }
1980 } else {
1981 check_lhs_property_is_super_type_of_rhs(
1982 (publicity, key),
1983 (lhs_property, base_type_arguments, optional),
1984 (handler, subtypepe_arguments),
1985 state,
1986 information,
1987 types,
1988 )
1989 }
1990 }
1991 Ok(LogicalOrValid::NeedsCalculation(NeedsCalculation::Infer { .. })) => {
1992 crate::utilities::notify!("TODO add constraint candidate");
1993 Ok(())
1994 }
1995 Err(_) => {
1996 if optional {
1997 Ok(())
1998 } else {
1999 Err(PropertyError::Missing)
2001 }
2002 }
2003 }
2004 }
2005 PropertyValue::GetterAndSetter { getter, setter } => {
2006 todo!("{:?}", (getter, setter));
2007 }
2008 PropertyValue::Getter(_getter) => {
2009 let res =
2010 get_property_unbound((ty, None), (publicity, key, None), true, information, types);
2011 crate::utilities::notify!("looking for {:?} found {:?}", key, res);
2012
2013 match res {
2014 Ok(LogicalOrValid::Logical(_res)) => {
2015 todo!("get get return type")
2016 }
2017 res => {
2019 crate::utilities::notify!("res={:?}", res);
2020 Err(PropertyError::Missing)
2021 }
2022 }
2023 }
2024 PropertyValue::Setter(_) => {
2025 let rhs =
2026 get_property_unbound((ty, None), (publicity, key, None), true, information, types);
2027
2028 match rhs {
2029 Ok(ok) => {
2030 crate::utilities::notify!("Set vs {:?}", ok);
2031 Ok(())
2032 }
2033 Err(_err) => Err(PropertyError::Missing),
2034 }
2035 }
2036 PropertyValue::Deleted => {
2037 let res =
2039 get_property_unbound((ty, None), (publicity, key, None), true, information, types);
2040 if res.is_ok() {
2041 Err(PropertyError::Missing)
2043 } else {
2044 Ok(())
2046 }
2047 }
2048 PropertyValue::ConditionallyExists { condition, truthy } => {
2049 crate::utilities::notify!("Here {:?}", (key, ty, condition, truthy));
2050
2051 let is_optional =
2053 !matches!(*condition, TypeId::TRUE | TypeId::NON_OPTIONAL_KEY_ARGUMENT);
2054
2055 check_lhs_property_is_super_type_of_rhs(
2056 (publicity, key),
2057 (truthy, base_type_arguments, is_optional),
2058 (ty, subtypepe_arguments),
2059 state,
2060 information,
2061 types,
2062 )
2063 }
2110 PropertyValue::Configured { on, .. } => {
2111 crate::utilities::notify!("TODO check readonly");
2112 check_lhs_property_is_super_type_of_rhs(
2113 (publicity, key),
2114 (on, base_type_arguments, optional),
2115 (ty, subtypepe_arguments),
2116 state,
2117 information,
2118 types,
2119 )
2120 }
2121 }
2122}
2123
2124fn check_logical_property(
2125 (lhs_property_value, lhs_property_value_type_arguments, optional): (TypeId, GenericChain, bool),
2126 (rhs_property, subtypepe_arguments): (Logical<PropertyValue>, GenericChain),
2127 state: &mut State,
2128 information: &impl InformationChain,
2129 types: &TypeStore,
2130) -> SubTypeResult {
2131 match rhs_property {
2132 Logical::Pure(rhs_property) => {
2133 let rhs_type = rhs_property.as_get_type(types);
2134 type_is_subtype_with_generics(
2143 (lhs_property_value, lhs_property_value_type_arguments),
2144 (rhs_type, subtypepe_arguments),
2145 state,
2146 information,
2147 types,
2148 )
2149 }
2150 Logical::Or { condition, left, right } => {
2151 crate::utilities::notify!("{:?}", (condition, &left, &right));
2152
2153 if let (LogicalOrValid::Logical(left), LogicalOrValid::Logical(right)) = (*left, *right)
2154 {
2155 let left_result = check_logical_property(
2156 (lhs_property_value, lhs_property_value_type_arguments, optional),
2157 (left, subtypepe_arguments),
2158 state,
2159 information,
2160 types,
2161 );
2162
2163 if let SubTypeResult::IsSubType = left_result {
2164 check_logical_property(
2165 (lhs_property_value, lhs_property_value_type_arguments, optional),
2166 (right, subtypepe_arguments),
2167 state,
2168 information,
2169 types,
2170 )
2171 } else {
2172 left_result
2174 }
2175 } else if optional {
2176 SubTypeResult::IsSubType
2177 } else {
2178 crate::utilities::notify!("One missing");
2179 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
2180 }
2181 }
2182 Logical::Implies { on, antecedent } => {
2183 crate::utilities::notify!("{:?}", antecedent);
2184 check_logical_property(
2185 (lhs_property_value, lhs_property_value_type_arguments, optional),
2186 (
2187 *on,
2188 GenericChainLink::append(
2189 TypeId::UNIMPLEMENTED_ERROR_TYPE,
2190 subtypepe_arguments.as_ref(),
2191 &antecedent,
2192 ),
2193 ),
2194 state,
2195 information,
2196 types,
2197 )
2198 }
2199 Logical::BasedOnKey(kind) => match kind {
2200 BasedOnKey::Left { value, key_arguments } => {
2201 let property_generics = Some(GenericChainLink::MappedPropertyLink {
2202 parent_link: subtypepe_arguments.as_ref(),
2203 value: &key_arguments,
2204 });
2205 check_logical_property(
2206 (lhs_property_value, lhs_property_value_type_arguments, optional),
2207 (*value, property_generics),
2208 state,
2209 information,
2210 types,
2211 )
2212 }
2213 BasedOnKey::Right(PropertyOn { on, key }) => {
2214 if let Type::RootPolyType(PolyNature::MappedGeneric { name: _, extends }) =
2215 types.get_type_by_id(key)
2216 {
2217 type_is_subtype_of_property_mapped_key(
2218 MappedKey { value: (*extends).into(), key },
2219 (lhs_property_value, lhs_property_value_type_arguments, optional),
2220 (on, subtypepe_arguments),
2221 state,
2222 information,
2223 types,
2224 )
2225 } else {
2226 let filter = get_constraint(key, types).unwrap_or(key);
2227
2228 let properties = get_properties_on_single_type2(
2229 (on, subtypepe_arguments),
2230 types,
2231 information,
2232 filter,
2233 );
2234 for (_key, rhs_property, _args) in properties {
2235 let result = check_logical_property(
2236 (lhs_property_value, lhs_property_value_type_arguments, optional),
2237 (Logical::Pure(rhs_property), subtypepe_arguments),
2238 state,
2239 information,
2240 types,
2241 );
2242 if result.is_mismatch() {
2243 return result;
2244 }
2245 }
2246 SubTypeResult::IsSubType
2247 }
2248 }
2249 },
2250 }
2251}
2252
2253pub struct MappedKey {
2254 pub value: CovariantContribution,
2256 pub key: TypeId,
2258}
2259
2260pub fn type_is_subtype_of_property_mapped_key(
2261 mapped_key: MappedKey,
2262 (base, property_generics, optional): (TypeId, GenericChain, bool),
2263 (ty, subtypepe_arguments): (TypeId, GenericChain),
2264 state: &mut State,
2265 information: &impl InformationChain,
2266 types: &TypeStore,
2267) -> SubTypeResult {
2268 match mapped_key.value {
2270 CovariantContribution::String(ref s) => {
2271 {
2272 crate::utilities::notify!(
2273 "Reading {:?}, with {:?} {:?}",
2274 types.get_type_by_id(ty),
2275 s,
2276 (property_generics.as_ref(), subtypepe_arguments.as_ref())
2277 );
2278 }
2279 let right_property = get_property_unbound(
2280 (ty, subtypepe_arguments),
2281 (
2282 Publicity::Public,
2283 &PropertyKey::String(std::borrow::Cow::Owned(s.to_owned())),
2284 None,
2285 ),
2286 false,
2287 information,
2288 types,
2289 );
2290
2291 match right_property {
2292 Ok(LogicalOrValid::Logical(right_property)) => {
2293 let map = crate::Map::from_iter([(mapped_key.key, (mapped_key.value, 0))]);
2294 let property_generics = Some(GenericChainLink::MappedPropertyLink {
2295 parent_link: property_generics.as_ref(),
2296 value: &map,
2297 });
2298 let result = check_logical_property(
2299 (base, property_generics, optional),
2300 (right_property, subtypepe_arguments),
2301 state,
2302 information,
2303 types,
2304 );
2305
2306 crate::utilities::notify!("Got {:?}", result);
2307
2308 result
2309 }
2310 _res => {
2312 crate::utilities::notify!("Missing");
2313 if optional {
2314 SubTypeResult::IsSubType
2315 } else {
2316 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
2317 }
2318 }
2319 }
2320 }
2321 CovariantContribution::TypeId(key_ty) => {
2322 match types.get_type_by_id(key_ty) {
2323 Type::Narrowed { narrowed_to: to, .. }
2324 | Type::AliasTo { to, name: _, parameters: _ } => type_is_subtype_of_property_mapped_key(
2325 MappedKey { value: (*to).into(), key: mapped_key.key },
2326 (base, property_generics, optional),
2327 (ty, subtypepe_arguments),
2328 state,
2329 information,
2330 types,
2331 ),
2332 Type::And(left, right) => {
2333 let left = type_is_subtype_of_property_mapped_key(
2334 MappedKey { value: (*left).into(), key: mapped_key.key },
2335 (base, property_generics, optional),
2336 (ty, subtypepe_arguments),
2337 state,
2338 information,
2339 types,
2340 );
2341 if left.is_mismatch() {
2342 type_is_subtype_of_property_mapped_key(
2343 MappedKey { value: (*right).into(), key: mapped_key.key },
2344 (base, property_generics, optional),
2345 (ty, subtypepe_arguments),
2346 state,
2347 information,
2348 types,
2349 )
2350 } else {
2351 left
2352 }
2353 }
2354 Type::Or(left, right) => {
2355 let left = type_is_subtype_of_property_mapped_key(
2356 MappedKey { value: (*left).into(), key: mapped_key.key },
2357 (base, property_generics, optional),
2358 (ty, subtypepe_arguments),
2359 state,
2360 information,
2361 types,
2362 );
2363 if left.is_mismatch() {
2364 left
2365 } else {
2366 type_is_subtype_of_property_mapped_key(
2367 MappedKey { value: (*right).into(), key: mapped_key.key },
2368 (base, property_generics, optional),
2369 (ty, subtypepe_arguments),
2370 state,
2371 information,
2372 types,
2373 )
2374 }
2375 }
2376 Type::RootPolyType(_) => {
2377 if let Some(value) =
2379 property_generics.and_then(|args| args.get_single_argument(key_ty))
2380 {
2381 type_is_subtype_of_property_mapped_key(
2382 MappedKey { value: value.into(), key: mapped_key.key },
2383 (base, property_generics, optional),
2384 (ty, subtypepe_arguments),
2385 state,
2386 information,
2387 types,
2388 )
2389 } else {
2390 todo!("no value {:?}", (ty, property_generics))
2391 }
2392 }
2393 Type::Constructor(Constructor::Property { .. }) => {
2394 todo!()
2395 }
2396 Type::Constructor(Constructor::KeyOf(key_of_ty)) => {
2397 let properties = get_properties_on_single_type2(
2398 (*key_of_ty, property_generics),
2399 types,
2400 information,
2401 TypeId::ANY_TYPE,
2402 );
2403 for (key, _, _) in properties {
2404 let value = match key {
2405 PropertyKey::Type(ty) => CovariantContribution::TypeId(ty),
2406 PropertyKey::String(str) => {
2407 CovariantContribution::String(str.into_owned())
2408 }
2409 };
2410 crate::utilities::notify!("Here {:?}", value);
2411 let result = type_is_subtype_of_property_mapped_key(
2412 MappedKey { value, key: mapped_key.key },
2413 (base, property_generics, optional),
2414 (ty, subtypepe_arguments),
2415 state,
2416 information,
2417 types,
2418 );
2419
2420 if result.is_mismatch() {
2421 return SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch);
2422 }
2423 }
2424 SubTypeResult::IsSubType
2425 }
2426 Type::Constructor(_) => todo!(),
2427 Type::PartiallyAppliedGenerics(_) => todo!(),
2428 Type::Interface { .. } => todo!(),
2429 Type::Class { .. } => todo!(),
2430 Type::Constant(_) => {
2431 let right_property = get_property_unbound(
2432 (ty, subtypepe_arguments),
2433 (Publicity::Public, &PropertyKey::Type(key_ty), subtypepe_arguments),
2434 true,
2435 information,
2436 types,
2437 );
2438
2439 match right_property {
2440 Ok(LogicalOrValid::Logical(right_property)) => {
2441 let map =
2442 crate::Map::from_iter([(mapped_key.key, (mapped_key.value, 0))]);
2443 let property_generics = Some(GenericChainLink::MappedPropertyLink {
2444 parent_link: property_generics.as_ref(),
2445 value: &map,
2446 });
2447 check_logical_property(
2448 (base, property_generics, optional),
2449 (right_property, subtypepe_arguments),
2450 state,
2451 information,
2452 types,
2453 )
2454 }
2455 _res => {
2457 if optional {
2458 SubTypeResult::IsSubType
2459 } else {
2460 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
2461 }
2462 }
2463 }
2464 }
2465 Type::FunctionReference(_) => todo!(),
2466 Type::Object(_) => todo!(),
2467 Type::SpecialObject(_) => todo!(),
2468 }
2469 }
2470 value => todo!("{:?}", value),
2471 }
2472}
2473
2474pub fn type_is_subtype_of_property(
2477 (property, property_generics): (&Logical<PropertyValue>, GenericChain),
2478 ty: TypeId,
2479 state: &mut State,
2480 information: &impl InformationChain,
2481 types: &TypeStore,
2482) -> SubTypeResult {
2483 match property {
2484 Logical::Pure(prop) => type_is_subtype_with_generics(
2485 (prop.as_set_type(types), property_generics),
2486 (ty, GenericChain::None),
2487 state,
2488 information,
2489 types,
2490 ),
2491 Logical::Or { condition: _, left, right } => {
2492 let left_result = if let LogicalOrValid::Logical(left) = &**left {
2493 type_is_subtype_of_property(
2494 (left, property_generics),
2495 ty,
2496 state,
2497 information,
2498 types,
2499 )
2500 } else {
2501 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
2502 };
2503 if let SubTypeResult::IsSubType = left_result {
2504 left_result
2505 } else if let LogicalOrValid::Logical(right) = &**right {
2506 type_is_subtype_of_property(
2507 (right, property_generics),
2508 ty,
2509 state,
2510 information,
2511 types,
2512 )
2513 } else {
2514 SubTypeResult::IsNotSubType(NonEqualityReason::Mismatch)
2515 }
2516 }
2517 Logical::Implies { on, antecedent } => {
2518 let property_generics = GenericChainLink::append(
2519 TypeId::UNIMPLEMENTED_ERROR_TYPE,
2520 property_generics.as_ref(),
2521 antecedent,
2522 );
2523 type_is_subtype_of_property((on, property_generics), ty, state, information, types)
2524 }
2525 Logical::BasedOnKey(on) => {
2526 crate::utilities::notify!("TODO, returning IsSubType {:?}", on);
2544 SubTypeResult::IsSubType
2545 }
2547 }
2548}
2549
2550impl NonEqualityReason {
2551 pub(crate) fn _into_error_message(self, _information: &GeneralContext) -> Vec<String> {
2552 match self {
2553 NonEqualityReason::GenericParameterMismatch
2554 | NonEqualityReason::MissingParameter
2555 | NonEqualityReason::Mismatch => Vec::new(),
2556 NonEqualityReason::PropertiesInvalid { errors } => {
2557 errors.into_iter().map(|error| format!("{error:?}")).collect()
2558 }
2559 NonEqualityReason::TooStrict => todo!(),
2560 NonEqualityReason::Excess => todo!(),
2561 }
2562 }
2563}
2564
2565pub type SliceArguments =
2566 TriMap<TypeId, super::generics::contributions::CovariantContribution, ContributionDepth>;
2567
2568pub(crate) fn slice_matches_type(
2577 (base, base_type_arguments): (TypeId, Option<super::GenericChainLink>),
2578 slice: &str,
2579 mut contributions: Option<&mut SliceArguments>,
2580 information: &impl InformationChain,
2581 types: &TypeStore,
2582 allow_casts: bool,
2583) -> bool {
2584 let base_ty = types.get_type_by_id(base);
2585
2586 if allow_casts {
2597 if base == TypeId::ANY_TYPE {
2598 return true;
2599 } else if base == TypeId::BOOLEAN_TYPE {
2600 return slice == "true" || slice == "false";
2601 } else if base == TypeId::NUMBER_TYPE {
2602 return slice.parse::<usize>().is_ok();
2603 } else if base == TypeId::STRING_TYPE {
2604 return slice.parse::<usize>().is_err();
2607 }
2608 }
2609 match base_ty {
2610 Type::Constant(Constant::String(base_string)) => {
2611 if let Some(transform) = base_type_arguments.and_then(|a| a.get_string_transform()) {
2612 apply_string_intrinsic(transform, base_string).as_str() == slice
2613 } else if base_type_arguments.is_some_and(|a| a.is_case_insensitive()) {
2614 base_string.to_lowercase() == slice.to_lowercase()
2615 } else {
2616 base_string == slice
2617 }
2618 }
2619 Type::RootPolyType(rpt) => {
2620 {
2622 let constraint = rpt.get_constraint();
2623 if let Type::Constructor(Constructor::KeyOf { .. }) =
2624 types.get_type_by_id(constraint)
2625 {
2626 let mut new_contributions = SliceArguments::default();
2627 let _ = slice_matches_type(
2628 (constraint, base_type_arguments),
2629 slice,
2630 Some(&mut new_contributions),
2631 information,
2632 types,
2633 allow_casts,
2634 );
2635 if let Some(ref mut contributions) = contributions {
2636 contributions.extend(new_contributions);
2637 }
2638 }
2639 }
2640
2641 if let Some(argument) = base_type_arguments.and_then(|v| v.get_single_argument(base)) {
2642 slice_matches_type(
2643 (argument, base_type_arguments),
2644 slice,
2645 contributions,
2646 information,
2647 types,
2648 allow_casts,
2649 )
2650 } else if let Some(contributions) = contributions {
2651 let constraint = rpt.get_constraint();
2653 let res = slice_matches_type(
2654 (constraint, base_type_arguments),
2655 slice,
2656 Some(contributions),
2657 information,
2658 types,
2659 allow_casts,
2660 );
2661 if res {
2662 contributions
2663 .insert(base, (CovariantContribution::String(slice.to_owned()), 0));
2664 }
2665 res
2666 } else {
2667 false
2668 }
2669 }
2670 Type::Narrowed { narrowed_to: to, .. } | Type::AliasTo { to, .. } => slice_matches_type(
2671 (*to, base_type_arguments),
2672 slice,
2673 contributions,
2674 information,
2675 types,
2676 allow_casts,
2677 ),
2678 Type::Or(l, r) => {
2679 let mut new_contributions = SliceArguments::default();
2681 let matches = slice_matches_type(
2682 (*l, base_type_arguments),
2683 slice,
2684 Some(&mut new_contributions),
2685 information,
2686 types,
2687 allow_casts,
2688 );
2689 if matches {
2690 if let Some(ref mut contributions) = contributions {
2691 contributions.extend(new_contributions);
2692 }
2693 true
2694 } else {
2695 slice_matches_type(
2697 (*r, base_type_arguments),
2698 slice,
2699 contributions,
2700 information,
2701 types,
2702 allow_casts,
2703 )
2704 }
2705 }
2706 Type::And(l, r) => {
2707 let mut new_contributions = SliceArguments::default();
2708 let matches = slice_matches_type(
2709 (*l, base_type_arguments),
2710 slice,
2711 Some(&mut new_contributions),
2712 information,
2713 types,
2714 allow_casts,
2715 );
2716 if matches {
2717 if let Some(ref mut contributions) = contributions {
2718 contributions.extend(new_contributions);
2719 }
2720 slice_matches_type(
2721 (*r, base_type_arguments),
2722 slice,
2723 contributions,
2724 information,
2725 types,
2726 allow_casts,
2727 )
2728 } else {
2729 false
2730 }
2731 }
2732 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
2733 on:
2734 transform @ (TypeId::STRING_CAPITALIZE
2735 | TypeId::STRING_UNCAPITALIZE
2736 | TypeId::STRING_LOWERCASE
2737 | TypeId::STRING_UPPERCASE),
2738 arguments,
2739 }) => {
2740 let matches_constraint = match *transform {
2741 TypeId::STRING_CAPITALIZE => slice.chars().next().map_or(true, char::is_uppercase),
2742 TypeId::STRING_UNCAPITALIZE => {
2743 slice.chars().next().map_or(true, char::is_lowercase)
2744 }
2745 TypeId::STRING_LOWERCASE => slice.chars().all(char::is_lowercase),
2746 TypeId::STRING_UPPERCASE => slice.chars().all(char::is_uppercase),
2747 _ => unreachable!(),
2748 };
2749
2750 if matches_constraint {
2751 let generic_chain_link = Some(GenericChainLink::SpecialGenericChainLink {
2752 parent_link: base_type_arguments.as_ref(),
2753 special: SpecialGenericChainLink::CaseTransform { transform: *transform },
2754 });
2755 let inner = arguments.get_structure_restriction(TypeId::STRING_GENERIC).unwrap();
2756
2757 let mut new_contributions = SliceArguments::default();
2758 let matches = slice_matches_type(
2760 (inner, generic_chain_link),
2761 slice,
2762 Some(&mut new_contributions),
2763 information,
2764 types,
2765 allow_casts,
2766 );
2767 if let (true, Some(current)) = (matches, contributions) {
2768 crate::utilities::notify!("{:?}", new_contributions);
2769 for (id, (c, d)) in new_contributions {
2770 current
2771 .insert(id, (CovariantContribution::CaseInsensitive(Box::new(c)), d));
2772 }
2773 crate::utilities::notify!("{:?}", current);
2774 }
2775 matches
2776 } else {
2777 false
2778 }
2779 }
2780 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
2781 on: TypeId::CASE_INSENSITIVE,
2782 arguments,
2783 }) => {
2784 let base_type_arguments = Some(GenericChainLink::SpecialGenericChainLink {
2785 parent_link: base_type_arguments.as_ref(),
2786 special: SpecialGenericChainLink::CaseInsensitive,
2787 });
2788 let inner = arguments.get_structure_restriction(TypeId::STRING_GENERIC).unwrap();
2789 slice_matches_type(
2790 (inner, base_type_arguments),
2791 slice,
2792 contributions,
2793 information,
2794 types,
2795 allow_casts,
2796 )
2797 }
2798 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
2799 on: TypeId::NOT_RESTRICTION,
2800 arguments,
2801 }) => {
2802 let argument = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
2804 let matches = slice_matches_type(
2806 (argument, base_type_arguments),
2807 slice,
2808 contributions,
2809 information,
2810 types,
2811 allow_casts,
2812 );
2813 !matches
2815 }
2816 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics { on, arguments: _ })
2817 if allow_casts && intrinsics::is_ezno_number_intrinsic(*on) =>
2818 {
2819 if let Ok(value) = slice.parse::<f64>() {
2821 number_matches_type(
2822 (base, base_type_arguments),
2823 value,
2824 contributions,
2825 information,
2826 types,
2827 )
2828 } else {
2829 false
2830 }
2831 }
2832 Type::Constructor(super::Constructor::KeyOf(on)) => {
2833 let argument =
2834 (Publicity::Public, &PropertyKey::String(std::borrow::Cow::Borrowed(slice)), None);
2835
2836 let arg = base_type_arguments
2837 .as_ref()
2838 .and_then(|link| link.get_single_argument(*on))
2839 .unwrap_or(*on);
2840
2841 let property = get_property_unbound(
2842 (arg, base_type_arguments),
2843 argument,
2844 true,
2845 information,
2846 types,
2847 );
2848
2849 if let Ok(LogicalOrValid::Logical(property)) = property {
2852 if let Some(contributions) = contributions {
2854 let is_writable =
2856 if let Logical::Pure(PropertyValue::Configured { on: _, ref descriptor }) =
2857 property
2858 {
2859 descriptor.writable
2860 } else {
2861 crate::utilities::notify!("Might be missing {:?}", property);
2863 TypeId::TRUE
2864 };
2865
2866 let is_defined = if let Logical::Pure(PropertyValue::ConditionallyExists {
2868 ref condition,
2869 ..
2870 }) = property
2871 {
2872 *condition
2873 } else {
2874 crate::utilities::notify!("Might be missing {:?}", property);
2876 TypeId::TRUE
2877 };
2878
2879 contributions.insert(
2880 TypeId::WRITABLE_KEY_ARGUMENT,
2881 (CovariantContribution::TypeId(is_writable), 0),
2882 );
2883 contributions.insert(
2884 TypeId::NON_OPTIONAL_KEY_ARGUMENT,
2885 (CovariantContribution::TypeId(is_defined), 0),
2886 );
2887 crate::utilities::notify!(
2888 "For MT set: (is_writable, is_defined)={:?}",
2889 (is_writable, is_defined)
2890 );
2891 }
2892
2893 true
2894 } else {
2895 false
2896 }
2897 }
2898 Type::Constant(Constant::Number(base)) => {
2899 crate::utilities::notify!("Here");
2900 if let Ok(slice_as_float) = slice.parse::<f64>() {
2901 *base == slice_as_float
2902 } else {
2903 false
2904 }
2905 }
2906 Type::Constructor(super::Constructor::BinaryOperator {
2907 lhs,
2908 rhs,
2909 operator: MathematicalOrBitwiseOperation::Add,
2910 result: _,
2911 }) => {
2912 let lhs = base_type_arguments
2913 .as_ref()
2914 .and_then(|link| link.get_single_argument(*lhs))
2915 .unwrap_or(*lhs);
2916
2917 let rhs = base_type_arguments
2918 .as_ref()
2919 .and_then(|link| link.get_single_argument(*rhs))
2920 .unwrap_or(*rhs);
2921
2922 if let Type::Constant(Constant::String(prefix)) = types.get_type_by_id(lhs) {
2923 if let Some(after) = slice.strip_prefix(prefix) {
2924 slice_matches_type(
2925 (rhs, base_type_arguments),
2926 after,
2927 contributions,
2928 information,
2929 types,
2930 allow_casts,
2931 )
2932 } else {
2933 false
2934 }
2935 } else if let Type::Constant(Constant::String(suffix)) = types.get_type_by_id(rhs) {
2936 if let Some(before) = slice.strip_suffix(suffix) {
2937 slice_matches_type(
2938 (lhs, base_type_arguments),
2939 before,
2940 contributions,
2941 information,
2942 types,
2943 allow_casts,
2944 )
2945 } else {
2946 false
2947 }
2948 } else {
2949 let lhs = types.get_type_by_id(lhs);
2950 let rhs = types.get_type_by_id(rhs);
2951 crate::utilities::notify!(
2952 "More complex type here, returning false. lhs={:?}, rhs={:?}, {:?}",
2953 lhs,
2954 rhs,
2955 base_type_arguments
2956 );
2957 false
2958 }
2959 }
2960 _ => {
2961 if base == TypeId::STRING_TYPE || base == TypeId::ANY_TYPE {
2962 true
2963 } else {
2964 crate::utilities::notify!("Cannot match key {:?}", base_ty);
2965 false
2966 }
2967 }
2968 }
2969}
2970
2971#[allow(clippy::only_used_in_recursion)]
2973pub(crate) fn number_matches_type(
2974 (base, base_type_arguments): (TypeId, Option<super::GenericChainLink>),
2975 number: f64,
2976 mut contributions: Option<&mut SliceArguments>,
2977 information: &impl InformationChain,
2978 types: &TypeStore,
2979) -> bool {
2980 match types.get_type_by_id(base) {
2981 Type::Constant(cst) => {
2982 if let Constant::Number(base_number) = cst {
2983 *base_number == number
2984 } else {
2985 false
2986 }
2987 }
2988 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
2989 on: TypeId::MULTIPLE_OF,
2990 arguments,
2991 }) => {
2992 let argument = arguments.get_structure_restriction(TypeId::NUMBER_GENERIC).unwrap();
2993 if let Type::Constant(Constant::Number(argument)) = types.get_type_by_id(argument) {
2994 let number: ordered_float::NotNan<f64> = number.try_into().unwrap();
2995 (number % argument) == 0.
2996 } else {
2997 crate::utilities::notify!("Here?");
2998 false
2999 }
3000 }
3001 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
3002 on: TypeId::LESS_THAN,
3003 arguments: _,
3004 }) => {
3005 todo!()
3006 }
3009 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
3010 on: TypeId::GREATER_THAN,
3011 arguments: _,
3012 }) => {
3013 todo!()
3014 }
3017 Type::PartiallyAppliedGenerics(PartiallyAppliedGenerics {
3018 on: TypeId::NOT_RESTRICTION,
3019 arguments,
3020 }) => {
3021 let argument = arguments.get_structure_restriction(TypeId::T_TYPE).unwrap();
3022
3023 !number_matches_type(
3024 (argument, base_type_arguments),
3025 number,
3026 contributions,
3027 information,
3028 types,
3029 )
3030 }
3031 Type::Or(l, r) => {
3032 let mut new_contributions = SliceArguments::default();
3034 let matches = number_matches_type(
3035 (*l, base_type_arguments),
3036 number,
3037 Some(&mut new_contributions),
3038 information,
3039 types,
3040 );
3041 if matches {
3042 if let Some(ref mut contributions) = contributions {
3043 contributions.extend(new_contributions);
3044 }
3045 true
3046 } else {
3047 number_matches_type(
3049 (*r, base_type_arguments),
3050 number,
3051 contributions,
3052 information,
3053 types,
3054 )
3055 }
3056 }
3057 Type::And(l, r) => {
3058 let mut new_contributions = SliceArguments::default();
3059 let matches = number_matches_type(
3060 (*l, base_type_arguments),
3061 number,
3062 Some(&mut new_contributions),
3063 information,
3064 types,
3065 );
3066 if matches {
3067 if let Some(ref mut contributions) = contributions {
3068 contributions.extend(new_contributions);
3069 }
3070 number_matches_type(
3071 (*r, base_type_arguments),
3072 number,
3073 contributions,
3074 information,
3075 types,
3076 )
3077 } else {
3078 false
3079 }
3080 }
3081 ty => {
3082 crate::utilities::notify!("TODO number matches ty={:?}", ty);
3083 true
3084 }
3085 }
3086}