Skip to main content

luaur_analysis/methods/
normalizer_negate_normal.rs

1use crate::functions::get_singleton_type::get_singleton_type;
2use crate::functions::get_type_alt_j::get_type_id;
3use crate::functions::is_top::is_top;
4use crate::functions::reset_to_top::reset_to_top;
5use crate::records::boolean_singleton::BooleanSingleton;
6use crate::records::never_type::NeverType;
7use crate::records::normalized_extern_type::NormalizedExternType;
8use crate::records::normalized_function_type::NormalizedFunctionType;
9use crate::records::normalized_string_type::NormalizedStringType;
10use crate::records::normalized_type::NormalizedType;
11use crate::records::normalizer::Normalizer;
12use crate::records::primitive_type::PrimitiveType;
13use crate::records::singleton_type::SingletonType;
14use crate::records::type_ids::TypeIds;
15use alloc::collections::BTreeMap;
16use luaur_common::macros::luau_assert::LUAU_ASSERT;
17use luaur_common::FFlag;
18
19impl Normalizer {
20    pub fn negate_normal(&mut self, here: &NormalizedType) -> Option<NormalizedType> {
21        self.consume_fuel();
22
23        let never_type = unsafe { (*here.builtin_types).neverType };
24        let mut result = NormalizedType {
25            builtin_types: here.builtin_types,
26            tops: never_type,
27            booleans: never_type,
28            extern_types: NormalizedExternType {
29                extern_types: BTreeMap::new(),
30                shape_extensions: TypeIds::type_ids(),
31                ordering: Vec::new(),
32            },
33            errors: never_type,
34            nils: never_type,
35            numbers: never_type,
36            integers: never_type,
37            strings: NormalizedStringType::never,
38            threads: never_type,
39            buffers: never_type,
40            tables: TypeIds::type_ids(),
41            functions: NormalizedFunctionType {
42                is_top: false,
43                parts: TypeIds::type_ids(),
44            },
45            tyvars: BTreeMap::new(),
46            is_cacheable: true,
47        };
48        result.is_cacheable = here.is_cacheable;
49
50        let here_tops = unsafe { get_type_id::<NeverType>(here.tops) };
51        if here_tops.is_null() {
52            return Some(result);
53        }
54
55        let here_errors = unsafe { get_type_id::<NeverType>(here.errors) };
56        if here_errors.is_null() {
57            result.errors = here.errors;
58            return Some(result);
59        }
60
61        let here_booleans = here.booleans;
62        let here_booleans_tv = unsafe { get_type_id::<NeverType>(here_booleans) };
63        if !here_booleans_tv.is_null() {
64            result.booleans = unsafe { (*here.builtin_types).booleanType };
65        } else {
66            let here_booleans_tv = unsafe { get_type_id::<PrimitiveType>(here_booleans) };
67            if !here_booleans_tv.is_null() {
68                result.booleans = unsafe { (*here.builtin_types).neverType };
69            } else {
70                let here_booleans_tv = unsafe { get_type_id::<SingletonType>(here_booleans) };
71                if !here_booleans_tv.is_null() {
72                    let boolean = get_singleton_type::<BooleanSingleton>(here_booleans_tv);
73                    LUAU_ASSERT!(!boolean.is_null());
74                    if unsafe { &*boolean }.value {
75                        result.booleans = unsafe { (*here.builtin_types).falseType };
76                    } else {
77                        result.booleans = unsafe { (*here.builtin_types).trueType };
78                    }
79                }
80            }
81        }
82
83        let extern_types = &here.extern_types;
84        if extern_types.is_never() {
85            reset_to_top(unsafe { &*here.builtin_types }, &mut result.extern_types);
86        } else if is_top(unsafe { &*here.builtin_types }, extern_types) {
87            result.extern_types.reset_to_never();
88        } else {
89            let mut root_negations = TypeIds::type_ids();
90
91            for (here_parent, here_negations) in &extern_types.extern_types {
92                if *here_parent != unsafe { (*here.builtin_types).externType } {
93                    root_negations.insert_type_id(*here_parent);
94                }
95
96                for &here_negation in &here_negations.order {
97                    self.union_extern_types_with_extern_type_normalized_extern_type_type_id(
98                        &mut result.extern_types,
99                        here_negation,
100                    );
101                }
102            }
103
104            if !root_negations.empty() {
105                result
106                    .extern_types
107                    .push_pair(unsafe { (*here.builtin_types).externType }, root_negations);
108            }
109        }
110
111        let here_nils = unsafe { get_type_id::<NeverType>(here.nils) };
112        if !here_nils.is_null() {
113            result.nils = unsafe { (*here.builtin_types).nilType };
114        } else {
115            result.nils = unsafe { (*here.builtin_types).neverType };
116        }
117
118        let here_numbers = unsafe { get_type_id::<NeverType>(here.numbers) };
119        if !here_numbers.is_null() {
120            result.numbers = unsafe { (*here.builtin_types).numberType };
121        } else {
122            result.numbers = unsafe { (*here.builtin_types).neverType };
123        }
124
125        if FFlag::LuauIntegerType2.get() {
126            let here_integers = unsafe { get_type_id::<NeverType>(here.integers) };
127            if !here_integers.is_null() {
128                result.integers = unsafe { (*here.builtin_types).integerType };
129            } else {
130                result.integers = unsafe { (*here.builtin_types).neverType };
131            }
132        }
133
134        result.strings = here.strings.clone();
135        result.strings.isCofinite = !result.strings.isCofinite;
136
137        let here_threads = unsafe { get_type_id::<NeverType>(here.threads) };
138        if !here_threads.is_null() {
139            result.threads = unsafe { (*here.builtin_types).threadType };
140        } else {
141            result.threads = unsafe { (*here.builtin_types).neverType };
142        }
143
144        let here_buffers = unsafe { get_type_id::<NeverType>(here.buffers) };
145        if !here_buffers.is_null() {
146            result.buffers = unsafe { (*here.builtin_types).bufferType };
147        } else {
148            result.buffers = unsafe { (*here.builtin_types).neverType };
149        }
150
151        if here.functions.is_never() {
152            result.functions.reset_to_top();
153        } else if here.functions.is_top {
154            result.functions.reset_to_never();
155        } else {
156            return None;
157        }
158
159        if here.tables.empty() {
160            result
161                .tables
162                .insert_type_id(unsafe { (*here.builtin_types).tableType });
163        } else if here.tables.size() == 1
164            && here.tables.front() == unsafe { (*here.builtin_types).tableType }
165        {
166            result.tables.clear();
167        } else {
168            return None;
169        }
170
171        Some(result)
172    }
173}