• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2022 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef _PANDA_TYPE_SYSTEM_HPP
17 #define _PANDA_TYPE_SYSTEM_HPP
18 
19 #include "verification/util/lazy.h"
20 #include "verification/util/relation.h"
21 
22 #include "subtyping_closure.h"
23 #include "type_sort.h"
24 #include "type_index.h"
25 #include "type_info.h"
26 #include "type_param.h"
27 #include "type_params.h"
28 #include "type_parametric.h"
29 #include "type_set.h"
30 #include "type_systems.h"
31 #include "type_tags.h"
32 #include "type_type.h"
33 
34 #include "runtime/include/mem/panda_containers.h"
35 
36 #include "libpandabase/os/mutex.h"
37 
38 #include "macros.h"
39 
40 #include <memory>
41 #include <variant>
42 #include <functional>
43 #include <algorithm>
44 
45 // TODO(vdyadov): refactor this awful code into more accurate pieces
46 
47 /*
48 todo:
49 3. lazy computation of parameters subtyping
50 4. unify TypeParam/TypeParams with TypeParamIdx/TypeParamsIdx
51 6. TypeParamsIdx - separate Variance from Indices
52 7. Check parameters variance of types from type family (same sort + same arity),
53    upon new type addition. Or separate parameters variance from parameters, make
54    it independent entity, which is defined for type family prior any of type addition
55 
56 Q: mutualy recursive types?
57 */
58 
59 namespace panda::verifier {
60 /*
61 Design decisions:
62 2. Subtyping relation is kept flat during types construction
63 3. Subtyping relation closing may be either incremental/implicit during types construction or explicit.
64 4. Sorts are abstracted in the form of indices (of type size_t)
65 5. Types internally represented as indices (size_t)
66 6. There are special initial and final types, named as Bot and Top, and all types are implicitly related
67    as Bot <: type <: Top
68 */
69 
70 class TypeSystem {
71 public:
72     TypeSystem(SortIdx bot, SortIdx top, ThreadNum threadnum = 0, TypeSystemKind kind = TypeSystemKind::PANDA)
73         : kind_ {kind},
74           threadnum_ {threadnum},
75           BotNum_ {FindNumOrCreate({bot, {}})},
76           TopNum_ {FindNumOrCreate({top, {}})}
77     {
78     }
79 
80     NO_COPY_SEMANTIC(TypeSystem);
81     DEFAULT_MOVE_SEMANTIC(TypeSystem);
82     ~TypeSystem() = default;
83 
84     using TypeUniverse = PandaVector<TypeInfo>;
85     using MappingToNum = PandaUnorderedMap<TypeInfo, TypeNum>;
86     // sort -> arity -> types
87     using TypeClasses = PandaVector<PandaUnorderedMap<size_t, VectorNum>>;
88 
89     Relation TypingRel_ = {};
90     PandaVector<PandaUnorderedSet<TypeNum>> ParameterOf_ = {};
91     TypeUniverse Universe_ = {};
92     MappingToNum InfoToNum_ = {};
93     mutable TypeClasses TypeClasses_ = {};
94     SubtypingClosureInfo SubtypingClosureCurrent_;
95     SubtypingClosureInfo SubtypingClosureNext_;
96     bool IncrementalSubtypingClosure_ = true;
97     bool DeferIncrementalSubtypingClosure_ = false;
98 
99     TypeSystemKind kind_ = TypeSystemKind::PANDA;
100     ThreadNum threadnum_ = 0;
101 
FindNum(const TypeInfo & ti)102     Index<TypeNum> FindNum(const TypeInfo &ti) const
103     {
104         auto it = InfoToNum_.find(ti);
105         if (it != InfoToNum_.end()) {
106             return it->second;
107         }
108         return {};
109     }
110 
FindNumOrCreate(const TypeInfo & ti)111     TypeNum FindNumOrCreate(const TypeInfo &ti)
112     {
113         Index<TypeNum> existingnum = FindNum(ti);
114         if (existingnum.IsValid()) {
115             return existingnum;
116         }
117         size_t num = Universe_.size();
118         TypingRel_.EnsureMinSize(num);
119         Universe_.push_back(ti);
120         ParameterOf_.push_back({});
121         const auto &params = ti.ParamsIdx();
122         for (const auto &param : params) {
123             ParameterOf_[param].insert(num);
124         }
125         InfoToNum_[ti] = num;
126         SortIdx sort = ti.Sort();
127         size_t arity = params.size();
128         if (sort >= TypeClasses_.size()) {
129             TypeClasses_.resize(sort + 1);
130         }
131         TypeClasses_[sort][arity].push_back(num);
132         Relate(num, num);
133         return num;
134     }
135 
TypeClassNum(TypeNum type)136     const VectorNum &TypeClassNum(TypeNum type) const
137     {
138         const auto &info = Universe_[type];
139         const auto &params = info.ParamsIdx();
140         return TypeClasses_[info.Sort()][params.size()];
141     }
142 
PerformClosingCurrentRelation()143     void PerformClosingCurrentRelation()
144     {
145         auto addToNext = [this](TypeNum type) {
146             const auto &info = Universe_[type];
147             SubtypingClosureNext_.AddType(info.Sort(), type, info.Arity());
148             return true;
149         };
150         while (!SubtypingClosureCurrent_.Empty()) {
151             SubtypingClosureCurrent_.ForAllTypeClasses([this, &addToNext](auto &types) {
152                 for (auto type_lhs : types) {
153                     for (auto type_rhs : types) {
154                         bool in_direct_relation = TypingRel_.IsInDirectRelation(type_lhs, type_rhs);
155                         if (!in_direct_relation && CheckIfLhsSubtypeOfRhs(type_lhs, type_rhs)) {
156                             addToNext(type_lhs);
157                             addToNext(type_rhs);
158                             TypingRel_ += {type_lhs, type_rhs};
159                             for (const auto &type : ParameterOf_[type_lhs]) {
160                                 addToNext(type);
161                                 TypingRel_.ForAllTo(type, addToNext);
162                                 TypingRel_.ForAllFrom(type, addToNext);
163                             }
164                             for (const auto &type : ParameterOf_[type_rhs]) {
165                                 addToNext(type);
166                                 TypingRel_.ForAllTo(type, addToNext);
167                                 TypingRel_.ForAllFrom(type, addToNext);
168                             }
169                         }
170                     }
171                 }
172             });
173             SubtypingClosureCurrent_.swap(SubtypingClosureNext_);
174             SubtypingClosureNext_.Clear();
175         }
176     }
177 
Relate(TypeNum lhs,TypeNum rhs)178     void Relate(TypeNum lhs, TypeNum rhs)
179     {
180         if (TypingRel_.IsInDirectRelation(lhs, rhs)) {
181             return;
182         }
183         TypingRel_ += {lhs, rhs};
184         if (IncrementalSubtypingClosure_) {
185             auto processType = [this](TypeNum type) {
186                 auto addToCurrent = [this](TypeNum type1) {
187                     const auto &info = Universe_[type1];
188                     SubtypingClosureCurrent_.AddType(info.Sort(), type1, info.Arity());
189                     return true;
190                 };
191                 for (const auto &typenum : TypeClassNum(type)) {
192                     addToCurrent(typenum);
193                 }
194                 for (const auto &type_idx : ParameterOf_[type]) {
195                     addToCurrent(type_idx);
196                     TypingRel_.ForAllTo(type_idx, addToCurrent);
197                     TypingRel_.ForAllFrom(type_idx, addToCurrent);
198                 }
199             };
200             processType(lhs);
201             if (lhs != rhs) {
202                 processType(rhs);
203             }
204             if (!DeferIncrementalSubtypingClosure_) {
205                 PerformClosingCurrentRelation();
206             }
207         }
208     }
209 
CheckIfLhsParamsSubtypeOfRhs(const TypeParamsIdx & lhs,const TypeParamsIdx & rhs)210     bool CheckIfLhsParamsSubtypeOfRhs(const TypeParamsIdx &lhs, const TypeParamsIdx &rhs) const
211     {
212         if (lhs.size() != rhs.size()) {
213             return false;
214         }
215         auto lhs_it = lhs.cbegin();
216         auto rhs_it = rhs.cbegin();
217         for (; lhs_it != lhs.cend(); ++lhs_it, ++rhs_it) {
218             switch (lhs_it->Variance()) {
219                 case TypeVariance::INVARIANT:
220                     if (!TypingRel_.IsInIsoRelation(*lhs_it, *rhs_it)) {
221                         return false;
222                     }
223                     break;
224                 case TypeVariance::COVARIANT:
225                     if (!TypingRel_.IsInDirectRelation(*lhs_it, *rhs_it)) {
226                         return false;
227                     }
228                     break;
229                 case TypeVariance::CONTRVARIANT:
230                     if (!TypingRel_.IsInInverseRelation(*lhs_it, *rhs_it)) {
231                         return false;
232                     }
233                     break;
234                 default:
235                     break;
236             }
237         }
238         return true;
239     }
240 
CheckIfLhsSubtypeOfRhs(TypeNum lhs,TypeNum rhs)241     bool CheckIfLhsSubtypeOfRhs(TypeNum lhs, TypeNum rhs) const
242     {
243         const TypeInfo &lhsInfo = Universe_[lhs];
244         const TypeInfo &rhsInfo = Universe_[rhs];
245         if (lhsInfo.Sort() != rhsInfo.Sort()) {
246             return false;
247         }
248         const TypeParamsIdx &lhsParams = lhsInfo.ParamsIdx();
249         const TypeParamsIdx &rhsParams = rhsInfo.ParamsIdx();
250         return CheckIfLhsParamsSubtypeOfRhs(lhsParams, rhsParams);
251     }
252 
IsInDirectRelation(TypeNum lhs,TypeNum rhs)253     bool IsInDirectRelation(TypeNum lhs, TypeNum rhs) const
254     {
255         return TypingRel_.IsInDirectRelation(lhs, rhs);
256     }
257 
GetSort(TypeNum t)258     size_t GetSort(TypeNum t) const
259     {
260         return Universe_[t].Sort();
261     }
262 
GetArity(TypeNum t)263     size_t GetArity(TypeNum t) const
264     {
265         return Universe_[t].Arity();
266     }
267 
GetParamsIdx(TypeNum t)268     const TypeParamsIdx &GetParamsIdx(TypeNum t) const
269     {
270         return Universe_[t].ParamsIdx();
271     }
272 
273     friend class Type;
274     friend class TypeParams;
275     friend class ParametricType;
276 
SetIncrementalRelationClosureMode(bool state)277     void SetIncrementalRelationClosureMode(bool state)
278     {
279         IncrementalSubtypingClosure_ = state;
280     }
281 
SetDeferIncrementalRelationClosure(bool state)282     void SetDeferIncrementalRelationClosure(bool state)
283     {
284         DeferIncrementalSubtypingClosure_ = state;
285     }
286 
287     template <typename Handler>
ForAllTypes(Handler && handler)288     void ForAllTypes(Handler &&handler) const
289     {
290         for (size_t num = 0; num < Universe_.size(); ++num) {
291             if (!handler(Type {kind_, threadnum_, num})) {
292                 return;
293             }
294         }
295     }
296 
297     template <typename Handler>
ForAllSubtypesOf(const Type & t,Handler && handler)298     void ForAllSubtypesOf(const Type &t, Handler &&handler) const
299     {
300         auto num = t.Number();
301         auto callback = [this, &handler](const TypeNum &t_num) {
302             bool result = handler(Type {kind_, threadnum_, t_num});
303             return result;
304         };
305         TypingRel_.ForAllTo(num, callback);
306     }
307 
308     template <typename Handler>
ForAllSupertypesOf(const Type & t,Handler && handler)309     void ForAllSupertypesOf(const Type &t, Handler &&handler) const
310     {
311         auto num = t.Number();
312         auto callback = [this, &handler](const TypeNum &t_num) {
313             bool result = handler(Type {kind_, threadnum_, t_num});
314             return result;
315         };
316         TypingRel_.ForAllFrom(num, callback);
317     }
318 
GetDirectlyRelated(TypeNum from)319     const IntSet<TypeNum> &GetDirectlyRelated(TypeNum from) const
320     {
321         return TypingRel_.GetDirectlyRelated(from);
322     }
323 
GetInverselyRelated(TypeNum to)324     const IntSet<TypeNum> &GetInverselyRelated(TypeNum to) const
325     {
326         return TypingRel_.GetInverselyRelated(to);
327     }
328 
CloseSubtypingRelation()329     void CloseSubtypingRelation()
330     {
331         ForAllTypes([this](const Type &type) {
332             auto sort = type.Sort();
333             auto number = type.Number();
334             auto arity = type.Arity();
335             SubtypingClosureCurrent_.AddType(sort, number, arity);
336             return true;
337         });
338         PerformClosingCurrentRelation();
339     }
340 
CloseAccumulatedSubtypingRelation()341     void CloseAccumulatedSubtypingRelation()
342     {
343         if (IncrementalSubtypingClosure_) {
344             if (DeferIncrementalSubtypingClosure_) {
345                 PerformClosingCurrentRelation();
346             }
347         } else {
348             CloseSubtypingRelation();
349         }
350     }
351 
Parametric(SortIdx sort)352     ParametricType Parametric(SortIdx sort)
353     {
354         return {kind_, threadnum_, sort};
355     }
356 
Bot()357     Type Bot() const
358     {
359         return {kind_, threadnum_, BotNum_};
360     }
361 
Top()362     Type Top() const
363     {
364         return {kind_, threadnum_, TopNum_};
365     }
366 
GetKind()367     TypeSystemKind GetKind() const
368     {
369         return kind_;
370     }
371 
GetThreadNum()372     ThreadNum GetThreadNum() const
373     {
374         return threadnum_;
375     }
376 
377 private:
378     TypeNum BotNum_;
379     TypeNum TopNum_;
380 };
381 }  // namespace panda::verifier
382 
383 #endif  // !_PANDA_TYPE_SYSTEM_HPP
384