luaur_compiler/functions/
get_type.rs1use luaur_ast::records::ast_array::AstArray;
2use luaur_ast::records::ast_generic_type::AstGenericType;
3use luaur_ast::records::ast_name::AstName;
4use luaur_ast::records::ast_stat_type_alias::AstStatTypeAlias;
5use luaur_ast::records::ast_type::AstType;
6use luaur_ast::records::ast_type_function::AstTypeFunction;
7use luaur_ast::records::ast_type_group::AstTypeGroup;
8use luaur_ast::records::ast_type_intersection::AstTypeIntersection;
9use luaur_ast::records::ast_type_optional::AstTypeOptional;
10use luaur_ast::records::ast_type_reference::AstTypeReference;
11use luaur_ast::records::ast_type_singleton_bool::AstTypeSingletonBool;
12use luaur_ast::records::ast_type_singleton_string::AstTypeSingletonString;
13use luaur_ast::records::ast_type_table::AstTypeTable;
14use luaur_ast::records::ast_type_union::AstTypeUnion;
15use luaur_ast::rtti::{ast_node_as, ast_node_is};
16use luaur_bytecode::records::bytecode_builder::BytecodeBuilder;
17use luaur_common::enums::luau_bytecode_type::{
18 LuauBytecodeType, LBC_TYPE_ANY, LBC_TYPE_BOOLEAN, LBC_TYPE_FUNCTION, LBC_TYPE_INVALID,
19 LBC_TYPE_NIL, LBC_TYPE_NUMBER, LBC_TYPE_OPTIONAL_BIT, LBC_TYPE_STRING, LBC_TYPE_TABLE,
20 LBC_TYPE_TAGGED_USERDATA_BASE, LBC_TYPE_USERDATA, LBC_TYPE_VECTOR,
21};
22use luaur_common::records::dense_hash_map::DenseHashMap;
23use luaur_common::records::dense_hash_set::DenseHashSet;
24use luaur_common::FFlag;
25
26pub fn get_type(
27 ty: *const AstType,
28 generics: AstArray<*mut AstGenericType>,
29 type_aliases: &DenseHashMap<AstName, *mut AstStatTypeAlias>,
30 resolve_aliases_deprecated: bool,
31 host_vector_type: *const core::ffi::c_char,
32 userdata_types: &DenseHashMap<AstName, u8>,
33 bytecode: &mut BytecodeBuilder,
34 seen_aliases: &mut DenseHashSet<AstName>,
35) -> LuauBytecodeType {
36 if ty.is_null() {
37 return LBC_TYPE_ANY;
38 }
39
40 let node = ty as *mut luaur_ast::records::ast_node::AstNode;
41
42 if let Some(ref_node) = unsafe { ast_node_as::<AstTypeReference>(node).as_ref() } {
43 if ref_node.prefix.is_some() {
44 return LBC_TYPE_ANY;
45 }
46
47 if let Some(alias_ptr) = type_aliases
52 .find(&ref_node.name)
53 .copied()
54 .filter(|p| !p.is_null())
55 {
56 let alias = unsafe { &*alias_ptr };
57 if FFlag::LuauCompileTypeAliases.get() {
58 if seen_aliases.contains(&alias.name) {
59 seen_aliases.clear();
60 return LBC_TYPE_ANY;
61 } else {
62 seen_aliases.insert(ref_node.name);
63 return get_type(
64 alias.type_ptr,
65 alias.generics,
66 type_aliases,
67 false,
68 host_vector_type,
69 userdata_types,
70 bytecode,
71 seen_aliases,
72 );
73 }
74 } else {
75 if resolve_aliases_deprecated {
77 return get_type(
78 alias.type_ptr,
79 alias.generics,
80 type_aliases,
81 false,
82 host_vector_type,
83 userdata_types,
84 bytecode,
85 seen_aliases,
86 );
87 } else {
88 return LBC_TYPE_ANY;
89 }
90 }
91 }
92
93 if crate::functions::is_generic::is_generic(ref_node.name, &generics) {
94 return LBC_TYPE_ANY;
95 }
96
97 if !host_vector_type.is_null() && ref_node.name.operator_eq_c_char(host_vector_type) {
98 return LBC_TYPE_VECTOR;
99 }
100
101 let prim = crate::functions::get_primitive_type::get_primitive_type(ref_node.name);
102 if prim != LBC_TYPE_INVALID {
103 return prim;
104 }
105
106 if let Some(userdata_index) = userdata_types.find(&ref_node.name) {
107 bytecode.use_userdata_type(*userdata_index as u32);
108 return LuauBytecodeType(LBC_TYPE_TAGGED_USERDATA_BASE.0 + *userdata_index as u16);
109 }
110
111 return LBC_TYPE_USERDATA;
113 } else if unsafe { ast_node_is::<AstTypeTable>(node) } {
114 return LBC_TYPE_TABLE;
115 } else if unsafe { ast_node_is::<AstTypeFunction>(node) } {
116 return LBC_TYPE_FUNCTION;
117 } else if let Some(un) = unsafe { ast_node_as::<AstTypeUnion>(node).as_ref() } {
118 let mut optional = false;
119 let mut r#type = LBC_TYPE_INVALID;
120
121 for &ty in un.types.as_slice() {
122 let et = get_type(
123 ty,
124 generics,
125 type_aliases,
126 resolve_aliases_deprecated,
127 host_vector_type,
128 userdata_types,
129 bytecode,
130 seen_aliases,
131 );
132
133 if et == LBC_TYPE_NIL {
134 optional = true;
135 continue;
136 }
137
138 if r#type == LBC_TYPE_INVALID {
139 r#type = et;
140 continue;
141 }
142
143 if r#type != et {
144 return LBC_TYPE_ANY;
145 }
146 }
147
148 if r#type == LBC_TYPE_INVALID {
149 return LBC_TYPE_ANY;
150 }
151
152 return LuauBytecodeType(
153 r#type.0
154 | (if optional && (r#type != LBC_TYPE_ANY) {
155 LBC_TYPE_OPTIONAL_BIT.0
156 } else {
157 0
158 }),
159 );
160 } else if unsafe { ast_node_is::<AstTypeIntersection>(node) } {
161 return LBC_TYPE_ANY;
162 } else if let Some(group) = unsafe { ast_node_as::<AstTypeGroup>(node).as_ref() } {
163 return get_type(
164 group.type_,
165 generics,
166 type_aliases,
167 resolve_aliases_deprecated,
168 host_vector_type,
169 userdata_types,
170 bytecode,
171 seen_aliases,
172 );
173 } else if unsafe { ast_node_is::<AstTypeOptional>(node) } {
174 return LBC_TYPE_NIL;
175 } else if unsafe { ast_node_is::<AstTypeSingletonBool>(node) } {
176 return LBC_TYPE_BOOLEAN; } else if unsafe { ast_node_is::<AstTypeSingletonString>(node) } {
178 return LBC_TYPE_STRING;
179 }
180
181 LBC_TYPE_ANY
182}