Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/Analysis/src/StructuralTypeEquality.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
3
#include "Luau/StructuralTypeEquality.h"
4
5
#include "Luau/Type.h"
6
#include "Luau/TypePack.h"
7
8
// Test Types for equivalence
9
// More complex than we'd like because Types can self-reference.
10
11
namespace Luau
12
{
13
14
bool areSeen(SeenSet& seen, const void* lhs, const void* rhs)
15
{
16
if (lhs == rhs)
17
return true;
18
19
auto p = std::make_pair(const_cast<void*>(lhs), const_cast<void*>(rhs));
20
if (seen.find(p) != seen.end())
21
return true;
22
23
seen.insert(p);
24
return false;
25
}
26
27
bool areEqual(SeenSet& seen, const TypePackVar& lhs, const TypePackVar& rhs)
28
{
29
TypePackId lhsId = const_cast<TypePackId>(&lhs);
30
TypePackId rhsId = const_cast<TypePackId>(&rhs);
31
TypePackIterator lhsIter = begin(lhsId);
32
TypePackIterator rhsIter = begin(rhsId);
33
TypePackIterator lhsEnd = end(lhsId);
34
TypePackIterator rhsEnd = end(rhsId);
35
while (lhsIter != lhsEnd && rhsIter != rhsEnd)
36
{
37
if (!areEqual(seen, **lhsIter, **rhsIter))
38
return false;
39
++lhsIter;
40
++rhsIter;
41
}
42
43
if (lhsIter != lhsEnd || rhsIter != rhsEnd)
44
return false;
45
46
if (!lhsIter.tail() && !rhsIter.tail())
47
return true;
48
if (!lhsIter.tail() || !rhsIter.tail())
49
return false;
50
51
TypePackId lhsTail = *lhsIter.tail();
52
TypePackId rhsTail = *rhsIter.tail();
53
54
{
55
const FreeTypePack* lf = get_if<FreeTypePack>(&lhsTail->ty);
56
const FreeTypePack* rf = get_if<FreeTypePack>(&rhsTail->ty);
57
if (lf && rf)
58
return lf->index == rf->index;
59
}
60
61
{
62
const Unifiable::Bound<TypePackId>* lb = get_if<Unifiable::Bound<TypePackId>>(&lhsTail->ty);
63
const Unifiable::Bound<TypePackId>* rb = get_if<Unifiable::Bound<TypePackId>>(&rhsTail->ty);
64
if (lb && rb)
65
return areEqual(seen, *lb->boundTo, *rb->boundTo);
66
}
67
68
{
69
const GenericTypePack* lg = get_if<GenericTypePack>(&lhsTail->ty);
70
const GenericTypePack* rg = get_if<GenericTypePack>(&rhsTail->ty);
71
if (lg && rg)
72
return lg->index == rg->index;
73
}
74
75
{
76
const VariadicTypePack* lv = get_if<VariadicTypePack>(&lhsTail->ty);
77
const VariadicTypePack* rv = get_if<VariadicTypePack>(&rhsTail->ty);
78
if (lv && rv)
79
return areEqual(seen, *lv->ty, *rv->ty);
80
}
81
82
return false;
83
}
84
85
bool areEqual(SeenSet& seen, const FunctionType& lhs, const FunctionType& rhs)
86
{
87
if (areSeen(seen, &lhs, &rhs))
88
return true;
89
90
// TODO: check generics CLI-39915
91
92
if (!areEqual(seen, *lhs.argTypes, *rhs.argTypes))
93
return false;
94
95
if (!areEqual(seen, *lhs.retTypes, *rhs.retTypes))
96
return false;
97
98
return true;
99
}
100
101
bool areEqual(SeenSet& seen, const TableType& lhs, const TableType& rhs)
102
{
103
if (areSeen(seen, &lhs, &rhs))
104
return true;
105
106
if (lhs.state != rhs.state)
107
return false;
108
109
if (lhs.props.size() != rhs.props.size())
110
return false;
111
112
if (bool(lhs.indexer) != bool(rhs.indexer))
113
return false;
114
115
if (lhs.indexer && rhs.indexer)
116
{
117
if (!areEqual(seen, *lhs.indexer->indexType, *rhs.indexer->indexType))
118
return false;
119
120
if (!areEqual(seen, *lhs.indexer->indexResultType, *rhs.indexer->indexResultType))
121
return false;
122
}
123
124
auto l = lhs.props.begin();
125
auto r = rhs.props.begin();
126
127
while (l != lhs.props.end())
128
{
129
if (l->first != r->first)
130
return false;
131
132
133
if (l->second.readTy && r->second.readTy)
134
{
135
if (!areEqual(seen, **l->second.readTy, **r->second.readTy))
136
return false;
137
}
138
else if (l->second.readTy || r->second.readTy)
139
return false;
140
141
if (l->second.writeTy && r->second.writeTy)
142
{
143
if (!areEqual(seen, **l->second.writeTy, **r->second.writeTy))
144
return false;
145
}
146
else if (l->second.writeTy || r->second.writeTy)
147
return false;
148
149
150
++l;
151
++r;
152
}
153
154
return true;
155
}
156
157
static bool areEqual(SeenSet& seen, const MetatableType& lhs, const MetatableType& rhs)
158
{
159
if (areSeen(seen, &lhs, &rhs))
160
return true;
161
162
return areEqual(seen, *lhs.table, *rhs.table) && areEqual(seen, *lhs.metatable, *rhs.metatable);
163
}
164
165
bool areEqual(SeenSet& seen, const Type& lhs, const Type& rhs)
166
{
167
if (auto bound = get_if<BoundType>(&lhs.ty))
168
return areEqual(seen, *bound->boundTo, rhs);
169
170
if (auto bound = get_if<BoundType>(&rhs.ty))
171
return areEqual(seen, lhs, *bound->boundTo);
172
173
if (lhs.ty.index() != rhs.ty.index())
174
return false;
175
176
{
177
const FreeType* lf = get_if<FreeType>(&lhs.ty);
178
const FreeType* rf = get_if<FreeType>(&rhs.ty);
179
if (lf && rf)
180
return lf->index == rf->index;
181
}
182
183
{
184
const GenericType* lg = get_if<GenericType>(&lhs.ty);
185
const GenericType* rg = get_if<GenericType>(&rhs.ty);
186
if (lg && rg)
187
return lg->index == rg->index;
188
}
189
190
{
191
const PrimitiveType* lp = get_if<PrimitiveType>(&lhs.ty);
192
const PrimitiveType* rp = get_if<PrimitiveType>(&rhs.ty);
193
if (lp && rp)
194
return lp->type == rp->type;
195
}
196
197
{
198
const GenericType* lg = get_if<GenericType>(&lhs.ty);
199
const GenericType* rg = get_if<GenericType>(&rhs.ty);
200
if (lg && rg)
201
return lg->index == rg->index;
202
}
203
204
{
205
const ErrorType* le = get_if<ErrorType>(&lhs.ty);
206
const ErrorType* re = get_if<ErrorType>(&rhs.ty);
207
if (le && re)
208
return le->index == re->index;
209
}
210
211
{
212
const FunctionType* lf = get_if<FunctionType>(&lhs.ty);
213
const FunctionType* rf = get_if<FunctionType>(&rhs.ty);
214
if (lf && rf)
215
return areEqual(seen, *lf, *rf);
216
}
217
218
{
219
const TableType* lt = get_if<TableType>(&lhs.ty);
220
const TableType* rt = get_if<TableType>(&rhs.ty);
221
if (lt && rt)
222
return areEqual(seen, *lt, *rt);
223
}
224
225
{
226
const MetatableType* lmt = get_if<MetatableType>(&lhs.ty);
227
const MetatableType* rmt = get_if<MetatableType>(&rhs.ty);
228
229
if (lmt && rmt)
230
return areEqual(seen, *lmt, *rmt);
231
}
232
233
if (get_if<AnyType>(&lhs.ty) && get_if<AnyType>(&rhs.ty))
234
return true;
235
236
return false;
237
}
238
239
} // namespace Luau
240
241