luaur_analysis/methods/
subtyping_is_contravariant_with_subtyping.rs1use crate::enums::subtyping_variance::SubtypingVariance;
2use crate::functions::assert_reasoning_valid_subtyping::assert_reasoning_valid;
3use crate::functions::merge_reasonings::k_empty_reasoning;
4use crate::records::scope::Scope;
5use crate::records::subtyping::Subtyping;
6use crate::records::subtyping_environment::SubtypingEnvironment;
7use crate::records::subtyping_reasoning::SubtypingReasoning;
8use crate::records::subtyping_result::SubtypingResult;
9use crate::records::table_indexer::TableIndexer;
10use crate::type_aliases::path::Path;
11use crate::type_aliases::subtyping_reasonings::SubtypingReasonings;
12use crate::type_aliases::type_id::TypeId;
13
14pub(crate) enum CovOperand {
23 Type(TypeId),
24 Indexer(TableIndexer),
25}
26
27pub(crate) trait IntoCovOperand: Copy {
28 fn into_cov_operand(self) -> CovOperand;
29}
30
31impl<T> IntoCovOperand for *const T {
32 #[inline]
33 fn into_cov_operand(self) -> CovOperand {
34 CovOperand::Type(self as TypeId)
35 }
36}
37
38impl IntoCovOperand for TableIndexer {
39 #[inline]
40 fn into_cov_operand(self) -> CovOperand {
41 CovOperand::Indexer(self)
42 }
43}
44
45impl Subtyping {
46 pub(crate) fn covariant_dispatch(
50 &mut self,
51 env: &mut SubtypingEnvironment,
52 sub: CovOperand,
53 sup: CovOperand,
54 scope: *mut Scope,
55 ) -> SubtypingResult {
56 match (sub, sup) {
57 (CovOperand::Type(a), CovOperand::Type(b)) => self
58 .is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
59 env, a, b, scope,
60 ),
61 (CovOperand::Indexer(a), CovOperand::Indexer(b)) => self
62 .is_covariant_with_subtyping_environment_table_indexer_table_indexer_not_null_scope(
63 env, &a, &b, scope,
64 ),
65 _ => unreachable!("isCovariantWith dispatch with mismatched operand kinds"),
67 }
68 }
69
70 pub fn is_contravariant_with_subtyping_environment_sub_ty_super_ty_not_null_scope<
71 SubTy,
72 SuperTy,
73 >(
74 &mut self,
75 env: &mut SubtypingEnvironment,
76 sub_ty: SubTy,
77 super_ty: SuperTy,
78 scope: *mut Scope,
79 ) -> SubtypingResult
80 where
81 SubTy: IntoCovOperand,
82 SuperTy: IntoCovOperand,
83 {
84 let mut result = self.covariant_dispatch(
86 env,
87 super_ty.into_cov_operand(),
88 sub_ty.into_cov_operand(),
89 scope,
90 );
91
92 if result.reasoning.empty() {
93 result.reasoning.insert(SubtypingReasoning {
94 sub_path: Path::default(),
95 super_path: Path::default(),
96 variance: SubtypingVariance::Contravariant,
97 is_property_modifier_violation: false,
98 });
99 } else {
100 let mut updated = SubtypingReasonings::new(k_empty_reasoning());
105 for r in result.reasoning.iter() {
106 let mut r = r.clone();
107 core::mem::swap(&mut r.sub_path, &mut r.super_path);
108
109 if r.variance == SubtypingVariance::Covariant {
112 r.variance = SubtypingVariance::Contravariant;
113 } else if r.variance == SubtypingVariance::Contravariant {
114 r.variance = SubtypingVariance::Covariant;
115 }
116 updated.insert(r);
117 }
118 result.reasoning = updated;
119 }
120
121 assert_reasoning_valid(sub_ty, sub_ty, &result, self.builtin_types, self.arena);
127
128 result
129 }
130}