• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021 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_VERIFICATION_TYPE_TYPE_SYSTEM_H_
17 #define PANDA_VERIFICATION_TYPE_TYPE_SYSTEM_H_
18 
19 #include "verification/util/lazy.h"
20 #include "verification/util/relation.h"
21 #include "type_sort.h"
22 #include "type_index.h"
23 #include "type_info.h"
24 #include "type_type.h"
25 #include "type_set.h"
26 #include "type_param.h"
27 #include "type_params.h"
28 #include "type_parametric.h"
29 #include "subtyping_closure.h"
30 
31 #include "type_systems.h"
32 
33 #include "runtime/include/mem/panda_containers.h"
34 
35 #include "libpandabase/os/mutex.h"
36 
37 #include "macros.h"
38 
39 #include "type_system_kind.h"
40 
41 #include <memory>
42 #include <variant>
43 #include <functional>
44 #include <algorithm>
45 
46 namespace panda::verifier {
47 /*
48 Design decisions:
49 1. Subtyping relation is kept flat during types construction
50 2. Subtyping relation closing may be either incremental/implicit during types construction or explicit
51 3. Sorts are abstracted in the form of indices (of type size_t)
52 4. Types internally represented as indices (size_t)
53 5. There are special initial and final types, named as Bot and Top, and all types are implicitly related
54    as Bot <: type <: Top
55 */
56 
57 class TypeSystem {
58 public:
59     TypeSystem(const TypeSystem &) = delete;
60     TypeSystem(TypeSystem &&) = delete;
61     TypeSystem &operator=(const TypeSystem &) = delete;
62     TypeSystem &operator=(TypeSystem &&) = delete;
63     ~TypeSystem() = default;
64 
65     using TypeUniverse = PandaVector<TypeInfo>;
66     using MappingToIdx = PandaUnorderedMap<TypeInfo, TypeIdx>;
67     // sort -> arity -> types
68     using TypeClasses = PandaVector<PandaUnorderedMap<size_t, VectorIdx>>;
69 
70     Relation TypingRel_;
71     PandaVector<PandaUnorderedSet<TypeIdx>> ParameterOf_;
72     TypeUniverse Universe_;
73     MappingToIdx InfoToIdx_;
74     mutable TypeClasses TypeClasses_;
75     SubtypingClosureInfo SubtypingClosureCurrent_;
76     SubtypingClosureInfo SubtypingClosureNext_;
77     bool IncrementalSubtypingClosure_ = true;
78     bool DeferIncrementalSubtypingClosure_ = false;
79 
80     TypeSystemKind kind_;
81 
FindIdx(const TypeInfo & ti)82     Index<TypeIdx> FindIdx(const TypeInfo &ti)
83     {
84         auto it = InfoToIdx_.find(ti);
85         if (it != InfoToIdx_.end()) {
86             return it->second;
87         }
88         return {};
89     }
90 
FindIdxOrCreate(const TypeInfo & ti)91     TypeIdx FindIdxOrCreate(const TypeInfo &ti)
92     {
93         Index<TypeIdx> existing_idx = FindIdx(ti);
94         if (existing_idx.IsValid()) {
95             return existing_idx;
96         }
97         size_t idx = Universe_.size();
98         TypingRel_.EnsureMinSize(idx);
99         Universe_.push_back(ti);
100         ParameterOf_.push_back({});
101         const auto &params = ti.ParamsIdx();
102         for (const auto &param : params) {
103             ParameterOf_[param].insert(idx);
104         }
105         InfoToIdx_[ti] = idx;
106         SortIdx sort = ti.Sort();
107         size_t arity = params.size();
108         if (sort >= TypeClasses_.size()) {
109             TypeClasses_.resize(sort + 1);
110         }
111         TypeClasses_[sort][arity].push_back(idx);
112         Relate(idx, idx);
113         return idx;
114     }
115 
TypeClassIdx(TypeIdx type)116     const VectorIdx &TypeClassIdx(TypeIdx type) const
117     {
118         const auto &info = Universe_[type];
119         const auto &params = info.ParamsIdx();
120         return TypeClasses_[info.Sort()][params.size()];
121     }
122 
PerformClosingCurrentRelation()123     void PerformClosingCurrentRelation() NO_THREAD_SAFETY_ANALYSIS
124     {
125         auto add_to_next = [this](TypeIdx type) NO_THREAD_SAFETY_ANALYSIS {
126             const auto &info = Universe_[type];
127             SubtypingClosureNext_.AddType(info.Sort(), type, info.Arity());
128             return true;
129         };
130         while (!SubtypingClosureCurrent_.Empty()) {
131             SubtypingClosureCurrent_.ForAllTypeClasses([this, &add_to_next](auto &types) {
132                 for (auto type_lhs : types) {
133                     for (auto type_rhs : types) {
134                         bool in_direct_relation = TypingRel_.IsInDirectRelation(type_lhs, type_rhs);
135                         if (!in_direct_relation && CheckIfLhsSubtypeOfRhs(type_lhs, type_rhs)) {
136                             add_to_next(type_lhs);
137                             add_to_next(type_rhs);
138                             TypingRel_ += {type_lhs, type_rhs};
139                             for (const auto &type : ParameterOf_[type_lhs]) {
140                                 add_to_next(type);
141                                 TypingRel_.ForAllTo(type, add_to_next);
142                                 TypingRel_.ForAllFrom(type, add_to_next);
143                             }
144                             for (const auto &type : ParameterOf_[type_rhs]) {
145                                 add_to_next(type);
146                                 TypingRel_.ForAllTo(type, add_to_next);
147                                 TypingRel_.ForAllFrom(type, add_to_next);
148                             }
149                         }
150                     }
151                 }
152             });
153             SubtypingClosureCurrent_.swap(SubtypingClosureNext_);
154             SubtypingClosureNext_.Clear();
155         }
156     }
157 
Relate(TypeIdx lhs,TypeIdx rhs)158     void Relate(TypeIdx lhs, TypeIdx rhs)
159     {
160         if (TypingRel_.IsInDirectRelation(lhs, rhs)) {
161             return;
162         }
163         TypingRel_ += {lhs, rhs};
164         if (IncrementalSubtypingClosure_) {
165             auto process_type = [this](TypeIdx type) {
166                 auto add_to_current = [this](TypeIdx type_idx) {
167                     const auto &info = Universe_[type_idx];
168                     SubtypingClosureCurrent_.AddType(info.Sort(), type_idx, info.Arity());
169                     return true;
170                 };
171                 for (const auto &type_idx : TypeClassIdx(type)) {
172                     add_to_current(type_idx);
173                 }
174                 for (const auto &type_idx : ParameterOf_[type]) {
175                     add_to_current(type_idx);
176                     TypingRel_.ForAllTo(type_idx, add_to_current);
177                     TypingRel_.ForAllFrom(type_idx, add_to_current);
178                 }
179             };
180             process_type(lhs);
181             if (lhs != rhs) {
182                 process_type(rhs);
183             }
184             if (!DeferIncrementalSubtypingClosure_) {
185                 PerformClosingCurrentRelation();
186             }
187         }
188     }
189 
CheckIfLhsParamsSubtypeOfRhs(const TypeParamsIdx & lhs,const TypeParamsIdx & rhs)190     bool CheckIfLhsParamsSubtypeOfRhs(const TypeParamsIdx &lhs, const TypeParamsIdx &rhs) const
191     {
192         if (lhs.size() != rhs.size()) {
193             return false;
194         }
195         auto lhs_it = lhs.cbegin();
196         auto rhs_it = rhs.cbegin();
197         for (; lhs_it != lhs.cend(); ++lhs_it, ++rhs_it) {
198             switch (lhs_it->Variance()) {
199                 case TypeVariance::INVARIANT:
200                     if (!TypingRel_.IsInIsoRelation(*lhs_it, *rhs_it)) {
201                         return false;
202                     };
203                     break;
204                 case TypeVariance::COVARIANT:
205                     if (!TypingRel_.IsInDirectRelation(*lhs_it, *rhs_it)) {
206                         return false;
207                     };
208                     break;
209                 case TypeVariance::CONTRVARIANT:
210                     if (!TypingRel_.IsInInverseRelation(*lhs_it, *rhs_it)) {
211                         return false;
212                     };
213                     break;
214                 default:
215                     break;
216             }
217         }
218         return true;
219     }
220 
CheckIfLhsSubtypeOfRhs(TypeIdx lhs,TypeIdx rhs)221     bool CheckIfLhsSubtypeOfRhs(TypeIdx lhs, TypeIdx rhs) const
222     {
223         const TypeInfo &lhs_info = Universe_[lhs];
224         const TypeInfo &rhs_info = Universe_[rhs];
225         if (lhs_info.Sort() != rhs_info.Sort()) {
226             return false;
227         }
228         const TypeParamsIdx &lhs_params = lhs_info.ParamsIdx();
229         const TypeParamsIdx &rhs_params = rhs_info.ParamsIdx();
230         return CheckIfLhsParamsSubtypeOfRhs(lhs_params, rhs_params);
231     }
232 
IsInDirectRelation(TypeIdx lhs,TypeIdx rhs)233     bool IsInDirectRelation(TypeIdx lhs, TypeIdx rhs) const
234     {
235         return TypingRel_.IsInDirectRelation(lhs, rhs);
236     }
237 
GetSort(TypeIdx t)238     size_t GetSort(TypeIdx t) const
239     {
240         return Universe_[t].Sort();
241     }
242 
GetArity(TypeIdx t)243     size_t GetArity(TypeIdx t) const
244     {
245         return Universe_[t].Arity();
246     }
247 
GetParamsIdx(TypeIdx t)248     const TypeParamsIdx &GetParamsIdx(TypeIdx t) const
249     {
250         return Universe_[t].ParamsIdx();
251     }
252 
253     friend class Type;
254     friend class TypeParams;
255     friend class ParametricType;
256 
SetIncrementalRelationClosureMode(bool state)257     void SetIncrementalRelationClosureMode(bool state)
258     {
259         IncrementalSubtypingClosure_ = state;
260     }
261 
SetDeferIncrementalRelationClosure(bool state)262     void SetDeferIncrementalRelationClosure(bool state)
263     {
264         DeferIncrementalSubtypingClosure_ = state;
265     }
266 
267     template <typename Handler>
ForAllTypes(Handler && handler)268     void ForAllTypes(Handler &&handler) const
269     {
270         for (size_t idx = 0; idx < Universe_.size(); ++idx) {
271             if (!handler(Type {kind_, idx})) {
272                 return;
273             }
274         }
275     }
276 
277     template <typename Handler>
ForAllSubtypesOf(const Type & t,Handler && handler)278     void ForAllSubtypesOf(const Type &t, Handler &&handler) const
279     {
280         auto idx = t.Index();
281         auto callback = [this, &handler](const TypeIdx &index) {
282             bool result = handler(Type {kind_, index});
283             return result;
284         };
285         TypingRel_.ForAllTo(idx, callback);
286     }
287 
288     template <typename Handler>
ForAllSupertypesOf(const Type & t,Handler && handler)289     void ForAllSupertypesOf(const Type &t, Handler &&handler) const
290     {
291         auto idx = t.Index();
292         auto callback = [this, &handler](const TypeIdx &index) {
293             bool result = handler(Type {kind_, index});
294             return result;
295         };
296         TypingRel_.ForAllFrom(idx, callback);
297     }
298 
GetDirectlyRelated(TypeIdx from)299     const IntSet<TypeIdx> &GetDirectlyRelated(TypeIdx from) const
300     {
301         return TypingRel_.GetDirectlyRelated(from);
302     }
303 
GetInverselyRelated(TypeIdx to)304     const IntSet<TypeIdx> &GetInverselyRelated(TypeIdx to) const
305     {
306         return TypingRel_.GetInverselyRelated(to);
307     }
308 
CloseSubtypingRelation()309     void CloseSubtypingRelation()
310     {
311         ForAllTypes([this](const Type &type) {
312             auto sort = type.Sort();
313             auto index = type.Index();
314             auto arity = type.Arity();
315             SubtypingClosureCurrent_.AddType(sort, index, arity);
316             return true;
317         });
318         PerformClosingCurrentRelation();
319     }
320 
CloseAccumulatedSubtypingRelation()321     void CloseAccumulatedSubtypingRelation()
322     {
323         if (IncrementalSubtypingClosure_) {
324             if (DeferIncrementalSubtypingClosure_) {
325                 PerformClosingCurrentRelation();
326             }
327         } else {
328             CloseSubtypingRelation();
329         }
330     }
331 
Parametric(SortIdx sort)332     ParametricType Parametric(SortIdx sort)
333     {
334         return {kind_, sort};
335     }
336 
Bot()337     Type Bot() const
338     {
339         return {kind_, BotIdx_};
340     }
341 
Top()342     Type Top() const
343     {
344         return {kind_, TopIdx_};
345     }
346 
GetKind()347     TypeSystemKind GetKind() const
348     {
349         return kind_;
350     }
351 
352     TypeSystem(SortIdx bot, SortIdx top, TypeSystemKind kind = TypeSystemKind::PANDA)
353         : kind_ {kind}, BotIdx_ {FindIdxOrCreate({bot, {}})}, TopIdx_ {FindIdxOrCreate({top, {}})}
354     {
355     }
356 
357 private:
358     TypeIdx BotIdx_;
359     TypeIdx TopIdx_;
360 };
361 }  // namespace panda::verifier
362 
363 #endif  // PANDA_VERIFICATION_TYPE_TYPE_SYSTEM_H_
364