• 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 #include "unionType.h"
17 #include <algorithm>
18 
19 #include <typescript/types/globalTypesHolder.h>
20 
21 namespace panda::es2panda::checker {
22 
ToString(std::stringstream & ss) const23 void UnionType::ToString(std::stringstream &ss) const
24 {
25     for (auto it = constituentTypes_.begin(); it != constituentTypes_.end(); it++) {
26         (*it)->ToString(ss);
27         if (std::next(it) != constituentTypes_.end()) {
28             ss << " | ";
29         }
30     }
31 }
32 
EachTypeRelatedToSomeType(TypeRelation * relation,UnionType * source,UnionType * target)33 bool UnionType::EachTypeRelatedToSomeType(TypeRelation *relation, UnionType *source, UnionType *target)
34 {
35     return std::all_of(source->constituentTypes_.begin(), source->constituentTypes_.end(),
36                        [relation, target](auto *s) { return TypeRelatedToSomeType(relation, s, target); });
37 }
38 
TypeRelatedToSomeType(TypeRelation * relation,Type * source,UnionType * target)39 bool UnionType::TypeRelatedToSomeType(TypeRelation *relation, Type *source, UnionType *target)
40 {
41     return std::any_of(target->constituentTypes_.begin(), target->constituentTypes_.end(),
42                        [relation, source](auto *t) { return relation->IsIdenticalTo(source, t); });
43 }
44 
Identical(TypeRelation * relation,Type * other)45 void UnionType::Identical(TypeRelation *relation, Type *other)
46 {
47     if (other->IsUnionType()) {
48         if (EachTypeRelatedToSomeType(relation, this, other->AsUnionType()) &&
49             EachTypeRelatedToSomeType(relation, other->AsUnionType(), this)) {
50             relation->Result(true);
51             return;
52         }
53     }
54 
55     relation->Result(false);
56 }
57 
AssignmentSource(TypeRelation * relation,Type * target)58 bool UnionType::AssignmentSource(TypeRelation *relation, Type *target)
59 {
60     for (auto *it : constituentTypes_) {
61         if (!relation->IsAssignableTo(it, target)) {
62             return false;
63         }
64     }
65 
66     relation->Result(true);
67     return true;
68 }
69 
AssignmentTarget(TypeRelation * relation,Type * source)70 void UnionType::AssignmentTarget(TypeRelation *relation, Type *source)
71 {
72     for (auto *it : constituentTypes_) {
73         if (relation->IsAssignableTo(source, it)) {
74             return;
75         }
76     }
77 }
78 
GetTypeFacts() const79 TypeFacts UnionType::GetTypeFacts() const
80 {
81     TypeFacts facts = TypeFacts::NONE;
82 
83     for (auto *it : constituentTypes_) {
84         facts |= it->GetTypeFacts();
85     }
86 
87     return facts;
88 }
89 
RemoveDuplicatedTypes(TypeRelation * relation,ArenaVector<Type * > & constituentTypes)90 void UnionType::RemoveDuplicatedTypes(TypeRelation *relation, ArenaVector<Type *> &constituentTypes)
91 {
92     auto compare = constituentTypes.begin();
93 
94     while (compare != constituentTypes.end()) {
95         auto it = compare + 1;
96 
97         while (it != constituentTypes.end()) {
98             relation->Result(false);
99 
100             (*compare)->Identical(relation, *it);
101 
102             if (relation->IsTrue()) {
103                 it = constituentTypes.erase(it);
104             } else {
105                 it++;
106             }
107         }
108 
109         compare++;
110     }
111 }
112 
HandleUnionType(UnionType * unionType,GlobalTypesHolder * globalTypesHolder)113 Type *UnionType::HandleUnionType(UnionType *unionType, GlobalTypesHolder *globalTypesHolder)
114 {
115     if (unionType->HasConstituentFlag(TypeFlag::ANY)) {
116         return globalTypesHolder->GlobalAnyType();
117     }
118 
119     if (unionType->HasConstituentFlag(TypeFlag::UNKNOWN)) {
120         return globalTypesHolder->GlobalUnknownType();
121     }
122 
123     RemoveRedundantLiteralTypesFromUnion(unionType);
124 
125     if (unionType->ConstituentTypes().size() == 1) {
126         return unionType->ConstituentTypes()[0];
127     }
128 
129     return unionType;
130 }
131 
RemoveRedundantLiteralTypesFromUnion(UnionType * type)132 void UnionType::RemoveRedundantLiteralTypesFromUnion(UnionType *type)
133 {
134     bool removeNumberLiterals = false;
135     bool removeStringLiterals = false;
136     bool removeBigintLiterals = false;
137     bool removeBooleanLiterals = false;
138 
139     if (type->HasConstituentFlag(TypeFlag::NUMBER) && type->HasConstituentFlag(TypeFlag::NUMBER_LITERAL)) {
140         removeNumberLiterals = true;
141     }
142 
143     if (type->HasConstituentFlag(TypeFlag::STRING) && type->HasConstituentFlag(TypeFlag::STRING_LITERAL)) {
144         removeStringLiterals = true;
145     }
146 
147     if (type->HasConstituentFlag(TypeFlag::BIGINT) && type->HasConstituentFlag(TypeFlag::BIGINT_LITERAL)) {
148         removeBigintLiterals = true;
149     }
150 
151     if (type->HasConstituentFlag(TypeFlag::BOOLEAN) && type->HasConstituentFlag(TypeFlag::BOOLEAN_LITERAL)) {
152         removeBooleanLiterals = true;
153     }
154 
155     auto &constituentTypes = type->ConstituentTypes();
156     /* TODO(dbatyai): use std::erase_if */
157     auto it = constituentTypes.begin();
158     while (it != constituentTypes.end()) {
159         if ((removeNumberLiterals && (*it)->IsNumberLiteralType()) ||
160             (removeStringLiterals && (*it)->IsStringLiteralType()) ||
161             (removeBigintLiterals && (*it)->IsBigintLiteralType()) ||
162             (removeBooleanLiterals && (*it)->IsBooleanLiteralType())) {
163             type->RemoveConstituentFlag((*it)->TypeFlags());
164             it = constituentTypes.erase(it);
165             continue;
166         }
167 
168         it++;
169     }
170 }
171 
Instantiate(ArenaAllocator * allocator,TypeRelation * relation,GlobalTypesHolder * globalTypes)172 Type *UnionType::Instantiate(ArenaAllocator *allocator, TypeRelation *relation, GlobalTypesHolder *globalTypes)
173 {
174     ArenaVector<Type *> copiedConstituents(constituentTypes_.size(), allocator->Adapter());
175 
176     for (auto *it : constituentTypes_) {
177         copiedConstituents.push_back(it->Instantiate(allocator, relation, globalTypes));
178     }
179 
180     RemoveDuplicatedTypes(relation, copiedConstituents);
181 
182     if (copiedConstituents.size() == 1) {
183         return copiedConstituents[0];
184     }
185 
186     Type *newUnionType = allocator->New<UnionType>(std::move(copiedConstituents));
187 
188     return HandleUnionType(newUnionType->AsUnionType(), globalTypes);
189 }
190 
191 }  // namespace panda::es2panda::checker
192