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 ¶ms = ti.ParamsIdx(); 122 for (const auto ¶m : 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 ¶ms = 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