Skip to main content

luaur_analysis/methods/
subtyping_is_sub_tail_covariant_with.rs

1//! Faithful port of `Subtyping::isSubTailCovariantWith`
2//! (Analysis/src/Subtyping.cpp:1180-1258).
3use crate::enums::early_exit::EarlyExit;
4use crate::enums::pack_field::PackField;
5use crate::enums::subtyping_suppression_policy::SubtypingSuppressionPolicy;
6use crate::enums::variant::Variant;
7use crate::functions::get_type_pack::get_type_pack_id;
8use crate::functions::slice_type_pack::slice_type_pack;
9use crate::records::error_type_pack::ErrorTypePack;
10use crate::records::free_type_pack::FreeTypePack;
11use crate::records::generic_pack_mapping::GenericPackMapping;
12use crate::records::generic_type_pack::GenericTypePack;
13use crate::records::index::Index;
14use crate::records::pack_slice::PackSlice;
15use crate::records::pack_subtype_constraint::PackSubtypeConstraint;
16use crate::records::scope::Scope;
17use crate::records::subtyping::Subtyping;
18use crate::records::subtyping_environment::SubtypingEnvironment;
19use crate::records::subtyping_result::SubtypingResult;
20use crate::records::type_error::TypeError;
21use crate::records::type_pack::TypePack;
22use crate::records::unexpected_type_pack_in_subtyping::UnexpectedTypePackInSubtyping;
23use crate::records::variadic_type_pack::VariadicTypePack;
24use crate::type_aliases::component::Component;
25use crate::type_aliases::constraint_v::ConstraintV;
26use crate::type_aliases::lookup_result::LookupResult;
27use crate::type_aliases::path::Path;
28use crate::type_aliases::type_id::TypeId;
29use crate::type_aliases::type_pack_id::TypePackId;
30
31use crate::functions::follow_type_pack::follow_type_pack_id;
32use crate::methods::path_builder_build::PathBuilderBuild;
33use crate::methods::path_builder_tail::PathBuilderTail;
34use crate::methods::path_builder_variadic::PathBuilderVariadic;
35use crate::records::path_builder::PathBuilder;
36
37impl Subtyping {
38    pub fn is_sub_tail_covariant_with(
39        &mut self,
40        env: &mut SubtypingEnvironment,
41        output_result: &mut SubtypingResult,
42        sub_tp: TypePackId,
43        sub_tail: TypePackId,
44        super_tp: TypePackId,
45        super_head_start_index: usize,
46        super_head: &Vec<TypeId>,
47        super_tail: Option<TypePackId>,
48        scope: *mut Scope,
49    ) -> EarlyExit {
50        let _ = sub_tp;
51
52        if let Some(vt) = unsafe { get_type_pack_id::<VariadicTypePack>(sub_tail).as_ref() } {
53            for i in super_head_start_index..super_head.len() {
54                let mut next = self
55                    .is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
56                        env,
57                        vt.ty,
58                        super_head[i],
59                        scope,
60                    );
61                next.with_sub_path(
62                    PathBuilder {
63                        components: alloc::vec::Vec::new(),
64                    }
65                    .tail()
66                    .variadic()
67                    .build(),
68                );
69                next.with_super_component(Component::Index(Index {
70                    index: i,
71                    variant: Variant::Pack,
72                }));
73                output_result.and_also(next, SubtypingSuppressionPolicy::Any);
74            }
75            EarlyExit::No
76        } else if !unsafe { get_type_pack_id::<GenericTypePack>(sub_tail).is_null() } {
77            let lookup_result = env.lookup_generic_pack(sub_tail);
78            let result: SubtypingResult;
79            if let LookupResult::V2(_) = lookup_result {
80                // get_if<MappedGenericEnvironment::NotBindable>
81                let mut r = SubtypingResult {
82                    is_subtype: false,
83                    normalization_too_complex: false,
84                    is_cacheable: false,
85                    ..Default::default()
86                };
87                r.with_sub_component(Component::PackField(PackField::Tail));
88                r.with_super_component(Component::PackSlice(PackSlice {
89                    start_index: super_head_start_index,
90                }));
91                result = r;
92            } else {
93                let super_tail_pack = slice_type_pack(
94                    super_head_start_index,
95                    super_tp,
96                    super_head,
97                    super_tail,
98                    unsafe { &*self.builtin_types },
99                    unsafe { &mut *self.arena },
100                );
101
102                if let LookupResult::V0(mapped_gen) = lookup_result {
103                    // get_if<TypePackId> — subtype against the mapped generic pack.
104                    let mut sub_tp_to_compare = mapped_gen;
105
106                    // If mappedGen has a hidden variadic tail, we clip it for better
107                    // arity mismatch reporting.
108                    let tp = unsafe { get_type_pack_id::<TypePack>(mapped_gen).as_ref() };
109                    if let Some(tp) = tp {
110                        if let Some(tail) = tp.tail {
111                            let vtp = unsafe {
112                                get_type_pack_id::<VariadicTypePack>(follow_type_pack_id(tail))
113                                    .as_ref()
114                            };
115                            if let Some(vtp) = vtp {
116                                if vtp.hidden {
117                                    sub_tp_to_compare = unsafe {
118                                        (*self.arena)
119                                            .add_type_pack_initializer_list_type_id(&tp.head)
120                                    };
121                                }
122                            }
123                        }
124                    }
125
126                    let mut r = self
127                        .is_covariant_with_subtyping_environment_type_pack_id_type_pack_id_not_null_scope(
128                            env,
129                            sub_tp_to_compare,
130                            super_tail_pack,
131                            scope,
132                        );
133                    r.with_sub_path(Path::from_components(alloc::vec![
134                        Component::PackField(PackField::Tail),
135                        Component::GenericPackMapping(GenericPackMapping {
136                            mappedType: mapped_gen
137                        }),
138                    ]));
139                    r.with_super_component(Component::PackSlice(PackSlice {
140                        start_index: super_head_start_index,
141                    }));
142                    result = r;
143                } else {
144                    // get_if<MappedGenericEnvironment::Unmapped>
145                    let ok = env
146                        .mapped_generic_packs
147                        .bind_generic(sub_tail, super_tail_pack);
148                    let mut r = SubtypingResult {
149                        is_subtype: ok,
150                        normalization_too_complex: false,
151                        is_cacheable: false,
152                        ..Default::default()
153                    };
154                    r.with_sub_component(Component::PackField(PackField::Tail));
155                    r.with_super_component(Component::PackSlice(PackSlice {
156                        start_index: super_head_start_index,
157                    }));
158                    result = r;
159                }
160            }
161
162            output_result.and_also(result, SubtypingSuppressionPolicy::Any);
163            EarlyExit::Yes
164        } else if !unsafe { get_type_pack_id::<ErrorTypePack>(sub_tail).is_null() } {
165            let mut r = SubtypingResult {
166                is_subtype: true,
167                ..Default::default()
168            };
169            r.with_sub_component(Component::PackField(PackField::Tail));
170            *output_result = r;
171            EarlyExit::Yes
172        } else if !unsafe { get_type_pack_id::<FreeTypePack>(sub_tail).is_null() } {
173            let super_tail_pack = slice_type_pack(
174                super_head_start_index,
175                super_tp,
176                super_head,
177                super_tail,
178                unsafe { &*self.builtin_types },
179                unsafe { &mut *self.arena },
180            );
181            let mut r = SubtypingResult {
182                is_subtype: true,
183                ..Default::default()
184            };
185            r.with_sub_component(Component::PackField(PackField::Tail));
186            r.with_assumed_constraint(ConstraintV::PackSubtype(PackSubtypeConstraint {
187                sub_pack: sub_tail,
188                super_pack: super_tail_pack,
189                returns: false,
190            }));
191            output_result.and_also(r, SubtypingSuppressionPolicy::Any);
192            EarlyExit::Yes
193        } else {
194            let mut r = SubtypingResult {
195                is_subtype: false,
196                ..Default::default()
197            };
198            r.with_sub_component(Component::PackField(PackField::Tail));
199            r.with_error(TypeError::type_error_location_type_error_data(
200                unsafe { (*scope).location.clone() },
201                UnexpectedTypePackInSubtyping { tp: sub_tail }.into(),
202            ));
203            *output_result = r;
204            EarlyExit::Yes
205        }
206    }
207}